--- src/etc/defaults/rc.conf.orig Mon Sep 27 13:46:00 2004 +++ src/etc/defaults/rc.conf Fri Sep 30 15:05:43 2005 @@ -384,6 +384,11 @@ kern_securelevel="-1" # range: -1..3 ; ` update_motd="YES" # update version info in /etc/motd (or NO) start_vinum="NO" # set to YES to start vinum unaligned_print="YES" # print unaligned access warnings on the alpha (or NO). +aoe_enable="NO" # ATA over Ethernet +aoe_iflist="" # space separated list of valid AoE interfaces +aoe_wc="1" # write cache enable for AoE ATA devices +aoe_vinum_drives="" # space separated list of AoE vinum drives (full path; must set start_vinum to YES) +aoe_mounts="" # space separated list of AoE based mounts in /etc/fstab (must be noauto, no boot-fsck) ############################################################## ### Define source_rc_confs, the mechanism used by /etc/rc.* ## --- src/etc/MAKEDEV.orig Thu Jan 13 21:07:40 2005 +++ src/etc/MAKEDEV Fri Sep 30 15:15:42 2005 @@ -460,11 +460,12 @@ wt*) ;; # Individual slices. -aacd*s*|ad*s*|ar*s*|afd*s*|amrd*s*|da*s*|fla*s*|idad*s*|ipsd*s*|md*s*|mlxd*s*|pst*s*|twed*s*|vn*s*|wd*s*|wfd*s*) +aacd*s*|ad*s*|aoed*s*|ar*s*|afd*s*|amrd*s*|da*s*|fla*s*|idad*s*|ipsd*s*|md*s*|mlxd*s*|pst*s*|twed*s*|vn*s*|wd*s*|wfd*s*) umask $disk_umask case $i in aacd*s*) name=aacd; chr=151;; ad*s*) name=ad; chr=116;; + aoed*s*) name=aoed; chr=187;; ar*s*) name=ar; chr=157;; afd*s*) name=afd; chr=118;; amrd*s*) name=amrd; chr=133;; @@ -481,7 +482,7 @@ aacd*s*|ad*s*|ar*s*|afd*s*|amrd*s*|da*s* wfd*s*) name=wfd; chr=87;; esac case $i in - aacd*s*|amrd*s*|idad*s*|ips*s*|mlxd*s*|twed*s*) + aacd*s*|amrd*s*|aoed*s*|idad*s*|ips*s*|mlxd*s*|twed*s*) unit=`expr $i : '....\([0-9]*\)s'` slice=`expr $i : '....[0-9]*s\([0-9]*\)'` part=`expr $i : '....[0-9]*s[0-9]*\(.*\)'` @@ -646,11 +647,12 @@ fd*) umask 77 ;; -aacd*|ad*|ar*|afd*|amrd*|da*|fla*|idad*|ips*|md*|mlxd*|pst*|twed*|vn*|wd*|wfd*) +aacd*|ad*|aoed*|ar*|afd*|amrd*|da*|fla*|idad*|ips*|md*|mlxd*|pst*|twed*|vn*|wd*|wfd*) umask $disk_umask case $i in aacd*) name=aacd; chr=151;; ad*) name=ad; chr=116;; + aoed*) name=aoed; chr=187;; ar*) name=ar; chr=157;; afd*) name=afd; chr=118;; amrd*) name=amrd; chr=133;; @@ -667,7 +669,7 @@ aacd*|ad*|ar*|afd*|amrd*|da*|fla*|idad*| wfd*) name=wfd; chr=87;; esac case $i in - aacd*|amrd*|idad*|ipsd*|mlxd*|twed*) + aacd*|amrd*|aoed*|idad*|ipsd*|mlxd*|twed*) unit=`expr $i : '....\(.*\)'` ;; afd*|fla*|pst*|wfd*) --- src/etc/rc.orig Thu Jan 13 16:09:17 2005 +++ src/etc/rc Fri Sep 30 15:05:43 2005 @@ -661,6 +661,35 @@ esac echo '.' +# Discover the AoE devices on requested interfaces and tell vinum +# about the disks requested +if [ -n "${aoe_iflist}" ]; then + sysctl net.aoe > /dev/null 2>&1 + if [ $? -eq 1 ]; then + kldload aoe > /dev/null 2>&1 + fi + if [ $? -eq 0 ]; then + sysctl net.aoe.iflist="${aoe_iflist}" + sysctl net.aoe.wc="${aoe_wc}" + sysctl net.aoe.discover=1 + sleep 1 + + case ${start_vinum} in + [Yy][Ee][Ss]) + if [ -n "${aoe_vinum_drives}" ]; then + vinum read "${aoe_vinum_drives}" + fi + ;; + esac + + for i in "${aoe_mounts}"; do + mount $i + done + else + echo 1>&2 Failure initializing AoE + fi +fi + # Do traditional (but rather obsolete) rc.local file if it exists. If you # use this file and want to make it programmatic, source /etc/defaults/rc.conf # in /etc/rc.local and add your custom variables to /etc/rc.conf, as --- src/share/man/man4/Makefile.orig Thu Jan 13 21:07:40 2005 +++ src/share/man/man4/Makefile Fri Sep 30 15:05:43 2005 @@ -12,6 +12,7 @@ MAN= aac.4 \ amd.4 \ amr.4 \ an.4 \ + aoe.4 \ ata.4 \ atapicam.4 \ atkbd.4 \ --- src/share/man/man4/aoe.4.orig Fri Sep 30 15:05:43 2005 +++ src/share/man/man4/aoe.4 Fri Sep 30 15:05:43 2005 @@ -0,0 +1,158 @@ +.\" +.\" Copyright (c) 2004 Sam Hopkins +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer, +.\" without modification, immediately at the beginning of the file. +.\" 2. 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. +.\" 3. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $FreeBSD: src/share/man/man4/aoe.4,v 1.46 2004/10/21 17:42:48 mpp Exp $ +.\" +.Dd October 31, 2004 +.Dt aoe 4 +.Os +.Sh NAME +.Nm aoe , +.Nm aoed +.Nd ATA over Ethernet (AoE) device driver +.Sh SYNOPSIS +For AoE device support: +.Pp +.Cd device aoe +.Pp +.Sh DESCRIPTION +The +.Nm +driver enables access to AoE devices on a network by making them appear as locally-attached disks. +.Pp +The only AoE device currently available is the Coraid EtherDrive storage blade. +.Pp +AoE works by packaging the ATA registers -- and data if necessary -- into Ethernet request/response frames. +Currently, the driver is only for ethernet networks using a maximum frame size of 1520 (no jumbo frames yet). +As such, the maximum size of a single I/O operation is 1K. +The AoE driver accepts strategy requests much larger than 1K by chopping the buffer into a series of appropriately sized "buflet" requests. +When all portions of an I/O operation are complete the entire buffer is acknowledged as finished. +.Pp +The +.Nm +driver has a mechanism for retransmitting frames which do not receive a response. +Each +.Nm +kernel device maintains a round-trip average of the time between when a request is sent and its response is received. +Whenever a request has been outstanding for 150% of this average, it is retransmitted and the average is backed off by a multiple of two. +The average is limited to between 200ms and 2s. +.Pp +When a request has been outstanding for +.Cd maxwait +time, the device is considered gone and is flagged as down. +If the device is not currently open, it is immediately removed from the system. +If the device is open, it will be removed on final close. +A device cannot come back up until it is removed from the system and a new discover sequence has been done. +.Cd Maxwait +defaults to 180s and is settable by a sysctl. +.Pp +The +.Nm +driver must be told what ethernet interfaces are acceptable for AoE traffic. +This is accomplished by setting a sysctl string that contains a space separated list of interface names. +.Pp +Once the list of valid interfaces is set, the +.Nm +driver must be told to probe the network for AoE devices. +This is accomplished by setting the sysctl integer +.Cd discover . +.Sh SYSCTL VARIABLES +The following are available as +.Xr sysctl 8 +variables: +.Bl -tag -width 12 +.It net.aoe.iflist +.Pp +A read-write string containing a space separated list of network interface names valid for AoE. +.It net.aoe.discover +.Pp +An integer that when set triggers a discovery beacon to be sent to all valid AoE interfaces specified in +.Cd iflist . +The value of +.Cd discover +is always 0 and may be "set" to any value. The setting only triggers the discover action. +.It net.aoe.maxwait +.Pp +An integer that specifies the number of seconds to wait for an outstanding AoE request to be completed before failing a device. +.It net.aoe.wc +.Pp +An integer that specifies whether or not the ATA disks attached to all AoE devices should have the write cache enabled. +Transitions in the state of this variable will cause all AoE devices to be flagged for enable/disable of the write cache on the next I/O operation. +The write cache is not affected immediately for driver simplicity. +To force the write cache action, do at least one read from each device after setting/clearing this variable. +The write cache is enabled by default. +.It net.aoe.devices +.Pp +A read-only string containing the devices the +.Nm +driver knows about, one per line. +.El +.Sh EXAMPLES +.Bd -literal +% kldload aoe +% sysctl net.aoe +net.aoe.iflist: +net.aoe.discover: 0 +net.aoe.maxwait: 180 +net.aoe.wc: 1 +net.aoe.devices: +% sysctl net.aoe.iflist=xl0 +net.aoe.iflist: -> xl0 +% sysctl net.aoe.discover=1 +net.aoe.discover: 0 -> 0 +% sysctl net.aoe +net.aoe.iflist: xl0 +net.aoe.discover: 0 +net.aoe.maxwait: 180 +net.aoe.wc: 1 +net.aoe.devices: +aoed10 xl0 UP +aoed3 xl0 UP +aoed30 xl0 UP +.Ed +.Sh NOTES +Each +.Nm +device node created in a system is comprised of aoed + system unit number. +The unit numbers used by +.Nm +are created by the relation: +.Pp +.Cd unit = aoemajor * 10 + aoeminor +.Pp +This simple relation makes it very easy for administrators to associate blades in a shelf with nodes in the system. +In the example above, there are three blades; one each in shelf 1 / slot 0, shelf 0 / slot 3, and shelf 3 / slot 0. +.Pp +When an AoE device is powered up it broadcasts a message so hosts may automatically acknowledge its existence. +.Sh FILES +.Bl -tag -width ".Pa /sys/i386/conf/GENERIC" -compact +.It Pa /dev/aoed* +AoE disk device nodes +.El +.Sh AUTHORS +.An Sam Hopkins +.Aq sah@coraid.com . --- src/sys/conf/files.orig Thu Jan 13 21:07:39 2005 +++ src/sys/conf/files Fri Sep 30 15:05:43 2005 @@ -285,6 +285,12 @@ dev/an/if_an_pccard.c optional an card dev/ar/if_ar.c optional ar dev/ar/if_ar_pci.c optional ar pci dev/asr/asr.c optional asr pci +dev/aoe/aoe.c optional aoe +dev/aoe/aoedev.c optional aoe +dev/aoe/aoecmd.c optional aoe +dev/aoe/aoenet.c optional aoe +dev/aoe/aoeblk.c optional aoe +dev/aoe/aoeutils.c optional aoe dev/ata/ata-all.c optional ata dev/ata/ata-isa.c optional ata isa dev/ata/ata-card.c optional ata card --- src/sys/conf/options.orig Mon Apr 19 01:02:17 2004 +++ src/sys/conf/options Fri Sep 30 15:05:43 2005 @@ -253,6 +253,9 @@ ISP_TARGET_MODE opt_isp.h # Options used in the 'ata' ATA/ATAPI driver ATA_STATIC_ID opt_ata.h +# AoE +AOE_HOOK opt_aoe.h + # Net stuff. ACCEPT_FILTER_DATA ACCEPT_FILTER_HTTP --- src/sys/dev/vinum/vinumio.c.orig Mon Apr 26 15:32:59 2004 +++ src/sys/dev/vinum/vinumio.c Fri Sep 30 15:05:43 2005 @@ -96,6 +96,9 @@ open_drive(struct drive *drive, struct p } else if (bcmp(dname, "twed", 4) == 0) { /* 3ware raid */ devmajor = 147; dname += 2; + } else if (bcmp(dname, "aoed", 4) == 0) { + devmajor = 187; + dname += 2; } else return ENODEV; dname += 2; /* point past */ --- src/sys/dev/aoe/all.h.orig Fri Sep 30 15:05:43 2005 +++ src/sys/dev/aoe/all.h Mon Oct 3 10:17:05 2005 @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2004, Sam Hopkins + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/aoe/all.h,v 1.23.2.5 2004/09/22 16:50:41 ?? Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __i386__ +# include +#endif + +#define nelem(a) (sizeof (a) / sizeof (a)[0]) +#define MINPERMAJ 10 +#define AOEMAJOR(unit) ((unit) / MINPERMAJ) +#define AOEMINOR(unit) ((unit) % MINPERMAJ) +#define AOEUNIT(maj, min) ((maj) * MINPERMAJ + (min)) +#define b_aoe_baddr b_driver1 +#define b_aoe_nbuflets b_driver2 + +enum { + DEVFL_UP = 1, /* device is installed in system and ready for AoE->ATA commands */ + DEVFL_OPEN = (1<<1), + DEVFL_TKILL = (1<<2), /* flag for timer to know when to kill self */ + DEVFL_EXT = (1<<3), /* device accepts lba48 commands */ + DEVFL_CLOSEWAIT = (1<<4), /* device is waiting for all closes to revalidate */ + DEVFL_WC_UPDATE = (1<<5), /* this device needs to update write cache status */ + + MAXATADATA = 1024, /* max permissable data in frame */ + FREETAG = -1, /* tag magic; denotes free frame */ + IFLISTSZ = 128, /* length of the aoe_iflist string */ +}; + +typedef struct Frame Frame; +struct Frame { + int tag; + struct buf *bp; + caddr_t *readdst; + struct mbuf *m; + ulong mlen; + ulong waited; + char data[MCLBYTES /* > sizeof (Aoehdr) + sizeof (Aoeahdr) + MAXATADATA */]; + /* data size needs to be the size of mbuf cluster (2048 bytes) */ +}; + +typedef struct Aoedev Aoedev; +struct Aoedev { + Aoedev *next; + char addr[6]; + ushort unit; + ushort major; + ushort minor; + ushort busy; /* busy flag for aoecmd_work() */ + struct disk disk; + dev_t dev; + struct devstat devstat; + struct ifnet *ifp; + struct callout callout; + struct buf_queue_head bufq; + struct buf *inprocess; + ushort flags; + ushort rttavg; + ushort lasttag; + ushort nframes; + Frame *frames; + char ident[512]; +}; + +dev_t aoeblk_register(ulong, struct disk *); +int aoeblk_init(void); +int aoeblk_exit(void); + +Aoedev *aoedev_set(ulong, char *, struct ifnet *, ulong); +void aoedev_downdev(Aoedev *); +Aoedev *aoedev_byaddr(char *); +Aoedev *aoedev_byunit(ulong); +int aoedev_busy(void); +int aoedev_init(void); +int aoedev_exit(void); +void aoedev_wc_update(void); + +void aoecmd_ata_rw(Aoedev *, Frame *); +/* void aoecmd_ata_id(Aoedev *); */ +void aoecmd_work(Aoedev *d); +void aoecmd_cfg_rsp(struct mbuf *m); +void aoecmd_ata_rsp(struct mbuf *m); +void aoecmd_cfg(ushort, uchar); + +int aoenet_init(void); +int aoenet_exit(void); + +ushort nhgets(uchar *); +ulong nhgetl(uchar *); +void hnputs(uchar *, ushort); +void hnputl(uchar *, ulong); +ushort lhgets(uchar *); +ulong lhgetl(uchar *); +void *mallocz(ulong, struct malloc_type *, int); +int isaoeifc(struct ifnet *); + --- src/sys/dev/aoe/aoe.c.orig Fri Sep 30 15:05:43 2005 +++ src/sys/dev/aoe/aoe.c Mon Oct 3 10:17:05 2005 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2004, Sam Hopkins + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/aoe/aoe.c,v 1.23.2.5 2004/09/22 16:50:41 ?? Exp $ + */ + +#include + +SYSCTL_NODE(_net, OID_AUTO, aoe, CTLFLAG_RW, 0, "AoE Driver controllables"); + +static int +aoe_exit(void) +{ + int (**p)(void); + int (*fns[])(void) = { aoenet_exit, aoedev_exit, aoeblk_exit, 0 }; + + for (p=fns; *p; p++) + (*p)(); + return 0; +} + +static int +aoe_init(void) +{ + int n, (**p)(void); + int (*fns[])(void) = { aoedev_init, aoeblk_init, aoenet_init, 0 }; + + for (p=fns; *p; p++) { + n = (*p)(); + if (n) { + aoe_exit(); + log(LOG_INFO, "aoe: Initialization failure\n"); + return n; + } + } + log(LOG_INFO, "aoe: AoE version %d.%d initialized\n", 1, 1); + return 0; +} + +static int +aoe_loader(struct module *m, int what, void *arg) +{ + switch (what) { + case MOD_LOAD: + return aoe_init(); + case MOD_UNLOAD: + if (aoedev_busy()) { + log(LOG_INFO, "aoe: aoe_loader: can't unload, devices open\n"); + return EBUSY; + } + aoe_exit(); + + tsleep(aoe_loader, 0, "aoeunl", hz<<1); + return 0; + default: + return EINVAL; + } +} + +DEV_MODULE(aoe, aoe_loader, NULL); + --- src/sys/dev/aoe/aoeblk.c.orig Fri Sep 30 15:05:43 2005 +++ src/sys/dev/aoe/aoeblk.c Mon Oct 3 10:45:47 2005 @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2004, Sam Hopkins + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/aoe/aoeblk.c,v 1.23.2.5 2004/09/22 16:50:41 ?? Exp $ + */ + +#include + +static int diskcreate_goo; + +static int +aoeblk_open(dev_t dev, int flags, int fmt, struct proc *p) +{ + Aoedev *d; + int s; + + d = dev->si_drv1; + s = splbio(); + if ((d->flags & DEVFL_UP) == 0) { + log(LOG_INFO, "aoe: aoeblk_open: AoE device %d.%d is not up.\n", + d->major, d->minor); + splx(s); + return EBUSY; + } + d->flags |= DEVFL_OPEN; + splx(s); + return 0; +} + +static int +aoeblk_close(dev_t dev, int flags, int fmt, struct proc *p) +{ + Aoedev *d; + int s; + + d = dev->si_drv1; + s = splbio(); + d->flags &= ~DEVFL_OPEN; + if (d->flags & DEVFL_CLOSEWAIT) { + devstat_remove_entry(&d->devstat); + disk_destroy(d->dev); + d->flags &= ~DEVFL_CLOSEWAIT; + splx(s); + aoecmd_cfg(d->major, d->minor); + return 0; + } + splx(s); + + return 0; +} + + +/* + * (2) Set busy flag so intr handler doesn't bother calling + * aoecmd_work() when it it doesn't need to. + */ +static void +aoeblk_strategy(struct buf *bp) +{ + Aoedev *d; + int s; + + d = bp->b_dev->si_drv1; + s = splbio(); + if ((d->flags & DEVFL_UP) == 0) { + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + splx(s); + biodone(bp); + return; + } + bufqdisksort(&d->bufq, bp); + splx(s); + + d->busy=1; /* (2) */ + aoecmd_work(d); + d->busy=0; +} + +static struct cdevsw aoe_devsw = { + .d_open = aoeblk_open, + .d_close = aoeblk_close, + .d_read = physread, + .d_write = physwrite, + .d_strategy = aoeblk_strategy, + .d_name = "aoed", + .d_maj = 187, + .d_flags = D_DISK, + .d_bmaj = -1 +}; +static struct cdevsw aoedisk_devsw; + +dev_t +aoeblk_register(ulong unit, struct disk *disk) +{ + diskcreate_goo=1; + return disk_create(unit, disk, 0, &aoe_devsw, &aoedisk_devsw); +} + +int +aoeblk_init(void) +{ + return 0; +} + +int +aoeblk_exit(void) +{ + if (diskcreate_goo) + cdevsw_remove(&aoedisk_devsw); + return 0; +} + --- src/sys/dev/aoe/aoecmd.c.orig Fri Sep 30 15:05:43 2005 +++ src/sys/dev/aoe/aoecmd.c Mon Oct 3 12:47:38 2005 @@ -0,0 +1,676 @@ +/* + * Copyright (c) 2004, Sam Hopkins + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/aoe/aoecmd.c,v 1.23.2.5 2004/09/22 16:50:41 ?? Exp $ + */ + +#include + +#define IFPADDR(ifp) (((struct arpcom *) (ifp))->ac_enaddr) +#define TIMERTICK (hz / 10) +#define MINTIMER (TIMERTICK << 1) +#define MAXTIMER (hz << 1) +#define MAXWAIT (60 * 3) /* After MAXWAIT rexmit time, give up and fail device */ + +/* these are 5.x names. We use them for consistency. */ +enum { + ATA_READ = 0x20, + ATA_READ48 = 0x24, + ATA_WRITE = 0x30, + ATA_WRITE48 = 0x34, + ATA_SETFEATURES = 0xef, + ATA_ATA_IDENTIFY = 0xec, + ATA_SF_ENAB_WCACHE = 0x02, + ATA_SF_DIS_WCACHE = 0x82, +}; + +static int aoe_maxwait = MAXWAIT; +static int aoe_wc = 1; +static int sysctl_aoe_wc(SYSCTL_HANDLER_ARGS); +static int sysctl_aoe_discover(SYSCTL_HANDLER_ARGS); +char aoe_iflist[IFLISTSZ]; + +SYSCTL_DECL(_net_aoe); +SYSCTL_STRING(_net_aoe, OID_AUTO, iflist, CTLFLAG_RW, aoe_iflist, + sizeof aoe_iflist - 1, "Comma separated list of interfaces valid for AoE"); +SYSCTL_OID(_net_aoe, OID_AUTO, discover, CTLTYPE_INT|CTLFLAG_RW, NULL, 0, + sysctl_aoe_discover, "I", "AoE device discover trigger"); +SYSCTL_INT(_net_aoe, OID_AUTO, maxwait, CTLFLAG_RW, &aoe_maxwait, 0, + "Max rexmit wait seconds before failing a device"); +SYSCTL_OID(_net_aoe, OID_AUTO, wc, CTLTYPE_INT|CTLFLAG_RW, NULL, 0, + sysctl_aoe_wc, "I", "AoE ATA device write cache enable / disable"); + +static void +nullfn(caddr_t p, uint sz) +{ +} + +/* Just malloc the mbuf and point to our data section */ +static struct mbuf * +frame_mbufinit(Frame *f) +{ + struct mbuf *m; + + m = m_get(M_DONTWAIT, MT_DATA); + if (m == NULL) + return NULL; + + m->m_flags |= M_EXT; + m->m_data = m->m_ext.ext_buf = f->data; + m->m_pkthdr.len = m->m_len = f->mlen; + m->m_pkthdr.rcvif = NULL; + m->m_ext.ext_size = MCLBYTES; + m->m_ext.ext_free = nullfn; + m->m_ext.ext_ref = nullfn; + SLIST_INIT(&m->m_pkthdr.tags); + m->m_pkthdr.csum_flags = 0; + return m; +} + +static Frame * +getframe(Aoedev *d, int tag) +{ + Frame *f, *e; + + f = d->frames; + e = f + d->nframes; + for (; ftag == tag) + return f; + return NULL; +} + +/* + * Leave the top bit clear so we have tagspace for userland. + * The bottom 16 bits are the xmit tick for rexmit/rttavg processing. + * This driver reserves tag -1 to mean "unused frame." + */ +static int +newtag(Aoedev *d) +{ + register int n; + + n = (++d->lasttag & 0x7fff) << 16; + return n |= ticks & 0xffff; +} + +static int +aoehdr_atainit(Aoedev *d, Aoehdr *h) +{ + int n; + + memcpy(h->src, IFPADDR(d->ifp), sizeof h->src); + memcpy(h->dst, d->addr, sizeof h->dst); + hnputs(h->type, AOE_ETYPE); + h->verfl = AOE_HVER; + hnputs(h->major, d->major); + h->minor = d->minor; + h->cmd = AOECMD_ATA; + hnputl(h->tag, n = newtag(d)); + return n; +} + +void +aoecmd_ata_rw(Aoedev *d, Frame *f) +{ + Aoehdr *h; + Aoeahdr *ah; + struct buf *bp; + struct mbuf *m; + ulong bcnt; + register daddr_t sector; + char writebit, extbit; + int s; + + writebit = 0x10; + extbit = 0x4; + + s = splbio(); + bp = d->inprocess; + + /* since we can't touch b_blkno we calc the current sector */ + sector = ((char *) bp->b_aoe_baddr - bp->b_data) >> DEV_BSHIFT; + sector += bp->b_blkno; + + /* + * Limit amount sent by frame size. + * XXX: interface specific. + */ + bcnt = bp->b_resid; + if (bcnt > MAXATADATA) + bcnt = MAXATADATA; + + /* initialize the headers & frame */ + h = (Aoehdr *) f->data; + ah = (Aoeahdr *) (h+1); + bzero(h, sizeof *h + sizeof *ah); + f->mlen = sizeof *h + sizeof *ah; + f->tag = aoehdr_atainit(d, h); + f->waited = 0; + f->bp = bp; + + /* set up ata header */ + ah->scnt = bcnt >> DEV_BSHIFT; + ah->lba0 = sector; + ah->lba1 = sector >>= 8; + ah->lba2 = sector >>= 8; + ah->lba3 = sector >>= 8; + if (d->flags & DEVFL_EXT) { + ah->aflags |= AOEAFL_EXT; + ah->lba4 = sector >>= 8; + ah->lba5 = sector >>= 8; + } else { + extbit = 0; + ah->lba3 &= 0x0f; + ah->lba3 |= 0xe0; /* LBA bit + obsolete 0xa0 */ + } + if (bp->b_flags & B_READ) { + writebit = 0; + f->readdst = bp->b_aoe_baddr; + } else { + ah->aflags |= AOEAFL_WRITE; + memcpy(ah+1, bp->b_aoe_baddr, bcnt); + f->mlen += bcnt; + } + ah->cmdstat = ATA_READ | writebit | extbit; + + /* now mark all our tracking fields and load out */ + bp->b_aoe_nbuflets = (void *) ((ulong) bp->b_aoe_nbuflets + 1); + bp->b_aoe_baddr = (void *) ((char *) bp->b_aoe_baddr + bcnt); + bp->b_resid -= bcnt; + if (bp->b_resid == 0) + d->inprocess = NULL; + splx(s); + + m = frame_mbufinit(f); + if (m == NULL) { + log(LOG_INFO, "aoe: aoecmd_ata_rw: mbuf init failure\n"); + return; + } + ether_output_frame(d->ifp, m); +} + +static void +rexmit(Aoedev *d, Frame *f) +{ + struct mbuf *m; + Aoehdr *h; + + h = (Aoehdr *) f->data; + hnputl(h->tag, f->tag = newtag(d)); + + m = frame_mbufinit(f); + if (m == NULL) { + log(LOG_INFO, "aoe: rexmit: mbuf init failure\n"); + return; + } + ether_output_frame(d->ifp, m); +} + +/* how long since we sent this tag? */ +static int +tsince(int tag) +{ + int n; + + n = ticks & 0xffff; + n -= tag & 0xffff; + if (n < 0) + n += 1<<16; + return n; +} + +static void +rexmit_timer(void *vp) +{ + int s, n, ntx; + Aoedev *d = vp; + Frame *f, *e; + register int timeout; + + /* timeout is always ~150% of the moving average */ + timeout = d->rttavg; + timeout += timeout >> 1; + ntx = 0; + + s = splbio(); + + if (d->flags & DEVFL_TKILL) + goto tdone; + f = d->frames; + e = f + d->nframes; + for (; ftag != FREETAG && + tsince(f->tag) >= timeout) { + n = f->waited += timeout; + n /= hz; + if (n > aoe_maxwait) { /* waited too long. device failure. */ + aoedev_downdev(d); + goto tdone; + } + ntx++; + rexmit(d, f); + } + } + if (ntx) { + n = d->rttavg <<= 1; + if (n > MAXTIMER) + d->rttavg = MAXTIMER; + } + callout_reset(&d->callout, TIMERTICK, rexmit_timer, d); + +tdone: splx(s); + return; +} + +/* Command to send an ATA identity */ +static void +aoecmd_ata_id(Aoedev *d) +{ + Aoehdr *h; + Aoeahdr *ah; + Frame *f; + struct mbuf *m; + + f = getframe(d, FREETAG); + if (f == NULL) { + log(LOG_INFO, "aoe: aoecmd_ata_id: can't get a frame. This shouldn't happen.\n"); + return; + } + + /* initialize the headers & frame */ + h = (Aoehdr *) f->data; + ah = (Aoeahdr *) (h+1); + bzero(h, sizeof *h + sizeof *ah); + f->mlen = sizeof *h + sizeof *ah; + f->tag = aoehdr_atainit(d, h); + f->waited = 0; + + /* this message initalizes the device, so we reset the rttavg */ + d->rttavg = MAXTIMER; + + /* set up ata header */ + ah->scnt = 1; + ah->cmdstat = ATA_ATA_IDENTIFY; + ah->lba3 = 0xa0; + + /* load out */ + m = frame_mbufinit(f); + if (m == NULL) { + log(LOG_INFO, "aoe: aoecmd_ata_id: mbuf init failure\n"); + return; + } + ether_output_frame(d->ifp, m); + + d->flags &= ~DEVFL_TKILL; + callout_reset(&d->callout, TIMERTICK, rexmit_timer, d); +} + +void +aoecmd_cfg_rsp(struct mbuf *m) +{ + Aoedev *d; + Aoehdr *h; + Aoechdr *ch; + ulong unit, bufcnt; + int s; + enum { MAXFRAMES = 16 }; + + s = splbio(); + h = mtod(m, Aoehdr *); + ch = (Aoechdr *) (h+1); + + unit = AOEUNIT(nhgets(h->major), h->minor); + if (unit > DKMAXUNIT) { + log(LOG_INFO, "aoe: aoecmd_cfg_rsp: unit %ld too large\n", unit); + goto rdone; + } + + bufcnt = nhgets(ch->bufcnt); + if (bufcnt > MAXFRAMES) /* let's keep it reasonable */ + bufcnt = MAXFRAMES; + + d = aoedev_set(unit, h->src, m->m_pkthdr.rcvif, bufcnt); + if (d == NULL) { + log(LOG_INFO, "aoe: aoecmd_cfg_rsp: failure setting device\n"); + goto rdone; + } + + if (d->flags & (DEVFL_UP | DEVFL_CLOSEWAIT)) + goto rdone; + + /* we get here only if the device is new */ + aoecmd_ata_id(d); + +rdone: splx(s); + return; +} + +/* Command to send an ATA write cache update. */ +static void +aoecmd_ata_wc(Aoedev *d, Frame *f) +{ + Aoehdr *h; + Aoeahdr *ah; + struct mbuf *m; + int s; + + s = splbio(); + + /* initialize the headers & frame */ + h = (Aoehdr *) f->data; + ah = (Aoeahdr *) (h+1); + bzero(h, sizeof *h + sizeof *ah); + f->mlen = sizeof *h + sizeof *ah; + f->tag = aoehdr_atainit(d, h); + f->waited = 0; + + /* set up ata header */ + ah->cmdstat = ATA_SETFEATURES; + ah->errfeat = aoe_wc ? ATA_SF_ENAB_WCACHE : ATA_SF_DIS_WCACHE; + ah->lba3 = 0xa0; /* obsolete bits */ + + splx(s); + + m = frame_mbufinit(f); + if (m == NULL) { + log(LOG_INFO, "aoe: aoecmd_ata_wc: mbuf init failure\n"); + return; + } + ether_output_frame(d->ifp, m); +} + +void +aoecmd_work(Aoedev *d) +{ + struct buf *bp; + Frame *f; + int s; + +loop: + s = splbio(); + f = getframe(d, FREETAG); + if (f == NULL) { + splx(s); + return; + } + if (d->flags & DEVFL_WC_UPDATE) { + d->flags &= ~DEVFL_WC_UPDATE; + splx(s); + aoecmd_ata_wc(d, f); + goto loop; + } + if (d->inprocess == NULL) { + bp = bufq_first(&d->bufq); + if (bp == NULL) { + splx(s); + return; + } + bufq_remove(&d->bufq, bp); + bp->b_aoe_baddr = bp->b_data; + bp->b_aoe_nbuflets = 0; + bp->b_resid = bp->b_bcount; + d->inprocess = bp; + splx(s); + devstat_start_transaction(&d->devstat); + } + aoecmd_ata_rw(d, f); + goto loop; +} + +static void +ataid_set(Aoedev *d, char *id) +{ + struct disklabel *dl; + int n; + + d->dev = aoeblk_register(d->unit, &d->disk); + d->dev->si_drv1 = d; + + /* Build disk label */ + dl = &d->disk.d_label; + bzero(dl, sizeof *dl); + dl->d_secsize = DEV_BSIZE; + + /* Decode the number of sectors on disk */ + n = lhgets(id + (83<<1)); /* command set supported */ + if (n & (1<<10)) { /* lba48 (really lba32 given b_blkno size) */ + d->flags |= DEVFL_EXT; + dl->d_secperunit = lhgetl(id + (100<<1)); /* n lba48 sectors */ + } else { + d->flags &= ~DEVFL_EXT; + dl->d_secperunit = lhgetl(id + (60<<1)); /* n lba28 sectors */ + } +} + +static void +calc_rttavg(Aoedev *d, int rtt) +{ + register long n; + + n = rtt; + if (n < MINTIMER) + n = MINTIMER; + else if (n > MAXTIMER) + n = MAXTIMER; + + /* g == .25; cf. Congestion Avoidance and Control, Jacobson & Karels; 1988 */ + n -= d->rttavg; + d->rttavg += n >> 2; +} + +void +aoecmd_ata_rsp(struct mbuf *m) +{ + Aoedev *d; + Aoehdr *hin; + Aoeahdr *ahin, *ahout; + Frame *f; + struct buf *bp; + register long n; + int s; + + s = splbio(); + hin = mtod(m, Aoehdr *); + d = aoedev_byaddr(hin->src); + if (d == NULL) { + log(LOG_INFO, "aoe: aoecmd_ata_rsp: response for unknown device\n"); + /* maybe run a discover cfg on this eaddr? */ + splx(s); + return; + } + + f = getframe(d, nhgetl(hin->tag)); + if (f == NULL) { + log(LOG_INFO, "aoe: aoecmd_ata_rsp: unsolicited response from %d.%d\n", + nhgets(hin->major), hin->minor); + /* might indicate a too short timeout */ + splx(s); + return; + } + + calc_rttavg(d, tsince(f->tag)); + + ahin = (Aoeahdr *) (hin+1); + ahout = (Aoeahdr *) (f->data + sizeof (Aoehdr)); + bp = f->bp; + + if (ahin->cmdstat & 0xa9) { /* These bits cleared on success */ + log(LOG_INFO, "aoe: aoecmd_ata_rsp: ata error cmd=%2.2Xh stat=%2.2Xh\n", + ahout->cmdstat, ahin->cmdstat); + if (bp) + bp->b_flags |= B_ERROR; + /* Smartmontools won't get errors. oh well. */ + } else { + switch (ahout->cmdstat) { + case ATA_READ: + case ATA_READ48: + n = ahout->scnt << DEV_BSHIFT; + if (m->m_len - sizeof *hin - sizeof *ahin < n) { + splx(s); + log(LOG_INFO, "aoe: aoecmd_ata_rsp: runt ata data size " + "in read. m_len=%d\n", m->m_len); + + /* fail frame f ? Just returning will rexmit. */ + return; + } + memcpy(f->readdst, ahin+1, n); + case ATA_WRITE: + case ATA_WRITE48: + break; + case ATA_SETFEATURES: + if (ahin->errfeat & (1<<2)) + log(LOG_INFO, "aoe: aoecmd_ata_rsp: setfeatures failure " + "for %d\n", d->unit); + break; + case ATA_ATA_IDENTIFY: + if (m->m_len - sizeof *hin - sizeof *ahin < 512) { + log(LOG_INFO, "aoe: aoecmd_ata_rsp: runt ata data size " + "in ataid\n"); + break; + } + ataid_set(d, (char *) (ahin+1)); + bzero(&d->devstat, sizeof d->devstat); + devstat_add_entry(&d->devstat, "aoed", d->unit, DEV_BSIZE, + DEVSTAT_NO_ORDERED_TAGS, + DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER, + DEVSTAT_PRIORITY_DISK); + d->flags |= DEVFL_UP; + break; + default: + /* SMART ? */ + log(LOG_INFO, "aoe: aoecmd_ata_rsp: unrecognized ata command " + "%2.2Xh from %d.%d\n", ahout->cmdstat, nhgets(hin->major), + hin->minor); + } + } + + if (bp) + bp->b_aoe_nbuflets = (void *) ((ulong) bp->b_aoe_nbuflets - 1); + splx(s); + if (bp && bp->b_aoe_nbuflets == 0 && bp->b_resid == 0) { + devstat_end_transaction_buf(&d->devstat, bp); + biodone(bp); + } + + f->bp = NULL; + f->tag = FREETAG; + + if (!d->busy) /* If "top side" is already doing don't bother */ + aoecmd_work(d); +} + +/* Send an AoE Config Query to all available network interfaces. */ +void +aoecmd_cfg(ushort major, uchar minor) +{ + Aoehdr *h; + Aoechdr *ch; + struct mbuf *m0, *m; + struct ifnet *ifp; + int s; + + m0 = m_get(M_DONTWAIT, MT_DATA); + if (m0 == NULL) { + log(LOG_INFO, "aoe: aoecmd_cfg: mget failure\n"); + return; + } + + m0->m_pkthdr.len = m0->m_len = sizeof *h + sizeof *ch; + MH_ALIGN(m0, m0->m_len); + h = mtod(m0, Aoehdr *); + ch = (Aoechdr *) (h+1); + bzero(h, sizeof *h + sizeof *ch); + m0->m_flags |= M_BCAST; + + memset(h->dst, 0xff, sizeof h->dst); + hnputs(h->type, AOE_ETYPE); + h->verfl = AOE_HVER; + hnputs(h->major, major); + h->minor = minor; + h->cmd = AOECMD_CFG; + + s = splimp(); + TAILQ_FOREACH(ifp, &ifnet, if_link) { + if (!isaoeifc(ifp)) + continue; + if ((ifp->if_flags & IFF_UP) == 0) + continue; + memcpy(h->src, IFPADDR(ifp), sizeof h->src); + m = m_copypacket(m0, M_DONTWAIT); + if (m == NULL) { + log(LOG_INFO, "aoe: aoecmd_cfg: copypacket failure\n"); + continue; + } + ether_output_frame(ifp, m); + } + splx(s); + + m_freem(m0); +} + +/* Set the write caching. */ +static int +sysctl_aoe_wc(SYSCTL_HANDLER_ARGS) +{ + int n, err; + + n = aoe_wc; + + err = SYSCTL_OUT(req, &aoe_wc, sizeof aoe_wc); + if (err || !req->newptr) + return err; + + err = SYSCTL_IN(req, &aoe_wc, sizeof aoe_wc); + if (err) + return err; + if (aoe_wc) /* KISS */ + aoe_wc = 1; + if (n != aoe_wc) + aoedev_wc_update(); + return 0; +} + +/* Trigger a Config Query discover. */ +static int +sysctl_aoe_discover(SYSCTL_HANDLER_ARGS) +{ + int n, err; + + n = 0; + err = SYSCTL_OUT(req, &n, sizeof n); + if (err || !req->newptr) + return err; + + err = SYSCTL_IN(req, &n, sizeof n); + if (err) + return err; + + aoecmd_cfg(0xffff, 0xff); + + return 0; +} + --- src/sys/dev/aoe/aoedev.c.orig Fri Sep 30 15:05:43 2005 +++ src/sys/dev/aoe/aoedev.c Mon Oct 3 12:48:06 2005 @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2004, Sam Hopkins + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/aoe/aoedev.c,v 1.23.2.5 2004/09/22 16:50:41 ?? Exp $ + */ + +#include + +static Aoedev *devlist; +static int sysctl_aoe_devices(SYSCTL_HANDLER_ARGS); + +MALLOC_DEFINE(M_AOEDEV, "AoE Disk", "ATA over Ethernet Disk"); +MALLOC_DEFINE(M_AOEFRAME, "AoE Frame", "ATA over Ethernet Disk Frame"); + +SYSCTL_DECL(_net_aoe); +SYSCTL_OID(_net_aoe, OID_AUTO, devices, CTLTYPE_STRING|CTLFLAG_RD, NULL, 0, + sysctl_aoe_devices, "A", "AoE Device Info"); + +static Aoedev * +aoedev_newdev(ulong nframes) +{ + Aoedev *d; + Frame *f, *e; + + d = (Aoedev *) mallocz(sizeof *d, M_AOEDEV, 0); + if (d == NULL) + return NULL; + f = (Frame *) mallocz(nframes * sizeof *f, M_AOEFRAME, 0); + if (f == NULL) { + free(d, M_AOEDEV); + return NULL; + } + + d->nframes = nframes; + d->frames = f; + e = f + nframes; + for (; ftag = FREETAG; + + callout_init(&d->callout); + bufq_init(&d->bufq); + + d->next = devlist; + devlist = d; + + return d; +} + +static void +aoedev_freedev(Aoedev *d) +{ + free(d->frames, M_AOEFRAME); + free(d, M_AOEDEV); +} + +void +aoedev_downdev(Aoedev *d) +{ + Frame *f, *e; + struct buf *bp; + + d->flags |= DEVFL_TKILL; + callout_stop(&d->callout); + + f = d->frames; + e = f + d->nframes; + for (; ftag != FREETAG) { + if ((bp = f->bp)) { + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + (ulong) bp->b_aoe_nbuflets -= 1; + if (bp->b_aoe_nbuflets == 0) + biodone(bp); + } + f->tag = FREETAG; + f->bp = NULL; + } + } + d->inprocess = NULL; + + while ((bp = bufq_first(&d->bufq))) { + bufq_remove(&d->bufq, bp); + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + biodone(bp); + } + + if (d->flags & DEVFL_OPEN) + d->flags |= DEVFL_CLOSEWAIT; + else if (d->flags & DEVFL_UP) { + devstat_remove_entry(&d->devstat); + disk_destroy(d->dev); + } + d->flags &= ~DEVFL_UP; +} + +/* + * (1) If the unit/addr is ok, but the device is not up + * we force reset the device to flush the outstanding + * messages (the potential ata ident). This is just to + * be safe. + */ +Aoedev * +aoedev_set(ulong unit, char *addr, struct ifnet *ifp, ulong bufcnt) +{ + Aoedev *d; + int s; + + s = splbio(); + for (d=devlist; d; d=d->next) + if (d->unit == unit + || memcmp(d->addr, addr, sizeof d->addr) == 0) + break; + + if (d == NULL) { + d = aoedev_newdev(bufcnt); + if (d == NULL) { + splx(s); + log(LOG_INFO, "aoe: aoedev_set: aoedev_newdev failure.\n"); + return NULL; + } + } + + d->ifp = ifp; + + if (d->unit != unit + || memcmp(d->addr, addr, sizeof d->addr) + || (d->flags & DEVFL_UP) == 0) { /* (1) */ + aoedev_downdev(d); + memcpy(d->addr, addr, sizeof d->addr); + d->unit = unit; + d->major = AOEMAJOR(unit); + d->minor = AOEMINOR(unit); + } + + splx(s); + return d; +} + +Aoedev * +aoedev_byaddr(char *addr) +{ + Aoedev *d; + + for (d=devlist; d; d=d->next) + if (memcmp(d->addr, addr, sizeof d->addr) == 0) + return d; + return NULL; +} + +int +aoedev_init(void) +{ + return 0; +} + +int +aoedev_exit(void) +{ + Aoedev *d; + int s; + + s = splbio(); + while ((d = devlist)) { + devlist = d->next; + aoedev_downdev(d); + aoedev_freedev(d); + } + splx(s); + return 0; +} + +int +aoedev_busy(void) +{ + Aoedev *d; + int s; + + s = splbio(); + d = devlist; + for (; d; d=d->next) + if (d->flags & DEVFL_OPEN) { + splx(s); + return 1; + } + splx(s); + return 0; +} + +void +aoedev_wc_update(void) +{ + Aoedev *d; + int s; + + s = splbio(); + for (d=devlist; d; d=d->next) + d->flags |= DEVFL_WC_UPDATE; + splx(s); + return; +} + +/* approach taken from vm/vm_zone.c */ +static int +sysctl_aoe_devices(SYSCTL_HANDLER_ARGS) +{ + char *buf; + Aoedev *d; + register int n; + int s; + enum { LINESZ = 64 }; + + s = splbio(); + + if (devlist == NULL) { + splx(s); + return SYSCTL_OUT(req, "\0", 1); + } + + n = 0; + d = devlist; + for (; d; d=d->next) + n += LINESZ; + buf = (char *) malloc(n+1, M_TEMP, M_NOWAIT|M_ZERO); + if (buf == NULL) { + splx(s); + log(LOG_INFO, "aoe: sysctl_aoe_devices: could not malloc " + "buffer size %d to print device list\n", n); + return ENOMEM; + } + + n = 0; + d = devlist; + for (; d; d=d->next) { + n += snprintf(buf+n, LINESZ, "\naoed%-6d\t%s%d\t%s%s%s", + d->unit, + d->ifp->if_name, + d->ifp->if_unit, + (d->flags & DEVFL_UP) ? "UP" : "DOWN", + (d->flags & DEVFL_OPEN) ? ",OPEN" : "", + (d->flags & DEVFL_CLOSEWAIT) ? ",CLOSEWAIT" : ""); + } + + splx(s); + + n = SYSCTL_OUT(req, buf, n+1); + free(buf, M_TEMP); + return n; +} + --- src/sys/dev/aoe/aoenet.c.orig Fri Sep 30 15:05:43 2005 +++ src/sys/dev/aoe/aoenet.c Mon Oct 3 10:17:05 2005 @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2004, Sam Hopkins + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/aoe/aoenet.c,v 1.23.2.5 2004/09/22 16:50:41 ?? Exp $ + */ + +#include + +#define NECODES 5 + +static struct ifqueue aoeq; +extern struct ifqueue *aoeintrq; + +static char *aoe_errlist[] = +{ + "no such error", + "unrecognized command code", + "bad argument parameter", + "device unavailable", + "config string present", + "unsupported version" +}; + +static void +aoeintr(void) +{ + struct mbuf *m; + Aoehdr *h; + int s; + ulong n; + + for (; aoeintrq->ifq_head; m_freem(m)) { + s = splimp(); + IF_DEQUEUE(aoeintrq, m); + splx(s); + if (m == NULL) + return; + if (!isaoeifc(m->m_pkthdr.rcvif)) + continue; + + m->m_len += ETHER_HDR_LEN; /* look ma! just like linux! :-X */ + m->m_data -= ETHER_HDR_LEN; + + h = mtod(m, Aoehdr *); + n = nhgetl(h->tag); + if ((h->verfl & AOEFL_RSP) == 0 || (n & 1<<31)) + continue; + if (h->verfl & AOEFL_ERR) { + n = h->err; + if (n > NECODES) + n = 0; + log(LOG_INFO, "aoe: aoeintr: error packet from %d.%d; ecode=%d '%s'\n", + nhgets(h->major), h->minor, h->err, aoe_errlist[n]); + continue; + } + + switch (h->cmd) { + case AOECMD_ATA: + aoecmd_ata_rsp(m); + break; + case AOECMD_CFG: + aoecmd_cfg_rsp(m); + break; + default: + log(LOG_INFO, "aoe: aoeintr: unknown cmd %d\n", h->cmd); + } + } +} + +int +aoenet_init(void) +{ + int n, s; + + /* + * The following is far from ideal but is needed to keep + * this driver from trompling the BIO playground. This keeps + * the higher priority net (imp) interrupts from running while + * in bio critical sections. + */ + s = splhigh(); + bio_imask |= net_imask; + net_imask |= bio_imask; +#ifdef __i386__ + update_intr_masks(); +#endif + splx(s); + + aoeq.ifq_maxlen = IFQ_MAXLEN; + n = register_netisr(NETISR_AOE, aoeintr); + if (n == 0) + aoeintrq = &aoeq; + return n; +} + +int +aoenet_exit(void) +{ + int s; + struct mbuf *m; + + s = splimp(); + aoeintrq = NULL; + splx(s); + while (aoeq.ifq_head) { + IF_DEQUEUE(&aoeq, m); + if (m) + m_freem(m); + } + return unregister_netisr(NETISR_AOE); +} + --- src/sys/dev/aoe/aoeutils.c.orig Fri Sep 30 15:05:43 2005 +++ src/sys/dev/aoe/aoeutils.c Mon Oct 3 10:17:05 2005 @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2004, Sam Hopkins + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/aoe/aoeutils.c,v 1.23.2.5 2004/09/22 16:50:41 ?? Exp $ + */ + +#include + +ushort +nhgets(uchar *p) +{ + ushort n; + + n = p[0] << 8; + return n |= p[1]; +} + +ulong +nhgetl(uchar *p) +{ + ulong n; + + n = nhgets(p) << 16; + return n |= nhgets(p+2); +} + +void +hnputs(uchar *p, ushort n) +{ + p[1] = n; + p[0] = n >>= 8; +} + +void +hnputl(uchar *p, ulong n) +{ + hnputs(p+2, n); + hnputs(p, n >>= 16); +} + +ushort +lhgets(uchar *p) +{ + ushort n; + + n = p[1] << 8; + return n |= p[0]; +} + +ulong +lhgetl(uchar *p) +{ + ulong n; + + n = lhgets(p+2) << 16; + return n |= lhgets(p); +} + +void * +mallocz(ulong sz, struct malloc_type *type, int flags) +{ + void *vp; + + vp = malloc(sz, type, flags); + if (vp) + bzero(vp, sz); + return vp; +} + +static char * +strchr(char *p, char c) +{ + if (p == NULL) + return NULL; +loop: + if (*p == c) + return p; + if (*p++ != '\0') + goto loop; + return NULL; +} + +extern char aoe_iflist[IFLISTSZ]; + +int +isaoeifc(struct ifnet *ifp) +{ + char ifname[64]; + register char *p, *r; + register int len; + + switch (ifp->if_data.ifi_type) { + default: + return 0; + case IFT_ETHER: + case IFT_FASTETHER: + case IFT_GIGABITETHERNET: + } + + snprintf(ifname, sizeof ifname, "%s%d", ifp->if_name, ifp->if_unit); + p = aoe_iflist; +loop: + if (p == NULL || *p == '\0') + return 0; + + r = strchr(p, ' '); + if (r) + len = r++ - p; + else + len = strlen(p); + + if (strlen(ifname) == len) + if (strncmp(ifname, p, len) == 0) + return 1; + p = r; + goto loop; +} + --- src/sys/dev/aoe/if_aoe.h.orig Fri Sep 30 15:05:43 2005 +++ src/sys/dev/aoe/if_aoe.h Mon Oct 3 10:17:05 2005 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2004, Sam Hopkins + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/aoe/if_aoe.h,v 1.23.2.5 2004/09/22 16:50:41 ?? Exp $ + */ + +enum +{ + AOECMD_ATA, + AOECMD_CFG, + + AOEFL_RSP = (1<<3), + AOEFL_ERR = (1<<2), + + AOEAFL_EXT = (1<<6), + AOEAFL_DEV = (1<<4), + AOEAFL_ASYNC = (1<<1), + AOEAFL_WRITE = (1<<0), + + AOECCMD_READ = 0, + AOECCMD_TEST, + AOECCMD_PTEST, + AOECCMD_SET, + AOECCMD_FSET, + + AOE_HVER = 0x10, + AOE_ETYPE = 0x88a2, +}; + +typedef struct Aoehdr Aoehdr; +struct Aoehdr +{ + uchar dst[6]; + uchar src[6]; + uchar type[2]; + uchar verfl; + uchar err; + uchar major[2]; + uchar minor; + uchar cmd; + uchar tag[4]; +}; + +typedef struct Aoeahdr Aoeahdr; +struct Aoeahdr +{ + uchar aflags; + uchar errfeat; + uchar scnt; + uchar cmdstat; + uchar lba0; + uchar lba1; + uchar lba2; + uchar lba3; + uchar lba4; + uchar lba5; + uchar res[2]; +}; + +typedef struct Aoechdr Aoechdr; +struct Aoechdr +{ + uchar bufcnt[2]; + uchar fwver[2]; + uchar res; + uchar aoeccmd; + uchar cslen[2]; +}; + --- src/sys/dev/aoe/u.h.orig Fri Sep 30 15:05:43 2005 +++ src/sys/dev/aoe/u.h Mon Oct 3 10:17:05 2005 @@ -0,0 +1,4 @@ + +typedef unsigned long ulong; +typedef unsigned char uchar; + --- src/sys/dev/aoe/CHANGELOG.orig Mon Oct 3 13:18:35 2005 +++ src/sys/dev/aoe/CHANGELOG Mon Oct 3 13:26:38 2005 @@ -0,0 +1,33 @@ +$FreeBSD: src/sys/dev/aoe/CHANGELOG,v 1.23.2.5 2005/10/03 16:50:41 ?? Exp $ + +1.2: (Future TODO) + + * Back port SMART stuff from FreeBSD 5.3 version of driver. + + * Add support for jumbo frames. + + +1.1: Mon Oct 3 12:52:06 CDT 2005 + + * Fixed mbuf initialization bug in frame_mbufinit() and aoecmd_cfg(). + (This fixes the bug with multi block writes corrupting the disk.) + + * Set bio_imask and net_imask to be the same in aoenet_init(). This + keeps the higher priority net/imp interrupts from running while the + kernel is running in BIO critical sections. (This fixes the problem + of the AoE driver panic'ing the kernel in critical BIO sections.) + + * Added a "busy" flag to Aoedev to keep the interrupt handler out of + aoecmd_work() when it is not needed. This gives priority to the + "top side" of the kernel where draining the BIO queue should be + done. + + * Tighten the splXXX()/splx() pairs so the interrupts are not masked + almost the entire time the kernel is running in the AoE driver. + + * Added a CHANGELOG (this) file. + + +1.0: Sep 22, 2004 + + * Initial version --- src/sys/modules/Makefile.orig Thu Jan 13 21:07:40 2005 +++ src/sys/modules/Makefile Fri Sep 30 15:05:43 2005 @@ -8,6 +8,7 @@ SUBDIR= accf_data \ aha \ amr \ an \ + aoe \ aue \ axe \ bfe \ --- src/sys/modules/aoe/Makefile.orig Fri Sep 30 15:05:43 2005 +++ src/sys/modules/aoe/Makefile Fri Sep 30 15:05:43 2005 @@ -0,0 +1,8 @@ +# $FreeBSD: src/sys/modules/aoe/Makefile,v 1.0 2004/08/31 18:52:57 sah Exp $ + +.PATH: ${.CURDIR}/../../dev/aoe +KMOD= aoe +SRCS= aoe.c aoecmd.c aoedev.c aoenet.c aoeblk.c aoeutils.c +NOMAN= + +.include --- src/sys/net/ethernet.h.orig Sun Dec 1 08:03:09 2002 +++ src/sys/net/ethernet.h Fri Sep 30 15:05:43 2005 @@ -307,6 +307,7 @@ struct ether_addr { #define ETHERTYPE_PPPOEDISC 0x8863 /* PPP Over Ethernet Discovery Stage */ #define ETHERTYPE_PPPOE 0x8864 /* PPP Over Ethernet Session Stage */ #define ETHERTYPE_LANPROBE 0x8888 /* HP LanProbe test? */ +#define ETHERTYPE_AOE 0x88A2 /* ATA over Ethernet */ #define ETHERTYPE_LOOPBACK 0x9000 /* Loopback: used to test interfaces */ #define ETHERTYPE_LBACK ETHERTYPE_LOOPBACK /* DEC MOP loopback */ #define ETHERTYPE_XNSSM 0x9001 /* 3Com (Formerly Bridge Communications), XNS Systems Management */ --- src/sys/net/if_ethersubr.c.orig Wed Mar 3 06:35:16 2004 +++ src/sys/net/if_ethersubr.c Fri Sep 30 15:05:43 2005 @@ -40,6 +40,7 @@ #include "opt_ipx.h" #include "opt_bdg.h" #include "opt_netgraph.h" +#include "opt_aoe.h" #include #include @@ -99,6 +100,10 @@ extern u_char at_org_code[3]; extern u_char aarp_org_code[3]; #endif /* NETATALK */ +#ifdef AOE_HOOK +struct ifqueue *aoeintrq; +#endif /* AOE_HOOK */ + /* netgraph node hooks for ng_ether(4) */ void (*ng_ether_input_p)(struct ifnet *ifp, struct mbuf **mp, struct ether_header *eh); @@ -743,6 +748,16 @@ post_stats: aarpinput(IFP2AC(ifp), m); /* XXX */ return; #endif /* NETATALK */ +#ifdef AOE_HOOK + case ETHERTYPE_AOE: + if (aoeintrq) { + schednetisr(NETISR_AOE); + inq = aoeintrq; + break; + } + goto typeunknown; +#endif /* AOE_HOOK */ + case ETHERTYPE_VLAN: /* XXX lock ? */ if (vlan_input_p != NULL) @@ -754,6 +769,7 @@ post_stats: /* XXX unlock ? */ return; default: +typeunknown: #ifdef IPX if (ef_inputp && ef_inputp(ifp, eh, m) == 0) return; --- src/sys/net/netisr.h.orig Sat Feb 9 17:02:39 2002 +++ src/sys/net/netisr.h Fri Sep 30 15:05:43 2005 @@ -57,6 +57,7 @@ #define NETISR_NS 6 /* same as AF_NS */ #define NETISR_ATALK 16 /* same as AF_APPLETALK */ #define NETISR_ARP 18 /* same as AF_LINK */ +#define NETISR_AOE 19 /* ATA over Ethernet */ #define NETISR_IPX 23 /* same as AF_IPX */ #define NETISR_USB 25 /* USB soft interrupt */ #define NETISR_PPP 27 /* PPP soft interrupt */