aoetools-36/0000755000076500007640000000000012203276036012436 5ustar ecashinbuildaoetools-36/aoeping.80000644000076500007640000001112012026614322014141 0ustar ecashinbuild.TH aoeping 8 .SH NAME aoeping \- simple communication with AoE device .SH SYNOPSIS .B aoeping [options] {shelf} {slot} {netif} .fi .SH DESCRIPTION The .IR aoeping (8) program performs simple one or two-round-trip communication with an ATA over Ethernet (AoE) device. It creates and receives AoE packets directly, using raw network sockets. .PP Running .IR aoeping (8) without command line arguments will result in a short usage summary being displayed. .PP The .IR aoeping (8) program will wait forever if it doesn't receive an expected response. The caller should use a time out to catch this situation. .SS Arguments .TP \fBshelf\fP This should be the shelf address (major AoE address) of the AoE device to communicate with. .TP \fBslot\fP This should be the slot address (minor AoE address) of the AoE device to communicate with. .TP \fBnetif\fP The name of the ethernet network interface to use for AoE communications, e.g., eth1. .SS Options .TP \fB-i\fP Issue an ATA "identify device" command after receiving the AoE device's Config Query response. The "ident" response will be printed on standard output as a hexidecimal dump. .TP \fB-I\fP Issue an ATA "identify device" command after receiving the AoE device's Config Query response. The "ident" response will be pretty-printed on standard output as selected human-readable fields. .TP \fB-v\fP Turn on more copious output, including a hexidecimal dump of the Config Query response from the AoE device (see AoE spec at URL below). .TP \fB-s\fP This option takes an argument. The argument is a decimal integer that specifies the number of seconds that .IR aoeping (8) will wait for a response before timing out and exiting with a non-zero status. .TP \fB-S\fP This option takes an argument. The argument is the name of a SMART command to send to the disk. The SMART commands in the list below are supported. If the command requires data transfer, one sector (512 bytes) of data is always the amount transfered. If the command takes a parameter (for the Low LBA register), then the name of the SMART command is immediately followed by a colon and then a number, the value of the parameter, e.g., "-S read_log:1". .IP read_data offline_immediate read_log write_log enable disable return_status For \fBwrite_log\fP, .IR aoeping (8) reads from standard input the one sector of data to be written to the specified log. If the AoE device does not support SMART commands or if the command is aborted, an error message is printed to standard error and .IR aoeping (8) exits with a non-zero status. A command may be aborted if SMART is disabled on the device. The .IR aoeping (8) command just sends and receives SMART commands, without interpreting them. See the ATA specification for more information on using SMART. .LP .TP \fB-t\fP (This is an advanced feature.) This option has an argument. The argument is a decimal integer that is used as the initial tag, with the highest bit set, as the first tag in ATA commands. Tags for subsequent ATA commands will be incremented by one. .TP \fB-h\fP Show a usage summary. .SH EXAMPLE In this example, the root user uses .IR aoeping (8) to check for the presence of aoe device e10.9 on network interface eth0. .IP .EX .nf bash# aoeping -v 10 9 eth0 | head tag: 80000000 eth: eth0 shelf: 10 slot: 9 config query response: 00 0d 87 aa c9 00 00 10 04 00 11 1f 88 a2 18 00 00 0a 09 01 00 00 00 00 00 03 30 08 00 10 00 04 66 6f 6f 0a 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff .fi .EE .LP The next example shows root making sure the disk on the e10.9 is still responsive by issuing an ATA device identify command with a 20-second timeout. .IP .EX .nf bash# aoeping -i -s 20 \\ 10 9 eth0 > /dev/null \\ && echo ok ok .fi .EE .LP The next example uses SMART to determine whether the disk on e10.9 thinks it has exceeded its error threshold. The ATA spec says that the LBA Mid register will be 0x4f when the disk has not exceeded its error threshold. .IP .EX .nf bash# aoeping -S return_status \\ 10 9 eth0 | grep 'LBA Mid: 0x4f' \\ > /dev/null \\ && echo ok ok .fi .EE .LP Note that in a script, it would be prudent to specify and handle a timeout. Also, a good script would make sure the \fBStatus\fP register does not have the error bit (bit zero) or the device fault bit (bit 5) set. .SH "SEE ALSO" .IR aoe-discover (8), .IR aoe-interfaces (8), .IR aoe-mkdevs (8), .IR aoe-mkshelf (8), .IR aoe-stat (8), \fIAoE (ATA over Ethernet)\fP: http://support.coraid.com/documents/AoEr10.txt, \fIATA specification\fP .SH AUTHOR Ed L. Cashin (ecashin@coraid.com) aoetools-36/HACKING0000644000076500007640000000171712026614322013430 0ustar ecashinbuildContributing Thanks for your interest in contributing to the aoetools. The best way to submit proposed changes is in plain-text "patches". These patches are generated by the diff program. Patches should be clean (to the point and easy to read) and should do one thing. Send multiple patches if necessary. Patches should be generated with "diff -uprN" if possible, and should be designed to be applied with "patch -p1". Design note: The aoe-mkdevs and aoe-mkshelf scripts are expected to work with special device files forever, but the aoe-discover script will likely someday use sysfs or something similar instead of /dev/etherd/discover. The same goes for aoe-interfaces. For that reason, there is no runtime interface for giving aoe-discover an alternative to /dev/etherd at runtime. Instead, the device directory is set once and for all by make. That way, the user interface won't change or become obsolete when aoe-discover stops using /dev/etherd/discover. aoetools-36/aoeping.c0000644000076500007640000002331312026614322014223 0ustar ecashinbuild/* aoeping.c - userland aoe pinger * Copyright 2009, CORAID, Inc., and licensed under GPL v.2. * * run without arguments for usage */ #include #include #include #include #include #include #include #include #include #include "dat.h" #include "fns.h" struct progopts { int shelf; int slot; char *netif; int verbose; int timeout; u32 tag; char *smart; char ata_ident; char pp_ataid; /* pretty print ATA device identify response */ }; static struct progopts defaults = { .shelf = 0, .slot = 0, .netif = NULL, .verbose = 0, .timeout = 0, .tag = 0, .smart = NULL, .ata_ident = 0, .pp_ataid = 0, }; static struct progopts opts; struct smartcmd { char *name; /* subcommand name from ATA spec */ int cmd; /* for features register */ char data; /* does this subcommand xfer data? */ }; static struct smartcmd smarts[] = { { "read_data", 0xd0, SmartDataRet }, // { "attr_autosave", 0xd2, 0 }, (unsupported b/c it overloads sector count) { "offline_immediate", 0xd4, 0 }, { "read_log", 0xd5, SmartDataRet }, { "write_log", 0xd6, SmartDataPut }, { "enable", 0xd8, 0 }, { "disable", 0xd9, 0 }, { "return_status", 0xda, 0 }, }; static char *progname; static int sfd; /* raw socket file descriptor */ static uchar mac[6]; void usage(void) { fprintf(stderr, "usage:\t%s [options] {shelf} {slot} {netif}\n", progname); fprintf(stderr, "%s\n\t%s\n\t%s\n\t%s\n\t%s\n", "options:", "-i\tdo ATA device identify dump as raw hex", "-I\tdo ATA device identify print fields", "-v\tbe verbose", "-h\tshow this usage summary"); fprintf(stderr, "%s\n\t%s\n\t%s\n\t%s\n", "options taking arguments:", "-s\ttimeout in seconds", "-S\tperform SMART command", "-t\tspecify number for starting AoE tag"); } void hex_print(FILE *out, uchar *buf, int n, char *sep) { int i; int per_line = 16; for (i = 0; i < n;) { fprintf(out, "%02x%s", *buf++ & 0xff, sep); if (!(++i % per_line)) putc('\n', out); } } void find_blade(Conf *c, struct progopts *opts) { int n; uchar buf[1400]; u32 tag; Aoehdr *h = &c->h; memset(h, 0, sizeof *h); memset(h->dst, 0xff, sizeof h->dst); memmove(h->src, mac, sizeof h->src); h->type = htons(AOE_ETH_PROTO); h->flags = AoEver << 4; h->maj = htons(opts->shelf); h->min = opts->slot; h->cmd = Config; tag = htonl(opts->tag); memmove(h->tag, &tag, sizeof h->tag); c->bufcnt = 0; c->firmware = 0; c->scnt = 0; c->vercmd = Qread; c->len = htons(1024); memset(c->data, 0xED, sizeof c->data); if (write(sfd, c, sizeof *c) == -1) { perror("send config query"); exit(EXIT_FAILURE); } for (;;) { n = read(sfd, buf, sizeof buf); if (n < 0) { perror("read network"); exit(EXIT_FAILURE); } if (n < 60) continue; h = (Aoehdr *) buf; if (ntohs(h->type) != AOE_ETH_PROTO || ntohs(h->maj) != opts->shelf || h->min != opts->slot || memcmp(h->tag, &tag, sizeof h->tag)) continue; break; } if (opts->verbose) { puts("config query response:"); hex_print(stdout, buf, n, " "); putchar('\n'); } memcpy(c, buf, sizeof *c); } /* read a packet that was sent by the device that returned *c earlier */ int aoe_pkt_read(uchar *buf, size_t siz, Conf *c, u32 tag) { Aoehdr *h; int n; tag = htonl(tag); for (;;) { n = read(sfd, buf, siz); if (n < 0) { perror("read network"); exit(EXIT_FAILURE); } if (n < 60) continue; h = (Aoehdr *) buf; if (ntohs(h->type) != AOE_ETH_PROTO || h->maj != c->h.maj || h->min != c->h.min || memcmp(&tag, h->tag, sizeof h->tag)) continue; break; } return n; } /* prepare a packet for doing ATA to a device that gave us Conf *c */ void ata_prep(Ata *a, Conf *c, u32 tag) { memset(a, 0, sizeof *a); memcpy(a->h.dst, c->h.src, sizeof a->h.dst); memcpy(a->h.src, mac, sizeof a->h.src); a->h.type = htons(AOE_ETH_PROTO); a->h.flags = AoEver << 4; a->h.maj = c->h.maj; a->h.min = c->h.min; a->h.cmd = ATAcmd; tag = htonl(tag); memmove(a->h.tag, &tag, sizeof a->h.tag); } /* pretty print ATA device identify text field * bytes have already been swapped */ void pp_idtext(char *prefix, unsigned char *p, size_t len) { int i; fputs(prefix, stdout); for (i = 0; i < len; ++i, ++p) { if (*p == '\0') break; if (!isgraph((int) *p) && *p != ' ') break; putchar(*p); } putchar('\n'); } int smart_supported(unsigned char *p) { u16 w; p += 82 * 2; /* skip to word 82 */ w = *p++; w |= *p << 8; /* word 82 bit 0 is SMART support per ATA spec */ return !!(w & 1); } void disk_identify(Conf *c, struct progopts *opts, int *smart) { int n; uchar buf[1400]; Ata a; Ata *p; struct hd_driveid *id; ata_prep(&a, c, opts->tag); a.sectors = 1; a.cmd = ATAid_dev; a.lba[3] = 0xa0; if (write(sfd, &a, sizeof a) == -1) { perror("send ATA identify device"); exit(EXIT_FAILURE); } n = aoe_pkt_read(buf, sizeof buf, c, opts->tag); p = (Ata *) buf; *smart = smart_supported(p->data); if (opts->ata_ident && !opts->pp_ataid) { puts("device identify response:"); hex_print(stdout, p->data, 512, " "); return; } if (!opts->pp_ataid) return; for (n = 0; n < 1024; n += 2) { unsigned char ch; ch = p->data[n]; p->data[n] = p->data[n+1]; p->data[n+1] = ch; } id = (struct hd_driveid *) p->data; puts("device identify fields:"); printf("vendor_specific_0: 0x%X\n", id->vendor0); printf("vendor_specific_1: 0x%X\n", id->vendor1); printf("vendor_specific_2: 0x%X\n", id->vendor2); pp_idtext("serial_number: ", id->serial_no, sizeof id->serial_no); pp_idtext("firmware_rev: ", id->fw_rev, sizeof id->fw_rev); pp_idtext("model: ", id->model, sizeof id->model); } struct smartcmd * smartcmd_lookup(char *nam) { int n = sizeof smarts / sizeof smarts[0]; int i; for (i = 0; i < n; ++i) { char *p = strchr(nam, ':'); if (p && !strncmp(smarts[i].name, nam, p - nam)) return &smarts[i]; else if (!strcmp(smarts[i].name, nam)) return &smarts[i]; } return nil; } void smart_registers(Ata *a, char *opts, struct smartcmd *s) { a->err = s->cmd; a->lba[1] = 0x4f; a->lba[2] = 0xc2; if (opts++) a->lba[0] = strtol(opts, NULL, 0); } int show_smart_regs(Ata *a) { if (a->err & ATAabrt) { fputs("SMART command aborted on target.\n", stderr); return -1; } puts("ATA registers:"); char *names[] = { "Features", "Sector Count", "LBA Low", "LBA Mid", "LBA High", "Status", }; int regs[] = { a->err, a->sectors, a->lba[0], a->lba[1], a->lba[2], a->cmd, }; int i; for (i = 0; i < sizeof regs / sizeof regs[0]; ++i) printf("%20s: 0x%02x\n", names[i], regs[i]); return 0; } void smart(Conf *c, u32 tag, char *smart_cmd) { int n; uchar buf[1400]; Ata a; Ata *p; struct smartcmd *s = smartcmd_lookup(smart_cmd); if (!s) { fprintf(stderr, "%s Error: no such SMART command: %s\n", progname, smart_cmd); exit(EXIT_FAILURE); } ata_prep(&a, c, tag); a.sectors = !!s->data; /* we only support one-sector data xfer */ a.cmd = ATAsmart; smart_registers(&a, strchr(smart_cmd, ':'), s); if (s->data & SmartDataPut) { if (read(STDIN_FILENO, a.data, 512) == -1) { perror("reading smart data from stdin"); exit(EXIT_FAILURE); } a.h.flags |= Write; } if (write(sfd, &a, sizeof a) == -1) { perror("send ATA identify device"); exit(EXIT_FAILURE); } n = aoe_pkt_read(buf, sizeof buf, c, tag); p = (Ata *) buf; if (show_smart_regs(p) != 0) exit(EXIT_FAILURE); if (s->data & SmartDataRet) { puts("SMART data:"); hex_print(stdout, p->data, 512, " "); } } void bad_option(char c) { fprintf(stderr, "%s Error: unrecognized option: ", progname); if (isprint(c)) fprintf(stderr, "%c\n", c); else fprintf(stderr, "0x%02x\n", c & 0xff); } void check_timeout(int secs) { if (secs < 1) { fprintf(stderr, "%s Error: timeout seconds must be one or more\n", progname); exit(EXIT_FAILURE); } } void init_opts(struct progopts *opts, int argc, char *argv[]) { int c; while ( (c = getopt(argc, argv, "hviIt:s:S:")) != -1) { switch (c) { case 'h': usage(); exit(EXIT_SUCCESS); break; case 'v': ++opts->verbose; break; case 'i': opts->ata_ident = 1; break; case 'I': opts->ata_ident = 1; opts->pp_ataid = 1; break; case 't': opts->tag = atoi(optarg); break; case 's': opts->timeout = atoi(optarg); check_timeout(opts->timeout); break; case 'S': opts->smart = optarg; break; case '?': bad_option(optopt); usage(); exit(EXIT_FAILURE); break; default: abort(); /* shouldn't happen */ } } if (argc - optind != 3) { usage(); exit(EXIT_FAILURE); } opts->shelf = atoi(argv[optind]); opts->slot = atoi(argv[optind+1]); opts->netif = argv[optind+2]; } int main(int argc, char *argv[]) { Conf c; int smartable = 0; opts = defaults; progname = strrchr(argv[0], '/'); if (progname) progname += 1; else progname = argv[0]; init_opts(&opts, argc, argv); opts.tag |= 1UL << 31; /* set high bit for userland AoE */ if (opts.verbose) { printf("tag: %x\neth: %s\nshelf: %u\nslot: %u\n", opts.tag, opts.netif, opts.shelf, opts.slot); fflush(stdout); } sfd = dial(opts.netif); if (!getea(sfd, opts.netif, mac)) exit(EXIT_FAILURE); alarm(opts.timeout); find_blade(&c, &opts); opts.tag += 1; alarm(0); if (opts.verbose) { printf("found e%d.%d with mac ", ntohs(c.h.maj), c.h.min); hex_print(stdout, c.h.src, sizeof c.h.src, ""); putchar('\n'); fflush(stdout); } if (opts.ata_ident || opts.smart) { alarm(opts.timeout); disk_identify(&c, &opts, &smartable); alarm(0); opts.tag += 1; } if (opts.smart) { if (!smartable) { fprintf(stderr, "Error: e%d.%d does not support SMART\n", ntohs(c.h.maj), c.h.min); exit(EXIT_FAILURE); } alarm(opts.timeout); smart(&c, opts.tag, opts.smart); alarm(0); opts.tag += 1; } return 0; } aoetools-36/devnodes.txt0000644000076500007640000000301112026614322014776 0ustar ecashinbuild Driver Compatibility Users of udev have device nodes like /dev/etherd/e0.0 created for them automatically, as needed. These are dynamic device nodes. The aoe driver version 50 and above use dynamic device node minor numbers in order to support a greater number of AoE devices. Some systems use static device nodes, which are present in /dev regardless of what AoE devices are really available to the system. The aoetools contain the aoe-mkdevs and aoe-mkshelf commands, which create these static device nodes. If the static device nodes do not match the static device minor numbers in the kernel, you could accidentally perform reads and writes to the wrong AoE device. (It really is easier to let udev take care of the device nodes.) If you use an aoe driver from the CORAID website (http://support.coraid.com/support/linux/) then just use the aoetools that come bundled with that deiver. If you don't have udev, make sure you always load the aoe module with the aoe_dyndevs=0 option for any driver version above 49. If you didn't get your aoe driver from the CORAID website, and you can't use udev, then here's what to do: * Of course, read the README file in the aoetools sources. * To use aoetools-8 and later with older 2.6 kernels (2.6.13 and earlier), build the aoetools with an extra parameter for "make", like this: make NPERSHELF=10 * Using aoetools-7 and earlier with newer kernels (2.6.14 and later) is not recommended. Other combinations should work with the default settings. aoetools-36/README0000644000076500007640000000416112026614322013315 0ustar ecashinbuildThe aoetools are programs that assist in using ATA over Ethernet on systems with version 2.6 and newer Linux kernels. Systems running 2.4 Linux kernels do not need and should not install the aoetools. The aoe driver for 2.4 kernels is self sufficient. Please see the aoetools manpage for a brief list of the tools. -------------------------------------------------------------------- AOE DRIVER COMPATIBILITY If you are using udev on your system, the aoe-mkdevs and aoe-mkshelf should not be used. Just let udev create device nodes for you. If you need to configure udev, its manpages, in conjunction with the example in the EtherDrive HOWTO FAQ, should help. If you are not using udev, it is important to ensure that the device nodes in /dev/etherd match the aoe driver. Please see devnodes.txt for information. -------------------------------------------------------------------- BUILDING THE AOETOOLS If you need to configure the software, look at the variables at the top of the Makefile. The defaults should work for most people. When using the defaults there's only one step to configure and install the aoetools software and documentation: make install You'll need sufficient permissions to install in the default locations if you haven't overridden them with your own locations. The aoe-sancheck tool depends on libpthread. If its header and library files are not present, the aoetools makefile skips aoe-sancheck. You can install your Linux distribution's "libpthread" and "libpthread-devel" packages (They might be called something slightly different) to help aoe-sancheck to build successfully. -------------------------------------------------------------------- LEGACY TOOLS These two are legacy commands for systems without udev. aoe-mkdevs create character and block device files aoe-mkshelf create block device files for one shelf address -------------------------------------------------------------------- RESOURCES The aoetools homepage http://aoetools.sourceforge.net/ The CORAID homepage http://www.coraid.com/ The Linux Support Page at CORAID http://support.coraid.com/support/linux/ aoetools-36/linux.c0000644000076500007640000000324412026614322013741 0ustar ecashinbuild/* linux.c: low level access routines for Linux * Copyright 2009, CORAID, Inc., and licensed under GPL v.2. */ #include "config.h" #include #include #include #include #include #include #include /* for the glibc version number */ #if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1 #include #include /* the L2 protocols */ #else #include #include #include /* The L2 protocols */ #endif #include #include #include #include #include #include #include "dat.h" #include "fns.h" static int getindx(int s, char *name) // return the index of device 'name' { struct ifreq xx; int n; strcpy(xx.ifr_name, name); n = ioctl(s, SIOCGIFINDEX, &xx); if (n == -1) return -1; return xx.ifr_ifindex; } int dial(char *eth) // get us a raw connection to an interface { int i; int n, s; struct sockaddr_ll sa; enum { aoe_type = 0x88a2 }; memset(&sa, 0, sizeof sa); s = socket(PF_PACKET, SOCK_RAW, htons(aoe_type)); if (s == -1) { perror("got bad socket"); return -1; } i = getindx(s, eth); sa.sll_family = AF_PACKET; sa.sll_protocol = htons(0x88a2); sa.sll_ifindex = i; n = bind(s, (struct sockaddr *)&sa, sizeof sa); if (n == -1) { perror("bind funky"); return -1; } return s; } int getea(int s, char *name, uchar *ea) { struct ifreq xx; int n; strcpy(xx.ifr_name, name); n = ioctl(s, SIOCGIFHWADDR, &xx); if (n == -1) { perror("Can't get hw addr"); return 0; } memmove(ea, xx.ifr_hwaddr.sa_data, 6); return 1; } aoetools-36/aoe-interfaces.in0000644000076500007640000000202612026614322015650 0ustar ecashinbuild#! /bin/sh # aoe-interfaces - set or list the allowed AoE network interfaces # Copyright 2009, CORAID, Inc., and licensed under GPL v.2. zero="`basename $0`" devf=@devdir@/interfaces sysf=/sys/module/aoe/parameters/aoe_iflist if test -z "$*"; then if test -r "$sysf"; then cat "$sysf" else # can't read from interfaces device false fi exit fi if test "$1" = "-c"; then shift if test "$#" != "0"; then echo "$zero Error: -c flag takes no arguments" 1>&2 exit 1 fi fi netifs="$*" err=no for i in $netifs; do test -d "/sys/class/net/$i" || { echo "$zero Error: \"$i\" is not a network interface" 1>&2 err=yes } done if test "$err" = "yes"; then exit 1 fi if test -w "$sysf"; then printf '%s\0' "$netifs" > "$sysf" else if test ! -w "$devf"; then echo 1>&2 "$zero: $devf does not exist or is not writeable." exit 1 fi if test ! -c "$devf"; then exec 1>&2 echo "$zero: $devf is not a character device file" echo "$zero: use udev or aoe-mkdevs to create it" exit 1 fi printf '%s\0' "$netifs" > "$devf" fi aoetools-36/aoe-version0000644000076500007640000000320012203211506014572 0ustar ecashinbuild#! /bin/sh # aoe-version - display versions of AoE-related software # Copyright 2013, CORAID, Inc., and licensed under GPL v.2. aoetools=36 # modinfo doesn't always work correctly when there is a file # in the current working directory called "aoe", but it's # not hard to change the current working directory. for wd in . / /sys /var/run /usr /proc /etc /home; do a=`{ cd "$wd" 2> /dev/null && test ! -r aoe && echo yes; } || echo no` if test "$a" = "yes"; then cd "$wd" break fi done # The aoe module isn't guaranteed to be in the location below, # but if we only try to use it when each of the directories # above was not usable, we shouldn't use the hard-coded location # often. aoe=aoe if test -r ./aoe; then aoe="/lib/modules/`uname -r`/kernel/drivers/block/aoe/aoe.ko" fi # standalone aoe drivers have a module parameter "version" installed="`modinfo \"$aoe\" 2>/dev/null | awk '/srcversion/ {next} /^parm:.*version:aoe module/ {print $NF; exit 0}'`" if test -z "$installed"; then # Recent kernels have a "version" of their own, so # they didn't want our module parameter, so we look # for that, too, in case user is using kernel.org driver. installed="`modinfo \"$aoe\" 2>/dev/null | awk '/^version:/ {print $NF; exit 0}'`" fi if test "$?" != "0" || test -z "$installed"; then installed="(unknown)" fi if test -d /sys/module/aoe; then running="`find /sys/module/aoe -name version | sed 1q | xargs cat`" if test "$?" != "0"; then running="(unknown)" fi else running="(none)" fi while read val desc; do printf "%22s:\t%s\n" "$desc" "$val" done <&2 $zero: $f does not exist or is not writeable. exit 1 fi if ! test -c $f; then exec 1>&2 echo "$zero: $f is not a character device file" echo "$zero: use udev or aoe-mkdevs to create it" exit 1 fi echo > $f aoetools-36/aoe-revalidate.in0000644000076500007640000000104212026614322015642 0ustar ecashinbuild#! /bin/sh # aoe-revalidate - ask aoe driver to query AoE target # Copyright 2009, CORAID, Inc., and licensed under GPL v.2. zero=`basename $0` f=@devdir@/revalidate if test -z "$*"; then echo 1>&2 Usage: $zero 'e{major}.{minor}' exit 1 fi if ! test -w $f; then echo 1>&2 $zero: $f does not exist or is not writeable exit 1 fi if ! test -c $f; then exec 1>&2 echo "$zero: $f is not a character device file" echo "$zero: use udev or aoe-mkdevs to create it" exit 1 fi echo "$*" > $f || { echo "$zero: revalidate failed" 1>&2 exit 1 } aoetools-36/sos-linux0000755000076500007640000000204312200517672014325 0ustar ecashinbuild#! /bin/sh me="`basename $0`" outf="$HOME/sos-`hostname`-`date +%Y%m%d-%H%M%S`.txt" if test "`whoami`" != "root"; then echo "$me: please run $me as root" 1>&2 exit 1 fi echo "$me: output file is $outf" exec > $outf exec 2>&1 set -x uname -a grep . /etc/*release* /etc/*version* | sed 50q find /sys/module/aoe -name version | xargs cat cat /proc/mounts aoe-version aoe-stat cat /proc/mdstat pvs ifconfig -a free dmesg | tail -n 50 lspci set +x for i in `aoe-stat | awk '{print $3}' | sed 's!,! !g'`; do echo ethtool -S $i done | sort | uniq | sh -x # top -b -n 1 # check for old-style sysfs-exported debug information, ignoring errors grep . /sys/block/etherd*/debug /dev/null # check for new-style debugfs-exported debug information, ignoring errors dmnt=/sys/kernel/debug didmount= mounted=`awk '$3=="debugfs"{print $2}' /proc/mounts` if test "x$mounted" = "x" && mount -t debugfs none "$dmnt"; then didmount="$dmnt" mounted="$dmnt" fi cd "$mounted"/aoe && grep . e[0-9]*.*[0-9] cd / if test "x$didmount" != "x"; then umount "$didmount" fi exit 0 aoetools-36/aoe-flush.in0000644000076500007640000000173712026614322014656 0ustar ecashinbuild#! /bin/sh # aoe-flush - ask aoe driver to forget about devices # Copyright 2009, CORAID, Inc., and licensed under GPL v.2. zero="`basename $0`" f="@devdir@/flush" spec="" if ! test -w "$f"; then echo 1>&2 "$zero: $f does not exist or is not writeable." exit 1 fi if ! test -c $f; then exec 1>&2 echo "$zero: $f is not a character device file" echo "$zero: use udev or aoe-mkdevs to create it" exit 1 fi # make sure that each device in the whitespace-separated # list exists verify_devs () { err="" for d; do aoe-stat | awk -vd="$d" '$1==d{print $1}' | test "`cat`" || { exec 2>&1 echo "$zero Error: \"$d\" is not an aoe device" err="$err $d" } done test ! "$err" } err="" if test "$1"; then if test "$1" = "-a"; then spec=all else spec="$*" verify_devs $spec || exit 1 fi for i in $spec; do printf "$i" > "$f" || { echo 1>&2 "$zero: flush failed" err="$err $i" } done else echo > "$f" || err=no_args fi if test "$err"; then exit 1 fi aoetools-36/aoe-flush.80000644000076500007640000000252212026614322014410 0ustar ecashinbuild.TH aoe-flush 8 .SH NAME aoe-flush \- flush the down devices out of the aoe driver .SH SYNOPSIS .nf .B aoe-flush [-a] .B aoe-flush dev1 [dev2 ...] .fi .SH DESCRIPTION The .I aoe-flush command tells the aoe driver to remove devices from the system and forget about them. Normally the aoe driver will remember all devices it has seen until the module is unloaded. By default, .I aoe-flush will only flush downed devices. With the \fB-a\fP flag all devices are candidates for removal. .PP .I aoe-flush will not remove devices that are in use. This includes devices in the closewait state or those in the process of being installed. .PP By specifying a series of specific aoe devices, e.g., \fBe7.0 e3.2\fP, it is possible to ask the aoe driver to forget these devices. This feature may be convenient after a temporary AoE target is no longer being used. .SH OPTIONS .TP \fB-a\fP The \fB-a\fP option tells the aoe driver to forget all unused devices. .SH EXAMPLE .EX .nf nai# aoe-stat | grep e12.0 e12.0 0.000GB eth1 down nai# aoe-flush nai# aoe-stat | grep e12.0 .fi .EE .SH BUGS Flushed devices may reappear when they are discovered by the periodic discovery beacon. .I aoe-discover may be used to force this behaviour. .SH "SEE ALSO" .IR aoe-stat (8), .IR aoe-discover (8), .IR aoetools (8). .SH AUTHOR Sam Hopkins (sah@coraid.com) aoetools-36/dat.h0000644000076500007640000000270412026614322013357 0ustar ecashinbuild/* dat.h - aoetools type definitions and macros * Copyright 2009, CORAID, Inc., and licensed under GPL v.2. */ #define nil NULL #define nelem(x) (sizeof(x)/sizeof((x)[0])) typedef unsigned char uchar; typedef struct Aoehdr Aoehdr; typedef struct Ata Ata; typedef struct Conf Conf; typedef struct Ataregs Ataregs; /* use C99's stdint.h for fixed-width types * * There's no guarantee an unsigned short is 16-bits wide, * but uint16_t is always correct. */ typedef uint64_t vlong; typedef uint32_t u32; typedef uint16_t u16; struct Ataregs { vlong lba; uchar cmd; uchar status; uchar err; uchar feature; uchar sectors; }; struct Aoehdr { uchar dst[6]; uchar src[6]; u16 type; uchar flags; uchar error; u16 maj; uchar min; uchar cmd; uchar tag[4]; }; struct Ata { Aoehdr h; uchar aflag; uchar err; uchar sectors; uchar cmd; uchar lba[6]; uchar resvd[2]; uchar data[1024]; }; struct Conf { Aoehdr h; u16 bufcnt; u16 firmware; uchar scnt; uchar vercmd; u16 len; uchar data[1024]; }; enum { AOE_ETH_PROTO = 0x88a2, AoEver = 1, ATAcmd = 0, // command codes Config, Resp = 1<<3, // flags Error = 1<<2, BadCmd = 1, BadArg, DevUnavailable, ConfigErr, BadVersion, Write = 1<<0, Async = 1<<1, Device = 1<<4, Extend = 1<<6, Qread = 0, Qtest, Qprefix, Qset, Qfset, Nretries = 3, ATAid_dev = 0xec, // ATA commands ATAsmart = 0xb0, ATAabrt = 0x4, // ATA error bits SmartDataPut = 0x01, SmartDataRet = 0x10, }; aoetools-36/sos-linux.80000644000076500007640000000076412026614322014474 0ustar ecashinbuild.TH sos-linux 8 .SH NAME sos-linux \- create file containing AoE-related information .SH SYNOPSIS .nf .B sos-linux .fi .SH DESCRIPTION The .I sos-linux script creates a dated output file in the home directory of the user running it. .PP The filename is printed on the standard output. .PP The file contains information about the local system that is likely to be relevant to its use as an AoE initiator. .SH "SEE ALSO" .IR aoe-stat (8), .IR aoetools (8). .SH AUTHOR Ed L. Cashin (ecashin@coraid.com) aoetools-36/aoe-stat.in0000755000076500007640000000366312026614322014513 0ustar ecashinbuild#! /bin/bash # aoe-stat - collate and present information about AoE storage # Copyright 2012, CORAID, Inc., and licensed under GPL v.2. set -e me=`basename $0` sysd=${sysfs_dir:-/sys} # printf "$format" device mac netif state # Suse 9.1 Pro doesn't put /sys in /etc/mtab #test -z "`mount | grep sysfs`" && { test ! -d "$sysd/block" && { echo "$me Error: sysfs is not mounted" 1>&2 exit 1 } checknode () { devname="$1" m_sysfs="$2" if test -b "@devdir@/$devname"; then m_node="`ls -l \"@devdir@/$devname\" | awk '{print $6}'`" test "$m_sysfs" = "$m_node" || { cat 1>&2 </dev/null | grep -v p` end; do # maybe ls comes up empty, so we use "end" test $d = end && continue test -r "$d/payload" && payload=yes done if test "$payload" = "yes"; then format="%10s %15s %10s %-5s %-14s\n" else format="%10s %15s %6s %-14s\n" fi for d in `ls -d $sysd/block/*e[0-9]*\.[0-9]* 2>/dev/null | grep -v p` end; do test $d = end && continue dev=`echo "$d" | sed 's/.*!//'` if test -r "$d"/dev; then minor="`awk -F: '{print $2}' \"$d/dev\"`" checknode "$dev" "$minor" else minor="$NA" fi sectors=`cat_or_NA "$d"/size` if test "$sectors" = "$NA"; then psize="$NA" else psize=$(((512000 * $sectors) / (1000 * 1000 * 1000))) psize=`printf "%04d\n" $psize | sed 's!\(...\)$!.\1!'`GB fi netif=`cat_or_NA "$d"/netif` state=`cat_or_NA "$d"/state` payload=`cat_or_NA "$d"/payload` if test "$payload" != "$NA"; then printf "$format" \ "$dev" \ "${psize}" \ "$netif" \ "$payload" \ "$state" else printf "$format" \ "$dev" \ "${psize}" \ "$netif" \ "$state" fi done | sort | grep $re aoetools-36/aoe-sancheck.c0000644000076500007640000003264512026614322015132 0ustar ecashinbuild/* Copyright Coraid, Inc. 2010. All Rights Reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define nelem(x) (sizeof(x)/sizeof((x)[0])) #define nil NULL #define vprintf(...) if (qflag) ; else fprintf(stderr, __VA_ARGS__) #define mintu(x) ((x) > 60 ? x : 60) typedef unsigned char uchar; typedef unsigned long ulong; typedef struct Aoe Aoe; typedef struct Qc Qc; typedef struct Ata Ata; typedef struct Lun Lun; typedef struct Eth Eth; typedef struct Targ Targ; typedef struct Mac Mac; struct Aoe { uchar dst[6]; uchar src[6]; uchar type[2]; uchar flags; uchar error; uchar major[2]; uchar minor; uchar cmd; uchar tag[4]; }; struct Qc { Aoe h; uchar bufcnt[2]; uchar firmware[2]; uchar scnt; uchar vercmd; uchar len[2]; // uchar data[1024]; }; struct Ata { Aoe h; uchar aflag; uchar err; uchar scnt; uchar cmd; uchar lba[6]; uchar res[2]; }; struct Lun { Lun *next; int state; char ea[6]; int major; int minor; int nsect; int maxsect; int id; }; struct Eth { Lun *luns; int fd; char *name; char ea[6]; int mtu; int up; uchar pkt[16*1024]; }; struct Targ { Targ *next; int major; int minor; }; struct Mac { Mac *next; char ea[6]; }; enum { Neth= 16, Nstack= 16*1024, Nws= 5, Lnew= 0, Lprobe, Arsp= (1<<3), Aerr= (1<<2), Cata= 0, Cqc= 1, ETaoe= 0x88a2, }; int ethlist(char **, int); int ethopen(Eth *); void *jcheck(void *); int jinput(Eth *); Lun *findlun(Eth *e, Aoe *a); void jprobe(Eth *e, Lun *lun); void printlist(void); void printsancheck(void); ulong nhgetl(uchar *); ushort nhgets(uchar *); void hnputs(uchar *, ushort); void hnputl(uchar *, ulong); void *mallocz(int); void inserttarg(int, int); void insertmac(Mac **, char *); void sancheck(int, int); void ifsummary(void); int ifup(char *); void inserteth(char **, int, char *); char *getpciid(char *, int, char *); Eth eth[Neth]; int waitsecs = Nws; pthread_t threads[Neth]; Targ *targlist; int main(int argc, char **argv) { int n, i; char *ethnames[Neth]; Eth *e; memset(ethnames, 0, sizeof ethnames); printf("Probing..."); fflush(0); n = ethlist(ethnames, nelem(ethnames)); for (i=0; iname = ethnames[i]; e->up = ifup(ethnames[i]); if (pthread_create(&threads[i], 0, jcheck, e)) { fprintf(stderr, "pthread_create failed.\n"); break; } } n = i; for (i=0; i> 4) & 0xf)]; *p++ = hex[ea[i] & 0xf]; } *p = 0; return op; } void printlist(void) { Eth *e; Lun *lun; char mac[13]; for (e=eth; e->name; e++) { printf("%s:\n", e->name); for (lun=e->luns; lun; lun=lun->next) printf("e%d.%d %s %d\n", lun->major, lun->minor, cea(mac, lun->ea), lun->maxsect); printf("\n"); } } void timewait(int secs) /* arrange for a sig_alarm signal after `secs' seconds */ { struct sigaction sa; void catch(int); memset(&sa, 0, sizeof sa); sa.sa_handler = catch; sa.sa_flags = SA_RESETHAND; sigaction(SIGALRM, &sa, NULL); alarm(secs); } int discover(Eth *e) { Aoe *a; Qc *q; memset(e->pkt, 0, sizeof e->pkt); a = (Aoe *) e->pkt; memset(a->dst, 0xff, 6); memmove(a->src, e->ea, 6); hnputs(a->type, ETaoe); hnputl(a->tag, 1<<31); hnputs(a->major, 0xffff); a->minor = 0xff; a->cmd = Cqc; a->flags = 0x10; if (write(e->fd, a, mintu(sizeof *q)) <= 0) return -1; return 0; } void * jcheck(void *v) { Eth *e = v; int n; time_t t, nt; struct pollfd pd; if (ethopen(e) < 0) return 0; if (discover(e) < 0) { fprintf(stderr, "skipping %s, discover failure: %s\n", e->name, strerror(errno)); return 0; } pd.fd = e->fd; pd.events = POLLIN; t = time(0); for (;;) { nt = time(0); if (nt-t >= waitsecs) return 0; if (poll(&pd, 1, waitsecs*1000) > 0) if ((n = read(e->fd, e->pkt, sizeof e->pkt)) > 0) if (jinput(e)) t = time(0); } } /* return 1 == useful, 0 == not useful */ int jinput(Eth *e) { Aoe *a; Qc *q; Ata *aa; Lun *lun; ulong tag; int n; a = (Aoe *) e->pkt; if ((a->flags & (Arsp|Aerr)) != Arsp) return 0; if ((a->tag[0] & 0x80) == 0) return 0; tag = nhgetl(a->tag); switch (a->cmd) { case Cqc: q = (Qc *) a; lun = findlun(e, a); if (lun->state == Lnew) { lun->nsect = q->scnt; jprobe(e, lun); lun->state = Lprobe; break; } return 0; case Cata: aa = (Ata *) a; lun = findlun(e, a); if (lun == nil) return 0; if (lun->id != tag>>16) { printf("lun->id %d != tag %ld for %d.%d\n", lun->id, tag>>16, lun->major, lun->minor); return 0; } n = tag & 0xff; if (n > lun->maxsect) lun->maxsect = n; break; default: return 0; } return 1; } void hnputl(uchar *p, ulong n) { *p++ = n >> 24; *p++ = n >> 16; *p++ = n >> 8; *p = n; } void hnputs(uchar *p, ushort s) { *p++ = s >> 8; *p = s; } ushort nhgets(uchar *p) { ushort s; s = *p++; s <<= 8; s += *p++ & 0xff; return s; } ulong nhgetl(uchar *p) { ulong n; n = *p++; n <<= 8; n += *p++ & 0xff; n <<= 8; n += *p++ & 0xff; n <<= 8; n += *p++ & 0xff; return n; } void jprobe(Eth *e, Lun *lun) { Aoe *a; Ata *aa; int n; memset(e->pkt, 0, sizeof e->pkt); a = (Aoe *) e->pkt; aa = (Ata *) a; memcpy(a->dst, lun->ea, 6); memcpy(a->src, e->ea, 6); hnputs(a->type, ETaoe); hnputs(a->major, lun->major); a->minor = lun->minor; a->flags = 0x10; hnputl(a->tag, lun->id<<16); aa->cmd = 0xec; aa->scnt = 1; n = e->mtu - sizeof *aa; for (n &= ~511; n > 0; n -= 512) { a->tag[3] = n/512; if (write(e->fd, a, sizeof *aa + n) <= 0) { printf("write failed\n"); } usleep(100); } } Lun * findlun(Eth *e, Aoe *a) { Lun *p, **pp; int maj, n; static int id; maj = nhgets(a->major); pp = &e->luns; for (; (p=*pp); pp=&p->next) { if (maj < p->major) continue; if (maj > p->major) break; if (a->minor < p->minor) continue; if (a->minor > p->minor) break; n = memcmp(p->ea, a->src, 6); if (n < 0) continue; if (n > 0) break; return p; } if (a->cmd == Cata) return nil; p = mallocz(sizeof *p); p->major = maj; p->minor = a->minor; memmove(p->ea, a->src, 6); p->next = *pp; p->id = 0x8000 | id++; inserttarg(p->major, p->minor); return *pp = p; } void catch(int sig) { } int getindx(int sfd, char *name) // return the index of device 'name' { struct ifreq xx; int n; strcpy(xx.ifr_name, name); n = ioctl(sfd, SIOCGIFINDEX, &xx); if (n == -1) return -1; return xx.ifr_ifindex; } int getmtu(Eth *e) { struct ifreq xx; int n; strcpy(xx.ifr_name, e->name); n = ioctl(e->fd, SIOCGIFMTU, &xx); if (n == -1) { perror("Can't get mtu"); return 1500; } return xx.ifr_mtu; } int ethopen(Eth *e) // get us a raw connection to an interface { int n, sfd, rbsz, sbsz; struct sockaddr_ll sa; struct ifreq xx; rbsz = 64*1024*1024; sbsz = 64*1024*1024; memset(&sa, 0, sizeof sa); memset(&xx, 0, sizeof xx); sfd = socket(PF_PACKET, SOCK_RAW, htons(ETaoe)); if (sfd == -1) { perror("got bad socket"); return -1; } if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUFFORCE, &rbsz, sizeof rbsz) < 0) fprintf(stderr, "Failed to set socket rcvbuf size\n"); if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUFFORCE, &sbsz, sizeof sbsz) < 0) fprintf(stderr, "Failed to set socket sndbuf size\n"); n = getindx(sfd, e->name); sa.sll_family = AF_PACKET; sa.sll_protocol = htons(ETaoe); sa.sll_ifindex = n; n = bind(sfd, (struct sockaddr *)&sa, sizeof sa); if (n == -1) { perror("bind funky"); return -1; } strcpy(xx.ifr_name, e->name); n = ioctl(sfd, SIOCGIFHWADDR, &xx); if (n == -1) { perror("Can't get hw addr"); return -1; } memmove(e->ea, xx.ifr_hwaddr.sa_data, 6); e->fd = sfd; e->mtu = getmtu(e); return 0; } int ethlist(char **ifs, int nifs) { int i, s, n; struct ifreq ifr; s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) return 0; n = 0; for (i=0; imajor = maj; nt->minor = min; if (targlist == NULL) { targlist = nt; return; } if (nt->major < targlist->major) { nt->next = targlist; targlist = nt; return; } else if (nt->major == targlist->major && nt->minor < targlist->minor) { nt->next = targlist; targlist = nt; return; } else if (nt->major == targlist->major && nt->minor == targlist->minor) return; for (p = targlist,t = targlist->next; t; p = t,t = t->next) { if (nt->major == t->major && nt->minor == t->minor) return; if (nt->major < t->major) { p->next = nt; nt->next = t; return; } else if (nt->major == t->major && nt->minor < t->minor) { p->next = nt; nt->next = t; return; } } p->next = nt; } void printsancheck() { Targ *t; printf("==========================================\n"); printf("INTERFACE SUMMARY\n"); printf("==========================================\n"); printf("Name\tStatus\tMTU\tPCI ID\n"); ifsummary(); printf("==========================================\n"); printf("DEVICE SUMMARY\n"); printf("==========================================\n"); printf("Device\tMacs\tPayload\tLocal Interfaces\n"); for (t = targlist; t; t = t->next) { sancheck(t->major, t->minor); } } void ifsummary() { Eth *e; char buf[32]; char *p; for (e=eth; e->name; e++) { p = getpciid(buf, sizeof buf, e->name); printf("%s\t%s\t%d\t%s\n", e->name, (e->up ? "UP" : "DN"), e->mtu, (p ? p : "")); } } void sancheck(int maj, int min) { Eth *e; Lun *l; Mac *ml, *m; int a, found; int ps, nsect, nea, nloc; int mtu, mtuflag; char buf[128]; char mac[13]; nsect = mtu = 0; mtuflag = 0; nloc = nea = 0; a = 0; ps = 0; memset(buf, 0, sizeof buf); ml = NULL; for (e=eth; e->name; e++) { found = 0; for (l = e->luns; l; l = l->next) { if (!(l->major == maj && l->minor == min)) continue; found = 1; if (mtu == 0) mtu = e->mtu; else if (mtu != e->mtu) { mtuflag = 1; mtu = (e->mtu > mtu ? e->mtu : mtu); } insertmac(&ml, l->ea); if (ps == 0) ps = l->maxsect; else ps = (l->maxsect < ps ? l->maxsect : ps); nsect = l->nsect; } if (found) { snprintf(buf + a,(sizeof buf) - a, "%s%s", (a ? ",": ""), e->name); a += strlen(e->name) + (a ? 1 : 0); nloc++; } } for (m = ml; m; ml = m, nea++) { m = m->next; free(ml); } printf("e%d.%d\t%4d\t%d\t%s\n", maj, min, nea, nsect*512, buf); if (nea != nloc) printf(" Mismatched number of local vs remote interfaces\n"); for (e=eth; e->name; e++) { found = 0; for (l = e->luns; l; l = l->next) if (l->major == maj && l->minor == min) { found = 1; if (l->maxsect < (e->mtu-32)/512) printf(" The path %s->%s is only capable of %d byte payloads\n", e->name, cea(mac, l->ea), l->maxsect*512); } if (found) { if (e->mtu < nsect*512 + 36) printf(" %s: MTU (%d) not set optimally for device's capable payload\n",e->name, e->mtu); if (e->mtu < mtu) printf(" %s: MTU different from other interfaces (%d vs. %d)\n", e->name, e->mtu, mtu); } } } void insertmac(Mac **ml, char *m) { Mac *nm,*p, *pp; for (p = *ml, pp=NULL; p; pp = p, p = p->next) if (memcmp(p->ea, m, 6) == 0) return; nm = mallocz(sizeof *nm); memcpy(nm->ea, m, 6); if (pp) pp->next = nm; else *ml = nm; } int ifup(char *ethname) { struct ifreq ifr; int r, s; memset(&ifr, 0, sizeof ifr); s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) return 0; strcpy(ifr.ifr_name, ethname); if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) { close(s); return 0; } r = ifr.ifr_flags & IFF_UP; close(s); return r; } void inserteth(char **ifs, int nifs, char *n) { int i, j; char a[64], b[64]; memset(a, 0, sizeof a); memset(b, 0, sizeof b); for (i=0; i < nifs; i++) { if (ifs[i] == 0) { ifs[i] = strdup(n); break; } j = strcmp(n, ifs[i]); if (j < 0) { strcpy(a, n); for (; ifs[i]; i++) { strcpy(b, ifs[i]); free(ifs[i]); ifs[i] = strdup(a); strcpy(a, b); } ifs[i] = strdup(a); break; } else if (j == 0) break; else if (j > 0) continue; } } char * getpciid(char *b, int blen, char *n) { FILE *fd; char dev[8]; char ven[8]; char path[128]; memset(dev, 0, sizeof dev); memset(ven, 0, sizeof ven); memset(path, 0, sizeof path); sprintf(path, "/sys/class/net/%s/device/vendor", n); if ((fd = fopen(path, "r")) == NULL) return NULL; fseek(fd, 2, SEEK_SET); if (fread(ven, 1, 4, fd) <= 0) { fclose(fd); return NULL; } fclose(fd); sprintf(path, "/sys/class/net/%s/device/device", n); if ((fd = fopen(path, "r")) == NULL) return NULL; fseek(fd, 2, SEEK_SET); if (fread(dev, 1, 4, fd) <= 0) { fclose(fd); return NULL; } fclose(fd); snprintf(b, blen, "%s:%s", ven, dev); return b; } aoetools-36/config.h0000644000076500007640000000003612026614322014050 0ustar ecashinbuild#define _FILE_OFFSET_BITS 64 aoetools-36/aoe-sancheck.80000644000076500007640000000611012026614322015043 0ustar ecashinbuild.TH aoe-sancheck 8 .SH NAME aoe-sancheck \- verify storage network capabilities .SH SYNOPSIS .nf .B aoe-sancheck [\-v] .fi .SH DESCRIPTION The .I aoe-sancheck command collects information about the local interfaces and probes the network for ATA over Ethernet devices, validating the paths for each device. It does not use the aoe kernel module but rather the bpf interface to evaluate the network. As such, the aoe module does not need to be loaded to perform the test. .PP The output of the command is divided into two sections: information about the local interfaces followed by a list of detected AoE devices. The first section displays the local interfaces, if the interface is up or down, its configured MTU, and the PCI ID for the interface. .PP The second section lists detected AoE devices, one per line, with the following information: .TP .BI Device The device name of the form .I eX.Y where .I X is the AoE device shelf address, and .I Y is the AoE device slot address. .TP .BI Macs The number of mac addresses detected for this device. .TP .BI Payload The number of bytes of data the device can handle in a single AoE request. This number does not represent the total frame size as it does not include bytes from ethernet or AoE headers. .TP .BI "Local Interfaces" The list of local interfaces from which the device is visible. .SS Options .TP \fB\-v\fP Prints out additional raw information. .SH DIAGNOSIS For each device, .I aoe-sancheck may print out additional lines of suggestions or warnings. The following checks are made: .TP .BI "The MTU of the local interfaces is set high enough to handle the AoE device's reported payload. " Depending on the host NIC's capabilities and storage network switch's capabilities, best performance may or may not be with local interface MTU set higher than a device's payload size. .TP .BI "The number of local interfaces matches the number of interfaces on the device. " Best performance comes from having a host and device with comparable bandwidth. \fIAoe-sancheck\fP simply counts the number of interfaces involved and does not figure link bandwidth in its comparison. .TP .BI "All local interfaces for an AoE device have the same MTU." If one interface for a device has a smaller MTU than the others, the AoE driver must use the smaller payload size for all interfaces. .TP .BI "Each path to the device is capable of the configured payload size." This check detects the situation where a local interface is configured for jumbo frames and the AoE device is capable of jumbo frames, but some aspect of the network is incapable of passing frames that size, for example, a misconfigured switch. \fIAoe-sancheck\fP reports the maximum payload size the path is capable of if less than the configured payload size. .SH BUGS The program may sometimes display inconsistent results between runs showing that a path is capable of a smaller frame size than it actually is. If you see this behavior, please email one of the authors with your verbose output. .SH "SEE ALSO" .IR aoeping (8), .IR aoetools (8) .SH AUTHORS Justin Sanders (justin@coraid.com), Sam Hopkins (sah@coraid.com) aoetools-36/aoe-interfaces.80000644000076500007640000000445112026614322015415 0ustar ecashinbuild.TH aoe-interfaces 8 .SH NAME aoe-interfaces \- restrict aoe driver to specified network interfaces .SH SYNOPSIS .nf .B aoe-interfaces [dev1] [dev2 ...] .B aoe-interfaces -c .fi .SH DESCRIPTION The .I aoe-interfaces command tells the aoe driver to ignore ATA over Ethernet (AoE) traffic on all but the specified network interfaces. It is analogous to the \fIaoe_iflist\fP module load option. .PP If neither the \fIaoe_iflist\fP module load option nor the \fIaoe-interfaces\fP command are used, the aoe driver will use any network interface for AoE traffic. Using \fIaoe-interfaces\fP to limit AoE to only trusted networks prevents the case where a rogue AoE target appears on a public network, diverting data from the legitimate AoE target. Such an imposter target effectively corrupts the data on the legitimate target. .PP If the aoe driver is a module, then calling .I aoe-interfaces without arguments will display the current interfaces list. If it hasn't been set then the output will be blank. .PP It's good to run the .I aoe-discover command after setting the AoE interfaces list. .SH OPTIONS .TP \fB-c\fP The \fB-c\fP flag will clear the interface access list, permitting any interface to be used. .SH EXAMPLE In this example, the root user on a host named .I nai loads the aoe module with only eth0 allowable for AoE traffic. After remembering that shelf 7 is on eth3, this sysadmin uses .I aoe-interfaces to add eth3 to the list of allowable network interfaces and then calls .I aoe-discover to ask the aoe driver to look for new AoE devices. .IP .EX .nf nai:~# modprobe aoe aoe_iflist="eth0" nai:~# aoe-stat e10.9 eth0 up nai:~# aoe-interfaces eth0 eth3 nai:~# aoe-discover nai:~# aoe-stat e7.0 eth3 up e7.1 eth3 up e7.2 eth3 up e7.3 eth3 up e7.4 eth3 up e7.5 eth3 up e7.6 eth3 up e7.7 eth3 up e7.8 eth3 up e7.9 eth3 up e10.9 eth0 up nai:~# aoe-interfaces eth0 eth3 .fi .EE .SH "SEE ALSO" .IR aoe-discover (8), .IR aoe-stat (8), .IR aoetools (8). .SH AUTHOR Ed L. Cashin (ecashin@coraid.com) aoetools-36/aoe-mkdevs.80000644000076500007640000000425512026614322014565 0ustar ecashinbuild.TH aoe-mkdevs 8 .SH NAME aoe-mkdevs \- create special device files for aoe driver .SH SYNOPSIS .nf .B aoe-mkdevs {device-dir} .B env n_partitions=1 aoe-mkdevs {device-dir} .fi .SH DESCRIPTION The .I aoe-mkdevs command is deprecated in favor of udev. Systems with udev do not need to use the \fIaoe-mkdevs\fP or \fIaoe-mkself\fP commands, because udev will create device nodes as needed. .PP Systems without udev use \fIaoe-mkdevs\fP to create the character special files necessary to control the aoe driver. The \fIaoe-mkdevs\fP command uses .I aoe-mkshelf to also create block special files. .PP The aoe drivers after version 49 support dynamic minor device numbers so that a greater number of devices can be supported. The \fIaoe-mkdevs\fP command is incompatible with dynamic device numbers. If your system lacks udev, and you are using an aoe driver version 50 or above, use the aoe_dyndevs=0 module option to force the aoe driver to use static device numbers. .PP If you are not using dynamic device numbers, and you built your aoe driver to support only one partition per device (whole-disk partitions), then the device files must match, and you should use the .I n_partitions environment variable described below. .SS Arguments .TP \fBdevice-dir\fP This should be the name of the directory where the special device files will be created. .SH ENVIRONMENT VARIABLES If the .I n_partitions variable is set in the environment, it will override the default number of partitions per aoe disk, namely 16. .SH EXAMPLE In this example, the root user on a host named .I nai creates special files for using the aoe disks in shelf 7. After remembering that the driver doesn't have partition support, this sysadmin gets rid of the mismatching device nodes and calls \fIaoe-mkdevs\fP again with \fIn_partitions\fP set to 1. .IP .EX .nf nai:~# rm -rf /dev/etherd nai:~# aoe-mkdevs /dev/etherd nai:~# ls /dev/etherd | wc -l 1603 nai:~# rm -rf /dev/etherd nai:~# n_partitions=1 aoe-mkdevs /dev/etherd nai:~# ls /dev/etherd | wc -l 103 .fi .EE .SH "SEE ALSO" .IR aoe-discover (8), .IR aoe-interfaces (8), .IR aoe-mkshelf (8), .IR aoe-stat (8), .IR aoetools (8), .IR udev (7). .SH AUTHOR Ed L. Cashin (ecashin@coraid.com) aoetools-36/aoe-stat.80000644000076500007640000000667712026614322014261 0ustar ecashinbuild.TH aoe-stat 8 .SH NAME aoe-stat \- print aoe device status report .SH SYNOPSIS .nf .B modprobe aoe .B aoe-stat .B env sysfs_dir=/sys aoe-stat .fi .SH DESCRIPTION The .I aoe-stat script collects information on ATA over Ethernet devices from sysfs. .PP For each AoE device the kernel has discovered, there is one row in the script's output. Each row has the following columns. .TP .BI devicename The device name is of the form .I eX.Y, with .I X being the AoE device shelf address, and .I Y being the AoE slot address. .TP .BI size The size of the AoE device is in gigabytes (billions of bytes). .TP .BI ifname The network interface name is printed in the third column. .TP .BI payload The number of bytes read from or written to the storage target in each AoE packet appears in the fourth column, unless the aoe driver does not export this information. .TP .BI status The device status is in the last column. Possible values are \fI up\fR, \fI down\fR, and \fI down,closewait\fR. The "up" status means the aoe driver considers this device ready for I/O. The "down" status means the opposite. The "down,closewait" status means that some software still has the device open, and when this straggler closes the device, it will enter the "down" state. .SH UNAVAILABLE TARGETS If a discovered AoE target will not respond to I/O commands, some of the information needed to allow Linux to use the device is not available. The .I aoe-stat command shows the missing information as "(NA)" fields. .PP It is normal for "(NA)" fields to appear during the brief time between the time that an AoE target is detected and the time the Linux kernel finishes reading its partition table. .SH ENVIRONMENT VARIABLES If the .I sysfs_dir variable is set in the environment, it will override the default location where .I aoe-stat will look for sysfs, namely \fI /sys\fR. .SH WARNINGS If the minor device number of a device node does not match that of its namesake, \fIaoe-stat\fP will print a warning as shown below. .IP .EX .nf nai:~# aoe-stat e0.3 0.104GB eth0 up e0.4 4398.046GB eth0 up e20.0 1000.215GB eth0 up e42.0 2000.431GB eth0 up aoe-stat Warning: device node /dev/etherd/e45.1 has wrong minor device number e45.1 1152.874GB eth0 up .fi .EE .PP Using such a device node is dangerous, because its name doesn't match the actual device that you would be reading from and writing to. Such a broken device node should be removed. Device nodes are created by \fIudev\fP or (on systems without \fIudev\fP) by \fIaoe-mkdevs\fP. .SH EXAMPLE In this example, the root user on a host named .I nai loads the aoe driver module and then prints a list of all the available aoe devices. Then he remembers to bring up the storage network interfaces, does an AoE discovery, and prints the list again. This time the list shows all the devices in shelf seven. .IP .EX .nf nai:~# modprobe aoe nai:~# aoe-stat nai:~# ifconfig eth3 up nai:~# aoe-discover nai:~# aoe-stat e0.0 10995.116GB eth3 up e0.1 10995.116GB eth3 up e0.2 10995.116GB eth3 up e1.0 1152.874GB eth3 up e7.0 370.566GB eth3 up nai:~# .fi .EE .SH "SEE ALSO" .IR aoe-discover (8), .IR aoe-interfaces (8), .IR aoe-mkdevs (8), .IR aoe-mkshelf (8), .IR aoetools (8), .IR udev (7). .SH AUTHOR Ed L. Cashin (ecashin@coraid.com) aoetools-36/aoe-discover.80000644000076500007640000000334012026614322015104 0ustar ecashinbuild.TH aoe-discover 8 .SH NAME aoe-discover \- tell aoe driver to discover AoE devices .SH SYNOPSIS .nf .B aoe-discover .fi .SH DESCRIPTION The .I aoe-discover command tells the aoe driver to discover ATA over Ethernet (AoE) devices on the network. All network interfaces will be probed with a AoE config query broadcast. .PP If the .I aoe-interfaces command has limited the allowable network interfaces, only devices discovered via allowable interfaces will become available. The default is to make available all AoE devices found on all accessible ethernet networks. .PP It's good to run the .I aoe-discover command after running \fIaoe-interfaces\fP. .SH EXAMPLE In this example, the root user on a host named .I nai loads the aoe module with only eth0 allowable for AoE traffic. After remembering that shelf 7 is on eth3, this sysadmin uses .I aoe-interfaces to add eth3 to the list of allowable network interfaces and then calls .I aoe-discover to ask the aoe driver to look for new AoE devices. .IP .EX .nf nai:~# modprobe aoe aoe_iflist="eth0" nai:~# aoe-stat e10.9 eth0 up nai:~# aoe-interfaces eth0 eth3 nai:~# aoe-discover nai:~# aoe-stat e7.0 eth3 up e7.1 eth3 up e7.2 eth3 up e7.3 eth3 up e7.4 eth3 up e7.5 eth3 up e7.6 eth3 up e7.7 eth3 up e7.8 eth3 up e7.9 eth3 up e10.9 eth0 up .fi .EE .SH "SEE ALSO" .IR aoe-interfaces (8), .IR aoe-stat (8), .IR aoetools (8). .SH AUTHOR Ed L. Cashin (ecashin@coraid.com) aoetools-36/aoe-mkshelf.80000644000076500007640000000423512026614322014723 0ustar ecashinbuild.TH aoe-mkshelf 8 .SH NAME aoe-mkshelf \- create special device files for one shelf address .SH SYNOPSIS .nf .B aoe-mkshelf {device-dir} {shelf-address} .B env n_partitions=1 aoe-mkshelf {device-dir} {shelf-address} .fi .SH DESCRIPTION The .I aoe-mkshelf command is not needed on systems that have udev installed and is incompatible with aoe drivers that have the \fIaoe_dyndevs\fP module parameter set to 1. .PP Systems lacking udev and having an aoe driver that uses static minor device numbers can use \fIaoe-mkshelf\fP to create the block special files necessary to access the AoE devices with the given shelf address. .PP All aoe drivers prior to \fIaoe6-50\fP use static minor device numbers. Versions 50 and up use dynamic minor device numbers when the module parameter aoe_dyndevs=1 is set. .PP If you are using static minor device numbers and your aoe driver supports only one partition per device (whole-disk partitions), then the device files must match, and you should use the .I n_partitions environment variable described below. .SS Arguments .TP \fBdevice-dir\fP This should be the name of the directory where the block device files will be created. .TP \fBshelf-address\fP This is the AoE major address, or shelf address, for which to create device nodes. For example, specifying a shelf address of 1 means that the e1.* device nodes will be created in \fBdevice-dir\fP. .SH ENVIRONMENT VARIABLES If the .I n_partitions variable is set in the environment, it will override the default number of partitions per aoe disk, namely 16. .SH EXAMPLE In this example, the root user on a host named .I nai creates special files for using the aoe disks in shelf 7. Then he remembers that the driver doesn't have partition support, so the command is called again with \fIn_partitions\fP set to 1. .IP .EX .nf nai:~# aoe-mkshelf /dev/etherd 7 nai:~# ls /dev/etherd/e7.* | wc -l 160 nai:~# rm /dev/etherd/e7.* nai:~# n_partitions=1 aoe-mkshelf /dev/etherd 7 nai:~# ls /dev/etherd/e7.* | wc -l 10 nai:~# .fi .EE .SH "SEE ALSO" .IR aoe-discover (8), .IR aoe-interfaces (8), .IR aoe-mkdevs (8), .IR aoe-stat (8), .IR aoetools (8), .IR udev (7). .SH AUTHOR Ed L. Cashin (ecashin@coraid.com) aoetools-36/fns.h0000644000076500007640000000017712026614322013377 0ustar ecashinbuild/* Copyright 2009, CORAID, Inc., and licensed under GPL v.2. */ int dial(char *eth); int getea(int s, char *name, uchar *ea); aoetools-36/coraid-update.80000644000076500007640000000163412026614322015251 0ustar ecashinbuild.TH coraid-update 8 .SH NAME coraid-update \- upload an update file to a CORAID appliance .SH SYNOPSIS .nf .B coraid-update {update file} {AoE device} .fi .SH DESCRIPTION The .I coraid-update script performs a few sanity checks before copying the local update file to the remote update AoE target on the CORAID appliance. .PP Two arguments are provided: 1) the name of the update file to be uploaded, and 2) the special block device file corresponding to the update target, e.g., \fI/dev/etherd/e100.40\fP. .PP It generates no output and exits with a zero status when the update file has been successfully uploaded to the update target on the appliance. Otherwise, an error message is printed to standard error and \fI coraid-update\fR exits with a non-zero status. .SH "SEE ALSO" .IR aoe-discover (8), .IR aoe-interfaces (8), .IR aoe-stat (8), .IR aoetools (8), .IR udev (7). .SH AUTHOR Ed L. Cashin (ecashin@coraid.com) aoetools-36/aoetools.80000644000076500007640000000240512026614322014352 0ustar ecashinbuild.TH aoetools 8 .SH NAME aoetools \- utilities for AoE on systems running Linux 2.6 and up .SH DESCRIPTION The .I aoetools package contains scripts and commands that interact with, support, and supplement the aoe driver in the Linux kernel. .TP .BI aoe-discover tell aoe driver to discover AoE devices .TP .BI aoe-flush flush the down devices out of the aoe driver .TP .BI aoe-interfaces restrict aoe driver to specified network interfaces .TP .BI aoe-mkdevs create special device files for system without udev .TP .BI aoe-mkshelf create device files for one shelf address for system without udev .TP .BI aoe-revalidate revalidate the disk size of an aoe device .TP .BI aoe-stat collate and present information about AoE storage .TP .BI aoe-version display version numbers of AoE-related software .TP .BI coraid-update send updates to CORAID appliances .TP .BI sos-linux collect AoE-related information about the localhost .TP .BI aoe-sancheck perform an analysis of the AoE storage network .SH "SEE ALSO" .IR aoe-discover (8), .IR aoe-flush (8), .IR aoe-interfaces (8), .IR aoe-mkdevs (8), .IR aoe-mkshelf (8), .IR aoe-revalidate (8), .IR aoe-stat (8), .IR aoe-version (8), .IR aoecfg (8), .IR aoeping (8), .IR coraid-update (8), .IR sos-linux (8), .IR aoe-sancheck (8), .IR udev (7). aoetools-36/aoe-mkshelf.in0000755000076500007640000000221212026614322015156 0ustar ecashinbuild#! /bin/sh # aoe-mkshelf - device nodes for one shelf without udev # Copyright 2009, CORAID, Inc., and licensed under GPL v.2. zero=`basename $0` if test "$#" != "2"; then echo "Usage: $zero {dir} {shelfaddress}" 1>&2 echo " n_partitions=16 $zero {dir} {shelfaddress}" 1>&2 exit 1 fi dyn=/sys/module/aoe/parameters/aoe_dyndevs if test -r "$dyn" && test "`cat $dyn`" = 1; then cat 1>&2 <&2 < support debugfs-exported debug info in sos-linux release 36 2013-07-10 Ed Cashin add pkg subdirectory for distro-specific packaging files 2012-09-20 Ed Cashin only use one of the sysfs version files in aoe-version release 35 2012-06-27 Ed Cashin restore payload field in aoe-stat output release 34 2012-01-24 Ed Cashin handle missing sysfs files in aoe-stat update docs for 3.x kernels remove "function" keyword in aoe-stat for Ubuntu release 33 2010-08-18 Justin Sanders aoe-sancheck fix: zero out every interface release 32 2010-08-18 Justin Sanders aoe-sancheck tool diagnoses MTU and other network issues release 31 2009-03-03 Ed Cashin aoe-version modinfo workaround: cd to a directory without aoe release 30 2008-12-09 Ed Cashin mention that aoeping uses raw sockets in manpage use absolute path to aoe.ko when ./aoe is readable release 29 2008-11-11 Ed Cashin remove "function" reserved word from aoe-flush (for dash shell) release 28 2008-08-01 Ed Cashin use ".txt" extension for output file of sos-linux 2008-06-27 Ed Cashin aoeping: recognize errors in SMART command response aoe-stat manpage improvements release 27 2008-05-14 "Ed L. Cashin" add sos-linux tool for collecting localhost information release 26 2008-04-11 "Ed L. Cashin" create coraid-update for uploading update file to an update target create coraid-update manpage release 25 2008-03-25 "Ed L. Cashin" clean up aoecfg object files in "clean" target 2008-02-22 "Ed L. Cashin" make aoeping and aoecfg more conforming to AoE protocol release 24 2008-01-09 "Ed L. Cashin" release 23 2008-01-09 Sam Hopkins support new payload size information from aoe driver 2008-01-08 "Ed L. Cashin" handle aoe-flush without arguments correctly 2007-12-19 "Ed L. Cashin" fix aoecfg manpage typo (-s for string) 2007-12-10 "Ed L. Cashin" aoe-flush: support flushing specific devices release 22 2007-10-29 "Ed L. Cashin" aoe-interfaces should complain about non network interfaces aoe-interfaces should accept quoted list of interfaces aoe-interfaces clearing and setting are exclusive actions release 21 2007-10-12 "Ed L. Cashin" add Erik Quanstrom's aoecfg program signal error when specified network interface starts with digit use a tag in the AoE header do not print shelf and slot when user specified both have aoeping use a tag for the first packet add pretty printing of ATA device identify fields based on input from Joshua Nicholas release 20 2007-08-27 "Ed L. Cashin" add copyright information support kernel.org aoe driver in aoe-version add aoetools manpage release 19 2007-08-08 "Ed L. Cashin" distinguish between missing device nodes and wrong ones release 18 2007-07-26 "Ed L. Cashin" aoe-mkdevs and aoe-mkshelf are for systems without udev aoe-stat warns when device node has wrong minor number new script, aoe-version, shows installed and running sfw release 17 2007-07-17 "Ed L. Cashin" check for char devices specifically before using them 2007-06-01 "Ed L. Cashin" workaround dash POSIX math bug release 16 2007-03-20 "Ed L. Cashin" add quoting to aoe-flush release 15 2007-02-26 Marcus Rueckert create the same directories we install to 2007-02-06 Sam Hopkins add support for -c flag to aoe-interfaces add support for -a flag to aoe-flush update manpages for aoe-interfaces, aoe-flush release 14 2006-12-21 Sam Hopkins support aoe devices without "etherd" prefix in name create new character device nodes release 13 2006-10-30 Sam Hopkins formatting cleanup of man pages cleanup of scripts, adding error checking add aoe-flush command release 12 2006-10-13 David Martinez Moreno aoe-stat: POSIX shell math can't count as high as bash 2006-09-07 Anthony Wright use POSIX shell math instead of relying on dc or bc release 11 2006-05-25 "Ed L. Cashin" update README: aoetools are for 2.6 systems release 10 2006-01-18 "Ed L. Cashin" aoe-revalidate: notice error in writing to revalidate device release 9 2005-11-09 Sam Hopkins add aoe-revalidate document driver compatibility release 8 2005-08-18 "Ed L. Cashin" format sub-gigabyte device sizes correctly release 7 2005-08-17 "Ed L. Cashin" make aoe-stat show device size release 6 2005-07-13 "Ed L. Cashin" make number of slots per shelf configurable Rob Holland : install using PREFIX "make install" builds aoeping avoid gcc 4 warnings by specifying uchar in params release 5 2005-05-17 "Ed L. Cashin" fix typo in Makefile preventing aoeping installation: s/PROG/PROGS/ add TODO file release 4 2005-04-14 "Ed L. Cashin" add very basic SMART support to aoeping release 3 2005-04-12 "Ed L. Cashin" add aoeping, a userland tool for simple AoE communications release 2 2005-03-23 "Ed L. Cashin" initial release of aoetools, version 1 aoetools-36/aoecfg.80000644000076500007640000000431512026614322013753 0ustar ecashinbuild.TH aoecfg 8 .SH NAME aoecfg \- manipulate AoE configuration strings .SH SYNOPSIS .B aoecfg [-c \fIcmd\fR] [-s \fIcfgstr\fR] [-t \fItimeout\fR] [\fIshelf slot\fR] [\fInetif\fR] .fi .SH DESCRIPTION .IR Aoecfg (8) sends AoE configuration commands that control the retrivial, conditional or unconditional setting of AoE configuration strings. Since configuration happens before the MAC address of the target is known, the packet is broadcast. AoE targets with a matching shelf and slot respond. Since the default shelf and slot are the wildcard values 0xffff and 0xff, with no arguments .IR aoecfg (8) will return configuration strings from all targets visible on the default interface, .IR eth0 . .SH OPTIONS .TP 8 .BI \-c " cmd" specify the AoE configuration command. The default is .IR read . The available commands are .HP 8 .B read Read the server config string without performing any test and respond. .HP 8 .B test Respond only if the specified string exactly matches the server configuration string. .HP 8 .B prefix Respond only if the specified string is a prefix of the server configuration string. .HP 8 .B set If the current server config string is empty, set the server config string to the argument string and respond. If the current server config string is not empty, return a response with Flags bit E set and Error set to 4. .HP 8 .B fset Force set the server config string to the argument string and respond. .TP .BI \-s " cfgstr" specify the config string. .TP .BI \-t " timeout" specify the timeout in seconds. The default is no timeout. If neither the shelf nor the slot are specified, .IR aoecfg (8) will exit after the first result. Otherwise, .IR aoecfg (8) will exit only after the timeout has expired since it does not know how many responses to expect. .TP .B shelf slot specify the shelf and slot used in the query. If unspecified, they default to broadcast. .TP .B netif specifiy the network interface. The default is .IR eth0 . .SH "SEE ALSO" .IR aoe-discover (8), .IR aoe-interfaces (8), .IR aoe-mkdevs (8), .IR aoe-mkshelf (8), .IR aoe-stat (8), .IR aoeping (8), \fIAoE (ATA over Ethernet)\fP: http://support.coraid.com/documents/AoEr10.txt, \fIATA specification\fP .SH AUTHOR Erik Quanstrom (quanstro@coraid.com) aoetools-36/aoe-mkdevs0000755000076500007640000000261012026614322014413 0ustar ecashinbuild#!/bin/sh # aoe-mkdevs - make static device nodes on systems without udev # Copyright 2009, CORAID, Inc., and licensed under GPL v.2. n_shelves=${n_shelves:-10} n_partitions=${n_partitions:-16} if test "$#" != "1"; then echo "Usage: `basename $0` {dir}" 1>&2 echo " n_partitions=16 `basename $0` {dir}" 1>&2 exit 1 fi dir=$1 zero="`basename $0`" MAJOR=152 dyn=/sys/module/aoe/parameters/aoe_dyndevs if test -r "$dyn" && test "`cat $dyn`" = 1; then cat 1>&2 <&2 < Version: 36 Release: 1%{dist} URL: http://aoetools.sourceforge.net/ Source0: %{name}-%{version}.tar.gz Source1: 60-aoe.rules License: GPLv2 Group: Application/System %description The command-line utilities for using the aoe driver to work with ATA over Ethernet storage targets on a Linux system. %define debug_package %{nil} %prep %setup -n %{name}-%{version} %build make SBINDIR=%{sbind} MANDIR=%{mand} %install mkdir -p -m 755 %{sbind}/ mkdir -p -m 755 %{mand}/man8/ make install SBINDIR=%{sbind} MANDIR=%{mand} mkdir -p -m 755 %{udevrulesd}/ install -m 644 %{SOURCE1} %{udevrulesd} %files %defattr(-,root,root) %doc %docfiles %attr(0755,root,root) %{_sbindir}/* %{_mandir}/man8/* %config %{_sysconfdir}/udev/rules.d/* %changelog * Thu Aug 15 2013 Ed Cashin - 36-1 - Update for v36 * Wed Jul 10 2013 Ed Cashin - 35-1 - Initial package for aoetools v35 plus udev rules aoetools-36/pkg/rhel6/SOURCES/0000755000076500007640000000000012167556641015376 5ustar ecashinbuildaoetools-36/pkg/rhel6/SOURCES/60-aoe.rules0000644000076500007640000000107212167556641017441 0ustar ecashinbuild# These rules tell udev what device nodes to create for aoe support. # aoe char devices SUBSYSTEM=="aoe", KERNEL=="discover", NAME="etherd/%k", GROUP="disk", MODE="0220" SUBSYSTEM=="aoe", KERNEL=="err", NAME="etherd/%k", GROUP="disk", MODE="0440" SUBSYSTEM=="aoe", KERNEL=="interfaces", NAME="etherd/%k", GROUP="disk", MODE="0220" SUBSYSTEM=="aoe", KERNEL=="revalidate", NAME="etherd/%k", GROUP="disk", MODE="0220" SUBSYSTEM=="aoe", KERNEL=="flush", NAME="etherd/%k", GROUP="disk", MODE="0220" # aoe block devices KERNEL=="etherd*", NAME="%k", GROUP="disk" aoetools-36/aoecfg.c0000644000076500007640000000776212026614322014037 0ustar ecashinbuild/* * aoecfgstr.c - fiddle aoe configuration strings. * Copyright 2009, Erik Quanstrom, CORAID, Inc., Licenced under GPL v2 */ #include #include #include #include #include #include #include #include #include #include #include #include "dat.h" #include "fns.h" int sfd; uchar mac[6]; int timeout; u16 shelf = 0xffff; uchar slot = 0xff; char *net = "eth0"; char *cfgstr; int cfgstrlen; char *errtab[7] = { "*GOK*", "*badcmd*", "*badarg*", "*baddev*", "*badcfg*", "*badvers*", "*GOK*", }; void resp(Conf *c) { Aoehdr *h; char *s; int l; h = (Aoehdr*) c; if (h->flags & Error) { s = errtab[h->error & 7]; l = strlen(s); } else { s = (char*) c->data; l = ntohs(c->len); } if (shelf != 0xffff && slot != 0xff) printf("%.*s\n", l, s); else printf("%d.%d\t%.*s\n", ntohs(h->maj), h->min, l, s); } int readto(int fd, void *buf, int size) { fd_set rfd; struct timeval tv; static int to; if (timeout == 0) goto f1; if (to == 0) to = time(0) + timeout; FD_ZERO(&rfd); FD_SET(fd, &rfd); tv.tv_sec = to - time(0); tv.tv_usec = 0; switch (select(fd+1, &rfd, 0, 0, &tv)) { case -1: perror("select"); exit(1); case 0: exit(0); } f1: return read(fd, buf, size); } u32 aoe_tag(void) { u32 n; struct timeval t = { 0, 0 }; /* Tag should be just enough to avoid conflicts with other * aoeping and aoecfg processes, and should set high bit * to avoid conflicting with in-kernel AoE. */ if (gettimeofday(&t, NULL)) { perror("gettimeofday"); exit(1); } n = t.tv_usec | 1UL << 31; return htonl(n); } void cfgquery(int cmd, int shelf, int slot) { int n; Aoehdr *h; Conf *c; uchar buf[1024 + sizeof *h]; u32 tag; c = (Conf*) buf; h = (Aoehdr*) c; memset(h, 0, sizeof *h); memset(h->dst, 0xff, sizeof h->dst); memmove(h->src, mac, sizeof h->src); h->type = htons(AOE_ETH_PROTO); h->flags = AoEver << 4; h->maj = htons(shelf); h->min = slot; h->cmd = Config; tag = aoe_tag(); memmove(h->tag, &tag, sizeof h->tag); c->bufcnt = 0; c->firmware = 0; c->scnt = 0; c->vercmd = cmd; memmove(c->data, cfgstr, cfgstrlen); c->len = htons(cfgstrlen); if (write(sfd, c, sizeof *c) == -1) { perror("send config query"); exit(1); } for (;;) { n = readto(sfd, buf, sizeof buf); if (n < 0) { perror("read network"); exit(1); } if (n < 60) continue; h = (Aoehdr *) buf; if (ntohs(h->type) != AOE_ETH_PROTO) continue; if (ntohs(h->maj) == 0xffff || h->min == 0xff) continue; if (shelf != 0xffff && ntohs(h->maj) != shelf) continue; if (slot != 0xff && h->min != slot) continue; if (memcmp(h->tag, &tag, sizeof h->tag)) continue; resp((Conf*) buf); if (shelf != 0xffff && slot != 0xff) break; } } void usage(void) { fputs("usage: aoecfg " "[-c cmd] [-s cfgstr] [-t timeout] " "[shelf slot] [net]\n", stderr); exit(1); } typedef struct{ char *s; int cmd; } Tab; Tab tab[] = { { "read", Qread, }, { "test", Qtest, }, { "prefix", Qprefix, }, { "set", Qset, }, { "fset", Qfset, }, }; int xlatecmd(char *s) { int i; for (i = 0; i < nelem(tab); i++) if (strcmp(tab[i].s, s) == 0) return tab[i].cmd; usage(); return -1; // whine whine whine } int main(int argc, char *argv[]) { int c, cmd; cmd = Qread; while ((c = getopt(argc, argv, "s:c:t:v")) != -1) { switch (c) { case 'c': cmd = xlatecmd(optarg); break; case 's': cfgstr = optarg; cfgstrlen = strlen(cfgstr); break; case 't': timeout = atoi(optarg); break; default: usage(); } } c = argc - optind; argv += optind; if (c < 2) goto f1; if (c != 3 && c != 2) usage(); shelf = strtoul(*argv++, 0, 0); slot = strtoul(*argv++, 0, 0); f1: if (*argv) { net = *argv; if (isdigit((int) *net)) { fprintf(stderr, "aoecfg Error: \"%s\" %s\n", net, "is not a valid network interface"); usage(); } } sfd = dial(net); if (getea(sfd, net, mac) == 0) exit(1); cfgquery(cmd, shelf, slot); return 0; } aoetools-36/aoe-version.80000644000076500007640000000103712026614322014754 0ustar ecashinbuild.TH aoe-version 8 .SH NAME aoe-version \- print AoE-related software version information .SH SYNOPSIS .nf .B aoe-version .fi .SH DESCRIPTION The .I aoe-version script collects information on running and installed ATA over Ethernet software, displaying a summary. .SH EXAMPLE .IP .EX .nf ellijay:~# aoe-version aoetools: 17 installed aoe driver: 50 running aoe driver: 50 .fi .EE .SH "SEE ALSO" .IR aoe-discover (8), .IR aoe-interfaces (8), .IR aoetools (8), .IR aoe-stat (8). .SH AUTHOR Ed L. Cashin (ecashin@coraid.com) aoetools-36/Makefile0000644000076500007640000000474712026614322014107 0ustar ecashinbuild# Makefile # You can edit this file or override these variables on # the commandline. For example, "make install MANDIR=/tmp/man" # would use defaults for all variables except ${MANDIR}. # You can set this to something like /opt/aoetools-x # if you want to install everything in one place. # # Note that even with ${PREFIX} set, the devices in # /dev/etherd will be used unless you override ${DEVDIR}. PREFIX = # Your aoe-driver device files should be in ${DEVDIR}. DEVDIR = /dev/etherd # The programs will be installed in ${SBINDIR}. SBINDIR = ${PREFIX}/usr/sbin MANDIR = ${PREFIX}/usr/share/man # NPERSHELF is the number of slot addresses per shelf address. # This number must match the same setting in the aoe driver. # # Older aoe drivers have NPERSHELF set to 10, and newer ones # use 16. # # You can see the setting in your driver like this in the driver # source directory. (Change into the "linux" directory if you're # using the standalone driver from CORAID.) # # grep 'NPERSHELF.*=' drivers/block/aoe/aoe.h # NPERSHELF=16 # end of user-configurable variables # these scripts are created from the *.in files CONF_SCRIPTS = aoe-discover aoe-interfaces aoe-mkshelf aoe-revalidate aoe-flush aoe-stat PROGS = aoeping aoecfg aoe-sancheck COMMANDS := ${CONF_SCRIPTS} aoe-mkdevs aoe-version coraid-update ${PROGS} CFLAGS = -Wall -O -g SANCHECKLIBS = -lpthread AOE_PING_OBJ = aoeping.o linux.o AOE_CFG_OBJ = aoecfg.o linux.o SANCHECK_OBJ = aoe-sancheck.o all : configure ${PROGS} @true configure : @for f in ${CONF_SCRIPTS}; do \ sh -xc "sed -e 's!@devdir@!${DEVDIR}!g' -e 's!@npershelf@!${NPERSHELF}!g' $$f.in > $$f" || break; \ done # DESTDIR was put in for Rob Holland to make gentoo packaging easier install : all mkdir -p ${DESTDIR}${SBINDIR} mkdir -p ${DESTDIR}${MANDIR}/man8 @for f in ${COMMANDS}; do \ sh -xc "install -m 700 $$f ${DESTDIR}${SBINDIR}/$$f" || break; \ sh -xc "install -m 664 $$f.8 ${DESTDIR}${MANDIR}/man8/$$f.8" || break; \ done clean : rm -f ${CONF_SCRIPTS} ${AOE_PING_OBJ} ${AOE_CFG_OBJ} ${SANCHECK_OBJ} ${PROGS} aoeping : ${AOE_PING_OBJ} ${CC} ${CFLAGS} -o $@ ${AOE_PING_OBJ} aoeping.o : aoeping.c dat.h fns.h ${CC} ${CFLAGS} -o $@ -c $< linux.o : linux.c config.h ${CC} ${CFLAGS} -o $@ -c $< aoecfg: ${AOE_CFG_OBJ} ${CC} ${CFLAGS} -o $@ ${AOE_CFG_OBJ} aoecfg.o : aoecfg.c dat.h fns.h ${CC} ${CFLAGS} -o $@ -c $< aoe-sancheck : ${SANCHECK_OBJ} -$(CC) $(CFLAGS) -o $@ ${SANCHECK_OBJ} $(SANCHECKLIBS) aoe-sancheck.o : aoe-sancheck.c -$(CC) $(CFLAGS) -o $@ -c $< aoetools-36/aoe-revalidate.80000644000076500007640000000156012026614322015410 0ustar ecashinbuild.TH aoe-revalidate 8 .SH NAME aoe-revalidate \- revalidate the disk size of an aoe device .SH SYNOPSIS .nf .B aoe-revalidate e{major}.{minor} .fi .SH DESCRIPTION The .I aoe-revalidate command tells the aoe driver to revalidate the disk size of an open aoe device. Normally the aoe driver will only acknowledge changes in an aoe device's disk size when the aoe device is not open. .PP It should be noted that if an aoe device's disk size shrinks in revalidation any users may become hopelessly confused when their resumed I/O starts to fail. .SH EXAMPLE .EX .nf nai# aoe-stat | grep e1.9 e1.9 82.348GB eth0 up nai# < /dev/etherd/e1.9 sleep 600 & [1] 13006 nai# aoe-revalidate e1.9 nai# aoe-stat | grep e1.9 e1.9 164.696GB eth0 up .fi .EE .SH "SEE ALSO" .IR aoe-stat (8), .IR aoetools (8). .SH AUTHOR Sam Hopkins (sah@coraid.com) aoetools-36/coraid-update0000755000076500007640000000421012026614322015077 0ustar ecashinbuild#! /bin/sh # usage: coraid-update {update file} {AoE target} # coraid-update depends upon sysfs mounted on /sys # The destination must be, # 1) an AoE target ready for I/O, and # 2) not too big to be an update target # # Later, when CORAID appliances mark update targets with special ATA # device identify content or special target content, a prompt should # be added after the check of the target's size if the identifying # content is not detected. # # The update file must either, # 1) be an SR tarc file that looks OK to the local tar, or # 2) any file not ending in ".tarc". # size of update LUN in /proc/partitions is 40000 max=70000 usage="usage: coraid-update {update file} {AoE device}" if test "$#" != 2; then echo "$usage" 1>&2 exit 1 fi update="$1" ulb="$2" # if it's an update target, it should be in `aoe-stat` aoe-stat | awk -vt="`basename $ulb`" ' BEGIN{fail=1} $1==t{fail=0} END{exit fail}' || { exec 1>&2 echo "coraid-update Error: \"$ulb\" is not an AoE target" echo "$usage" exit 1 } # it should have a size no larger than $max in /proc/partitions t="`echo $ulb | sed 's!^/dev/!!'`" awk -vt="$t" '$NF==t{print $3}' /proc/partitions | awk -vhi=$max -vdev="$ulb" ' BEGIN{ err = "could not get size of " dev } { err = "none" if ($1 > hi) { err = dev " is too large to be an update target" exit } } END{ if (err != "none") { print "Error coraid-update: " err > "/dev/stderr" exit 1 } exit 0 }' || exit 1 # this test should be removed when it is performed on the appliance # # For a 2734080-byte tarc file, an incomplete file of 2727450 bytes passes # this test, but one of 2727400 does not. So this test isn't fullproof. # if test "`echo \"$update\" | grep '\.tarc$'`"; then tar tf "$update" > /dev/null 2>&1 || { exec 1>&2 echo "coraid-update Error: \"$update\" does not appear to be a valid tarc file" exit 1 } fi if test ! -r "$update"; then echo "coraid-update Error: \"$update\" is not readable" 1>&2 exit 1 fi # send it over and complain on error if ! dd if="$update" of="$ulb" 2> /dev/null || ! sync; then exec 1>&2 echo "coraid-update Error: could not successfully write \"$update\" to \"$ulb\"" exit 1 fi aoetools-36/COPYING0000644000076500007640000004311012026614322013465 0ustar ecashinbuild GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.