Netdev List
 help / color / mirror / Atom feed
* [PATCH 2/12] d80211: better sysfs registration of symlinks to wiphy
From: Jiri Benc @ 2006-06-08  7:49 UTC (permalink / raw)
  To: netdev; +Cc: John W. Linville
In-Reply-To: <20060608094822.014829000.midnight@suse.cz>

Lately, delayed sysfs registration of net_device (in netdev_run_todo) was
removed. This allows us to remove hack that used class interface for sysfs
registration.

Signed-off-by: Jiri Benc <jbenc@suse.cz>

---

 net/d80211/ieee80211.c       |   18 +++++++++++++++--
 net/d80211/ieee80211_i.h     |    2 ++
 net/d80211/ieee80211_iface.c |   15 ++++++++++++++
 net/d80211/ieee80211_sysfs.c |   45 ++++++------------------------------------
 4 files changed, 39 insertions(+), 41 deletions(-)

beb1533d9181d1c6d195de5743517b3559bfd9f9
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index f549098..9724a49 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -4197,9 +4197,21 @@ int ieee80211_register_hw(struct net_dev
 
 	if (hw->fraglist)
 		dev->features |= NETIF_F_FRAGLIST;
-	result = register_netdev(dev);
-	if (result < 0)
+	rtnl_lock();
+	result = dev_alloc_name(dev, dev->name);
+	if (result < 0) {
+		rtnl_unlock();
+		goto fail_dev;
+	}
+	result = register_netdevice(dev);
+	if (result < 0) {
+		rtnl_unlock();
 		goto fail_dev;
+	}
+	result = ieee80211_sysfs_add_netdevice(dev);
+	rtnl_unlock();
+	if (result < 0)
+		goto fail_if_sysfs;
 
 	if (rate_control_initialize(local) < 0) {
 		printk(KERN_DEBUG "%s: Failed to initialize rate control "
@@ -4223,6 +4235,8 @@ int ieee80211_register_hw(struct net_dev
 	return 0;
 
 fail_rate:
+	ieee80211_sysfs_remove_netdevice(dev);
+fail_if_sysfs:
 	unregister_netdev(dev);
 fail_dev:
 	sta_info_stop(local);
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 94e151d..19d9d98 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -599,6 +599,8 @@ int ieee80211_if_add_mgmt(struct net_dev
 void ieee80211_if_del_mgmt(struct net_device *dev);
 
 /* ieee80211_sysfs.c */
+int ieee80211_sysfs_add_netdevice(struct net_device *dev);
+void ieee80211_sysfs_remove_netdevice(struct net_device *dev);
 int ieee80211_register_sysfs(struct ieee80211_local *local);
 void ieee80211_unregister_sysfs(struct ieee80211_local *local);
 int ieee80211_sysfs_init(void);
diff --git a/net/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c
index 6631738..d534fe4 100644
--- a/net/d80211/ieee80211_iface.c
+++ b/net/d80211/ieee80211_iface.c
@@ -76,6 +76,13 @@ int ieee80211_if_add(struct net_device *
 	ret = register_netdevice(ndev);
 	if (ret)
 		goto fail;
+	ret = ieee80211_sysfs_add_netdevice(ndev);
+	if (ret) {
+		/* ndev will be freed by ndev->destructor */
+		unregister_netdevice(ndev);
+		*new_dev = NULL;
+		return ret;
+	}
 
 	list_add(&sdata->list, &local->sub_if_list);
 	ieee80211_proc_init_virtual(ndev);
@@ -123,10 +130,16 @@ int ieee80211_if_add_mgmt(struct net_dev
 	ret = register_netdevice(ndev);
 	if (ret)
 		goto fail;
+	ret = ieee80211_sysfs_add_netdevice(ndev);
+	if (ret)
+		goto fail_sysfs;
 	if (local->open_count > 0)
 		dev_open(ndev);
 	local->apdev = ndev;
 	return 0;
+
+fail_sysfs:
+	unregister_netdevice(ndev);
 fail:
 	free_netdev(ndev);
 	return ret;
@@ -139,6 +152,7 @@ void ieee80211_if_del_mgmt(struct net_de
 
 	ASSERT_RTNL();
 	apdev = local->apdev;
+	ieee80211_sysfs_remove_netdevice(apdev);
 	local->apdev = NULL;
 	unregister_netdevice(apdev);
 }
@@ -293,6 +307,7 @@ void __ieee80211_if_del(struct ieee80211
 	ieee80211_if_reinit(dev);
 	list_del(&sdata->list);
 	ieee80211_proc_deinit_virtual(dev);
+	ieee80211_sysfs_remove_netdevice(dev);
 	unregister_netdevice(dev);
 	/* Except master interface, the net_device will be freed by
 	 * net_device->destructor (i. e. ieee80211_if_free). */
diff --git a/net/d80211/ieee80211_sysfs.c b/net/d80211/ieee80211_sysfs.c
index 463f9aa..5c7af9f 100644
--- a/net/d80211/ieee80211_sysfs.c
+++ b/net/d80211/ieee80211_sysfs.c
@@ -98,60 +98,27 @@ void ieee80211_unregister_sysfs(struct i
 	class_device_del(&local->class_dev);
 }
 
-static int ieee80211_add_netdevice(struct class_device *cd,
-				   struct class_interface *cintf)
+int ieee80211_sysfs_add_netdevice(struct net_device *dev)
 {
-	struct net_device *dev = container_of(cd, struct net_device, class_dev);
 	struct ieee80211_local *local = dev->priv;
 
-	if (ieee80211_dev_find_index(local) < 0)
-		return 0;
-	return sysfs_create_link(&cd->kobj, &local->class_dev.kobj, "wiphy");
+	return sysfs_create_link(&dev->class_dev.kobj, &local->class_dev.kobj,
+				 "wiphy");
 }
 
-static void ieee80211_remove_netdevice(struct class_device *cd,
-				       struct class_interface *cintf)
+void ieee80211_sysfs_remove_netdevice(struct net_device *dev)
 {
-	struct net_device *dev = container_of(cd, struct net_device, class_dev);
 	struct ieee80211_local *local = dev->priv;
 
-	if (ieee80211_dev_find_index(local) >= 0)
-		sysfs_remove_link(&cd->kobj, "wiphy");
-}
-
-static struct class_interface ieee80211_wiphy_cintf = {
-	.add = ieee80211_add_netdevice,
-	.remove = ieee80211_remove_netdevice,
-};
-
-/* Adds class interface watching for new network devices and adding "wiphy"
- * attribute (symlink) to them. */
-static int ieee80211_register_wiphy_cintf(void)
-{
-	ieee80211_wiphy_cintf.class = loopback_dev.class_dev.class;
-	return class_interface_register(&ieee80211_wiphy_cintf);
-}
-
-static void ieee80211_unregister_wiphy_cintf(void)
-{
-	class_interface_unregister(&ieee80211_wiphy_cintf);
+	sysfs_remove_link(&dev->class_dev.kobj, "wiphy");
 }
 
 int ieee80211_sysfs_init(void)
 {
-	int result;
-
-	result = class_register(&ieee80211_class);
-	if (result)
-		return result;
-	result = ieee80211_register_wiphy_cintf();
-	if (result)
-		class_unregister(&ieee80211_class);
-	return result;
+	return class_register(&ieee80211_class);
 }
 
 void ieee80211_sysfs_deinit(void)
 {
-	ieee80211_unregister_wiphy_cintf();
 	class_unregister(&ieee80211_class);
 }
-- 
1.3.0


^ permalink raw reply related

* [PATCH 1/12] d80211: deinit sysfs in case of an error
From: Jiri Benc @ 2006-06-08  7:49 UTC (permalink / raw)
  To: netdev; +Cc: John W. Linville
In-Reply-To: <20060608094822.014829000.midnight@suse.cz>

When ieee80211_wme_register fails in ieee80211_init, ieee80211 class was not
unregistered.

Signed-off-by: Jiri Benc <jbenc@suse.cz>

---

 net/d80211/ieee80211.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

3aed246a5117bd4d1a4f2d5f5074c583d9b4941e
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index b850fb7..f549098 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -4462,6 +4462,7 @@ static int __init ieee80211_init(void)
 		if (ret) {
 			printk(KERN_DEBUG "ieee80211_init: failed to "
 			       "initialize WME (err=%d)\n", ret);
+			ieee80211_sysfs_deinit();
 			ieee80211_proc_deinit();
 			return ret;
 		}
-- 
1.3.0


^ permalink raw reply related

* [PATCH 0/12] d80211: use sysfs instead of procfs
From: Jiri Benc @ 2006-06-08  7:49 UTC (permalink / raw)
  To: netdev; +Cc: John W. Linville

The following series of patches makes d80211 to use sysfs instead of procfs.
This means that custom reference counting in most structures is replaced by
kobjects and nearly all informations from procfs files are converted to
sysfs attributes.

The only information missing in sysfs (compared to procfs) is channels and
rates info. Implementing this in a sysfs way (i. e. one information per
attribute rule) requires a lot of code and (more important) adding kobjects
to channel and rate structures. I doubt these informations are really so
useful to be worth such complications. If there are good arguments why these
informations should be exported via sysfs I will add them.

If you find a better name for some object (directory) or attribute (file) or
just consider some name wrong or ugly, let me know please.

The third patch ("separate allocation of ieee80211_local") touches the code
outside of net/d80211 - it adds ieee80211_ptr to net_device structure.

All of patches can be also obtained from 'master' branch of
git://git.kernel.org/pub/scm/linux/kernel/git/jbenc/dscape.git

---

Jiri Benc:
      d80211: deinit sysfs in case of an error
      d80211: better sysfs registration of symlinks to wiphy
      d80211: separate allocation of ieee80211_local
      d80211: fix Oops when writing to add_ and remove_iface
      d80211: wiphy sysfs attributes
      d80211: network interface sysfs attributes
      d80211: rename sta_info_relase to sta_info_put
      d80211: sysfs attributes for associated stations
      d80211: remove useless parameters
      d80211: rate_control sysfs attributes
      d80211: encryption keys sysfs attributes
      d80211: remove procfs files

 include/linux/netdevice.h        |    1 
 net/d80211/Makefile              |    2 
 net/d80211/ieee80211.c           |  206 +++++++---
 net/d80211/ieee80211_dev.c       |   17 +
 net/d80211/ieee80211_i.h         |   45 ++
 net/d80211/ieee80211_iface.c     |   43 +-
 net/d80211/ieee80211_ioctl.c     |  213 ++++++----
 net/d80211/ieee80211_key.h       |    2 
 net/d80211/ieee80211_proc.c      |  771 --------------------------------------
 net/d80211/ieee80211_proc.h      |   45 --
 net/d80211/ieee80211_scan.c      |   10 
 net/d80211/ieee80211_sta.c       |   68 ++-
 net/d80211/ieee80211_sysfs.c     |  706 +++++++++++++++++++++++++++++++++--
 net/d80211/ieee80211_sysfs_sta.c |  434 +++++++++++++++++++++
 net/d80211/rate_control.c        |   55 ++-
 net/d80211/rate_control.h        |   57 ++-
 net/d80211/sta_info.c            |  132 ++++---
 net/d80211/sta_info.h            |   16 -
 net/d80211/wme.c                 |   26 +
 19 files changed, 1663 insertions(+), 1186 deletions(-)


-- 
Jiri Benc
SUSE Labs

^ permalink raw reply

* Re: [patch] workaround zd1201 interference problem
From: Pavel Machek @ 2006-06-08  7:13 UTC (permalink / raw)
  To: Daniel Drake; +Cc: Jiri Benc, linville, kernel list, netdev
In-Reply-To: <20060608070525.GE3688@elf.ucw.cz>

Hi!

> > >Well, I'll try _enable() alone, but it seems to me that _enable()
> > >command is needed to initialize radio properly. I do not think we can
> > >get much further without firmware sources...
> > 
> > If you can formulate a proper and technical description of the issue 
> > (and exactly what is needed to workaround it), I can contact ZyDAS for 
> > you. They have been very helpful with ZD1211.
> 
> Okay, the issue is:
> 
> if you plug zd1201 into USB, it starts jamming radio,
> immediately. Enable/disable, or iwlist wlan0 scan, or basically any
> operation unjams the radio. This patch works it around:

Of course, the patch should have been:

 diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
 index 335eaf3..dcc7bc7 100644
 --- a/drivers/net/wireless/zd1201.c
 +++ b/drivers/net/wireless/zd1201.c
 @@ -1835,6 +1835,8 @@ static int zd1201_probe(struct usb_inter
  	    zd->dev->name);
  	
  	usb_set_intfdata(interface, zd);
 +	zd1201_enable(zd);	/* zd1201 likes to startup enabled, interfering */
 +	zd1201_disable(zd); 	/* with all the wifis in range */
  	return 0;
  
  err_net:
 
 
 ....question is "is that right solution, or is something different
 needed to solve that problem properly"?
 								Pavel

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply

* Re: [patch] workaround zd1201 interference problem
From: Pavel Machek @ 2006-06-08  7:05 UTC (permalink / raw)
  To: Daniel Drake; +Cc: Jiri Benc, linville, kernel list, netdev
In-Reply-To: <4486FD2F.8040205@gentoo.org>

Hi!

> >Well, I'll try _enable() alone, but it seems to me that _enable()
> >command is needed to initialize radio properly. I do not think we can
> >get much further without firmware sources...
> 
> If you can formulate a proper and technical description of the issue 
> (and exactly what is needed to workaround it), I can contact ZyDAS for 
> you. They have been very helpful with ZD1211.

Okay, the issue is:

if you plug zd1201 into USB, it starts jamming radio,
immediately. Enable/disable, or iwlist wlan0 scan, or basically any
operation unjams the radio. This patch works it around:

diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
index 335eaf3..dcc7bc7 100644
--- a/drivers/net/wireless/zd1201.c
+++ b/drivers/net/wireless/zd1201.c
@@ -1835,8 +1835,8 @@ static int zd1201_probe(struct usb_inter
 	    zd->dev->name);
 	
 	usb_set_intfdata(interface, zd);
-	zd1201_enable(zd);
-	zd1201_disable(zd);
+	zd1201_enable(zd);	/* zd1201 likes to startup enabled, interfering */
+	zd1201_disable(zd); 	/* with all the wifis in range */
 	return 0;
 
 err_net:


....question is "is that right solution, or is something different
needed to solve that problem properly"?
								Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply related

* Re: [PATCH 3/4] ehea: queue managment
From: Muli Ben-Yehuda @ 2006-06-08  6:35 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: ossthema, netdev, Marcus Eder, Christoph Raisch,
	Jan-Bernd Themann, Thomas Q Klein
In-Reply-To: <20060607102950.54dd83c1@localhost.localdomain>

On Wed, Jun 07, 2006 at 10:29:50AM -0700, Stephen Hemminger wrote:

> Be careful about global namespace issues. Stick to one prefix like ehea_
> for all non static function names. Consider putting all in one file, or
> use #include to cause it to be one compilation unit.

I thought including .c files was discouraged (if not, it should be...)

Cheers,
Muli

^ permalink raw reply

* Re: Updated sysctl documentation take #2
From: David Lang @ 2006-06-07 22:52 UTC (permalink / raw)
  To: Johannes Stezenbach
  Cc: Diego Calleja, linux-kernel, akpm, netdev, linux-xfs, ecki, lkml
In-Reply-To: <20060607235631.GA10688@linuxtv.org>

On Thu, 8 Jun 2006, Johannes Stezenbach wrote:

> On Wed, Jun 07, 2006, Diego Calleja wrote:
>> Since people didn't like the "many small files" approach, I've moved
>> it to directories containing index.txt files:
>>
>> Documentation/sysctl/vm/index.txt
>> Documentation/sysctl/net/core/index.txt
>
> Why not just
>
> Documentation/sysctl/vm.txt
> Documentation/sysctl/net/core.txt
>
> etc.?

better matching of the proc layout would be my guess.

^ permalink raw reply

* Re: Updated sysctl documentation take #2
From: Johannes Stezenbach @ 2006-06-07 23:56 UTC (permalink / raw)
  To: Diego Calleja; +Cc: linux-kernel, akpm, netdev, linux-xfs, ecki, lkml
In-Reply-To: <20060607205316.bbb3c379.diegocg@gmail.com>

On Wed, Jun 07, 2006, Diego Calleja wrote:
> Since people didn't like the "many small files" approach, I've moved
> it to directories containing index.txt files:
> 
> Documentation/sysctl/vm/index.txt
> Documentation/sysctl/net/core/index.txt

Why not just

Documentation/sysctl/vm.txt
Documentation/sysctl/net/core.txt

etc.?


Johannes

^ permalink raw reply

* [PATCH 9/10] Add Vitesse 8244 PHY for MPC8641 HPCN platform.
From: Jon Loeliger @ 2006-06-07 22:45 UTC (permalink / raw)
  To: linuxppc-dev@ozlabs.org, netdev, jeff


Signed-off-by: Kriston Carson <KristonCarson@freescale.com>
Signed-off-by: Xianghua Xiao <x.xiao@freescale.com>
Signed-off-by: Jon Loeliger <jdl@freescale.com>

---

 drivers/net/Kconfig       |    6 +-
 drivers/net/phy/Kconfig   |    5 ++
 drivers/net/phy/Makefile  |    1 
 drivers/net/phy/vitesse.c |  136 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 145 insertions(+), 3 deletions(-)


diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index bdaaad8..c1c2758 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2179,11 +2179,11 @@ config SPIDER_NET
 
 config GIANFAR
 	tristate "Gianfar Ethernet"
-	depends on 85xx || 83xx
+	depends on 85xx || 83xx || PPC_86xx
 	select PHYLIB
 	help
-	  This driver supports the Gigabit TSEC on the MPC85xx 
-	  family of chips, and the FEC on the 8540
+	  This driver supports the Gigabit TSEC on the MPC83xx, MPC85xx,
+	  and MPC86xx family of chips, and the FEC on the 8540.
 
 config GFAR_NAPI
 	bool "NAPI Support"
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index fa39b94..76e51b1 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -44,6 +44,11 @@ config CICADA_PHY
 	depends on PHYLIB
 	---help---
 	  Currently supports the cis8204
+config VITESSE_PHY
+        tristate "Drivers for the Vitesse PHYs"
+        depends on PHYLIB
+        ---help---
+          Currently supports the vsc8244
 
 endmenu
 
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index e4116a5..a8d066e 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_DAVICOM_PHY)	+= davicom.o
 obj-$(CONFIG_CICADA_PHY)	+= cicada.o
 obj-$(CONFIG_LXT_PHY)		+= lxt.o
 obj-$(CONFIG_QSEMI_PHY)		+= qsemi.o
+obj-$(CONFIG_VITESSE_PHY)	+= vitesse.o
diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c
new file mode 100644
index 0000000..45a605f
--- /dev/null
+++ b/drivers/net/phy/vitesse.c
@@ -0,0 +1,136 @@
+/*
+ * Driver for Vitesse PHYs
+ *
+ * Author: Kriston Carson
+ *
+ * Copyright (c) 2005 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+/* Vitesse Extended Control Register 1 */
+#define MII_VSC8244_EXT_CON1           0x17
+#define MII_VSC8244_EXTCON1_INIT       0x0000
+
+/* Vitesse Interrupt Mask Register */
+#define MII_VSC8244_IMASK		0x19
+#define MII_VSC8244_IMASK_IEN		0x8000
+#define MII_VSC8244_IMASK_SPEED		0x4000
+#define MII_VSC8244_IMASK_LINK		0x2000
+#define MII_VSC8244_IMASK_DUPLEX	0x1000
+#define MII_VSC8244_IMASK_MASK		0xf000
+
+/* Vitesse Interrupt Status Register */
+#define MII_VSC8244_ISTAT		0x1a
+#define MII_VSC8244_ISTAT_STATUS	0x8000
+#define MII_VSC8244_ISTAT_SPEED		0x4000
+#define MII_VSC8244_ISTAT_LINK		0x2000
+#define MII_VSC8244_ISTAT_DUPLEX	0x1000
+
+/* Vitesse Auxiliary Control/Status Register */
+#define MII_VSC8244_AUX_CONSTAT        	0x1c
+#define MII_VSC8244_AUXCONSTAT_INIT    	0x0004
+#define MII_VSC8244_AUXCONSTAT_DUPLEX  	0x0020
+#define MII_VSC8244_AUXCONSTAT_SPEED   	0x0018
+#define MII_VSC8244_AUXCONSTAT_GBIT    	0x0010
+#define MII_VSC8244_AUXCONSTAT_100     	0x0008
+
+MODULE_DESCRIPTION("Vitesse PHY driver");
+MODULE_AUTHOR("Kriston Carson");
+MODULE_LICENSE("GPL");
+
+static int vsc824x_config_init(struct phy_device *phydev)
+{
+	int err;
+
+	err = phy_write(phydev, MII_VSC8244_AUX_CONSTAT,
+			MII_VSC8244_AUXCONSTAT_INIT);
+
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, MII_VSC8244_EXT_CON1,
+			MII_VSC8244_EXTCON1_INIT);
+
+	return err;
+
+}
+
+static int vsc824x_ack_interrupt(struct phy_device *phydev)
+{
+	int err = phy_read(phydev, MII_VSC8244_ISTAT);
+
+	return (err < 0) ? err : 0;
+
+}
+
+static int vsc824x_config_intr(struct phy_device *phydev)
+{
+	int err;
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		err = phy_write(phydev, MII_VSC8244_IMASK,
+				MII_VSC8244_IMASK_MASK);
+	else
+		err = phy_write(phydev, MII_VSC8244_IMASK, 0);
+
+	return err;
+
+}
+
+/* Vitesse 824x */
+static struct phy_driver vsc8244_driver = {
+	.phy_id		= 0x000fc6c2,
+	.name		= "Vitesse VSC8244",
+	.phy_id_mask	= 0x000fffc0,
+	.features	= PHY_GBIT_FEATURES,
+	.flags		= PHY_HAS_INTERRUPT,
+	.config_init	= &vsc824x_config_init,
+	.config_aneg	= &genphy_config_aneg,
+	.read_status	= &genphy_read_status,
+	.ack_interrupt	= &vsc824x_ack_interrupt,
+	.config_intr	= &vsc824x_config_intr,
+	.driver 	= { .owner = THIS_MODULE,},
+};
+
+static int __init vsc8244_init(void)
+{
+	return phy_driver_register(&vsc8244_driver);
+}
+
+static void __exit vsc8244_exit(void)
+{
+	phy_driver_unregister(&vsc8244_driver);
+}
+
+module_init(vsc8244_init);
+module_exit(vsc8244_exit);



^ permalink raw reply related

* Re: [PATCH] pcnet32 driver NAPI support
From: Don Fry @ 2006-06-07 22:32 UTC (permalink / raw)
  To: Lennart Sorensen; +Cc: netdev
In-Reply-To: <20060607215236.GA13380@us.ibm.com>

One other problem I ran into.  I applied the patch but it will not
compile because rl_active is never defined.  I have worked around it but
...


-- 
Don Fry
brazilnut@us.ibm.com

^ permalink raw reply

* Re: Updated sysctl documentation take #2
From: Diego Calleja @ 2006-06-07 22:18 UTC (permalink / raw)
  To: Randy.Dunlap; +Cc: linux-kernel, akpm, netdev, linux-xfs, ecki, lkml
In-Reply-To: <20060607130653.9a4d572c.rdunlap@xenotime.net>

El Wed, 7 Jun 2006 13:06:53 -0700,
"Randy.Dunlap" <rdunlap@xenotime.net> escribió:


> I don't know how long it takes to review such a large patch, but
> I'll continue to do so.  For now:

Yeah, my english is poor ;)

Most of the sysctl documentation cames from other files anyway, 
README was (re)written by me, so the rest is not so bad...


> OK, that's all for the README file.  I'll look at the rest of it
> sometime this week.  I don't think that it's quite ready to be merged.


Thank's for your review, altought I didn't though someone was to review
so deeply a documentation patch ;) I've gone through all the files and
fixed the 72-col limit and everything I could. I've updated the patch
http://terra.es/personal/diegocg/sysctl-docs


^ permalink raw reply

* Re: [PATCH v2 2/2] iWARP Core Changes.
From: Tom Tucker @ 2006-06-07 22:13 UTC (permalink / raw)
  To: Steve Wise; +Cc: rdreier, mshefty, linux-kernel, netdev, openib-general
In-Reply-To: <20060607200610.9003.54068.stgit@stevo-desktop>


A reference is being taken on an iWARP device that is never getting
released. This prevents a participating iWARP netdev device from being
unloaded after a connection has been established on the passive side.

Search for ip_dev_find below...

On Wed, 2006-06-07 at 15:06 -0500, Steve Wise wrote:
> This patch contains modifications to the existing rdma header files,
> core files, drivers, and ulp files to support iWARP.
> 
> Review updates:
> 
> - copy_addr() -> rdma_copy_addr()
> 
> - dst_dev_addr param in rdma_copy_addr to const.
> 
> - various spacing nits with recasting
> 
> - include linux/inetdevice.h to get ip_dev_find() prototype.
> ---
> 
>  drivers/infiniband/core/Makefile             |    4 
>  drivers/infiniband/core/addr.c               |   19 +
>  drivers/infiniband/core/cache.c              |    8 -
>  drivers/infiniband/core/cm.c                 |    3 
>  drivers/infiniband/core/cma.c                |  353 +++++++++++++++++++++++---
>  drivers/infiniband/core/device.c             |    6 
>  drivers/infiniband/core/mad.c                |   11 +
>  drivers/infiniband/core/sa_query.c           |    5 
>  drivers/infiniband/core/smi.c                |   18 +
>  drivers/infiniband/core/sysfs.c              |   18 +
>  drivers/infiniband/core/ucm.c                |    5 
>  drivers/infiniband/core/user_mad.c           |    9 -
>  drivers/infiniband/hw/ipath/ipath_verbs.c    |    2 
>  drivers/infiniband/hw/mthca/mthca_provider.c |    2 
>  drivers/infiniband/ulp/ipoib/ipoib_main.c    |    8 +
>  drivers/infiniband/ulp/srp/ib_srp.c          |    2 
>  include/rdma/ib_addr.h                       |   15 +
>  include/rdma/ib_verbs.h                      |   39 +++
>  18 files changed, 435 insertions(+), 92 deletions(-)
> 
> diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile
> index 68e73ec..163d991 100644
> --- a/drivers/infiniband/core/Makefile
> +++ b/drivers/infiniband/core/Makefile
> @@ -1,7 +1,7 @@
>  infiniband-$(CONFIG_INFINIBAND_ADDR_TRANS)	:= ib_addr.o rdma_cm.o
>  
>  obj-$(CONFIG_INFINIBAND) +=		ib_core.o ib_mad.o ib_sa.o \
> -					ib_cm.o $(infiniband-y)
> +					ib_cm.o iw_cm.o $(infiniband-y)
>  obj-$(CONFIG_INFINIBAND_USER_MAD) +=	ib_umad.o
>  obj-$(CONFIG_INFINIBAND_USER_ACCESS) +=	ib_uverbs.o ib_ucm.o
>  
> @@ -14,6 +14,8 @@ ib_sa-y :=			sa_query.o
>  
>  ib_cm-y :=			cm.o
>  
> +iw_cm-y :=			iwcm.o
> +
>  rdma_cm-y :=			cma.o
>  
>  ib_addr-y :=			addr.o
> diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
> index d294bbc..83f84ef 100644
> --- a/drivers/infiniband/core/addr.c
> +++ b/drivers/infiniband/core/addr.c
> @@ -32,6 +32,7 @@ #include <linux/mutex.h>
>  #include <linux/inetdevice.h>
>  #include <linux/workqueue.h>
>  #include <linux/if_arp.h>
> +#include <linux/inetdevice.h>
>  #include <net/arp.h>
>  #include <net/neighbour.h>
>  #include <net/route.h>
> @@ -60,12 +61,15 @@ static LIST_HEAD(req_list);
>  static DECLARE_WORK(work, process_req, NULL);
>  static struct workqueue_struct *addr_wq;
>  
> -static int copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev,
> -		     unsigned char *dst_dev_addr)
> +int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev,
> +		     const unsigned char *dst_dev_addr)
>  {
>  	switch (dev->type) {
>  	case ARPHRD_INFINIBAND:
> -		dev_addr->dev_type = IB_NODE_CA;
> +		dev_addr->dev_type = RDMA_NODE_IB_CA;
> +		break;
> +	case ARPHRD_ETHER:
> +		dev_addr->dev_type = RDMA_NODE_RNIC;
>  		break;
>  	default:
>  		return -EADDRNOTAVAIL;
> @@ -77,6 +81,7 @@ static int copy_addr(struct rdma_dev_add
>  		memcpy(dev_addr->dst_dev_addr, dst_dev_addr, MAX_ADDR_LEN);
>  	return 0;
>  }
> +EXPORT_SYMBOL(rdma_copy_addr);
>  
>  int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr)
>  {
> @@ -88,7 +93,7 @@ int rdma_translate_ip(struct sockaddr *a
>  	if (!dev)
>  		return -EADDRNOTAVAIL;
>  
> -	ret = copy_addr(dev_addr, dev, NULL);
> +	ret = rdma_copy_addr(dev_addr, dev, NULL);
>  	dev_put(dev);
>  	return ret;
>  }
> @@ -160,7 +165,7 @@ static int addr_resolve_remote(struct so
>  
>  	/* If the device does ARP internally, return 'done' */
>  	if (rt->idev->dev->flags & IFF_NOARP) {
> -		copy_addr(addr, rt->idev->dev, NULL);
> +		rdma_copy_addr(addr, rt->idev->dev, NULL);
>  		goto put;
>  	}
>  
> @@ -180,7 +185,7 @@ static int addr_resolve_remote(struct so
>  		src_in->sin_addr.s_addr = rt->rt_src;
>  	}
>  
> -	ret = copy_addr(addr, neigh->dev, neigh->ha);
> +	ret = rdma_copy_addr(addr, neigh->dev, neigh->ha);
>  release:
>  	neigh_release(neigh);
>  put:
> @@ -244,7 +249,7 @@ static int addr_resolve_local(struct soc
>  	if (ZERONET(src_ip)) {
>  		src_in->sin_family = dst_in->sin_family;
>  		src_in->sin_addr.s_addr = dst_ip;
> -		ret = copy_addr(addr, dev, dev->dev_addr);
> +		ret = rdma_copy_addr(addr, dev, dev->dev_addr);
>  	} else if (LOOPBACK(src_ip)) {
>  		ret = rdma_translate_ip((struct sockaddr *)dst_in, addr);
>  		if (!ret)
> diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c
> index e05ca2c..061858c 100644
> --- a/drivers/infiniband/core/cache.c
> +++ b/drivers/infiniband/core/cache.c
> @@ -32,13 +32,12 @@
>   * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
>   * SOFTWARE.
>   *
> - * $Id: cache.c 1349 2004-12-16 21:09:43Z roland $
> + * $Id: cache.c 6885 2006-05-03 18:22:02Z sean.hefty $
>   */
>  
>  #include <linux/module.h>
>  #include <linux/errno.h>
>  #include <linux/slab.h>
> -#include <linux/sched.h>	/* INIT_WORK, schedule_work(), flush_scheduled_work() */
>  
>  #include <rdma/ib_cache.h>
>  
> @@ -62,12 +61,13 @@ struct ib_update_work {
>  
>  static inline int start_port(struct ib_device *device)
>  {
> -	return device->node_type == IB_NODE_SWITCH ? 0 : 1;
> +	return (device->node_type == RDMA_NODE_IB_SWITCH) ? 0 : 1;
>  }
>  
>  static inline int end_port(struct ib_device *device)
>  {
> -	return device->node_type == IB_NODE_SWITCH ? 0 : device->phys_port_cnt;
> +	return (device->node_type == RDMA_NODE_IB_SWITCH) ?
> +		0 : device->phys_port_cnt;
>  }
>  
>  int ib_get_cached_gid(struct ib_device *device,
> diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
> index 1c7463b..cf43ccb 100644
> --- a/drivers/infiniband/core/cm.c
> +++ b/drivers/infiniband/core/cm.c
> @@ -3253,6 +3253,9 @@ static void cm_add_one(struct ib_device 
>  	int ret;
>  	u8 i;
>  
> +	if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
> +		return;
> +
>  	cm_dev = kmalloc(sizeof(*cm_dev) + sizeof(*port) *
>  			 device->phys_port_cnt, GFP_KERNEL);
>  	if (!cm_dev)
> diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
> index 94555d2..414600c 100644
> --- a/drivers/infiniband/core/cma.c
> +++ b/drivers/infiniband/core/cma.c
> @@ -35,6 +35,7 @@ #include <linux/in6.h>
>  #include <linux/mutex.h>
>  #include <linux/random.h>
>  #include <linux/idr.h>
> +#include <linux/inetdevice.h>
>  
>  #include <net/tcp.h>
>  
> @@ -43,6 +44,7 @@ #include <rdma/rdma_cm_ib.h>
>  #include <rdma/ib_cache.h>
>  #include <rdma/ib_cm.h>
>  #include <rdma/ib_sa.h>
> +#include <rdma/iw_cm.h>
>  
>  MODULE_AUTHOR("Sean Hefty");
>  MODULE_DESCRIPTION("Generic RDMA CM Agent");
> @@ -124,6 +126,7 @@ struct rdma_id_private {
>  	int			query_id;
>  	union {
>  		struct ib_cm_id	*ib;
> +		struct iw_cm_id	*iw;
>  	} cm_id;
>  
>  	u32			seq_num;
> @@ -259,13 +262,23 @@ static void cma_detach_from_dev(struct r
>  	id_priv->cma_dev = NULL;
>  }
>  
> -static int cma_acquire_ib_dev(struct rdma_id_private *id_priv)
> +static int cma_acquire_dev(struct rdma_id_private *id_priv)
>  {
> +	enum rdma_node_type dev_type = id_priv->id.route.addr.dev_addr.dev_type;
>  	struct cma_device *cma_dev;
>  	union ib_gid *gid;
>  	int ret = -ENODEV;
>  
> -	gid = ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr);
> +	switch (rdma_node_get_transport(dev_type)) {
> +	case RDMA_TRANSPORT_IB:
> +		gid = ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr);
> +		break;
> +	case RDMA_TRANSPORT_IWARP:
> +		gid = iw_addr_get_sgid(&id_priv->id.route.addr.dev_addr);
> +		break;
> +	default:
> +		return -ENODEV;
> +	}
>  
>  	mutex_lock(&lock);
>  	list_for_each_entry(cma_dev, &dev_list, list) {
> @@ -280,16 +293,6 @@ static int cma_acquire_ib_dev(struct rdm
>  	return ret;
>  }
>  
> -static int cma_acquire_dev(struct rdma_id_private *id_priv)
> -{
> -	switch (id_priv->id.route.addr.dev_addr.dev_type) {
> -	case IB_NODE_CA:
> -		return cma_acquire_ib_dev(id_priv);
> -	default:
> -		return -ENODEV;
> -	}
> -}
> -
>  static void cma_deref_id(struct rdma_id_private *id_priv)
>  {
>  	if (atomic_dec_and_test(&id_priv->refcount))
> @@ -347,6 +350,16 @@ static int cma_init_ib_qp(struct rdma_id
>  					  IB_QP_PKEY_INDEX | IB_QP_PORT);
>  }
>  
> +static int cma_init_iw_qp(struct rdma_id_private *id_priv, struct ib_qp *qp)
> +{
> +	struct ib_qp_attr qp_attr;
> +
> +	qp_attr.qp_state = IB_QPS_INIT;
> +	qp_attr.qp_access_flags = IB_ACCESS_LOCAL_WRITE;
> +
> +	return ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_ACCESS_FLAGS);
> +}
> +
>  int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd,
>  		   struct ib_qp_init_attr *qp_init_attr)
>  {
> @@ -362,10 +375,13 @@ int rdma_create_qp(struct rdma_cm_id *id
>  	if (IS_ERR(qp))
>  		return PTR_ERR(qp);
>  
> -	switch (id->device->node_type) {
> -	case IB_NODE_CA:
> +	switch (rdma_node_get_transport(id->device->node_type)) {
> +	case RDMA_TRANSPORT_IB:
>  		ret = cma_init_ib_qp(id_priv, qp);
>  		break;
> +	case RDMA_TRANSPORT_IWARP:
> +		ret = cma_init_iw_qp(id_priv, qp);
> +		break;
>  	default:
>  		ret = -ENOSYS;
>  		break;
> @@ -451,13 +467,17 @@ int rdma_init_qp_attr(struct rdma_cm_id 
>  	int ret;
>  
>  	id_priv = container_of(id, struct rdma_id_private, id);
> -	switch (id_priv->id.device->node_type) {
> -	case IB_NODE_CA:
> +	switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
> +	case RDMA_TRANSPORT_IB:
>  		ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr,
>  					 qp_attr_mask);
>  		if (qp_attr->qp_state == IB_QPS_RTR)
>  			qp_attr->rq_psn = id_priv->seq_num;
>  		break;
> +	case RDMA_TRANSPORT_IWARP:
> +		ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr,
> +					qp_attr_mask);
> +		break;
>  	default:
>  		ret = -ENOSYS;
>  		break;
> @@ -590,8 +610,8 @@ static int cma_notify_user(struct rdma_i
>  
>  static void cma_cancel_route(struct rdma_id_private *id_priv)
>  {
> -	switch (id_priv->id.device->node_type) {
> -	case IB_NODE_CA:
> +	switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
> +	case RDMA_TRANSPORT_IB:
>  		if (id_priv->query)
>  			ib_sa_cancel_query(id_priv->query_id, id_priv->query);
>  		break;
> @@ -611,11 +631,15 @@ static void cma_destroy_listen(struct rd
>  	cma_exch(id_priv, CMA_DESTROYING);
>  
>  	if (id_priv->cma_dev) {
> -		switch (id_priv->id.device->node_type) {
> -		case IB_NODE_CA:
> +		switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
> +		case RDMA_TRANSPORT_IB:
>  	 		if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib))
>  				ib_destroy_cm_id(id_priv->cm_id.ib);
>  			break;
> +		case RDMA_TRANSPORT_IWARP:
> +	 		if (id_priv->cm_id.iw && !IS_ERR(id_priv->cm_id.iw))
> +				iw_destroy_cm_id(id_priv->cm_id.iw);
> +			break;
>  		default:
>  			break;
>  		}
> @@ -690,11 +714,15 @@ void rdma_destroy_id(struct rdma_cm_id *
>  	cma_cancel_operation(id_priv, state);
>  
>  	if (id_priv->cma_dev) {
> -		switch (id->device->node_type) {
> -		case IB_NODE_CA:
> +		switch (rdma_node_get_transport(id->device->node_type)) {
> +		case RDMA_TRANSPORT_IB:
>  	 		if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib))
>  				ib_destroy_cm_id(id_priv->cm_id.ib);
>  			break;
> +		case RDMA_TRANSPORT_IWARP:
> +	 		if (id_priv->cm_id.iw && !IS_ERR(id_priv->cm_id.iw))
> +				iw_destroy_cm_id(id_priv->cm_id.iw);
> +			break;
>  		default:
>  			break;
>  		}
> @@ -868,7 +896,7 @@ static struct rdma_id_private *cma_new_i
>  	ib_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid);
>  	ib_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid);
>  	ib_addr_set_pkey(&rt->addr.dev_addr, be16_to_cpu(rt->path_rec[0].pkey));
> -	rt->addr.dev_addr.dev_type = IB_NODE_CA;
> +	rt->addr.dev_addr.dev_type = RDMA_NODE_IB_CA;
>  
>  	id_priv = container_of(id, struct rdma_id_private, id);
>  	id_priv->state = CMA_CONNECT;
> @@ -897,7 +925,7 @@ static int cma_req_handler(struct ib_cm_
>  	}
>  
>  	atomic_inc(&conn_id->dev_remove);
> -	ret = cma_acquire_ib_dev(conn_id);
> +	ret = cma_acquire_dev(conn_id);
>  	if (ret) {
>  		ret = -ENODEV;
>  		cma_release_remove(conn_id);
> @@ -981,6 +1009,123 @@ static void cma_set_compare_data(enum rd
>  	}
>  }
>  
> +static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event)
> +{
> +	struct rdma_id_private *id_priv = iw_id->context;
> +	enum rdma_cm_event_type event = 0;
> +	struct sockaddr_in *sin;
> +	int ret = 0;
> +
> +	atomic_inc(&id_priv->dev_remove);
> +
> +	switch (iw_event->event) {
> +	case IW_CM_EVENT_CLOSE:
> +		event = RDMA_CM_EVENT_DISCONNECTED;
> +		break;
> +	case IW_CM_EVENT_CONNECT_REPLY:
> +		sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr;
> +		*sin = iw_event->local_addr;
> +		sin = (struct sockaddr_in *) &id_priv->id.route.addr.dst_addr;
> +		*sin = iw_event->remote_addr;
> +		if (iw_event->status)
> +			event = RDMA_CM_EVENT_REJECTED;
> +		else
> +			event = RDMA_CM_EVENT_ESTABLISHED;
> +		break;
> +	case IW_CM_EVENT_ESTABLISHED:
> +		event = RDMA_CM_EVENT_ESTABLISHED;
> +		break;
> +	default:
> +		BUG_ON(1);
> +	}	
> +
> +	ret = cma_notify_user(id_priv, event, iw_event->status, 
> +			      iw_event->private_data, 
> +			      iw_event->private_data_len);
> +	if (ret) {
> +		/* Destroy the CM ID by returning a non-zero value. */
> +		id_priv->cm_id.iw = NULL;
> +		cma_exch(id_priv, CMA_DESTROYING);
> +		cma_release_remove(id_priv);
> +		rdma_destroy_id(&id_priv->id);
> +		return ret;
> +	}
> +
> +	cma_release_remove(id_priv);
> +	return ret;
> +}
> +
> +static int iw_conn_req_handler(struct iw_cm_id *cm_id, 
> +			       struct iw_cm_event *iw_event)
> +{
> +	struct rdma_cm_id *new_cm_id;
> +	struct rdma_id_private *listen_id, *conn_id;
> +	struct sockaddr_in *sin;
> +	struct net_device *dev;
> +	int ret;
> +
> +	listen_id = cm_id->context;
> +	atomic_inc(&listen_id->dev_remove);
> +	if (!cma_comp(listen_id, CMA_LISTEN)) {
> +		ret = -ECONNABORTED;
> +		goto out;
> +	}
> +
> +	/* Create a new RDMA id for the new IW CM ID */
> +	new_cm_id = rdma_create_id(listen_id->id.event_handler, 
> +				   listen_id->id.context,
> +				   RDMA_PS_TCP);
> +	if (!new_cm_id) {
> +		ret = -ENOMEM;
> +		goto out;
> +	}
> +	conn_id = container_of(new_cm_id, struct rdma_id_private, id);
> +	atomic_inc(&conn_id->dev_remove);
> +	conn_id->state = CMA_CONNECT;
> +

we take a reference on the iWARP device here that we never release

> +	dev = ip_dev_find(iw_event->local_addr.sin_addr.s_addr);
> +	if (!dev) {
> +		ret = -EADDRNOTAVAIL;
> +		rdma_destroy_id(new_cm_id);
> +		goto out;
> +	}
> +	ret = rdma_copy_addr(&conn_id->id.route.addr.dev_addr, dev, NULL);
> +	if (ret) {
> +		rdma_destroy_id(new_cm_id);
> +		goto out;
> +	}
> +
> +	ret = cma_acquire_dev(conn_id);
> +	if (ret) {
> +		rdma_destroy_id(new_cm_id);
> +		goto out;
> +	}
> +
> +	conn_id->cm_id.iw = cm_id;
> +	cm_id->context = conn_id;
> +	cm_id->cm_handler = cma_iw_handler;
> +
> +	sin = (struct sockaddr_in *) &new_cm_id->route.addr.src_addr;
> +	*sin = iw_event->local_addr;
> +	sin = (struct sockaddr_in *) &new_cm_id->route.addr.dst_addr;
> +	*sin = iw_event->remote_addr;
> +
> +	ret = cma_notify_user(conn_id, RDMA_CM_EVENT_CONNECT_REQUEST, 0,
> +			      iw_event->private_data,
> +			      iw_event->private_data_len);
> +	if (ret) {
> +		/* User wants to destroy the CM ID */
> +		conn_id->cm_id.iw = NULL;
> +		cma_exch(conn_id, CMA_DESTROYING);
> +		cma_release_remove(conn_id);
> +		rdma_destroy_id(&conn_id->id);
> +	}
> +
> +out:

We need to put a dev_put here or the reference on the device will never
get released and you won't be able to remove it after you've had at
least one connection. This is my bug....

	dev_put(dev);

> +	cma_release_remove(listen_id);
> +	return ret;
> +}
> +
>  static int cma_ib_listen(struct rdma_id_private *id_priv)
>  {
>  	struct ib_cm_compare_data compare_data;
> @@ -1010,6 +1155,30 @@ static int cma_ib_listen(struct rdma_id_
>  	return ret;
>  }
>  
> +static int cma_iw_listen(struct rdma_id_private *id_priv, int backlog)
> +{
> +	int ret;
> +	struct sockaddr_in *sin;
> +
> +	id_priv->cm_id.iw = iw_create_cm_id(id_priv->id.device, 
> +					    iw_conn_req_handler,
> +					    id_priv);
> +	if (IS_ERR(id_priv->cm_id.iw))
> +		return PTR_ERR(id_priv->cm_id.iw);
> +
> +	sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr;
> +	id_priv->cm_id.iw->local_addr = *sin;
> +
> +	ret = iw_cm_listen(id_priv->cm_id.iw, backlog);
> +
> +	if (ret) {
> +		iw_destroy_cm_id(id_priv->cm_id.iw);
> +		id_priv->cm_id.iw = NULL;
> +	}
> +
> +	return ret;
> +}
> +
>  static int cma_listen_handler(struct rdma_cm_id *id,
>  			      struct rdma_cm_event *event)
>  {
> @@ -1085,12 +1254,17 @@ int rdma_listen(struct rdma_cm_id *id, i
>  		return -EINVAL;
>  
>  	if (id->device) {
> -		switch (id->device->node_type) {
> -		case IB_NODE_CA:
> +		switch (rdma_node_get_transport(id->device->node_type)) {
> +		case RDMA_TRANSPORT_IB:
>  			ret = cma_ib_listen(id_priv);
>  			if (ret)
>  				goto err;
>  			break;
> +		case RDMA_TRANSPORT_IWARP:
> +			ret = cma_iw_listen(id_priv, backlog);
> +			if (ret)
> +				goto err;
> +			break;
>  		default:
>  			ret = -ENOSYS;
>  			goto err;
> @@ -1229,6 +1403,23 @@ err:
>  }
>  EXPORT_SYMBOL(rdma_set_ib_paths);
>  
> +static int cma_resolve_iw_route(struct rdma_id_private *id_priv, int timeout_ms)
> +{
> +	struct cma_work *work;
> +
> +	work = kzalloc(sizeof *work, GFP_KERNEL);
> +	if (!work)
> +		return -ENOMEM;
> +
> +	work->id = id_priv;
> +	INIT_WORK(&work->work, cma_work_handler, work);
> +	work->old_state = CMA_ROUTE_QUERY;
> +	work->new_state = CMA_ROUTE_RESOLVED;
> +	work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED;
> +	queue_work(cma_wq, &work->work);
> +	return 0;
> +}
> +
>  int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)
>  {
>  	struct rdma_id_private *id_priv;
> @@ -1239,10 +1430,13 @@ int rdma_resolve_route(struct rdma_cm_id
>  		return -EINVAL;
>  
>  	atomic_inc(&id_priv->refcount);
> -	switch (id->device->node_type) {
> -	case IB_NODE_CA:
> +	switch (rdma_node_get_transport(id->device->node_type)) {
> +	case RDMA_TRANSPORT_IB:
>  		ret = cma_resolve_ib_route(id_priv, timeout_ms);
>  		break;
> +	case RDMA_TRANSPORT_IWARP:
> +		ret = cma_resolve_iw_route(id_priv, timeout_ms);
> +		break;
>  	default:
>  		ret = -ENOSYS;
>  		break;
> @@ -1354,8 +1548,8 @@ static int cma_resolve_loopback(struct r
>  			 ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr));
>  
>  	if (cma_zero_addr(&id_priv->id.route.addr.src_addr)) {
> -		src_in = (struct sockaddr_in *)&id_priv->id.route.addr.src_addr;
> -		dst_in = (struct sockaddr_in *)&id_priv->id.route.addr.dst_addr;
> +		src_in = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr;
> +		dst_in = (struct sockaddr_in *) &id_priv->id.route.addr.dst_addr;
>  		src_in->sin_family = dst_in->sin_family;
>  		src_in->sin_addr.s_addr = dst_in->sin_addr.s_addr;
>  	}
> @@ -1646,6 +1840,47 @@ out:
>  	return ret;
>  }
>  
> +static int cma_connect_iw(struct rdma_id_private *id_priv,
> +			  struct rdma_conn_param *conn_param)
> +{
> +	struct iw_cm_id *cm_id;
> +	struct sockaddr_in* sin;
> +	int ret;
> +	struct iw_cm_conn_param iw_param;
> +
> +	cm_id = iw_create_cm_id(id_priv->id.device, cma_iw_handler, id_priv);
> +	if (IS_ERR(cm_id)) {
> +		ret = PTR_ERR(cm_id);
> +		goto out;
> +	}
> +
> +	id_priv->cm_id.iw = cm_id;
> +
> +	sin = (struct sockaddr_in*) &id_priv->id.route.addr.src_addr;
> +	cm_id->local_addr = *sin;
> +
> +	sin = (struct sockaddr_in*) &id_priv->id.route.addr.dst_addr;
> +	cm_id->remote_addr = *sin;
> +
> +	ret = cma_modify_qp_rtr(&id_priv->id);
> +	if (ret) {
> +		iw_destroy_cm_id(cm_id);
> +		return ret;
> +	}
> +
> +	iw_param.ord = conn_param->initiator_depth;
> +	iw_param.ird = conn_param->responder_resources;
> +	iw_param.private_data = conn_param->private_data;
> +	iw_param.private_data_len = conn_param->private_data_len;
> +	if (id_priv->id.qp)
> +		iw_param.qpn = id_priv->qp_num;
> +	else 
> +		iw_param.qpn = conn_param->qp_num;
> +	ret = iw_cm_connect(cm_id, &iw_param);
> +out:
> +	return ret;
> +}
> +
>  int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
>  {
>  	struct rdma_id_private *id_priv;
> @@ -1661,10 +1896,13 @@ int rdma_connect(struct rdma_cm_id *id, 
>  		id_priv->srq = conn_param->srq;
>  	}
>  
> -	switch (id->device->node_type) {
> -	case IB_NODE_CA:
> +	switch (rdma_node_get_transport(id->device->node_type)) {
> +	case RDMA_TRANSPORT_IB:
>  		ret = cma_connect_ib(id_priv, conn_param);
>  		break;
> +	case RDMA_TRANSPORT_IWARP:
> +		ret = cma_connect_iw(id_priv, conn_param);
> +		break;
>  	default:
>  		ret = -ENOSYS;
>  		break;
> @@ -1705,6 +1943,28 @@ static int cma_accept_ib(struct rdma_id_
>  	return ib_send_cm_rep(id_priv->cm_id.ib, &rep);
>  }
>  
> +static int cma_accept_iw(struct rdma_id_private *id_priv, 
> +		  struct rdma_conn_param *conn_param)
> +{
> +	struct iw_cm_conn_param iw_param;
> +	int ret;
> +
> +	ret = cma_modify_qp_rtr(&id_priv->id);
> +	if (ret)
> +		return ret;
> +
> +	iw_param.ord = conn_param->initiator_depth;
> +	iw_param.ird = conn_param->responder_resources;
> +	iw_param.private_data = conn_param->private_data;
> +	iw_param.private_data_len = conn_param->private_data_len;
> +	if (id_priv->id.qp) {
> +		iw_param.qpn = id_priv->qp_num;
> +	} else 
> +		iw_param.qpn = conn_param->qp_num;
> +
> +	return iw_cm_accept(id_priv->cm_id.iw, &iw_param);
> +}
> +
>  int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
>  {
>  	struct rdma_id_private *id_priv;
> @@ -1720,13 +1980,16 @@ int rdma_accept(struct rdma_cm_id *id, s
>  		id_priv->srq = conn_param->srq;
>  	}
>  
> -	switch (id->device->node_type) {
> -	case IB_NODE_CA:
> +	switch (rdma_node_get_transport(id->device->node_type)) {
> +	case RDMA_TRANSPORT_IB:
>  		if (conn_param)
>  			ret = cma_accept_ib(id_priv, conn_param);
>  		else
>  			ret = cma_rep_recv(id_priv);
>  		break;
> +	case RDMA_TRANSPORT_IWARP:
> +		ret = cma_accept_iw(id_priv, conn_param);
> +		break;
>  	default:
>  		ret = -ENOSYS;
>  		break;
> @@ -1753,12 +2016,16 @@ int rdma_reject(struct rdma_cm_id *id, c
>  	if (!cma_comp(id_priv, CMA_CONNECT))
>  		return -EINVAL;
>  
> -	switch (id->device->node_type) {
> -	case IB_NODE_CA:
> +	switch (rdma_node_get_transport(id->device->node_type)) {
> +	case RDMA_TRANSPORT_IB:
>  		ret = ib_send_cm_rej(id_priv->cm_id.ib,
>  				     IB_CM_REJ_CONSUMER_DEFINED, NULL, 0,
>  				     private_data, private_data_len);
>  		break;
> +	case RDMA_TRANSPORT_IWARP: 
> +		ret = iw_cm_reject(id_priv->cm_id.iw, 
> +				   private_data, private_data_len);
> +		break;
>  	default:
>  		ret = -ENOSYS;
>  		break;
> @@ -1777,16 +2044,18 @@ int rdma_disconnect(struct rdma_cm_id *i
>  	    !cma_comp(id_priv, CMA_DISCONNECT))
>  		return -EINVAL;
>  
> -	ret = cma_modify_qp_err(id);
> -	if (ret)
> -		goto out;
> -
> -	switch (id->device->node_type) {
> -	case IB_NODE_CA:
> +	switch (rdma_node_get_transport(id->device->node_type)) {
> +	case RDMA_TRANSPORT_IB:
> +		ret = cma_modify_qp_err(id);
> +		if (ret)
> +			goto out;
>  		/* Initiate or respond to a disconnect. */
>  		if (ib_send_cm_dreq(id_priv->cm_id.ib, NULL, 0))
>  			ib_send_cm_drep(id_priv->cm_id.ib, NULL, 0);
>  		break;
> +	case RDMA_TRANSPORT_IWARP:
> +		ret = iw_cm_disconnect(id_priv->cm_id.iw, 0);
> +		break;
>  	default:
>  		break;
>  	}
> diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
> index b2f3cb9..7318fba 100644
> --- a/drivers/infiniband/core/device.c
> +++ b/drivers/infiniband/core/device.c
> @@ -30,7 +30,7 @@
>   * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
>   * SOFTWARE.
>   *
> - * $Id: device.c 1349 2004-12-16 21:09:43Z roland $
> + * $Id: device.c 5943 2006-03-22 00:58:04Z roland $
>   */
>  
>  #include <linux/module.h>
> @@ -505,7 +505,7 @@ int ib_query_port(struct ib_device *devi
>  		  u8 port_num,
>  		  struct ib_port_attr *port_attr)
>  {
> -	if (device->node_type == IB_NODE_SWITCH) {
> +	if (device->node_type == RDMA_NODE_IB_SWITCH) {
>  		if (port_num)
>  			return -EINVAL;
>  	} else if (port_num < 1 || port_num > device->phys_port_cnt)
> @@ -580,7 +580,7 @@ int ib_modify_port(struct ib_device *dev
>  		   u8 port_num, int port_modify_mask,
>  		   struct ib_port_modify *port_modify)
>  {
> -	if (device->node_type == IB_NODE_SWITCH) {
> +	if (device->node_type == RDMA_NODE_IB_SWITCH) {
>  		if (port_num)
>  			return -EINVAL;
>  	} else if (port_num < 1 || port_num > device->phys_port_cnt)
> diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
> index b38e02a..a928ecf 100644
> --- a/drivers/infiniband/core/mad.c
> +++ b/drivers/infiniband/core/mad.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved.
> + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.
>   * Copyright (c) 2005 Intel Corporation.  All rights reserved.
>   * Copyright (c) 2005 Mellanox Technologies Ltd.  All rights reserved.
>   *
> @@ -31,7 +31,7 @@
>   * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
>   * SOFTWARE.
>   *
> - * $Id: mad.c 5596 2006-03-03 01:00:07Z sean.hefty $
> + * $Id: mad.c 7294 2006-05-17 18:12:30Z roland $
>   */
>  #include <linux/dma-mapping.h>
>  #include <rdma/ib_cache.h>
> @@ -2877,7 +2877,10 @@ static void ib_mad_init_device(struct ib
>  {
>  	int start, end, i;
>  
> -	if (device->node_type == IB_NODE_SWITCH) {
> +	if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
> +		return;
> +
> +	if (device->node_type == RDMA_NODE_IB_SWITCH) {
>  		start = 0;
>  		end   = 0;
>  	} else {
> @@ -2924,7 +2927,7 @@ static void ib_mad_remove_device(struct 
>  {
>  	int i, num_ports, cur_port;
>  
> -	if (device->node_type == IB_NODE_SWITCH) {
> +	if (device->node_type == RDMA_NODE_IB_SWITCH) {
>  		num_ports = 1;
>  		cur_port = 0;
>  	} else {
> diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
> index 501cc05..4230277 100644
> --- a/drivers/infiniband/core/sa_query.c
> +++ b/drivers/infiniband/core/sa_query.c
> @@ -887,7 +887,10 @@ static void ib_sa_add_one(struct ib_devi
>  	struct ib_sa_device *sa_dev;
>  	int s, e, i;
>  
> -	if (device->node_type == IB_NODE_SWITCH)
> +	if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
> +		return;
> +
> +	if (device->node_type == RDMA_NODE_IB_SWITCH)
>  		s = e = 0;
>  	else {
>  		s = 1;
> diff --git a/drivers/infiniband/core/smi.c b/drivers/infiniband/core/smi.c
> index 35852e7..b81b2b9 100644
> --- a/drivers/infiniband/core/smi.c
> +++ b/drivers/infiniband/core/smi.c
> @@ -34,7 +34,7 @@
>   * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
>   * SOFTWARE.
>   *
> - * $Id: smi.c 1389 2004-12-27 22:56:47Z roland $
> + * $Id: smi.c 5258 2006-02-01 20:32:40Z sean.hefty $
>   */
>  
>  #include <rdma/ib_smi.h>
> @@ -64,7 +64,7 @@ int smi_handle_dr_smp_send(struct ib_smp
>  
>  		/* C14-9:2 */
>  		if (hop_ptr && hop_ptr < hop_cnt) {
> -			if (node_type != IB_NODE_SWITCH)
> +			if (node_type != RDMA_NODE_IB_SWITCH)
>  				return 0;
>  
>  			/* smp->return_path set when received */
> @@ -77,7 +77,7 @@ int smi_handle_dr_smp_send(struct ib_smp
>  		if (hop_ptr == hop_cnt) {
>  			/* smp->return_path set when received */
>  			smp->hop_ptr++;
> -			return (node_type == IB_NODE_SWITCH ||
> +			return (node_type == RDMA_NODE_IB_SWITCH ||
>  				smp->dr_dlid == IB_LID_PERMISSIVE);
>  		}
>  
> @@ -95,7 +95,7 @@ int smi_handle_dr_smp_send(struct ib_smp
>  
>  		/* C14-13:2 */
>  		if (2 <= hop_ptr && hop_ptr <= hop_cnt) {
> -			if (node_type != IB_NODE_SWITCH)
> +			if (node_type != RDMA_NODE_IB_SWITCH)
>  				return 0;
>  
>  			smp->hop_ptr--;
> @@ -107,7 +107,7 @@ int smi_handle_dr_smp_send(struct ib_smp
>  		if (hop_ptr == 1) {
>  			smp->hop_ptr--;
>  			/* C14-13:3 -- SMPs destined for SM shouldn't be here */
> -			return (node_type == IB_NODE_SWITCH ||
> +			return (node_type == RDMA_NODE_IB_SWITCH ||
>  				smp->dr_slid == IB_LID_PERMISSIVE);
>  		}
>  
> @@ -142,7 +142,7 @@ int smi_handle_dr_smp_recv(struct ib_smp
>  
>  		/* C14-9:2 -- intermediate hop */
>  		if (hop_ptr && hop_ptr < hop_cnt) {
> -			if (node_type != IB_NODE_SWITCH)
> +			if (node_type != RDMA_NODE_IB_SWITCH)
>  				return 0;
>  
>  			smp->return_path[hop_ptr] = port_num;
> @@ -156,7 +156,7 @@ int smi_handle_dr_smp_recv(struct ib_smp
>  				smp->return_path[hop_ptr] = port_num;
>  			/* smp->hop_ptr updated when sending */
>  
> -			return (node_type == IB_NODE_SWITCH ||
> +			return (node_type == RDMA_NODE_IB_SWITCH ||
>  				smp->dr_dlid == IB_LID_PERMISSIVE);
>  		}
>  
> @@ -175,7 +175,7 @@ int smi_handle_dr_smp_recv(struct ib_smp
>  
>  		/* C14-13:2 */
>  		if (2 <= hop_ptr && hop_ptr <= hop_cnt) {
> -			if (node_type != IB_NODE_SWITCH)
> +			if (node_type != RDMA_NODE_IB_SWITCH)
>  				return 0;
>  
>  			/* smp->hop_ptr updated when sending */
> @@ -190,7 +190,7 @@ int smi_handle_dr_smp_recv(struct ib_smp
>  				return 1;
>  			}
>  			/* smp->hop_ptr updated when sending */
> -			return (node_type == IB_NODE_SWITCH);
> +			return (node_type == RDMA_NODE_IB_SWITCH);
>  		}
>  
>  		/* C14-13:4 -- hop_ptr = 0 -> give to SM */
> diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
> index 21f9282..cfd2c06 100644
> --- a/drivers/infiniband/core/sysfs.c
> +++ b/drivers/infiniband/core/sysfs.c
> @@ -31,7 +31,7 @@
>   * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
>   * SOFTWARE.
>   *
> - * $Id: sysfs.c 1349 2004-12-16 21:09:43Z roland $
> + * $Id: sysfs.c 6940 2006-05-04 17:04:55Z roland $
>   */
>  
>  #include "core_priv.h"
> @@ -589,10 +589,16 @@ static ssize_t show_node_type(struct cla
>  		return -ENODEV;
>  
>  	switch (dev->node_type) {
> -	case IB_NODE_CA:     return sprintf(buf, "%d: CA\n", dev->node_type);
> -	case IB_NODE_SWITCH: return sprintf(buf, "%d: switch\n", dev->node_type);
> -	case IB_NODE_ROUTER: return sprintf(buf, "%d: router\n", dev->node_type);
> -	default:             return sprintf(buf, "%d: <unknown>\n", dev->node_type);
> +	case RDMA_NODE_IB_CA:
> +		return sprintf(buf, "%d: CA\n", dev->node_type);
> +	case RDMA_NODE_RNIC:
> +		return sprintf(buf, "%d: RNIC\n", dev->node_type);
> +	case RDMA_NODE_IB_SWITCH:
> +		return sprintf(buf, "%d: switch\n", dev->node_type);
> +	case RDMA_NODE_IB_ROUTER:
> +		return sprintf(buf, "%d: router\n", dev->node_type);
> +	default:
> +		return sprintf(buf, "%d: <unknown>\n", dev->node_type);
>  	}
>  }
>  
> @@ -708,7 +714,7 @@ int ib_device_register_sysfs(struct ib_d
>  	if (ret)
>  		goto err_put;
>  
> -	if (device->node_type == IB_NODE_SWITCH) {
> +	if (device->node_type == RDMA_NODE_IB_SWITCH) {
>  		ret = add_port(device, 0);
>  		if (ret)
>  			goto err_put;
> diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c
> index 67caf36..ad2e417 100644
> --- a/drivers/infiniband/core/ucm.c
> +++ b/drivers/infiniband/core/ucm.c
> @@ -30,7 +30,7 @@
>   * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
>   * SOFTWARE.
>   *
> - * $Id: ucm.c 4311 2005-12-05 18:42:01Z sean.hefty $
> + * $Id: ucm.c 7119 2006-05-11 16:40:38Z sean.hefty $
>   */
>  
>  #include <linux/completion.h>
> @@ -1248,7 +1248,8 @@ static void ib_ucm_add_one(struct ib_dev
>  {
>  	struct ib_ucm_device *ucm_dev;
>  
> -	if (!device->alloc_ucontext)
> +	if (!device->alloc_ucontext ||
> +	    rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
>  		return;
>  
>  	ucm_dev = kzalloc(sizeof *ucm_dev, GFP_KERNEL);
> diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
> index afe70a5..0cbd692 100644
> --- a/drivers/infiniband/core/user_mad.c
> +++ b/drivers/infiniband/core/user_mad.c
> @@ -1,6 +1,6 @@
>  /*
>   * Copyright (c) 2004 Topspin Communications.  All rights reserved.
> - * Copyright (c) 2005 Voltaire, Inc. All rights reserved. 
> + * Copyright (c) 2005-2006 Voltaire, Inc. All rights reserved. 
>   * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
>   *
>   * This software is available to you under a choice of one of two
> @@ -31,7 +31,7 @@
>   * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
>   * SOFTWARE.
>   *
> - * $Id: user_mad.c 5596 2006-03-03 01:00:07Z sean.hefty $
> + * $Id: user_mad.c 6041 2006-03-27 21:06:00Z halr $
>   */
>  
>  #include <linux/module.h>
> @@ -967,7 +967,10 @@ static void ib_umad_add_one(struct ib_de
>  	struct ib_umad_device *umad_dev;
>  	int s, e, i;
>  
> -	if (device->node_type == IB_NODE_SWITCH)
> +	if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
> +		return;
> +
> +	if (device->node_type == RDMA_NODE_IB_SWITCH)
>  		s = e = 0;
>  	else {
>  		s = 1;
> diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c
> index 28fdbda..e4b45d7 100644
> --- a/drivers/infiniband/hw/ipath/ipath_verbs.c
> +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c
> @@ -984,7 +984,7 @@ static void *ipath_register_ib_device(in
>  		(1ull << IB_USER_VERBS_CMD_QUERY_SRQ)		|
>  		(1ull << IB_USER_VERBS_CMD_DESTROY_SRQ)		|
>  		(1ull << IB_USER_VERBS_CMD_POST_SRQ_RECV);
> -	dev->node_type = IB_NODE_CA;
> +	dev->node_type = RDMA_NODE_IB_CA;
>  	dev->phys_port_cnt = 1;
>  	dev->dma_device = ipath_layer_get_device(dd);
>  	dev->class_dev.dev = dev->dma_device;
> diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
> index a2eae8a..5c31819 100644
> --- a/drivers/infiniband/hw/mthca/mthca_provider.c
> +++ b/drivers/infiniband/hw/mthca/mthca_provider.c
> @@ -1273,7 +1273,7 @@ int mthca_register_device(struct mthca_d
>  		(1ull << IB_USER_VERBS_CMD_MODIFY_SRQ)		|
>  		(1ull << IB_USER_VERBS_CMD_QUERY_SRQ)		|
>  		(1ull << IB_USER_VERBS_CMD_DESTROY_SRQ);
> -	dev->ib_dev.node_type            = IB_NODE_CA;
> +	dev->ib_dev.node_type            = RDMA_NODE_IB_CA;
>  	dev->ib_dev.phys_port_cnt        = dev->limits.num_ports;
>  	dev->ib_dev.dma_device           = &dev->pdev->dev;
>  	dev->ib_dev.class_dev.dev        = &dev->pdev->dev;
> diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
> index 1c6ea1c..262427f 100644
> --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
> +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
> @@ -1084,13 +1084,16 @@ static void ipoib_add_one(struct ib_devi
>  	struct ipoib_dev_priv *priv;
>  	int s, e, p;
>  
> +	if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
> +		return;
> +
>  	dev_list = kmalloc(sizeof *dev_list, GFP_KERNEL);
>  	if (!dev_list)
>  		return;
>  
>  	INIT_LIST_HEAD(dev_list);
>  
> -	if (device->node_type == IB_NODE_SWITCH) {
> +	if (device->node_type == RDMA_NODE_IB_SWITCH) {
>  		s = 0;
>  		e = 0;
>  	} else {
> @@ -1114,6 +1117,9 @@ static void ipoib_remove_one(struct ib_d
>  	struct ipoib_dev_priv *priv, *tmp;
>  	struct list_head *dev_list;
>  
> +	if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
> +		return;
> +
>  	dev_list = ib_get_client_data(device, &ipoib_client);
>  
>  	list_for_each_entry_safe(priv, tmp, dev_list, list) {
> diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
> index f1401e1..bba2956 100644
> --- a/drivers/infiniband/ulp/srp/ib_srp.c
> +++ b/drivers/infiniband/ulp/srp/ib_srp.c
> @@ -1845,7 +1845,7 @@ static void srp_add_one(struct ib_device
>  	if (IS_ERR(srp_dev->fmr_pool))
>  		srp_dev->fmr_pool = NULL;
>  
> -	if (device->node_type == IB_NODE_SWITCH) {
> +	if (device->node_type == RDMA_NODE_IB_SWITCH) {
>  		s = 0;
>  		e = 0;
>  	} else {
> diff --git a/include/rdma/ib_addr.h b/include/rdma/ib_addr.h
> index fcb5ba8..d95d3eb 100644
> --- a/include/rdma/ib_addr.h
> +++ b/include/rdma/ib_addr.h
> @@ -40,7 +40,7 @@ struct rdma_dev_addr {
>  	unsigned char src_dev_addr[MAX_ADDR_LEN];
>  	unsigned char dst_dev_addr[MAX_ADDR_LEN];
>  	unsigned char broadcast[MAX_ADDR_LEN];
> -	enum ib_node_type dev_type;
> +	enum rdma_node_type dev_type;
>  };
>  
>  /**
> @@ -72,6 +72,9 @@ int rdma_resolve_ip(struct sockaddr *src
>  
>  void rdma_addr_cancel(struct rdma_dev_addr *addr);
>  
> +int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev,
> +	      const unsigned char *dst_dev_addr);
> +
>  static inline int ip_addr_size(struct sockaddr *addr)
>  {
>  	return addr->sa_family == AF_INET6 ?
> @@ -111,4 +114,14 @@ static inline void ib_addr_set_dgid(stru
>  	memcpy(dev_addr->dst_dev_addr + 4, gid, sizeof *gid);
>  }
>  
> +static inline union ib_gid* iw_addr_get_sgid(struct rdma_dev_addr* rda)
> +{
> +	return (union ib_gid *) rda->src_dev_addr;
> +}
> +
> +static inline union ib_gid* iw_addr_get_dgid(struct rdma_dev_addr* rda)
> +{
> +	return (union ib_gid *) rda->dst_dev_addr;
> +}
> +
>  #endif /* IB_ADDR_H */
> diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
> index aeb4fcd..eac2d8f 100644
> --- a/include/rdma/ib_verbs.h
> +++ b/include/rdma/ib_verbs.h
> @@ -35,7 +35,7 @@
>   * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
>   * SOFTWARE.
>   *
> - * $Id: ib_verbs.h 1349 2004-12-16 21:09:43Z roland $
> + * $Id: ib_verbs.h 6885 2006-05-03 18:22:02Z sean.hefty $
>   */
>  
>  #if !defined(IB_VERBS_H)
> @@ -56,12 +56,35 @@ union ib_gid {
>  	} global;
>  };
>  
> -enum ib_node_type {
> -	IB_NODE_CA 	= 1,
> -	IB_NODE_SWITCH,
> -	IB_NODE_ROUTER
> +enum rdma_node_type {
> +	/* IB values map to NodeInfo:NodeType. */
> +	RDMA_NODE_IB_CA 	= 1,
> +	RDMA_NODE_IB_SWITCH,
> +	RDMA_NODE_IB_ROUTER,
> +	RDMA_NODE_RNIC
>  };
>  
> +enum rdma_transport_type {
> +	RDMA_TRANSPORT_IB,
> +	RDMA_TRANSPORT_IWARP
> +};
> +
> +static inline enum rdma_transport_type
> +rdma_node_get_transport(enum rdma_node_type node_type)
> +{
> +	switch (node_type) {
> +	case RDMA_NODE_IB_CA:
> +	case RDMA_NODE_IB_SWITCH:
> +	case RDMA_NODE_IB_ROUTER:
> +		return RDMA_TRANSPORT_IB;
> +	case RDMA_NODE_RNIC:
> +		return RDMA_TRANSPORT_IWARP;
> +	default:
> +		BUG();
> +		return 0;
> +	}
> +}
> +
>  enum ib_device_cap_flags {
>  	IB_DEVICE_RESIZE_MAX_WR		= 1,
>  	IB_DEVICE_BAD_PKEY_CNTR		= (1<<1),
> @@ -78,6 +101,9 @@ enum ib_device_cap_flags {
>  	IB_DEVICE_RC_RNR_NAK_GEN	= (1<<12),
>  	IB_DEVICE_SRQ_RESIZE		= (1<<13),
>  	IB_DEVICE_N_NOTIFY_CQ		= (1<<14),
> +	IB_DEVICE_ZERO_STAG		= (1<<15),
> +	IB_DEVICE_SEND_W_INV		= (1<<16),
> +	IB_DEVICE_MEM_WINDOW		= (1<<17)
>  };
>  
>  enum ib_atomic_cap {
> @@ -830,6 +856,7 @@ struct ib_cache {
>  	u8                     *lmc_cache;
>  };
>  
> +struct iw_cm_verbs;
>  struct ib_device {
>  	struct device                *dma_device;
>  
> @@ -846,6 +873,8 @@ struct ib_device {
>  
>  	u32                           flags;
>  
> +	struct iw_cm_verbs	     *iwcm;
> +
>  	int		           (*query_device)(struct ib_device *device,
>  						   struct ib_device_attr *device_attr);
>  	int		           (*query_port)(struct ib_device *device,
> -
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply

* Re: [PATCH] pcnet32 driver NAPI support
From: Don Fry @ 2006-06-07 21:52 UTC (permalink / raw)
  To: Lennart Sorensen; +Cc: netdev
In-Reply-To: <20060607193456.GN7857@csclub.uwaterloo.ca>

On Wed, Jun 07, 2006 at 03:34:56PM -0400, Lennart Sorensen wrote:
> On Wed, Jun 07, 2006 at 11:20:40AM -0700, Don Fry wrote:
> 
> > Some areas of concern that you may have addressed already, I have not
> > scanned your changes yet, are what happens if the ring size is changed
> > without bringing down the interface (via ethtool), or if the loopback
> > test is run in a similar fashion, or a tx timeout occurs.
> 
> The same thing as if it was done before enabling napi.  From a few
> messages I have seen, it doesn't work right now, and it won't work any
> better with my changes.  I have never tried changing the ring size on
> the fly, so I don't know.

Today without your NAPI changes the device can be up and operational,
and change the ring size without hanging or causing a panic or causing
problems with the driver.  The same can be said for running the loopback
test, or when a tx timeout occurs.

It does not look like the same can be said for your NAPI changes, yet.
Try changing the ring size a dozen times during a receive storm and see
what happens.

> 
> It appears that the port is stopped before the ring size change is done,
> although I can't really tell how it handles things if the queue is not
> empty when it stops the port.  Does it try to handle anything left in
> the ring first or does it just toss those packets? (That I would
> consider wrong).
> 
> > The lp->lock MUST be held whenever accessing the csr or bcr registers as
> > this is a multi-step process, and has been the source of problems in the
> > past.  Even on UP systems.
> 
> Hmm, I just followed what appeared to be in pcnet32_rx and how tulip and
> a few other drivers had done their napi conversions.  It certainly works
> for me the way I did it.  Haven't seen any lockups yet.  I do see that I
> am not holding the lock when I acknowledge IRQs in pcnet32_poll, which
> pcnet32_rx doesn't need to worry about since it is called from the
> interrupt handler which already holds the lock.  That should be fixed
> then.

Yes, that is the minimum that needs to be changed.
There have been a lot of changes made to the driver, by myself included,
that seem to work just fine, but later the timing changes and you lose
the race, resulting in problems.  Changing one part of the driver
without understanding the whole thing is very risky.

> 
> So I can do:
>         // Clear RX interrupts
>         spin_lock(&lp->lock);
>         lp->a.write_csr (ioaddr, 0, 0x1400);
>         spin_unlock(&lp->lock);
> That part seems simple enough to protect.
> 
> Is this safe without holding the lock?
>     } while(lp->a.read_csr (ioaddr, 0) & 0x1400);

No, see below.

> Not sure how to wrap a lock around that one without holding the lock for
> way too long.
> 
> perhaps:
>         spin_lock(&lp->lock);
> 	state=lp->a.read_csr (ioaddr, 0) & 0x1400;
>         spin_unlock(&lp->lock);
>     } while(state);
> Does that seem more reasonable?

The lock must be held during ANY read or write to a csr or bcr.

The problem is that accessing a csr/bcr takes two steps.  One is to
write the address register indicating which register to read or write,
and second, read or write the register.  The problem is that without the
lock, entity A writes to the rap to access register X, then before it
can access that register entity B writes the rap to access register Y,
At that point entity A will read, or worse write, the contents of the
wrong register.

This problem is even worse when reading/writing a PHY register because
it entails writing bcr 33 and reading/writing bcr 34, without being
interrupted by something that might change bcr 33.  Not likely, but not
something that can be ignored.  It may not happen often, but it will
happen eventually.

> 
> Len Sorensen

-- 
Don Fry
brazilnut@us.ibm.com

^ permalink raw reply

* [PATCH] Updated Documentation/networking/ip-sysctl.txt
From: Robert Fitzsimons @ 2006-06-07 21:24 UTC (permalink / raw)
  To: Diego Calleja; +Cc: Stephen Hemminger, linux-kernel, netdev
In-Reply-To: <20060607225551.9b7e9688.diegocg@gmail.com>

Reformatted entries so they are now sorted alphabetical within a
/proc/sys/net/ sub-directory.
Synced with 2.6.17-rc6, added markers for new entries which are missing
a description or new descriptions which need to be checked.
Added some missing descriptions, also added descriptions suggested by
Stephen Hemminger <shemminger@osdl.org>.
Updated some existing descriptions.
Use consistant formatting and text wrapping, and updated default values
to match code.

Signed-off-by: Robert Fitzsimons <robfitz@273k.net>
---

Hello Diego

I was working on updating ip-sysctl.txt as a kernel-janitors project as
suggested by Stephen.

Here is my work so far.

Robert


 Documentation/networking/ip-sysctl.txt | 1565 +++++++++++++++++++-------------
 1 files changed, 907 insertions(+), 658 deletions(-)

diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index f12007b..94e6916 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -1,667 +1,822 @@
+/proc/sys/net/core/* Variables:
+
+dev_weight - INTEGER
+	TODO Add description.
+	Default: 64
+
+divert_version - STRING
+	TODO Check description.
+	String returned by DIVCMD_GETVERSION ioctl().
+	Default: 0.46
+
+message_burst - INTEGER
+	TODO Check description.
+	Allow a burst of message_burst network warning messages before the
+	rate limiting starts.  Also see message_cost.
+	Default: 10
+
+message_cost - INTEGER
+	TODO Check description.
+	Rate limit the number of network warning messages to one every
+	message_cost seconds.  Also see message_burst.
+	Default: 5
+
+netdev_budget - INTEGER
+	TODO Check description.
+	Maximum number of packets processed per device per softirq.  Used to
+	stop a device from overloading the system under massive packet load.
+	Default: 300
+
+netdev_max_backlog - INTEGER
+	TODO Check description.
+	Limit on the outstanding receive packets queued per cpu.  Applies to
+	non-NAPI devices only.
+	Default: 1000
+
+optmem_max - INTEGER
+	TODO Add description.
+
+rmem_default - INTEGER
+	TODO Add description.
+
+rmem_max - INTEGER
+	TODO Add description.
+
+somaxconn - INTEGER
+	Limit of socket listen() backlog, known in userspace as SOMAXCONN.
+	See also tcp_max_syn_backlog for additional tuning for TCP sockets.
+	Default: 128
+
+wmem_default - INTEGER
+	TODO Add description.
+
+wmem_max - INTEGER
+	TODO Add description.
+
+xfrm_aevent_etime - u32
+	TODO Add description.
+	Default: 10
+
+xfrm_aevent_rseqth - u32
+	TODO Add description.
+	Default: 2
+
+
 /proc/sys/net/ipv4/* Variables:
 
-ip_forward - BOOLEAN
-	0 - disabled (default)
-	not 0 - enabled 
+icmp_echo_ignore_all - BOOLEAN
+	If set non-zero, then the kernel will ignore all ICMP ECHO requests
+	sent to it.
+	Default: 0
 
-	Forward Packets between interfaces.
+icmp_echo_ignore_broadcasts - BOOLEAN
+	If set non-zero, then the kernel will ignore all ICMP ECHO and
+	TIMESTAMP requests sent to it via broadcast/multicast.
+	Default: 1
 
-	This variable is special, its change resets all configuration
-	parameters to their default state (RFC1122 for hosts, RFC1812
-	for routers)
+icmp_errors_use_inbound_ifaddr - BOOLEAN
+	If zero, ICMP error messages are sent with the primary address of
+	the exiting interface.
 
-ip_default_ttl - INTEGER
-	default 64
+	If non-zero, the message will be sent with the primary address of
+	the interface that received the packet that caused the ICMP error.
+	This is the behaviour network many administrators will expect from
+	a router.  And it can make debugging complicated network layouts
+	much easier.
 
-ip_no_pmtu_disc - BOOLEAN
-	Disable Path MTU Discovery.
-	default FALSE
+	Note that if no primary address exists for the interface selected,
+	then the primary address of the first non-loopback interface that
+	has one will be used regardless of this setting.
+	Default: 0
 
-min_pmtu - INTEGER
-	default 562 - minimum discovered Path MTU
+icmp_ignore_bogus_error_responses - BOOLEAN
+	Some routers violate RFC1122 by sending bogus responses to broadcast
+	frames.  Such violations are normally logged via a kernel warning.
+	If this is set to TRUE, the kernel will not give such warnings,
+	which will avoid log file clutter.
+	Default: 1
 
-mtu_expires - INTEGER
-	Time, in seconds, that cached PMTU information is kept.
+icmp_ratelimit - INTEGER
+	Limit the maximal rates for sending ICMP packets whose type matches
+	icmp_ratemask to specific targets.
+	0 to disable any limiting, otherwise the maximal rate in jiffies(1)
+	Default: jiffies in one second
 
-min_adv_mss - INTEGER
-	The advertised MSS depends on the first hop route MTU, but will
-	never be lower than this setting.
+icmp_ratemask - INTEGER
+	Mask made of ICMP types for which rates are being limited.
 
-IP Fragmentation:
+	Bit definitions (see include/linux/icmp.h):
+		0 Echo Reply
+		3 Destination Unreachable *
+		4 Source Quench *
+		5 Redirect
+		8 Echo Request
+		B Time Exceeded *
+		C Parameter Problem *
+		D Timestamp Request
+		E Timestamp Reply
+		F Info Request
+		G Info Reply
+		H Address Mask Request
+		I Address Mask Reply
+	* These are rate limited by default (see default mask above)
 
-ipfrag_high_thresh - INTEGER
-	Maximum memory used to reassemble IP fragments. When 
-	ipfrag_high_thresh bytes of memory is allocated for this purpose,
-	the fragment handler will toss packets until ipfrag_low_thresh
-	is reached.
-	
-ipfrag_low_thresh - INTEGER
-	See ipfrag_high_thresh	
+	Significant bits: IHGFEDCBA9876543210
+	Default mask:     0000001100000011000 (6168)
 
-ipfrag_time - INTEGER
-	Time in seconds to keep an IP fragment in memory.	
+igmp_max_memberships - INTEGER
+	Change the maximum number of multicast groups we can subscribe to.
+	Default: 20
 
-ipfrag_secret_interval - INTEGER
-	Regeneration interval (in seconds) of the hash secret (or lifetime 
-	for the hash secret) for IP fragments.
-	Default: 600
+igmp_max_msf - INTEGER
+	TODO Check description.
+	Limit on the number of multicast source filters.
+	Default: 10
 
-ipfrag_max_dist - INTEGER
-	ipfrag_max_dist is a non-negative integer value which defines the 
-	maximum "disorder" which is allowed among fragments which share a 
-	common IP source address. Note that reordering of packets is 
-	not unusual, but if a large number of fragments arrive from a source 
-	IP address while a particular fragment queue remains incomplete, it 
-	probably indicates that one or more fragments belonging to that queue 
-	have been lost. When ipfrag_max_dist is positive, an additional check 
-	is done on fragments before they are added to a reassembly queue - if 
-	ipfrag_max_dist (or more) fragments have arrived from a particular IP 
-	address between additions to any IP fragment queue using that source 
-	address, it's presumed that one or more fragments in the queue are 
-	lost. The existing fragment queue will be dropped, and a new one 
-	started. An ipfrag_max_dist value of zero disables this check.
+inet_peer_gc_maxtime - INTEGER
+	Maximum interval between garbage collection passes.  This interval
+	is in effect under low (or absent) memory pressure on the pool.
+	Default: 120 sec
 
-	Using a very small value, e.g. 1 or 2, for ipfrag_max_dist can
-	result in unnecessarily dropping fragment queues when normal
-	reordering of packets occurs, which could lead to poor application 
-	performance. Using a very large value, e.g. 50000, increases the 
-	likelihood of incorrectly reassembling IP fragments that originate 
-	from different IP datagrams, which could result in data corruption.
-	Default: 64
+inet_peer_gc_mintime - INTEGER
+	Minimum interval between garbage collection passes.  This interval
+	is in effect under high memory pressure on the pool.
+	Default: 10 sec
 
-INET peer storage:
+inet_peer_maxttl - INTEGER
+	Maximum time-to-live of entries.  Unused entries will expire after
+	this period of time if there is no memory pressure on the pool (i.e.
+	when the number of entries in the pool is very small).
+	Default: 600 sec
+
+inet_peer_minttl - INTEGER
+	Minimum time-to-live of entries.  Should be enough to cover fragment
+	time-to-live on the reassembling side.  This minimum time-to-live is
+	guaranteed if the pool size is less than inet_peer_threshold.
+	Default: 120 sec
 
 inet_peer_threshold - INTEGER
-	The approximate size of the storage.  Starting from this threshold	
+	The approximate size of the storage.  Starting from this threshold
 	entries will be thrown aggressively.  This threshold also determines
 	entries' time-to-live and time intervals between garbage collection
 	passes.  More entries, less time-to-live, less GC interval.
+	Default: dependent on system memory
 
-inet_peer_minttl - INTEGER
-	Minimum time-to-live of entries.  Should be enough to cover fragment
-	time-to-live on the reassembling side.  This minimum time-to-live  is
-	guaranteed if the pool size is less than inet_peer_threshold.
-	Measured in jiffies(1).
+ip_autoconfig - ????
+	TODO Add description.
 
-inet_peer_maxttl - INTEGER
-	Maximum time-to-live of entries.  Unused entries will expire after
-	this period of time if there is no memory pressure on the pool (i.e.
-	when the number of entries in the pool is very small).
-	Measured in jiffies(1).
+ip_default_ttl - INTEGER
+	Default: 64
 
-inet_peer_gc_mintime - INTEGER
-	Minimum interval between garbage collection passes.  This interval is
-	in effect under high memory pressure on the pool.
-	Measured in jiffies(1).
+ip_dynaddr - BOOLEAN
+	If non-zero, enables support for dynamic addresses.  If set to a
+	non-zero value larger than 1, a kernel log message will be printed
+	when dynamic address rewriting occurs.
+	Default: 0
 
-inet_peer_gc_maxtime - INTEGER
-	Minimum interval between garbage collection passes.  This interval is
-	in effect under low (or absent) memory pressure on the pool.
-	Measured in jiffies(1).
+ip_forward - BOOLEAN
+	If non-zero, forward packets between interfaces.  This variable is
+	special, its change resets all configuration parameters to their
+	default state (RFC1122 for hosts, RFC1812 for routers).
+	Default: 0
 
-TCP variables: 
+ipfrag_high_thresh - INTEGER
+	Maximum memory used to reassemble IP fragments.  When
+	ipfrag_high_thresh bytes of memory is allocated for this purpose,
+	the fragment handler will toss packets until ipfrag_low_thresh is
+	reached.
+	Default: 256k
+
+ipfrag_low_thresh - INTEGER
+	See ipfrag_high_thresh.
+	Default: 192k
+
+ipfrag_max_dist - INTEGER
+	ipfrag_max_dist is a non-negative integer value which defines the
+	maximum "disorder" which is allowed among fragments which share a
+	common IP source address.  Note that reordering of packets is not
+	unusual, but if a large number of fragments arrive from a source IP
+	address while a particular fragment queue remains incomplete, it
+	probably indicates that one or more fragments belonging to that
+	queue have been lost.
+	
+	When ipfrag_max_dist is positive, an additional check is done on
+	fragments before they are added to a reassembly queue - if
+	ipfrag_max_dist (or more) fragments have arrived from a particular
+	IP address between additions to any IP fragment queue using that
+	source address, it's presumed that one or more fragments in the
+	queue are lost.  The existing fragment queue will be dropped, and a
+	new one started.  An ipfrag_max_dist value of zero disables this
+	check.
+
+	Using a very small value, e.g. 1 or 2, for ipfrag_max_dist can
+	result in unnecessarily dropping fragment queues when normal
+	reordering of packets occurs, which could lead to poor application
+	performance.  Using a very large value, e.g. 50000, increases the
+	likelihood of incorrectly reassembling IP fragments that originate
+	from different IP datagrams, which could result in data corruption.
+	Default: 64
+
+ipfrag_secret_interval - INTEGER
+	Regeneration interval (in seconds) of the hash secret (or lifetime
+	for the hash secret) for IP fragments.
+	Default: 600
+
+ipfrag_time - INTEGER
+	Time in seconds to keep an IP fragment in memory.
+	Default: 30
+
+ip_local_port_range - 2 INTEGERS
+	Defines the local port range that is used by TCP and UDP to choose
+	the local port.  The first number is the first, the second the last
+	local port number.
+
+	This number defines number of active connections, which this system
+	can issue simultaneously to systems not supporting TCP extensions
+	(timestamps).  With tcp_tw_recycle enabled (i.e. by default) range
+	1024-4999 is enough to issue up to 2000 connections per second to
+	systems supporting timestamps.
+	Default: dependent on system memory
+	> 128Mb 32768-61000
+	< 128Mb 1024-4999 or even less.
+
+ip_nonlocal_bind - BOOLEAN
+	If set, allows processes to bind() to non-local IP addresses, which
+	can be quite useful - but may break some applications.
+	Default: 0
+
+ip_no_pmtu_disc - BOOLEAN
+	Disable Path MTU Discovery.
+	Default: 0
 
 tcp_abc - INTEGER
-	Controls Appropriate Byte Count defined in RFC3465. If set to
-	0 then does congestion avoid once per ack. 1 is conservative
-	value, and 2 is more agressive.
+	Controls Appropriate Byte Count defined in RFC3465.  If set to 0
+	then does congestion avoid once per ACK.  1 is conservative value,
+	and 2 is more aggressive.
+	Default: 1
 
-tcp_syn_retries - INTEGER
-	Number of times initial SYNs for an active TCP connection attempt
-	will be retransmitted. Should not be higher than 255. Default value
-	is 5, which corresponds to ~180seconds.
+tcp_abort_on_overflow - BOOLEAN
+	If listening service is too slow to accept new connections, reset
+	them.  It means that if overflow occurred due to a burst, connection
+	will recover.  Enable this option _only_ if you are really sure that
+	listening daemon cannot be tuned to accept connections faster.
+	Enabling this option can harm clients of your server.
+	Default: 0
 
-tcp_synack_retries - INTEGER
-	Number of times SYNACKs for a passive TCP connection attempt will
-	be retransmitted. Should not be higher than 255. Default value
-	is 5, which corresponds to ~180seconds.
+tcp_adv_win_scale - INTEGER
+	Count buffering overhead as bytes/2^tcp_adv_win_scale
+	(if tcp_adv_win_scale > 0) or bytes-bytes/2^(-tcp_adv_win_scale),
+	if it is <= 0.
+	Default: 2
 
-tcp_keepalive_time - INTEGER
-	How often TCP sends out keepalive messages when keepalive is enabled.
-	Default: 2hours.
+tcp_app_win - INTEGER
+	Reserve max(window/2^tcp_app_win, mss) of window for application
+	buffer.  Value 0 is special, it means that nothing is reserved.
+	Default: 31
 
-tcp_keepalive_probes - INTEGER
-	How many keepalive probes TCP sends out, until it decides that the
-	connection is broken. Default value: 9.
+tcp_base_mss - INTEGER
+	TODO Check description.
+	Lower bound for TCP path MTU discovery probing.
+	Default: 512
 
-tcp_keepalive_intvl - INTEGER
-	How frequently the probes are send out. Multiplied by
-	tcp_keepalive_probes it is time to kill not responding connection,
-	after probes started. Default value: 75sec i.e. connection
-	will be aborted after ~11 minutes of retries.
+tcp_congestion_control - STRING
+	Set the congestion control algorithm to be used for new connections.
+	The algorithm "reno" is always available, but additional choices may
+	be available based on kernel configuration.
 
-tcp_retries1 - INTEGER
-	How many times to retry before deciding that something is wrong
-	and it is necessary to report this suspicion to network layer.
-	Minimal RFC value is 3, it is default, which corresponds
-	to ~3sec-8min depending on RTO.
+tcp_dsack - BOOLEAN
+	Allows TCP to send "duplicate" SACKs.
+	Default: 1
 
-tcp_retries2 - INTEGER
-	How may times to retry before killing alive TCP connection.
-	RFC1122 says that the limit should be longer than 100 sec.
-	It is too small number.	Default value 15 corresponds to ~13-30min
-	depending on RTO.
+tcp_ecn - BOOLEAN
+	Enable Explicit Congestion Notification in TCP.
+	Default: 0
 
-tcp_orphan_retries - INTEGER
-	How may times to retry before killing TCP connection, closed
-	by our side. Default value 7 corresponds to ~50sec-16min
-	depending on RTO. If you machine is loaded WEB server,
-	you should think about lowering this value, such sockets
-	may consume significant resources. Cf. tcp_max_orphans.
+tcp_fack - BOOLEAN
+	Enable FACK congestion avoidance and fast retransmission.  The value
+	is not used, if tcp_sack is not enabled.
+	Default: 1
 
 tcp_fin_timeout - INTEGER
-	Time to hold socket in state FIN-WAIT-2, if it was closed
-	by our side. Peer can be broken and never close its side,
-	or even died unexpectedly. Default value is 60sec.
-	Usual value used in 2.2 was 180 seconds, you may restore
-	it, but remember that if your machine is even underloaded WEB server,
-	you risk to overflow memory with kilotons of dead sockets,
-	FIN-WAIT-2 sockets are less dangerous than FIN-WAIT-1,
-	because they eat maximum 1.5K of memory, but they tend
-	to live longer.	Cf. tcp_max_orphans.
+	Time in seconds to hold socket in state FIN-WAIT-2, if it was closed
+	by our side.  Peer can be broken and never close its side, or even
+	died unexpectedly.
+
+	Usual value used in 2.2 was 180 seconds, you may restore it, but
+	remember that if your machine is even underloaded WEB server, you
+	risk to overflow memory with kilotons of dead sockets, FIN-WAIT-2
+	sockets are less dangerous than FIN-WAIT-1, because they eat maximum
+	1.5K of memory, but they tend to live longer.  See tcp_max_orphans.
+	Default: 60
 
-tcp_max_tw_buckets - INTEGER
-	Maximal number of timewait sockets held by system simultaneously.
-	If this number is exceeded time-wait socket is immediately destroyed
-	and warning is printed. This limit exists only to prevent
-	simple DoS attacks, you _must_ not lower the limit artificially,
-	but rather increase it (probably, after increasing installed memory),
-	if network conditions require more than default value.
+tcp_frto - BOOLEAN
+	Enables F-RTO, an enhanced recovery algorithm for TCP retransmission
+	timeouts.  It is particularly beneficial in wireless environments
+	where packet loss is typically due to random radio interference
+	rather than intermediate router congestion.
+	Default: 0
 
-tcp_tw_recycle - BOOLEAN
-	Enable fast recycling TIME-WAIT sockets. Default value is 0.
-	It should not be changed without advice/request of technical
-	experts.
+tcp_keepalive_intvl - INTEGER
+	How frequently the probes are send out.  Multiplied by
+	tcp_keepalive_probes it is time to kill not responding connection,
+	after probes started.
+	Default: 75 secs
 
-tcp_tw_reuse - BOOLEAN
-	Allow to reuse TIME-WAIT sockets for new connections when it is
-	safe from protocol viewpoint. Default value is 0.
-	It should not be changed without advice/request of technical
-	experts.
+tcp_keepalive_probes - INTEGER
+	How many keepalive probes TCP sends out, until it decides that the
+	connection is broken.
+	Default: 9
+
+tcp_keepalive_time - INTEGER
+	How often TCP sends out keepalive messages when keepalive is
+	enabled.
+	Default: 2 hours
+
+tcp_low_latency - BOOLEAN
+	If set, the TCP stack makes decisions that prefer lower latency as
+	opposed to higher throughput.  By default, this option is not set
+	meaning that higher throughput is preferred.  An example of an
+	application where this default should be changed would be a Beowulf
+	compute cluster.
+	Default: 0
 
 tcp_max_orphans - INTEGER
 	Maximal number of TCP sockets not attached to any user file handle,
-	held by system.	If this number is exceeded orphaned connections are
-	reset immediately and warning is printed. This limit exists
-	only to prevent simple DoS attacks, you _must_ not rely on this
-	or lower the limit artificially, but rather increase it
-	(probably, after increasing installed memory),
-	if network conditions require more than default value,
-	and tune network services to linger and kill such states
-	more aggressively. Let me to remind again: each orphan eats
-	up to ~64K of unswappable memory.
+	held by system.  If this number is exceeded orphaned connections are
+	reset immediately and warning is printed.  This limit exists only to
+	prevent simple DoS attacks, you _must_ not rely on this or lower the
+	limit artificially, but rather increase it (probably, after
+	increasing installed memory), if network conditions require more
+	than default value, and tune network services to linger and kill
+	such states more aggressively.  Let me to remind again: each orphan
+	eats up to ~64K of unswappable memory.
 
-tcp_abort_on_overflow - BOOLEAN
-	If listening service is too slow to accept new connections,
-	reset them. Default state is FALSE. It means that if overflow
-	occurred due to a burst, connection will recover. Enable this
-	option _only_ if you are really sure that listening daemon
-	cannot be tuned to accept connections faster. Enabling this
-	option can harm clients of your server.
+tcp_max_syn_backlog - INTEGER
+	Maximal number of remembered connection requests, which are still
+	did not receive an acknowledgment from connecting client.  If server
+	suffers of overload, try to increase this number.
+	Default: dependent on system memory
+	> 128Mb 1024
+	< 128Mb 128
 
-tcp_syncookies - BOOLEAN
-	Only valid when the kernel was compiled with CONFIG_SYNCOOKIES
-	Send out syncookies when the syn backlog queue of a socket 
-	overflows. This is to prevent against the common 'syn flood attack'
-	Default: FALSE
+tcp_max_tw_buckets - INTEGER
+	Maximal number of time-wait sockets held by system simultaneously.
+	If this number is exceeded time-wait socket is immediately destroyed
+	and warning is printed.  This limit exists only to prevent simple
+	DoS attacks, you _must_ not lower the limit artificially, but rather
+	increase it (probably, after increasing installed memory), if
+	network conditions require more than default value.
 
-	Note, that syncookies is fallback facility.
-	It MUST NOT be used to help highly loaded servers to stand
-	against legal connection rate. If you see synflood warnings
-	in your logs, but investigation	shows that they occur
-	because of overload with legal connections, you should tune
-	another parameters until this warning disappear.
-	See: tcp_max_syn_backlog, tcp_synack_retries, tcp_abort_on_overflow.
-
-	syncookies seriously violate TCP protocol, do not allow
-	to use TCP extensions, can result in serious degradation
-	of some services (f.e. SMTP relaying), visible not by you,
-	but your clients and relays, contacting you. While you see
-	synflood warnings in logs not being really flooded, your server
-	is seriously misconfigured.
+tcp_mem - vector of 3 INTEGERs: low, pressure, max
+	low: Below this number of pages TCP is not bothered about its memory
+	appetite.
 
-tcp_stdurg - BOOLEAN
-	Use the Host requirements interpretation of the TCP urg pointer field.
-	Most hosts use the older BSD interpretation, so if you turn this on
-	Linux might not communicate correctly with them.	
-	Default: FALSE 
-	
-tcp_max_syn_backlog - INTEGER
-	Maximal number of remembered connection requests, which are
-	still did not receive an acknowledgment from connecting client.
-	Default value is 1024 for systems with more than 128Mb of memory,
-	and 128 for low memory machines. If server suffers of overload,
-	try to increase this number.
+	pressure: When amount of memory allocated by TCP exceeds this number
+	of pages, TCP moderates its memory consumption and enters memory
+	pressure mode, which is exited when memory consumption falls under
+	"low".
 
-tcp_window_scaling - BOOLEAN
-	Enable window scaling as defined in RFC1323.
+	max: Number of pages allowed for queueing by all TCP sockets.
 
-tcp_timestamps - BOOLEAN
-	Enable timestamps as defined in RFC1323.
+	See tcp_rmem, tcp_wmem.
+	Default: dependent on system memory
 
-tcp_sack - BOOLEAN
-	Enable select acknowledgments (SACKS).
+tcp_moderate_rcvbuf - BOOLEAN
+	TODO Check description.
+	If set TCP automatically adjusts the size of the socket receive
+	window based on the amount of space used in the receive queue.
+	Default: 1
 
-tcp_fack - BOOLEAN
-	Enable FACK congestion avoidance and fast retransmission.
-	The value is not used, if tcp_sack is not enabled.
+tcp_mtu_probing - INTEGER
+	TODO Check description.
+	If non-zero, then TCP attempts to discover routers that do not
+	correctly return ICMP fragmentation needed when receiving oversize
+	packets "black-holes".  If the value is greater than one, don't use
+	the cached pmtu value before attempting to probe.
+	Default: 0
 
-tcp_dsack - BOOLEAN
-	Allows TCP to send "duplicate" SACKs.
+tcp_no_metrics_save - BOOLEAN
+	TODO Check description.
+	Normally, TCP will remember some characteristics about the last
+	connection in the flow cache.  If tcp_no_metrics_save is set, then
+	it doesn't.  Useful for benchmarks or other tests.
+	Default: 0
 
-tcp_ecn - BOOLEAN
-	Enable Explicit Congestion Notification in TCP.
+tcp_orphan_retries - INTEGER
+	How may times to retry before killing TCP connection, closed by our
+	side.  If you machine is a loaded WEB server, you should think about
+	lowering this value, such sockets may consume significant resources.
+	See tcp_max_orphans.
+	Default: 0
 
 tcp_reordering - INTEGER
 	Maximal reordering of packets in a TCP stream.
-	Default: 3	
+	Default: 3
 
 tcp_retrans_collapse - BOOLEAN
-	Bug-to-bug compatibility with some broken printers.
-	On retransmit try to send bigger packets to work around bugs in
-	certain TCP stacks.
+	Bug-to-bug compatibility with some broken printers.  On retransmit
+	try to send bigger packets to work around bugs in certain TCP
+	stacks.
+	Default: 1
 
-tcp_wmem - vector of 3 INTEGERs: min, default, max
-	min: Amount of memory reserved for send buffers for TCP socket.
-	Each TCP socket has rights to use it due to fact of its birth.
-	Default: 4K
+tcp_retries1 - INTEGER
+	How many times to retry before deciding that something is wrong and
+	it is necessary to report this suspicion to network layer.  Minimal
+	RFC value is 3.
+	Default: 3
 
-	default: Amount of memory allowed for send buffers for TCP socket
-	by default. This value overrides net.core.wmem_default used
-	by other protocols, it is usually lower than net.core.wmem_default.
-	Default: 16K
+tcp_retries2 - INTEGER
+	How may times to retry before killing alive TCP connection.  RFC1122
+	says that the limit should be longer than 100 sec.  It is too small
+	number.
+	Default: 15
 
-	max: Maximal amount of memory allowed for automatically selected
-	send buffers for TCP socket. This value does not override
-	net.core.wmem_max, "static" selection via SO_SNDBUF does not use this.
-	Default: 128K
+tcp_rfc1337 - BOOLEAN
+	If set, the TCP stack behaves conforming to RFC1337.  If unset, we
+	are not conforming to RFC, but prevent TCP TIME_WAIT assassination.
+	Default: 0
 
 tcp_rmem - vector of 3 INTEGERs: min, default, max
-	min: Minimal size of receive buffer used by TCP sockets.
-	It is guaranteed to each TCP socket, even under moderate memory
-	pressure.
-	Default: 8K
-
-	default: default size of receive buffer used by TCP sockets.
-	This value overrides net.core.rmem_default used by other protocols.
-	Default: 87380 bytes. This value results in window of 65535 with
+	min: Minimal size of receive buffer used by TCP sockets.  It is
+	guaranteed to each TCP socket, even under moderate memory pressure.
+
+	default: Default size of receive buffer used by TCP sockets.  This
+	value overrides net.core.rmem_default used by other protocols.  The
+	default value of 87380 bytes, results in window of 65535 with
 	default setting of tcp_adv_win_scale and tcp_app_win:0 and a bit
-	less for default tcp_app_win. See below about these variables.
+	less for default tcp_app_win.
 
-	max: maximal size of receive buffer allowed for automatically
-	selected receiver buffers for TCP socket. This value does not override
-	net.core.rmem_max, "static" selection via SO_RCVBUF does not use this.
-	Default: 87380*2 bytes.
+	max: Maximal size of receive buffer allowed for automatically
+	selected receiver buffers for TCP socket.  This value does not
+	override net.core.rmem_max, "static" selection via SO_RCVBUF does
+	not use this.
+	See tcp_mem, tcp_wmem.
+	Default: 1 page, 16k, dependent on tcp_mem default
 
-tcp_mem - vector of 3 INTEGERs: min, pressure, max
-	low: below this number of pages TCP is not bothered about its
-	memory appetite.
+tcp_sack - BOOLEAN
+	Enable select acknowledgments (SACKS).
+	Default: 1
 
-	pressure: when amount of memory allocated by TCP exceeds this number
-	of pages, TCP moderates its memory consumption and enters memory
-	pressure mode, which is exited when memory consumption falls
-	under "low".
+tcp_stdurg - BOOLEAN
+	Use the Host requirements interpretation of the TCP urg pointer
+	field.  Most hosts use the older BSD interpretation, so if you turn
+	this on Linux might not communicate correctly with them.
+	Default: 0
 
-	high: number of pages allowed for queueing by all TCP sockets.
+tcp_synack_retries - INTEGER
+	Number of times SYNACKs for a passive TCP connection attempt will be
+	retransmitted.  Should not be higher than 255.  
+	Default: 5
 
-	Defaults are calculated at boot time from amount of available
-	memory.
+tcp_syncookies - BOOLEAN
+	Only valid when the kernel was compiled with CONFIG_SYNCOOKIES Send
+	out syncookies when the syn backlog queue of a socket overflows.
+	This is to prevent against the common 'syn flood attack'
 
-tcp_app_win - INTEGER
-	Reserve max(window/2^tcp_app_win, mss) of window for application
-	buffer. Value 0 is special, it means that nothing is reserved.
-	Default: 31
+	Note, that syncookies is fallback facility.
+	It MUST NOT be used to help highly loaded servers to stand against
+	legal connection rate.  If you see synflood warnings in your logs,
+	but investigation shows that they occur because of overload with
+	legal connections, you should tune another parameters until this
+	warning disappear.  See tcp_max_syn_backlog, tcp_synack_retries,
+	tcp_abort_on_overflow.
+
+	syncookies seriously violate TCP protocol, do not allow to use TCP
+	extensions, can result in serious degradation of some services (f.e.
+	SMTP relaying), visible not by you, but your clients and relays,
+	contacting you.  While you see synflood warnings in logs not being
+	really flooded, your server is seriously misconfigured.
+	Default: 0
 
-tcp_adv_win_scale - INTEGER
-	Count buffering overhead as bytes/2^tcp_adv_win_scale
-	(if tcp_adv_win_scale > 0) or bytes-bytes/2^(-tcp_adv_win_scale),
-	if it is <= 0.
-	Default: 2
+tcp_syn_retries - INTEGER
+	Number of times initial SYNs for an active TCP connection attempt
+	will be retransmitted.  Should not be higher than 255.
+	Default: 5
 
-tcp_rfc1337 - BOOLEAN
-	If set, the TCP stack behaves conforming to RFC1337. If unset,
-	we are not conforming to RFC, but prevent TCP TIME_WAIT
-	assassination.   
+tcp_timestamps - BOOLEAN
+	Enable timestamps as defined in RFC1323.
+	Default: 1
+
+tcp_tso_win_divisor - INTEGER
+	This allows control over what percentage of the congestion window
+	can be consumed by a single TSO frame.  The setting of this
+	parameter is a choice between burstiness and building larger TSO
+	frames.
+	Default: 3
+
+tcp_tw_recycle - BOOLEAN
+	Enable fast recycling TIME-WAIT sockets.  The default value should
+	not be changed without advice/request of technical experts.
 	Default: 0
 
-tcp_low_latency - BOOLEAN
-	If set, the TCP stack makes decisions that prefer lower
-	latency as opposed to higher throughput.  By default, this
-	option is not set meaning that higher throughput is preferred.
-	An example of an application where this default should be
-	changed would be a Beowulf compute cluster.
+tcp_tw_reuse - BOOLEAN
+	Allow to reuse TIME-WAIT sockets for new connections when it is safe
+	from protocol viewpoint.  The default value should not be changed
+	without advice/request of technical experts.
 	Default: 0
 
-tcp_tso_win_divisor - INTEGER
-       This allows control over what percentage of the congestion window
-       can be consumed by a single TSO frame.
-       The setting of this parameter is a choice between burstiness and
-       building larger TSO frames.
-       Default: 3
+tcp_window_scaling - BOOLEAN
+	Enable window scaling as defined in RFC1323.
+	Default: 1
 
-tcp_frto - BOOLEAN
-	Enables F-RTO, an enhanced recovery algorithm for TCP retransmission
-	timeouts.  It is particularly beneficial in wireless environments
-	where packet loss is typically due to random radio interference
-	rather than intermediate router congestion.
+tcp_wmem - vector of 3 INTEGERs: min, default, max
+	min: Amount of memory reserved for send buffers for TCP socket.
+	Each TCP socket has rights to use it due to fact of its birth.
 
-tcp_congestion_control - STRING
-	Set the congestion control algorithm to be used for new
-	connections. The algorithm "reno" is always available, but
-	additional choices may be available based on kernel configuration.
+	default: Amount of memory allowed for send buffers for TCP socket by
+	default.  This value overrides net.core.wmem_default used by other
+	protocols, it is usually lower than net.core.wmem_default.
 
-somaxconn - INTEGER
-	Limit of socket listen() backlog, known in userspace as SOMAXCONN.
-	Defaults to 128.  See also tcp_max_syn_backlog for additional tuning
-	for TCP sockets.
+	max: Maximal amount of memory allowed for automatically selected
+	send buffers for TCP socket.  This value does not override
+	net.core.wmem_max, "static" selection via SO_SNDBUF does not use
+	this.
+	See tcp_mem, tcp_rmem.
+	Default: 1 page, 16k, dependent on tcp_mem default
 
 tcp_workaround_signed_windows - BOOLEAN
 	If set, assume no receipt of a window scaling option means the
-	remote TCP is broken and treats the window as a signed quantity.
-	If unset, assume the remote TCP is not broken even if we do
-	not receive a window scaling option from them.
+	remote TCP is broken and treats the window as a signed quantity.  If
+	unset, assume the remote TCP is not broken even if we do not receive
+	a window scaling option from them.
 	Default: 0
 
-IP Variables:
 
-ip_local_port_range - 2 INTEGERS
-	Defines the local port range that is used by TCP and UDP to
-	choose the local port. The first number is the first, the 
-	second the last local port number. Default value depends on
-	amount of memory available on the system:
-	> 128Mb 32768-61000
-	< 128Mb 1024-4999 or even less.
-	This number defines number of active connections, which this
-	system can issue simultaneously to systems not supporting
-	TCP extensions (timestamps). With tcp_tw_recycle enabled
-	(i.e. by default) range 1024-4999 is enough to issue up to
-	2000 connections per second to systems supporting timestamps.
-
-ip_nonlocal_bind - BOOLEAN
-	If set, allows processes to bind() to non-local IP addresses,
-	which can be quite useful - but may break some applications.
-	Default: 0
+/proc/sys/net/ipv4/route/* Variables:
 
-ip_dynaddr - BOOLEAN
-	If set non-zero, enables support for dynamic addresses.
-	If set to a non-zero value larger than 1, a kernel log
-	message will be printed when dynamic address rewriting
-	occurs.
-	Default: 0
-
-icmp_echo_ignore_all - BOOLEAN
-	If set non-zero, then the kernel will ignore all ICMP ECHO
-	requests sent to it.
-	Default: 0
+error_burst - INTEGER
+	TODO Add description.
+	Default: 5
 
-icmp_echo_ignore_broadcasts - BOOLEAN
-	If set non-zero, then the kernel will ignore all ICMP ECHO and
-	TIMESTAMP requests sent to it via broadcast/multicast.
+error_cost - INTEGER
+	TODO Add description.
 	Default: 1
 
-icmp_ratelimit - INTEGER
-	Limit the maximal rates for sending ICMP packets whose type matches
-	icmp_ratemask (see below) to specific targets.
-	0 to disable any limiting, otherwise the maximal rate in jiffies(1)
-	Default: 100
-
-icmp_ratemask - INTEGER
-	Mask made of ICMP types for which rates are being limited.
-	Significant bits: IHGFEDCBA9876543210
-	Default mask:     0000001100000011000 (6168)
-
-	Bit definitions (see include/linux/icmp.h):
-		0 Echo Reply
-		3 Destination Unreachable *
-		4 Source Quench *
-		5 Redirect
-		8 Echo Request
-		B Time Exceeded *
-		C Parameter Problem *
-		D Timestamp Request
-		E Timestamp Reply
-		F Info Request
-		G Info Reply
-		H Address Mask Request
-		I Address Mask Reply
+flush - INTEGER
+	TODO Add description.
+	Default: 0
 
-	* These are rate limited by default (see default mask above)
+gc_elasticity - INTEGER
+	TODO Add description.
+	Default: 8
 
-icmp_ignore_bogus_error_responses - BOOLEAN
-	Some routers violate RFC1122 by sending bogus responses to broadcast
-	frames.  Such violations are normally logged via a kernel warning.
-	If this is set to TRUE, the kernel will not give such warnings, which
-	will avoid log file clutter.
-	Default: FALSE
+gc_interval - INTEGER
+	TODO Add description.
+	Default: 60
 
-icmp_errors_use_inbound_ifaddr - BOOLEAN
+gc_min_interval - INTEGER
+	TODO Check description.
+	Deprecated.  Use gc_min_interval_ms.
 
-	If zero, icmp error messages are sent with the primary address of
-	the exiting interface.
- 
-	If non-zero, the message will be sent with the primary address of
-	the interface that received the packet that caused the icmp error.
-	This is the behaviour network many administrators will expect from
-	a router. And it can make debugging complicated network layouts
-	much easier. 
+gc_min_interval_ms - INTEGER
+	TODO Add description.
+	Default: 500
 
-	Note that if no primary address exists for the interface selected,
-	then the primary address of the first non-loopback interface that
-	has one will be used regarldess of this setting.
+gc_thresh - INTEGER
+	TODO Add description.
 
-	Default: 0
+gc_timeout - INTEGER
+	TODO Add description.
+	Default: 300
 
-igmp_max_memberships - INTEGER
-	Change the maximum number of multicast groups we can subscribe to.
-	Default: 20
+max_delay - INTEGER
+	TODO Add description.
+	Default: 10
 
-conf/interface/*  changes special settings per interface (where "interface" is 
-		  the name of your network interface)
-conf/all/*	  is special, changes the settings for all interfaces
+max_size - INTEGER
+	TODO Add description.
 
+min_adv_mss - INTEGER
+	The advertised MSS depends on the first hop route MTU, but will
+	never be lower than this setting.
+	Default: 256
 
-log_martians - BOOLEAN
-	Log packets with impossible addresses to kernel log.
-	log_martians for the interface will be enabled if at least one of
-	conf/{all,interface}/log_martians is set to TRUE,
-	it will be disabled otherwise
+min_delay - INTEGER
+	TODO Add description.
+	Default: 2
 
-accept_redirects - BOOLEAN
-	Accept ICMP redirect messages.
-	accept_redirects for the interface will be enabled if:
-	- both conf/{all,interface}/accept_redirects are TRUE in the case forwarding
-	  for the interface is enabled
-	or
-	- at least one of conf/{all,interface}/accept_redirects is TRUE in the case
-	  forwarding for the interface is disabled
-	accept_redirects for the interface will be disabled otherwise
-	default TRUE (host)
-		FALSE (router)
+min_pmtu - INTEGER
+	Minimum discovered Path MTU
+	Default: 552
 
-forwarding - BOOLEAN
-	Enable IP forwarding on this interface.
+mtu_expires - INTEGER
+	Time, in seconds, that cached PMTU information is kept.
+	Default: 600
 
-mc_forwarding - BOOLEAN
-	Do multicast routing. The kernel needs to be compiled with CONFIG_MROUTE
-	and a multicast routing daemon is required.
-	conf/all/mc_forwarding must also be set to TRUE to enable multicast routing
-	for the interface
+redirect_load - INTEGER
+	TODO Add description.
+	Default: 5
 
-medium_id - INTEGER
-	Integer value used to differentiate the devices by the medium they
-	are attached to. Two devices can have different id values when
-	the broadcast packets are received only on one of them.
-	The default value 0 means that the device is the only interface
-	to its medium, value of -1 means that medium is not known.
-	
-	Currently, it is used to change the proxy_arp behavior:
-	the proxy_arp feature is enabled for packets forwarded between
-	two devices attached to different media.
+redirect_number - INTEGER
+	TODO Add description.
+	Default: 9
 
-proxy_arp - BOOLEAN
-	Do proxy arp.
-	proxy_arp for the interface will be enabled if at least one of
-	conf/{all,interface}/proxy_arp is set to TRUE,
-	it will be disabled otherwise
+redirect_silence - INTEGER
+	TODO Add description.
 
-shared_media - BOOLEAN
-	Send(router) or accept(host) RFC1620 shared media redirects.
-	Overrides ip_secure_redirects.
-	shared_media for the interface will be enabled if at least one of
-	conf/{all,interface}/shared_media is set to TRUE,
-	it will be disabled otherwise
-	default TRUE
+secret_interval - INTEGER
+	TODO Add description.
+	Default: 600
 
-secure_redirects - BOOLEAN
-	Accept ICMP redirect messages only for gateways,
-	listed in default gateway list.
-	secure_redirects for the interface will be enabled if at least one of
-	conf/{all,interface}/secure_redirects is set to TRUE,
-	it will be disabled otherwise
-	default TRUE
 
-send_redirects - BOOLEAN
-	Send redirects, if router.
-	send_redirects for the interface will be enabled if at least one of
-	conf/{all,interface}/send_redirects is set to TRUE,
-	it will be disabled otherwise
-	Default: TRUE
+/proc/sys/net/ipv4/conf/*/*
+/proc/sys/net/ipv4/conf/all/*
+/proc/sys/net/ipv4/conf/default/*
 
-bootp_relay - BOOLEAN
-	Accept packets with source address 0.b.c.d destined
-	not to this host as local ones. It is supposed, that
-	BOOTP relay daemon will catch and forward such packets.
-	conf/all/bootp_relay must also be set to TRUE to enable BOOTP relay
-	for the interface
-	default FALSE
-	Not Implemented Yet.
+accept_redirects - BOOLEAN
+	Accept ICMP redirect messages.
+	accept_redirects for the interface will be enabled if:
+	- both conf/{all,interface}/accept_redirects are TRUE in the case
+	  forwarding for the interface is enabled
+	or
+	- at least one of conf/{all,interface}/accept_redirects is TRUE in
+	  the case forwarding for the interface is disabled
+	accept_redirects for the interface will be disabled otherwise value
+	1 (host) and 0 (router).
+	Default: 1
 
 accept_source_route - BOOLEAN
-	Accept packets with SRR option.
-	conf/all/accept_source_route must also be set to TRUE to accept packets
-	with SRR option on the interface
-	default TRUE (router)
-		FALSE (host)
+	Accept packets with SRR option.  conf/all/accept_source_route must
+	also be set to 1 to accept packets with SRR option on the interface
+	value 1 (router) and 0 (host).
+	Default: 1
 
-rp_filter - BOOLEAN
-	1 - do source validation by reversed path, as specified in RFC1812
-	    Recommended option for single homed hosts and stub network
-	    routers. Could cause troubles for complicated (not loop free)
-	    networks running a slow unreliable protocol (sort of RIP),
-	    or using static routes.
+arp_accept - BOOLEAN
+	Define behavior when gratuitous ARP replies are received:
+	0 - drop gratuitous ARP frames
+	1 - accept gratuitous ARP frames
+	Default: 0
 
-	0 - No source validation.
+arp_announce - INTEGER
+	Define different restriction levels for announcing the local source
+	IP address from IP packets in ARP requests sent on interface:
+	0 - Use any local address, configured on any interface.
+	1 - Try to avoid local addresses that are not in the target's subnet
+	    for this interface.  This mode is useful when target hosts
+	    reachable via this interface require the source IP address in
+	    ARP requests to be part of their logical network configured on
+	    the receiving interface.  When we generate the request we will
+	    check all our subnets that include the target IP and will
+	    preserve the source address if it is from such subnet.  If there
+	    is no such subnet we select source address according to the
+	    rules for level 2.
+	2 - Always use the best local address for this target.  In this mode
+	    we ignore the source address in the IP packet and try to select
+	    local address that we prefer for talks with the target host.
+	    Such local address is selected by looking for primary IP
+	    addresses on all our subnets on the outgoing interface that
+	    include the target IP address.  If no suitable local address is
+	    found we select the first local address we have on the outgoing
+	    interface or on all other interfaces, with the hope we will
+	    receive reply for our request and even sometimes no matter the
+	    source IP address we announce.
 
-	conf/all/rp_filter must also be set to TRUE to do source validation
-	on the interface
+	The max value from conf/{all,interface}/arp_announce is used.
 
-	Default value is 0. Note that some distributions enable it
-	in startup scripts.
+	Increasing the restriction level gives more chance for receiving
+	answer from the resolved target while decreasing the level announces
+	more valid sender's information.
+	Default: 0
 
 arp_filter - BOOLEAN
 	1 - Allows you to have multiple network interfaces on the same
-	subnet, and have the ARPs for each interface be answered
-	based on whether or not the kernel would route a packet from
-	the ARP'd IP out that interface (therefore you must use source
-	based routing for this to work). In other words it allows control
-	of which cards (usually 1) will respond to an arp request.
-
-	0 - (default) The kernel can respond to arp requests with addresses
-	from other interfaces. This may seem wrong but it usually makes
-	sense, because it increases the chance of successful communication.
-	IP addresses are owned by the complete host on Linux, not by
-	particular interfaces. Only for more complex setups like load-
-	balancing, does this behaviour cause problems.
+	    subnet, and have the ARPs for each interface be answered based
+	    on whether or not the kernel would route a packet from the ARP'd
+	    IP out that interface (therefore you must use source based
+	    routing for this to work).  In other words it allows control of
+	    which cards (usually 1) will respond to an ARP request.
+
+	0 - The kernel can respond to ARP requests with addresses from other
+	    interfaces.  This may seem wrong but it usually makes sense,
+	    because it increases the chance of successful communication.  IP
+	    addresses are owned by the complete host on Linux, not by
+	    particular interfaces.  Only for more complex setups like load-
+	    balancing, does this behaviour cause problems.
 
 	arp_filter for the interface will be enabled if at least one of
-	conf/{all,interface}/arp_filter is set to TRUE,
-	it will be disabled otherwise
-
-arp_announce - INTEGER
-	Define different restriction levels for announcing the local
-	source IP address from IP packets in ARP requests sent on
-	interface:
-	0 - (default) Use any local address, configured on any interface
-	1 - Try to avoid local addresses that are not in the target's
-	subnet for this interface. This mode is useful when target
-	hosts reachable via this interface require the source IP
-	address in ARP requests to be part of their logical network
-	configured on the receiving interface. When we generate the
-	request we will check all our subnets that include the
-	target IP and will preserve the source address if it is from
-	such subnet. If there is no such subnet we select source
-	address according to the rules for level 2.
-	2 - Always use the best local address for this target.
-	In this mode we ignore the source address in the IP packet
-	and try to select local address that we prefer for talks with
-	the target host. Such local address is selected by looking
-	for primary IP addresses on all our subnets on the outgoing
-	interface that include the target IP address. If no suitable
-	local address is found we select the first local address
-	we have on the outgoing interface or on all other interfaces,
-	with the hope we will receive reply for our request and
-	even sometimes no matter the source IP address we announce.
-
-	The max value from conf/{all,interface}/arp_announce is used.
-
-	Increasing the restriction level gives more chance for
-	receiving answer from the resolved target while decreasing
-	the level announces more valid sender's information.
+	conf/{all,interface}/arp_filter is set to 1, it will be disabled
+	otherwise.
+	Default: 0
 
 arp_ignore - INTEGER
-	Define different modes for sending replies in response to
-	received ARP requests that resolve local target IP addresses:
-	0 - (default): reply for any local target IP address, configured
-	on any interface
-	1 - reply only if the target IP address is local address
-	configured on the incoming interface
-	2 - reply only if the target IP address is local address
-	configured on the incoming interface and both with the
-	sender's IP address are part from same subnet on this interface
-	3 - do not reply for local addresses configured with scope host,
-	only resolutions for global and link addresses are replied
+	Define different modes for sending replies in response to received
+	ARP requests that resolve local target IP addresses:
+	0   - reply for any local target IP address, configured on any
+	      interface
+	1   - reply only if the target IP address is local address
+	      configured on the incoming interface
+	2   - reply only if the target IP address is local address
+	      configured on the incoming interface and both with the
+	      sender's IP address are part from same subnet on this
+	      interface
+	3   - do not reply for local addresses configured with scope host,
+	      only resolutions for global and link addresses are replied
 	4-7 - reserved
-	8 - do not reply for all local addresses
+	8   - do not reply for all local addresses
 
-	The max value from conf/{all,interface}/arp_ignore is used
-	when ARP request is received on the {interface}
-
-arp_accept - BOOLEAN
-	Define behavior when gratuitous arp replies are received:
-	0 - drop gratuitous arp frames
-	1 - accept gratuitous arp frames
+	The max value from conf/{all,interface}/arp_ignore is used when ARP
+	request is received on the {interface}.
+	Default: 0
 
-app_solicit - INTEGER
-	The maximum number of probes to send to the user space ARP daemon
-	via netlink before dropping back to multicast probes (see
-	mcast_solicit).  Defaults to 0.
+bootp_relay - BOOLEAN
+	Accept packets with source address 0.b.c.d destined not to this host
+	as local ones.  It is supposed, that BOOTP relay daemon will catch
+	and forward such packets.  conf/all/bootp_relay must also be set to
+	1 to enable BOOTP relay for the interface.
+	Default: 0
+	Not Implemented Yet.
 
 disable_policy - BOOLEAN
 	Disable IPSEC policy (SPD) for this interface
+	Default: 0
 
 disable_xfrm - BOOLEAN
 	Disable IPSEC encryption on this interface, whatever the policy
+	Default: 0
 
+force_igmp_version - INTEGER
+	TODO Add description.
 
+forwarding - BOOLEAN
+	Enable IP forwarding on this interface.
+	Default: 0
 
-tag - INTEGER
-	Allows you to write a number, which can be used as required.
-	Default value is 0.
+log_martians - BOOLEAN
+	Log packets with impossible addresses to kernel log.  log_martians
+	for the interface will be enabled if at least one of
+	conf/{all,interface}/log_martians is set to 1, it will be disabled
+	otherwise
+	Default: 0
 
-(1) Jiffie: internal timeunit for the kernel. On the i386 1/100s, on the
-Alpha 1/1024s. See the HZ define in /usr/include/asm/param.h for the exact
-value on your system. 
+mc_forwarding - BOOLEAN
+	Do multicast routing.  The kernel needs to be compiled with
+	CONFIG_MROUTE and a multicast routing daemon is required.
+	conf/all/mc_forwarding must also be set to 1 to enable multicast
+	routing for the interface
+	Default: 0
 
-Alexey Kuznetsov.
-kuznet@ms2.inr.ac.ru
+medium_id - INTEGER
+	Integer value used to differentiate the devices by the medium they
+	are attached to.  Two devices can have different id values when the
+	broadcast packets are received only on one of them.  The value 0
+	means that the device is the only interface to its medium, value of
+	-1 means that medium is not known.
+
+	Currently, it is used to change the proxy_arp behavior: the
+	proxy_arp feature is enabled for packets forwarded between two
+	devices attached to different media.
+	Default: 0
+
+promote_secondaries - ????
+	TODO Add description.
+
+proxy_arp - BOOLEAN
+	Do proxy ARP.
+	proxy_arp for the interface will be enabled if at least one of
+	conf/{all,interface}/proxy_arp is set to 1, it will be disabled
+	otherwise.
+	Default: 0
+
+rp_filter - BOOLEAN
+	1 - do source validation by reversed path, as specified in RFC1812
+	    Recommended option for single homed hosts and stub network
+	    routers.  Could cause troubles for complicated (not loop free)
+	    networks running a slow unreliable protocol (sort of RIP), or
+	    using static routes.
+	0 - No source validation.
+
+	conf/all/rp_filter must also be set to 1 to do source validation on
+	the interface
+
+	Default: 0.  Note that some distributions enable it in startup
+	scripts.
+
+secure_redirects - BOOLEAN
+	Accept ICMP redirect messages only for gateways, listed in default
+	gateway list.
+	secure_redirects for the interface will be enabled if at least one
+	of conf/{all,interface}/secure_redirects is set to 1, it will be
+	disabled otherwise
+	Default: 1
 
-Updated by:
-Andi Kleen
-ak@muc.de
-Nicolas Delon
-delon.nicolas@wanadoo.fr
+send_redirects - BOOLEAN
+	Send redirects, if router.
+	send_redirects for the interface will be enabled if at least one of
+	conf/{all,interface}/send_redirects is set to 1, it will be disabled
+	otherwise
+	Default: 1
 
+shared_media - BOOLEAN
+	Send(router) or accept(host) RFC1620 shared media redirects.
+	Overrides ip_secure_redirects.
+	shared_media for the interface will be enabled if at least one of
+	conf/{all,interface}/shared_media is set to 1, it will be disabled
+	otherwise
+	Default: 1
 
+tag - INTEGER
+	Allows you to write a number, which can be used as required.
+	Default: 0
 
 
 /proc/sys/net/ipv6/* Variables:
@@ -670,155 +825,208 @@ IPv6 has no global variables such as tcp
 apply to IPv6 [XXX?].
 
 bindv6only - BOOLEAN
-	Default value for IPV6_V6ONLY socket option,
-	which restricts use of the IPv6 socket to IPv6 communication 
-	only.
-		TRUE: disable IPv4-mapped address feature
-		FALSE: enable IPv4-mapped address feature
-
-	Default: FALSE (as specified in RFC2553bis)
-
-IPv6 Fragmentation:
+	Default value for IPV6_V6ONLY socket option, which restricts use of
+	the IPv6 socket to IPv6 communication only.
+		1: disable IPv4-mapped address feature
+		0: enable IPv4-mapped address feature
+	Default: 0 (as specified in RFC2553bis)
 
 ip6frag_high_thresh - INTEGER
-	Maximum memory used to reassemble IPv6 fragments. When 
+	Maximum memory used to reassemble IPv6 fragments.  When
 	ip6frag_high_thresh bytes of memory is allocated for this purpose,
-	the fragment handler will toss packets until ip6frag_low_thresh
-	is reached.
-	
-ip6frag_low_thresh - INTEGER
-	See ip6frag_high_thresh	
+	the fragment handler will toss packets until ip6frag_low_thresh is
+	reached.
+	Default: 256k
 
-ip6frag_time - INTEGER
-	Time in seconds to keep an IPv6 fragment in memory.
+ip6frag_low_thresh - INTEGER
+	See ip6frag_high_thresh
+	Default: 192k
 
 ip6frag_secret_interval - INTEGER
-	Regeneration interval (in seconds) of the hash secret (or lifetime 
+	Regeneration interval (in seconds) of the hash secret (or lifetime
 	for the hash secret) for IPv6 fragments.
 	Default: 600
 
-conf/default/*:
-	Change the interface-specific default settings.
+ip6frag_time - INTEGER
+	Time in seconds to keep an IPv6 fragment in memory.
+	Default: 60
+
+mld_max_msf - INTEGER
+	TODO Add description.
 
 
-conf/all/*:
-	Change all the interface-specific settings.  
+/proc/sys/net/ipv6/icmp/* Variables:
 
-	[XXX:  Other special features than forwarding?]
+ratelimit - INTEGER
+	Limit the maximal rates for sending ICMPv6 packets.
+	0 to disable any limiting, otherwise the maximal rate in jiffies(1).
+	Default: jiffies in one second
 
-conf/all/forwarding - BOOLEAN
-	Enable global IPv6 forwarding between all interfaces.  
 
-	IPv4 and IPv6 work differently here; e.g. netfilter must be used 
-	to control which interfaces may forward packets and which not.
+/proc/sys/net/ipv6/route/* Variables:
 
-	This also sets all interfaces' Host/Router setting 
-	'forwarding' to the specified value.  See below for details.
+flush - INTEGER
+	TODO Add description.
+	See ipv4/route/flush description.
 
-	This referred to as global forwarding.
+gc_elasticity - INTEGER
+	TODO Add description.
+	See ipv4/route/gc_elasticity description.
 
-conf/interface/*:
-	Change special settings per interface.
+gc_interval - INTEGER
+	TODO Add description.
+	See ipv4/route/gc_interval description.
 
-	The functional behaviour for certain settings is different 
-	depending on whether local forwarding is enabled or not.
+gc_min_interval - INTEGER
+	TODO Add description.
+	See ipv4/route/gc_min_interval description.
+
+gc_min_interval_ms - INTEGER
+	TODO Add description.
+	See ipv4/route/gc_min_interval_ms description.
+
+gc_thresh - INTEGER
+	TODO Add description.
+	See ipv4/route/gc_thresh description.
+
+gc_timeout - INTEGER
+	TODO Add description.
+	See ipv4/route/gc_timeout description.
+
+max_size - INTEGER
+	TODO Add description.
+	See ipv4/route/max_size description.
+
+min_adv_mss - INTEGER
+	TODO Add description.
+	See ipv4/route/min_adv_mss description.
+
+mtu_expires - INTEGER
+	TODO Add description.
+	See ipv4/route/mtu_expires description.
+
+
+/proc/sys/net/ipv6/conf/*/*
+/proc/sys/net/ipv6/conf/all/*
+/proc/sys/net/ipv6/conf/default/*
 
 accept_ra - BOOLEAN
 	Accept Router Advertisements; autoconfigure using them.
-	
-	Functional default: enabled if local forwarding is disabled.
-			    disabled if local forwarding is enabled.
+
+	Default: enabled if local forwarding is disabled.
+		 disabled if local forwarding is enabled.
 
 accept_ra_defrtr - BOOLEAN
 	Learn default router in Router Advertisement.
 
-	Functional default: enabled if accept_ra is enabled.
-			    disabled if accept_ra is disabled.
+	Default: enabled if accept_ra is enabled.
+		 disabled if accept_ra is disabled.
 
 accept_ra_pinfo - BOOLEAN
 	Learn Prefix Inforamtion in Router Advertisement.
 
-	Functional default: enabled if accept_ra is enabled.
-			    disabled if accept_ra is disabled.
+	Default: enabled if accept_ra is enabled.
+		 disabled if accept_ra is disabled.
 
 accept_ra_rt_info_max_plen - INTEGER
 	Maximum prefix length of Route Information in RA.
 
-	Route Information w/ prefix larger than or equal to this
-	variable shall be ignored.
+	Route Information with prefix larger than or equal to this variable
+	shall be ignored.
 
-	Functional default: 0 if accept_ra_rtr_pref is enabled.
-			    -1 if accept_ra_rtr_pref is disabled.
+	Default: 0 if accept_ra_rtr_pref is enabled.
+		 -1 if accept_ra_rtr_pref is disabled.
 
 accept_ra_rtr_pref - BOOLEAN
 	Accept Router Preference in RA.
 
-	Functional default: enabled if accept_ra is enabled.
-			    disabled if accept_ra is disabled.
+	Default: enabled if accept_ra is enabled.
+		 disabled if accept_ra is disabled.
 
 accept_redirects - BOOLEAN
 	Accept Redirects.
 
-	Functional default: enabled if local forwarding is disabled.
-			    disabled if local forwarding is enabled.
+	Default: enabled if local forwarding is disabled.
+		 disabled if local forwarding is enabled.
 
 autoconf - BOOLEAN
-	Autoconfigure addresses using Prefix Information in Router 
+	Autoconfigure addresses using Prefix Information in Router
 	Advertisements.
 
-	Functional default: enabled if accept_ra_pinfo is enabled.
-			    disabled if accept_ra_pinfo is disabled.
+	Default: enabled if accept_ra_pinfo is enabled.
+		 disabled if accept_ra_pinfo is disabled.
 
 dad_transmits - INTEGER
 	The amount of Duplicate Address Detection probes to send.
 	Default: 1
-	
+
+force_mld_version - INTEGER
+	TODO Add description.
+	Default: 0
+
 forwarding - BOOLEAN
-	Configure interface-specific Host/Router behaviour.  
+	Configure interface-specific Host/Router behaviour.
 
-	Note: It is recommended to have the same setting on all 
-	interfaces; mixed router/host scenarios are rather uncommon.
+	Note: It is recommended to have the same setting on all interfaces;
+	mixed router/host scenarios are rather uncommon.
 
-	FALSE:
+	FALSE (0):
 
 	By default, Host behaviour is assumed.  This means:
 
 	1. IsRouter flag is not set in Neighbour Advertisements.
 	2. Router Solicitations are being sent when necessary.
-	3. If accept_ra is TRUE (default), accept Router 
-	   Advertisements (and do autoconfiguration).
-	4. If accept_redirects is TRUE (default), accept Redirects.
+	3. If accept_ra is 1 (default), accept Router Advertisements (and
+	   do autoconfiguration).
+	4. If accept_redirects is 1 (default), accept Redirects.
 
-	TRUE:
+	TRUE (1):
 
-	If local forwarding is enabled, Router behaviour is assumed. 
-	This means exactly the reverse from the above:
+	If local forwarding is enabled, Router behaviour is assumed.  This
+	means exactly the reverse from the above:
 
 	1. IsRouter flag is set in Neighbour Advertisements.
 	2. Router Solicitations are not sent.
 	3. Router Advertisements are ignored.
 	4. Redirects are ignored.
 
-	Default: FALSE if global forwarding is disabled (default),
-		 otherwise TRUE.
+	Default: 0 if global forwarding is disabled (default),
+		 otherwise 1.
 
 hop_limit - INTEGER
 	Default Hop Limit to set.
 	Default: 64
 
+max_addresses - INTEGER
+	Number of maximum addresses per interface.  0 disables limitation.
+	It is recommended not set too large value (or 0) because it would be
+	too easy way to crash kernel to allow to create too much of
+	autoconfigured addresses.
+	Default: 16
+
+max_desync_factor - INTEGER
+	Maximum value in seconds for DESYNC_FACTOR, which is a random value
+	that ensures that clients don't synchronize with each other and
+	generate new addresses at exactly the same time.
+	Default: 600
+
 mtu - INTEGER
 	Default Maximum Transfer Unit
 	Default: 1280 (IPv6 required minimum)
 
+regen_max_retry - INTEGER
+	Number of attempts before give up attempting to generate valid
+	temporary addresses.
+	Default: 5
+
 router_probe_interval - INTEGER
 	Minimum interval (in seconds) between Router Probing described
 	in RFC4191.
-
 	Default: 60
 
 router_solicitation_delay - INTEGER
-	Number of seconds to wait after interface is brought up
-	before sending Router Solicitations.
+	Number of seconds to wait after interface is brought up before
+	sending Router Solicitations.
 	Default: 1
 
 router_solicitation_interval - INTEGER
@@ -826,57 +1034,102 @@ router_solicitation_interval - INTEGER
 	Default: 4
 
 router_solicitations - INTEGER
-	Number of Router Solicitations to send until assuming no 
-	routers are present.
+	Number of Router Solicitations to send until assuming no routers are
+	present.
 	Default: 3
 
+temp_prefered_lft - INTEGER
+	Preferred lifetime (in seconds) for temporary addresses.
+	Default: 86400 (1 day)
+
+temp_valid_lft - INTEGER
+	Valid lifetime (in seconds) for temporary addresses.
+	Default: 604800 (7 days)
+
 use_tempaddr - INTEGER
 	Preference for Privacy Extensions (RFC3041).
 	  <= 0 : disable Privacy Extensions
-	  == 1 : enable Privacy Extensions, but prefer public
-	         addresses over temporary addresses.
-	  >  1 : enable Privacy Extensions and prefer temporary
-	         addresses over public addresses.
-	Default:  0 (for most devices)
-		 -1 (for point-to-point devices and loopback devices)
+	  == 1 : enable Privacy Extensions, but prefer public addresses over
+	         temporary addresses.
+	  >  1 : enable Privacy Extensions and prefer temporary addresses
+	         over public addresses.
+	Values 0 for most devices and -1 for point-to-point devices and
+	loopback devices.
+	Default: 0
 
-temp_valid_lft - INTEGER
-	valid lifetime (in seconds) for temporary addresses.
-	Default: 604800 (7 days)
 
-temp_prefered_lft - INTEGER
-	Preferred lifetime (in seconds) for temporary addresses.
-	Default: 86400 (1 day)
+/proc/sys/net/unix/* Variables:
 
-max_desync_factor - INTEGER
-	Maximum value for DESYNC_FACTOR, which is a random value
-	that ensures that clients don't synchronize with each 
-	other and generate new addresses at exactly the same time.
-	value is in seconds.
-	Default: 600
-	
-regen_max_retry - INTEGER
-	Number of attempts before give up attempting to generate
-	valid temporary addresses.
-	Default: 5
+max_dgram_qlen - INTEGER
+	TODO Add description.
+	Default: 10
 
-max_addresses - INTEGER
-	Number of maximum addresses per interface.  0 disables limitation.
-	It is recommended not set too large value (or 0) because it would 
-	be too easy way to crash kernel to allow to create too much of 
-	autoconfigured addresses.
-	Default: 16
 
-icmp/*:
-ratelimit - INTEGER
-	Limit the maximal rates for sending ICMPv6 packets.
-	0 to disable any limiting, otherwise the maximal rate in jiffies(1)
-	Default: 100
+/proc/sys/net/ipv[46]/neigh/*/*
+/proc/sys/net/ipv[46]/neigh/default/*
 
+anycast_delay - INTEGER
+	TODO Add description.
 
-IPv6 Update by:
-Pekka Savola <pekkas@netcore.fi>
-YOSHIFUJI Hideaki / USAGI Project <yoshfuji@linux-ipv6.org>
+app_solicit - INTEGER
+	The maximum number of probes to send to the user space ARP daemon
+	via netlink before dropping back to multicast probes (see
+	mcast_solicit).
+	Default: 0
+
+base_reachable_time - INTEGER
+	TODO Check description.
+	See base_reachable_time_ms.
+
+base_reachable_time_ms - INTEGER
+	TODO Add description.
+	Default: 30000
+
+delay_first_probe_time - ????
+	TODO Add description.
+
+gc_interval - INTEGER
+	TODO Add description.
+	Default: 30
+
+gc_stale_time - ????
+	TODO Add description.
+
+gc_thresh1 - ????
+	TODO Add description.
+
+gc_thresh2 - ????
+	TODO Add description.
+
+gc_thresh3 - ????
+	TODO Add description.
+
+locktime - ????
+	TODO Add description.
+
+mcast_solicit - ????
+	TODO Add description.
+
+proxy_delay - INTEGER
+	TODO Add description.
+	Default: 80
+
+proxy_qlen - INTEGER
+	TODO Add description.
+	Default: 64
+
+retrans_time - ????
+	TODO Check description.
+	See retrans_time_ms.
+
+retrans_time_ms - ????
+	TODO Add description.
+
+ucast_solicit - ????
+	TODO Add description.
+
+unres_qlen - ????
+	TODO Add description.
 
 
 /proc/sys/net/bridge/* Variables:
@@ -886,13 +1139,13 @@ bridge-nf-call-arptables - BOOLEAN
 	0 : disable this.
 	Default: 1
 
-bridge-nf-call-iptables - BOOLEAN
-	1 : pass bridged IPv4 traffic to iptables' chains.
+bridge-nf-call-ip6tables - BOOLEAN
+	1 : pass bridged IPv6 traffic to ip6tables' chains.
 	0 : disable this.
 	Default: 1
 
-bridge-nf-call-ip6tables - BOOLEAN
-	1 : pass bridged IPv6 traffic to ip6tables' chains.
+bridge-nf-call-iptables - BOOLEAN
+	1 : pass bridged IPv4 traffic to iptables' chains.
 	0 : disable this.
 	Default: 1
 
@@ -902,25 +1155,21 @@ bridge-nf-filter-vlan-tagged - BOOLEAN
 	Default: 1
 
 
-UNDOCUMENTED:
-
-dev_weight FIXME
-discovery_slots FIXME
-discovery_timeout FIXME
-fast_poll_increase FIXME
-ip6_queue_maxlen FIXME
-lap_keepalive_time FIXME
-lo_cong FIXME
-max_baud_rate FIXME
-max_dgram_qlen FIXME
-max_noreply_time FIXME
-max_tx_data_size FIXME
-max_tx_window FIXME
-min_tx_turn_time FIXME
-mod_cong FIXME
-no_cong FIXME
-no_cong_thresh FIXME
-slot_timeout FIXME
-warn_noreply_time FIXME
-
-$Id: ip-sysctl.txt,v 1.20 2001/12/13 09:00:18 davem Exp $
+(1) Jiffie: internal timeunit for the kernel.  On the i386 1/100s, on the
+Alpha 1/1024s.  See the HZ define in /usr/include/asm/param.h for the exact
+value on your system.
+
+
+IPv4:
+Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
+IPv4 Updated by:
+Andi Kleen <ak@muc.de>
+Nicolas Delon <delon.nicolas@wanadoo.fr>
+
+IPv6 Updated by:
+Pekka Savola <pekkas@netcore.fi>
+YOSHIFUJI Hideaki / USAGI Project <yoshfuji@linux-ipv6.org>
+
+Reformatted/Updated:
+Robert Fitzsimons <robfitz@273k.net>, June 2006 synced with 2.6.17-rc6.
+
--
1.3.3.g16a4-dirty


^ permalink raw reply related

* Re: [PATCH v2 2/7] AMSO1100 WR / Event Definitions.
From: Steve Wise @ 2006-06-07 20:59 UTC (permalink / raw)
  To: Roland Dreier; +Cc: mshefty, linux-kernel, netdev, openib-general
In-Reply-To: <ada4pywg0ir.fsf@cisco.com>

On Wed, 2006-06-07 at 13:43 -0700, Roland Dreier wrote:
> I just realized it could be the spam filters.  You have some comments
> with three 'X's in a row which might be getting it blocked.  Is that
> possible?


There are other files that have comments with 'XXX' like c2_provider.c
and c2_qp.c which is in patch 3/7 and it made it though.  

These 'XXX' comments need to be cleaned up anyway, so I'll remove them
(or address the issue if there is one) and we'll see next time I post a
new version.

Steve.


^ permalink raw reply

* Re: Updated sysctl documentation take #2
From: Diego Calleja @ 2006-06-07 20:55 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: linux-kernel, netdev
In-Reply-To: <20060607124641.516c7fff@localhost.localdomain>

El Wed, 7 Jun 2006 12:46:41 -0700,
Stephen Hemminger <shemminger@osdl.org> escribió:

> The network stuff was all in Documentation/networking/ip-sysctl.txt.
> Someone else has already started fixing it.

Darn, didn't know that. Anyway, I merged that file into
Documentation/sysctl/ because IMO all sysctls must be in the same
place.

^ permalink raw reply

* Re: [PATCH v2 2/7] AMSO1100 WR / Event Definitions.
From: Roland Dreier @ 2006-06-07 20:43 UTC (permalink / raw)
  To: Steve Wise; +Cc: mshefty, linux-kernel, netdev, openib-general
In-Reply-To: <1149712762.27684.82.camel@stevo-desktop>

I just realized it could be the spam filters.  You have some comments
with three 'X's in a row which might be getting it blocked.  Is that
possible?

 - R.

^ permalink raw reply

* [PATCH v2 2/7] AMSO1100 WR / Event Definitions.
From: Steve Wise @ 2006-06-07 20:39 UTC (permalink / raw)
  To: rdreier; +Cc: mshefty, linux-kernel, netdev, openib-general
In-Reply-To: <20060607200646.9259.24588.stgit@stevo-desktop>

[-- Attachment #1: Type: text/plain, Size: 240 bytes --]

Resending 2/7 gziped.  

linux-kernel and netdev mailing lists didn't formward the plain text
patch... 

If anywone knows how to address this issue, please email me directly cuz
I don't know why 2/7 didn't get forwarded.  

Sorry.

Steve.


[-- Attachment #2: amso1100_wr.gz --]
[-- Type: application/x-gzip, Size: 10387 bytes --]

^ permalink raw reply

* [PATCH v2 7/7] AMSO1100 Makefiles and Kconfig changes.
From: Steve Wise @ 2006-06-07 20:07 UTC (permalink / raw)
  To: rdreier, mshefty; +Cc: linux-kernel, netdev, openib-general
In-Reply-To: <20060607200646.9259.24588.stgit@stevo-desktop>


Review Changes:

- C2DEBUG -> DEBUG
---

 drivers/infiniband/Kconfig             |    1 +
 drivers/infiniband/Makefile            |    1 +
 drivers/infiniband/hw/amso1100/Kbuild  |   10 ++++++++++
 drivers/infiniband/hw/amso1100/Kconfig |   15 +++++++++++++++
 drivers/infiniband/hw/amso1100/README  |   11 +++++++++++
 5 files changed, 38 insertions(+), 0 deletions(-)

diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index ba2d650..04e6d4f 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -36,6 +36,7 @@ config INFINIBAND_ADDR_TRANS
 
 source "drivers/infiniband/hw/mthca/Kconfig"
 source "drivers/infiniband/hw/ipath/Kconfig"
+source "drivers/infiniband/hw/amso1100/Kconfig"
 
 source "drivers/infiniband/ulp/ipoib/Kconfig"
 
diff --git a/drivers/infiniband/Makefile b/drivers/infiniband/Makefile
index eea2732..e2b93f9 100644
--- a/drivers/infiniband/Makefile
+++ b/drivers/infiniband/Makefile
@@ -1,5 +1,6 @@
 obj-$(CONFIG_INFINIBAND)		+= core/
 obj-$(CONFIG_INFINIBAND_MTHCA)		+= hw/mthca/
 obj-$(CONFIG_IPATH_CORE)		+= hw/ipath/
+obj-$(CONFIG_INFINIBAND_AMSO1100)	+= hw/amso1100/
 obj-$(CONFIG_INFINIBAND_IPOIB)		+= ulp/ipoib/
 obj-$(CONFIG_INFINIBAND_SRP)		+= ulp/srp/
diff --git a/drivers/infiniband/hw/amso1100/Kbuild b/drivers/infiniband/hw/amso1100/Kbuild
new file mode 100644
index 0000000..e1f10ab
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/Kbuild
@@ -0,0 +1,10 @@
+EXTRA_CFLAGS += -Idrivers/infiniband/include
+
+ifdef CONFIG_INFINIBAND_AMSO1100_DEBUG
+EXTRA_CFLAGS += -DDEBUG
+endif
+
+obj-$(CONFIG_INFINIBAND_AMSO1100) += iw_c2.o
+
+iw_c2-y := c2.o c2_provider.o c2_rnic.o c2_alloc.o c2_mq.o c2_ae.o c2_vq.o \
+	c2_intr.o c2_cq.o c2_qp.o c2_cm.o c2_mm.o c2_pd.o
diff --git a/drivers/infiniband/hw/amso1100/Kconfig b/drivers/infiniband/hw/amso1100/Kconfig
new file mode 100644
index 0000000..809cb14
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/Kconfig
@@ -0,0 +1,15 @@
+config INFINIBAND_AMSO1100
+	tristate "Ammasso 1100 HCA support"
+	depends on PCI && INET && INFINIBAND
+	---help---
+	  This is a low-level driver for the Ammasso 1100 host
+	  channel adapter (HCA).
+
+config INFINIBAND_AMSO1100_DEBUG
+	bool "Verbose debugging output"
+	depends on INFINIBAND_AMSO1100
+	default n
+	---help---
+	  This option causes the amso1100 driver to produce a bunch of
+	  debug messages.  Select this if you are developing the driver
+	  or trying to diagnose a problem.
diff --git a/drivers/infiniband/hw/amso1100/README b/drivers/infiniband/hw/amso1100/README
new file mode 100644
index 0000000..1331353
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/README
@@ -0,0 +1,11 @@
+This is the OpenFabrics provider driver for the 
+AMSO1100 1Gb RNIC adapter. 
+
+This adapter is available in limited quantities 
+for development purposes from Open Grid Computing.
+
+This driver requires the IWCM and CMA mods necessary
+to support iWARP.
+
+Contact tom@opengridcomputing.com for more information.
+

^ permalink raw reply related

* [PATCH v2 6/7] AMSO1100: Privileged Verbs Queues.
From: Steve Wise @ 2006-06-07 20:07 UTC (permalink / raw)
  To: rdreier, mshefty; +Cc: linux-kernel, netdev, openib-general
In-Reply-To: <20060607200646.9259.24588.stgit@stevo-desktop>


Review Changes:

dprintk() -> pr_debug()
---

 drivers/infiniband/hw/amso1100/c2_vq.c |  260 ++++++++++++++++++++++++++++++++
 drivers/infiniband/hw/amso1100/c2_vq.h |   63 ++++++++
 2 files changed, 323 insertions(+), 0 deletions(-)

diff --git a/drivers/infiniband/hw/amso1100/c2_vq.c b/drivers/infiniband/hw/amso1100/c2_vq.c
new file mode 100644
index 0000000..445b1ed
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_vq.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "c2_vq.h"
+#include "c2_provider.h"
+
+/*
+ * Verbs Request Objects:
+ *
+ * VQ Request Objects are allocated by the kernel verbs handlers.
+ * They contain a wait object, a refcnt, an atomic bool indicating that the
+ * adapter has replied, and a copy of the verb reply work request.
+ * A pointer to the VQ Request Object is passed down in the context
+ * field of the work request message, and reflected back by the adapter
+ * in the verbs reply message.  The function handle_vq() in the interrupt
+ * path will use this pointer to:
+ * 	1) append a copy of the verbs reply message
+ * 	2) mark that the reply is ready
+ * 	3) wake up the kernel verbs handler blocked awaiting the reply.
+ *
+ *
+ * The kernel verbs handlers do a "get" to put a 2nd reference on the 
+ * VQ Request object.  If the kernel verbs handler exits before the adapter
+ * can respond, this extra reference will keep the VQ Request object around
+ * until the adapter's reply can be processed.  The reason we need this is
+ * because a pointer to this object is stuffed into the context field of
+ * the verbs work request message, and reflected back in the reply message.
+ * It is used in the interrupt handler (handle_vq()) to wake up the appropriate
+ * kernel verb handler that is blocked awaiting the verb reply.  
+ * So handle_vq() will do a "put" on the object when it's done accessing it.
+ * NOTE:  If we guarantee that the kernel verb handler will never bail before 
+ *        getting the reply, then we don't need these refcnts.
+ *
+ *
+ * VQ Request objects are freed by the kernel verbs handlers only 
+ * after the verb has been processed, or when the adapter fails and
+ * does not reply.  
+ *
+ *
+ * Verbs Reply Buffers:
+ *
+ * VQ Reply bufs are local host memory copies of a 
+ * outstanding Verb Request reply
+ * message.  The are always allocated by the kernel verbs handlers, and _may_ be
+ * freed by either the kernel verbs handler -or- the interrupt handler.  The
+ * kernel verbs handler _must_ free the repbuf, then free the vq request object
+ * in that order.
+ */
+
+int vq_init(struct c2_dev *c2dev)
+{
+	sprintf(c2dev->vq_cache_name, "c2-vq:dev%c",
+		(char) ('0' + c2dev->devnum));
+	c2dev->host_msg_cache =
+	    kmem_cache_create(c2dev->vq_cache_name, c2dev->rep_vq.msg_size, 0,
+			      SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (c2dev->host_msg_cache == NULL) {
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+void vq_term(struct c2_dev *c2dev)
+{
+	kmem_cache_destroy(c2dev->host_msg_cache);
+}
+
+/* vq_req_alloc - allocate a VQ Request Object and initialize it.
+ * The refcnt is set to 1.
+ */
+struct c2_vq_req *vq_req_alloc(struct c2_dev *c2dev)
+{
+	struct c2_vq_req *r;
+
+	r = kmalloc(sizeof(struct c2_vq_req), GFP_KERNEL);
+	if (r) {
+		init_waitqueue_head(&r->wait_object);
+		r->reply_msg = (u64) NULL;
+		r->event = 0;
+		r->cm_id = NULL;
+		r->qp = NULL;
+		atomic_set(&r->refcnt, 1);
+		atomic_set(&r->reply_ready, 0);
+	}
+	return r;
+}
+
+
+/* vq_req_free - free the VQ Request Object.  It is assumed the verbs handler
+ * has already free the VQ Reply Buffer if it existed.
+ */
+void vq_req_free(struct c2_dev *c2dev, struct c2_vq_req *r)
+{
+	r->reply_msg = (u64) NULL;
+	if (atomic_dec_and_test(&r->refcnt)) {
+		kfree(r);
+	}
+}
+
+/* vq_req_get - reference a VQ Request Object.  Done 
+ * only in the kernel verbs handlers.
+ */
+void vq_req_get(struct c2_dev *c2dev, struct c2_vq_req *r)
+{
+	atomic_inc(&r->refcnt);
+}
+
+
+/* vq_req_put - dereference and potentially free a VQ Request Object.
+ *
+ * This is only called by handle_vq() on the 
+ * interrupt when it is done processing
+ * a verb reply message.  If the associated 
+ * kernel verbs handler has already bailed,
+ * then this put will actually free the VQ 
+ * Request object _and_ the VQ Reply Buffer
+ * if it exists.
+ */
+void vq_req_put(struct c2_dev *c2dev, struct c2_vq_req *r)
+{
+	if (atomic_dec_and_test(&r->refcnt)) {
+		if (r->reply_msg != (u64) NULL)
+			vq_repbuf_free(c2dev,
+				       (void *) (unsigned long) r->reply_msg);
+		kfree(r);
+	}
+}
+
+
+/*
+ * vq_repbuf_alloc - allocate a VQ Reply Buffer.
+ */
+void *vq_repbuf_alloc(struct c2_dev *c2dev)
+{
+	return kmem_cache_alloc(c2dev->host_msg_cache, SLAB_ATOMIC);
+}
+
+/*
+ * vq_send_wr - post a verbs request message to the Verbs Request Queue.
+ * If a message is not available in the MQ, then block until one is available.
+ * NOTE: handle_mq() on the interrupt context will wake up threads blocked here.
+ * When the adapter drains the Verbs Request Queue, 
+ * it inserts MQ index 0 in to the
+ * adapter->host activity fifo and interrupts the host.
+ */
+int vq_send_wr(struct c2_dev *c2dev, union c2wr *wr)
+{
+	void *msg;
+	wait_queue_t __wait;
+
+	/*
+	 * grab adapter vq lock
+	 */
+	spin_lock(&c2dev->vqlock);
+
+	/*
+	 * allocate msg
+	 */
+	msg = c2_mq_alloc(&c2dev->req_vq);
+
+	/*
+	 * If we cannot get a msg, then we'll wait
+	 * When a messages are available, the int handler will wake_up() 
+	 * any waiters.
+	 */
+	while (msg == NULL) {
+		pr_debug("%s:%d no available msg in VQ, waiting...\n",
+		       __FUNCTION__, __LINE__);
+		init_waitqueue_entry(&__wait, current);
+		add_wait_queue(&c2dev->req_vq_wo, &__wait);
+		spin_unlock(&c2dev->vqlock);
+		for (;;) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			if (!c2_mq_full(&c2dev->req_vq)) {
+				break;
+			}
+			if (!signal_pending(current)) {
+				schedule_timeout(1 * HZ);	/* 1 second... */
+				continue;
+			}
+			set_current_state(TASK_RUNNING);
+			remove_wait_queue(&c2dev->req_vq_wo, &__wait);
+			return -EINTR;
+		}
+		set_current_state(TASK_RUNNING);
+		remove_wait_queue(&c2dev->req_vq_wo, &__wait);
+		spin_lock(&c2dev->vqlock);
+		msg = c2_mq_alloc(&c2dev->req_vq);
+	}
+
+	/*
+	 * copy wr into adapter msg
+	 */
+	memcpy(msg, wr, c2dev->req_vq.msg_size);
+
+	/*
+	 * post msg
+	 */
+	c2_mq_produce(&c2dev->req_vq);
+
+	/*
+	 * release adapter vq lock
+	 */
+	spin_unlock(&c2dev->vqlock);
+	return 0;
+}
+
+
+/*
+ * vq_wait_for_reply - block until the adapter posts a Verb Reply Message.  
+ */
+int vq_wait_for_reply(struct c2_dev *c2dev, struct c2_vq_req *req)
+{
+	if (!wait_event_timeout(req->wait_object,
+				atomic_read(&req->reply_ready),
+				60*HZ))
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+/*
+ * vq_repbuf_free - Free a Verbs Reply Buffer.
+ */
+void vq_repbuf_free(struct c2_dev *c2dev, void *reply)
+{
+	kmem_cache_free(c2dev->host_msg_cache, reply);
+}
diff --git a/drivers/infiniband/hw/amso1100/c2_vq.h b/drivers/infiniband/hw/amso1100/c2_vq.h
new file mode 100644
index 0000000..3380562
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_vq.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _C2_VQ_H_
+#define _C2_VQ_H_
+#include <linux/sched.h>
+#include "c2.h"
+#include "c2_wr.h"
+#include "c2_provider.h"
+
+struct c2_vq_req {
+	u64 reply_msg;		/* ptr to reply msg */
+	wait_queue_head_t wait_object;	/* wait object for vq reqs */
+	atomic_t reply_ready;	/* set when reply is ready */
+	atomic_t refcnt;	/* used to cancel WRs... */
+	int event;
+	struct iw_cm_id *cm_id;
+	struct c2_qp *qp;
+};
+
+extern int vq_init(struct c2_dev *c2dev);
+extern void vq_term(struct c2_dev *c2dev);
+
+extern struct c2_vq_req *vq_req_alloc(struct c2_dev *c2dev);
+extern void vq_req_free(struct c2_dev *c2dev, struct c2_vq_req *req);
+extern void vq_req_get(struct c2_dev *c2dev, struct c2_vq_req *req);
+extern void vq_req_put(struct c2_dev *c2dev, struct c2_vq_req *req);
+extern int vq_send_wr(struct c2_dev *c2dev, union c2wr * wr);
+
+extern void *vq_repbuf_alloc(struct c2_dev *c2dev);
+extern void vq_repbuf_free(struct c2_dev *c2dev, void *reply);
+
+extern int vq_wait_for_reply(struct c2_dev *c2dev, struct c2_vq_req *req);
+#endif				/* _C2_VQ_H_ */

^ permalink raw reply related

* [PATCH v2 5/7] AMSO1100 Message Queues.
From: Steve Wise @ 2006-06-07 20:06 UTC (permalink / raw)
  To: rdreier, mshefty; +Cc: linux-kernel, netdev, openib-general
In-Reply-To: <20060607200646.9259.24588.stgit@stevo-desktop>


Review Changes:

- remove useless asserts

- assert() -> BUG_ON()

- C2_DEBUG -> DEBUG
---

 drivers/infiniband/hw/amso1100/c2_mq.c |  175 ++++++++++++++++++++++++++++++++
 drivers/infiniband/hw/amso1100/c2_mq.h |  103 +++++++++++++++++++
 2 files changed, 278 insertions(+), 0 deletions(-)

diff --git a/drivers/infiniband/hw/amso1100/c2_mq.c b/drivers/infiniband/hw/amso1100/c2_mq.c
new file mode 100644
index 0000000..0b0ab02
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_mq.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "c2.h"
+#include "c2_mq.h"
+
+void *c2_mq_alloc(struct c2_mq *q)
+{
+	BUG_ON(q->magic != C2_MQ_MAGIC);
+	BUG_ON(q->type != C2_MQ_ADAPTER_TARGET);
+
+	if (c2_mq_full(q)) {
+		return NULL;
+	} else {
+#ifdef DEBUG
+		struct c2wr_hdr *m =
+		    (struct c2wr_hdr *) (q->msg_pool.host + q->priv * q->msg_size);
+#ifdef CCMSGMAGIC
+		BUG_ON(m->magic != be32_to_cpu(~CCWR_MAGIC));
+		m->magic = cpu_to_be32(CCWR_MAGIC);
+#endif
+		return m;
+#else
+		return q->msg_pool.host + q->priv * q->msg_size;
+#endif
+	}
+}
+
+void c2_mq_produce(struct c2_mq *q)
+{
+	BUG_ON(q->magic != C2_MQ_MAGIC);
+	BUG_ON(q->type != C2_MQ_ADAPTER_TARGET);
+
+	if (!c2_mq_full(q)) {
+		q->priv = (q->priv + 1) % q->q_size;
+		q->hint_count++;
+		/* Update peer's offset. */
+		__raw_writew(cpu_to_be16(q->priv), &q->peer->shared);
+	}
+}
+
+void *c2_mq_consume(struct c2_mq *q)
+{
+	BUG_ON(q->magic != C2_MQ_MAGIC);
+	BUG_ON(q->type != C2_MQ_HOST_TARGET);
+
+	if (c2_mq_empty(q)) {
+		return NULL;
+	} else {
+#ifdef DEBUG
+		struct c2wr_hdr *m = (struct c2wr_hdr *)
+		    (q->msg_pool.host + q->priv * q->msg_size);
+#ifdef CCMSGMAGIC
+		BUG_ON(m->magic != be32_to_cpu(CCWR_MAGIC));
+#endif
+		return m;
+#else
+		return q->msg_pool.host + q->priv * q->msg_size;
+#endif
+	}
+}
+
+void c2_mq_free(struct c2_mq *q)
+{
+	BUG_ON(q->magic != C2_MQ_MAGIC);
+	BUG_ON(q->type != C2_MQ_HOST_TARGET);
+
+	if (!c2_mq_empty(q)) {
+
+#ifdef CCMSGMAGIC
+		{
+			struct c2wr_hdr __iomem *m = (struct c2wr_hdr __iomem *)
+			    (q->msg_pool.adapter + q->priv * q->msg_size);
+			__raw_writel(cpu_to_be32(~CCWR_MAGIC), &m->magic);
+		}
+#endif
+		q->priv = (q->priv + 1) % q->q_size;
+		/* Update peer's offset. */
+		__raw_writew(cpu_to_be16(q->priv), &q->peer->shared);
+	}
+}
+
+
+void c2_mq_lconsume(struct c2_mq *q, u32 wqe_count)
+{
+	BUG_ON(q->magic != C2_MQ_MAGIC);
+	BUG_ON(q->type != C2_MQ_ADAPTER_TARGET);
+
+	while (wqe_count--) {
+		BUG_ON(c2_mq_empty(q));
+		*q->shared = cpu_to_be16((be16_to_cpu(*q->shared)+1) % q->q_size);
+	}
+}
+
+
+u32 c2_mq_count(struct c2_mq *q)
+{
+	s32 count;
+
+	if (q->type == C2_MQ_HOST_TARGET) {
+		count = be16_to_cpu(*q->shared) - q->priv;
+	} else {
+		count = q->priv - be16_to_cpu(*q->shared);
+	}
+
+	if (count < 0) {
+		count += q->q_size;
+	}
+
+	return (u32) count;
+}
+
+void c2_mq_req_init(struct c2_mq *q, u32 index, u32 q_size, u32 msg_size,
+		    u8 __iomem *pool_start, u16 __iomem *peer, u32 type)
+{
+	BUG_ON(!q->shared);
+
+	/* This code assumes the byte swapping has already been done! */
+	q->index = index;
+	q->q_size = q_size;
+	q->msg_size = msg_size;
+	q->msg_pool.adapter = pool_start;
+	q->peer = (struct c2_mq_shared __iomem *) peer;
+	q->magic = C2_MQ_MAGIC;
+	q->type = type;
+	q->priv = 0;
+	q->hint_count = 0;
+	return;
+}
+void c2_mq_rep_init(struct c2_mq *q, u32 index, u32 q_size, u32 msg_size,
+		    u8 *pool_start, u16 __iomem *peer, u32 type)
+{
+	BUG_ON(!q->shared);
+
+	/* This code assumes the byte swapping has already been done! */
+	q->index = index;
+	q->q_size = q_size;
+	q->msg_size = msg_size;
+	q->msg_pool.host = pool_start;
+	q->peer = (struct c2_mq_shared __iomem *) peer;
+	q->magic = C2_MQ_MAGIC;
+	q->type = type;
+	q->priv = 0;
+	q->hint_count = 0;
+	return;
+}
diff --git a/drivers/infiniband/hw/amso1100/c2_mq.h b/drivers/infiniband/hw/amso1100/c2_mq.h
new file mode 100644
index 0000000..de00184
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_mq.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _C2_MQ_H_
+#define _C2_MQ_H_
+#include <linux/kernel.h>
+#include "c2_wr.h"
+
+enum c2_shared_regs {
+
+	C2_SHARED_ARMED = 0x10,
+	C2_SHARED_NOTIFY = 0x18,
+	C2_SHARED_SHARED = 0x40,
+};
+
+struct c2_mq_shared {
+	u16 unused1;
+	u8 armed;
+	u8 notification_type;
+	u32 unused2;
+	u16 shared;
+	/* Pad to 64 bytes. */
+	u8 pad[64 - sizeof(u16) - 2 * sizeof(u8) - sizeof(u32) - sizeof(u16)];
+};
+
+enum c2_mq_type {
+	C2_MQ_HOST_TARGET = 1,
+	C2_MQ_ADAPTER_TARGET = 2,
+};
+
+/*
+ * c2_mq_t is for kernel-mode MQs like the VQs Cand the AEQ.
+ * c2_user_mq_t (which is the same format) is for user-mode MQs...
+ */
+#define C2_MQ_MAGIC 0x4d512020	/* 'MQ  ' */
+struct c2_mq {
+	u32 magic; 
+	union {
+		u8 *host;
+		u8 __iomem *adapter;
+	} msg_pool;
+	u16 hint_count;
+	u16 priv;
+	struct c2_mq_shared __iomem *peer;
+	u16 *shared;
+	u32 q_size;
+	u32 msg_size;
+	u32 index;
+	enum c2_mq_type type;
+};
+
+static __inline__ int c2_mq_empty(struct c2_mq *q)
+{
+	return q->priv == be16_to_cpu(*q->shared);
+}
+
+static __inline__ int c2_mq_full(struct c2_mq *q)
+{
+	return q->priv == (be16_to_cpu(*q->shared) + q->q_size - 1) % q->q_size;
+}
+
+extern void c2_mq_lconsume(struct c2_mq *q, u32 wqe_count);
+extern void *c2_mq_alloc(struct c2_mq *q);
+extern void c2_mq_produce(struct c2_mq *q);
+extern void *c2_mq_consume(struct c2_mq *q);
+extern void c2_mq_free(struct c2_mq *q);
+extern u32 c2_mq_count(struct c2_mq *q);
+extern void c2_mq_req_init(struct c2_mq *q, u32 index, u32 q_size, u32 msg_size,
+		       u8 __iomem *pool_start, u16 __iomem *peer, u32 type);
+extern void c2_mq_rep_init(struct c2_mq *q, u32 index, u32 q_size, u32 msg_size,
+			   u8 *pool_start, u16 __iomem *peer, u32 type);
+
+#endif				/* _C2_MQ_H_ */

^ permalink raw reply related

* [PATCH v2 3/7] AMSO1100 OpenFabrics Provider.
From: Steve Wise @ 2006-06-07 20:06 UTC (permalink / raw)
  To: rdreier, mshefty; +Cc: linux-kernel, netdev, openib-general
In-Reply-To: <20060607200646.9259.24588.stgit@stevo-desktop>


Review Changes:

sizeof -> sizeof()

dprintk() -> pr_debug()

assert() -> BUG_ON()

C2_DEBUG -> DEBUG
---

 drivers/infiniband/hw/amso1100/c2_cm.c       |  452 ++++++++++++
 drivers/infiniband/hw/amso1100/c2_cq.c       |  423 +++++++++++
 drivers/infiniband/hw/amso1100/c2_pd.c       |   71 ++
 drivers/infiniband/hw/amso1100/c2_provider.c |  867 +++++++++++++++++++++++
 drivers/infiniband/hw/amso1100/c2_provider.h |  182 +++++
 drivers/infiniband/hw/amso1100/c2_qp.c       |  975 ++++++++++++++++++++++++++
 drivers/infiniband/hw/amso1100/c2_user.h     |   82 ++
 7 files changed, 3052 insertions(+), 0 deletions(-)

diff --git a/drivers/infiniband/hw/amso1100/c2_cm.c b/drivers/infiniband/hw/amso1100/c2_cm.c
new file mode 100644
index 0000000..018d11f
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_cm.c
@@ -0,0 +1,452 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc.  All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include "c2.h"
+#include "c2_wr.h"
+#include "c2_vq.h"
+#include <rdma/iw_cm.h>
+
+int c2_llp_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
+{
+	struct c2_dev *c2dev = to_c2dev(cm_id->device);
+	struct ib_qp *ibqp;
+	struct c2_qp *qp;
+	struct c2wr_qp_connect_req *wr;	/* variable size needs a malloc. */
+	struct c2_vq_req *vq_req;
+	int err;
+
+	ibqp = c2_get_qp(cm_id->device, iw_param->qpn);
+	if (!ibqp)
+		return -EINVAL;
+	qp = to_c2qp(ibqp);
+
+	/* Associate QP <--> CM_ID */
+	cm_id->provider_data = qp;
+	cm_id->add_ref(cm_id);
+	qp->cm_id = cm_id;
+
+	/*
+	 * only support the max private_data length
+	 */
+	if (iw_param->private_data_len > C2_MAX_PRIVATE_DATA_SIZE) {
+		err = -EINVAL;
+		goto bail0;
+	}
+	/* 
+	 * Set the rdma read limits 
+	 */
+	err = c2_qp_set_read_limits(c2dev, qp, iw_param->ord, iw_param->ird);
+	if (err)
+		goto bail0;
+
+	/*
+	 * Create and send a WR_QP_CONNECT...
+	 */
+	wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);
+	if (!wr) {
+		err = -ENOMEM;
+		goto bail0;
+	}
+
+	vq_req = vq_req_alloc(c2dev);
+	if (!vq_req) {
+		err = -ENOMEM;
+		goto bail1;
+	}
+
+	c2_wr_set_id(wr, CCWR_QP_CONNECT);
+	wr->hdr.context = 0;
+	wr->rnic_handle = c2dev->adapter_handle;
+	wr->qp_handle = qp->adapter_handle;
+
+	wr->remote_addr = cm_id->remote_addr.sin_addr.s_addr;
+	wr->remote_port = cm_id->remote_addr.sin_port;
+
+	/*
+	 * Move any private data from the callers's buf into 
+	 * the WR.
+	 */
+	if (iw_param->private_data) {
+		wr->private_data_length = 
+			cpu_to_be32(iw_param->private_data_len);
+		memcpy(&wr->private_data[0], iw_param->private_data,
+		       iw_param->private_data_len);
+	} else
+		wr->private_data_length = 0;
+
+	/*
+	 * Send WR to adapter.  NOTE: There is no synch reply from 
+	 * the adapter.
+	 */
+	err = vq_send_wr(c2dev, (union c2wr *) wr);
+	vq_req_free(c2dev, vq_req);
+
+ bail1:
+	kfree(wr);
+ bail0:
+	if (err) {
+		/* 
+		 * If we fail, release reference on QP and
+		 * disassociate QP from CM_ID  
+		 */
+		cm_id->provider_data = NULL;
+		qp->cm_id = NULL;
+		cm_id->rem_ref(cm_id);
+	}
+	return err;
+}
+
+int c2_llp_service_create(struct iw_cm_id *cm_id, int backlog)
+{
+	struct c2_dev *c2dev;
+	struct c2wr_ep_listen_create_req wr;
+	struct c2wr_ep_listen_create_rep *reply;
+	struct c2_vq_req *vq_req;
+	int err;
+
+	c2dev = to_c2dev(cm_id->device);
+	if (c2dev == NULL)
+		return -EINVAL;
+
+	/*
+	 * Allocate verbs request.
+	 */
+	vq_req = vq_req_alloc(c2dev);
+	if (!vq_req)
+		return -ENOMEM;
+
+	/* 
+	 * Build the WR
+	 */
+	c2_wr_set_id(&wr, CCWR_EP_LISTEN_CREATE);
+	wr.hdr.context = (u64) (unsigned long) vq_req;
+	wr.rnic_handle = c2dev->adapter_handle;
+	wr.local_addr = cm_id->local_addr.sin_addr.s_addr;
+	wr.local_port = cm_id->local_addr.sin_port;
+	wr.backlog = cpu_to_be32(backlog);
+	wr.user_context = (u64) (unsigned long) cm_id;
+
+	/*
+	 * Reference the request struct.  Dereferenced in the int handler.
+	 */
+	vq_req_get(c2dev, vq_req);
+
+	/*
+	 * Send WR to adapter
+	 */
+	err = vq_send_wr(c2dev, (union c2wr *) & wr);
+	if (err) {
+		vq_req_put(c2dev, vq_req);
+		goto bail0;
+	}
+
+	/*
+	 * Wait for reply from adapter
+	 */
+	err = vq_wait_for_reply(c2dev, vq_req);
+	if (err)
+		goto bail0;
+
+	/*
+	 * Process reply 
+	 */
+	reply =
+	    (struct c2wr_ep_listen_create_rep *) (unsigned long) vq_req->reply_msg;
+	if (!reply) {
+		err = -ENOMEM;
+		goto bail1;
+	}
+
+	if ((err = c2_errno(reply)) != 0)
+		goto bail1;
+
+	/* 
+	 * Keep the adapter handle. Used in subsequent destroy 
+	 */
+	cm_id->provider_data = (void*)(unsigned long) reply->ep_handle;
+
+	/*
+	 * free vq stuff
+	 */
+	vq_repbuf_free(c2dev, reply);
+	vq_req_free(c2dev, vq_req);
+
+	return 0;
+
+ bail1:
+	vq_repbuf_free(c2dev, reply);
+ bail0:
+	vq_req_free(c2dev, vq_req);
+	return err;
+}
+
+
+int c2_llp_service_destroy(struct iw_cm_id *cm_id)
+{
+
+	struct c2_dev *c2dev;
+	struct c2wr_ep_listen_destroy_req wr;
+	struct c2wr_ep_listen_destroy_rep *reply;
+	struct c2_vq_req *vq_req;
+	int err;
+
+	c2dev = to_c2dev(cm_id->device);
+	if (c2dev == NULL)
+		return -EINVAL;
+
+	/*
+	 * Allocate verbs request.
+	 */
+	vq_req = vq_req_alloc(c2dev);
+	if (!vq_req)
+		return -ENOMEM;
+
+	/* 
+	 * Build the WR
+	 */
+	c2_wr_set_id(&wr, CCWR_EP_LISTEN_DESTROY);
+	wr.hdr.context = (unsigned long) vq_req;
+	wr.rnic_handle = c2dev->adapter_handle;
+	wr.ep_handle = (u32)(unsigned long)cm_id->provider_data;
+
+	/*
+	 * reference the request struct.  dereferenced in the int handler.
+	 */
+	vq_req_get(c2dev, vq_req);
+
+	/*
+	 * Send WR to adapter
+	 */
+	err = vq_send_wr(c2dev, (union c2wr *) & wr);
+	if (err) {
+		vq_req_put(c2dev, vq_req);
+		goto bail0;
+	}
+
+	/*
+	 * Wait for reply from adapter
+	 */
+	err = vq_wait_for_reply(c2dev, vq_req);
+	if (err)
+		goto bail0;
+
+	/*
+	 * Process reply 
+	 */
+	reply=(struct c2wr_ep_listen_destroy_rep *)(unsigned long)vq_req->reply_msg;
+	if (!reply) {
+		err = -ENOMEM;
+		goto bail0;
+	}
+	if ((err = c2_errno(reply)) != 0)
+		goto bail1;
+
+ bail1:
+	vq_repbuf_free(c2dev, reply);
+ bail0:
+	vq_req_free(c2dev, vq_req);
+	return err;
+}
+
+int c2_llp_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
+{
+	struct c2_dev *c2dev = to_c2dev(cm_id->device);
+	struct c2_qp *qp;
+	struct ib_qp *ibqp;
+	struct c2wr_cr_accept_req *wr;	/* variable length WR */
+	struct c2_vq_req *vq_req;
+	struct c2wr_cr_accept_rep *reply;	/* VQ Reply msg ptr. */
+	int err;
+
+	ibqp = c2_get_qp(cm_id->device, iw_param->qpn);
+	if (!ibqp)
+		return -EINVAL;
+	qp = to_c2qp(ibqp);
+
+	/* Set the RDMA read limits */
+	err = c2_qp_set_read_limits(c2dev, qp, iw_param->ord, iw_param->ird);
+	if (err)
+		goto bail0;
+
+	/* Allocate verbs request. */
+	vq_req = vq_req_alloc(c2dev);
+	if (!vq_req) {
+		err = -ENOMEM;
+		goto bail1;
+	}
+	vq_req->qp = qp;
+	vq_req->cm_id = cm_id;
+	vq_req->event = IW_CM_EVENT_ESTABLISHED;
+
+	wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);
+	if (!wr) {
+		err = -ENOMEM;
+		goto bail2;
+	}
+
+	/* Build the WR */
+	c2_wr_set_id(wr, CCWR_CR_ACCEPT);
+	wr->hdr.context = (unsigned long) vq_req;
+	wr->rnic_handle = c2dev->adapter_handle;
+	wr->ep_handle = (u32) (unsigned long) cm_id->provider_data;
+	wr->qp_handle = qp->adapter_handle;
+
+	/* Replace the cr_handle with the QP after accept */
+	cm_id->provider_data = qp;
+	cm_id->add_ref(cm_id);
+	qp->cm_id = cm_id;
+
+	cm_id->provider_data = qp;
+
+	/* Validate private_data length */
+	if (iw_param->private_data_len > C2_MAX_PRIVATE_DATA_SIZE) {
+		err = -EINVAL;
+		goto bail2;
+	}
+
+	if (iw_param->private_data) {
+		wr->private_data_length = cpu_to_be32(iw_param->private_data_len);
+		memcpy(&wr->private_data[0], 
+		       iw_param->private_data, iw_param->private_data_len);
+	} else 
+		wr->private_data_length = 0;
+
+	/* Reference the request struct.  Dereferenced in the int handler. */
+	vq_req_get(c2dev, vq_req);
+
+	/* Send WR to adapter */
+	err = vq_send_wr(c2dev, (union c2wr *) wr);
+	if (err) {
+		vq_req_put(c2dev, vq_req);
+		goto bail2;
+	}
+
+	/* Wait for reply from adapter */
+	err = vq_wait_for_reply(c2dev, vq_req);
+	if (err)
+		goto bail2;
+
+	/* Check that reply is present */
+	reply = (struct c2wr_cr_accept_rep *) (unsigned long) vq_req->reply_msg;
+	if (!reply) {
+		err = -ENOMEM;
+		goto bail2;
+	}
+
+	err = c2_errno(reply);
+	vq_repbuf_free(c2dev, reply);
+
+	if (!err)
+		c2_set_qp_state(qp, C2_QP_STATE_RTS);
+ bail2:
+	kfree(wr);
+ bail1:
+	vq_req_free(c2dev, vq_req);
+ bail0:
+	if (err) {
+		/* 
+		 * If we fail, release reference on QP and
+		 * disassociate QP from CM_ID  
+		 */
+		cm_id->provider_data = NULL;
+		qp->cm_id = NULL;
+		cm_id->rem_ref(cm_id);
+	}
+	return err;
+}
+
+int c2_llp_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
+{
+	struct c2_dev *c2dev;
+	struct c2wr_cr_reject_req wr;
+	struct c2_vq_req *vq_req;
+	struct c2wr_cr_reject_rep *reply;
+	int err;
+
+	c2dev = to_c2dev(cm_id->device);
+
+	/*
+	 * Allocate verbs request.
+	 */
+	vq_req = vq_req_alloc(c2dev);
+	if (!vq_req)
+		return -ENOMEM;
+
+	/* 
+	 * Build the WR
+	 */
+	c2_wr_set_id(&wr, CCWR_CR_REJECT);
+	wr.hdr.context = (unsigned long) vq_req;
+	wr.rnic_handle = c2dev->adapter_handle;
+	wr.ep_handle = (u32) (unsigned long) cm_id->provider_data;
+
+	/*
+	 * reference the request struct.  dereferenced in the int handler.
+	 */
+	vq_req_get(c2dev, vq_req);
+
+	/*
+	 * Send WR to adapter
+	 */
+	err = vq_send_wr(c2dev, (union c2wr *) & wr);
+	if (err) {
+		vq_req_put(c2dev, vq_req);
+		goto bail0;
+	}
+
+	/*
+	 * Wait for reply from adapter
+	 */
+	err = vq_wait_for_reply(c2dev, vq_req);
+	if (err)
+		goto bail0;
+
+	/*
+	 * Process reply 
+	 */
+	reply = (struct c2wr_cr_reject_rep *) (unsigned long) 
+		vq_req->reply_msg;
+	if (!reply) {
+		err = -ENOMEM;
+		goto bail0;
+	}
+	err = c2_errno(reply);
+	/*
+	 * free vq stuff
+	 */
+	vq_repbuf_free(c2dev, reply);
+
+ bail0:
+	vq_req_free(c2dev, vq_req);
+	return err;
+}
diff --git a/drivers/infiniband/hw/amso1100/c2_cq.c b/drivers/infiniband/hw/amso1100/c2_cq.c
new file mode 100644
index 0000000..71128ff
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_cq.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include "c2.h"
+#include "c2_vq.h"
+#include "c2_status.h"
+
+#define C2_CQ_MSG_SIZE ((sizeof(struct c2wr_ce) + 32-1) & ~(32-1))
+
+struct c2_cq *c2_cq_get(struct c2_dev *c2dev, int cqn)
+{
+	struct c2_cq *cq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&c2dev->lock, flags);
+	cq = c2dev->qptr_array[cqn];
+	if (!cq) {
+		spin_unlock_irqrestore(&c2dev->lock, flags);
+		return NULL;
+	}
+	atomic_inc(&cq->refcount);
+	spin_unlock_irqrestore(&c2dev->lock, flags);
+	return cq;
+}
+
+void c2_cq_put(struct c2_cq *cq)
+{
+	if (atomic_dec_and_test(&cq->refcount))
+		wake_up(&cq->wait);
+}
+
+void c2_cq_event(struct c2_dev *c2dev, u32 mq_index)
+{
+	struct c2_cq *cq;
+
+	cq = c2_cq_get(c2dev, mq_index);
+	if (!cq) {
+		printk("discarding events on destroyed CQN=%d\n", mq_index);
+		return;
+	}
+
+	(*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context);
+	c2_cq_put(cq);
+}
+
+void c2_cq_clean(struct c2_dev *c2dev, struct c2_qp *qp, u32 mq_index)
+{
+	struct c2_cq *cq;
+	struct c2_mq *q;
+
+	cq = c2_cq_get(c2dev, mq_index);
+	if (!cq)
+		return;
+
+	spin_lock_irq(&cq->lock);
+	q = &cq->mq;
+	if (q && !c2_mq_empty(q)) {
+		u16 priv = q->priv;
+		struct c2wr_ce *msg;
+
+		while (priv != be16_to_cpu(*q->shared)) {
+			msg = (struct c2wr_ce *) 
+				(q->msg_pool.host + priv * q->msg_size);
+			if (msg->qp_user_context == (u64) (unsigned long) qp) {
+				msg->qp_user_context = (u64) 0;
+			}
+			priv = (priv + 1) % q->q_size;
+		}
+	}
+	spin_unlock_irq(&cq->lock);
+	c2_cq_put(cq);
+}
+
+static inline enum ib_wc_status c2_cqe_status_to_openib(u8 status)
+{
+	switch (status) {
+	case C2_OK:
+		return IB_WC_SUCCESS;
+	case CCERR_FLUSHED:
+		return IB_WC_WR_FLUSH_ERR;
+	case CCERR_BASE_AND_BOUNDS_VIOLATION:
+		return IB_WC_LOC_PROT_ERR;
+	case CCERR_ACCESS_VIOLATION:
+		return IB_WC_LOC_ACCESS_ERR;
+	case CCERR_TOTAL_LENGTH_TOO_BIG:
+		return IB_WC_LOC_LEN_ERR;
+	case CCERR_INVALID_WINDOW:
+		return IB_WC_MW_BIND_ERR;
+	default:
+		return IB_WC_GENERAL_ERR;
+	}
+}
+
+
+static inline int c2_poll_one(struct c2_dev *c2dev,
+			      struct c2_cq *cq, struct ib_wc *entry)
+{
+	struct c2wr_ce *ce;
+	struct c2_qp *qp;
+	int is_recv = 0;
+
+	ce = (struct c2wr_ce *) c2_mq_consume(&cq->mq);
+	if (!ce) {
+		return -EAGAIN;
+	}
+
+	/*
+	 * if the qp returned is null then this qp has already 
+	 * been freed and we are unable process the completion.  
+	 * try pulling the next message
+	 */
+	while ((qp =
+		(struct c2_qp *) (unsigned long) ce->qp_user_context) == NULL) {
+		c2_mq_free(&cq->mq);
+		ce = (struct c2wr_ce *) c2_mq_consume(&cq->mq);
+		if (!ce)
+			return -EAGAIN;
+	}
+
+	entry->status = c2_cqe_status_to_openib(c2_wr_get_result(ce));
+	entry->wr_id = ce->hdr.context;
+	entry->qp_num = ce->handle;
+	entry->wc_flags = 0;
+	entry->slid = 0;
+	entry->sl = 0;
+	entry->src_qp = 0;
+	entry->dlid_path_bits = 0;
+	entry->pkey_index = 0;
+
+	switch (c2_wr_get_id(ce)) {
+	case C2_WR_TYPE_SEND:
+		entry->opcode = IB_WC_SEND;
+		break;
+	case C2_WR_TYPE_RDMA_WRITE:
+		entry->opcode = IB_WC_RDMA_WRITE;
+		break;
+	case C2_WR_TYPE_RDMA_READ:
+		entry->opcode = IB_WC_RDMA_READ;
+		break;
+	case C2_WR_TYPE_BIND_MW:
+		entry->opcode = IB_WC_BIND_MW;
+		break;
+	case C2_WR_TYPE_RECV:
+		entry->byte_len = be32_to_cpu(ce->bytes_rcvd);
+		entry->opcode = IB_WC_RECV;
+		is_recv = 1;
+		break;
+	default:
+		break;
+	}
+
+	/* consume the WQEs */
+	if (is_recv)
+		c2_mq_lconsume(&qp->rq_mq, 1);
+	else
+		c2_mq_lconsume(&qp->sq_mq,
+			       be32_to_cpu(c2_wr_get_wqe_count(ce)) + 1);
+
+	/* free the message */
+	c2_mq_free(&cq->mq);
+
+	return 0;
+}
+
+int c2_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
+{
+	struct c2_dev *c2dev = to_c2dev(ibcq->device);
+	struct c2_cq *cq = to_c2cq(ibcq);
+	unsigned long flags;
+	int npolled, err;
+
+	spin_lock_irqsave(&cq->lock, flags);
+
+	for (npolled = 0; npolled < num_entries; ++npolled) {
+
+		err = c2_poll_one(c2dev, cq, entry + npolled);
+		if (err)
+			break;
+	}
+
+	spin_unlock_irqrestore(&cq->lock, flags);
+
+	return npolled;
+}
+
+int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
+{
+	struct c2_mq_shared __iomem *shared;
+	struct c2_cq *cq;
+
+	cq = to_c2cq(ibcq);
+	shared = cq->mq.peer;
+
+	if (notify == IB_CQ_NEXT_COMP)
+		writeb(C2_CQ_NOTIFICATION_TYPE_NEXT, &shared->notification_type);
+	else if (notify == IB_CQ_SOLICITED)
+		writeb(C2_CQ_NOTIFICATION_TYPE_NEXT_SE, &shared->notification_type);
+	else
+		return -EINVAL;
+
+	writeb(CQ_WAIT_FOR_DMA | CQ_ARMED, &shared->armed);
+
+	/*
+	 * Now read back shared->armed to make the PCI
+	 * write synchronous.  This is necessary for
+	 * correct cq notification semantics.
+	 */
+	readb(&shared->armed);
+
+	return 0;
+}
+
+static void c2_free_cq_buf(struct c2_mq *mq)
+{
+	free_pages((unsigned long) mq->msg_pool.host, 
+		   get_order(mq->q_size * mq->msg_size));
+}
+
+static int c2_alloc_cq_buf(struct c2_mq *mq, int q_size, int msg_size)
+{
+	unsigned long pool_start;
+
+	pool_start = __get_free_pages(GFP_KERNEL, 
+				      get_order(q_size * msg_size));
+	if (!pool_start)
+		return -ENOMEM;
+
+	c2_mq_rep_init(mq, 
+		       0,		/* index (currently unknown) */
+		       q_size, 
+		       msg_size, 
+		       (u8 *) pool_start, 
+		       NULL,	/* peer (currently unknown) */
+		       C2_MQ_HOST_TARGET);
+
+	return 0;
+}
+
+int c2_init_cq(struct c2_dev *c2dev, int entries,
+	       struct c2_ucontext *ctx, struct c2_cq *cq)
+{
+	struct c2wr_cq_create_req wr;
+	struct c2wr_cq_create_rep *reply;
+	unsigned long peer_pa;
+	struct c2_vq_req *vq_req;
+	int err;
+
+	might_sleep();
+
+	cq->ibcq.cqe = entries - 1;
+	cq->is_kernel = !ctx;
+
+	/* Allocate a shared pointer */
+	cq->mq.shared = c2_alloc_mqsp(c2dev->kern_mqsp_pool);
+	if (!cq->mq.shared)
+		return -ENOMEM;
+
+	/* Allocate pages for the message pool */
+	err = c2_alloc_cq_buf(&cq->mq, entries + 1, C2_CQ_MSG_SIZE);
+	if (err)
+		goto bail0;
+
+	vq_req = vq_req_alloc(c2dev);
+	if (!vq_req) {
+		err = -ENOMEM;
+		goto bail1;
+	}
+
+	memset(&wr, 0, sizeof(wr));
+	c2_wr_set_id(&wr, CCWR_CQ_CREATE);
+	wr.hdr.context = (unsigned long) vq_req;
+	wr.rnic_handle = c2dev->adapter_handle;
+	wr.msg_size = cpu_to_be32(cq->mq.msg_size);
+	wr.depth = cpu_to_be32(cq->mq.q_size);
+	wr.shared_ht = cpu_to_be64(__pa(cq->mq.shared));
+	wr.msg_pool = cpu_to_be64(__pa(cq->mq.msg_pool.host));
+	wr.user_context = (u64) (unsigned long) (cq);
+
+	vq_req_get(c2dev, vq_req);
+
+	err = vq_send_wr(c2dev, (union c2wr *) & wr);
+	if (err) {
+		vq_req_put(c2dev, vq_req);
+		goto bail2;
+	}
+
+	err = vq_wait_for_reply(c2dev, vq_req);
+	if (err)
+		goto bail2;
+
+	reply = (struct c2wr_cq_create_rep *) (unsigned long) (vq_req->reply_msg);
+	if (!reply) {
+		err = -ENOMEM;
+		goto bail2;
+	}
+
+	if ((err = c2_errno(reply)) != 0)
+		goto bail3;
+
+	cq->adapter_handle = reply->cq_handle;
+	cq->mq.index = be32_to_cpu(reply->mq_index);
+
+	peer_pa = c2dev->pa + be32_to_cpu(reply->adapter_shared);
+	cq->mq.peer = ioremap_nocache(peer_pa, PAGE_SIZE);
+	if (!cq->mq.peer) {
+		err = -ENOMEM;
+		goto bail3;
+	}
+
+	vq_repbuf_free(c2dev, reply);
+	vq_req_free(c2dev, vq_req);
+
+	spin_lock_init(&cq->lock);
+	atomic_set(&cq->refcount, 1);
+	init_waitqueue_head(&cq->wait);
+
+	/* 
+	 * Use the MQ index allocated by the adapter to
+	 * store the CQ in the qptr_array
+	 */
+	cq->cqn = cq->mq.index;
+	c2dev->qptr_array[cq->cqn] = cq;
+
+	return 0;
+
+      bail3:
+	vq_repbuf_free(c2dev, reply);
+      bail2:
+	vq_req_free(c2dev, vq_req);
+      bail1:
+	c2_free_cq_buf(&cq->mq);
+      bail0:
+	c2_free_mqsp(cq->mq.shared);
+
+	return err;
+}
+
+void c2_free_cq(struct c2_dev *c2dev, struct c2_cq *cq)
+{
+	int err;
+	struct c2_vq_req *vq_req;
+	struct c2wr_cq_destroy_req wr;
+	struct c2wr_cq_destroy_rep *reply;
+
+	might_sleep();
+
+	/* Clear CQ from the qptr array */
+	spin_lock_irq(&c2dev->lock);
+	c2dev->qptr_array[cq->mq.index] = NULL;
+	atomic_dec(&cq->refcount);
+	spin_unlock_irq(&c2dev->lock);
+
+	wait_event(cq->wait, !atomic_read(&cq->refcount));
+
+	vq_req = vq_req_alloc(c2dev);
+	if (!vq_req) {
+		goto bail0;
+	}
+
+	memset(&wr, 0, sizeof(wr));
+	c2_wr_set_id(&wr, CCWR_CQ_DESTROY);
+	wr.hdr.context = (unsigned long) vq_req;
+	wr.rnic_handle = c2dev->adapter_handle;
+	wr.cq_handle = cq->adapter_handle;
+
+	vq_req_get(c2dev, vq_req);
+
+	err = vq_send_wr(c2dev, (union c2wr *) & wr);
+	if (err) {
+		vq_req_put(c2dev, vq_req);
+		goto bail1;
+	}
+
+	err = vq_wait_for_reply(c2dev, vq_req);
+	if (err)
+		goto bail1;
+
+	reply = (struct c2wr_cq_destroy_rep *) (unsigned long) (vq_req->reply_msg);
+
+	vq_repbuf_free(c2dev, reply);
+      bail1:
+	vq_req_free(c2dev, vq_req);
+      bail0:
+	if (cq->is_kernel) {
+		c2_free_cq_buf(&cq->mq);
+	}
+
+	return;
+}
diff --git a/drivers/infiniband/hw/amso1100/c2_pd.c b/drivers/infiniband/hw/amso1100/c2_pd.c
new file mode 100644
index 0000000..27459b8
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_pd.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+
+#include "c2.h"
+#include "c2_provider.h"
+
+int c2_pd_alloc(struct c2_dev *dev, int privileged, struct c2_pd *pd)
+{
+	int err = 0;
+
+	might_sleep();
+
+	atomic_set(&pd->sqp_count, 0);
+	pd->pd_id = c2_alloc(&dev->pd_table.alloc);
+	if (pd->pd_id == -1)
+		return -ENOMEM;
+
+	return err;
+}
+
+void c2_pd_free(struct c2_dev *dev, struct c2_pd *pd)
+{
+	might_sleep();
+	c2_free(&dev->pd_table.alloc, pd->pd_id);
+}
+
+int __devinit c2_init_pd_table(struct c2_dev *dev)
+{
+	return c2_alloc_init(&dev->pd_table.alloc, dev->props.max_pd, 0);
+}
+
+void __devexit c2_cleanup_pd_table(struct c2_dev *dev)
+{
+	/* XXX check if any PDs are still allocated? */
+	c2_alloc_cleanup(&dev->pd_table.alloc);
+}
diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c
new file mode 100644
index 0000000..eaf786e
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_provider.c
@@ -0,0 +1,867 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/if_vlan.h>
+#include <linux/crc32.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/if_arp.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+
+#include <rdma/ib_smi.h>
+#include <rdma/ib_user_verbs.h>
+#include "c2.h"
+#include "c2_provider.h"
+#include "c2_user.h"
+
+static int c2_query_device(struct ib_device *ibdev,
+			   struct ib_device_attr *props)
+{
+	struct c2_dev *c2dev = to_c2dev(ibdev);
+
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+
+	*props = c2dev->props;
+	return 0;
+}
+
+static int c2_query_port(struct ib_device *ibdev,
+			 u8 port, struct ib_port_attr *props)
+{
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+
+	props->max_mtu = IB_MTU_4096;
+	props->lid = 0;
+	props->lmc = 0;
+	props->sm_lid = 0;
+	props->sm_sl = 0;
+	props->state = IB_PORT_ACTIVE;
+	props->phys_state = 0;
+	props->port_cap_flags =
+	    IB_PORT_CM_SUP |
+	    IB_PORT_REINIT_SUP |
+	    IB_PORT_VENDOR_CLASS_SUP | IB_PORT_BOOT_MGMT_SUP;
+	props->gid_tbl_len = 1;
+	props->pkey_tbl_len = 1;
+	props->qkey_viol_cntr = 0;
+	props->active_width = 1;
+	props->active_speed = 1;
+
+	return 0;
+}
+
+static int c2_modify_port(struct ib_device *ibdev,
+			  u8 port, int port_modify_mask,
+			  struct ib_port_modify *props)
+{
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+	return 0;
+}
+
+static int c2_query_pkey(struct ib_device *ibdev,
+			 u8 port, u16 index, u16 * pkey)
+{
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+	*pkey = 0;
+	return 0;
+}
+
+static int c2_query_gid(struct ib_device *ibdev, u8 port,
+			int index, union ib_gid *gid)
+{
+	struct c2_dev *c2dev = to_c2dev(ibdev);
+
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+	memset(&(gid->raw[0]), 0, sizeof(gid->raw));
+	memcpy(&(gid->raw[0]), c2dev->pseudo_netdev->dev_addr, 6);
+
+	return 0;
+}
+
+/* Allocate the user context data structure. This keeps track
+ * of all objects associated with a particular user-mode client.
+ */
+static struct ib_ucontext *c2_alloc_ucontext(struct ib_device *ibdev,
+					     struct ib_udata *udata)
+{
+	struct c2_ucontext *context;
+
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+	context = kmalloc(sizeof(*context), GFP_KERNEL);
+	if (!context)
+		return ERR_PTR(-ENOMEM);
+
+	return &context->ibucontext;
+}
+
+static int c2_dealloc_ucontext(struct ib_ucontext *context)
+{
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+	kfree(context);
+	return 0;
+}
+
+static int c2_mmap_uar(struct ib_ucontext *context, struct vm_area_struct *vma)
+{
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+	return -ENOSYS;
+}
+
+static struct ib_pd *c2_alloc_pd(struct ib_device *ibdev,
+				 struct ib_ucontext *context,
+				 struct ib_udata *udata)
+{
+	struct c2_pd *pd;
+	int err;
+
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+
+	pd = kmalloc(sizeof(*pd), GFP_KERNEL);
+	if (!pd)
+		return ERR_PTR(-ENOMEM);
+
+	err = c2_pd_alloc(to_c2dev(ibdev), !context, pd);
+	if (err) {
+		kfree(pd);
+		return ERR_PTR(err);
+	}
+
+	if (context) {
+		if (ib_copy_to_udata(udata, &pd->pd_id, sizeof(__u32))) {
+			c2_pd_free(to_c2dev(ibdev), pd);
+			kfree(pd);
+			return ERR_PTR(-EFAULT);
+		}
+	}
+
+	return &pd->ibpd;
+}
+
+static int c2_dealloc_pd(struct ib_pd *pd)
+{
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+	c2_pd_free(to_c2dev(pd->device), to_c2pd(pd));
+	kfree(pd);
+
+	return 0;
+}
+
+static struct ib_ah *c2_ah_create(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
+{
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+	return ERR_PTR(-ENOSYS);
+}
+
+static int c2_ah_destroy(struct ib_ah *ah)
+{
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+	return -ENOSYS;
+}
+
+static void c2_add_ref(struct ib_qp *ibqp)
+{
+	struct c2_qp *qp;
+	BUG_ON(!ibqp);
+	qp = to_c2qp(ibqp);
+	atomic_inc(&qp->refcount);
+}
+
+static void c2_rem_ref(struct ib_qp *ibqp)
+{
+	struct c2_qp *qp;
+	BUG_ON(!ibqp);
+	qp = to_c2qp(ibqp);
+	if (atomic_dec_and_test(&qp->refcount))
+		wake_up(&qp->wait);
+}
+
+struct ib_qp *c2_get_qp(struct ib_device *device, int qpn)
+{
+	struct c2_dev* c2dev = to_c2dev(device);
+	struct c2_qp *qp;
+
+	qp = c2dev->qp_table.map[qpn];
+	pr_debug("%s Returning QP=%p for QPN=%d, device=%p, refcount=%d\n",
+		__FUNCTION__, qp, qpn, device,
+		(qp?atomic_read(&qp->refcount):0));
+
+	return (qp?&qp->ibqp:NULL);
+}
+
+static struct ib_qp *c2_create_qp(struct ib_pd *pd,
+				  struct ib_qp_init_attr *init_attr,
+				  struct ib_udata *udata)
+{
+	struct c2_qp *qp;
+	int err;
+
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+
+	switch (init_attr->qp_type) {
+	case IB_QPT_RC:
+		qp = kzalloc(sizeof(*qp), GFP_KERNEL);
+		if (!qp) {
+			pr_debug("%s: Unable to allocate QP\n", __FUNCTION__);
+			return ERR_PTR(-ENOMEM);
+		}
+		spin_lock_init(&qp->lock);
+		if (pd->uobject) {
+			/* XXX userspace specific */
+		}
+
+		err = c2_alloc_qp(to_c2dev(pd->device),
+				  to_c2pd(pd), init_attr, qp);
+		
+		if (err && pd->uobject) {
+			/* XXX userspace specific */
+		}
+
+		break;
+	default:
+		pr_debug("%s: Invalid QP type: %d\n", __FUNCTION__,
+			init_attr->qp_type);
+		return ERR_PTR(-EINVAL);
+		break;
+	}
+
+	if (err) {
+		kfree(qp);
+		return ERR_PTR(err);
+	}
+
+	return &qp->ibqp;
+}
+
+static int c2_destroy_qp(struct ib_qp *ib_qp)
+{
+	struct c2_qp *qp = to_c2qp(ib_qp);
+
+	pr_debug("%s:%u qp=%p,qp->state=%d\n", 
+		__FUNCTION__, __LINE__,ib_qp,qp->state);
+	c2_free_qp(to_c2dev(ib_qp->device), qp);
+	kfree(qp);
+	return 0;
+}
+
+static struct ib_cq *c2_create_cq(struct ib_device *ibdev, int entries,
+				  struct ib_ucontext *context,
+				  struct ib_udata *udata)
+{
+	struct c2_cq *cq;
+	int err;
+
+	cq = kmalloc(sizeof(*cq), GFP_KERNEL);
+	if (!cq) {
+		pr_debug("%s: Unable to allocate CQ\n", __FUNCTION__);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	err = c2_init_cq(to_c2dev(ibdev), entries, NULL, cq);
+	if (err) {
+		pr_debug("%s: error initializing CQ\n", __FUNCTION__);
+		kfree(cq);
+		return ERR_PTR(err);
+	}
+
+	return &cq->ibcq;
+}
+
+static int c2_destroy_cq(struct ib_cq *ib_cq)
+{
+	struct c2_cq *cq = to_c2cq(ib_cq);
+
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+
+	c2_free_cq(to_c2dev(ib_cq->device), cq);
+	kfree(cq);
+
+	return 0;
+}
+
+static inline u32 c2_convert_access(int acc)
+{
+	return (acc & IB_ACCESS_REMOTE_WRITE ? C2_ACF_REMOTE_WRITE : 0) |
+	    (acc & IB_ACCESS_REMOTE_READ ? C2_ACF_REMOTE_READ : 0) |
+	    (acc & IB_ACCESS_LOCAL_WRITE ? C2_ACF_LOCAL_WRITE : 0) |
+	    C2_ACF_LOCAL_READ | C2_ACF_WINDOW_BIND;
+}
+
+static struct ib_mr *c2_reg_phys_mr(struct ib_pd *ib_pd,
+				    struct ib_phys_buf *buffer_list,
+				    int num_phys_buf, int acc, u64 * iova_start)
+{
+	struct c2_mr *mr;
+	u64 *page_list;
+	u32 total_len;
+	int err, i, j, k, page_shift, pbl_depth;
+
+	pbl_depth = 0;
+	total_len = 0;
+
+	page_shift = PAGE_SHIFT;
+	/*
+	 * If there is only 1 buffer we assume this could
+	 * be a map of all phy mem...use a 32k page_shift.
+	 */
+	if (num_phys_buf == 1)
+		page_shift += 3;	/* XXX */
+
+	for (i = 0; i < num_phys_buf; i++) {
+
+		if (buffer_list[i].addr & ~PAGE_MASK) {
+			pr_debug("Unaligned Memory Buffer: 0x%x\n",
+				(unsigned int) buffer_list[i].addr);
+			return ERR_PTR(-EINVAL);
+		}
+
+		if (!buffer_list[i].size) {
+			pr_debug("Invalid Buffer Size\n");
+			return ERR_PTR(-EINVAL);
+		}
+
+		total_len += buffer_list[i].size;
+		pbl_depth += ALIGN(buffer_list[i].size, 
+				   (1 << page_shift)) >> page_shift;
+	}
+
+	page_list = vmalloc(sizeof(u64) * pbl_depth);
+	if (!page_list) {
+		pr_debug("couldn't vmalloc page_list of size %zd\n",
+			(sizeof(u64) * pbl_depth));
+		return ERR_PTR(-ENOMEM);
+	}
+
+	for (i = 0, j = 0; i < num_phys_buf; i++) {
+
+		int naddrs;
+
+ 		naddrs = ALIGN(buffer_list[i].size, 
+			       (1 << page_shift)) >> page_shift;
+		for (k = 0; k < naddrs; k++)
+			page_list[j++] = (buffer_list[i].addr + 
+						     (k << page_shift));
+	}
+
+	mr = kmalloc(sizeof(*mr), GFP_KERNEL);
+	if (!mr)
+		return ERR_PTR(-ENOMEM);
+
+	mr->pd = to_c2pd(ib_pd);
+	pr_debug("%s - page shift %d, pbl_depth %d, total_len %u, "
+		"*iova_start %llx, first pa %llx, last pa %llx\n",
+		__FUNCTION__, page_shift, pbl_depth, total_len, 
+		*iova_start, page_list[0], page_list[pbl_depth-1]);
+  	err = c2_nsmr_register_phys_kern(to_c2dev(ib_pd->device), page_list,
+ 					 (1 << page_shift), pbl_depth, 
+					 total_len, 0, iova_start, 
+					 c2_convert_access(acc), mr);
+	vfree(page_list);
+	if (err) {
+		kfree(mr);
+		return ERR_PTR(err);
+	}
+
+	return &mr->ibmr;
+}
+
+static struct ib_mr *c2_get_dma_mr(struct ib_pd *pd, int acc)
+{
+	struct ib_phys_buf bl;
+	u64 kva = 0;
+
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+
+	/* AMSO1100 limit */
+	bl.size = 0xffffffff;
+	bl.addr = 0;
+	return c2_reg_phys_mr(pd, &bl, 1, acc, &kva);
+}
+
+static struct ib_mr *c2_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
+				    int acc, struct ib_udata *udata)
+{
+	u64 *pages;
+	u64 kva = 0;
+	int shift, n, len;
+	int i, j, k;
+	int err = 0;
+	struct ib_umem_chunk *chunk;
+	struct c2_pd *c2pd = to_c2pd(pd);
+	struct c2_mr *c2mr;
+
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+	shift = ffs(region->page_size) - 1;
+
+	c2mr = kmalloc(sizeof(*c2mr), GFP_KERNEL);
+	if (!c2mr)
+		return ERR_PTR(-ENOMEM);
+	c2mr->pd = c2pd;
+
+	n = 0;
+	list_for_each_entry(chunk, &region->chunk_list, list)
+		n += chunk->nents;
+
+	pages = kmalloc(n * sizeof(u64), GFP_KERNEL);
+	if (!pages) {
+		err = -ENOMEM;
+		goto err;
+	}
+
+	i = 0;
+	list_for_each_entry(chunk, &region->chunk_list, list) {
+		for (j = 0; j < chunk->nmap; ++j) {
+			len = sg_dma_len(&chunk->page_list[j]) >> shift;
+			for (k = 0; k < len; ++k) {
+				pages[i++] = 
+					sg_dma_address(&chunk->page_list[j]) +
+					(region->page_size * k);
+			}
+		}
+	}
+
+	kva = (u64)region->virt_base;
+  	err = c2_nsmr_register_phys_kern(to_c2dev(pd->device), 
+					 pages,
+ 					 region->page_size,
+					 i, 
+					 region->length, 
+					 region->offset,
+					 &kva,
+					 c2_convert_access(acc), 
+					 c2mr);
+	kfree(pages);
+	if (err) {
+		kfree(c2mr);
+		return ERR_PTR(err);
+	}
+	return &c2mr->ibmr;
+
+err:
+	kfree(c2mr);
+	return ERR_PTR(err);
+}
+
+static int c2_dereg_mr(struct ib_mr *ib_mr)
+{
+	struct c2_mr *mr = to_c2mr(ib_mr);
+	int err;
+
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+
+	err = c2_stag_dealloc(to_c2dev(ib_mr->device), ib_mr->lkey);
+	if (err)
+		pr_debug("c2_stag_dealloc failed: %d\n", err);
+	else
+		kfree(mr);
+
+	return err;
+}
+
+static ssize_t show_rev(struct class_device *cdev, char *buf)
+{
+	struct c2_dev *dev = container_of(cdev, struct c2_dev, ibdev.class_dev);
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+	return sprintf(buf, "%x\n", dev->props.hw_ver);
+}
+
+static ssize_t show_fw_ver(struct class_device *cdev, char *buf)
+{
+	struct c2_dev *dev = container_of(cdev, struct c2_dev, ibdev.class_dev);
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+	return sprintf(buf, "%x.%x.%x\n",
+		       (int) (dev->props.fw_ver >> 32),
+		       (int) (dev->props.fw_ver >> 16) & 0xffff,
+		       (int) (dev->props.fw_ver & 0xffff));
+}
+
+static ssize_t show_hca(struct class_device *cdev, char *buf)
+{
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+	return sprintf(buf, "AMSO1100\n");
+}
+
+static ssize_t show_board(struct class_device *cdev, char *buf)
+{
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+	return sprintf(buf, "%.*s\n", 32, "AMSO1100 Board ID");
+}
+
+static CLASS_DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
+static CLASS_DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL);
+static CLASS_DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);
+static CLASS_DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL);
+
+static struct class_device_attribute *c2_class_attributes[] = {
+	&class_device_attr_hw_rev,
+	&class_device_attr_fw_ver,
+	&class_device_attr_hca_type,
+	&class_device_attr_board_id
+};
+
+static int c2_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+			int attr_mask)
+{
+	int err;
+
+	err =
+	    c2_qp_modify(to_c2dev(ibqp->device), to_c2qp(ibqp), attr,
+			 attr_mask);
+
+	return err;
+}
+
+static int c2_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+	return -ENOSYS;
+}
+
+static int c2_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+	return -ENOSYS;
+}
+
+static int c2_process_mad(struct ib_device *ibdev,
+			  int mad_flags,
+			  u8 port_num,
+			  struct ib_wc *in_wc,
+			  struct ib_grh *in_grh,
+			  struct ib_mad *in_mad, struct ib_mad *out_mad)
+{
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+	return -ENOSYS;
+}
+
+static int c2_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
+{
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+
+	/* Request a connection */
+	return c2_llp_connect(cm_id, iw_param);
+}
+
+static int c2_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
+{
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+
+	/* Accept the new connection */
+	return c2_llp_accept(cm_id, iw_param);
+}
+
+static int c2_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
+{
+	int err;
+
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+
+	err = c2_llp_reject(cm_id, pdata, pdata_len);
+	return err;
+}
+
+static int c2_service_create(struct iw_cm_id *cm_id, int backlog)
+{
+	int err;
+
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+	err = c2_llp_service_create(cm_id, backlog);
+	pr_debug("%s:%u err=%d\n", 
+		__FUNCTION__, __LINE__,
+		err);
+	return err;
+}
+
+static int c2_service_destroy(struct iw_cm_id *cm_id)
+{
+	int err;
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+
+	err = c2_llp_service_destroy(cm_id);
+
+	return err;
+}
+
+static int c2_pseudo_up(struct net_device *netdev)
+{
+	struct in_device *ind;
+	struct c2_dev *c2dev = netdev->priv;
+
+	ind = in_dev_get(netdev);
+	if (!ind)
+		return 0;
+
+	pr_debug("adding...\n");
+	for_ifa(ind) {
+#ifdef DEBUG
+		u8 *ip = (u8 *) & ifa->ifa_address;
+
+		pr_debug("%s: %d.%d.%d.%d\n",
+		       ifa->ifa_label, ip[0], ip[1], ip[2], ip[3]);
+#endif
+		c2_add_addr(c2dev, ifa->ifa_address, ifa->ifa_mask);
+	}
+	endfor_ifa(ind);
+	in_dev_put(ind);
+
+	return 0;
+}
+
+static int c2_pseudo_down(struct net_device *netdev)
+{
+	struct in_device *ind;
+	struct c2_dev *c2dev = netdev->priv;
+
+	ind = in_dev_get(netdev);
+	if (!ind)
+		return 0;
+
+	pr_debug("deleting...\n");
+	for_ifa(ind) {
+#ifdef DEBUG
+		u8 *ip = (u8 *) & ifa->ifa_address;
+
+		pr_debug("%s: %d.%d.%d.%d\n",
+		       ifa->ifa_label, ip[0], ip[1], ip[2], ip[3]);
+#endif
+		c2_del_addr(c2dev, ifa->ifa_address, ifa->ifa_mask);
+	}
+	endfor_ifa(ind);
+	in_dev_put(ind);
+
+	return 0;
+}
+
+static int c2_pseudo_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+	kfree_skb(skb);
+	return NETDEV_TX_OK;
+}
+
+static int c2_pseudo_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	int ret = 0;
+
+	if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
+		return -EINVAL;
+
+	netdev->mtu = new_mtu;
+
+	/* XXX tell rnic about new rmda interface mtu */
+	return ret;
+}
+
+static void setup(struct net_device *netdev)
+{
+	SET_MODULE_OWNER(netdev);
+	netdev->open = c2_pseudo_up;
+	netdev->stop = c2_pseudo_down;
+	netdev->hard_start_xmit = c2_pseudo_xmit_frame;
+	netdev->get_stats = NULL;
+	netdev->tx_timeout = NULL;
+	netdev->set_mac_address = NULL;
+	netdev->change_mtu = c2_pseudo_change_mtu;
+	netdev->watchdog_timeo = 0;
+	netdev->type = ARPHRD_ETHER;
+	netdev->mtu = 1500;
+	netdev->hard_header_len = ETH_HLEN;
+	netdev->addr_len = ETH_ALEN;
+	netdev->tx_queue_len = 0;
+	netdev->flags |= IFF_NOARP;
+	return;
+}
+
+static struct net_device *c2_pseudo_netdev_init(struct c2_dev *c2dev)
+{
+	char name[IFNAMSIZ];
+	struct net_device *netdev;
+
+	/* change ethxxx to iwxxx */
+	strcpy(name, "iw");
+	strcat(name, &c2dev->netdev->name[3]);
+	netdev = alloc_netdev(sizeof(*netdev), name, setup);
+	if (!netdev) {
+		printk(KERN_ERR PFX "%s -  etherdev alloc failed",
+			__FUNCTION__);
+		return NULL;
+	}
+
+	netdev->priv = c2dev;
+
+	SET_NETDEV_DEV(netdev, &c2dev->pcidev->dev);
+
+	memcpy_fromio(netdev->dev_addr, c2dev->kva + C2_REGS_RDMA_ENADDR, 6);
+
+	/* Print out the MAC address */
+	pr_debug("%s: MAC %02X:%02X:%02X:%02X:%02X:%02X\n",
+		netdev->name,
+		netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
+		netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
+
+	/* Disable network packets */
+	netif_stop_queue(netdev);
+	return netdev;
+}
+
+int c2_register_device(struct c2_dev *dev)
+{
+	int ret;
+	int i;
+
+	/* Register pseudo network device */
+	dev->pseudo_netdev = c2_pseudo_netdev_init(dev);
+	if (dev->pseudo_netdev) {
+		ret = register_netdev(dev->pseudo_netdev);
+		if (ret) {
+			printk(KERN_ERR PFX
+				"Unable to register netdev, ret = %d\n", ret);
+			free_netdev(dev->pseudo_netdev);
+			return ret;
+		}
+	}
+
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+	strlcpy(dev->ibdev.name, "amso%d", IB_DEVICE_NAME_MAX);
+	dev->ibdev.owner = THIS_MODULE;
+	dev->ibdev.uverbs_cmd_mask =
+	    (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
+	    (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
+	    (1ull << IB_USER_VERBS_CMD_QUERY_PORT) |
+	    (1ull << IB_USER_VERBS_CMD_ALLOC_PD) |
+	    (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) |
+	    (1ull << IB_USER_VERBS_CMD_REG_MR) |
+	    (1ull << IB_USER_VERBS_CMD_DEREG_MR) |
+	    (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
+	    (1ull << IB_USER_VERBS_CMD_CREATE_CQ) |
+	    (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) |
+	    (1ull << IB_USER_VERBS_CMD_REQ_NOTIFY_CQ) |
+	    (1ull << IB_USER_VERBS_CMD_CREATE_QP) |
+	    (1ull << IB_USER_VERBS_CMD_MODIFY_QP) |
+	    (1ull << IB_USER_VERBS_CMD_POLL_CQ) |
+	    (1ull << IB_USER_VERBS_CMD_DESTROY_QP) |
+	    (1ull << IB_USER_VERBS_CMD_POST_SEND) |
+	    (1ull << IB_USER_VERBS_CMD_POST_RECV);
+
+	dev->ibdev.node_type = RDMA_NODE_RNIC;
+	memset(&dev->ibdev.node_guid, 0, sizeof(dev->ibdev.node_guid));
+	memcpy(&dev->ibdev.node_guid, dev->pseudo_netdev->dev_addr, 6);
+	dev->ibdev.phys_port_cnt = 1;
+	dev->ibdev.dma_device = &dev->pcidev->dev;
+	dev->ibdev.class_dev.dev = &dev->pcidev->dev;
+	dev->ibdev.query_device = c2_query_device;
+	dev->ibdev.query_port = c2_query_port;
+	dev->ibdev.modify_port = c2_modify_port;
+	dev->ibdev.query_pkey = c2_query_pkey;
+	dev->ibdev.query_gid = c2_query_gid;
+	dev->ibdev.alloc_ucontext = c2_alloc_ucontext;
+	dev->ibdev.dealloc_ucontext = c2_dealloc_ucontext;
+	dev->ibdev.mmap = c2_mmap_uar;
+	dev->ibdev.alloc_pd = c2_alloc_pd;
+	dev->ibdev.dealloc_pd = c2_dealloc_pd;
+	dev->ibdev.create_ah = c2_ah_create;
+	dev->ibdev.destroy_ah = c2_ah_destroy;
+	dev->ibdev.create_qp = c2_create_qp;
+	dev->ibdev.modify_qp = c2_modify_qp;
+	dev->ibdev.destroy_qp = c2_destroy_qp;
+	dev->ibdev.create_cq = c2_create_cq;
+	dev->ibdev.destroy_cq = c2_destroy_cq;
+	dev->ibdev.poll_cq = c2_poll_cq;
+	dev->ibdev.get_dma_mr = c2_get_dma_mr;
+	dev->ibdev.reg_phys_mr = c2_reg_phys_mr;
+	dev->ibdev.reg_user_mr = c2_reg_user_mr;
+	dev->ibdev.dereg_mr = c2_dereg_mr;
+
+	dev->ibdev.alloc_fmr = NULL;
+	dev->ibdev.unmap_fmr = NULL;
+	dev->ibdev.dealloc_fmr = NULL;
+	dev->ibdev.map_phys_fmr = NULL;
+
+	dev->ibdev.attach_mcast = c2_multicast_attach;
+	dev->ibdev.detach_mcast = c2_multicast_detach;
+	dev->ibdev.process_mad = c2_process_mad;
+
+	dev->ibdev.req_notify_cq = c2_arm_cq;
+	dev->ibdev.post_send = c2_post_send;
+	dev->ibdev.post_recv = c2_post_receive;
+
+	dev->ibdev.iwcm = kmalloc(sizeof(*dev->ibdev.iwcm), GFP_KERNEL);
+	dev->ibdev.iwcm->add_ref = c2_add_ref;
+	dev->ibdev.iwcm->rem_ref = c2_rem_ref;
+	dev->ibdev.iwcm->get_qp = c2_get_qp;
+	dev->ibdev.iwcm->connect = c2_connect;
+	dev->ibdev.iwcm->accept = c2_accept;
+	dev->ibdev.iwcm->reject = c2_reject;
+	dev->ibdev.iwcm->create_listen = c2_service_create;
+	dev->ibdev.iwcm->destroy_listen = c2_service_destroy;
+
+	ret = ib_register_device(&dev->ibdev);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < ARRAY_SIZE(c2_class_attributes); ++i) {
+		ret = class_device_create_file(&dev->ibdev.class_dev,
+					       c2_class_attributes[i]);
+		if (ret) {
+			unregister_netdev(dev->pseudo_netdev);
+			free_netdev(dev->pseudo_netdev);
+			ib_unregister_device(&dev->ibdev);
+			return ret;
+		}
+	}
+
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+	return 0;
+}
+
+void c2_unregister_device(struct c2_dev *dev)
+{
+	pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+	unregister_netdev(dev->pseudo_netdev);
+	free_netdev(dev->pseudo_netdev);
+	ib_unregister_device(&dev->ibdev);
+}
diff --git a/drivers/infiniband/hw/amso1100/c2_provider.h b/drivers/infiniband/hw/amso1100/c2_provider.h
new file mode 100644
index 0000000..05c4ab6
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_provider.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef C2_PROVIDER_H
+#define C2_PROVIDER_H
+#include <linux/inetdevice.h>
+
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_pack.h>
+
+#include "c2_mq.h"
+#include <rdma/iw_cm.h>
+
+#define C2_MPT_FLAG_ATOMIC        (1 << 14)
+#define C2_MPT_FLAG_REMOTE_WRITE  (1 << 13)
+#define C2_MPT_FLAG_REMOTE_READ   (1 << 12)
+#define C2_MPT_FLAG_LOCAL_WRITE   (1 << 11)
+#define C2_MPT_FLAG_LOCAL_READ    (1 << 10)
+
+struct c2_buf_list {
+	void *buf;
+	 DECLARE_PCI_UNMAP_ADDR(mapping)
+};
+
+
+/* The user context keeps track of objects allocated for a
+ * particular user-mode client. */
+struct c2_ucontext {
+	struct ib_ucontext ibucontext;
+};
+
+struct c2_mtt;
+
+/* All objects associated with a PD are kept in the 
+ * associated user context if present. 
+ */
+struct c2_pd {
+	struct ib_pd ibpd;
+	u32 pd_id;
+	atomic_t sqp_count;
+};
+
+struct c2_mr {
+	struct ib_mr ibmr;
+	struct c2_pd *pd;
+};
+
+struct c2_av;
+
+enum c2_ah_type {
+	C2_AH_ON_HCA,
+	C2_AH_PCI_POOL,
+	C2_AH_KMALLOC
+};
+
+struct c2_ah {
+	struct ib_ah ibah;
+};
+
+struct c2_cq {
+	struct ib_cq ibcq;
+	spinlock_t lock;
+	atomic_t refcount;
+	int cqn;
+	int is_kernel;
+	wait_queue_head_t wait;
+
+	u32 adapter_handle;
+	struct c2_mq mq;
+};
+
+struct c2_wq {
+	spinlock_t lock;
+};
+struct iw_cm_id;
+struct c2_qp {
+	struct ib_qp ibqp;
+	struct iw_cm_id *cm_id;
+	spinlock_t lock;
+	atomic_t refcount;
+	wait_queue_head_t wait;
+	int qpn;
+
+	u32 adapter_handle;
+	u32 send_sgl_depth;
+	u32 recv_sgl_depth;
+	u32 rdma_write_sgl_depth;
+	u8 state;
+
+	struct c2_mq sq_mq;
+	struct c2_mq rq_mq;
+};
+
+struct c2_cr_query_attrs {
+	u32 local_addr;
+	u32 remote_addr;
+	u16 local_port;
+	u16 remote_port;
+};
+
+static inline struct c2_pd *to_c2pd(struct ib_pd *ibpd)
+{
+	return container_of(ibpd, struct c2_pd, ibpd);
+}
+
+static inline struct c2_ucontext *to_c2ucontext(struct ib_ucontext *ibucontext)
+{
+	return container_of(ibucontext, struct c2_ucontext, ibucontext);
+}
+
+static inline struct c2_mr *to_c2mr(struct ib_mr *ibmr)
+{
+	return container_of(ibmr, struct c2_mr, ibmr);
+}
+
+
+static inline struct c2_ah *to_c2ah(struct ib_ah *ibah)
+{
+	return container_of(ibah, struct c2_ah, ibah);
+}
+
+static inline struct c2_cq *to_c2cq(struct ib_cq *ibcq)
+{
+	return container_of(ibcq, struct c2_cq, ibcq);
+}
+
+static inline struct c2_qp *to_c2qp(struct ib_qp *ibqp)
+{
+	return container_of(ibqp, struct c2_qp, ibqp);
+}
+
+static inline int is_rnic_addr(struct net_device *netdev, u32 addr)
+{
+	struct in_device *ind;
+	int ret = 0;
+
+	ind = in_dev_get(netdev);
+	if (!ind)
+		return 0;
+
+	for_ifa(ind) {
+		if (ifa->ifa_address == addr) {
+			ret = 1;
+			break;
+		}
+	}
+	endfor_ifa(ind);
+	in_dev_put(ind);
+	return ret;
+}
+#endif				/* C2_PROVIDER_H */
diff --git a/drivers/infiniband/hw/amso1100/c2_qp.c b/drivers/infiniband/hw/amso1100/c2_qp.c
new file mode 100644
index 0000000..6071cf0
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_qp.c
@@ -0,0 +1,975 @@
+/*
+ * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2004 Voltaire, Inc. All rights reserved. 
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include "c2.h"
+#include "c2_vq.h"
+#include "c2_status.h"
+
+#define C2_MAX_ORD_PER_QP 128
+#define C2_MAX_IRD_PER_QP 128
+
+#define C2_HINT_MAKE(q_index, hint_count) (((q_index) << 16) | hint_count)
+#define C2_HINT_GET_INDEX(hint) (((hint) & 0x7FFF0000) >> 16)
+#define C2_HINT_GET_COUNT(hint) ((hint) & 0x0000FFFF)
+
+#define NO_SUPPORT -1
+static const u8 c2_opcode[] = {
+	[IB_WR_SEND] = C2_WR_TYPE_SEND,
+	[IB_WR_SEND_WITH_IMM] = NO_SUPPORT,
+	[IB_WR_RDMA_WRITE] = C2_WR_TYPE_RDMA_WRITE,
+	[IB_WR_RDMA_WRITE_WITH_IMM] = NO_SUPPORT,
+	[IB_WR_RDMA_READ] = C2_WR_TYPE_RDMA_READ,
+	[IB_WR_ATOMIC_CMP_AND_SWP] = NO_SUPPORT,
+	[IB_WR_ATOMIC_FETCH_AND_ADD] = NO_SUPPORT,
+};
+
+static int to_c2_state(enum ib_qp_state ib_state)
+{
+	switch (ib_state) {
+	case IB_QPS_RESET:
+		return C2_QP_STATE_IDLE;
+	case IB_QPS_RTS:
+		return C2_QP_STATE_RTS;
+	case IB_QPS_SQD:
+		return C2_QP_STATE_CLOSING;
+	case IB_QPS_SQE:
+		return C2_QP_STATE_CLOSING;
+	case IB_QPS_ERR:
+		return C2_QP_STATE_ERROR;
+	default:
+		return -1;
+	}
+}
+
+int to_ib_state(enum c2_qp_state c2_state)
+{
+	switch (c2_state) {
+	case C2_QP_STATE_IDLE:
+		return IB_QPS_RESET;
+	case C2_QP_STATE_CONNECTING:
+		return IB_QPS_RTR;
+	case C2_QP_STATE_RTS:
+		return IB_QPS_RTS;
+	case C2_QP_STATE_CLOSING:
+		return IB_QPS_SQD;
+	case C2_QP_STATE_ERROR:
+		return IB_QPS_ERR;
+	case C2_QP_STATE_TERMINATE:
+		return IB_QPS_SQE;
+	default:
+		return -1;
+	}
+}
+
+const char *to_ib_state_str(int ib_state)
+{
+	static const char *state_str[] = {
+		"IB_QPS_RESET",
+		"IB_QPS_INIT",
+		"IB_QPS_RTR",
+		"IB_QPS_RTS",
+		"IB_QPS_SQD",
+		"IB_QPS_SQE",
+		"IB_QPS_ERR"
+	};
+	if (ib_state < IB_QPS_RESET ||
+	    ib_state > IB_QPS_ERR)
+		return "<invalid IB QP state>";
+
+	ib_state -= IB_QPS_RESET;
+	return state_str[ib_state];
+}
+
+void c2_set_qp_state(struct c2_qp *qp, int c2_state)
+{
+	int new_state = to_ib_state(c2_state);
+
+	pr_debug("%s: qp[%p] state modify %s --> %s\n", 
+	       __FUNCTION__,
+		qp, 
+		to_ib_state_str(qp->state), 
+		to_ib_state_str(new_state));
+	qp->state = new_state;
+}
+
+#define C2_QP_NO_ATTR_CHANGE 0xFFFFFFFF
+
+int c2_qp_modify(struct c2_dev *c2dev, struct c2_qp *qp,
+		 struct ib_qp_attr *attr, int attr_mask)
+{
+	struct c2wr_qp_modify_req wr;
+	struct c2wr_qp_modify_rep *reply;
+	struct c2_vq_req *vq_req;
+	unsigned long flags;
+	u8 next_state;
+	int err;
+
+	pr_debug("%s:%d qp=%p, %s --> %s\n", 
+		__FUNCTION__, __LINE__,
+		qp, 
+		to_ib_state_str(qp->state), 
+		to_ib_state_str(attr->qp_state));
+
+	vq_req = vq_req_alloc(c2dev);
+	if (!vq_req)
+		return -ENOMEM;
+
+	c2_wr_set_id(&wr, CCWR_QP_MODIFY);
+	wr.hdr.context = (unsigned long) vq_req;
+	wr.rnic_handle = c2dev->adapter_handle;
+	wr.qp_handle = qp->adapter_handle;
+	wr.ord = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
+	wr.ird = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
+	wr.sq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
+	wr.rq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
+
+	if (attr_mask & IB_QP_STATE) {
+		/* Ensure the state is valid */
+		if (attr->qp_state < 0 || attr->qp_state > IB_QPS_ERR)
+			return -EINVAL;
+
+		wr.next_qp_state = cpu_to_be32(to_c2_state(attr->qp_state));
+
+		if (attr->qp_state == IB_QPS_ERR) {
+			spin_lock_irqsave(&qp->lock, flags);
+			if (qp->cm_id && qp->state == IB_QPS_RTS) {
+				pr_debug("Generating CLOSE event for QP-->ERR, "
+					"qp=%p, cm_id=%p\n",qp,qp->cm_id);
+				/* Generate an CLOSE event */
+				vq_req->cm_id = qp->cm_id;
+				vq_req->event = IW_CM_EVENT_CLOSE;
+			}
+			spin_unlock_irqrestore(&qp->lock, flags);
+		}
+		next_state =  attr->qp_state;
+
+	} else if (attr_mask & IB_QP_CUR_STATE) {
+
+		if (attr->cur_qp_state != IB_QPS_RTR &&
+		    attr->cur_qp_state != IB_QPS_RTS &&
+		    attr->cur_qp_state != IB_QPS_SQD &&
+		    attr->cur_qp_state != IB_QPS_SQE)
+			return -EINVAL;
+		else
+			wr.next_qp_state =
+			    cpu_to_be32(to_c2_state(attr->cur_qp_state));
+
+		next_state = attr->cur_qp_state;
+
+	} else {
+		err = 0;
+		goto bail0;
+	}
+
+	/* reference the request struct */
+	vq_req_get(c2dev, vq_req);
+
+	err = vq_send_wr(c2dev, (union c2wr *) & wr);
+	if (err) {
+		vq_req_put(c2dev, vq_req);
+		goto bail0;
+	}
+
+	err = vq_wait_for_reply(c2dev, vq_req);
+	if (err)
+		goto bail0;
+
+	reply = (struct c2wr_qp_modify_rep *) (unsigned long) vq_req->reply_msg;
+	if (!reply) {
+		err = -ENOMEM;
+		goto bail0;
+	}
+
+	err = c2_errno(reply);
+	if (!err) 
+		qp->state = next_state;
+#ifdef DEBUG
+	else
+		pr_debug("%s: c2_errno=%d\n", __FUNCTION__, err);
+#endif
+	/*
+	 * If we're going to error and generating the event here, then 
+	 * we need to remove the reference because there will be no
+	 * close event generated by the adapter 
+	*/
+	spin_lock_irqsave(&qp->lock, flags);
+	if (vq_req->event==IW_CM_EVENT_CLOSE && qp->cm_id) {
+		qp->cm_id->rem_ref(qp->cm_id);
+		qp->cm_id = NULL;
+	}
+	spin_unlock_irqrestore(&qp->lock, flags);
+
+	vq_repbuf_free(c2dev, reply);
+      bail0:
+	vq_req_free(c2dev, vq_req);
+
+	pr_debug("%s:%d qp=%p, cur_state=%s\n", 
+		__FUNCTION__, __LINE__,
+		qp, 
+		to_ib_state_str(qp->state));
+	return err;
+}
+
+int c2_qp_set_read_limits(struct c2_dev *c2dev, struct c2_qp *qp, 
+			  int ord, int ird)
+{
+	struct c2wr_qp_modify_req wr;
+	struct c2wr_qp_modify_rep *reply;
+	struct c2_vq_req *vq_req;
+	int err;
+
+	vq_req = vq_req_alloc(c2dev);
+	if (!vq_req)
+		return -ENOMEM;
+
+	c2_wr_set_id(&wr, CCWR_QP_MODIFY);
+	wr.hdr.context = (unsigned long) vq_req;
+	wr.rnic_handle = c2dev->adapter_handle;
+	wr.qp_handle = qp->adapter_handle;
+	wr.ord = cpu_to_be32(ord);
+	wr.ird = cpu_to_be32(ird);
+	wr.sq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
+	wr.rq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
+	wr.next_qp_state = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
+
+	/* reference the request struct */
+	vq_req_get(c2dev, vq_req);
+
+	err = vq_send_wr(c2dev, (union c2wr *) & wr);
+	if (err) {
+		vq_req_put(c2dev, vq_req);
+		goto bail0;
+	}
+
+	err = vq_wait_for_reply(c2dev, vq_req);
+	if (err)
+		goto bail0;
+
+	reply = (struct c2wr_qp_modify_rep *) (unsigned long) 
+		vq_req->reply_msg;
+	if (!reply) {
+		err = -ENOMEM;
+		goto bail0;
+	}
+
+	err = c2_errno(reply);
+	vq_repbuf_free(c2dev, reply);
+      bail0:
+	vq_req_free(c2dev, vq_req);
+	return err;
+}
+
+static int destroy_qp(struct c2_dev *c2dev, struct c2_qp *qp)
+{
+	struct c2_vq_req *vq_req;
+	struct c2wr_qp_destroy_req wr;
+	struct c2wr_qp_destroy_rep *reply;
+	unsigned long flags;
+	int err;
+
+	/*
+	 * Allocate a verb request message
+	 */
+	vq_req = vq_req_alloc(c2dev);
+	if (!vq_req) {
+		return -ENOMEM;
+	}
+
+	/* 
+	 * Initialize the WR 
+	 */
+	c2_wr_set_id(&wr, CCWR_QP_DESTROY);
+	wr.hdr.context = (unsigned long) vq_req;
+	wr.rnic_handle = c2dev->adapter_handle;
+	wr.qp_handle = qp->adapter_handle;
+
+	/*
+	 * reference the request struct.  dereferenced in the int handler.
+	 */
+	vq_req_get(c2dev, vq_req);
+
+	spin_lock_irqsave(&qp->lock, flags);
+	if (qp->cm_id && qp->state == IB_QPS_RTS) {
+		pr_debug("destroy_qp: generating CLOSE event for QP-->ERR, "
+			"qp=%p, cm_id=%p\n",qp,qp->cm_id);
+		/* Generate an CLOSE event */
+		vq_req->qp = qp;
+		vq_req->cm_id = qp->cm_id;
+		vq_req->event = IW_CM_EVENT_CLOSE;
+	}
+	spin_unlock_irqrestore(&qp->lock, flags);
+
+	/*
+	 * Send WR to adapter
+	 */
+	err = vq_send_wr(c2dev, (union c2wr *) & wr);
+	if (err) {
+		vq_req_put(c2dev, vq_req);
+		goto bail0;
+	}
+
+	/*
+	 * Wait for reply from adapter
+	 */
+	err = vq_wait_for_reply(c2dev, vq_req);
+	if (err) {
+		goto bail0;
+	}
+
+	/*
+	 * Process reply
+	 */
+	reply = (struct c2wr_qp_destroy_rep *) (unsigned long) (vq_req->reply_msg);
+	if (!reply) {
+		err = -ENOMEM;
+		goto bail0;
+	}
+
+	spin_lock_irqsave(&qp->lock, flags);
+	if (qp->cm_id) {
+		qp->cm_id->rem_ref(qp->cm_id);
+		qp->cm_id = NULL;
+	}
+	spin_unlock_irqrestore(&qp->lock, flags);
+
+	vq_repbuf_free(c2dev, reply);
+      bail0:
+	vq_req_free(c2dev, vq_req);
+	return err;
+}
+
+int c2_alloc_qp(struct c2_dev *c2dev,
+		struct c2_pd *pd,
+		struct ib_qp_init_attr *qp_attrs, struct c2_qp *qp)
+{
+	struct c2wr_qp_create_req wr;
+	struct c2wr_qp_create_rep *reply;
+	struct c2_vq_req *vq_req;
+	struct c2_cq *send_cq = to_c2cq(qp_attrs->send_cq);
+	struct c2_cq *recv_cq = to_c2cq(qp_attrs->recv_cq);
+	unsigned long peer_pa;
+	u32 q_size, msg_size, mmap_size;
+	void __iomem *mmap;
+	int err;
+
+	qp->qpn = c2_alloc(&c2dev->qp_table.alloc);
+	if (qp->qpn == -1)
+		return -ENOMEM;
+
+	qp->ibqp.qp_num = qp->qpn;
+	qp->ibqp.qp_type = IB_QPT_RC;
+
+	/* Allocate the SQ and RQ shared pointers */
+	qp->sq_mq.shared = c2_alloc_mqsp(c2dev->kern_mqsp_pool);
+	if (!qp->sq_mq.shared) {
+		err = -ENOMEM;
+		goto bail0;
+	}
+
+	qp->rq_mq.shared = c2_alloc_mqsp(c2dev->kern_mqsp_pool);
+	if (!qp->rq_mq.shared) {
+		err = -ENOMEM;
+		goto bail1;
+	}
+
+	/* Allocate the verbs request */
+	vq_req = vq_req_alloc(c2dev);
+	if (vq_req == NULL) {
+		err = -ENOMEM;
+		goto bail2;
+	}
+
+	/* Initialize the work request */
+	memset(&wr, 0, sizeof(wr));
+	c2_wr_set_id(&wr, CCWR_QP_CREATE);
+	wr.hdr.context = (unsigned long) vq_req;
+	wr.rnic_handle = c2dev->adapter_handle;
+	wr.sq_cq_handle = send_cq->adapter_handle;
+	wr.rq_cq_handle = recv_cq->adapter_handle;
+	wr.sq_depth = cpu_to_be32(qp_attrs->cap.max_send_wr + 1);
+	wr.rq_depth = cpu_to_be32(qp_attrs->cap.max_recv_wr + 1);
+	wr.srq_handle = 0;
+	wr.flags = cpu_to_be32(QP_RDMA_READ | QP_RDMA_WRITE | QP_MW_BIND |
+			       QP_ZERO_STAG | QP_RDMA_READ_RESPONSE);
+	wr.send_sgl_depth = cpu_to_be32(qp_attrs->cap.max_send_sge);
+	wr.recv_sgl_depth = cpu_to_be32(qp_attrs->cap.max_recv_sge);
+	wr.rdma_write_sgl_depth = cpu_to_be32(qp_attrs->cap.max_send_sge);
+	// XXX no write depth?
+	wr.shared_sq_ht = cpu_to_be64(__pa(qp->sq_mq.shared));
+	wr.shared_rq_ht = cpu_to_be64(__pa(qp->rq_mq.shared));
+	wr.ord = cpu_to_be32(C2_MAX_ORD_PER_QP);
+	wr.ird = cpu_to_be32(C2_MAX_IRD_PER_QP);
+	wr.pd_id = pd->pd_id;
+	wr.user_context = (unsigned long) qp;
+
+	vq_req_get(c2dev, vq_req);
+
+	/* Send the WR to the adapter */
+	err = vq_send_wr(c2dev, (union c2wr *) & wr);
+	if (err) {
+		vq_req_put(c2dev, vq_req);
+		goto bail3;
+	}
+
+	/* Wait for the verb reply  */
+	err = vq_wait_for_reply(c2dev, vq_req);
+	if (err) {
+		goto bail3;
+	}
+
+	/* Process the reply */
+	reply = (struct c2wr_qp_create_rep *) (unsigned long) (vq_req->reply_msg);
+	if (!reply) {
+		err = -ENOMEM;
+		goto bail3;
+	}
+
+	if ((err = c2_wr_get_result(reply)) != 0) {
+		goto bail4;
+	}
+
+	/* Fill in the kernel QP struct */
+	atomic_set(&qp->refcount, 1);
+	qp->adapter_handle = reply->qp_handle;
+	qp->state = IB_QPS_RESET;
+	qp->send_sgl_depth = qp_attrs->cap.max_send_sge;
+	qp->rdma_write_sgl_depth = qp_attrs->cap.max_send_sge;
+	qp->recv_sgl_depth = qp_attrs->cap.max_recv_sge;
+
+	/* Initialize the SQ MQ */
+	q_size = be32_to_cpu(reply->sq_depth);
+	msg_size = be32_to_cpu(reply->sq_msg_size);
+	peer_pa = c2dev->pa + be32_to_cpu(reply->sq_mq_start);
+	mmap_size = PAGE_ALIGN(sizeof(struct c2_mq_shared) + msg_size * q_size);
+	mmap = ioremap_nocache(peer_pa, mmap_size);
+	if (!mmap) {
+		err = -ENOMEM;
+		goto bail5;
+	}
+
+	c2_mq_req_init(&qp->sq_mq, 
+		       be32_to_cpu(reply->sq_mq_index), 
+		       q_size, 
+		       msg_size, 
+		       mmap + sizeof(struct c2_mq_shared),	/* pool start */
+		       mmap,				/* peer */
+		       C2_MQ_ADAPTER_TARGET);
+
+	/* Initialize the RQ mq */
+	q_size = be32_to_cpu(reply->rq_depth);
+	msg_size = be32_to_cpu(reply->rq_msg_size);
+	peer_pa = c2dev->pa + be32_to_cpu(reply->rq_mq_start);
+	mmap_size = PAGE_ALIGN(sizeof(struct c2_mq_shared) + msg_size * q_size);
+	mmap = ioremap_nocache(peer_pa, mmap_size);
+	if (!mmap) {
+		err = -ENOMEM;
+		goto bail6;
+	}
+
+	c2_mq_req_init(&qp->rq_mq, 
+		       be32_to_cpu(reply->rq_mq_index), 
+		       q_size, 
+		       msg_size, 
+		       mmap + sizeof(struct c2_mq_shared),	/* pool start */
+		       mmap,				/* peer */
+		       C2_MQ_ADAPTER_TARGET);
+
+	vq_repbuf_free(c2dev, reply);
+	vq_req_free(c2dev, vq_req);
+
+	spin_lock_irq(&c2dev->qp_table.lock);
+	c2_array_set(&c2dev->qp_table.qp, qp->qpn & (c2dev->props.max_qp - 1), qp);
+	c2dev->qp_table.map[qp->qpn] = qp;
+	spin_unlock_irq(&c2dev->qp_table.lock);
+
+	return 0;
+
+      bail6:
+	iounmap(qp->sq_mq.peer);
+      bail5:
+	destroy_qp(c2dev, qp);
+      bail4:
+	vq_repbuf_free(c2dev, reply);
+      bail3:
+	vq_req_free(c2dev, vq_req);
+      bail2:
+	c2_free_mqsp(qp->rq_mq.shared);
+      bail1:
+	c2_free_mqsp(qp->sq_mq.shared);
+      bail0:
+	c2_free(&c2dev->qp_table.alloc, qp->qpn);
+	return err;
+}
+
+void c2_free_qp(struct c2_dev *c2dev, struct c2_qp *qp)
+{
+	struct c2_cq *send_cq;
+	struct c2_cq *recv_cq;
+
+	send_cq = to_c2cq(qp->ibqp.send_cq);
+	recv_cq = to_c2cq(qp->ibqp.recv_cq);
+
+	/*
+	 * Lock CQs here, so that CQ polling code can do QP lookup
+	 * without taking a lock.
+	 */
+	spin_lock_irq(&send_cq->lock);
+	if (send_cq != recv_cq)
+		spin_lock(&recv_cq->lock);
+
+	spin_lock(&c2dev->qp_table.lock);
+	c2_array_clear(&c2dev->qp_table.qp, qp->qpn & (c2dev->props.max_qp - 1));
+	c2dev->qp_table.map[qp->qpn] = NULL;
+	spin_unlock(&c2dev->qp_table.lock);
+
+	if (send_cq != recv_cq)
+		spin_unlock(&recv_cq->lock);
+	spin_unlock_irq(&send_cq->lock);
+
+	/*
+	 * Destory qp in the rnic...
+	 */
+	destroy_qp(c2dev, qp);
+
+	/*
+	 * Mark any unreaped CQEs as null and void.
+	 */
+	c2_cq_clean(c2dev, qp, send_cq->cqn);
+	if (send_cq != recv_cq)
+		c2_cq_clean(c2dev, qp, recv_cq->cqn);
+	/*
+	 * Unmap the MQs and return the shared pointers
+	 * to the message pool.
+	 */
+	iounmap(qp->sq_mq.peer);
+	iounmap(qp->rq_mq.peer);
+	c2_free_mqsp(qp->sq_mq.shared);
+	c2_free_mqsp(qp->rq_mq.shared);
+
+	atomic_dec(&qp->refcount);
+	wait_event(qp->wait, !atomic_read(&qp->refcount));
+	c2_free(&c2dev->qp_table.alloc, qp->qpn);
+}
+
+/*
+ * Function: move_sgl 
+ *
+ * Description: 
+ * Move an SGL from the user's work request struct into a CCIL Work Request 
+ * message, swapping to WR byte order and ensure the total length doesn't 
+ * overflow. 
+ *
+ * IN: 
+ * dst		- ptr to CCIL Work Request message SGL memory.
+ * src		- ptr to the consumers SGL memory.
+ *
+ * OUT: none
+ *
+ * Return: 
+ * CCIL status codes.
+ */
+static int
+move_sgl(struct c2_data_addr * dst, struct ib_sge *src, int count, u32 * p_len,
+	 u8 * actual_count)
+{
+	u32 tot = 0;		/* running total */
+	u8 acount = 0;		/* running total non-0 len sge's */
+
+	while (count > 0) {
+		/*
+		 * If the addition of this SGE causes the
+		 * total SGL length to exceed 2^32-1, then
+		 * fail-n-bail.
+		 *
+		 * If the current total plus the next element length
+		 * wraps, then it will go negative and be less than the
+		 * current total...
+		 */
+		if ((tot + src->length) < tot) {
+			return -EINVAL;
+		}
+		/*
+		 * Bug: 1456 (as well as 1498 & 1643)
+		 * Skip over any sge's supplied with len=0
+		 */
+		if (src->length) {
+			tot += src->length;
+			dst->stag = cpu_to_be32(src->lkey);
+			dst->to = cpu_to_be64(src->addr);
+			dst->length = cpu_to_be32(src->length);
+			dst++;
+			acount++;
+		}
+		src++;
+		count--;
+	}
+
+	if (acount == 0) {
+		/*
+		 * Bug: 1476 (as well as 1498, 1456 and 1643)
+		 * Setup the SGL in the WR to make it easier for the RNIC.
+		 * This way, the FW doesn't have to deal with special cases.
+		 * Setting length=0 should be sufficient.
+		 */
+		dst->stag = 0;
+		dst->to = 0;
+		dst->length = 0;
+	}
+
+	*p_len = tot;
+	*actual_count = acount;
+	return 0;
+}
+
+/*
+ * Function: c2_activity (private function)
+ *
+ * Description: 
+ * Post an mq index to the host->adapter activity fifo.
+ *
+ * IN: 
+ * c2dev	- ptr to c2dev structure
+ * mq_index	- mq index to post
+ * shared	- value most recently written to shared 
+ *
+ * OUT: 
+ *
+ * Return: 
+ * none
+ */
+static inline void c2_activity(struct c2_dev *c2dev, u32 mq_index, u16 shared)
+{
+	/*
+	 * First read the register to see if the FIFO is full, and if so,
+	 * spin until it's not.  This isn't perfect -- there is no
+	 * synchronization among the clients of the register, but in
+	 * practice it prevents multiple CPU from hammering the bus
+	 * with PCI RETRY. Note that when this does happen, the card
+	 * cannot get on the bus and the card and system hang in a
+	 * deadlock -- thus the need for this code. [TOT]
+	 */
+	while (readl(c2dev->regs + PCI_BAR0_ADAPTER_HINT) & 0x80000000) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(0);
+	}
+
+	__raw_writel(C2_HINT_MAKE(mq_index, shared),
+		     c2dev->regs + PCI_BAR0_ADAPTER_HINT);
+}
+
+/*
+ * Function: qp_wr_post 
+ *
+ * Description: 
+ * This in-line function allocates a MQ msg, then moves the host-copy of 
+ * the completed WR into msg.  Then it posts the message. 
+ * 
+ * IN: 
+ * q		- ptr to user MQ.
+ * wr		- ptr to host-copy of the WR.
+ * qp		- ptr to user qp
+ * size		- Number of bytes to post.  Assumed to be divisible by 4.
+ *
+ * OUT: none
+ *
+ * Return: 
+ * CCIL status codes.
+ */
+static int qp_wr_post(struct c2_mq *q, union c2wr * wr, struct c2_qp *qp, u32 size)
+{
+	union c2wr *msg;
+
+	msg = c2_mq_alloc(q);
+	if (msg == NULL) {
+		return -EINVAL;
+	}
+#ifdef CCMSGMAGIC
+	((c2wr_hdr_t *) wr)->magic = cpu_to_be32(CCWR_MAGIC);
+#endif
+
+	/*
+	 * Since all header fields in the WR are the same as the
+	 * CQE, set the following so the adapter need not.
+	 */
+	c2_wr_set_result(wr, CCERR_PENDING);
+
+	/*
+	 * Copy the wr down to the adapter
+	 */
+	memcpy((void *) msg, (void *) wr, size);
+
+	c2_mq_produce(q);
+	return 0;
+}
+
+
+int c2_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
+		 struct ib_send_wr **bad_wr)
+{
+	struct c2_dev *c2dev = to_c2dev(ibqp->device);
+	struct c2_qp *qp = to_c2qp(ibqp);
+	union c2wr wr;
+	int err = 0;
+
+	u32 flags;
+	u32 tot_len;
+	u8 actual_sge_count;
+	u32 msg_size;
+
+	if (qp->state > IB_QPS_RTS)
+		return -EINVAL;
+
+	while (ib_wr) {
+
+		flags = 0;
+		wr.sqwr.sq_hdr.user_hdr.hdr.context = ib_wr->wr_id;
+		if (ib_wr->send_flags & IB_SEND_SIGNALED) {
+			flags |= SQ_SIGNALED;
+		}
+
+		switch (ib_wr->opcode) {
+		case IB_WR_SEND:
+			if (ib_wr->send_flags & IB_SEND_SOLICITED) {
+				c2_wr_set_id(&wr, C2_WR_TYPE_SEND_SE);
+				msg_size = sizeof(struct c2wr_send_req);
+			} else {
+				c2_wr_set_id(&wr, C2_WR_TYPE_SEND);
+				msg_size = sizeof(struct c2wr_send_req);
+			}
+
+			wr.sqwr.send.remote_stag = 0;
+			msg_size += sizeof(struct c2_data_addr) * ib_wr->num_sge;
+			if (ib_wr->num_sge > qp->send_sgl_depth) {
+				err = -EINVAL;
+				break;
+			}
+			if (ib_wr->send_flags & IB_SEND_FENCE) {
+				flags |= SQ_READ_FENCE;
+			}
+			err = move_sgl((struct c2_data_addr *) & (wr.sqwr.send.data),
+				       ib_wr->sg_list,
+				       ib_wr->num_sge,
+				       &tot_len, &actual_sge_count);
+			wr.sqwr.send.sge_len = cpu_to_be32(tot_len);
+			c2_wr_set_sge_count(&wr, actual_sge_count);
+			break;
+		case IB_WR_RDMA_WRITE:
+			c2_wr_set_id(&wr, C2_WR_TYPE_RDMA_WRITE);
+			msg_size = sizeof(struct c2wr_rdma_write_req) +
+			    (sizeof(struct c2_data_addr) * ib_wr->num_sge);
+			if (ib_wr->num_sge > qp->rdma_write_sgl_depth) {
+				err = -EINVAL;
+				break;
+			}
+			if (ib_wr->send_flags & IB_SEND_FENCE) {
+				flags |= SQ_READ_FENCE;
+			}
+			wr.sqwr.rdma_write.remote_stag =
+			    cpu_to_be32(ib_wr->wr.rdma.rkey);
+			wr.sqwr.rdma_write.remote_to =
+			    cpu_to_be64(ib_wr->wr.rdma.remote_addr);
+			err = move_sgl((struct c2_data_addr *)
+				       & (wr.sqwr.rdma_write.data),
+				       ib_wr->sg_list,
+				       ib_wr->num_sge,
+				       &tot_len, &actual_sge_count);
+			wr.sqwr.rdma_write.sge_len = cpu_to_be32(tot_len);
+			c2_wr_set_sge_count(&wr, actual_sge_count);
+			break;
+		case IB_WR_RDMA_READ:
+			c2_wr_set_id(&wr, C2_WR_TYPE_RDMA_READ);
+			msg_size = sizeof(struct c2wr_rdma_read_req);
+
+			/* IWarp only suppots 1 sge for RDMA reads */
+			if (ib_wr->num_sge > 1) {
+				err = -EINVAL;
+				break;
+			}
+
+			/*
+			 * Move the local and remote stag/to/len into the WR. 
+			 */
+			wr.sqwr.rdma_read.local_stag =
+			    cpu_to_be32(ib_wr->sg_list->lkey);
+			wr.sqwr.rdma_read.local_to =
+			    cpu_to_be64(ib_wr->sg_list->addr);
+			wr.sqwr.rdma_read.remote_stag =
+			    cpu_to_be32(ib_wr->wr.rdma.rkey);
+			wr.sqwr.rdma_read.remote_to =
+			    cpu_to_be64(ib_wr->wr.rdma.remote_addr);
+			wr.sqwr.rdma_read.length =
+			    cpu_to_be32(ib_wr->sg_list->length);
+			break;
+		default:
+			/* error */
+			msg_size = 0;
+			err = -EINVAL;
+			break;
+		}
+
+		/*
+		 * If we had an error on the last wr build, then
+		 * break out.  Possible errors include bogus WR 
+		 * type, and a bogus SGL length...
+		 */
+		if (err) {
+			break;
+		}
+
+		/*
+		 * Store flags
+		 */
+		c2_wr_set_flags(&wr, flags);
+
+		/*
+		 * Post the puppy!
+		 */
+		err = qp_wr_post(&qp->sq_mq, &wr, qp, msg_size);
+		if (err) {
+			break;
+		}
+
+		/*
+		 * Enqueue mq index to activity FIFO.
+		 */
+		c2_activity(c2dev, qp->sq_mq.index, qp->sq_mq.hint_count);
+
+		ib_wr = ib_wr->next;
+	}
+
+	if (err)
+		*bad_wr = ib_wr;
+	return err;
+}
+
+int c2_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr,
+		    struct ib_recv_wr **bad_wr)
+{
+	struct c2_dev *c2dev = to_c2dev(ibqp->device);
+	struct c2_qp *qp = to_c2qp(ibqp);
+	union c2wr wr;
+	int err = 0;
+
+	if (qp->state > IB_QPS_RTS)
+		return -EINVAL;
+
+	/*
+	 * Try and post each work request
+	 */
+	while (ib_wr) {
+		u32 tot_len;
+		u8 actual_sge_count;
+
+		if (ib_wr->num_sge > qp->recv_sgl_depth) {
+			err = -EINVAL;
+			break;
+		}
+
+		/*
+		 * Create local host-copy of the WR
+		 */
+		wr.rqwr.rq_hdr.user_hdr.hdr.context = ib_wr->wr_id;
+		c2_wr_set_id(&wr, CCWR_RECV);
+		c2_wr_set_flags(&wr, 0);
+
+		/* sge_count is limited to eight bits. */
+		BUG_ON(ib_wr->num_sge >= 256);
+		err = move_sgl((struct c2_data_addr *) & (wr.rqwr.data),
+			       ib_wr->sg_list,
+			       ib_wr->num_sge, &tot_len, &actual_sge_count);
+		c2_wr_set_sge_count(&wr, actual_sge_count);
+
+		/*
+		 * If we had an error on the last wr build, then
+		 * break out.  Possible errors include bogus WR 
+		 * type, and a bogus SGL length...
+		 */
+		if (err) {
+			break;
+		}
+
+		err = qp_wr_post(&qp->rq_mq, &wr, qp, qp->rq_mq.msg_size);
+		if (err) {
+			break;
+		}
+
+		/*
+		 * Enqueue mq index to activity FIFO
+		 */
+		c2_activity(c2dev, qp->rq_mq.index, qp->rq_mq.hint_count);
+
+		ib_wr = ib_wr->next;
+	}
+
+	if (err)
+		*bad_wr = ib_wr;
+	return err;
+}
+
+int __devinit c2_init_qp_table(struct c2_dev *c2dev)
+{
+	int err;
+
+	spin_lock_init(&c2dev->qp_table.lock);
+
+	err = c2_alloc_init(&c2dev->qp_table.alloc, 
+			    c2dev->props.max_qp, 1);
+	if (err)
+		return err;
+
+	err = c2_array_init(&c2dev->qp_table.qp, c2dev->props.max_qp);
+	if (err) {
+		c2_alloc_cleanup(&c2dev->qp_table.alloc);
+		return err;
+	}
+
+	c2dev->qp_table.map = vmalloc(sizeof(struct c2_qp *) * c2dev->props.max_qp);
+	if (!c2dev->qp_table.map) {
+		pr_debug("Could not allocate QPN <-> QP map\n");
+		c2_alloc_cleanup(&c2dev->qp_table.alloc);
+		c2_array_cleanup(&c2dev->qp_table.qp, c2dev->props.max_qp);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+void __devexit c2_cleanup_qp_table(struct c2_dev *c2dev)
+{
+	c2_alloc_cleanup(&c2dev->qp_table.alloc);
+	c2_array_cleanup(&c2dev->qp_table.qp, c2dev->props.max_qp);
+}
diff --git a/drivers/infiniband/hw/amso1100/c2_user.h b/drivers/infiniband/hw/amso1100/c2_user.h
new file mode 100644
index 0000000..7e9e7ad
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_user.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef C2_USER_H
+#define C2_USER_H
+
+#include <linux/types.h>
+
+/*
+ * Make sure that all structs defined in this file remain laid out so
+ * that they pack the same way on 32-bit and 64-bit architectures (to
+ * avoid incompatibility between 32-bit userspace and 64-bit kernels).
+ * In particular do not use pointer types -- pass pointers in __u64
+ * instead.
+ */
+
+struct c2_alloc_ucontext_resp {
+	__u32 qp_tab_size;
+	__u32 uarc_size;
+};
+
+struct c2_alloc_pd_resp {
+	__u32 pdn;
+	__u32 reserved;
+};
+
+struct c2_create_cq {
+	__u32 lkey;
+	__u32 pdn;
+	__u64 arm_db_page;
+	__u64 set_db_page;
+	__u32 arm_db_index;
+	__u32 set_db_index;
+};
+
+struct c2_create_cq_resp {
+	__u32 cqn;
+	__u32 reserved;
+};
+
+struct c2_create_qp {
+	__u32 lkey;
+	__u32 reserved;
+	__u64 sq_db_page;
+	__u64 rq_db_page;
+	__u32 sq_db_index;
+	__u32 rq_db_index;
+};
+
+#endif				/* C2_USER_H */

^ permalink raw reply related

* [PATCH v2 4/7] AMSO1100 Memory Management.
From: Steve Wise @ 2006-06-07 20:06 UTC (permalink / raw)
  To: rdreier, mshefty; +Cc: netdev, linux-kernel, openib-general
In-Reply-To: <20060607200646.9259.24588.stgit@stevo-desktop>


Review Changes:

- sizeof -> sizeof()
---

 drivers/infiniband/hw/amso1100/c2_alloc.c |  256 ++++++++++++++++++++
 drivers/infiniband/hw/amso1100/c2_mm.c    |  378 +++++++++++++++++++++++++++++
 2 files changed, 634 insertions(+), 0 deletions(-)

diff --git a/drivers/infiniband/hw/amso1100/c2_alloc.c b/drivers/infiniband/hw/amso1100/c2_alloc.c
new file mode 100644
index 0000000..e496eb7
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_alloc.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/bitmap.h>
+
+#include "c2.h"
+
+/* Trivial bitmap-based allocator */
+u32 c2_alloc(struct c2_alloc *alloc)
+{
+	u32 obj;
+
+	spin_lock(&alloc->lock);
+	obj = find_next_zero_bit(alloc->table, alloc->max, alloc->last);
+	if (obj >= alloc->max)
+		obj = find_first_zero_bit(alloc->table, alloc->max);
+	if (obj >= 0) {
+	    alloc->last = obj+1;
+	    if (alloc->last > alloc->max)
+		    alloc->last = 0;
+	}
+	spin_unlock(&alloc->lock);
+
+	return obj;
+}
+
+void c2_free(struct c2_alloc *alloc, u32 obj)
+{
+	spin_lock(&alloc->lock);
+	clear_bit(obj, alloc->table);
+	spin_unlock(&alloc->lock);
+}
+
+int c2_alloc_init(struct c2_alloc *alloc, u32 num, u32 reserved)
+{
+	int i;
+
+	alloc->last = 0;
+	alloc->max = num;
+	spin_lock_init(&alloc->lock);
+	alloc->table = kmalloc(BITS_TO_LONGS(num) * sizeof(long), GFP_KERNEL);
+	if (!alloc->table)
+		return -ENOMEM;
+
+	bitmap_zero(alloc->table, num);
+	for (i = 0; i < reserved; ++i)
+		set_bit(i, alloc->table);
+
+	return 0;
+}
+
+void c2_alloc_cleanup(struct c2_alloc *alloc)
+{
+	kfree(alloc->table);
+}
+
+/*
+ * Array of pointers with lazy allocation of leaf pages.  Callers of
+ * _get, _set and _clear methods must use a lock or otherwise
+ * serialize access to the array.
+ */
+
+void *c2_array_get(struct c2_array *array, int index)
+{
+	int p = (index * sizeof(void *)) >> PAGE_SHIFT;
+
+	if (array->page_list[p].page) {
+		int i = index & (PAGE_SIZE / sizeof(void *) - 1);
+		return array->page_list[p].page[i];
+	} else
+		return NULL;
+}
+
+int c2_array_set(struct c2_array *array, int index, void *value)
+{
+	int p = (index * sizeof(void *)) >> PAGE_SHIFT;
+
+	/* Allocate with GFP_ATOMIC because we'll be called with locks held. */
+	if (!array->page_list[p].page)
+		array->page_list[p].page =
+		    (void **) get_zeroed_page(GFP_ATOMIC);
+
+	if (!array->page_list[p].page)
+		return -ENOMEM;
+
+	array->page_list[p].page[index & (PAGE_SIZE / sizeof(void *) - 1)] =
+	    value;
+	++array->page_list[p].used;
+
+	return 0;
+}
+
+void c2_array_clear(struct c2_array *array, int index)
+{
+	int p = (index * sizeof(void *)) >> PAGE_SHIFT;
+
+	if (--array->page_list[p].used == 0) {
+		free_page((unsigned long) array->page_list[p].page);
+		array->page_list[p].page = NULL;
+	}
+
+	if (array->page_list[p].used < 0)
+		pr_debug("Array %p index %d page %d with ref count %d < 0\n",
+			 array, index, p, array->page_list[p].used);
+}
+
+int c2_array_init(struct c2_array *array, int nent)
+{
+	int npage = (nent * sizeof(void *) + PAGE_SIZE - 1) / PAGE_SIZE;
+	int i;
+
+	array->page_list =
+	    kmalloc(npage * sizeof(*array->page_list), GFP_KERNEL);
+	if (!array->page_list)
+		return -ENOMEM;
+
+	for (i = 0; i < npage; ++i) {
+		array->page_list[i].page = NULL;
+		array->page_list[i].used = 0;
+	}
+
+	return 0;
+}
+
+void c2_array_cleanup(struct c2_array *array, int nent)
+{
+	int i;
+
+	for (i = 0; i < (nent * sizeof(void *) + PAGE_SIZE - 1) / PAGE_SIZE;
+	     ++i)
+		free_page((unsigned long) array->page_list[i].page);
+
+	kfree(array->page_list);
+}
+
+static int c2_alloc_mqsp_chunk(gfp_t gfp_mask, struct sp_chunk **head)
+{
+	int i;
+	struct sp_chunk *new_head;
+
+	new_head = (struct sp_chunk *) __get_free_page(gfp_mask | GFP_DMA);
+	if (new_head == NULL)
+		return -ENOMEM;
+
+	new_head->next = NULL;
+	new_head->head = 0;
+	new_head->gfp_mask = gfp_mask;
+
+	/* build list where each index is the next free slot */
+	for (i = 0;
+	     i < (PAGE_SIZE - sizeof(struct sp_chunk) - 
+		  sizeof(u16)) / sizeof(u16) - 1; 
+	     i++) {
+		new_head->shared_ptr[i] = i + 1;
+	}
+	/* terminate list */
+	new_head->shared_ptr[i] = 0xFFFF;
+
+	*head = new_head;
+	return 0;
+}
+
+int c2_init_mqsp_pool(gfp_t gfp_mask, struct sp_chunk **root)
+{
+	return c2_alloc_mqsp_chunk(gfp_mask, root);
+}
+
+void c2_free_mqsp_pool(struct sp_chunk *root)
+{
+	struct sp_chunk *next;
+
+	while (root) {
+		next = root->next;
+		__free_page((struct page *) root);
+		root = next;
+	}
+}
+
+u16 *c2_alloc_mqsp(struct sp_chunk *head)
+{
+	u16 mqsp;
+
+	while (head) {
+		mqsp = head->head;
+		if (mqsp != 0xFFFF) {
+			head->head = head->shared_ptr[mqsp];
+			break;
+		} else if (head->next == NULL) {
+			if (c2_alloc_mqsp_chunk(head->gfp_mask, &head->next)==0) {
+				head = head->next;
+				mqsp = head->head;
+				head->head = head->shared_ptr[mqsp];
+				break;
+			} else
+				return NULL;
+		} else
+			head = head->next;
+	}
+	if (head)
+		return &(head->shared_ptr[mqsp]);
+	return NULL;
+}
+
+void c2_free_mqsp(u16 * mqsp)
+{
+	struct sp_chunk *head;
+	u16 idx;
+
+	/* The chunk containing this ptr begins at the page boundary */
+	head = (struct sp_chunk *) ((unsigned long) mqsp & PAGE_MASK);
+
+	/* Link head to new mqsp */
+	*mqsp = head->head;
+
+	/* Compute the shared_ptr index */
+	idx = ((unsigned long) mqsp & ~PAGE_MASK) >> 1;
+	idx -= (unsigned long) &(((struct sp_chunk *) 0)->shared_ptr[0]) >> 1;
+
+	/* Point this index at the head */
+	head->shared_ptr[idx] = head->head;
+
+	/* Point head at this index */
+	head->head = idx;
+}
diff --git a/drivers/infiniband/hw/amso1100/c2_mm.c b/drivers/infiniband/hw/amso1100/c2_mm.c
new file mode 100644
index 0000000..13c8122
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_mm.c
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "c2.h"
+#include "c2_vq.h"
+
+#define PBL_VIRT 1
+#define PBL_PHYS 2
+
+/*
+ * Send all the PBL messages to convey the remainder of the PBL
+ * Wait for the adapter's reply on the last one.
+ * This is indicated by setting the MEM_PBL_COMPLETE in the flags.
+ *
+ * NOTE:  vq_req is _not_ freed by this function.  The VQ Host
+ *	  Reply buffer _is_ freed by this function.
+ */
+static int
+send_pbl_messages(struct c2_dev *c2dev, u32 stag_index,
+		  unsigned long va, u32 pbl_depth,
+		  struct c2_vq_req *vq_req, int pbl_type)
+{
+	u32 pbe_count;		/* amt that fits in a PBL msg */
+	u32 count;		/* amt in this PBL MSG. */
+	struct c2wr_nsmr_pbl_req *wr;	/* PBL WR ptr */
+	struct c2wr_nsmr_pbl_rep *reply;	/* reply ptr */
+ 	int err, pbl_virt, pbl_index, i;
+
+	switch (pbl_type) {
+	case PBL_VIRT:
+		pbl_virt = 1;
+		break;
+	case PBL_PHYS:
+		pbl_virt = 0;
+		break;
+	default:
+		return -EINVAL;
+		break;
+	}
+
+	pbe_count = (c2dev->req_vq.msg_size -
+		     sizeof(struct c2wr_nsmr_pbl_req)) / sizeof(u64);
+	wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);
+	if (!wr) {
+		return -ENOMEM;
+	}
+	c2_wr_set_id(wr, CCWR_NSMR_PBL);
+
+	/*
+	 * Only the last PBL message will generate a reply from the verbs, 
+	 * so we set the context to 0 indicating there is no kernel verbs
+	 * handler blocked awaiting this reply.
+	 */
+	wr->hdr.context = 0;
+	wr->rnic_handle = c2dev->adapter_handle;
+	wr->stag_index = stag_index;	/* already swapped */
+	wr->flags = 0;
+	pbl_index = 0;
+	while (pbl_depth) {
+		count = min(pbe_count, pbl_depth);
+		wr->addrs_length = cpu_to_be32(count);
+
+		/*
+		 *  If this is the last message, then reference the
+		 *  vq request struct cuz we're gonna wait for a reply.
+		 *  also make this PBL msg as the last one.
+		 */
+		if (count == pbl_depth) {
+			/*
+			 * reference the request struct.  dereferenced in the 
+			 * int handler.
+			 */
+			vq_req_get(c2dev, vq_req);
+			wr->flags = cpu_to_be32(MEM_PBL_COMPLETE);
+
+			/*
+			 * This is the last PBL message.
+			 * Set the context to our VQ Request Object so we can
+			 * wait for the reply.
+			 */
+			wr->hdr.context = (unsigned long) vq_req;
+		}
+
+		/*
+		 * If pbl_virt is set then va is a virtual address 
+		 * that describes a virtually contiguous memory
+		 * allocation. The wr needs the start of each virtual page
+		 * to be converted to the corresponding physical address
+		 * of the page. If pbl_virt is not set then va is an array
+		 * of physical addresses and there is no conversion to do.
+		 * Just fill in the wr with what is in the array.  
+		 */
+		for (i = 0; i < count; i++) {
+			if (pbl_virt) {
+				/* XXX */
+				//wr->paddrs[i] = 
+				//	cpu_to_be64(user_virt_to_phys(va));
+				va += PAGE_SIZE;
+			} else {
+ 				wr->paddrs[i] = 
+				    cpu_to_be64(((u64 *)va)[pbl_index + i]);
+			}
+		}
+
+		/*
+		 * Send WR to adapter
+		 */
+		err = vq_send_wr(c2dev, (union c2wr *) wr);
+		if (err) {
+			if (count <= pbe_count) {
+				vq_req_put(c2dev, vq_req);
+			}
+			goto bail0;
+		}
+		pbl_depth -= count;
+		pbl_index += count;
+	}
+
+	/*
+	 *  Now wait for the reply...
+	 */
+	err = vq_wait_for_reply(c2dev, vq_req);
+	if (err) {
+		goto bail0;
+	}
+
+	/*
+	 * Process reply 
+	 */
+	reply = (struct c2wr_nsmr_pbl_rep *) (unsigned long) vq_req->reply_msg;
+	if (!reply) {
+		err = -ENOMEM;
+		goto bail0;
+	}
+
+	err = c2_errno(reply);
+
+	vq_repbuf_free(c2dev, reply);
+      bail0:
+	kfree(wr);
+	return err;
+}
+
+#define C2_PBL_MAX_DEPTH 131072
+int
+c2_nsmr_register_phys_kern(struct c2_dev *c2dev, u64 *addr_list, 
+ 			   int page_size, int pbl_depth, u32 length, 
+ 			   u32 offset, u64 *va, enum c2_acf acf, 
+			   struct c2_mr *mr)
+{
+	struct c2_vq_req *vq_req;
+	struct c2wr_nsmr_register_req *wr;
+	struct c2wr_nsmr_register_rep *reply;
+	u16 flags;
+	int i, pbe_count, count;
+	int err;
+
+	if (!va || !length || !addr_list || !pbl_depth)
+		return -EINTR;
+
+	/*
+	 * Verify PBL depth is within rnic max
+	 */
+	if (pbl_depth > C2_PBL_MAX_DEPTH) {
+		return -EINTR;
+	}
+
+	/*
+	 * allocate verbs request object
+	 */
+	vq_req = vq_req_alloc(c2dev);
+	if (!vq_req)
+		return -ENOMEM;
+
+	wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);
+	if (!wr) {
+		err = -ENOMEM;
+		goto bail0;
+	}
+
+	/*
+	 * build the WR
+	 */
+	c2_wr_set_id(wr, CCWR_NSMR_REGISTER);
+	wr->hdr.context = (unsigned long) vq_req;
+	wr->rnic_handle = c2dev->adapter_handle;
+
+	flags = (acf | MEM_VA_BASED | MEM_REMOTE);
+
+	/*
+	 * compute how many pbes can fit in the message
+	 */
+	pbe_count = (c2dev->req_vq.msg_size -
+		     sizeof(struct c2wr_nsmr_register_req)) / sizeof(u64);
+
+	if (pbl_depth <= pbe_count) {
+		flags |= MEM_PBL_COMPLETE;
+	}
+	wr->flags = cpu_to_be16(flags);
+	wr->stag_key = 0;	//stag_key;
+	wr->va = cpu_to_be64(*va);
+	wr->pd_id = mr->pd->pd_id;
+	wr->pbe_size = cpu_to_be32(page_size);
+	wr->length = cpu_to_be32(length);
+	wr->pbl_depth = cpu_to_be32(pbl_depth);
+	wr->fbo = cpu_to_be32(offset);
+	count = min(pbl_depth, pbe_count);
+	wr->addrs_length = cpu_to_be32(count);
+
+	/*
+	 * fill out the PBL for this message
+	 */
+	for (i = 0; i < count; i++) {
+		wr->paddrs[i] = cpu_to_be64(addr_list[i]);
+	}
+
+	/*
+	 * regerence the request struct 
+	 */
+	vq_req_get(c2dev, vq_req);
+
+	/*
+	 * send the WR to the adapter
+	 */
+	err = vq_send_wr(c2dev, (union c2wr *) wr);
+	if (err) {
+		vq_req_put(c2dev, vq_req);
+		goto bail1;
+	}
+
+	/*
+	 * wait for reply from adapter
+	 */
+	err = vq_wait_for_reply(c2dev, vq_req);
+	if (err) {
+		goto bail1;
+	}
+
+	/*
+	 * process reply
+	 */
+	reply =
+	    (struct c2wr_nsmr_register_rep *) (unsigned long) (vq_req->reply_msg);
+	if (!reply) {
+		err = -ENOMEM;
+		goto bail1;
+	}
+	if ((err = c2_errno(reply))) {
+		goto bail2;
+	}
+	//*p_pb_entries = be32_to_cpu(reply->pbl_depth);
+	mr->ibmr.lkey = mr->ibmr.rkey = be32_to_cpu(reply->stag_index);
+	vq_repbuf_free(c2dev, reply);
+
+	/*
+	 * if there are still more PBEs we need to send them to
+	 * the adapter and wait for a reply on the final one.
+	 * reuse vq_req for this purpose.
+	 */
+	pbl_depth -= count;
+	if (pbl_depth) {
+
+		vq_req->reply_msg = (unsigned long) NULL;
+		atomic_set(&vq_req->reply_ready, 0);
+		err = send_pbl_messages(c2dev,
+					cpu_to_be32(mr->ibmr.lkey),
+					(unsigned long) &addr_list[i],
+					pbl_depth, vq_req, PBL_PHYS);
+		if (err) {
+			goto bail1;
+		}
+	}
+
+	vq_req_free(c2dev, vq_req);
+	kfree(wr);
+
+	return err;
+
+      bail2:
+	vq_repbuf_free(c2dev, reply);
+      bail1:
+	kfree(wr);
+      bail0:
+	vq_req_free(c2dev, vq_req);
+	return err;
+}
+
+int c2_stag_dealloc(struct c2_dev *c2dev, u32 stag_index)
+{
+	struct c2_vq_req *vq_req;	/* verbs request object */
+	struct c2wr_stag_dealloc_req wr;	/* work request */
+	struct c2wr_stag_dealloc_rep *reply;	/* WR reply  */
+	int err;
+
+
+	/*
+	 * allocate verbs request object
+	 */
+	vq_req = vq_req_alloc(c2dev);
+	if (!vq_req) {
+		return -ENOMEM;
+	}
+
+	/* 
+	 * Build the WR
+	 */
+	c2_wr_set_id(&wr, CCWR_STAG_DEALLOC);
+	wr.hdr.context = (u64) (unsigned long) vq_req;
+	wr.rnic_handle = c2dev->adapter_handle;
+	wr.stag_index = cpu_to_be32(stag_index);
+
+	/*
+	 * reference the request struct.  dereferenced in the int handler.
+	 */
+	vq_req_get(c2dev, vq_req);
+
+	/*
+	 * Send WR to adapter
+	 */
+	err = vq_send_wr(c2dev, (union c2wr *) & wr);
+	if (err) {
+		vq_req_put(c2dev, vq_req);
+		goto bail0;
+	}
+
+	/*
+	 * Wait for reply from adapter
+	 */
+	err = vq_wait_for_reply(c2dev, vq_req);
+	if (err) {
+		goto bail0;
+	}
+
+	/*
+	 * Process reply 
+	 */
+	reply = (struct c2wr_stag_dealloc_rep *) (unsigned long) vq_req->reply_msg;
+	if (!reply) {
+		err = -ENOMEM;
+		goto bail0;
+	}
+
+	err = c2_errno(reply);
+
+	vq_repbuf_free(c2dev, reply);
+      bail0:
+	vq_req_free(c2dev, vq_req);
+	return err;
+}

^ permalink raw reply related

* Re: Updated sysctl documentation take #2
From: Randy.Dunlap @ 2006-06-07 20:06 UTC (permalink / raw)
  To: Diego Calleja; +Cc: linux-kernel, akpm, netdev, linux-xfs, ecki, lkml
In-Reply-To: <20060607205316.bbb3c379.diegocg@gmail.com>

On Wed, 7 Jun 2006 20:53:16 +0200 Diego Calleja wrote:

> Since people didn't like the "many small files" approach, I've moved
> it to directories containing index.txt files:
> 
> Documentation/sysctl/vm/index.txt
> Documentation/sysctl/net/core/index.txt
> Documentation/sysctl/net/unix/index.txt
> Documentation/sysctl/net/ipv4/index.txt
> Documentation/sysctl/net/ipv4/conf/index.txt
> Documentation/sysctl/net/ipv4/route/index.txt
> Documentation/sysctl/net/ipv4/neigh/index.txt
> 
> and so on.
> 
> As previously, this moves all sysctl documentation (including
> XFS and network) to Documentation/sysctl/*. The patch is
> against linus tree and weights more than 200K in size
> and is place at: http://www.terra.es/personal/diegocg/sysctl-docs

~> diffstat -p1 -w 70 sysctl-docs 
 Documentation/filesystems/proc.txt            | 1210 ----------------
 Documentation/filesystems/xfs.txt             |   84 -
 Documentation/networking/00-INDEX             |    2 
 Documentation/networking/Configurable         |    2 
 Documentation/networking/decnet.txt           |    4 
 Documentation/networking/ip-sysctl.txt        |  899 -----------
 Documentation/networking/xfrm_sync.txt        |   11 
 Documentation/sysctl/README                   |  121 -
 Documentation/sysctl/abi.txt                  |   54 
 Documentation/sysctl/abi/index.txt            |   49 
 Documentation/sysctl/dev/README               |    2 
 Documentation/sysctl/fs.txt                   |  150 -
 Documentation/sysctl/fs/index.txt             |  240 +++
 Documentation/sysctl/fs/xfs/index.txt         |  170 ++
 Documentation/sysctl/kernel.txt               |  344 ----
 Documentation/sysctl/kernel/index.txt         |  628 ++++++++
 Documentation/sysctl/net/README               |    8 
 Documentation/sysctl/net/appletalk/index.txt  |   38 
 Documentation/sysctl/net/bridge/index.txt     |   44 
 Documentation/sysctl/net/core/index.txt       |  115 +
 Documentation/sysctl/net/ipv4/conf/index.txt  |  270 +++
 Documentation/sysctl/net/ipv4/index.txt       |  739 +++++++++
 Documentation/sysctl/net/ipv4/neigh/index.txt |  138 +
 Documentation/sysctl/net/ipv4/route/index.txt |  143 +
 Documentation/sysctl/net/ipv6/conf/index.txt  |  256 +++
 Documentation/sysctl/net/ipv6/icmp/index.txt  |   15 
 Documentation/sysctl/net/ipv6/index.txt       |   65 
 Documentation/sysctl/net/ipv6/neigh/index.txt |  134 +
 Documentation/sysctl/net/ipv6/route/index.txt |   78 +
 Documentation/sysctl/net/unix/index.txt       |   15 
 Documentation/sysctl/sunrpc.txt               |   20 
 Documentation/sysctl/sunrpc/index.txt         |   64 
 Documentation/sysctl/vm.txt                   |  180 --
 Documentation/sysctl/vm/index.txt             |  334 ++++
 Documentation/sysrq.txt                       |   20 
 35 files changed, 3611 insertions(+), 3035 deletions(-)
I don't know how long it takes to review such a large patch, but
I'll continue to do so.  For now:

README:

1. +Documentation for /proc/sys/, aka. sysctl

a.k.a. or just "aka".  Not "aka.".  or spell it out, or omit it,
maybe like:

Documentation for /proc/sys/ (sysctl)

2.  Limit lines to max. of 80 characters, but around 70-72 is better
IMO.  That allows someone to make minor corrections without having
to fudge the lines around.

3.  +This means there're several parameters
use "there are"

4.  +are: enabling or disabling forwading in a certain network interface
forwarding

5.  +is also used to export some stadistic information, ej: some
statistic or statistics or statistical
ej: ??  use e.g.: (preferred) or eg:

6.  +can be read but can _not_ be written.
_cannot_

7.  +own program to read them aswell)
as well)

8.  +to change '/' by '.' and ignore the '/proc/sys' part of the path, ie
s/by/to/
s/ie/i.e./

9.  +means that any tweak that you do will be lost the next time you restart  your
* collapse 2 spaces to 1

10. +_VERY_ DANGEROUS and can ruin the performance performance,
drop one "performance"

11. +As a quick 'ls /proc/sys' will show, the directory consists of several subdirs.
+Each subdir is mainly about one part of the kernel, so you can do configuration

Spell out "subdirectories" and "subdirectory".

12. +fs/		specific filesystems filehandle, inode, dentry and quota tuning

insert ":" after "filesystems"


OK, that's all for the README file.  I'll look at the rest of it
sometime this week.  I don't think that it's quite ready to be merged.

---
~Randy

^ permalink raw reply

* [PATCH v2 2/7] AMSO1100 WR / Event Definitions.
From: Steve Wise @ 2006-06-07 20:06 UTC (permalink / raw)
  To: rdreier, mshefty; +Cc: netdev, linux-kernel, openib-general
In-Reply-To: <20060607200646.9259.24588.stgit@stevo-desktop>


Review Changes:

C2_DEBUG -> DEBUG
---

 drivers/infiniband/hw/amso1100/c2_ae.h     |  108 ++
 drivers/infiniband/hw/amso1100/c2_status.h |  158 +++
 drivers/infiniband/hw/amso1100/c2_wr.h     | 1523 ++++++++++++++++++++++++++++
 3 files changed, 1789 insertions(+), 0 deletions(-)

diff --git a/drivers/infiniband/hw/amso1100/c2_ae.h b/drivers/infiniband/hw/amso1100/c2_ae.h
new file mode 100644
index 0000000..3a065c3
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_ae.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _C2_AE_H_
+#define _C2_AE_H_
+
+/*
+ * WARNING: If you change this file, also bump C2_IVN_BASE
+ * in common/include/clustercore/c2_ivn.h.
+ */
+
+/*
+ * Asynchronous Event Identifiers
+ *
+ * These start at 0x80 only so it's obvious from inspection that
+ * they are not work-request statuses.  This isn't critical.
+ *
+ * NOTE: these event id's must fit in eight bits.
+ */
+enum c2_event_id {
+	CCAE_REMOTE_SHUTDOWN = 0x80,
+	CCAE_ACTIVE_CONNECT_RESULTS,
+	CCAE_CONNECTION_REQUEST,
+	CCAE_LLP_CLOSE_COMPLETE,
+	CCAE_TERMINATE_MESSAGE_RECEIVED,
+	CCAE_LLP_CONNECTION_RESET,
+	CCAE_LLP_CONNECTION_LOST,
+	CCAE_LLP_SEGMENT_SIZE_INVALID,
+	CCAE_LLP_INVALID_CRC,
+	CCAE_LLP_BAD_FPDU,
+	CCAE_INVALID_DDP_VERSION,
+	CCAE_INVALID_RDMA_VERSION,
+	CCAE_UNEXPECTED_OPCODE,
+	CCAE_INVALID_DDP_QUEUE_NUMBER,
+	CCAE_RDMA_READ_NOT_ENABLED,
+	CCAE_RDMA_WRITE_NOT_ENABLED,
+	CCAE_RDMA_READ_TOO_SMALL,
+	CCAE_NO_L_BIT,
+	CCAE_TAGGED_INVALID_STAG,
+	CCAE_TAGGED_BASE_BOUNDS_VIOLATION,
+	CCAE_TAGGED_ACCESS_RIGHTS_VIOLATION,
+	CCAE_TAGGED_INVALID_PD,
+	CCAE_WRAP_ERROR,
+	CCAE_BAD_CLOSE,
+	CCAE_BAD_LLP_CLOSE,
+	CCAE_INVALID_MSN_RANGE,
+	CCAE_INVALID_MSN_GAP,
+	CCAE_IRRQ_OVERFLOW,
+	CCAE_IRRQ_MSN_GAP,
+	CCAE_IRRQ_MSN_RANGE,
+	CCAE_IRRQ_INVALID_STAG,
+	CCAE_IRRQ_BASE_BOUNDS_VIOLATION,
+	CCAE_IRRQ_ACCESS_RIGHTS_VIOLATION,
+	CCAE_IRRQ_INVALID_PD,
+	CCAE_IRRQ_WRAP_ERROR,
+	CCAE_CQ_SQ_COMPLETION_OVERFLOW,
+	CCAE_CQ_RQ_COMPLETION_ERROR,
+	CCAE_QP_SRQ_WQE_ERROR,
+	CCAE_QP_LOCAL_CATASTROPHIC_ERROR,
+	CCAE_CQ_OVERFLOW,
+	CCAE_CQ_OPERATION_ERROR,
+	CCAE_SRQ_LIMIT_REACHED,
+	CCAE_QP_RQ_LIMIT_REACHED,
+	CCAE_SRQ_CATASTROPHIC_ERROR,
+	CCAE_RNIC_CATASTROPHIC_ERROR
+/* WARNING If you add more id's, make sure their values fit in eight bits. */
+};
+
+/*
+ * Resource Indicators and Identifiers
+ */
+enum c2_resource_indicator {
+	C2_RES_IND_QP = 1,
+	C2_RES_IND_EP,
+	C2_RES_IND_CQ,
+	C2_RES_IND_SRQ,
+};
+
+#endif /* _C2_AE_H_ */
diff --git a/drivers/infiniband/hw/amso1100/c2_status.h b/drivers/infiniband/hw/amso1100/c2_status.h
new file mode 100644
index 0000000..6ee4aa9
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_status.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef	_C2_STATUS_H_
+#define _C2_STATUS_H_
+
+/*
+ * Verbs Status Codes
+ */
+enum c2_status {
+	C2_OK = 0,		/* This must be zero */
+	CCERR_INSUFFICIENT_RESOURCES = 1,
+	CCERR_INVALID_MODIFIER = 2,
+	CCERR_INVALID_MODE = 3,
+	CCERR_IN_USE = 4,
+	CCERR_INVALID_RNIC = 5,
+	CCERR_INTERRUPTED_OPERATION = 6,
+	CCERR_INVALID_EH = 7,
+	CCERR_INVALID_CQ = 8,
+	CCERR_CQ_EMPTY = 9,
+	CCERR_NOT_IMPLEMENTED = 10,
+	CCERR_CQ_DEPTH_TOO_SMALL = 11,
+	CCERR_PD_IN_USE = 12,
+	CCERR_INVALID_PD = 13,
+	CCERR_INVALID_SRQ = 14,
+	CCERR_INVALID_ADDRESS = 15,
+	CCERR_INVALID_NETMASK = 16,
+	CCERR_INVALID_QP = 17,
+	CCERR_INVALID_QP_STATE = 18,
+	CCERR_TOO_MANY_WRS_POSTED = 19,
+	CCERR_INVALID_WR_TYPE = 20,
+	CCERR_INVALID_SGL_LENGTH = 21,
+	CCERR_INVALID_SQ_DEPTH = 22,
+	CCERR_INVALID_RQ_DEPTH = 23,
+	CCERR_INVALID_ORD = 24,
+	CCERR_INVALID_IRD = 25,
+	CCERR_QP_ATTR_CANNOT_CHANGE = 26,
+	CCERR_INVALID_STAG = 27,
+	CCERR_QP_IN_USE = 28,
+	CCERR_OUTSTANDING_WRS = 29,
+	CCERR_STAG_IN_USE = 30,
+	CCERR_INVALID_STAG_INDEX = 31,
+	CCERR_INVALID_SGL_FORMAT = 32,
+	CCERR_ADAPTER_TIMEOUT = 33,
+	CCERR_INVALID_CQ_DEPTH = 34,
+	CCERR_INVALID_PRIVATE_DATA_LENGTH = 35,
+	CCERR_INVALID_EP = 36,
+	CCERR_MR_IN_USE = CCERR_STAG_IN_USE,
+	CCERR_FLUSHED = 38,
+	CCERR_INVALID_WQE = 39,
+	CCERR_LOCAL_QP_CATASTROPHIC_ERROR = 40,
+	CCERR_REMOTE_TERMINATION_ERROR = 41,
+	CCERR_BASE_AND_BOUNDS_VIOLATION = 42,
+	CCERR_ACCESS_VIOLATION = 43,
+	CCERR_INVALID_PD_ID = 44,
+	CCERR_WRAP_ERROR = 45,
+	CCERR_INV_STAG_ACCESS_ERROR = 46,
+	CCERR_ZERO_RDMA_READ_RESOURCES = 47,
+	CCERR_QP_NOT_PRIVILEGED = 48,
+	CCERR_STAG_STATE_NOT_INVALID = 49,
+	CCERR_INVALID_PAGE_SIZE = 50,
+	CCERR_INVALID_BUFFER_SIZE = 51,
+	CCERR_INVALID_PBE = 52,
+	CCERR_INVALID_FBO = 53,
+	CCERR_INVALID_LENGTH = 54,
+	CCERR_INVALID_ACCESS_RIGHTS = 55,
+	CCERR_PBL_TOO_BIG = 56,
+	CCERR_INVALID_VA = 57,
+	CCERR_INVALID_REGION = 58,
+	CCERR_INVALID_WINDOW = 59,
+	CCERR_TOTAL_LENGTH_TOO_BIG = 60,
+	CCERR_INVALID_QP_ID = 61,
+	CCERR_ADDR_IN_USE = 62,
+	CCERR_ADDR_NOT_AVAIL = 63,
+	CCERR_NET_DOWN = 64,
+	CCERR_NET_UNREACHABLE = 65,
+	CCERR_CONN_ABORTED = 66,
+	CCERR_CONN_RESET = 67,
+	CCERR_NO_BUFS = 68,
+	CCERR_CONN_TIMEDOUT = 69,
+	CCERR_CONN_REFUSED = 70,
+	CCERR_HOST_UNREACHABLE = 71,
+	CCERR_INVALID_SEND_SGL_DEPTH = 72,
+	CCERR_INVALID_RECV_SGL_DEPTH = 73,
+	CCERR_INVALID_RDMA_WRITE_SGL_DEPTH = 74,
+	CCERR_INSUFFICIENT_PRIVILEGES = 75,
+	CCERR_STACK_ERROR = 76,
+	CCERR_INVALID_VERSION = 77,
+	CCERR_INVALID_MTU = 78,
+	CCERR_INVALID_IMAGE = 79,
+	CCERR_PENDING = 98,	/* not an error; user internally by adapter */
+	CCERR_DEFER = 99,	/* not an error; used internally by adapter */
+	CCERR_FAILED_WRITE = 100,
+	CCERR_FAILED_ERASE = 101,
+	CCERR_FAILED_VERIFICATION = 102,
+	CCERR_NOT_FOUND = 103,
+
+};
+
+/*
+ * CCAE_ACTIVE_CONNECT_RESULTS status result codes.
+ */
+enum c2_connect_status {
+	C2_CONN_STATUS_SUCCESS = C2_OK,
+	C2_CONN_STATUS_NO_MEM = CCERR_INSUFFICIENT_RESOURCES,
+	C2_CONN_STATUS_TIMEDOUT = CCERR_CONN_TIMEDOUT,
+	C2_CONN_STATUS_REFUSED = CCERR_CONN_REFUSED,
+	C2_CONN_STATUS_NETUNREACH = CCERR_NET_UNREACHABLE,
+	C2_CONN_STATUS_HOSTUNREACH = CCERR_HOST_UNREACHABLE,
+	C2_CONN_STATUS_INVALID_RNIC = CCERR_INVALID_RNIC,
+	C2_CONN_STATUS_INVALID_QP = CCERR_INVALID_QP,
+	C2_CONN_STATUS_INVALID_QP_STATE = CCERR_INVALID_QP_STATE,
+	C2_CONN_STATUS_REJECTED = CCERR_CONN_RESET,
+	C2_CONN_STATUS_ADDR_NOT_AVAIL = CCERR_ADDR_NOT_AVAIL,
+};
+
+/*
+ * Flash programming status codes.
+ */
+enum c2_flash_status {
+	C2_FLASH_STATUS_SUCCESS = 0x0000,
+	C2_FLASH_STATUS_VERIFY_ERR = 0x0002,
+	C2_FLASH_STATUS_IMAGE_ERR = 0x0004,
+	C2_FLASH_STATUS_ECLBS = 0x0400,
+	C2_FLASH_STATUS_PSLBS = 0x0800,
+	C2_FLASH_STATUS_VPENS = 0x1000,
+};
+
+#endif				/* _C2_STATUS_H_ */
diff --git a/drivers/infiniband/hw/amso1100/c2_wr.h b/drivers/infiniband/hw/amso1100/c2_wr.h
new file mode 100644
index 0000000..9d6468d
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_wr.h
@@ -0,0 +1,1523 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _C2_WR_H_
+#define _C2_WR_H_
+
+#ifdef CCDEBUG
+#define CCWR_MAGIC		0xb07700b0
+#endif
+
+#define C2_QP_NO_ATTR_CHANGE 0xFFFFFFFF
+
+/* Maximum allowed size in bytes of private_data exchange
+ * on connect.
+ */
+#define C2_MAX_PRIVATE_DATA_SIZE 200
+
+/*
+ * These types are shared among the adapter, host, and CCIL consumer.  
+ */
+enum c2_cq_notification_type {
+	C2_CQ_NOTIFICATION_TYPE_NONE = 1,
+	C2_CQ_NOTIFICATION_TYPE_NEXT,
+	C2_CQ_NOTIFICATION_TYPE_NEXT_SE
+};
+
+enum c2_setconfig_cmd {
+	C2_CFG_ADD_ADDR = 1,
+	C2_CFG_DEL_ADDR = 2,
+	C2_CFG_ADD_ROUTE = 3,
+	C2_CFG_DEL_ROUTE = 4
+};
+
+enum c2_getconfig_cmd {
+	C2_GETCONFIG_ROUTES = 1,
+	C2_GETCONFIG_ADDRS
+};
+
+/*
+ *  CCIL Work Request Identifiers
+ */
+enum c2wr_ids {
+	CCWR_RNIC_OPEN = 1,
+	CCWR_RNIC_QUERY,
+	CCWR_RNIC_SETCONFIG,
+	CCWR_RNIC_GETCONFIG,
+	CCWR_RNIC_CLOSE,
+	CCWR_CQ_CREATE,
+	CCWR_CQ_QUERY,
+	CCWR_CQ_MODIFY,
+	CCWR_CQ_DESTROY,
+	CCWR_QP_CONNECT,
+	CCWR_PD_ALLOC,
+	CCWR_PD_DEALLOC,
+	CCWR_SRQ_CREATE,
+	CCWR_SRQ_QUERY,
+	CCWR_SRQ_MODIFY,
+	CCWR_SRQ_DESTROY,
+	CCWR_QP_CREATE,
+	CCWR_QP_QUERY,
+	CCWR_QP_MODIFY,
+	CCWR_QP_DESTROY,
+	CCWR_NSMR_STAG_ALLOC,
+	CCWR_NSMR_REGISTER,
+	CCWR_NSMR_PBL,
+	CCWR_STAG_DEALLOC,
+	CCWR_NSMR_REREGISTER,
+	CCWR_SMR_REGISTER,
+	CCWR_MR_QUERY,
+	CCWR_MW_ALLOC,
+	CCWR_MW_QUERY,
+	CCWR_EP_CREATE,
+	CCWR_EP_GETOPT,
+	CCWR_EP_SETOPT,
+	CCWR_EP_DESTROY,
+	CCWR_EP_BIND,
+	CCWR_EP_CONNECT,
+	CCWR_EP_LISTEN,
+	CCWR_EP_SHUTDOWN,
+	CCWR_EP_LISTEN_CREATE,
+	CCWR_EP_LISTEN_DESTROY,
+	CCWR_EP_QUERY,
+	CCWR_CR_ACCEPT,
+	CCWR_CR_REJECT,
+	CCWR_CONSOLE,
+	CCWR_TERM,
+	CCWR_FLASH_INIT,
+	CCWR_FLASH,
+	CCWR_BUF_ALLOC,
+	CCWR_BUF_FREE,
+	CCWR_FLASH_WRITE,
+	CCWR_INIT,		/* WARNING: Don't move this ever again! */
+
+
+
+	/* Add new IDs here */
+
+
+
+	/* 
+	 * WARNING: CCWR_LAST must always be the last verbs id defined! 
+	 *          All the preceding IDs are fixed, and must not change.
+	 *          You can add new IDs, but must not remove or reorder
+	 *          any IDs. If you do, YOU will ruin any hope of
+	 *          compatability between versions.
+	 */
+	CCWR_LAST,
+
+	/*
+	 * Start over at 1 so that arrays indexed by user wr id's
+	 * begin at 1.  This is OK since the verbs and user wr id's
+	 * are always used on disjoint sets of queues.
+	 */
+	/* 
+	 * The order of the CCWR_SEND_XX verbs must 
+	 * match the order of the RDMA_OPs 
+	 */
+	CCWR_SEND = 1,
+	CCWR_SEND_INV,
+	CCWR_SEND_SE,
+	CCWR_SEND_SE_INV,
+	CCWR_RDMA_WRITE,
+	CCWR_RDMA_READ,
+	CCWR_RDMA_READ_INV,
+	CCWR_MW_BIND,
+	CCWR_NSMR_FASTREG,
+	CCWR_STAG_INVALIDATE,
+	CCWR_RECV,
+	CCWR_NOP,
+	CCWR_UNIMPL,		
+/* WARNING: This must always be the last user wr id defined! */
+};
+#define RDMA_SEND_OPCODE_FROM_WR_ID(x)   (x+2)
+
+/*
+ * SQ/RQ Work Request Types
+ */
+enum c2_wr_type {
+	C2_WR_TYPE_SEND = CCWR_SEND,
+	C2_WR_TYPE_SEND_SE = CCWR_SEND_SE,
+	C2_WR_TYPE_SEND_INV = CCWR_SEND_INV,
+	C2_WR_TYPE_SEND_SE_INV = CCWR_SEND_SE_INV,
+	C2_WR_TYPE_RDMA_WRITE = CCWR_RDMA_WRITE,
+	C2_WR_TYPE_RDMA_READ = CCWR_RDMA_READ,
+	C2_WR_TYPE_RDMA_READ_INV_STAG = CCWR_RDMA_READ_INV,
+	C2_WR_TYPE_BIND_MW = CCWR_MW_BIND,
+	C2_WR_TYPE_FASTREG_NSMR = CCWR_NSMR_FASTREG,
+	C2_WR_TYPE_INV_STAG = CCWR_STAG_INVALIDATE,
+	C2_WR_TYPE_RECV = CCWR_RECV,
+	C2_WR_TYPE_NOP = CCWR_NOP,
+};
+
+struct c2_netaddr {
+	u32 ip_addr;
+	u32 netmask;
+	u32 mtu;
+};
+
+struct c2_route {
+	u32 ip_addr;		/* 0 indicates the default route */
+	u32 netmask;		/* netmask associated with dst */
+	u32 flags;
+	union {
+		u32 ipaddr;	/* address of the nexthop interface */
+		u8 enaddr[6];
+	} nexthop;
+};
+
+/*
+ * A Scatter Gather Entry.
+ */
+struct c2_data_addr {
+	u32 stag;
+	u32 length;
+	u64 to;
+};
+
+/*
+ * MR and MW flags used by the consumer, RI, and RNIC.
+ */
+enum c2_mm_flags {
+	MEM_REMOTE = 0x0001,	/* allow mw binds with remote access. */
+	MEM_VA_BASED = 0x0002,	/* Not Zero-based */
+	MEM_PBL_COMPLETE = 0x0004,	/* PBL array is complete in this msg */
+	MEM_LOCAL_READ = 0x0008,	/* allow local reads */
+	MEM_LOCAL_WRITE = 0x0010,	/* allow local writes */
+	MEM_REMOTE_READ = 0x0020,	/* allow remote reads */
+	MEM_REMOTE_WRITE = 0x0040,	/* allow remote writes */
+	MEM_WINDOW_BIND = 0x0080,	/* binds allowed */
+	MEM_SHARED = 0x0100,	/* set if MR is shared */
+	MEM_STAG_VALID = 0x0200	/* set if STAG is in valid state */
+};
+
+/*
+ * CCIL API ACF flags defined in terms of the low level mem flags.
+ * This minimizes translation needed in the user API
+ */
+enum c2_acf {
+	C2_ACF_LOCAL_READ = MEM_LOCAL_READ,
+	C2_ACF_LOCAL_WRITE = MEM_LOCAL_WRITE,
+	C2_ACF_REMOTE_READ = MEM_REMOTE_READ,
+	C2_ACF_REMOTE_WRITE = MEM_REMOTE_WRITE,
+	C2_ACF_WINDOW_BIND = MEM_WINDOW_BIND
+};
+
+/*
+ * Image types of objects written to flash
+ */
+#define C2_FLASH_IMG_BITFILE 1
+#define C2_FLASH_IMG_OPTION_ROM 2
+#define C2_FLASH_IMG_VPD 3
+
+/*
+ *  to fix bug 1815 we define the max size allowable of the
+ *  terminate message (per the IETF spec).Refer to the IETF
+ *  protocal specification, section 12.1.6, page 64)
+ *  The message is prefixed by 20 types of DDP info.
+ *
+ *  Then the message has 6 bytes for the terminate control 
+ *  and DDP segment length info plus a DDP header (either
+ *  14 or 18 byts) plus 28 bytes for the RDMA header.
+ *  Thus the max size in:
+ *  20 + (6 + 18 + 28) = 72
+ */
+#define C2_MAX_TERMINATE_MESSAGE_SIZE (72)
+
+/*
+ * Build String Length.  It must be the same as C2_BUILD_STR_LEN in ccil_api.h
+ */
+#define WR_BUILD_STR_LEN 64
+
+/*
+ * WARNING:  All of these structs need to align any 64bit types on   
+ * 64 bit boundaries!  64bit types include u64 and u64.
+ */
+
+/*
+ * Clustercore Work Request Header.  Be sensitive to field layout
+ * and alignment.
+ */
+struct c2wr_hdr {
+	/* wqe_count is part of the cqe.  It is put here so the
+	 * adapter can write to it while the wr is pending without
+	 * clobbering part of the wr.  This word need not be dma'd
+	 * from the host to adapter by libccil, but we copy it anyway
+	 * to make the memcpy to the adapter better aligned.
+	 */
+	u32 wqe_count;
+
+	/* Put these fields next so that later 32- and 64-bit
+	 * quantities are naturally aligned.
+	 */
+	u8 id;
+	u8 result;		/* adapter -> host */
+	u8 sge_count;		/* host -> adapter */
+	u8 flags;		/* host -> adapter */
+
+	u64 context;
+#ifdef CCMSGMAGIC
+	u32 magic;
+	u32 pad;
+#endif
+} __attribute__((packed));
+
+/*
+ *------------------------ RNIC ------------------------
+ */
+
+/*
+ * WR_RNIC_OPEN
+ */
+
+/*
+ * Flags for the RNIC WRs
+ */
+enum c2_rnic_flags {
+	RNIC_IRD_STATIC = 0x0001,
+	RNIC_ORD_STATIC = 0x0002,
+	RNIC_QP_STATIC = 0x0004,
+	RNIC_SRQ_SUPPORTED = 0x0008,
+	RNIC_PBL_BLOCK_MODE = 0x0010,
+	RNIC_SRQ_MODEL_ARRIVAL = 0x0020,
+	RNIC_CQ_OVF_DETECTED = 0x0040,
+	RNIC_PRIV_MODE = 0x0080
+};
+
+struct c2wr_rnic_open_req {
+	struct c2wr_hdr hdr;
+	u64 user_context;
+	u16 flags;		/* See enum c2_rnic_flags */
+	u16 port_num;
+} __attribute__((packed));
+
+struct c2wr_rnic_open_rep {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+} __attribute__((packed));
+
+union c2wr_rnic_open {
+	struct c2wr_rnic_open_req req;
+	struct c2wr_rnic_open_rep rep;
+} __attribute__((packed));
+
+struct c2wr_rnic_query_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+} __attribute__((packed));
+
+/*
+ * WR_RNIC_QUERY
+ */
+struct c2wr_rnic_query_rep {
+	struct c2wr_hdr hdr;
+	u64 user_context;
+	u32 vendor_id;
+	u32 part_number;
+	u32 hw_version;
+	u32 fw_ver_major;
+	u32 fw_ver_minor;
+	u32 fw_ver_patch;
+	char fw_ver_build_str[WR_BUILD_STR_LEN];
+	u32 max_qps;
+	u32 max_qp_depth;
+	u32 max_srq_depth;
+	u32 max_send_sgl_depth;
+	u32 max_rdma_sgl_depth;
+	u32 max_cqs;
+	u32 max_cq_depth;
+	u32 max_cq_event_handlers;
+	u32 max_mrs;
+	u32 max_pbl_depth;
+	u32 max_pds;
+	u32 max_global_ird;
+	u32 max_global_ord;
+	u32 max_qp_ird;
+	u32 max_qp_ord;
+	u32 flags;		
+	u32 max_mws;
+	u32 pbe_range_low;
+	u32 pbe_range_high;
+	u32 max_srqs;
+	u32 page_size;
+} __attribute__((packed));
+
+union c2wr_rnic_query {
+	struct c2wr_rnic_query_req req;
+	struct c2wr_rnic_query_rep rep;
+} __attribute__((packed));
+
+/*
+ * WR_RNIC_GETCONFIG
+ */
+
+struct c2wr_rnic_getconfig_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 option;		/* see c2_getconfig_cmd_t */
+	u64 reply_buf;
+	u32 reply_buf_len;
+} __attribute__((packed)) ;
+
+struct c2wr_rnic_getconfig_rep {
+	struct c2wr_hdr hdr;
+	u32 option;		/* see c2_getconfig_cmd_t */
+	u32 count_len;		/* length of the number of addresses configured */
+} __attribute__((packed)) ;
+
+union c2wr_rnic_getconfig {
+	struct c2wr_rnic_getconfig_req req;
+	struct c2wr_rnic_getconfig_rep rep;
+} __attribute__((packed)) ;
+
+/*
+ * WR_RNIC_SETCONFIG
+ */
+struct c2wr_rnic_setconfig_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 option;		/* See c2_setconfig_cmd_t */
+	/* variable data and pad. See c2_netaddr and c2_route */
+	u8 data[0];
+} __attribute__((packed)) ;
+
+struct c2wr_rnic_setconfig_rep {
+	struct c2wr_hdr hdr;
+} __attribute__((packed)) ;
+
+union c2wr_rnic_setconfig {
+	struct c2wr_rnic_setconfig_req req;
+	struct c2wr_rnic_setconfig_rep rep;
+} __attribute__((packed)) ;
+
+/*
+ * WR_RNIC_CLOSE
+ */
+struct c2wr_rnic_close_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+} __attribute__((packed)) ;
+
+struct c2wr_rnic_close_rep {
+	struct c2wr_hdr hdr;
+} __attribute__((packed)) ;
+
+union c2wr_rnic_close {
+	struct c2wr_rnic_close_req req;
+	struct c2wr_rnic_close_rep rep;
+} __attribute__((packed)) ;
+
+/*
+ *------------------------ CQ ------------------------
+ */
+struct c2wr_cq_create_req {
+	struct c2wr_hdr hdr;
+	u64 shared_ht;
+	u64 user_context;
+	u64 msg_pool;
+	u32 rnic_handle;
+	u32 msg_size;
+	u32 depth;
+} __attribute__((packed)) ;
+
+struct c2wr_cq_create_rep {
+	struct c2wr_hdr hdr;
+	u32 mq_index;
+	u32 adapter_shared;
+	u32 cq_handle;
+} __attribute__((packed)) ;
+
+union c2wr_cq_create {
+	struct c2wr_cq_create_req req;
+	struct c2wr_cq_create_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_cq_modify_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 cq_handle;
+	u32 new_depth;
+	u64 new_msg_pool;
+} __attribute__((packed)) ;
+
+struct c2wr_cq_modify_rep {
+	struct c2wr_hdr hdr;
+} __attribute__((packed)) ;
+
+union c2wr_cq_modify {
+	struct c2wr_cq_modify_req req;
+	struct c2wr_cq_modify_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_cq_destroy_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 cq_handle;
+} __attribute__((packed)) ;
+
+struct c2wr_cq_destroy_rep {
+	struct c2wr_hdr hdr;
+} __attribute__((packed)) ;
+
+union c2wr_cq_destroy {
+	struct c2wr_cq_destroy_req req;
+	struct c2wr_cq_destroy_rep rep;
+} __attribute__((packed)) ;
+
+/*
+ *------------------------ PD ------------------------
+ */
+struct c2wr_pd_alloc_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 pd_id;
+} __attribute__((packed)) ;
+
+struct c2wr_pd_alloc_rep {
+	struct c2wr_hdr hdr;
+} __attribute__((packed)) ;
+
+union c2wr_pd_alloc {
+	struct c2wr_pd_alloc_req req;
+	struct c2wr_pd_alloc_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_pd_dealloc_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 pd_id;
+} __attribute__((packed)) ;
+
+struct c2wr_pd_dealloc_rep {
+	struct c2wr_hdr hdr;
+} __attribute__((packed)) ;
+
+union c2wr_pd_dealloc {
+	struct c2wr_pd_dealloc_req req;
+	struct c2wr_pd_dealloc_rep rep;
+} __attribute__((packed)) ;
+
+/*
+ *------------------------ SRQ ------------------------
+ */
+struct c2wr_srq_create_req {
+	struct c2wr_hdr hdr;
+	u64 shared_ht;
+	u64 user_context;
+	u32 rnic_handle;
+	u32 srq_depth;
+	u32 srq_limit;
+	u32 sgl_depth;
+	u32 pd_id;
+} __attribute__((packed)) ;
+
+struct c2wr_srq_create_rep {
+	struct c2wr_hdr hdr;
+	u32 srq_depth;
+	u32 sgl_depth;
+	u32 msg_size;
+	u32 mq_index;
+	u32 mq_start;
+	u32 srq_handle;
+} __attribute__((packed)) ;
+
+union c2wr_srq_create {
+	struct c2wr_srq_create_req req;
+	struct c2wr_srq_create_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_srq_destroy_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 srq_handle;
+} __attribute__((packed)) ;
+
+struct c2wr_srq_destroy_rep {
+	struct c2wr_hdr hdr;
+} __attribute__((packed)) ;
+
+union c2wr_srq_destroy {
+	struct c2wr_srq_destroy_req req;
+	struct c2wr_srq_destroy_rep rep;
+} __attribute__((packed)) ;
+
+/*
+ *------------------------ QP ------------------------
+ */
+enum c2wr_qp_flags {
+	QP_RDMA_READ = 0x00000001,	/* RDMA read enabled? */
+	QP_RDMA_WRITE = 0x00000002,	/* RDMA write enabled? */
+	QP_MW_BIND = 0x00000004,	/* MWs enabled */
+	QP_ZERO_STAG = 0x00000008,	/* enabled? */
+	QP_REMOTE_TERMINATION = 0x00000010,	/* remote end terminated */
+	QP_RDMA_READ_RESPONSE = 0x00000020	/* Remote RDMA read  */
+	    /* enabled? */
+};
+
+struct c2wr_qp_create_req {
+	struct c2wr_hdr hdr;
+	u64 shared_sq_ht;
+	u64 shared_rq_ht;
+	u64 user_context;
+	u32 rnic_handle;
+	u32 sq_cq_handle;
+	u32 rq_cq_handle;
+	u32 sq_depth;
+	u32 rq_depth;
+	u32 srq_handle;
+	u32 srq_limit;
+	u32 flags;		/* see enum c2wr_qp_flags */
+	u32 send_sgl_depth;
+	u32 recv_sgl_depth;
+	u32 rdma_write_sgl_depth;
+	u32 ord;
+	u32 ird;
+	u32 pd_id;
+} __attribute__((packed)) ;
+
+struct c2wr_qp_create_rep {
+	struct c2wr_hdr hdr;
+	u32 sq_depth;
+	u32 rq_depth;
+	u32 send_sgl_depth;
+	u32 recv_sgl_depth;
+	u32 rdma_write_sgl_depth;
+	u32 ord;
+	u32 ird;
+	u32 sq_msg_size;
+	u32 sq_mq_index;
+	u32 sq_mq_start;
+	u32 rq_msg_size;
+	u32 rq_mq_index;
+	u32 rq_mq_start;
+	u32 qp_handle;
+} __attribute__((packed)) ;
+
+union c2wr_qp_create {
+	struct c2wr_qp_create_req req;
+	struct c2wr_qp_create_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_qp_query_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 qp_handle;
+} __attribute__((packed)) ;
+
+struct c2wr_qp_query_rep {
+	struct c2wr_hdr hdr;
+	u64 user_context;
+	u32 rnic_handle;
+	u32 sq_depth;
+	u32 rq_depth;
+	u32 send_sgl_depth;
+	u32 rdma_write_sgl_depth;
+	u32 recv_sgl_depth;
+	u32 ord;
+	u32 ird;
+	u16 qp_state;
+	u16 flags;		/* see c2wr_qp_flags_t */
+	u32 qp_id;
+	u32 local_addr;
+	u32 remote_addr;
+	u16 local_port;
+	u16 remote_port;
+	u32 terminate_msg_length;	/* 0 if not present */
+	u8 data[0];
+	/* Terminate Message in-line here. */
+} __attribute__((packed)) ;
+
+union c2wr_qp_query {
+	struct c2wr_qp_query_req req;
+	struct c2wr_qp_query_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_qp_modify_req {
+	struct c2wr_hdr hdr;
+	u64 stream_msg;
+	u32 stream_msg_length;
+	u32 rnic_handle;
+	u32 qp_handle;
+	u32 next_qp_state;
+	u32 ord;
+	u32 ird;
+	u32 sq_depth;
+	u32 rq_depth;
+	u32 llp_ep_handle;
+} __attribute__((packed)) ;
+
+struct c2wr_qp_modify_rep {
+	struct c2wr_hdr hdr;
+	u32 ord;
+	u32 ird;
+	u32 sq_depth;
+	u32 rq_depth;
+	u32 sq_msg_size;
+	u32 sq_mq_index;
+	u32 sq_mq_start;
+	u32 rq_msg_size;
+	u32 rq_mq_index;
+	u32 rq_mq_start;
+} __attribute__((packed)) ;
+
+union c2wr_qp_modify {
+	struct c2wr_qp_modify_req req;
+	struct c2wr_qp_modify_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_qp_destroy_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 qp_handle;
+} __attribute__((packed)) ;
+
+struct c2wr_qp_destroy_rep {
+	struct c2wr_hdr hdr;
+} __attribute__((packed)) ;
+
+union c2wr_qp_destroy {
+	struct c2wr_qp_destroy_req req;
+	struct c2wr_qp_destroy_rep rep;
+} __attribute__((packed)) ;
+
+/*
+ * The CCWR_QP_CONNECT msg is posted on the verbs request queue.  It can
+ * only be posted when a QP is in IDLE state.  After the connect request is
+ * submitted to the LLP, the adapter moves the QP to CONNECT_PENDING state.
+ * No synchronous reply from adapter to this WR.  The results of
+ * connection are passed back in an async event CCAE_ACTIVE_CONNECT_RESULTS
+ * See c2wr_ae_active_connect_results_t
+ */
+struct c2wr_qp_connect_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 qp_handle;
+	u32 remote_addr;
+	u16 remote_port;
+	u16 pad;
+	u32 private_data_length;
+	u8 private_data[0];	/* Private data in-line. */
+} __attribute__((packed)) ;
+
+struct c2wr_qp_connect {
+	struct c2wr_qp_connect_req req;
+	/* no synchronous reply.         */
+} __attribute__((packed)) ;
+
+
+/*
+ *------------------------ MM ------------------------
+ */
+
+struct c2wr_nsmr_stag_alloc_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 pbl_depth;
+	u32 pd_id;
+	u32 flags;
+} __attribute__((packed)) ;
+
+struct c2wr_nsmr_stag_alloc_rep {
+	struct c2wr_hdr hdr;
+	u32 pbl_depth;
+	u32 stag_index;
+} __attribute__((packed)) ;
+
+union c2wr_nsmr_stag_alloc {
+	struct c2wr_nsmr_stag_alloc_req req;
+	struct c2wr_nsmr_stag_alloc_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_nsmr_register_req {
+	struct c2wr_hdr hdr;
+	u64 va;
+	u32 rnic_handle;
+	u16 flags;
+	u8 stag_key;
+	u8 pad;
+	u32 pd_id;
+	u32 pbl_depth;
+	u32 pbe_size;
+	u32 fbo;
+	u32 length;
+	u32 addrs_length;
+	/* array of paddrs (must be aligned on a 64bit boundary) */
+	u64 paddrs[0];
+} __attribute__((packed)) ;
+
+struct c2wr_nsmr_register_rep {
+	struct c2wr_hdr hdr;
+	u32 pbl_depth;
+	u32 stag_index;
+} __attribute__((packed)) ;
+
+union c2wr_nsmr_register {
+	struct c2wr_nsmr_register_req req;
+	struct c2wr_nsmr_register_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_nsmr_pbl_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 flags;
+	u32 stag_index;
+	u32 addrs_length;
+	/* array of paddrs (must be aligned on a 64bit boundary) */
+	u64 paddrs[0];
+} __attribute__((packed)) ;
+
+struct c2wr_nsmr_pbl_rep {
+	struct c2wr_hdr hdr;
+} __attribute__((packed)) ;
+
+union c2wr_nsmr_pbl {
+	struct c2wr_nsmr_pbl_req req;
+	struct c2wr_nsmr_pbl_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_mr_query_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 stag_index;
+} __attribute__((packed)) ;
+
+struct c2wr_mr_query_rep {
+	struct c2wr_hdr hdr;
+	u8 stag_key;
+	u8 pad[3];
+	u32 pd_id;
+	u32 flags;
+	u32 pbl_depth;
+} __attribute__((packed)) ;
+
+union c2wr_mr_query {
+	struct c2wr_mr_query_req req;
+	struct c2wr_mr_query_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_mw_query_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 stag_index;
+} __attribute__((packed)) ;
+
+struct c2wr_mw_query_rep {
+	struct c2wr_hdr hdr;
+	u8 stag_key;
+	u8 pad[3];
+	u32 pd_id;
+	u32 flags;
+} __attribute__((packed)) ;
+
+union c2wr_mw_query {
+	struct c2wr_mw_query_req req;
+	struct c2wr_mw_query_rep rep;
+} __attribute__((packed)) ;
+
+
+struct c2wr_stag_dealloc_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 stag_index;
+} __attribute__((packed)) ;
+
+struct c2wr_stag_dealloc_rep {
+	struct c2wr_hdr hdr;
+} __attribute__((packed)) ;
+
+union c2wr_stag_dealloc {
+	struct c2wr_stag_dealloc_req req;
+	struct c2wr_stag_dealloc_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_nsmr_reregister_req {
+	struct c2wr_hdr hdr;
+	u64 va;
+	u32 rnic_handle;
+	u16 flags;
+	u8 stag_key;
+	u8 pad;
+	u32 stag_index;
+	u32 pd_id;
+	u32 pbl_depth;
+	u32 pbe_size;
+	u32 fbo;
+	u32 length;
+	u32 addrs_length;
+	u32 pad1;
+	/* array of paddrs (must be aligned on a 64bit boundary) */
+	u64 paddrs[0];
+} __attribute__((packed)) ;
+
+struct c2wr_nsmr_reregister_rep {
+	struct c2wr_hdr hdr;
+	u32 pbl_depth;
+	u32 stag_index;
+} __attribute__((packed)) ;
+
+union c2wr_nsmr_reregister {
+	struct c2wr_nsmr_reregister_req req;
+	struct c2wr_nsmr_reregister_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_smr_register_req {
+	struct c2wr_hdr hdr;
+	u64 va;
+	u32 rnic_handle;
+	u16 flags;
+	u8 stag_key;
+	u8 pad;
+	u32 stag_index;
+	u32 pd_id;
+} __attribute__((packed)) ;
+
+struct c2wr_smr_register_rep {
+	struct c2wr_hdr hdr;
+	u32 stag_index;
+} __attribute__((packed)) ;
+
+union c2wr_smr_register {
+	struct c2wr_smr_register_req req;
+	struct c2wr_smr_register_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_mw_alloc_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 pd_id;
+} __attribute__((packed)) ;
+
+struct c2wr_mw_alloc_rep {
+	struct c2wr_hdr hdr;
+	u32 stag_index;
+} __attribute__((packed)) ;
+
+union c2wr_mw_alloc {
+	struct c2wr_mw_alloc_req req;
+	struct c2wr_mw_alloc_rep rep;
+} __attribute__((packed)) ;
+
+/*
+ *------------------------ WRs -----------------------
+ */
+
+struct c2wr_user_hdr {
+	struct c2wr_hdr hdr;		/* Has status and WR Type */
+} __attribute__((packed)) ;
+
+enum c2_qp_state {
+	C2_QP_STATE_IDLE = 0x01,
+	C2_QP_STATE_CONNECTING = 0x02,
+	C2_QP_STATE_RTS = 0x04,
+	C2_QP_STATE_CLOSING = 0x08,
+	C2_QP_STATE_TERMINATE = 0x10,
+	C2_QP_STATE_ERROR = 0x20,
+};
+
+/* Completion queue entry. */
+struct c2wr_ce {
+	struct c2wr_hdr hdr;		/* Has status and WR Type */
+	u64 qp_user_context;	/* c2_user_qp_t * */
+	u32 qp_state;		/* Current QP State */
+	u32 handle;		/* QPID or EP Handle */
+	u32 bytes_rcvd;		/* valid for RECV WCs */
+	u32 stag;
+} __attribute__((packed)) ;
+
+
+/*
+ * Flags used for all post-sq WRs.  These must fit in the flags
+ * field of the struct c2wr_hdr (eight bits).
+ */
+enum {
+	SQ_SIGNALED = 0x01,
+	SQ_READ_FENCE = 0x02,
+	SQ_FENCE = 0x04,
+};
+
+/*
+ * Common fields for all post-sq WRs.  Namely the standard header and a 
+ * secondary header with fields common to all post-sq WRs.
+ */
+struct c2_sq_hdr {
+	struct c2wr_user_hdr user_hdr;
+} __attribute__((packed));
+
+/*
+ * Same as above but for post-rq WRs.
+ */
+struct c2_rq_hdr {
+	struct c2wr_user_hdr user_hdr;
+} __attribute__((packed));
+
+/*
+ * use the same struct for all sends.
+ */
+struct c2wr_send_req {
+	struct c2_sq_hdr sq_hdr;
+	u32 sge_len;
+	u32 remote_stag;
+	u8 data[0];		/* SGE array */
+} __attribute__((packed));
+/* XXX c2wr_send_req_t, c2wr_send_se_req_t, c2wr_send_inv_req_t,
+   c2wr_send_se_inv_req_t;*/
+
+union c2wr_send {
+	struct c2wr_send_req req;
+	struct c2wr_ce rep;
+} __attribute__((packed));
+
+struct c2wr_rdma_write_req {
+	struct c2_sq_hdr sq_hdr;
+	u64 remote_to;
+	u32 remote_stag;
+	u32 sge_len;
+	u8 data[0];		/* SGE array */
+} __attribute__((packed));
+
+union c2wr_rdma_write {
+	struct c2wr_rdma_write_req req;
+	struct c2wr_ce rep;
+} __attribute__((packed));
+
+struct c2wr_rdma_read_req {
+	struct c2_sq_hdr sq_hdr;
+	u64 local_to;
+	u64 remote_to;
+	u32 local_stag;
+	u32 remote_stag;
+	u32 length;
+} __attribute__((packed));
+
+union c2wr_rdma_read {
+	struct c2wr_rdma_read_req req;
+	struct c2wr_ce rep;
+} __attribute__((packed));
+
+struct c2wr_mw_bind_req {
+	struct c2_sq_hdr sq_hdr;
+	u64 va;
+	u8 stag_key;
+	u8 pad[3];
+	u32 mw_stag_index;
+	u32 mr_stag_index;
+	u32 length;
+	u32 flags;
+} __attribute__((packed));
+
+union c2wr_mw_bind {
+	struct c2wr_mw_bind_req req;
+	struct c2wr_ce rep;
+} __attribute__((packed));
+
+struct c2wr_nsmr_fastreg_req {
+	struct c2_sq_hdr sq_hdr;
+	u64 va;
+	u8 stag_key;
+	u8 pad[3];
+	u32 stag_index;
+	u32 pbe_size;
+	u32 fbo;
+	u32 length;
+	u32 addrs_length;
+	/* array of paddrs (must be aligned on a 64bit boundary) */
+	u64 paddrs[0];
+} __attribute__((packed));
+
+union c2wr_nsmr_fastreg {
+	struct c2wr_nsmr_fastreg_req req;
+	struct c2wr_ce rep;
+} __attribute__((packed));
+
+struct c2wr_stag_invalidate_req {
+	struct c2_sq_hdr sq_hdr;
+	u8 stag_key;
+	u8 pad[3];
+	u32 stag_index;
+} __attribute__((packed));
+
+union c2wr_stag_invalidate {
+	struct c2wr_stag_invalidate_req req;
+	struct c2wr_ce rep;
+} __attribute__((packed));
+
+union c2wr_sqwr {
+	struct c2_sq_hdr sq_hdr;
+	struct c2wr_send_req send;
+	struct c2wr_send_req send_se;
+	struct c2wr_send_req send_inv;
+	struct c2wr_send_req send_se_inv;
+	struct c2wr_rdma_write_req rdma_write;
+	struct c2wr_rdma_read_req rdma_read;
+	struct c2wr_mw_bind_req mw_bind;
+	struct c2wr_nsmr_fastreg_req nsmr_fastreg;
+	struct c2wr_stag_invalidate_req stag_inv;
+} __attribute__((packed));
+
+
+/*
+ * RQ WRs
+ */
+struct c2wr_rqwr {
+	struct c2_rq_hdr rq_hdr;
+	u8 data[0];		/* array of SGEs */
+} __attribute__((packed));
+/* XXX  c2wr_rqwr_t, c2wr_recv_req_t; */
+
+union c2wr_recv {
+	struct c2wr_rqwr req;
+	struct c2wr_ce rep;
+} __attribute__((packed));
+
+/*
+ * All AEs start with this header.  Most AEs only need to convey the
+ * information in the header.  Some, like LLP connection events, need
+ * more info.  The union typdef c2wr_ae_t has all the possible AEs.
+ *
+ * hdr.context is the user_context from the rnic_open WR.  NULL If this 
+ * is not affiliated with an rnic
+ *
+ * hdr.id is the AE identifier (eg;  CCAE_REMOTE_SHUTDOWN, 
+ * CCAE_LLP_CLOSE_COMPLETE)
+ *
+ * resource_type is one of:  C2_RES_IND_QP, C2_RES_IND_CQ, C2_RES_IND_SRQ
+ *
+ * user_context is the context passed down when the host created the resource.
+ */
+struct c2wr_ae_hdr {
+	struct c2wr_hdr hdr;
+	u64 user_context;	/* user context for this res. */
+	u32 resource_type;	/* see enum c2_resource_indicator */
+	u32 resource;		/* handle for resource */
+	u32 qp_state;		/* current QP State */
+} __attribute__((packed));
+
+/*
+ * After submitting the CCAE_ACTIVE_CONNECT_RESULTS message on the AEQ, 
+ * the adapter moves the QP into RTS state
+ */
+struct c2wr_ae_active_connect_results {
+	struct c2wr_ae_hdr ae_hdr;
+	u32 laddr;
+	u32 raddr;
+	u16 lport;
+	u16 rport;
+	u32 private_data_length;
+	u8 private_data[0];	/* data is in-line in the msg. */
+} __attribute__((packed));
+
+/*
+ * When connections are established by the stack (and the private data
+ * MPA frame is received), the adapter will generate an event to the host.
+ * The details of the connection, any private data, and the new connection
+ * request handle is passed up via the CCAE_CONNECTION_REQUEST msg on the
+ * AE queue:
+ */
+struct c2wr_ae_connection_request {
+	struct c2wr_ae_hdr ae_hdr;
+	u32 cr_handle;		/* connreq handle (sock ptr) */
+	u32 laddr;
+	u32 raddr;
+	u16 lport;
+	u16 rport;
+	u32 private_data_length;
+	u8 private_data[0];	/* data is in-line in the msg. */
+} __attribute__((packed));
+
+union c2wr_ae {
+	struct c2wr_ae_hdr ae_generic;
+	struct c2wr_ae_active_connect_results ae_active_connect_results;
+	struct c2wr_ae_connection_request ae_connection_request;
+} __attribute__((packed));
+
+struct c2wr_init_req {
+	struct c2wr_hdr hdr;
+	u64 hint_count;
+	u64 q0_host_shared;
+	u64 q1_host_shared;
+	u64 q1_host_msg_pool;
+	u64 q2_host_shared;
+	u64 q2_host_msg_pool;
+} __attribute__((packed));
+
+struct c2wr_init_rep {
+	struct c2wr_hdr hdr;
+} __attribute__((packed));
+
+union c2wr_init {
+	struct c2wr_init_req req;
+	struct c2wr_init_rep rep;
+} __attribute__((packed));
+
+/*
+ * For upgrading flash.
+ */
+
+struct c2wr_flash_init_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+} __attribute__((packed));
+
+struct c2wr_flash_init_rep {
+	struct c2wr_hdr hdr;
+	u32 adapter_flash_buf_offset;
+	u32 adapter_flash_len;
+} __attribute__((packed));
+
+union c2wr_flash_init {
+	struct c2wr_flash_init_req req;
+	struct c2wr_flash_init_rep rep;
+} __attribute__((packed));
+
+struct c2wr_flash_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 len;
+} __attribute__((packed));
+
+struct c2wr_flash_rep {
+	struct c2wr_hdr hdr;
+	u32 status;
+} __attribute__((packed));
+
+union c2wr_flash {
+	struct c2wr_flash_req req;
+	struct c2wr_flash_rep rep;
+} __attribute__((packed));
+
+struct c2wr_buf_alloc_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 size;
+} __attribute__((packed));
+
+struct c2wr_buf_alloc_rep {
+	struct c2wr_hdr hdr;
+	u32 offset;		/* 0 if mem not available */
+	u32 size;		/* 0 if mem not available */
+} __attribute__((packed));
+
+union c2wr_buf_alloc {
+	struct c2wr_buf_alloc_req req;
+	struct c2wr_buf_alloc_rep rep;
+} __attribute__((packed));
+
+struct c2wr_buf_free_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 offset;		/* Must match value from alloc */
+	u32 size;		/* Must match value from alloc */
+} __attribute__((packed));
+
+struct c2wr_buf_free_rep {
+	struct c2wr_hdr hdr;
+} __attribute__((packed));
+
+union c2wr_buf_free {
+	struct c2wr_buf_free_req req;
+	struct c2wr_ce rep;
+} __attribute__((packed));
+
+struct c2wr_flash_write_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 offset;
+	u32 size;
+	u32 type;
+	u32 flags;
+} __attribute__((packed));
+
+struct c2wr_flash_write_rep {
+	struct c2wr_hdr hdr;
+	u32 status;
+} __attribute__((packed));
+
+union c2wr_flash_write {
+	struct c2wr_flash_write_req req;
+	struct c2wr_flash_write_rep rep;
+} __attribute__((packed));
+
+/*
+ * Messages for LLP connection setup. 
+ */
+
+/*
+ * Listen Request.  This allocates a listening endpoint to allow passive
+ * connection setup.  Newly established LLP connections are passed up
+ * via an AE.  See c2wr_ae_connection_request_t
+ */
+struct c2wr_ep_listen_create_req {
+	struct c2wr_hdr hdr;
+	u64 user_context;	/* returned in AEs. */
+	u32 rnic_handle;
+	u32 local_addr;		/* local addr, or 0  */
+	u16 local_port;		/* 0 means "pick one" */
+	u16 pad;
+	u32 backlog;		/* tradional tcp listen bl */
+} __attribute__((packed));
+
+struct c2wr_ep_listen_create_rep {
+	struct c2wr_hdr hdr;
+	u32 ep_handle;		/* handle to new listening ep */
+	u16 local_port;		/* resulting port... */
+	u16 pad;
+} __attribute__((packed));
+
+union c2wr_ep_listen_create {
+	struct c2wr_ep_listen_create_req req;
+	struct c2wr_ep_listen_create_rep rep;
+} __attribute__((packed));
+
+struct c2wr_ep_listen_destroy_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 ep_handle;
+} __attribute__((packed));
+
+struct c2wr_ep_listen_destroy_rep {
+	struct c2wr_hdr hdr;
+} __attribute__((packed));
+
+union c2wr_ep_listen_destroy {
+	struct c2wr_ep_listen_destroy_req req;
+	struct c2wr_ep_listen_destroy_rep rep;
+} __attribute__((packed));
+
+struct c2wr_ep_query_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 ep_handle;
+} __attribute__((packed));
+
+struct c2wr_ep_query_rep {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 local_addr;
+	u32 remote_addr;
+	u16 local_port;
+	u16 remote_port;
+} __attribute__((packed));
+
+union c2wr_ep_query {
+	struct c2wr_ep_query_req req;
+	struct c2wr_ep_query_rep rep;
+} __attribute__((packed));
+
+
+/*
+ * The host passes this down to indicate acceptance of a pending iWARP
+ * connection.  The cr_handle was obtained from the CONNECTION_REQUEST
+ * AE passed up by the adapter.  See c2wr_ae_connection_request_t.
+ */
+struct c2wr_cr_accept_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 qp_handle;		/* QP to bind to this LLP conn */
+	u32 ep_handle;		/* LLP  handle to accept */
+	u32 private_data_length;
+	u8 private_data[0];	/* data in-line in msg. */
+} __attribute__((packed));
+
+/*
+ * adapter sends reply when private data is successfully submitted to 
+ * the LLP.
+ */
+struct c2wr_cr_accept_rep {
+	struct c2wr_hdr hdr;
+} __attribute__((packed));
+
+union c2wr_cr_accept {
+	struct c2wr_cr_accept_req req;
+	struct c2wr_cr_accept_rep rep;
+} __attribute__((packed));
+
+/*
+ * The host sends this down if a given iWARP connection request was 
+ * rejected by the consumer.  The cr_handle was obtained from a 
+ * previous c2wr_ae_connection_request_t AE sent by the adapter.
+ */
+struct  c2wr_cr_reject_req {
+	struct c2wr_hdr hdr;
+	u32 rnic_handle;
+	u32 ep_handle;		/* LLP handle to reject */
+} __attribute__((packed));
+
+/*
+ * Dunno if this is needed, but we'll add it for now.  The adapter will
+ * send the reject_reply after the LLP endpoint has been destroyed.
+ */
+struct  c2wr_cr_reject_rep {
+	struct c2wr_hdr hdr;
+} __attribute__((packed));
+
+union c2wr_cr_reject {
+	struct c2wr_cr_reject_req req;
+	struct c2wr_cr_reject_rep rep;
+} __attribute__((packed));
+
+/*
+ * console command.  Used to implement a debug console over the verbs
+ * request and reply queues.  
+ */
+
+/*
+ * Console request message.  It contains:
+ *	- message hdr with id = CCWR_CONSOLE
+ *	- the physaddr/len of host memory to be used for the reply. 
+ *	- the command string.  eg:  "netstat -s" or "zoneinfo"
+ */
+struct c2wr_console_req {
+	struct c2wr_hdr hdr;		/* id = CCWR_CONSOLE */
+	u64 reply_buf;		/* pinned host buf for reply */
+	u32 reply_buf_len;	/* length of reply buffer */
+	u8 command[0];		/* NUL terminated ascii string */
+	/* containing the command req */
+} __attribute__((packed));
+
+/*
+ * flags used in the console reply.
+ */
+enum c2_console_flags {
+	CONS_REPLY_TRUNCATED = 0x00000001	/* reply was truncated */
+} __attribute__((packed));
+
+/*
+ * Console reply message.  
+ * hdr.result contains the c2_status_t error if the reply was _not_ generated, 
+ * or C2_OK if the reply was generated.
+ */
+struct c2wr_console_rep {
+	struct c2wr_hdr hdr;		/* id = CCWR_CONSOLE */
+	u32 flags;
+} __attribute__((packed));
+
+union c2wr_console {
+	struct c2wr_console_req req;
+	struct c2wr_console_rep rep;
+} __attribute__((packed));
+
+
+/*
+ * Giant union with all WRs.  Makes life easier...
+ */
+union c2wr {
+	struct c2wr_hdr hdr;
+	struct c2wr_user_hdr user_hdr;
+	union c2wr_rnic_open rnic_open;
+	union c2wr_rnic_query rnic_query;
+	union c2wr_rnic_getconfig rnic_getconfig;
+	union c2wr_rnic_setconfig rnic_setconfig;
+	union c2wr_rnic_close rnic_close;
+	union c2wr_cq_create cq_create;
+	union c2wr_cq_modify cq_modify;
+	union c2wr_cq_destroy cq_destroy;
+	union c2wr_pd_alloc pd_alloc;
+	union c2wr_pd_dealloc pd_dealloc;
+	union c2wr_srq_create srq_create;
+	union c2wr_srq_destroy srq_destroy;
+	union c2wr_qp_create qp_create;
+	union c2wr_qp_query qp_query;
+	union c2wr_qp_modify qp_modify;
+	union c2wr_qp_destroy qp_destroy;
+	struct c2wr_qp_connect qp_connect;
+	union c2wr_nsmr_stag_alloc nsmr_stag_alloc;
+	union c2wr_nsmr_register nsmr_register;
+	union c2wr_nsmr_pbl nsmr_pbl;
+	union c2wr_mr_query mr_query;
+	union c2wr_mw_query mw_query;
+	union c2wr_stag_dealloc stag_dealloc;
+	union c2wr_sqwr sqwr;
+	struct c2wr_rqwr rqwr;
+	struct c2wr_ce ce;
+	union c2wr_ae ae;
+	union c2wr_init init;
+	union c2wr_ep_listen_create ep_listen_create;
+	union c2wr_ep_listen_destroy ep_listen_destroy;
+	union c2wr_cr_accept cr_accept;
+	union c2wr_cr_reject cr_reject;
+	union c2wr_console console;
+	union c2wr_flash_init flash_init;
+	union c2wr_flash flash;
+	union c2wr_buf_alloc buf_alloc;
+	union c2wr_buf_free buf_free;
+	union c2wr_flash_write flash_write;
+} __attribute__((packed));
+
+
+/*
+ * Accessors for the wr fields that are packed together tightly to
+ * reduce the wr message size.  The wr arguments are void* so that
+ * either a struct c2wr*, a struct c2wr_hdr*, or a pointer to any of the types
+ * in the struct c2wr union can be passed in.
+ */
+static __inline__ u8 c2_wr_get_id(void *wr)
+{
+	return ((struct c2wr_hdr *) wr)->id;
+}
+static __inline__ void c2_wr_set_id(void *wr, u8 id)
+{
+	((struct c2wr_hdr *) wr)->id = id;
+}
+static __inline__ u8 c2_wr_get_result(void *wr)
+{
+	return ((struct c2wr_hdr *) wr)->result;
+}
+static __inline__ void c2_wr_set_result(void *wr, u8 result)
+{
+	((struct c2wr_hdr *) wr)->result = result;
+}
+static __inline__ u8 c2_wr_get_flags(void *wr)
+{
+	return ((struct c2wr_hdr *) wr)->flags;
+}
+static __inline__ void c2_wr_set_flags(void *wr, u8 flags)
+{
+	((struct c2wr_hdr *) wr)->flags = flags;
+}
+static __inline__ u8 c2_wr_get_sge_count(void *wr)
+{
+	return ((struct c2wr_hdr *) wr)->sge_count;
+}
+static __inline__ void c2_wr_set_sge_count(void *wr, u8 sge_count)
+{
+	((struct c2wr_hdr *) wr)->sge_count = sge_count;
+}
+static __inline__ u32 c2_wr_get_wqe_count(void *wr)
+{
+	return ((struct c2wr_hdr *) wr)->wqe_count;
+}
+static __inline__ void c2_wr_set_wqe_count(void *wr, u32 wqe_count)
+{
+	((struct c2wr_hdr *) wr)->wqe_count = wqe_count;
+}
+
+#endif				/* _C2_WR_H_ */

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox