This patch applies to kernel 2.6.15. The aoe6-21 driver from the Coraid website should be used in place of 2.6.15's aoe driver. Although changes in aoe6-21 have been submitted to the Linux Kernel Mailing List, they are not in 2.6.15. Todo: * add support for booting from a partition Changes: 20060130 "Ed L. Cashin" Support a kernel parameter to override default shelf and slot. diff -uprN a/drivers/block/Kconfig b/drivers/block/Kconfig --- a/drivers/block/Kconfig 2006-01-25 11:39:15.000000000 -0500 +++ b/drivers/block/Kconfig 2006-01-25 11:39:15.000000000 -0500 @@ -452,4 +452,19 @@ config ATA_OVER_ETH This driver provides Support for ATA over Ethernet block devices like the Coraid EtherDrive (R) Storage Blade. +config ATA_OVER_ETH_ROOT + bool "ATA over Ethernet root device" + depends on ATA_OVER_ETH=y + help + If you want to use ATA Over Ethernet as the root device, + set this to 'y' + +config ATA_OVER_ETH_ROOT_SHELF + int "Shelf ID" + depends on ATA_OVER_ETH_ROOT + +config ATA_OVER_ETH_ROOT_SLOT + int "Slot ID" + depends on ATA_OVER_ETH_ROOT + endmenu diff -uprN a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h --- a/drivers/block/aoe/aoe.h 2006-01-25 11:39:15.000000000 -0500 +++ b/drivers/block/aoe/aoe.h 2006-01-25 11:39:15.000000000 -0500 @@ -159,6 +159,7 @@ void aoecmd_cfg_rsp(struct sk_buff *); int aoedev_init(void); void aoedev_exit(void); struct aoedev *aoedev_by_aoeaddr(int maj, int min); +struct aoedev *aoedev_bymajor_minor(ulong major, ulong minor); void aoedev_downdev(struct aoedev *d); struct aoedev *aoedev_set(ulong, unsigned char *, struct net_device *, ulong); int aoedev_busy(void); diff -uprN a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c --- a/drivers/block/aoe/aoeblk.c 2006-01-25 11:39:15.000000000 -0500 +++ b/drivers/block/aoe/aoeblk.c 2006-01-25 11:39:15.000000000 -0500 @@ -244,6 +244,7 @@ aoeblk_gdalloc(void *vp) gd->capacity = d->ssize; snprintf(gd->disk_name, sizeof gd->disk_name, "etherd/e%ld.%ld", d->aoemajor, d->aoeminor); + strncpy(gd->devfs_name, gd->disk_name, sizeof gd->devfs_name); gd->queue = &d->blkq; d->gd = gd; diff -uprN a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c --- a/drivers/block/aoe/aoedev.c 2006-01-25 11:39:15.000000000 -0500 +++ b/drivers/block/aoe/aoedev.c 2006-01-25 11:39:15.000000000 -0500 @@ -28,6 +28,22 @@ aoedev_by_aoeaddr(int maj, int min) return d; } +struct aoedev *aoedev_bymajor_minor(ulong major, ulong minor) +{ + struct aoedev *d; + ulong flags; + + spin_lock_irqsave(&devlist_lock, flags); + + for (d = devlist; d; d = d->next) + if (d->aoemajor == major && d->aoeminor == minor) + break; + + spin_unlock_irqrestore(&devlist_lock, flags); + return d; +} + + /* called with devlist lock held */ static struct aoedev * aoedev_newdev(ulong nframes) diff -uprN a/drivers/block/aoe/aoemain.c b/drivers/block/aoe/aoemain.c --- a/drivers/block/aoe/aoemain.c 2006-01-25 11:39:15.000000000 -0500 +++ b/drivers/block/aoe/aoemain.c 2006-01-26 11:27:45.000000000 -0500 @@ -7,6 +7,15 @@ #include #include #include +#include + +/* AOE Root device includes */ +#include +#include +#include +#include +#include + #include "aoe.h" MODULE_LICENSE("GPL"); @@ -53,6 +62,60 @@ discover_timer(ulong vp) } } +#ifdef CONFIG_ATA_OVER_ETH_ROOT +static char aoe_rootdev[16]; +module_param_string(aoe_rootdev, aoe_rootdev, sizeof aoe_rootdev, 0600); +MODULE_PARM_DESC(aoe_iflist, "aoe_rootdev=\"e0.0\"\n"); + +void aoe_root(unsigned long major, unsigned long minor) +{ + struct net_device *dev; + + if (aoe_rootdev[0] != '\0') { + unsigned maj; + unsigned min; + int n = sscanf(aoe_rootdev, "e%u.%u", &maj, &min); + + if (n != 2) + printk(KERN_INFO + "%s:\"%s\" using default: e%lu.%lu\n", + "aoe: invalid aoe_rootdev parameter", + aoe_rootdev, major, minor); + else { + major = maj; + minor = min; + } + } + + printk(KERN_INFO + "aoe: Waiting for root AOE device e%ld.%ld\n", major, minor); + + /* Give hardware a chance to settle */ + msleep(500); + + rtnl_shlock(); + /* bring loopback device up first */ + if (dev_change_flags(&loopback_dev, loopback_dev.flags | IFF_UP) < 0) + printk(KERN_ERR "AOE Root: Failed to open %s\n", loopback_dev.name); + + /* Setup all network devices */ + for (dev = dev_base; dev ; dev = dev->next) { + if (dev == &loopback_dev) + continue; + dev_change_flags(dev, dev->flags | IFF_UP); + } + rtnl_shunlock(); + + /* Give drivers a chance to settle */ + ssleep(1); + + do { + aoecmd_cfg(major, minor); + msleep(1); + } while (!aoedev_bymajor_minor(major, minor)); +} +#endif + static void aoe_exit(void) { @@ -63,6 +126,7 @@ aoe_exit(void) aoechr_exit(); aoedev_exit(); aoeblk_exit(); /* free cache after de-allocating bufs */ + devfs_remove("etherd"); } static int __init @@ -70,6 +134,8 @@ aoe_init(void) { int ret; + devfs_mk_dir("etherd"); + ret = aoedev_init(); if (ret) return ret; @@ -91,6 +157,9 @@ aoe_init(void) printk(KERN_INFO "aoe: aoe_init: AoE v2.6-%s initialised.\n", VERSION); +#ifdef CONFIG_ATA_OVER_ETH_ROOT + aoe_root(CONFIG_ATA_OVER_ETH_ROOT_SHELF,CONFIG_ATA_OVER_ETH_ROOT_SLOT); +#endif discover_timer(TINIT); return 0; @@ -102,6 +171,7 @@ aoe_init(void) aoechr_exit(); chr_fail: aoedev_exit(); + devfs_remove("etherd"); printk(KERN_INFO "aoe: aoe_init: initialisation failure.\n"); return ret;