Browse Source

Import upstream version 3

Ed L. Cashin 19 years ago
commit
3c1ef57e16
21 changed files with 1649 additions and 0 deletions
  1. 340 0
      COPYING
  2. 23 0
      HACKING
  3. 57 0
      Makefile
  4. 10 0
      NEWS
  5. 31 0
      README
  6. 64 0
      aoe-discover.8
  7. 4 0
      aoe-discover.in
  8. 67 0
      aoe-interfaces.8
  9. 14 0
      aoe-interfaces.in
  10. 37 0
      aoe-mkdevs
  11. 56 0
      aoe-mkdevs.8
  12. 26 0
      aoe-mkshelf
  13. 58 0
      aoe-mkshelf.8
  14. 27 0
      aoe-stat
  15. 80 0
      aoe-stat.8
  16. 149 0
      aoeping.8
  17. 423 0
      aoeping.c
  18. 1 0
      config.h
  19. 97 0
      dat.h
  20. 3 0
      fns.h
  21. 82 0
      linux.c

+ 340 - 0
COPYING

@@ -0,0 +1,340 @@
+		    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.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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.
+
+  <signature of Ty Coon>, 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.

+ 23 - 0
HACKING

@@ -0,0 +1,23 @@
+Contributing
+
+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.

+ 57 - 0
Makefile

@@ -0,0 +1,57 @@
+# 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
+
+# end of user-configurable variables
+
+
+# these scripts are created from the *.in files
+CONF_SCRIPTS = aoe-discover aoe-interfaces
+PROGS = aoeping
+COMMANDS := ${CONF_SCRIPTS} aoe-mkdevs aoe-mkshelf aoe-stat ${PROG}
+CFLAGS = -Wall -O -g
+
+AOE_PING_OBJ = aoeping.o linux.o
+
+all : configure ${PROGS}
+	@true
+
+configure :
+	@for f in ${CONF_SCRIPTS}; do \
+	  sh -xc "sed 's!@devdir@!${DEVDIR}!g' $$f.in > $$f" || break; \
+	done
+
+install : configure
+	mkdir -p ${SBINDIR}
+	mkdir -p ${MANDIR}/man8
+	@for f in ${COMMANDS}; do \
+	  sh -xc "install -m 700 $$f ${SBINDIR}/$$f" || break; \
+	  sh -xc "install -m 664 $$f.8 ${MANDIR}/man8/$$f.8" || break; \
+	done
+
+clean :
+	rm -f ${CONF_SCRIPTS} ${AOE_PING_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 $<

+ 10 - 0
NEWS

@@ -0,0 +1,10 @@
+2005-04-14 17:51:44 GMT Ed L. Cashin <ecashin@coraid.com>
+	release 3
+	add very basic SMART support to aoeping
+
+2005-04-12 20:20:14 GMT Ed L. Cashin <ecashin@coraid.com>
+	release 2
+	add aoeping, a userland tool for simple AoE communications
+
+2005-03-23 16:25:50 GMT	Ed L. Cashin <ecashin@coraid.com>
+	initial release of aoetools, version 1

+ 31 - 0
README

@@ -0,0 +1,31 @@
+The aoetools are programs that assist in using ATA over Ethernet.  For
+now, the tools are designed to work with the "aoe" driver for Linux
+2.6 kernels.  Support for 2.4 kernels and other operating systems
+would be helpful, but we're starting with 2.6 support.
+
+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.
+
+Here is a brief list of the tools.  Please see the man pages for
+further details.
+
+  aoe-discover		trigger discovery of ATA over Ethernet 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-stat		print status information for AoE devices
+  aoeping		simple userland communication with AoE devices
+
+The aoetools homepage
+  http://aoetools.sourceforge.net/
+
+The Coraid homepage
+  http://www.coraid.com/
+  http://www.coraid.com/support/linux/

+ 64 - 0
aoe-discover.8

@@ -0,0 +1,64 @@
+.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
+ 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:~# 
+.EE
+.LP
+.SH "SEE ALSO"
+.IR aoe-interfaces (8),
+.IR aoe-mkdevs (8),
+.IR aoe-mkshelf (8),
+.IR aoe-stat (8).
+.SH AUTHOR
+Ed L. Cashin (ecashin@coraid.com)

+ 4 - 0
aoe-discover.in

@@ -0,0 +1,4 @@
+#! /bin/sh
+# aoe-discover - trigger an AoE device discovery
+
+echo > @devdir@/discover

+ 67 - 0
aoe-interfaces.8

@@ -0,0 +1,67 @@
+.TH aoe-interfaces 8
+.SH NAME
+aoe-interfaces \- restrict aoe driver to specified network interfaces
+.SH SYNOPSIS
+.nf
+.B aoe-interfaces [dev1] [dev2 ...]
+.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.
+.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 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
+ 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
+.EE
+.LP
+.SH "SEE ALSO"
+.IR aoe-discover (8),
+.IR aoe-mkdevs (8),
+.IR aoe-mkshelf (8),
+.IR aoe-stat (8).
+.SH AUTHOR
+Ed L. Cashin (ecashin@coraid.com)

+ 14 - 0
aoe-interfaces.in

@@ -0,0 +1,14 @@
+#! /bin/sh
+# aoe-interfaces
+
+listf=/sys/module/aoe/parameters/aoe_iflist
+
+if test -z "$*"; then
+	test -r $listf && cat $listf
+else
+	if test -w $listf; then
+		printf '%s' "$*" > $listf
+	else
+		printf '%s' "$*" > @devdir@/interfaces
+	fi
+fi

+ 37 - 0
aoe-mkdevs

@@ -0,0 +1,37 @@
+#!/bin/sh
+
+n_shelves=${n_shelves:-10}
+n_partitions=${n_partitions:-16}
+
+if test "$#" != "1"; then
+	echo "Usage: sh `basename $0` {dir}" 1>&2
+	echo "       n_partitions=16 sh `basename $0` {dir}" 1>&2
+	exit 1
+fi
+dir=$1
+
+MAJOR=152
+
+set -e
+
+mkdir -p $dir
+
+# (Status info is in sysfs.  See status.sh.)
+# rm -f $dir/stat
+# mknod -m 0400 $dir/stat c $MAJOR 1
+rm -f $dir/err
+mknod -m 0400 $dir/err c $MAJOR 2
+rm -f $dir/discover
+mknod -m 0200 $dir/discover c $MAJOR 3
+rm -f $dir/interfaces
+mknod -m 0200 $dir/interfaces c $MAJOR 4
+
+# pass along the env var to aoe-mkshelf
+export n_partitions
+
+mkshelf=`echo $0 | sed 's!mkdevs!mkshelf!'`
+i=0
+while test $i -lt $n_shelves; do
+	sh $mkshelf $dir $i
+	i=`expr $i + 1`
+done

+ 56 - 0
aoe-mkdevs.8

@@ -0,0 +1,56 @@
+.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 uses mknod to create the character special files necessary to
+control the aoe driver.  It also uses 
+.I aoe-mkshelf
+to create block special files.
+.PP
+If 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 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
+  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
+.EE
+.LP
+.SH "SEE ALSO"
+.IR aoe-discover (8),
+.IR aoe-interfaces (8),
+.IR aoe-mkshelf (8),
+.IR aoe-stat (8).
+.SH AUTHOR
+Ed L. Cashin (ecashin@coraid.com)

+ 26 - 0
aoe-mkshelf

@@ -0,0 +1,26 @@
+#! /bin/sh
+
+if test "$#" != "2"; then
+	echo "Usage: sh `basename $0` {dir} {shelfaddress}" 1>&2
+	echo "       n_partitions=16 sh `basename $0` {dir} {shelfaddress}" 1>&2
+	exit 1
+fi
+n_partitions=${n_partitions:-16}
+dir=$1
+shelf=$2
+MAJOR=152
+
+set -e
+
+minor=`echo 10 \* $shelf \* $n_partitions | bc`
+endp=`echo $n_partitions - 1 | bc`
+for slot in `seq 0 9`; do
+	for part in `seq 0 $endp`; do
+		name=e$shelf.$slot
+		test "$part" != "0" && name=${name}p$part
+		rm -f $dir/$name
+		mknod -m 0660 $dir/$name b $MAJOR $minor
+
+		minor=`expr $minor + 1`
+	done
+done

+ 58 - 0
aoe-mkshelf.8

@@ -0,0 +1,58 @@
+.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 uses mknod to create the block special files necessary to
+access the AoE devices with the given shelf address.
+.PP
+If 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
+  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:~# 
+.EE
+.LP
+.SH "SEE ALSO"
+.IR aoe-discover (8),
+.IR aoe-interfaces (8),
+.IR aoe-mkdevs (8),
+.IR aoe-stat (8).
+.SH AUTHOR
+Ed L. Cashin (ecashin@coraid.com)

+ 27 - 0
aoe-stat

@@ -0,0 +1,27 @@
+#! /bin/sh
+# collate and present sysfs information about AoE storage
+
+set -e
+format="%8s\t%8s\t%8s\n"
+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
+}
+
+for d in `ls -d $sysd/block/etherd* 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/.*!//'`
+	printf "$format" \
+		"$dev" \
+		"`cat \"$d/netif\"`" \
+		"`cat \"$d/state\"`"
+done | sort

+ 80 - 0
aoe-stat.8

@@ -0,0 +1,80 @@
+.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 ifname
+The network interface name is printed in the second column.
+.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 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 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
+ nai:~# modprobe aoe
+ nai:~# aoe-stat
+ nai:~# ifconfig eth3 up
+ 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
+ nai:~# 
+.EE
+.LP
+.SH "SEE ALSO"
+.IR aoe-discover (8),
+.IR aoe-interfaces (8),
+.IR aoe-mkdevs (8),
+.IR aoe-mkshelf (8).
+.SH AUTHOR
+Ed L. Cashin (ecashin@coraid.com)

+ 149 - 0
aoeping.8

@@ -0,0 +1,149 @@
+.TH aoeping 8
+.SH NAME
+aoeping \- simple communication with AoE device
+.SH SYNOPSIS
+.nf
+.B aoeping [options] {shelf} {slot} {netif}
+.fi
+.SH DESCRIPTION
+The
+.I aoeping
+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 
+short usage summary being displayed.
+.PP
+The \fBaoeping\fP 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
+.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-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 \fBaoeping\fP 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, \fBaoeping\fP 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
+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 \fBaoeping\fP to check for the presence of aoe device e10.9 on
+network interface eth0.
+.IP
+.EX
+  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 
+.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
+  bash# aoeping -i -s 20 \\
+    10 9 eth0 > /dev/null \\
+    && echo ok
+  ok
+.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
+  bash# aoeping -S return_status \\
+    10 9 eth0 | grep 'LBA Mid: 0x4f' \\
+    > /dev/null \\
+    && echo ok
+  ok
+.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://www.coraid.com/documents/AoEr8.txt,
+
+\fIATA specification\fP
+.SH AUTHOR
+Ed L. Cashin (ecashin@coraid.com)

+ 423 - 0
aoeping.c

@@ -0,0 +1,423 @@
+/* aoeping.c - userland aoe pinger
+ *
+ * run without arguments for usage
+ */
+#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 "dat.h"
+#include "fns.h"
+
+struct progopts {
+	int shelf;
+	int slot;
+	char *netif;
+	int verbose;
+	int timeout;
+	u32 tag;
+	char *smart;
+	char ata_ident;
+};
+
+static struct progopts defaults = {
+	.shelf = 0,
+	.slot = 0,
+	.netif = NULL,
+	.verbose = 0,
+	.timeout = 0,
+	.tag = 0,
+	.smart = NULL,
+	.ata_ident = 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];
+
+#if 0
+void
+show_opts(struct progopts *opts)
+{
+	printf("shelf: %d\n", opts->shelf);
+	printf("slot: %d\n", opts->slot);
+	printf("netif: %s\n", opts->netif);
+	printf("verbose: %d\n", opts->verbose);
+	printf("timeout: %d\n", opts->timeout);
+	printf("tag: %d\n", opts->tag);
+	printf("ata_ident: %d\n", (int) opts->ata_ident);
+}
+#endif
+
+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",
+		"options:",
+		"-i\tdo ATA device identify",
+		"-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, char *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, int shelf, int slot)
+{
+	int n;
+	uchar buf[1400];
+
+	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(shelf);
+	h->min = slot;
+	h->cmd = Config;
+	c->bufcnt = 3;
+	c->vercmd = 0x10 | Qread;
+	memset(c->data, 0xED, sizeof c->data);
+	c->len = htons(1024);
+	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) != shelf
+			|| h->min != slot)
+			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(int fd, char *buf, size_t siz, Conf *c)
+{
+	Aoehdr *h;
+	int n;
+
+	for (;;) {
+		n = read(fd, 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)
+			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);
+}
+
+void
+disk_identify(Conf *c, u32 tag)
+{
+	int n;
+	uchar buf[1400];
+	Ata a;
+	Ata *p;
+
+	ata_prep(&a, c, 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(sfd, buf, sizeof buf, c);
+	p = (Ata *) buf;
+	puts("device identify response:");
+	hex_print(stdout, p->data, 512, " ");
+}
+
+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);
+}
+
+void
+show_smart_regs(Ata *a)
+{
+	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]);
+}
+
+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(sfd, buf, sizeof buf, c);
+	p = (Ata *) buf;
+	show_smart_regs(p);
+	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, "hvit: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 '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;
+
+	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.shelf, opts.slot);
+	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) {
+		alarm(opts.timeout);
+		disk_identify(&c, opts.tag);
+		alarm(0);
+		opts.tag += 1;
+	}
+
+	if (opts.smart) {
+		alarm(opts.timeout);
+		smart(&c, opts.tag, opts.smart);
+		alarm(0);
+		opts.tag += 1;
+	}
+
+	return 0;
+}

+ 1 - 0
config.h

@@ -0,0 +1 @@
+#define _FILE_OFFSET_BITS 64 

+ 97 - 0
dat.h

@@ -0,0 +1,97 @@
+/* dat.h - aoetools type definitions and macros
+ */
+
+#define	nil	NULL
+#define AOE_ETH_PROTO 0x88a2
+
+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	filler;
+	uchar	vercmd;
+	u16	len;
+	uchar	data[1024];
+};
+
+enum {
+	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,
+
+	SmartDataPut = 0x01,
+	SmartDataRet = 0x10,
+};

+ 3 - 0
fns.h

@@ -0,0 +1,3 @@
+int dial(char *eth);
+int getea(int s, char *name, uchar *ea);
+

+ 82 - 0
linux.c

@@ -0,0 +1,82 @@
+// linux.c: low level access routines for Linux
+#include "config.h"
+#include <sys/socket.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <features.h>    /* for the glibc version number */
+#if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1
+#include <netpacket/packet.h>
+#include <net/ethernet.h>     /* the L2 protocols */
+#else
+#include <asm/types.h>
+#include <linux/if_packet.h>
+#include <linux/if_ether.h>   /* The L2 protocols */
+#endif
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <linux/fs.h>
+#include <sys/stat.h>
+
+#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;
+}