diff -upr --new-file src/etc/defaults/rc.conf src2/etc/defaults/rc.conf --- src/etc/defaults/rc.conf Thu Oct 28 13:59:44 2004 +++ src2/etc/defaults/rc.conf Fri Nov 5 19:18:14 2004 @@ -472,6 +472,12 @@ ugidfw_enable="NO" # Load mac_bsdextende bsdextended_script="/etc/rc.bsdextended" # Default mac_bsdextended(4) # ruleset file. swapoff="NO" # Remove swap partitions upon shutdown +aoe_enable="NO" # ATA over Ethernet +aoe_iflist="" # space separated list of interface names valid for AoE +aoe_wc="1" # write cache enable for AoE ATA devices +aoe_vinum_drives="" # space separated list of AoE devices used by vinum +aoe_mounts="" # space separated list of AoE device based mounts (vinum incl.) + ############################################################## ### Jail Configuration ####################################### diff -upr --new-file src/etc/rc.d/Makefile src2/etc/rc.d/Makefile --- src/etc/rc.d/Makefile Fri Oct 15 14:22:43 2004 +++ src2/etc/rc.d/Makefile Mon Nov 8 18:27:44 2004 @@ -3,7 +3,7 @@ FILES= DAEMON LOGIN NETWORKING SERVERS \ abi accounting addswap adjkerntz amd \ - apm apmd archdep atm1 atm2 atm3 \ + aoe apm apmd archdep atm1 atm2 atm3 \ bgfsck bootparams \ ccd cleanvar cleartmp cron \ devd devfs dhclient \ diff -upr --new-file src/etc/rc.d/aoe src2/etc/rc.d/aoe --- src/etc/rc.d/aoe Thu Jan 1 00:00:00 1970 +++ src2/etc/rc.d/aoe Fri Nov 5 19:14:01 2004 @@ -0,0 +1,51 @@ +#!/bin/sh +# +# $FreeBSD: src/etc/rc.d/aoe,v 1.0.0.1 2004/10/10 09:50:54 sah Exp $ +# + +# PROVIDE: netdisks +# REQUIRE: NETWORKING sysctl +# KEYWORD: nojail + +. /etc/rc.subr + +name="aoe" +rcvar="`set_rcvar`" +start_cmd="aoe_start" +stop_cmd=":" + +# discover the AoE devices on requested interfaces and tell vinum +# about the disks requested +aoe_start() +{ + if [ -z "${aoe_iflist}" ]; then + echo 2>&1 aoe_start: unset aoe_iflist + return + fi + 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 + + if checkyesno start_vinum; then + if [ -n "${aoe_vinum_drives}" ]; then + vinum read "${aoe_vinum_drives}" + fi + fi + + for i in "${aoe_mounts}"; do + mount $i + done + else + echo 1>&2 Failure initializing AoE + fi +} + + +load_rc_config $name +run_rc_command "$1" diff -upr --new-file src/share/man/man4/Makefile src2/share/man/man4/Makefile --- src/share/man/man4/Makefile Sat Oct 9 15:29:14 2004 +++ src2/share/man/man4/Makefile Fri Nov 5 19:14:01 2004 @@ -17,6 +17,7 @@ MAN= aac.4 \ amd.4 \ amr.4 \ an.4 \ + aoe.4 \ asr.4 \ ata.4 \ atapicam.4 \ diff -upr --new-file src/share/man/man4/aoe.4 src2/share/man/man4/aoe.4 --- src/share/man/man4/aoe.4 Thu Jan 1 00:00:00 1970 +++ src2/share/man/man4/aoe.4 Wed Nov 10 18:32:07 2004 @@ -0,0 +1,167 @@ +.\" +.\" 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 +% ls /dev/aoed* +ls: /dev/aoed*: No such file or directory +% 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 +% ls -l /dev/aoed* +crw-r----- 1 root operator 4, 153 Oct 12 17:10 /dev/aoed10 +crw-r----- 1 root operator 4, 154 Oct 12 17:10 /dev/aoed10s1 +crw-r----- 1 root operator 4, 155 Oct 12 17:10 /dev/aoed10s1a +crw-r----- 1 root operator 4, 156 Oct 12 17:10 /dev/aoed10s1c +crw-r----- 1 root operator 4, 152 Oct 12 17:10 /dev/aoed3 +crw-r----- 1 root operator 4, 151 Oct 12 17:10 /dev/aoed30 +.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 . diff -upr --new-file src/sys/conf/files src2/sys/conf/files --- src/sys/conf/files Wed Sep 22 19:23:37 2004 +++ src2/sys/conf/files Fri Nov 5 19:14:01 2004 @@ -351,6 +351,12 @@ dev/ata/ata-card.c optional ata pccard dev/ata/ata-pci.c optional ata pci dev/ata/ata-chipset.c optional ata pci dev/ata/ata-dma.c optional ata pci +dev/aoe/aoe.c optional aoe +dev/aoe/aoeblk.c optional aoe +dev/aoe/aoecmd.c optional aoe +dev/aoe/aoedev.c optional aoe +dev/aoe/aoenet.c optional aoe +dev/aoe/aoeutils.c optional aoe dev/ata/ata-disk.c optional atadisk dev/ata/ata-raid.c optional ataraid dev/ata/atapi-cd.c optional atapicd diff -upr --new-file src/sys/dev/aoe/all.h src2/sys/dev/aoe/all.h --- src/sys/dev/aoe/all.h Thu Jan 1 00:00:00 1970 +++ src2/sys/dev/aoe/all.h Thu Dec 9 12:49:03 2004 @@ -0,0 +1,163 @@ +/* + * 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 +#include +#include +#include + +#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 bio_aoe_baddr bio_driver1 +#define bio_aoe_nbuflets bio_driver2 + +typedef unsigned char uchar; +typedef unsigned long ulong; +typedef unsigned int uint; +typedef unsigned short ushort; + +enum { /* this should be in sys/ata.h */ + ATA_SMART = 0xb0, + ATA_SMART_READ_DATA = 0xd0, + ATA_SMART_READ_THRESHOLDS = 0xd1, + ATA_SMART_ATTR_AUTOSAVE = 0xd2, + ATA_SMART_OFFLINE_IMMEDIATE = 0xd4, + ATA_SMART_READ_LOG = 0xd5, + ATA_SMART_WRITE_LOG = 0xd6, + ATA_SMART_ENABLE = 0xd8, + ATA_SMART_DISABLE = 0xd9, + ATA_SMART_STATUS = 0xda, +}; + +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 close to revalidate */ + DEVFL_TASKON = (1<<5), /* disk create/destroy task is active */ + DEVFL_WC_UPDATE = (1<<6), /* This device needs to update write cache status */ + + MAXATADATA = 1024, /* max permissable data in frame */ + FREETAG = -1, /* tag magic; denotes free frame */ + INPROCTAG = -2, /* tag magic; denotes frame in processing */ + IFLISTSZ = 128, /* length of the aoe_iflist string */ +}; + +typedef struct Frame Frame; +struct Frame { + int tag; + ulong mlen; + ulong waited; + struct bio *bp; + caddr_t *bioaddr; + struct mbuf *m; + char data[sizeof (Aoehdr) + sizeof (Aoeahdr) + MAXATADATA]; /* largest possible */ +}; + +typedef struct Aoedev Aoedev; +struct Aoedev { + Aoedev *next; + char addr[6]; + ushort flags; + ushort major; + ushort minor; + struct disk *disk; + struct task task; + struct ifnet *ifp; + struct callout callout; + struct mtx mtx; + struct bio_queue_head bioq; + struct bio *inprocess; + ulong unit; + off_t nsectors; + ushort rttavg; + ushort lasttag; + ulong nframes; + Frame *frames; + char ident[512]; +}; + +int aoe_isexiting(void); + +int aoeblk_register(Aoedev *); +int aoeblk_unregister(Aoedev *); + +int aoecmd_ata_smart(Aoedev *, struct ata_cmd *); +void aoecmd_work(Aoedev *d); +void aoecmd_cfg_rsp(struct mbuf *m); +void aoecmd_ata_rsp(struct mbuf *m); +void aoecmd_cfg(ushort, uchar); + +Aoedev *aoedev_set(ulong, char *, struct ifnet *, ulong); +void aoedev_downdev(Aoedev *); +Aoedev *aoedev_byaddr(char *); +Aoedev *aoedev_byunit(ulong); +int aoedev_busy(void); +void aoedev_freedev(Aoedev *); +void aoedev_init(void); +void aoedev_exit(void); +void aoedev_wc_update(void); + +void aoenet_init(void); +void aoenet_exit(void); + +uint16_t nhget16(uchar *); +uint32_t nhget32(uchar *); +void hnput16(uchar *, uint16_t); +void hnput32(uchar *, uint32_t); +uint16_t lhget16(uchar *); +uint32_t lhget32(uchar *); +int isaoeif(struct ifnet *); + diff -upr --new-file src/sys/dev/aoe/aoe.c src2/sys/dev/aoe/aoe.c --- src/sys/dev/aoe/aoe.c Thu Jan 1 00:00:00 1970 +++ src2/sys/dev/aoe/aoe.c Thu Dec 9 12:32:04 2004 @@ -0,0 +1,86 @@ +/* + * 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 + +static int aoe_exiting; +static struct mtx aoe_exit_mtx; + +SYSCTL_NODE(_net, OID_AUTO, aoe, CTLFLAG_RW, 0, "AoE Driver controllables"); + +/* + * The entry points in the code call this function so we + * can sort of gate them for module unload. It's not a guarantee, + * but it goes a long way. + */ +int +aoe_isexiting(void) +{ + int n; + + mtx_lock(&aoe_exit_mtx); + n = aoe_exiting; + mtx_unlock(&aoe_exit_mtx); + return n; +} + +static int +aoe_loader(struct module *m, int what, void *arg) +{ + switch (what) { + case MOD_LOAD: + mtx_init(&aoe_exit_mtx, "AoE exit mutex", NULL, MTX_DEF); + aoedev_init(); + aoenet_init(); + log(LOG_INFO, "aoe: AoE version %d.%d initialized\n", 1, 1); + return 0; + case MOD_UNLOAD: + mtx_lock(&aoe_exit_mtx); + aoe_exiting = 1; + if (aoedev_busy()) { + aoe_exiting = 0; + mtx_unlock(&aoe_exit_mtx); + log(LOG_INFO, "aoe: aoe_loader: can't unload, devices busy\n"); + return EBUSY; + } + mtx_unlock(&aoe_exit_mtx); + aoenet_exit(); + aoedev_exit(); + + tsleep(aoe_loader, 0, "aoeunl", hz<<1); + + mtx_destroy(&aoe_exit_mtx); + return 0; + default: + return EINVAL; + } +} + +DEV_MODULE(aoe, aoe_loader, NULL); + diff -upr --new-file src/sys/dev/aoe/aoeblk.c src2/sys/dev/aoe/aoeblk.c --- src/sys/dev/aoe/aoeblk.c Thu Jan 1 00:00:00 1970 +++ src2/sys/dev/aoe/aoeblk.c Thu Dec 9 12:41:51 2004 @@ -0,0 +1,260 @@ +/* + * 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 +aoeblk_open(struct disk *disk) +{ + Aoedev *d; + + if (aoe_isexiting()) + return EBUSY; + + d = disk->d_drv1; + mtx_lock(&d->mtx); + if ((d->flags & DEVFL_UP) == 0) { + log(LOG_INFO, "aoe: aoeblk_open: AoE device %ld is not up.\n", d->unit); + mtx_unlock(&d->mtx); + return EBUSY; + } + d->flags |= DEVFL_OPEN; + mtx_unlock(&d->mtx); + + return 0; +} + +/* + * (1) On final close we might be waiting to reinitialize the + * blade. If so, we'll unregister the disk (which will eventually + * trigger reinitialization when complete). + */ +static int +aoeblk_close(struct disk *disk) +{ + Aoedev *d; + + d = disk->d_drv1; + mtx_lock(&d->mtx); + d->flags &= ~DEVFL_OPEN; + if (d->flags & DEVFL_CLOSEWAIT) { /* (1) */ + if (aoeblk_unregister(d) != 0) + log(LOG_INFO, "aoe: aoeblk_close: can't unregister disk. " + "Expect buggy behaviour.\n"); + } + mtx_unlock(&d->mtx); + + return 0; +} + +static void +aoeblk_strategy(struct bio *bp) +{ + Aoedev *d; + + d = bp->bio_disk->d_drv1; + mtx_lock(&d->mtx); + if ((d->flags & DEVFL_UP) == 0) { + biofinish(bp, NULL, EIO); + mtx_unlock(&d->mtx); + return; + } + bioq_disksort(&d->bioq, bp); + aoecmd_work(d); + mtx_unlock(&d->mtx); +} + +/* + * Ioctl only for select smartmontools ata commands. + * We fake out the ATAREQUEST ata ioctl -- ugly, but effective. + */ +static int +aoeblk_ioctl(struct disk *disk, ulong cmd, void *vp, int flag, struct thread *td) +{ + struct ata_cmd *iocmd; + Aoedev *d; + int n; + + if (cmd != IOCATA) { + log(LOG_INFO, "aoe: aoeblk_ioctl: cmd %ld not IOCATA.\n", cmd); + return ENOTTY; + } + + iocmd = (struct ata_cmd *) vp; + if (iocmd == NULL) { + log(LOG_INFO, "aoe: aoeblk_ioctl: NULL arg ptr.\n"); + return EINVAL; + } + + if (iocmd->cmd != ATAREQUEST) { + log(LOG_INFO, "aoe: aoeblk_ioctl: unknown iocmd->cmd=%d\n", iocmd->cmd); + return ENOTTY; + } + + if (iocmd->u.request.count) { + if (iocmd->u.request.data == NULL) { + log(LOG_INFO, "aoe: aoeblk_ioctl: null return data pointer\n"); + return EINVAL; + } + iocmd->u.request.count = 512; + iocmd->u.request.u.ata.count = 1; + } + + d = disk->d_drv1; + mtx_lock(&d->mtx); + if ((d->flags & DEVFL_UP) == 0) { + log(LOG_INFO, "aoe: aoeblk_ioctl: device for unit %ld is not up.\n", d->unit); + mtx_unlock(&d->mtx); + return ENXIO; + } + + switch (iocmd->u.request.u.ata.command) { + case ATA_ATA_IDENTIFY: + copyout(d->ident, iocmd->u.request.data, sizeof d->ident); + mtx_unlock(&d->mtx); + return 0; + case ATA_SMART: + if (iocmd->u.request.u.ata.feature != ATA_SMART_ATTR_AUTOSAVE) { + n = aoecmd_ata_smart(d, iocmd); + mtx_unlock(&d->mtx); + return n; + } + default: + mtx_unlock(&d->mtx); + log(LOG_INFO, "aoe: aoeblk_ioctl: unallowed ata command; " + "cmd=%2.2X feat=%2.2X.\n", + iocmd->u.request.u.ata.command, + iocmd->u.request.u.ata.feature); + return EINVAL; + } +} + +static void +disk_create_task(void *ctx, int useless) +{ + struct disk *disk; + Aoedev *d; + + d = (Aoedev *) ctx; + + disk = disk_alloc(); /* Disk_destroy triggers freeing the allocated disk. */ + if (disk == NULL) { + log(LOG_INFO, "aoe: disk_create_task: cannot alloc disk structure.\n"); + mtx_lock(&d->mtx); + d->flags &= ~DEVFL_TASKON; + mtx_unlock(&d->mtx); + return; + } + + d->disk = disk; + disk->d_drv1 = d; + disk->d_maxsize = DFLTPHYS; + disk->d_sectorsize = DEV_BSIZE; + disk->d_mediasize = DEV_BSIZE * d->nsectors; + disk->d_unit = d->unit; + disk->d_name = "aoed"; + disk->d_open = aoeblk_open; + disk->d_close = aoeblk_close; + disk->d_ioctl = aoeblk_ioctl; + disk->d_strategy = aoeblk_strategy; + + disk_create(disk, DISK_VERSION_00); + + mtx_lock(&d->mtx); + d->flags &= ~DEVFL_TASKON; + d->flags |= DEVFL_UP; + mtx_unlock(&d->mtx); +} + +/* + * (1) If we are in closewait state the device has either + * failed or its identity has changed (eaddr, major, minor). + * We schedule a discovery in either case to give it a + * chance to reinitialize. + */ +static void +disk_destroy_task(void *ctx, int useless) +{ + Aoedev *d; + int flags; + + d = (Aoedev *) ctx; + + disk_destroy(d->disk); + + mtx_lock(&d->mtx); + d->disk = NULL; + flags = d->flags; + d->flags &= ~(DEVFL_TASKON|DEVFL_CLOSEWAIT); + mtx_unlock(&d->mtx); + + if (flags & DEVFL_CLOSEWAIT) /* (1) */ + aoecmd_cfg(d->major, d->minor); +} + +static int +runtask(task_fn_t fn, Aoedev *d) +{ + struct task *t; + int n; + + if (d->flags & DEVFL_TASKON) + return EBUSY; + + t = &d->task; + TASK_INIT(t, 0, fn, d); + + n = taskqueue_enqueue(taskqueue_thread, t); + if (n == 0) + d->flags |= DEVFL_TASKON; + return n; +} + +int +aoeblk_register(Aoedev *d) +{ + int n; + + n = runtask(disk_create_task, d); + if (n != 0) + log(LOG_INFO, "aoe: aoeblk_register: runtask failure.\n"); + return n; +} + +int +aoeblk_unregister(Aoedev *d) +{ + int n; + + n = runtask(disk_destroy_task, d); + if (n != 0) + log(LOG_INFO, "aoe: aoeblk_unregister: runtask failure.\n"); + return n; +} + diff -upr --new-file src/sys/dev/aoe/aoecmd.c src2/sys/dev/aoe/aoecmd.c --- src/sys/dev/aoe/aoecmd.c Thu Jan 1 00:00:00 1970 +++ src2/sys/dev/aoe/aoecmd.c Thu Dec 9 12:47:04 2004 @@ -0,0 +1,736 @@ +/* + * 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. */ + +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, "Space 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, &aoe_maxwait, 0, + sysctl_aoe_wc, "I", "AoE ATA device write cache enable / disable"); + +static void +nilfn(void *a, void *b) +{ +} + +/* Just alloc the mbuf and point to our data section. */ +static struct mbuf * +frame_mbufinit(Frame *f) +{ + static uint refcnt; + struct mbuf *m; + + m = m_gethdr(M_NOWAIT, 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_ext.ext_free = nilfn; + m->m_ext.ext_type = EXT_EXTREF; + m->m_ext.ref_cnt = &refcnt; + + return m; +} + +/* + * Leave the top bit clear so we have tagspace for userland. + * The bottom 16 bits are the xmit tick for rexmit/rttavg processing. + * We don't worry about collision with the special tag values + * because we clear the top bit. + */ +static int +newtag(Aoedev *d) +{ + register int n; + + n = (++d->lasttag & 0x7fff) << 16; + return n |= ticks & 0xffff; +} + +/* Initialize the Aoehdr for an ATA command. */ +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); + hnput16(h->type, AOE_ETYPE); + h->verfl = AOE_HVER; + hnput16(h->major, d->major); + h->minor = d->minor; + h->cmd = AOECMD_ATA; + hnput32(h->tag, n = newtag(d)); + return n; +} + +static Frame * +getframe(Aoedev *d, int tag) +{ + Frame *f, *e; + + f = d->frames; + e = f + d->nframes; + for (; ftag == tag) + return f; + return NULL; +} + +/* The standard read/write ATA command handler. */ +static void +aoecmd_ata_rw(Aoedev *d, Frame *f) +{ + Aoehdr *h; + Aoeahdr *ah; + struct bio *bp; + struct mbuf *m; + ulong bcnt; + register daddr_t sector; + char writebit, extbit; + + writebit = 0x10; + extbit = 0x4; + + bp = d->inprocess; + + /* Since we can't touch bio_pblkno we calc the current sector. */ + sector = ((char *) bp->bio_aoe_baddr - bp->bio_data) >> DEV_BSHIFT; + sector += bp->bio_pblkno; + + /* + * Limit amount sent by frame size. + * XXX: interface specific. + */ + bcnt = bp->bio_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->bio_cmd == BIO_READ) { + writebit = 0; + f->bioaddr = bp->bio_aoe_baddr; + } else { + ah->aflags |= AOEAFL_WRITE; + memcpy(ah+1, bp->bio_aoe_baddr, bcnt); + f->mlen += bcnt; + } + ah->cmdstat = ATA_READ | writebit | extbit; + + /* Now mark all our tracking fields and load out. */ + bp->bio_aoe_nbuflets = (void *) ((ulong) bp->bio_aoe_nbuflets + 1); + bp->bio_aoe_baddr = (void *) ((char *) bp->bio_aoe_baddr + bcnt); + bp->bio_resid -= bcnt; + if (bp->bio_resid == 0) /* We have satisfied strategy bio. */ + d->inprocess = NULL; + + 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; + Aoeahdr *ah; + + h = (Aoehdr *) f->data; + ah = (Aoeahdr *) (h+1); + +#ifdef AOE_DEBUG + + log(LOG_INFO, "aoe: rexmit: mlen=%ld verfl=%X major=%X minor=%X cmd=%X\n" + "\ttag=%lX aflags=%X errfeat=%X scnt=%X cmdstat=%X\n" + "\tlba0=%X lba1=%X lba2=%X lba3=%X lba4=%X lba5=%X\n", + f->mlen, h->verfl, nhget16(h->major), h->minor, h->cmd, + nhget32(h->tag), ah->aflags, ah->errfeat, ah->scnt, ah->cmdstat, + ah->lba0, ah->lba1, ah->lba2, ah->lba3, ah->lba4, ah->lba5); +#endif + + hnput32(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 n, ntx; + Aoedev *d = vp; + Frame *f, *e; + register int timeout; + + if (aoe_isexiting()) + return; + + mtx_lock(&d->mtx); + + /* Timeout is always ~150% of the moving average. */ + timeout = d->rttavg; + timeout += timeout >> 1; + ntx = 0; + + if (d->flags & DEVFL_TKILL) { +tdie: mtx_unlock(&d->mtx); + return; + } + f = d->frames; + e = f + d->nframes; + for (; ftag != FREETAG) + if (f->tag != INPROCTAG) + if (tsince(f->tag) >= timeout) { + n = f->waited += timeout; + n /= hz; + if (n > aoe_maxwait) { /* Waited too long. Device failure. */ + aoedev_downdev(d); + goto tdie; + } + ntx++; + rexmit(d, f); + } + } + if (ntx) { + n = d->rttavg <<= 1; + if (n > MAXTIMER) + d->rttavg = MAXTIMER; + } + callout_reset(&d->callout, TIMERTICK, rexmit_timer, d); + + mtx_unlock(&d->mtx); +} + +/* Command to send an ATA write cache update. */ +static void +aoecmd_ata_wc(Aoedev *d, Frame *f) +{ + Aoehdr *h; + Aoeahdr *ah; + struct mbuf *m; + + /* 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 per ATA6. */ + + 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); +} + +/* Command to send an ATA identify. */ +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 initializes 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; + enum { MAXFRAMES = 8 }; + + h = mtod(m, Aoehdr *); + ch = (Aoechdr *) (h+1); + + unit = AOEUNIT(nhget16(h->major), h->minor); + + bufcnt = nhget16(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"); + return; + } + + mtx_lock(&d->mtx); + + if (d->flags & (DEVFL_UP | DEVFL_CLOSEWAIT)) { + mtx_unlock(&d->mtx); + return; + } + + /* We get here only if the device is new. */ + aoecmd_ata_id(d); + + mtx_unlock(&d->mtx); +} + +void +aoecmd_work(Aoedev *d) +{ + struct bio *bp; + Frame *f; +loop: + f = getframe(d, FREETAG); + if (f == NULL) + return; + if (d->flags & DEVFL_WC_UPDATE) { + aoecmd_ata_wc(d, f); + d->flags &= ~DEVFL_WC_UPDATE; + goto loop; + } + if (d->inprocess == NULL) { + bp = bioq_first(&d->bioq); + if (bp == NULL) + return; + bioq_remove(&d->bioq, bp); + + switch (bp->bio_cmd) { + default: + log(LOG_INFO, "aoe: aoecmd_work: unknown bio op 0x%X\n", bp->bio_cmd); + biofinish(bp, NULL, EOPNOTSUPP); + goto loop; /* Yep, it sure is. */ + case BIO_READ: + case BIO_WRITE: + break; + } + + bp->bio_aoe_baddr = bp->bio_data; + bp->bio_aoe_nbuflets = 0; + bp->bio_resid = bp->bio_bcount; + d->inprocess = bp; + } + aoecmd_ata_rw(d, f); + goto loop; +} + +static void +ataid_complete(Aoedev *d, char *id) +{ + int n; + + memcpy(d->ident, id, sizeof d->ident); + + n = lhget16(id + (83<<1)); /* Command set supported. */ + if (n & (1<<10)) { /* Lba48 */ + d->flags |= DEVFL_EXT; + d->nsectors = lhget32(id + (100<<1)); /* n lba48 sectors. */ + } else { + d->flags &= ~DEVFL_EXT; + d->nsectors = lhget32(id + (60<<1)); /* n lba28 sectors. */ + } + if (aoeblk_register(d) != 0) + log(LOG_INFO, "aoe: ataid_complete: could not register disk\n"); +} + +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 bio *bp; + register long n; + + hin = mtod(m, Aoehdr *); + d = aoedev_byaddr(hin->src); + if (d == NULL) { + log(LOG_INFO, "aoe: aoecmd_ata_rsp: response for unknown device %d.%d\n", + nhget16(hin->major), hin->minor); + /* Maybe run a discover cfg on this eaddr? */ + return; + } + + mtx_lock(&d->mtx); + + f = getframe(d, nhget32(hin->tag)); + if (f == NULL) { + log(LOG_INFO, "aoe: aoecmd_ata_rsp: unsolicited response from %d.%d\n", + nhget16(hin->major), hin->minor); + /* Might indicate a too short timeout. */ + mtx_unlock(&d->mtx); + 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->bio_flags |= BIO_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) { + 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. */ + mtx_unlock(&d->mtx); + return; + } + memcpy(f->bioaddr, 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 %ld\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_complete(d, (char *) (ahin+1)); + d->flags |= DEVFL_WC_UPDATE; + break; + case ATA_SMART: + n = m->m_len; + if (n > sizeof f->data) + n = sizeof f->data; + memcpy(f->data, hin, n); + f->tag = INPROCTAG; + wakeup(d); + mtx_unlock(&d->mtx); + return; + default: + log(LOG_INFO, "aoe: aoecmd_ata_rsp: unrecognized ata " + "command %2.2Xh from %d.%d\n", ahout->cmdstat, + nhget16(hin->major), hin->minor); + } + } + + if (bp) { + bp->bio_aoe_nbuflets = (void *) ((ulong) bp->bio_aoe_nbuflets - 1); + if (bp->bio_aoe_nbuflets == 0) + if (bp->bio_resid == 0) + biodone(bp); + } + + f->bp = NULL; + f->tag = FREETAG; + aoecmd_work(d); + + mtx_unlock(&d->mtx); +} + +/* 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_gethdr(M_NOWAIT, MT_DATA); + if (m0 == NULL) { + log(LOG_INFO, "aoe: aoecmd_cfg: mget failure\n"); + return; + } + m0->m_len = sizeof *h + sizeof *ch; + m0->m_pkthdr.len = m0->m_len; + 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); + hnput16(h->type, AOE_ETYPE); + h->verfl = AOE_HVER; + hnput16(h->major, major); + h->minor = minor; + h->cmd = AOECMD_CFG; + + s = splimp(); + TAILQ_FOREACH(ifp, &ifnet, if_link) { + if (!isaoeif(ifp)) + 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); +} + +/* Send an ATA smart command set up from ioctl. */ +int +aoecmd_ata_smart(Aoedev *d, struct ata_cmd *iocmd) +{ + Frame *f; + Aoehdr *h; + Aoeahdr *ah; + struct mbuf *m; + register daddr_t lba; + int timeout; + + timeout = iocmd->u.request.timeout; + + while ((f = getframe(d, FREETAG)) == NULL) { + msleep(d, &d->mtx, 0, "aoesmt", hz>>1); + timeout -= hz>>1; + if (timeout < 0) { + log(LOG_INFO, "aoe: aoecmd_smart: frame access timeout\n"); + return EIO; + } + } + + /* 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 = iocmd->u.request.u.ata.command; + ah->scnt = iocmd->u.request.u.ata.count; + ah->errfeat = iocmd->u.request.u.ata.feature; + lba = iocmd->u.request.u.ata.lba; + ah->lba0 = lba; + ah->lba1 = lba >>= 8; + ah->lba2 = lba >>= 8; + ah->lba3 = lba >>= 8; + + m = frame_mbufinit(f); + if (m == NULL) + log(LOG_INFO, "aoe: aoecmd_smart: mbuf init failure\n"); + else + ether_output_frame(d->ifp, m); + + if (msleep(d, &d->mtx, 0, "aoesmt", timeout) == EWOULDBLOCK) { + f->tag = FREETAG; + log(LOG_INFO, "aoe: aoecmd_smart: command timeout\n"); + return EIO; + } + + /* At this point, response has been copied over request. */ + iocmd->u.request.u.ata.command = ah->cmdstat; + iocmd->u.request.u.ata.feature = ah->errfeat; + iocmd->u.request.u.ata.count = ah->scnt; + + lba = ah->lba3 << 24; + lba |= ah->lba2 << 16; + lba |= ah->lba1 << 8; + lba |= ah->lba0; + iocmd->u.request.u.ata.lba = lba; + + if (iocmd->u.request.flags == ATA_CMD_READ) + copyout(ah+1, iocmd->u.request.data, iocmd->u.request.count); + + f->tag = FREETAG; + return 0; +} + +/* 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 err, n; + + 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; +} + diff -upr --new-file src/sys/dev/aoe/aoedev.c src2/sys/dev/aoe/aoedev.c --- src/sys/dev/aoe/aoedev.c Thu Jan 1 00:00:00 1970 +++ src2/sys/dev/aoe/aoedev.c Thu Dec 9 12:47:56 2004 @@ -0,0 +1,300 @@ +/* + * 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 struct mtx devlist_mtx; +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, ulong unit) +{ + Aoedev *d; + Frame *f, *e; + char buf[16]; + + d = (Aoedev *) malloc(sizeof *d, M_AOEDEV, M_NOWAIT | M_ZERO); + if (d == NULL) + return NULL; + f = (Frame *) malloc(nframes * sizeof *f, M_AOEFRAME, M_NOWAIT | M_ZERO); + 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, 1); + bioq_init(&d->bioq); + snprintf(buf, sizeof buf, "aoed%ld", unit); + mtx_init(&d->mtx, buf, NULL, MTX_DEF); + + mtx_lock(&devlist_mtx); + d->next = devlist; + devlist = d; + mtx_unlock(&devlist_mtx); + + return d; +} + +void +aoedev_freedev(Aoedev *d) +{ + free(d->frames, M_AOEFRAME); + mtx_destroy(&d->mtx); + free(d, M_AOEDEV); +} + +void +aoedev_downdev(Aoedev *d) +{ + Frame *f, *e; + struct bio *bp; + + d->flags |= DEVFL_TKILL; + callout_stop(&d->callout); + + f = d->frames; + e = f + d->nframes; + for (; ftag != FREETAG) { + if ((bp = f->bp)) { + bp->bio_error = EIO; + bp->bio_flags |= BIO_ERROR; + bp->bio_aoe_nbuflets = (void *) ((ulong) bp->bio_aoe_nbuflets - 1); + if (bp->bio_aoe_nbuflets == 0) + biodone(bp); + } + f->tag = FREETAG; + f->bp = NULL; + } + } + d->inprocess = NULL; + + bioq_flush(&d->bioq, NULL, EIO); + + if (d->flags & DEVFL_OPEN) + d->flags |= DEVFL_CLOSEWAIT; + else if (d->flags & DEVFL_UP && aoeblk_unregister(d)) { + log(LOG_INFO, "aoe: aoedev_downdev: Can't unregister disk. " + "Expect buggy behaviour.\n"); + } + 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; + + mtx_lock(&devlist_mtx); + for (d=devlist; d; d=d->next) + if (d->unit == unit + || memcmp(d->addr, addr, sizeof d->addr) == 0) + break; + mtx_unlock(&devlist_mtx); + + if (d == NULL) { + d = aoedev_newdev(bufcnt, unit); + if (d == NULL) { + log(LOG_INFO, "aoe: aoedev_set: aoedev_newdev failure.\n"); + return NULL; + } + } + + mtx_lock(&d->mtx); + + 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); + } + + mtx_unlock(&d->mtx); + return d; +} + +Aoedev * +aoedev_byaddr(char *addr) +{ + Aoedev *d; + + mtx_lock(&devlist_mtx); + for (d=devlist; d; d=d->next) + if (memcmp(d->addr, addr, sizeof d->addr) == 0) + break; + mtx_unlock(&devlist_mtx); + + return d; +} + +Aoedev * +aoedev_byunit(ulong unit) +{ + Aoedev *d; + + mtx_lock(&devlist_mtx); + for (d=devlist; d; d=d->next) + if (d->unit == unit) + break; + mtx_unlock(&devlist_mtx); + + return d; +} + +int +aoedev_busy(void) +{ + Aoedev *d; + enum { BUSYFLAGS = DEVFL_OPEN | DEVFL_TASKON }; + + mtx_lock(&devlist_mtx); + d = devlist; + for (; d; d=d->next) { + mtx_lock(&d->mtx); + if (d->flags & BUSYFLAGS) { + mtx_unlock(&d->mtx); + mtx_unlock(&devlist_mtx); + return 1; + } + mtx_unlock(&d->mtx); + } + mtx_unlock(&devlist_mtx); + return 0; +} + +/* approach taken from vm/uma_core.c */ +static int +sysctl_aoe_devices(SYSCTL_HANDLER_ARGS) +{ + char *buf; + Aoedev *d; + register int n; + enum { LINESZ = 64 }; + + mtx_lock(&devlist_mtx); + if (devlist == NULL) { + mtx_unlock(&devlist_mtx); + return SYSCTL_OUT(req, "\0", 1); + } + + n = 0; + for (d=devlist; d; d=d->next) + n += LINESZ; + buf = (char *) malloc(n+1, M_TEMP, M_NOWAIT | M_ZERO); + if (buf == NULL) { + log(LOG_INFO, "aoe: sysctl_aoe_devices: could not malloc " + "buffer size %d to print device list\n", n); + mtx_unlock(&devlist_mtx); + return ENOMEM; + } + + n = 0; + for (d=devlist; d; d=d->next) { + n += snprintf(buf+n, LINESZ, "\naoed%-6ld\t%s\t%s%s%s", + d->unit, + d->ifp->if_xname, + (d->flags & DEVFL_UP) ? "UP" : "DOWN", + (d->flags & DEVFL_OPEN) ? ",OPEN" : "", + (d->flags & DEVFL_CLOSEWAIT) ? ",CLOSEWAIT" : ""); + } + mtx_unlock(&devlist_mtx); + + n = SYSCTL_OUT(req, buf, n+1); + free(buf, M_TEMP); + return n; +} + +/* + * Flag devices for update. Accomplished on next call to + * individual aoecmd_work(). + */ +void +aoedev_wc_update(void) +{ + Aoedev *d; + + mtx_lock(&devlist_mtx); + for (d=devlist; d; d=d->next) { + mtx_lock(&d->mtx); + d->flags |= DEVFL_WC_UPDATE; + mtx_unlock(&d->mtx); + } + mtx_unlock(&devlist_mtx); +} + +void +aoedev_init(void) +{ + mtx_init(&devlist_mtx, "AoE devlist mutex", NULL, MTX_DEF); +} + +void +aoedev_exit(void) +{ + Aoedev *d; + + while ((d = devlist)) { + devlist = d->next; + mtx_lock(&d->mtx); + aoedev_downdev(d); + mtx_unlock(&d->mtx); + + callout_drain(&d->callout); + while (d->flags & DEVFL_TASKON) + tsleep(d, 0, "aoeunl", hz>>1); + aoedev_freedev(d); + } + mtx_destroy(&devlist_mtx); +} + diff -upr --new-file src/sys/dev/aoe/aoenet.c src2/sys/dev/aoe/aoenet.c --- src/sys/dev/aoe/aoenet.c Thu Jan 1 00:00:00 1970 +++ src2/sys/dev/aoe/aoenet.c Thu Dec 9 12:52:19 2004 @@ -0,0 +1,104 @@ +/* + * 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 + +struct ifqueue aoeintrq; + +static char *aoe_errlist[] = +{ + "no such error", + "unrecognized command code", + "bad argument parameter", + "device unavailable", + "config string present", + "unsupported version" +}; + +/* (1) The tag high bit is not permitted to be set for our responses. */ +static void +aoeintr(struct mbuf *m) +{ + Aoehdr *h; + uint32_t n; + + if (aoe_isexiting()) { + m_freem(m); + return; + } + + do { + if (!isaoeif(m->m_pkthdr.rcvif)) + break; + + h = mtod(m, Aoehdr *); + n = nhget32(h->tag); + if ((h->verfl & AOEFL_RSP) == 0 || (n & 1<<31)) /* (1) */ + break; + 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", + nhget16(h->major), h->minor, h->err, aoe_errlist[n]); + break; + } + + 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); + } + } while (0); + + m_freem(m); +} + +void +aoenet_init(void) +{ + aoeintrq.ifq_maxlen = IFQ_MAXLEN; + mtx_init(&aoeintrq.ifq_mtx, "aoe_inq", NULL, MTX_DEF); + netisr_register(NETISR_AOE, aoeintr, &aoeintrq, NETISR_MPSAFE); +} + +void +aoenet_exit(void) +{ + netisr_unregister(NETISR_AOE); + mtx_destroy(&aoeintrq.ifq_mtx); +} + diff -upr --new-file src/sys/dev/aoe/aoeutils.c src2/sys/dev/aoe/aoeutils.c --- src/sys/dev/aoe/aoeutils.c Thu Jan 1 00:00:00 1970 +++ src2/sys/dev/aoe/aoeutils.c Thu Dec 9 12:48:55 2004 @@ -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/aoeutils.c,v 1.23.2.5 2004/09/22 16:50:41 ?? Exp $ + */ + +#include + +uint16_t +nhget16(uchar *p) +{ + uint16_t n; + + n = p[0]; + n <<= 8; + return n |= p[1]; +} + +uint32_t +nhget32(uchar *p) +{ + uint32_t n; + + n = nhget16(p); + n <<= 16; + return n |= nhget16(p+2); +} + +void +hnput16(uchar *p, uint16_t n) +{ + p[1] = n; + p[0] = n >>= 8; +} + +void +hnput32(uchar *p, uint32_t n) +{ + hnput16(p+2, n); + hnput16(p, n >>= 16); +} + +uint16_t +lhget16(uchar *p) +{ + uint16_t n; + + n = p[1]; + n <<= 8; + return n |= p[0]; +} + +uint32_t +lhget32(uchar *p) +{ + uint32_t n; + + n = lhget16(p+2); + n <<= 16; + return n |= lhget16(p); +} + +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 +isaoeif(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: + break; + } + + snprintf(ifname, sizeof ifname, "%s", ifp->if_xname); + 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; +} + diff -upr --new-file src/sys/dev/aoe/if_aoe.h src2/sys/dev/aoe/if_aoe.h --- src/sys/dev/aoe/if_aoe.h Thu Jan 1 00:00:00 1970 +++ src2/sys/dev/aoe/if_aoe.h Tue Dec 7 17:13:50 2004 @@ -0,0 +1,96 @@ +/* + * 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, +}; + +#define uchar unsigned char + +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]; +}; + +#undef uchar + diff -upr --new-file src/sys/modules/Makefile src2/sys/modules/Makefile --- src/sys/modules/Makefile Fri Nov 5 18:33:59 2004 +++ src2/sys/modules/Makefile Fri Nov 5 19:14:02 2004 @@ -18,6 +18,7 @@ SUBDIR= ${_3dfx} \ ${_amd} \ amr \ an \ + aoe \ ${_aout} \ ${_apm} \ ${_ar} \ diff -upr --new-file src/sys/modules/aoe/Makefile src2/sys/modules/aoe/Makefile --- src/sys/modules/aoe/Makefile Thu Jan 1 00:00:00 1970 +++ src2/sys/modules/aoe/Makefile Fri Nov 5 19:14:02 2004 @@ -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 diff -upr --new-file src/sys/net/ethernet.h src2/sys/net/ethernet.h --- src/sys/net/ethernet.h Wed Jun 2 21:34:14 2004 +++ src2/sys/net/ethernet.h Fri Nov 5 19:19:50 2004 @@ -319,6 +319,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 */ diff -upr --new-file src/sys/net/if_ethersubr.c src2/sys/net/if_ethersubr.c --- src/sys/net/if_ethersubr.c Fri Nov 5 18:34:24 2004 +++ src2/sys/net/if_ethersubr.c Fri Nov 5 19:14:02 2004 @@ -726,6 +726,9 @@ post_stats: m_freem(m); } return; + case ETHERTYPE_AOE: + netisr_dispatch(NETISR_AOE, m); + return; } /* Strip off Ethernet header. */ diff -upr --new-file src/sys/net/netisr.h src2/sys/net/netisr.h --- src/sys/net/netisr.h Wed Jun 9 02:48:23 2004 +++ src2/sys/net/netisr.h Fri Nov 5 19:14:02 2004 @@ -55,6 +55,7 @@ #define NETISR_ATALK2 16 /* Appletalk phase 2 */ #define NETISR_ATALK1 17 /* Appletalk phase 1 */ #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 26 /* PPP soft interrupt */