Browse Source

Import upstream version 21

Ed L. Cashin 16 years ago
parent
commit
7eff639d44
29 changed files with 798 additions and 105 deletions
  1. 1 0
      .gitignore
  2. 8 3
      Makefile
  3. 39 0
      NEWS
  4. 11 21
      README
  5. 2 3
      aoe-discover.8
  6. 7 0
      aoe-discover.in
  7. 2 1
      aoe-flush.8
  8. 8 1
      aoe-flush.in
  9. 4 4
      aoe-interfaces.8
  10. 27 4
      aoe-interfaces.in
  11. 21 1
      aoe-mkdevs
  12. 21 5
      aoe-mkdevs.8
  13. 17 4
      aoe-mkshelf.8
  14. 23 3
      aoe-mkshelf.in
  15. 2 1
      aoe-revalidate.8
  16. 8 1
      aoe-revalidate.in
  17. 23 1
      aoe-stat.8
  18. 18 2
      aoe-stat
  19. 34 0
      aoe-version
  20. 29 0
      aoe-version.8
  21. 77 0
      aoecfg.8
  22. 240 0
      aoecfg.c
  23. 26 9
      aoeping.8
  24. 72 17
      aoeping.c
  25. 45 0
      aoetools.8
  26. 10 7
      dat.h
  27. 18 15
      devnodes.txt
  28. 1 0
      fns.h
  29. 4 2
      linux.c

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+*~

+ 8 - 3
Makefile

@@ -37,12 +37,13 @@ NPERSHELF=16
 
 
 # these scripts are created from the *.in files
-CONF_SCRIPTS = aoe-discover aoe-interfaces aoe-mkshelf aoe-revalidate aoe-flush
-PROGS = aoeping
-COMMANDS := ${CONF_SCRIPTS} aoe-mkdevs aoe-stat ${PROGS}
+CONF_SCRIPTS = aoe-discover aoe-interfaces aoe-mkshelf aoe-revalidate aoe-flush aoe-stat
+PROGS = aoeping aoecfg
+COMMANDS := ${CONF_SCRIPTS} aoe-mkdevs aoe-version ${PROGS}
 CFLAGS = -Wall -O -g
 
 AOE_PING_OBJ = aoeping.o linux.o
+AOE_CFG_OBJ = aoecfg.o linux.o
 
 all : configure ${PROGS}
 	@true
@@ -70,3 +71,7 @@ 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 $<

+ 39 - 0
NEWS

@@ -1,3 +1,42 @@
+2007-10-29 "Ed L. Cashin" <ecashin@coraid.com>
+	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" <ecashin@coraid.com>
+	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" <ecashin@coraid.com>
+	add copyright information
+	support kernel.org aoe driver in aoe-version
+	add aoetools manpage
+	release 19
+
+2007-08-08 "Ed L. Cashin" <ecashin@coraid.com>
+	distinguish between missing device nodes and wrong ones
+	release 18
+
+2007-07-26 "Ed L. Cashin" <ecashin@coraid.com>
+	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" <ecashin@coraid.com>
+	check for char devices specifically before using them
+
+2007-06-01 "Ed L. Cashin" <ecashin@coraid.com>
+	workaround dash POSIX math bug
+	release 16
+
 2007-03-20 "Ed L. Cashin" <ecashin@coraid.com>
 	add quoting to aoe-flush
 	release 15

+ 11 - 21
README

@@ -7,19 +7,14 @@ the aoetools.  The aoe driver for 2.4 kernels is self sufficient.
 --------------------------------------------------------------------
 AOE DRIVER COMPATIBILITY
 
-  ATA over Ethernet (AoE) devices have a shelf address and a slot
-  address. The aoe driver used to support only 10 slots per shelf
-  address. The 2.6.14 kernel contains an aoe driver that supports up
-  to 16 slots per shelf address. This change means that ...
-  
-     1. It's easy to use the aoetools that come bundled with the aoe
-        driver at the Coraid website.
-  
-     2. It's easy to use aoetools-8 or later with kernels 2.6.14 or
-        later.
-  
-     3. It's easy to use other combinations as long as you read the
-        information in the devnodes.txt file here.
+  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.
 --------------------------------------------------------------------
 
 
@@ -33,17 +28,12 @@ aoetools software and documentation:
 You'll need sufficient permissions to install in the default locations
 if you haven't overridden them with your own locations.
 
-Here is a brief list of the tools.  Please see the man pages for
-further details.
+Please see the aoetools manpage for a brief list of the tools.
+
+These two are legacy commands for systems without udev.
 
-  aoe-discover		trigger discovery of ATA over Ethernet devices
-  aoe-flush		ask aoe driver to forget down devices
-  aoe-interfaces	restrict network interfaces used for AoE
   aoe-mkdevs		create character and block device files
   aoe-mkshelf		create block device files for one shelf address
-  aoe-revalidate	ask the aoe driver to update its state for a device
-  aoe-stat		print status information for AoE devices
-  aoeping		simple userland communication with AoE devices
 
 The aoetools homepage
   http://aoetools.sourceforge.net/

+ 2 - 3
aoe-discover.8

@@ -57,8 +57,7 @@ nai:~# aoe-stat
 .EE
 .SH "SEE ALSO"
 .IR aoe-interfaces (8),
-.IR aoe-mkdevs (8),
-.IR aoe-mkshelf (8),
-.IR aoe-stat (8).
+.IR aoe-stat (8),
+.IR aoetools (8).
 .SH AUTHOR
 Ed L. Cashin (ecashin@coraid.com)

+ 7 - 0
aoe-discover.in

@@ -1,5 +1,6 @@
 #! /bin/sh
 # aoe-discover - trigger an AoE device discovery
+# Copyright 2007, Coraid, Inc., and licensed under GPL v.2.
 
 zero=`basename $0`
 f=@devdir@/discover
@@ -8,4 +9,10 @@ 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

+ 2 - 1
aoe-flush.8

@@ -38,6 +38,7 @@ beacon.
 may be used to force this behaviour.
 .SH "SEE ALSO"
 .IR aoe-stat (8),
-.IR aoe-discover (8).
+.IR aoe-discover (8),
+.IR aoetools (8).
 .SH AUTHOR
 Sam Hopkins (sah@coraid.com)

+ 8 - 1
aoe-flush.in

@@ -1,5 +1,6 @@
 #! /bin/sh
-# aoe-flush
+# aoe-flush - ask aoe driver to forget about devices
+# Copyright 2007, Coraid, Inc., and licensed under GPL v.2.
 
 zero="`basename $0`"
 f="@devdir@/flush"
@@ -9,6 +10,12 @@ 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
 
 if test "$1" = "-a"; then
 	spec=all

+ 4 - 4
aoe-interfaces.8

@@ -3,7 +3,8 @@
 aoe-interfaces \- restrict aoe driver to specified network interfaces
 .SH SYNOPSIS
 .nf
-.B aoe-interfaces [-c] [dev1] [dev2 ...]
+.B aoe-interfaces [dev1] [dev2 ...]
+.B aoe-interfaces -c
 .fi
 .SH DESCRIPTION
 The
@@ -65,8 +66,7 @@ eth0 eth3
 .EE
 .SH "SEE ALSO"
 .IR aoe-discover (8),
-.IR aoe-mkdevs (8),
-.IR aoe-mkshelf (8),
-.IR aoe-stat (8).
+.IR aoe-stat (8),
+.IR aoetools (8).
 .SH AUTHOR
 Ed L. Cashin (ecashin@coraid.com)

+ 27 - 4
aoe-interfaces.in

@@ -1,5 +1,6 @@
 #! /bin/sh
-# aoe-interfaces
+# aoe-interfaces - set or list the allowed AoE network interfaces
+# Copyright 2007, Coraid, Inc., and licensed under GPL v.2.
 
 zero="`basename $0`"
 devf=@devdir@/interfaces
@@ -15,16 +16,38 @@ if test -z "$*"; then
 	exit
 fi
 
-if test $1 = "-c"; then
+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' "$*" > "$sysf"
+	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
-	printf '%s\0' "$*" > "$devf"
+	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

+ 21 - 1
aoe-mkdevs

@@ -1,4 +1,6 @@
 #!/bin/sh
+# aoe-mkdevs - make static device nodes on systems without udev
+# Copyright 2007, Coraid, Inc., and licensed under GPL v.2.
 
 n_shelves=${n_shelves:-10}
 n_partitions=${n_partitions:-16}
@@ -9,9 +11,27 @@ if test "$#" != "1"; then
 	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 <<EOF
+$zero Error: aoe module is using dynamic devices.
+$zero: Please see the aoe-mkdevs manpage.
+$zero: Exiting.
+EOF
+	exit 1
+fi
+if test "`ps axwwww | grep 'udev[d]'`" || test -d "/dev/.udev"; then
+	cat 1>&2 <<EOF
+$zero Error: udev detected.  You shouldn't need to use $zero.
+$zero: Please see the aoe-mkdevs manpage.
+$zero: Exiting.
+EOF
+	exit 1
+fi
+
 set -e
 
 mkdir -p $dir

+ 21 - 5
aoe-mkdevs.8

@@ -9,12 +9,26 @@ aoe-mkdevs \- create special device files for aoe driver
 .SH DESCRIPTION
 The
 .I aoe-mkdevs
-command uses mknod to create the character special files necessary to
-control the aoe driver.  It also uses 
+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 create block special files.
+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 your aoe driver supports only one partition per device (whole-disk
+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.
@@ -52,6 +66,8 @@ nai:~# ls /dev/etherd | wc -l
 .IR aoe-discover (8),
 .IR aoe-interfaces (8),
 .IR aoe-mkshelf (8),
-.IR aoe-stat (8).
+.IR aoe-stat (8),
+.IR aoetools (8),
+.IR udev (7).
 .SH AUTHOR
 Ed L. Cashin (ecashin@coraid.com)

+ 17 - 4
aoe-mkshelf.8

@@ -9,10 +9,21 @@ aoe-mkshelf \- create special device files for one shelf address
 .SH DESCRIPTION
 The
 .I aoe-mkshelf
-command uses mknod to create the block special files necessary to
-access the AoE devices with the given shelf address.
+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
-If your aoe driver supports only one partition per device (whole-disk
+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.
@@ -54,6 +65,8 @@ nai:~#
 .IR aoe-discover (8),
 .IR aoe-interfaces (8),
 .IR aoe-mkdevs (8),
-.IR aoe-stat (8).
+.IR aoe-stat (8),
+.IR aoetools (8),
+.IR udev (7).
 .SH AUTHOR
 Ed L. Cashin (ecashin@coraid.com)

+ 23 - 3
aoe-mkshelf.in

@@ -1,4 +1,6 @@
 #! /bin/sh
+# aoe-mkshelf - device nodes for one shelf without udev
+# Copyright 2007, Coraid, Inc., and licensed under GPL v.2.
 
 zero=`basename $0`
 
@@ -7,17 +9,35 @@ if test "$#" != "2"; then
 	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 <<EOF
+$zero Error: aoe module is using dynamic devices.
+$zero: Please see the aoe-mkshelf manpage.
+$zero: Exiting.
+EOF
+	exit 1
+fi
+if test "`ps axwwww | grep 'udev[d]'`" || test -d "/dev/.udev"; then
+	cat 1>&2 <<EOF
+$zero Error: udev detected.  You shouldn't need to use $zero.
+$zero: Please see the aoe-mkshelf manpage.
+$zero: Exiting.
+EOF
+	exit 1
+fi
+
 n_partitions=${n_partitions:-16}
 dir=$1
 shelf=$2
 nslots=@npershelf@
-maxslot=$((nslots - 1))
+maxslot=$(($nslots - 1))
 MAJOR=152
 
 set -e
 
-minor=$((nslots * shelf * n_partitions))
-endp=$((n_partitions - 1))
+minor=$(($nslots * $shelf * $n_partitions))
+endp=$(($n_partitions - 1))
 for slot in `seq 0 $maxslot`; do
 	for part in `seq 0 $endp`; do
 		name=e$shelf.$slot

+ 2 - 1
aoe-revalidate.8

@@ -27,6 +27,7 @@ nai# aoe-stat | grep e1.9
 .fi
 .EE
 .SH "SEE ALSO"
-.IR aoe-stat (8).
+.IR aoe-stat (8),
+.IR aoetools (8).
 .SH AUTHOR
 Sam Hopkins (sah@coraid.com)

+ 8 - 1
aoe-revalidate.in

@@ -1,5 +1,6 @@
 #! /bin/sh
-# aoe-revalidate
+# aoe-revalidate - ask aoe driver to query AoE target
+# Copyright 2007, Coraid, Inc., and licensed under GPL v.2.
 
 zero=`basename $0`
 f=@devdir@/revalidate
@@ -12,6 +13,12 @@ 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

+ 23 - 1
aoe-stat.8

@@ -47,6 +47,26 @@ 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
@@ -74,6 +94,8 @@ nai:~#
 .IR aoe-discover (8),
 .IR aoe-interfaces (8),
 .IR aoe-mkdevs (8),
-.IR aoe-mkshelf (8).
+.IR aoe-mkshelf (8),
+.IR aoetools (8),
+.IR udev (7).
 .SH AUTHOR
 Ed L. Cashin (ecashin@coraid.com)

+ 18 - 2
aoe-stat

@@ -1,5 +1,6 @@
 #! /bin/bash
-# collate and present sysfs information about AoE storage
+# aoe-stat - collate and present information about AoE storage
+# Copyright 2007, Coraid, Inc., and licensed under GPL v.2.
 
 set -e
 format="%10s %15s %6s %-14s\n"
@@ -15,13 +16,28 @@ test ! -d "$sysd/block" && {
 	exit 1
 }
 
+function 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 <<EOF
+$me Warning: device node @devdir@/$devname has wrong minor device number
+EOF
+		}
+	fi
+}
+
 for d in `ls -d $sysd/block/*e[0-9]*\.[0-9]* 2>/dev/null | grep -v p` end; do
 	# maybe ls comes up empty, so we use "end"
 	test $d = end && continue
 
 	dev=`echo "$d" | sed 's/.*!//'`
 	sectors="`cat \"$d/size\"`"
-	psize=$(((512000 * sectors) / (1000 * 1000 * 1000)))
+	minor="`awk -F: '{print $2}' \"$d/dev\"`"
+	checknode "$dev" "$minor"
+	psize=$(((512000 * $sectors) / (1000 * 1000 * 1000)))
 	psize=`printf "%04d\n" $psize | sed 's!\(...\)$!.\1!'`
 	printf "$format" \
 		"$dev" \

+ 34 - 0
aoe-version

@@ -0,0 +1,34 @@
+#! /bin/sh
+# aoe-version - display versions of AoE-related software
+# Copyright 2007, Coraid, Inc., and licensed under GPL v.2.
+
+aoetools=21
+
+# 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 | 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 <<EOF
+$aoetools aoetools
+$installed installed aoe driver
+$running running aoe driver
+EOF

+ 29 - 0
aoe-version.8

@@ -0,0 +1,29 @@
+.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)

+ 77 - 0
aoecfg.8

@@ -0,0 +1,77 @@
+.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 \-c " 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://www.coraid.com/documents/AoEr10.txt,
+\fIATA specification\fP
+.SH AUTHOR
+Erik Quanstrom (quanstro@coraid.com)

+ 240 - 0
aoecfg.c

@@ -0,0 +1,240 @@
+/*
+ * aoecfgstr.c - fiddle aoe configuration strings.
+ * Copyright 2007, Erik Quanstrom, Coraid, Inc., Licenced under GPL v2
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <time.h>
+#include <arpa/inet.h>
+#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 = 3;
+	c->vercmd = 0x10 | 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;
+}

+ 26 - 9
aoeping.8

@@ -2,19 +2,22 @@
 .SH NAME
 aoeping \- simple communication with AoE device
 .SH SYNOPSIS
-.nf
 .B aoeping [options] {shelf} {slot} {netif}
 .fi
 .SH DESCRIPTION
 The
-.I aoeping
+.IR aoeping (8)
 program performs simple one or two-round-trip communication with an
 ATA over Ethernet (AoE) device.
 .PP
-Running \fBaoeping\fP without command line arguments will result in a 
+Running
+.IR aoeping (8)
+without command line arguments will result in a 
 short usage summary being displayed.
 .PP
-The \fBaoeping\fP program will wait forever if if doesn't receive
+The
+.IR aoeping (8)
+program will wait forever if if doesn't receive
 an expected response.  The caller should use a time out to catch
 this situation.
 .SS Arguments
@@ -38,6 +41,12 @@ 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
@@ -46,7 +55,9 @@ response from the AoE device (see AoE spec at URL below).
 \fB-s\fP
 This option takes an argument.  The
 argument is a decimal integer that specifies the number of seconds
-that \fBaoeping\fP will wait for a response before timing out and
+that
+.IR aoeping (8)
+will wait for a response before timing out and
 exiting with a non-zero status.
 .TP
 \fB-S\fP
@@ -68,11 +79,15 @@ read_log:1".
   disable
   return_status
 
-For \fBwrite_log\fP, \fBaoeping\fP reads from
+For \fBwrite_log\fP,
+.IR aoeping (8)
+reads from
 standard input the one sector of data to be
 written to the specified log.
 
-The aoeping command just sends and receives SMART commands, without
+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
@@ -89,7 +104,9 @@ incremented by one.
 Show a usage summary.
 .SH EXAMPLE
 In this example, the root user
-uses \fBaoeping\fP to check for the presence of aoe device e10.9 on
+uses
+.IR aoeping (8)
+to check for the presence of aoe device e10.9 on
 network interface eth0.
 .IP
 .EX
@@ -148,7 +165,7 @@ device fault bit (bit 5) set.
 .IR aoe-mkshelf (8),
 .IR aoe-stat (8),
 
-\fIAoE (ATA over Ethernet)\fP: http://www.coraid.com/documents/AoEr8.txt,
+\fIAoE (ATA over Ethernet)\fP: http://www.coraid.com/documents/AoEr10.txt,
 
 \fIATA specification\fP
 .SH AUTHOR

+ 72 - 17
aoeping.c

@@ -1,4 +1,5 @@
 /* aoeping.c - userland aoe pinger
+ * Copyright 2007, Coraid, Inc., and licensed under GPL v.2.
  *
  * run without arguments for usage
  */
@@ -9,6 +10,7 @@
 #include <stdint.h>
 #include <ctype.h>
 #include <netinet/in.h>
+#include <linux/hdreg.h>
 #include <errno.h>
 #include "dat.h"
 #include "fns.h"
@@ -22,6 +24,7 @@ struct progopts {
 	u32 tag;
 	char *smart;
 	char ata_ident;
+	char pp_ataid;		/* pretty print ATA device identify response */
 };
 
 static struct progopts defaults = {
@@ -33,6 +36,7 @@ static struct progopts defaults = {
 	.tag = 0,
 	.smart = NULL,
 	.ata_ident = 0,
+	.pp_ataid = 0,
 };
 static struct progopts opts;
 
@@ -76,9 +80,10 @@ 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",
+	fprintf(stderr, "%s\n\t%s\n\t%s\n\t%s\n\t%s\n",
 		"options:",
-		"-i\tdo ATA device identify",
+		"-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",
@@ -102,10 +107,11 @@ hex_print(FILE *out, uchar *buf, int n, char *sep)
 }
 
 void
-find_blade(Conf *c, int shelf, int slot)
+find_blade(Conf *c, struct progopts *opts)
 {
 	int n;
 	uchar buf[1400];
+	u32 tag;
 
 	Aoehdr *h = &c->h;
 
@@ -115,9 +121,11 @@ find_blade(Conf *c, int shelf, int slot)
 	
 	h->type = htons(AOE_ETH_PROTO);
 	h->flags = AoEver << 4;
-	h->maj = htons(shelf);
-	h->min = slot;
+	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 = 3;
 	c->vercmd = 0x10 | Qread;
 	memset(c->data, 0xED, sizeof c->data);
@@ -136,12 +144,13 @@ find_blade(Conf *c, int shelf, int slot)
 			continue;
 		h = (Aoehdr *) buf;
 		if (ntohs(h->type) != AOE_ETH_PROTO
-			|| ntohs(h->maj) != shelf
-			|| h->min != slot)
+			|| ntohs(h->maj) != opts->shelf
+			|| h->min != opts->slot
+			|| memcmp(h->tag, &tag, sizeof h->tag))
 			continue;
 		break;
 	}
-	if (opts.verbose) {
+	if (opts->verbose) {
 		puts("config query response:");
 		hex_print(stdout, buf, n, " ");
 		putchar('\n');
@@ -152,13 +161,14 @@ find_blade(Conf *c, int shelf, int slot)
 /* read a packet that was sent by the device that returned *c earlier
  */
 int
-aoe_pkt_read(int fd, uchar *buf, size_t siz, Conf *c)
+aoe_pkt_read(uchar *buf, size_t siz, Conf *c, u32 tag)
 {
 	Aoehdr *h;
 	int n;
 
+	tag = htonl(tag);
 	for (;;) {
-		n = read(fd, buf, siz);
+		n = read(sfd, buf, siz);
 		if (n < 0) {
 			perror("read network");
 			exit(EXIT_FAILURE);
@@ -168,7 +178,8 @@ aoe_pkt_read(int fd, uchar *buf, size_t siz, Conf *c)
 		h = (Aoehdr *) buf;
 		if (ntohs(h->type) != AOE_ETH_PROTO
 			|| h->maj != c->h.maj
-			|| h->min != c->h.min)
+			|| h->min != c->h.min
+			|| memcmp(&tag, h->tag, sizeof h->tag))
 			continue;
 		break;
 	}
@@ -192,6 +203,25 @@ ata_prep(Ata *a, Conf *c, u32 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');
+}
+
 void
 disk_identify(Conf *c, u32 tag)
 {
@@ -199,6 +229,7 @@ disk_identify(Conf *c, u32 tag)
 	uchar buf[1400];
 	Ata a;
 	Ata *p;
+	struct hd_driveid *id;
 
 	ata_prep(&a, c, tag);
 	a.sectors = 1;
@@ -210,10 +241,29 @@ disk_identify(Conf *c, u32 tag)
 		exit(EXIT_FAILURE);
 	}
 
-	n = aoe_pkt_read(sfd, buf, sizeof buf, c);
+	n = aoe_pkt_read(buf, sizeof buf, c, tag);
 	p = (Ata *) buf;
-	puts("device identify response:");
-	hex_print(stdout, p->data, 512, " ");
+
+	if (!opts.pp_ataid) {
+		puts("device identify response:");
+		hex_print(stdout, p->data, 512, " ");
+		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 *
@@ -295,7 +345,7 @@ smart(Conf *c, u32 tag, char *smart_cmd)
 		perror("send ATA identify device");
 		exit(EXIT_FAILURE);
 	}
-	n = aoe_pkt_read(sfd, buf, sizeof buf, c);
+	n = aoe_pkt_read(buf, sizeof buf, c, tag);
 	p = (Ata *) buf;
 	show_smart_regs(p);
 	if (s->data & SmartDataRet) {
@@ -330,7 +380,7 @@ init_opts(struct progopts *opts, int argc, char *argv[])
 {
 	int c;
 
-	while ( (c = getopt(argc, argv, "hvit:s:S:")) != -1) {
+	while ( (c = getopt(argc, argv, "hviIt:s:S:")) != -1) {
 		switch (c) {
 		case 'h':
 			usage();
@@ -342,6 +392,10 @@ init_opts(struct progopts *opts, int argc, char *argv[])
 		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;
@@ -395,7 +449,8 @@ main(int argc, char *argv[])
 		exit(EXIT_FAILURE);
 	
 	alarm(opts.timeout);
-	find_blade(&c, opts.shelf, opts.slot);
+	find_blade(&c, &opts);
+	opts.tag += 1;
 	alarm(0);
 	if (opts.verbose) {
 		printf("found e%d.%d with mac ",

+ 45 - 0
aoetools.8

@@ -0,0 +1,45 @@
+.TH aoetools 8
+.SH NAME
+aoetools \- utilities for AoE on systems running Linux 2.6
+.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
+.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 udev (7).

+ 10 - 7
dat.h

@@ -1,8 +1,9 @@
 /* dat.h - aoetools type definitions and macros
+ * Copyright 2007, Coraid, Inc., and licensed under GPL v.2.
  */
 
 #define	nil	NULL
-#define AOE_ETH_PROTO 0x88a2
+#define	nelem(x)	(sizeof(x)/sizeof((x)[0]))
 
 typedef unsigned char uchar;
 typedef struct Aoehdr Aoehdr;
@@ -62,13 +63,15 @@ struct Conf {
 };
 
 enum {
+	AOE_ETH_PROTO = 0x88a2,
+
 	AoEver = 1,
 
 	ATAcmd = 0,		// command codes
 	Config,
 
-	Resp = (1<<3),		// flags
-	Error = (1<<2),
+	Resp = 1<<3,		// flags
+	Error = 1<<2,
 
 	BadCmd = 1,
 	BadArg,
@@ -76,10 +79,10 @@ enum {
 	ConfigErr,
 	BadVersion,
 
-	Write = (1<<0),
-	Async = (1<<1),
-	Device = (1<<4),
-	Extend = (1<<6),
+	Write = 1<<0,
+	Async = 1<<1,
+	Device = 1<<4,
+	Extend = 1<<6,
 
 	Qread = 0,
 	Qtest,

+ 18 - 15
devnodes.txt

@@ -1,19 +1,28 @@
 			 Driver Compatibility
 
 Users of udev have device nodes like /dev/etherd/e0.0 created for them
-automatically, as needed. These are dynamic device nodes.
+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 devices are really available to the system. The
+regardless of what AoE devices are really available to the system. The
 aoetools contain the aoe-mkdevs and aoe-mkshelf commands, which create
-static device nodes.
+these static device nodes.
 
-To guard against confusion, it's important to have an aoetools
-installation that is compatible with your aoe driver. If you use an
-aoe driver from the Coraid website
+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://www.coraid.com/support/linux/) then just use the aoetools that
-come bundled with that deiver. If you didn't get your aoe driver from
-the Coraid website, then here's what to do:
+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.
 
@@ -23,13 +32,7 @@ the Coraid website, then here's what to do:
 
         make NPERSHELF=10
 
-    * To use aoetools-5 through aoetools-7 with newer 2.6 kernels
-      (2.6.14 and later), build the aoetools with an extra parameter
-      for "make", like this:
-
-        make NPERSHELF=16
-
-    * Using aoetools-4 and earlier with newer 2.6 kernels (2.6.14 and
+    * Using aoetools-7 and earlier with newer 2.6 kernels (2.6.14 and
       later) is not recommended.
 
 Other combinations should work with the default settings.

+ 1 - 0
fns.h

@@ -1,3 +1,4 @@
+/* Copyright 2007, Coraid, Inc., and licensed under GPL v.2. */
 int dial(char *eth);
 int getea(int s, char *name, uchar *ea);
 

+ 4 - 2
linux.c

@@ -1,4 +1,6 @@
-// linux.c: low level access routines for Linux
+/* linux.c: low level access routines for Linux
+ * Copyright 2007, Coraid, Inc., and licensed under GPL v.2.
+ */
 #include "config.h"
 #include <sys/socket.h>
 #include <stdio.h>
@@ -71,7 +73,7 @@ getea(int s, char *name, uchar *ea)
 	struct ifreq xx;
 	int n;
 
-        strcpy(xx.ifr_name, name);
+	strcpy(xx.ifr_name, name);
 	n = ioctl(s, SIOCGIFHWADDR, &xx);
 	if (n == -1) {
 		perror("Can't get hw addr");