[Endpoint-commits]
rev 2 - in trunk: . libjconfig librbc libsbp2 src
svn-commits at oss.oracle.com
svn-commits at oss.oracle.com
Thu Jul 17 20:27:11 CDT 2003
Author: manish
Date: 2003-07-17 14:27:07 -0500 (Thu, 17 Jul 2003)
New Revision: 2
Added:
trunk/AUTHORS
trunk/COPYING
trunk/ChangeLog
trunk/Makefile.am
trunk/NEWS
trunk/README
trunk/autogen.sh
trunk/configure.in
trunk/libjconfig/
trunk/libjconfig/Makefile.am
trunk/libjconfig/jconfig.c
trunk/libjconfig/jconfig.h
trunk/libjconfig/jiterator.c
trunk/libjconfig/jiterator.h
trunk/librbc/
trunk/librbc/Makefile.am
trunk/librbc/rbcbuffer.c
trunk/librbc/rbcbuffer.h
trunk/librbc/rbccommand.c
trunk/librbc/rbccommand.h
trunk/librbc/rbcdisk.c
trunk/librbc/rbcdisk.h
trunk/librbc/rbcprivate.h
trunk/librbc/rbctypes.h
trunk/libsbp2/
trunk/libsbp2/Makefile.am
trunk/libsbp2/sbp2byteswap.h
trunk/libsbp2/sbp2configrom.c
trunk/libsbp2/sbp2configrom.h
trunk/libsbp2/sbp2constants.h
trunk/libsbp2/sbp2csr.h
trunk/libsbp2/sbp2login.h
trunk/libsbp2/sbp2logout.h
trunk/libsbp2/sbp2main.c
trunk/libsbp2/sbp2main.h
trunk/libsbp2/sbp2manager.c
trunk/libsbp2/sbp2manager.h
trunk/libsbp2/sbp2pagetable.h
trunk/libsbp2/sbp2pointer.h
trunk/libsbp2/sbp2querylogins.h
trunk/libsbp2/sbp2raw1394.c
trunk/libsbp2/sbp2raw1394.h
trunk/libsbp2/sbp2reconnect.h
trunk/libsbp2/sbp2scsicommand.h
trunk/libsbp2/sbp2scsistatus.h
trunk/libsbp2/sbp2status.h
trunk/libsbp2/sbp2worker.c
trunk/libsbp2/sbp2worker.h
trunk/src/
trunk/src/Makefile.am
trunk/src/app.c
trunk/src/app.h
trunk/src/cleanup.c
trunk/src/cleanup.h
trunk/src/main.c
trunk/src/manager.c
trunk/src/manager.h
trunk/src/process.c
trunk/src/process.h
trunk/src/util.c
trunk/src/util.h
trunk/src/wire.c
trunk/src/wire.h
trunk/src/worker.c
trunk/src/worker.h
Log:
Initial import
Added: trunk/AUTHORS
==============================================================================
--- trunk/AUTHORS 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/AUTHORS 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1 @@
+Manish Singh <manish.singh at oracle.com>
Added: trunk/COPYING
==============================================================================
--- trunk/COPYING 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/COPYING 2003-07-17 19:27:07 UTC (rev 2)
@@ -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.
Added: trunk/ChangeLog
==============================================================================
--- trunk/ChangeLog 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/ChangeLog 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,3 @@
+Thu Jul 17 12:19:36 2003 Manish Singh <manish.singh at oracle.com>
+
+ * Initial import
Added: trunk/Makefile.am
==============================================================================
--- trunk/Makefile.am 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/Makefile.am 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1 @@
+SUBDIRS = libjconfig librbc libsbp2 src
Added: trunk/NEWS
==============================================================================
Added: trunk/README
==============================================================================
--- trunk/README 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/README 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,4 @@
+Endpoint turns a Linux machine with one or more firewire cards into an SBP-2
+device. The advantage is that you can use any file or device the linux
+machine supports as storage, and that multiple clients can sit on separate
+buses so they can get the full bandwidth of the bus.
Added: trunk/autogen.sh
==============================================================================
--- trunk/autogen.sh 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/autogen.sh 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+aclocal-1.7 $ACLOCAL_FLAGS
+autoheader
+automake-1.7 -a
+autoconf
+
+./configure --enable-maintainer-mode "$@"
Added: trunk/configure.in
==============================================================================
--- trunk/configure.in 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/configure.in 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,52 @@
+AC_PREREQ(2.53)
+
+AC_INIT(libsbp2/sbp2manager.c)
+
+PACKAGE=endpoint
+
+ENDPOINT_MAJOR_VERSION=0
+ENDPOINT_MINOR_VERSION=1
+ENDPOINT_MICRO_VERSION=0
+
+VERSION=$ENDPOINT_MAJOR_VERSION.$ENDPOINT_MINOR_VERSION.$ENDPOINT_MICRO_VERSION
+
+AM_INIT_AUTOMAKE($PACKAGE, $VERSION, no-define)
+
+AM_CONFIG_HEADER(config.h)
+
+AM_MAINTAINER_MODE
+
+ACLOCAL="$ACLOCAL $ACLOCAL_FLAGS"
+
+AC_PROG_CC
+AC_PROG_CPP
+
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+
+AC_PROG_RANLIB
+
+if eval "test x$GCC = xyes"; then
+ case " $CFLAGS " in
+ *[\ \ ]-Wall[\ \ ]*) ;;
+ *) CFLAGS="$CFLAGS -Wall" ;;
+ esac
+fi
+
+AC_LIB_RAW1394(0.9.0,,
+ AC_MSG_ERROR([Could not find libraw1394]))
+
+PKG_CHECK_MODULES(GLIB, glib-2.0,,
+ AC_MSG_ERROR([Could not find GLIB 2.x]))
+
+AC_SUBST(GLIB_CFLAGS)
+AC_SUBST(GLIB_LIBS)
+
+AC_OUTPUT([
+Makefile
+libjconfig/Makefile
+librbc/Makefile
+libsbp2/Makefile
+src/Makefile
+])
Added: trunk/libjconfig/Makefile.am
==============================================================================
--- trunk/libjconfig/Makefile.am 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libjconfig/Makefile.am 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,12 @@
+noinst_LIBRARIES = libjconfig.a
+
+INCLUDES = \
+ -I$(top_srcdir) \
+ $(GLIB_CFLAGS) \
+ -I$(includedir)
+
+libjconfig_a_SOURCES = \
+ jconfig.c \
+ jconfig.h \
+ jiterator.c \
+ jiterator.h
Added: trunk/libjconfig/jconfig.c
==============================================================================
--- trunk/libjconfig/jconfig.c 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libjconfig/jconfig.c 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,1727 @@
+/*
+ * jconfig.c
+ *
+ * Routines for handling the config file format of
+ * Helpers::JConfig.
+ *
+ * Copyright (C) 2002 Joel Becker <jlbec at evilplan.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+/* Check G_LOG_DOMAIN before including glib.h */
+#ifndef G_LOG_DOMAIN
+#define G_LOG_DOMAIN "JConfig"
+#endif /* G_LOG_DOMAIN */
+
+#include <glib.h>
+
+#include "jiterator.h"
+#include "jconfig.h"
+
+
+
+/*
+ * Defines
+ */
+#define CF_SCAN_WHITESPACE " \t"
+
+
+
+/*
+ * Types
+ */
+typedef struct _JOutputCtxt JOutputCtxt;
+
+
+/*
+ * Structures
+ */
+struct _JConfigCtxt
+{
+ JConfig *cf;
+ JConfigStanza *cfs;
+ gboolean verbose;
+ gboolean error;
+};
+
+struct _JConfigStanza
+{
+ gchar *stanza_name;
+ GHashTable *attrs;
+};
+
+struct _JConfig
+{
+ gchar *filename;
+ GList *stanza_names;
+ GHashTable *stanzas;
+};
+
+struct _JOutputCtxt
+{
+ FILE *output;
+ gboolean success;
+};
+
+
+
+/*
+ * File globals
+ */
+static const GScannerConfig test_config =
+{
+ "" /* cset_skip_characters */,
+ (
+ G_CSET_a_2_z
+ "_0123456789"
+ G_CSET_A_2_Z
+ ) /* cset_identifier_first */,
+ (
+ G_CSET_a_2_z
+ "_0123456789"
+ G_CSET_A_2_Z
+ ) /* cset_identifier_nth */,
+ "" /* cpair_comment_single */,
+ TRUE /* case_sensitive */,
+ FALSE /* skip_comment_multi */,
+ FALSE /* skip_comment_single */,
+ FALSE /* scan_comment_multi */,
+ TRUE /* scan_identifier */,
+ TRUE /* scan_identifier_1char */,
+ FALSE /* scan_identifier_NULL */,
+ TRUE /* scan_symbols */,
+ FALSE /* scan_binary */,
+ FALSE /* scan_octal */,
+ FALSE /* scan_float */,
+ FALSE /* scan_hex */,
+ FALSE /* scan_hex_dollar */,
+ FALSE /* scan_string_sq */,
+ FALSE /* scan_string_dq */,
+ FALSE /* numbers_2_int */,
+ FALSE /* int_2_float */,
+ FALSE /* identifier_2_string */,
+ FALSE /* char_2_token */,
+ TRUE /* symbol_2_token */,
+ FALSE /* scope_0_fallback */
+};
+
+
+
+
+/*
+ * Forward declarations
+ */
+static JConfig *j_config_parse_any(JConfigCtxt *cfc,
+ const gchar *input_name,
+ gint input_fd,
+ const gchar *input_string,
+ gint input_len);
+static void j_config_parse_base(GScanner *scanner, JConfigCtxt *cfc);
+static void j_config_parse_to_eol(GScanner *scanner);
+static void j_config_parse_comment(GScanner *scanner);
+static void j_config_parse_stanza_name(GScanner *scanner,
+ JConfigCtxt *cfc);
+static void j_config_parse_white_start(GScanner *scanner,
+ JConfigCtxt *cfc);
+static void j_config_parse_stanza_attr(GScanner *scanner,
+ JConfigCtxt *cfc);
+static void j_config_foreach_attr_print(gpointer key,
+ gpointer value,
+ gpointer o_ctxt);
+static void j_config_foreach_stanza_print(gpointer key,
+ gpointer value,
+ gpointer o_ctxt);
+static void j_config_attr_names_foreach(gpointer key,
+ gpointer value,
+ gpointer user_data);
+static void j_config_free_stanza(JConfigStanza *cfs);
+static JConfig *j_config_config_new();
+static JConfigStanza *j_config_stanza_new();
+static void j_config_free_stanza_node(gpointer key,
+ gpointer value,
+ gpointer thrway);
+static void j_config_free_config_node(gpointer key,
+ gpointer value,
+ gpointer thrway);
+static void j_config_free_stanza_proxy(gpointer data, gpointer thrway);
+static void j_config_foreach_attr_append(gpointer key,
+ gpointer value,
+ gpointer fbuffer);
+static void j_config_foreach_stanza_append(gpointer key,
+ gpointer value,
+ gpointer fbuffer);
+
+
+
+/*
+ * Functions
+ */
+
+
+/*
+ * JConfigCtxt *j_config_new_context()
+ *
+ * Returns a new JConfigCtxt.
+ */
+JConfigCtxt *j_config_new_context()
+{
+ JConfigCtxt *cfc;
+
+ cfc = g_new(JConfigCtxt, 1);
+ if (cfc == NULL)
+ {
+ g_warning("Unable to create a JConfigCtxt structure: %s\n",
+ g_strerror(errno));
+ return(NULL);
+ }
+
+ cfc->cfs = NULL;
+ cfc->cf = NULL;
+ cfc->verbose = TRUE;
+ cfc->error = FALSE;
+
+ return cfc;
+} /* j_config_context_new() */
+
+
+/*
+ * void j_config_context_free(JConfigCtxt *cfc)
+ *
+ * Frees a JConfigCtxt. Does *not* free the associated JConfig.
+ */
+void j_config_context_free(JConfigCtxt *cfc)
+{
+ g_return_if_fail(cfc != NULL);
+ g_free(cfc);
+} /* j_config_context_free() */
+
+
+/*
+ * gboolean j_config_context_get_error(JConfigCtxt *cfc)
+ *
+ * Set zero for continuing past errors, nonzero to fail.
+ */
+gboolean j_config_context_get_error(JConfigCtxt *cfc)
+{
+ g_return_val_if_fail(cfc != NULL, TRUE);
+
+ return cfc->error;
+} /* j_config_context_get_error() */
+
+
+/*
+ * void j_config_context_set_verbose(JConfigCtxt *cfc, gboolean verbose)
+ *
+ * Set zero for quiet, nonzero for verbose.
+ */
+void j_config_context_set_verbose(JConfigCtxt *cfc, gboolean verbose)
+{
+ g_return_if_fail(cfc != NULL);
+
+ cfc->verbose = verbose;
+} /* j_config_context_set_verbose() */
+
+
+/*
+ * static JConfig *j_config_parse_any(JConfigCtxt *cfc,
+ * const gchar *input_name,
+ * gint input_fd,
+ * const gchar *input_string,
+ * gint input_len)
+ *
+ * The real initial parsing routine.
+ * Creates the JConfig and structures and then
+ * calls j_config_parse_base();
+ *
+ * some of this is ripped from gtkrc.c
+ */
+static JConfig *j_config_parse_any(JConfigCtxt *cfc,
+ const gchar *input_name,
+ gint input_fd,
+ const gchar *input_string,
+ gint input_len)
+{
+ GScanner *scanner;
+
+ scanner = g_scanner_new((GScannerConfig *)&test_config);
+
+ if (input_fd >= 0)
+ {
+ g_assert(input_string == NULL);
+ g_scanner_input_file(scanner, input_fd);
+ }
+ else
+ {
+ g_assert(input_string != NULL);
+ g_assert(input_len >= 0);
+ g_scanner_input_text(scanner, input_string, input_len);
+ }
+ scanner->input_name = input_name;
+
+ cfc->cf = j_config_config_new();
+ if (cfc->cf == NULL)
+ {
+ if (cfc->verbose)
+ {
+ g_warning("Unable to create a JConfig structure: %s\n",
+ g_strerror(errno));
+ }
+ cfc->error = TRUE;
+ return(NULL);
+ }
+
+ cfc->cf->filename = g_strdup(input_name);
+ j_config_parse_base(scanner, cfc);
+
+ g_scanner_destroy(scanner);
+
+ return(cfc->cf);
+} /* j_config_parse_any() */
+
+
+/*
+ * static void j_config_parse_base(GScanner *scanner, JConfigCtxt *cfc)
+ *
+ * The config file is line oriented. In this scope, it is assumed
+ * that the scanner is situated at the begining of a line _always_.
+ * As such, every sub-function called must return with the scanner
+ * at the beginning of a line (or EOF);
+ *
+ * This function runs through line by line, deciding what
+ * sub-function should handle each line.
+ */
+static void j_config_parse_base(GScanner *scanner, JConfigCtxt *cfc)
+{
+ gboolean done;
+ gchar *toknam;
+ GTokenValue *value;
+
+ value = &scanner->next_value;
+
+ done = FALSE;
+ while (done == FALSE)
+ {
+ GTokenType token;
+
+ token = g_scanner_peek_next_token(scanner);
+
+ switch (token)
+ {
+ case G_TOKEN_EOF:
+ done = TRUE;
+ break;
+ case G_TOKEN_NONE:
+ /* will this ever happen? */
+ break;
+ case G_TOKEN_ERROR:
+ /* should do something here */
+ break;
+ case G_TOKEN_CHAR:
+ if (strchr(CF_SCAN_WHITESPACE, value->v_char) != NULL)
+ j_config_parse_white_start(scanner, cfc);
+ else if (value->v_char == '#')
+ j_config_parse_comment(scanner);
+ else if (value->v_char == '\n')
+ {
+#ifdef DEBUG
+ g_print("Newline\n");
+#endif /* DEBUG */
+ g_scanner_get_next_token(scanner);
+ if (cfc->cfs != NULL)
+ cfc->cfs = NULL;
+ }
+ else
+ {
+ if (cfc->verbose)
+ {
+ g_warning("Invalid character in stanza name: %c\n",
+ value->v_char);
+ }
+ cfc->error = TRUE;
+ j_config_parse_to_eol(scanner);
+ if (cfc->cfs != NULL)
+ cfc->cfs = NULL;
+ }
+ break;
+ case G_TOKEN_SYMBOL:
+ /* Another one I don't think I should get */
+ break;
+ case G_TOKEN_IDENTIFIER:
+ toknam = "G_TOKEN_IDENTIFIER";
+ j_config_parse_stanza_name(scanner, cfc);
+ break;
+ default:
+ toknam = "NONE";
+ if (cfc->verbose)
+ g_warning("Unknown token\n");
+ cfc->error = TRUE;
+ j_config_parse_to_eol(scanner);
+ if (cfc->cfs != NULL)
+ cfc->cfs = NULL;
+ break;
+ }
+ }
+} /* j_config_parse_base() */
+
+
+/*
+ * static void j_config_parse_to_eol(GScanner *scanner)
+ *
+ * This is a simple function that just finds the end of a line,
+ * throwing away anything it sees.
+ */
+static void j_config_parse_to_eol(GScanner *scanner)
+{
+ gboolean done;
+ GTokenType token;
+ GTokenValue *value;
+
+ value = &scanner->value;
+
+ done = FALSE;
+ while (done == FALSE)
+ {
+ token = g_scanner_peek_next_token(scanner);
+ if (token == G_TOKEN_EOF)
+ done = TRUE;
+ else
+ {
+ token = g_scanner_get_next_token(scanner);
+ if ((token = G_TOKEN_CHAR) && (value->v_char == '\n'))
+ done = TRUE;
+ }
+ }
+} /* j_config_parse_to_eol() */
+
+
+/*
+ * static void j_config_parse_comment(GScanner *scanner)
+ *
+ * Parses a comment out of the file, throwing it away.
+ */
+static void j_config_parse_comment(GScanner *scanner)
+{
+ GTokenType token;
+ GTokenValue *value;
+
+ value = &scanner->value;
+ token = g_scanner_get_next_token(scanner);
+
+ g_assert(token == G_TOKEN_CHAR);
+ g_assert(value->v_char == '#');
+
+ j_config_parse_to_eol(scanner);
+
+#ifdef DEBUG
+ g_print("Skipped comment\n");
+#endif /* DEBUG */
+} /* j_config_parse_comment() */
+
+
+/*
+ * static void j_config_parse_stanza_name(GScanner *scanner,
+ * JConfigCtxt *cfc)
+ *
+ * If a line starts with a non-whitespace character, it signifies a
+ * new stanza. Stanza names are defined by the Perl-style regular
+ * expression /^\w+:\s*\n/. Just by virtue of entering this function,
+ * any current stanza is closed.
+ *
+ * The gotos are because I decided it was cleaner than a
+ * g_free() at every error.
+ */
+static void j_config_parse_stanza_name(GScanner *scanner,
+ JConfigCtxt *cfc)
+{
+ gboolean done;
+ gchar *stanza_name;
+ GTokenType token;
+ GTokenValue *value;
+
+ value = &scanner->value;
+ token = g_scanner_get_next_token(scanner);
+
+ g_assert(token == G_TOKEN_IDENTIFIER);
+
+ if (cfc->cfs != NULL)
+ cfc->cfs = NULL;
+
+ stanza_name = g_strdup(value->v_identifier);
+
+ token = g_scanner_peek_next_token(scanner);
+ if (token == G_TOKEN_EOF)
+ {
+ if (cfc->verbose)
+ g_warning("Invalid stanza name declaration: missing ':'\n");
+ cfc->error = TRUE;
+ goto stanza_name_free;
+ }
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_CHAR)
+ {
+ if (cfc->verbose)
+ g_warning("Invalid stanza name declaration\n");
+ cfc->error = TRUE;
+ j_config_parse_to_eol(scanner);
+ goto stanza_name_free;
+ }
+ if (value->v_char == '\n')
+ {
+ if (cfc->verbose)
+ g_warning("Invalid stanza name declaration: missing ':'\n");
+ cfc->error = TRUE;
+ goto stanza_name_free;
+ }
+ if (value->v_char != ':')
+ {
+ if (cfc->verbose)
+ {
+ g_warning("Invalid character in stanza name declaration: %c\n",
+ value->v_char);
+ }
+ cfc->error = TRUE;
+ j_config_parse_to_eol(scanner);
+ goto stanza_name_free;
+ }
+
+ done = FALSE;
+ while (done == FALSE)
+ {
+ token = g_scanner_peek_next_token(scanner);
+ if (token == G_TOKEN_EOF)
+ done = TRUE;
+ else if (token == G_TOKEN_CHAR)
+ {
+ token = g_scanner_get_next_token(scanner);
+ if (value->v_char == '\n')
+ done = TRUE;
+ else if (strchr(CF_SCAN_WHITESPACE, value->v_char) == NULL)
+ {
+ if (cfc->verbose)
+ g_warning("Trailing garbage on stanza name declaration\n");
+ cfc->error = TRUE;
+ j_config_parse_to_eol(scanner);
+ goto stanza_name_free;
+ }
+ }
+ else
+ {
+ if (cfc->verbose)
+ g_warning("Trailing garbage on stanza name declaration\n");
+ cfc->error = TRUE;
+ j_config_parse_to_eol(scanner);
+ goto stanza_name_free;
+ }
+ }
+
+ cfc->cfs = j_config_add_stanza(cfc->cf, stanza_name);
+
+#ifdef DEBUG
+ g_print("New stanza: %s\n", stanza_name);
+#endif /* DEBUG */
+
+stanza_name_free:
+ g_free(stanza_name);
+} /* j_config_parse_stanza_name() */
+
+
+/*
+ * static void j_config_parse_white_start(GScanner *scanner,
+ * JConfigCtxt *cfc)
+ *
+ * If a line starts with whitespace, it is either a blank line, or an
+ * attribute line. We skip whitespace lines.
+ * If it looks like an attribute line, we call the proper function.
+ */
+static void j_config_parse_white_start(GScanner *scanner,
+ JConfigCtxt *cfc)
+{
+ gboolean done;
+ GTokenType token;
+ GTokenValue *value;
+
+ value = &scanner->value;
+ token = g_scanner_get_next_token(scanner);
+
+ g_assert(token == G_TOKEN_CHAR);
+ g_assert(strchr(CF_SCAN_WHITESPACE, value->v_char) != NULL);
+
+ done = FALSE;
+ while (done == FALSE)
+ {
+ token = g_scanner_peek_next_token(scanner);
+ switch (token)
+ {
+ case G_TOKEN_EOF:
+ done = TRUE;
+ break;
+ case G_TOKEN_IDENTIFIER:
+ j_config_parse_stanza_attr(scanner, cfc);
+ done = TRUE;
+ break;
+ case G_TOKEN_CHAR:
+ token = g_scanner_get_next_token(scanner);
+ if (value->v_char == '\n')
+ {
+#ifdef DEBUG
+ g_print("Skipped whitespace line\n");
+#endif /* DEBUG */
+ if (cfc->cfs == NULL)
+ cfc->cfs = NULL;
+ done = TRUE;
+ }
+ else if (strchr(CF_SCAN_WHITESPACE, value->v_char) == NULL)
+ {
+ if (cfc->verbose)
+ {
+ g_warning("Invalid character in attribute name: %c\n",
+ value->v_char);
+ }
+ cfc->error = TRUE;
+ j_config_parse_to_eol(scanner);
+ done = TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+} /* j_config_parse_white_start() */
+
+
+/*
+ * static void j_config_parse_stanza_attr(GScanner *scanner,
+ * JConfigCtxt *cfc)
+ *
+ * An attribute is of the form <attribute name>=<attribute value>.
+ * <attribute name> is defined by the Perl-style regular expression
+ * /^\s+\w+\s* /. Note that the leading whitespace (/^\s+/) has been
+ * stripped by j_config_parse_white_start() already.
+ * <attribute value> is defined as /\s*.*\n/. The leading whitespace
+ * (between the "=" and the first non-whitespace character in
+ * <attribute value>) is stripped, as is the newline.
+ *
+ * This now supports continuation lines. An attribute line ending in
+ * '\<newline>' will cause a <newline> to be entered into the buffer
+ * and the next line will be treated as part of the attribute.
+ */
+static void j_config_parse_stanza_attr(GScanner *scanner,
+ JConfigCtxt *cfc)
+{
+ gboolean done, multi_line;
+ gchar *attr_name;
+ GString *attr_value;
+ GTokenType token;
+ GTokenValue *value;
+
+ enum
+ {
+ CF_STATE_ID,
+ CF_STATE_EQUAL,
+ CF_STATE_VALUE
+ } cur_state;
+
+ value = &scanner->value;
+ token = g_scanner_get_next_token(scanner);
+
+ g_assert(token == G_TOKEN_IDENTIFIER);
+
+ if (cfc->cfs == NULL)
+ {
+ if (cfc->verbose)
+ g_warning("Attributes require a matching stanza\n");
+ cfc->error = TRUE;
+ j_config_parse_to_eol(scanner);
+ return;
+ }
+
+ attr_name = g_strdup(value->v_identifier);
+ attr_value = g_string_new(NULL);
+
+ cur_state = CF_STATE_ID;
+ done = FALSE;
+ multi_line = FALSE;
+ while (done == FALSE)
+ {
+ token = g_scanner_peek_next_token(scanner);
+ if (token == G_TOKEN_EOF)
+ {
+ if (cur_state == CF_STATE_ID)
+ {
+ if (cfc->verbose)
+ g_warning("Invalid attribute: missing '='\n");
+ cfc->error = TRUE;
+ goto attribute_free;
+ }
+ done = TRUE;
+ }
+ else if (token == G_TOKEN_CHAR)
+ {
+ token = g_scanner_get_next_token(scanner);
+ if (value->v_char == '\n')
+ {
+ if (cur_state == CF_STATE_ID)
+ {
+ if (cfc->verbose)
+ g_warning("Invalid attribute: missing '='\n");
+ cfc->error = TRUE;
+ goto attribute_free;
+ }
+ if (multi_line == FALSE)
+ done = TRUE;
+ else
+ {
+ g_string_append_c(attr_value, value->v_char);
+ multi_line = FALSE;
+ }
+ }
+ else if (multi_line == TRUE)
+ {
+ g_string_append_c(attr_value, '\\');
+ multi_line = FALSE;
+
+ if (value->v_char == '\\')
+ multi_line = TRUE;
+ else
+ g_string_append_c(attr_value, value->v_char);
+ }
+ else if (cur_state == CF_STATE_ID)
+ {
+ if (value->v_char == '=')
+ cur_state = CF_STATE_EQUAL;
+ else if (strchr(CF_SCAN_WHITESPACE, value->v_char) == NULL)
+ {
+ if (cfc->verbose)
+ g_warning("Invalid attribute: expecting '='\n");
+ cfc->error = TRUE;
+ j_config_parse_to_eol(scanner);
+ goto attribute_free;
+ }
+ }
+ else if (cur_state == CF_STATE_EQUAL)
+ {
+ if (strchr(CF_SCAN_WHITESPACE, value->v_char) == NULL)
+ {
+ cur_state = CF_STATE_VALUE;
+ if (value->v_char == '\\')
+ multi_line = TRUE;
+ else
+ g_string_append_c(attr_value, value->v_char);
+ }
+ }
+ else
+ {
+ if (value->v_char == '\\')
+ multi_line = TRUE;
+ else
+ g_string_append_c(attr_value, value->v_char);
+ }
+ }
+ else
+ {
+ token = g_scanner_get_next_token(scanner);
+ if (cur_state == CF_STATE_ID)
+ {
+ if (cfc->verbose)
+ g_warning("Invalid attribute: expecting '='\n");
+ cfc->error = TRUE;
+ j_config_parse_to_eol(scanner);
+ return;
+ }
+ else if (cur_state == CF_STATE_EQUAL)
+ cur_state = CF_STATE_VALUE;
+
+ if (token != G_TOKEN_IDENTIFIER)
+ {
+ if (cfc->verbose)
+ g_warning("Error parsing value\n");
+ cfc->error = TRUE;
+ j_config_parse_to_eol(scanner);
+ goto attribute_free;
+ }
+
+ if (multi_line == TRUE)
+ {
+ g_string_append_c(attr_value, '\\');
+ multi_line = FALSE;
+ }
+
+ g_string_append(attr_value, value->v_identifier);
+ }
+ }
+
+
+ j_config_set_attribute(cfc->cfs, attr_name, attr_value->str);
+#ifdef DEBUG
+ g_print("Attribute: \"%s\" = \"%s\"\n", attr_name, attr_value->str);
+#endif /* DEBUG */
+
+attribute_free:
+ g_free(attr_name);
+ g_string_free(attr_value, FALSE);
+}
+
+
+/*
+ * static JConfig *j_config_config_new()
+ *
+ * Allocates a new JConfig structure
+ */
+static JConfig *j_config_config_new()
+{
+ JConfig *cf;
+
+ cf = g_new(JConfig, 1);
+ if (cf == NULL) return(NULL);
+
+ cf->filename = NULL;
+ cf->stanza_names = NULL;
+ cf->stanzas = g_hash_table_new(g_str_hash, g_str_equal);
+ if (cf->stanzas == NULL)
+ {
+ g_free(cf);
+ return(NULL);
+ }
+
+ return(cf);
+} /* j_config_config_new() */
+
+
+/*
+ * static JConfigStanza *j_config_stanza_new()
+ *
+ * Allocates a new JConfigStanza structure
+ */
+static JConfigStanza *j_config_stanza_new()
+{
+ JConfigStanza *cfs;
+
+ cfs = g_new(JConfigStanza, 1);
+ if (cfs == NULL) return(NULL);
+
+ cfs->stanza_name = NULL;
+ cfs->attrs = g_hash_table_new(g_str_hash, g_str_equal);
+ if (cfs->attrs == NULL)
+ {
+ g_free(cfs);
+ return(NULL);
+ }
+
+ return(cfs);
+} /* j_config_stanza_new() */
+
+
+/*
+ * static void j_config_foreach_attr_print(gpointer key,
+ * gpointer value,
+ * gpointer o_ctxt)
+ *
+ * Prints each attribute -> value pair.
+ */
+static void j_config_foreach_attr_print(gpointer key,
+ gpointer value,
+ gpointer o_ctxt)
+{
+ gchar delimiter[2] = {'\n', '\0'};
+ gchar **output_lines;
+ gboolean first_line;
+ gint i, rc;
+ JOutputCtxt *ctxt;
+
+ ctxt = (JOutputCtxt *)o_ctxt;
+ if (ctxt->success == FALSE)
+ return;
+
+ if ((value == NULL) || (((gchar *)value)[0] == '\0'))
+ {
+ rc = fprintf(ctxt->output, "\t%s =\n", (gchar *)key);
+ if (rc < 1)
+ ctxt->success = FALSE;
+ return;
+ }
+
+ output_lines = g_strsplit(value, delimiter, 0);
+ if (output_lines == NULL)
+ {
+#if DEBUG
+ g_warning("Unable to allocate memory for multiline attribute: %s\n",
+ g_strerror(errno));
+#endif
+ ctxt->success = FALSE;
+ return;
+ }
+
+ first_line = TRUE;
+ rc = 0;
+ for (i = 0; output_lines[i] != NULL; i++)
+ {
+ if (first_line == TRUE)
+ {
+ rc = fprintf(ctxt->output, "\t%s = %s",
+ (gchar *)key, output_lines[i]);
+ first_line = FALSE;
+ }
+ else
+ rc = fprintf(ctxt->output, "\\\n%s", output_lines[i]);
+ }
+ g_strfreev(output_lines);
+
+ if (rc < 1)
+ {
+ ctxt->success = FALSE;
+ return;
+ }
+
+ rc = fprintf(ctxt->output, "\n");
+ if (rc < 1)
+ ctxt->success = FALSE;
+} /* j_config_foreach_attr_print() */
+
+
+/*
+ * static void j_config_foreach_stanza_print(gpointer key,
+ * gpointer value,
+ * gpointer o_ctxt)
+ *
+ * Runs through each stanza, printing the header and
+ * calling j_config_foreach_attr_print() on the attributes.
+ */
+static void j_config_foreach_stanza_print(gpointer key,
+ gpointer value,
+ gpointer o_ctxt)
+{
+ gint rc;
+ GList *elem;
+ JConfigStanza *cfs;
+ JOutputCtxt *ctxt;
+
+ elem = (GList *)value;
+ ctxt = (JOutputCtxt *)o_ctxt;
+ if (ctxt->success == FALSE)
+ return;
+
+ while (elem)
+ {
+ cfs = (JConfigStanza *)elem->data;
+ rc = fprintf(ctxt->output, "%s:\n", (gchar *)key);
+ if (rc < 1)
+ {
+ ctxt->success = FALSE;
+ break;
+ }
+
+ g_hash_table_foreach(cfs->attrs, j_config_foreach_attr_print,
+ o_ctxt);
+
+ rc = fprintf(ctxt->output, "\n");
+ if (rc < 1)
+ {
+ ctxt->success = FALSE;
+ break;
+ }
+ elem = g_list_next(elem);
+ }
+} /* j_config_foreach_stanza_print() */
+
+
+/*
+ * gboolean j_config_dump_file(JConfig *cf,
+ * const gchar *o_ctxt)
+ *
+ * Prints the configuration.
+ *
+ * FIXME: This needs to do more work to protect the resulting file from
+ * ENOSPC, etc.
+ */
+gboolean j_config_dump_file(JConfig *cf,
+ const gchar *output_file)
+{
+ gint rc;
+ JOutputCtxt ctxt;
+
+ g_return_val_if_fail(cf != NULL, FALSE);
+ g_return_val_if_fail(output_file != NULL, FALSE);
+
+ ctxt.success = TRUE;
+ if (strcmp(output_file, "-") == 0)
+ ctxt.output = stdout;
+ else
+ ctxt.output = fopen(output_file, "w");
+
+ if (ctxt.output == NULL)
+ {
+#if DEBUG
+ g_warning("Unable to open file \"%s\" for writing: %s\n",
+ output_file,
+ g_strerror(errno));
+#endif
+ return(FALSE);
+ }
+ g_hash_table_foreach(cf->stanzas,
+ j_config_foreach_stanza_print,
+ &ctxt);
+ if (strcmp(output_file, "-") != 0)
+ {
+ rc = fclose(ctxt.output);
+ if (rc != 0)
+ ctxt.success = FALSE;
+ }
+
+ return(ctxt.success);
+} /* j_config_dump_file() */
+
+
+/*
+ * JIterator *j_config_get_stanza_names(JConfig *cf)
+ *
+ * Returns a list of stanzas contained in this config
+ */
+JIterator *j_config_get_stanza_names(JConfig *cf)
+{
+ g_return_val_if_fail(cf != NULL, NULL);
+
+ return(j_iterator_new_from_list(cf->stanza_names));
+} /* j_config_get_stanza_names() */
+
+
+/*
+ * JConfigStanza *j_config_get_stanza_nth(JConfig *cf,
+ * const gchar *stanza_name,
+ * guint n)
+ *
+ * Retreives the nth stanza with the given name, or NULL if
+ * that does not exist
+ */
+JConfigStanza *j_config_get_stanza_nth(JConfig *cf,
+ const gchar *stanza_name,
+ guint n)
+{
+ JConfigStanza *cfs;
+ GList *elem;
+
+ g_return_val_if_fail(cf != NULL, NULL);
+ g_return_val_if_fail(stanza_name != NULL, NULL);
+
+ elem = g_hash_table_lookup(cf->stanzas, stanza_name);
+ if (elem == NULL)
+ return(NULL);
+
+ elem = g_list_nth(elem, n);
+ cfs = elem != NULL ? (JConfigStanza *)elem->data : NULL;
+
+ return(cfs);
+} /* j_config_get_stanza_nth() */
+
+
+/*
+ * gchar *j_config_get_stanza_name(JConfigStanza *cfs)
+ *
+ * Returns the stanza's name
+ */
+gchar *j_config_get_stanza_name(JConfigStanza *cfs)
+{
+ g_return_val_if_fail(cfs != NULL, NULL);
+
+ return(g_strdup(cfs->stanza_name));
+} /* j_config_get_stanza_name() */
+
+
+/*
+ * JConfigStanza *j_config_add_stanza(JConfig *cf,
+ * const gchar *stanza_name);
+ *
+ * Adds a new stanza to the configuration structure
+ */
+JConfigStanza *j_config_add_stanza(JConfig *cf,
+ const gchar *stanza_name)
+{
+ JConfigStanza *cfs;
+ GList *elem;
+
+ g_return_val_if_fail(cf != NULL, NULL);
+ g_return_val_if_fail(stanza_name != NULL, NULL);
+
+ cfs = j_config_stanza_new();
+ if (cfs == NULL)
+ {
+#if DEBUG
+ g_warning("Unable to allocate memory for a new stanza: %s\n",
+ g_strerror(errno));
+#endif
+ return NULL;
+ }
+
+ cfs->stanza_name = g_strdup(stanza_name);
+ elem = (GList *)g_hash_table_lookup(cf->stanzas, stanza_name);
+ if (elem == NULL)
+ {
+ cf->stanza_names =
+ g_list_append(cf->stanza_names, g_strdup(stanza_name));
+ elem = g_list_append(NULL, cfs);
+ g_hash_table_insert(cf->stanzas,
+ g_strdup(stanza_name),
+ elem);
+ }
+ else
+ g_list_append(elem, cfs);
+
+ return(cfs);
+} /* j_config_add_stanza() */
+
+
+/*
+ * void j_config_delete_stanza(JConfig *cf,
+ * JConfigStanza *cfs)
+ *
+ * Removes the stanza pointed to by cfs from the configuration.
+ */
+void j_config_delete_stanza(JConfig *cf,
+ JConfigStanza *cfs)
+{
+ GList *elem, *new_elem;
+ gpointer orig_key;
+ gchar *orig_data;
+
+ g_return_if_fail(cf != NULL);
+ g_return_if_fail(cfs != NULL);
+
+ elem = (GList *)g_hash_table_lookup(cf->stanzas, cfs->stanza_name);
+ if (elem == NULL)
+ {
+#if DEBUG
+ g_warning("Unable to remove stanza - no such class: %s\n",
+ cfs->stanza_name);
+#endif
+ return;
+ }
+
+ new_elem = g_list_remove(elem, cfs);
+ if (elem == NULL)
+ {
+ if (g_hash_table_lookup_extended(cf->stanzas,
+ cfs->stanza_name,
+ &orig_key,
+ NULL))
+ {
+ g_hash_table_remove(cf->stanzas, cfs->stanza_name);
+ g_free(orig_key);
+ }
+
+ elem = cf->stanza_names;
+ while (elem != NULL)
+ {
+ orig_data = (gchar *)elem->data;
+ if (strcmp(cfs->stanza_name, orig_data) == 0)
+ {
+ cf->stanza_names =
+ g_list_remove(cf->stanza_names, elem->data);
+ g_free(orig_data);
+ break;
+ }
+ elem = g_list_next(elem);
+ }
+ }
+ else if (elem != new_elem)
+ {
+ if (g_hash_table_lookup_extended(cf->stanzas,
+ cfs->stanza_name,
+ &orig_key,
+ NULL))
+ {
+ g_hash_table_remove(cf->stanzas, cfs->stanza_name);
+ g_free(orig_key);
+ }
+ g_hash_table_insert(cf->stanzas,
+ g_strdup(cfs->stanza_name),
+ new_elem);
+ }
+
+ j_config_free_stanza(cfs);
+} /* j_config_delete_stanza() */
+
+
+/*
+ * void j_config_delete_stanza_nth(JConfig *cf,
+ * const gchar *stanza_name,
+ * guint n)
+ *
+ * Removes the nth stanza of class stanza_name from the
+ * configuration.
+ */
+void j_config_delete_stanza_nth(JConfig *cf,
+ const gchar *stanza_name,
+ guint n)
+{
+ JConfigStanza *cfs;
+
+ g_return_if_fail(cf != NULL);
+ g_return_if_fail(stanza_name != NULL);
+
+ cfs = j_config_get_stanza_nth(cf, stanza_name, n);
+ if (cfs == NULL)
+ return;
+
+ j_config_delete_stanza(cf, cfs);
+} /* j_config_delete_stanza() */
+
+
+/*
+ * JConfig *j_config_parse_file_with_context(JConfigCtxt *cfc,
+ * const gchar *filename)
+ *
+ * Parses a config file
+ */
+JConfig *j_config_parse_file_with_context(JConfigCtxt *cfc,
+ const gchar *filename)
+{
+ gint fd;
+ JConfig *cf;
+
+ g_return_val_if_fail(cfc != NULL, NULL);
+ g_return_val_if_fail(filename != NULL, NULL);
+
+ if (strcmp(filename, "-") == 0)
+ fd = STDIN_FILENO;
+ else
+ fd = open(filename, O_RDONLY);
+
+ if (fd < 0)
+ {
+ if (cfc->verbose)
+ {
+ g_warning("Unable to open file \"%s\": %s\n",
+ filename,
+ g_strerror(errno));
+ }
+ cfc->error = TRUE;
+ return(NULL);
+ }
+
+ cf = j_config_parse_any(cfc, filename, fd, NULL, 0);
+
+ if (strcmp(filename, "-") != 0)
+ close(fd);
+
+ return(cf);
+} /* j_config_parse_file_with_context() */
+
+
+/*
+ * JConfig *j_config_parse_file(const gchar *filename)
+ *
+ * Parses a config file, creating the context.
+ */
+JConfig *j_config_parse_file(const gchar *filename)
+{
+ JConfigCtxt *cfc;
+ JConfig *cf = NULL;
+
+ cfc = j_config_new_context();
+ if (cfc)
+ {
+ cf = j_config_parse_file_with_context(cfc, filename);
+ j_config_context_free(cfc);
+ }
+
+ return(cf);
+} /* j_config_parse_file() */
+
+
+/*
+ * JConfig *j_config_parse_memory_with_context(JConfigCtxt *cfc,
+ * gchar *buffer,
+ * gint buf_len)
+ *
+ * Parses a config from a text buffer
+ */
+JConfig *j_config_parse_memory_with_context(JConfigCtxt *cfc,
+ gchar *buffer,
+ gint buf_len)
+{
+ JConfig *cf;
+
+ g_return_val_if_fail(cfc != NULL, NULL);
+ g_return_val_if_fail(buffer != NULL, NULL);
+
+ if (buf_len < 0)
+ buf_len = 0;
+
+ cf = j_config_parse_any(cfc, "memory", -1, buffer, buf_len);
+
+ return(cf);
+} /* j_config_parse_memory() */
+
+
+/*
+ * JConfig *j_config_parse_memory(gchar *buffer, gint buf_len)
+ *
+ * Parses a buffer, creating the context.
+ */
+JConfig *j_config_parse_memory(gchar *buffer, gint buf_len)
+{
+ JConfigCtxt *cfc;
+ JConfig *cf = NULL;
+
+ cfc = j_config_new_context();
+ if (cfc)
+ {
+ cf = j_config_parse_memory_with_context(cfc, buffer, buf_len);
+ j_config_context_free(cfc);
+ }
+
+ return(cf);
+} /* j_config_parse_file() */
+
+
+/*
+ * JConfigMatch *j_config_match_build(guint num_matches, ...)
+ *
+ * Convenience function to build an array of JConfigMatch structures.
+ * num_matches is the number of key, value pairs passed to this
+ * function. The number of varargs passed should therefore be double
+ * num_matches. eg:
+ *
+ * j_config_match_build(2, "foo", "bar", "quuz", "quuuz");
+ *
+ * This function builds a match that requires:
+ *
+ * foo = bar
+ * quuz = quuuz
+ *
+ * Strings passed in are *NOT* copied. They are merely referenced.
+ * Because of this, the returned array of JConfigMatch structures can
+ * be freed with g_free(). The caller must take care not to change or
+ * destroy the referened strings until they are done with the
+ * array of JConfigMatch structures.
+ */
+JConfigMatch *j_config_match_build(guint num_matches, ...)
+{
+ guint i;
+ va_list args;
+ JConfigMatch *matches;
+
+ matches = g_new0(JConfigMatch, num_matches);
+
+ va_start(args, num_matches);
+ for (i = 0; i < num_matches; i++)
+ {
+ matches[i].type = J_CONFIG_MATCH_VALUE;
+ matches[i].name = va_arg(args, gchar *);
+ if (matches[i].name == NULL)
+ {
+ g_free(matches);
+ matches = NULL;
+ break;
+ }
+ matches[i].value = va_arg(args, gchar *);
+ }
+ va_end(args);
+
+ return(matches);
+} /* j_config_match_build() */
+
+
+/*
+ * JIterator *j_config_get_stanzas(JConfig *cf,
+ * const gchar *stanza_name,
+ * JConfigMatch *matches,
+ * guint num_matches)
+ *
+ * Gets the list of stanzas with a given name. Optionally
+ * return only those that staitisfy matches. matches is an array
+ * of JConfigMatch structures. num_matches describes the number
+ * of items in the array. This array can be built by the caller
+ * explicitly, or the caller can use the convenience function
+ * j_config_match_build(). If num_matches is 0, matches can be
+ * NULL.
+ */
+JIterator *j_config_get_stanzas(JConfig *cf,
+ const gchar *stanza_name,
+ JConfigMatch *matches,
+ guint num_matches)
+{
+ gint i;
+ JConfigStanza *cfs;
+ gchar *value;
+ GList *elem, *tmp;
+ JIterator *iter;
+
+ g_return_val_if_fail(cf != NULL, NULL);
+ g_return_val_if_fail(stanza_name != NULL, NULL);
+ g_return_val_if_fail((num_matches == 0) || (matches != NULL), NULL);
+
+ elem = (GList *)g_hash_table_lookup(cf->stanzas, stanza_name);
+
+ if (num_matches > 0)
+ {
+ tmp = NULL;
+ for (; elem != NULL; elem = g_list_next(elem))
+ {
+ cfs = (JConfigStanza *)elem->data;
+ g_assert(cfs != NULL);
+
+ for (i = 0; i < num_matches; i++)
+ {
+ g_assert(matches[i].name != NULL);
+ value = j_config_get_attribute(cfs, matches[i].name);
+ if (value != NULL)
+ {
+ if (matches[i].value == NULL)
+ {
+ if (value[0] != '\0')
+ {
+ g_free(value);
+ break;
+ }
+ }
+ else if (strcmp(value, matches[i].value) != 0)
+ {
+ g_free(value);
+ break;
+ }
+ g_free(value);
+ }
+ else
+ {
+ if (matches[i].value != '\0')
+ break;
+ }
+ }
+ if (i >= num_matches) /* All tests succeeded */
+ tmp = g_list_prepend(tmp, cfs);
+ }
+ elem = g_list_reverse(tmp);
+
+ iter = j_iterator_new_from_list(elem);
+ g_list_free(elem);
+ }
+ else
+ iter = j_iterator_new_from_list(elem);
+
+ return(iter);
+} /* j_config_get_stanzas() */
+
+
+/*
+ * void j_config_set_attribute(JConfigStanza *cfs,
+ * const gchar *attr_name,
+ * const gchar *attr_value)
+ *
+ * Sets the value of a given attribute name
+ */
+void j_config_set_attribute(JConfigStanza *cfs,
+ const gchar *attr_name,
+ const gchar *attr_value)
+{
+ g_return_if_fail(cfs != NULL);
+ g_return_if_fail(attr_name != NULL);
+
+ j_config_delete_attribute(cfs, attr_name);
+ g_hash_table_insert(cfs->attrs,
+ g_strdup(attr_name),
+ g_strdup(attr_value));
+} /* j_config_set_attribute() */
+
+
+/*
+ * static void j_config_attr_names_foreach(gpointer key,
+ * gpointer value,
+ * gpointer user_data)
+ *
+ * Foreach function to build the attribute names list.
+ */
+static void j_config_attr_names_foreach(gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ GList **list = (GList **)user_data;
+
+ *list = g_list_append(*list, key);
+} /* j_config_attr_names_foreach() */
+
+
+/*
+ * JIterator *j_config_get_attribute_names(JConfigStanza *cfs)
+ *
+ * Returns an iterator over every attribute name in the stanza.
+ */
+JIterator *j_config_get_attribute_names(JConfigStanza *cfs)
+{
+ JIterator *iter;
+ GList *attr_names = NULL;
+
+ g_return_val_if_fail(cfs != NULL, NULL);
+
+ g_hash_table_foreach(cfs->attrs, j_config_attr_names_foreach,
+ &attr_names);
+
+ iter = j_iterator_new_from_list(attr_names);
+ g_list_free(attr_names);
+
+ return(iter);
+} /* j_config_get_attribute_names() */
+
+
+/*
+ * gchar *j_config_get_attribute(JConfigStanza *cfs,
+ * const gchar *attr_name)
+ *
+ * Retrieves the value of a given attribute name
+ */
+gchar *j_config_get_attribute(JConfigStanza *cfs,
+ const gchar *attr_name)
+{
+ gchar *s;
+
+ g_return_val_if_fail(cfs != NULL, NULL);
+ g_return_val_if_fail(attr_name != NULL, NULL);
+
+ s = (gchar *)g_hash_table_lookup(cfs->attrs, attr_name);
+ s = g_strdup(s);
+
+ return(s);
+} /* j_config_get_attribute() */
+
+
+/*
+ * void j_config_delete_attribute(JConfigStanza *cfs,
+ * const gchar *attr_name)
+ *
+ * Removes the attribute attr_name from the stanza pointed to
+ * by cfs.
+ */
+void j_config_delete_attribute(JConfigStanza *cfs,
+ const gchar *attr_name)
+{
+ gpointer orig_key, orig_value;
+
+ g_return_if_fail(cfs != NULL);
+ g_return_if_fail(attr_name != NULL);
+
+ if (g_hash_table_lookup_extended(cfs->attrs,
+ attr_name,
+ &orig_key,
+ &orig_value))
+ {
+ g_hash_table_remove(cfs->attrs,
+ attr_name);
+ g_free(orig_key);
+ g_free(orig_value);
+ }
+} /* j_config_delete_attribute() */
+
+
+/*
+ * static void j_config_free_stanza_node(gpointer key,
+ * gpointer value,
+ * gpointer thrway)
+ *
+ * Removes a node from a stanza
+ */
+static void j_config_free_stanza_node(gpointer key,
+ gpointer value,
+ gpointer thrway)
+{
+ g_free(key);
+ g_free(value);
+} /* j_config_free_stanza_node() */
+
+
+/*
+ * static void j_config_free_stanza(JConfigStanza *cfs)
+ *
+ * Clears a config file stanza
+ */
+static void j_config_free_stanza(JConfigStanza *cfs)
+{
+ g_return_if_fail(cfs != NULL);
+
+ g_hash_table_foreach(cfs->attrs, j_config_free_stanza_node, NULL);
+ g_hash_table_destroy(cfs->attrs);
+ g_free(cfs->stanza_name);
+ g_free(cfs);
+} /* j_config_free_stanza() */
+
+
+/*
+ * static void j_config_free_stanza_proxy(gpointer data,
+ * gpointer thrway)
+ *
+ * A proxy to call j_config_free_stanza() as a GFunc()
+ */
+static void j_config_free_stanza_proxy(gpointer elem_data,
+ gpointer thrway)
+{
+ j_config_free_stanza(elem_data);
+} /* j_config_free_stanza_proxy() */
+
+
+/*
+ * static void j_config_free_config_node(gpointer key,
+ * gpointer value,
+ * gpointer thrway)
+ *
+ * Removes a node from a config
+ */
+static void j_config_free_config_node(gpointer key,
+ gpointer value,
+ gpointer thrway)
+{
+ GList *elem;
+
+ elem = (GList *)value;
+ g_list_foreach(elem, j_config_free_stanza_proxy, NULL);
+ g_list_free(elem);
+ g_free(key);
+} /* j_config_free_config_node() */
+
+
+/*
+ * void j_config_free(JConfig *cf)
+ *
+ * Deletes a config file tree
+ */
+void j_config_free(JConfig *cf)
+{
+ g_return_if_fail(cf != NULL);
+
+ g_hash_table_foreach(cf->stanzas, j_config_free_config_node, NULL);
+ g_hash_table_destroy(cf->stanzas);
+ g_free(cf->filename);
+ g_free(cf);
+} /* j_config_free() */
+
+
+/*
+ * static void j_config_foreach_attr_append(gpointer key,
+ * gpointer value,
+ * gpointer fbuffer)
+ *
+ * Prints each attribute -> value pair.
+ */
+static void j_config_foreach_attr_append(gpointer key,
+ gpointer value,
+ gpointer fbuffer)
+{
+ gchar delimiter[2] = {'\n', '\0'};
+ gchar **output_lines;
+ gboolean first_line;
+ gint i;
+ GString *buffer;
+
+ g_return_if_fail(fbuffer != NULL);
+
+ buffer = (GString *)fbuffer;
+
+ if ((value == NULL) || (((gchar *)value)[0] == '\0'))
+ {
+ g_string_append_printf(buffer, "\t%s =\n", (gchar *)key);
+ return;
+ }
+
+ output_lines = g_strsplit(value, delimiter, 0);
+ if (output_lines == NULL)
+ {
+ g_warning("Unable to allocate memory for multiline attribute: %s\n",
+ g_strerror(errno));
+ return;
+ }
+
+ first_line = TRUE;
+ for (i = 0; output_lines[i] != NULL; i++)
+ {
+ if (first_line == TRUE)
+ {
+ g_string_append_printf(buffer, "\t%s = %s",
+ (gchar *)key, output_lines[i]);
+ first_line = FALSE;
+ }
+ else
+ g_string_append_printf(buffer, "\\\n%s", output_lines[i]);
+ }
+ g_string_append_printf(buffer, "\n");
+
+ g_strfreev(output_lines);
+} /* j_config_foreach_attr_append() */
+
+
+/*
+ * static void j_config_foreach_stanza_append(gpointer key,
+ * gpointer value,
+ * gpointer fbuffer)
+ *
+ * Runs through each stanza, printing the header and
+ * calling j_config_foreach_attr_append() on the attributes.
+ */
+static void j_config_foreach_stanza_append(gpointer key,
+ gpointer value,
+ gpointer fbuffer)
+{
+ GList *elem;
+ JConfigStanza *cfs;
+ GString *buffer;
+
+ g_return_if_fail(fbuffer != NULL);
+
+ buffer = (GString *)fbuffer;
+ elem = (GList *)value;
+
+ while (elem)
+ {
+ cfs = (JConfigStanza *)elem->data;
+ g_string_append_printf(buffer, "%s:\n", (gchar *)key);
+ g_hash_table_foreach(cfs->attrs, j_config_foreach_attr_append,
+ fbuffer);
+ g_string_append(buffer, "\n");
+ elem = g_list_next(elem);
+ }
+} /* j_config_foreach_stanza_append() */
+
+
+/*
+ * gchar *j_config_dump_memory(JConfig *cf)
+ *
+ * Prints the configuration to an in-memory string.
+ */
+gchar *j_config_dump_memory(JConfig *cf)
+{
+ gchar *output_text;
+ GString *output;
+
+ g_return_val_if_fail(cf != NULL, FALSE);
+
+ output = g_string_new(NULL);
+ if (output == NULL)
+ return(NULL);
+ g_hash_table_foreach(cf->stanzas,
+ j_config_foreach_stanza_append,
+ (gpointer)output);
+
+ output_text = output->str;
+ g_string_free(output, FALSE);
+ return(output_text);
+} /* j_config_dump_memory() */
+
Added: trunk/libjconfig/jconfig.h
==============================================================================
--- trunk/libjconfig/jconfig.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libjconfig/jconfig.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,103 @@
+/*
+ * jconfig.h
+ *
+ * Header file for configuration file parser
+ *
+ * Copyright (C) 2002 Joel Becker <jlbec at evilplan.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#ifndef __JCONFIG_H
+#define __JCONFIG_H
+
+
+
+/*
+ * Type definitions
+ */
+typedef struct _JConfigStanza JConfigStanza;
+typedef struct _JConfig JConfig;
+typedef struct _JConfigMatch JConfigMatch;
+typedef struct _JConfigCtxt JConfigCtxt;
+
+
+
+/*
+ * Enums
+ */
+typedef enum _JConfigMatchType
+{
+ J_CONFIG_MATCH_VALUE = 0,
+} JConfigMatchType;
+
+
+
+/*
+ * Structures
+ */
+struct _JConfigMatch
+{
+ JConfigMatchType type;
+ gchar *name;
+ gchar *value;
+};
+
+
+
+/*
+ * Functions
+ */
+
+JConfig *j_config_parse_file(const gchar *filename);
+JConfig *j_config_parse_memory(gchar *buffer, gint buf_len);
+JConfigCtxt *j_config_new_context();
+void j_config_context_free(JConfigCtxt *cfc);
+void j_config_set_context_verbose(JConfigCtxt *cfc, gboolean verbose);
+gboolean j_config_context_get_error(JConfigCtxt *cfc);
+JConfig *j_config_parse_file_with_context(JConfigCtxt *cfc,
+ const gchar *filename);
+JConfig *j_config_parse_memory_with_context(JConfigCtxt *cfc,
+ gchar *buffer,
+ gint buf_len);
+JIterator *j_config_get_stanza_names(JConfig *cf);
+JConfigMatch *j_config_match_build(guint num_matches, ...);
+JIterator *j_config_get_stanzas(JConfig *cf,
+ const gchar *stanza_name,
+ JConfigMatch *matches,
+ guint num_matches);
+JConfigStanza *j_config_get_stanza_nth(JConfig *cf,
+ const gchar *stanza_name,
+ guint n);
+gchar *j_config_get_stanza_name(JConfigStanza *cfs);
+JConfigStanza *j_config_add_stanza(JConfig *cf,
+ const gchar *stanza_name);
+void j_config_delete_stanza(JConfig *cf, JConfigStanza *cfs);
+void j_config_delete_stanza_nth(JConfig *cf,
+ const gchar *stanza_name,
+ guint n);
+JIterator *j_config_get_attribute_names(JConfigStanza *cfs);
+gchar *j_config_get_attribute(JConfigStanza *cfs,
+ const gchar *attr_name);
+void j_config_set_attribute(JConfigStanza *cfs,
+ const gchar *attr_name,
+ const gchar *attr_value);
+void j_config_delete_attribute(JConfigStanza *cfs,
+ const gchar *attr_name);
+gboolean j_config_dump_file(JConfig *cf, const gchar *output_file);
+gchar *j_config_dump_memory(JConfig *cf);
+void j_config_free(JConfig *cf);
+
+#endif /* __JCONFIG_H */
Added: trunk/libjconfig/jiterator.c
==============================================================================
--- trunk/libjconfig/jiterator.c 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libjconfig/jiterator.c 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,179 @@
+/*
+ * jiterator.c
+ *
+ * Code for opaque iterators.
+ *
+ * Copyright (C) 2001 Oracle Corporation, Joel Becker
+ * <joel.becker at oracle.com>
+ * All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have recieved a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+/*
+ * MT safe
+ */
+
+#include <sys/types.h>
+#include <glib.h>
+
+#include "jiterator.h"
+
+
+/* Structures
+ */
+struct _JIterator
+{
+ gpointer context;
+ JIteratorFunc has_more_func;
+ JIteratorFunc get_next_func;
+ GDestroyNotify notify_func;
+};
+
+
+static gpointer j_iterator_list_has_more (gpointer context);
+static gpointer j_iterator_list_get_next (gpointer context);
+static void j_iterator_list_destroy_notify (gpointer context);
+
+
+
+/* Enumerations
+ */
+JIterator*
+j_iterator_new (gpointer context,
+ JIteratorFunc has_more_func,
+ JIteratorFunc get_next_func,
+ GDestroyNotify notify_func)
+{
+ JIterator *iterator;
+
+ iterator = g_new (JIterator, 1);
+ iterator->context = context;
+ iterator->has_more_func = has_more_func;
+ iterator->get_next_func = get_next_func;
+ iterator->notify_func = notify_func;
+
+ return iterator;
+} /* j_iterator_new() */
+
+JIterator*
+j_iterator_new_from_list (GList *init_list)
+{
+ JIterator *iterator;
+ GList *list_copy, *header;
+
+ /* The list is copied here, the caller is responsible for the
+ * data items. On _free(), the list is removed and the data items
+ * left alone. If the caller wants different semantics, the
+ * caller can specify their own functions with _new() */
+ list_copy = g_list_copy(init_list);
+
+ /* This is a header element to refer to the list */
+ header = g_list_prepend(NULL, (gpointer) list_copy);
+
+ iterator = j_iterator_new ((gpointer) header,
+ j_iterator_list_has_more,
+ j_iterator_list_get_next,
+ j_iterator_list_destroy_notify);
+
+ return(iterator);
+} /* j_iterator_new_from_list() */
+
+gboolean
+j_iterator_has_more (JIterator *iterator)
+{
+ gpointer result;
+
+ g_return_val_if_fail (iterator != NULL, FALSE);
+
+ result = (*iterator->has_more_func) (iterator->context);
+
+ return (gboolean) result;
+} /* j_iterator_has_more() */
+
+gpointer
+j_iterator_get_next (JIterator *iterator)
+{
+ gpointer result;
+
+ g_return_val_if_fail (iterator != NULL, NULL);
+
+ result = (*iterator->get_next_func) (iterator->context);
+
+ return result;
+} /* j_iterator_get_next() */
+
+void
+j_iterator_free (JIterator *iterator)
+{
+ (*iterator->notify_func) (iterator->context);
+
+ g_free(iterator);
+} /* j_iterator_free() */
+
+static gpointer
+j_iterator_list_has_more (gpointer context)
+{
+ GList *header, *elem;
+ gboolean result;
+
+ g_return_val_if_fail (context != NULL, (gpointer) FALSE);
+
+ header = (GList *) context;
+ elem = (GList *) header->data;
+
+ result = (elem != NULL);
+
+ return (gpointer) result;
+} /* j_iterator_list_has_more() */
+
+static gpointer
+j_iterator_list_get_next (gpointer context)
+{
+ GList *header, *elem;
+ gpointer result;
+
+ g_return_val_if_fail(context != NULL, NULL);
+
+ header = (GList *) context;
+ elem = (GList *) header->data;
+
+ /* User should have called has_more() */
+ g_return_val_if_fail(elem != NULL, NULL);
+
+ result = elem->data;
+
+ header->data = (gpointer) g_list_next(elem);
+
+ g_list_free_1(elem);
+
+ return result;
+} /* j_iterator_list_get_next() */
+
+static void
+j_iterator_list_destroy_notify (gpointer context)
+{
+ GList *header, *elem;
+
+ g_return_if_fail (context != NULL);
+
+ header = (GList *) context;
+ elem = (GList *) header->data;
+
+ g_list_free(elem); /* NULL if at end of list */
+
+ g_list_free(header);
+} /* j_iterator_list_destroy_notify() */
Added: trunk/libjconfig/jiterator.h
==============================================================================
--- trunk/libjconfig/jiterator.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libjconfig/jiterator.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,42 @@
+/*
+ * jiterator.h
+ *
+ * Prototypes for JIterator
+ *
+ * Copyright (C) 2002 Joel Becker <jlbec at evilplan.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __JITERATOR_H
+#define __JITERATOR_H
+
+
+/* Typedefs */
+typedef struct _JIterator JIterator;
+typedef gpointer (*JIteratorFunc) (gpointer context);
+
+
+/* Functions */
+JIterator* j_iterator_new(gpointer context,
+ JIteratorFunc has_more_func,
+ JIteratorFunc get_next_func,
+ GDestroyNotify notify_func);
+JIterator* j_iterator_new_from_list(GList *init_list);
+gboolean j_iterator_has_more(JIterator *iterator);
+gpointer j_iterator_get_next(JIterator *iterator);
+void j_iterator_free(JIterator *iterator);
+
+#endif /* __JITERATOR_H */
+
Added: trunk/librbc/Makefile.am
==============================================================================
--- trunk/librbc/Makefile.am 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/librbc/Makefile.am 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,16 @@
+noinst_LIBRARIES = librbc.a
+
+INCLUDES = \
+ -I$(top_srcdir) \
+ $(GLIB_CFLAGS) \
+ -I$(includedir)
+
+librbc_a_SOURCES = \
+ rbcbuffer.h \
+ rbcbuffer.c \
+ rbccommand.h \
+ rbccommand.c \
+ rbcdisk.c \
+ rbcdisk.h \
+ rbcprivate.h \
+ rbctypes.h
Added: trunk/librbc/rbcbuffer.c
==============================================================================
--- trunk/librbc/rbcbuffer.c 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/librbc/rbcbuffer.c 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,121 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#include <glib.h>
+
+#include "rbcbuffer.h"
+
+
+static inline RBCBuffer *
+alloc_buffer (RBCBufferType type)
+{
+ RBCBuffer *buffer;
+
+ buffer = g_new (RBCBuffer, 1);
+ buffer->type = type;
+
+ return buffer;
+}
+
+
+RBCBuffer *
+rbc_buffer_empty_new (void)
+{
+ return alloc_buffer (RBC_BUFFER_EMPTY);
+}
+
+RBCBuffer *
+rbc_buffer_simple_new (gsize length)
+{
+ RBCBuffer *buffer;
+
+ g_return_val_if_fail (length > 0, NULL);
+
+ buffer = alloc_buffer (RBC_BUFFER_SIMPLE);
+
+ buffer->length = length;
+ buffer->data = g_malloc (length);
+
+ return buffer;
+}
+
+RBCBuffer *
+rbc_buffer_page_table_new (gsize length)
+{
+ RBCBuffer *buffer;
+
+ g_return_val_if_fail (length > 0, NULL);
+
+ buffer = alloc_buffer (RBC_BUFFER_PAGE_TABLE);
+
+ buffer->length = length;
+ buffer->data = g_new (RBCPage, length);
+
+ return buffer;
+}
+
+void
+rbc_buffer_destroy (RBCBuffer *buffer)
+{
+ RBCPage *pages;
+ gint i;
+
+ g_return_if_fail (buffer != NULL);
+
+ switch (buffer->type)
+ {
+
+ case RBC_BUFFER_PAGE_TABLE:
+ pages = buffer->data;
+
+ for (i = 0; i < buffer->length; i++)
+ g_free (pages[i].data);
+
+ /* fall through */
+
+ case RBC_BUFFER_SIMPLE:
+ g_free (buffer->data);
+ /* fall through */
+
+ case RBC_BUFFER_EMPTY:
+ g_free (buffer);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+void
+rbc_buffer_fill_from_page (RBCBuffer *buffer,
+ RBCPage *page)
+{
+ g_return_if_fail (buffer != NULL);
+ g_return_if_fail (page != NULL);
+
+ buffer->type = RBC_BUFFER_SIMPLE;
+ buffer->length = page->length;
+ buffer->data = page->data;
+}
+
Added: trunk/librbc/rbcbuffer.h
==============================================================================
--- trunk/librbc/rbcbuffer.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/librbc/rbcbuffer.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,70 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __RBC_BUFFER_H__
+#define __RBC_BUFFER_H__
+
+
+#include <glib.h>
+
+
+typedef enum
+{
+ RBC_BUFFER_EMPTY,
+ RBC_BUFFER_SIMPLE,
+ RBC_BUFFER_PAGE_TABLE
+} RBCBufferType;
+
+
+typedef struct _RBCBuffer RBCBuffer;
+typedef struct _RBCPage RBCPage;
+
+struct _RBCBuffer
+{
+ RBCBufferType type;
+
+ gpointer data;
+ gsize length;
+};
+
+/* This needs to match struct iovec for readv/writev */
+struct _RBCPage
+{
+ gpointer data;
+ gsize length;
+};
+
+
+RBCBuffer *rbc_buffer_empty_new (void);
+
+RBCBuffer *rbc_buffer_simple_new (gsize length);
+
+RBCBuffer *rbc_buffer_page_table_new (gsize length);
+
+void rbc_buffer_destroy (RBCBuffer *buffer);
+
+void rbc_buffer_fill_from_page (RBCBuffer *buffer,
+ RBCPage *page);
+
+
+#endif /* __RBC_BUFFER_H__ */
Added: trunk/librbc/rbccommand.c
==============================================================================
--- trunk/librbc/rbccommand.c 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/librbc/rbccommand.c 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,416 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#define _GNU_SOURCE
+#define _FILE_OFFSET_BITS 64
+
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/uio.h>
+
+#include <glib.h>
+
+#include "rbccommand.h"
+#include "rbcprivate.h"
+
+
+#define VENDOR_ID "Linux "
+#define PRODUCT_ID "Endpoint "
+#define PRODUCT_REV "0001"
+
+
+typedef enum
+{
+ INQUIRY = 0x12,
+ MODE_SELECT = 0x15,
+ MODE_SENSE = 0x1a,
+ READ = 0x28,
+ READ_CAPACITY = 0x25,
+ START_STOP_UNIT = 0x1b,
+ TEST_UNIT_READY = 0x00,
+ VERIFY = 0x2f,
+ WRITE = 0x2a,
+ WRITE_BUFFER = 0x3b
+} Command;
+
+typedef enum
+{
+ GOOD = 0x0,
+ CHECK_CONDITION = 0x2,
+ CONDITION_MET = 0x4,
+ BUSY = 0x8,
+ RESERVATION_CONFLICT = 0x18,
+ COMMAND_TERMINATED = 0x22
+} Status;
+
+typedef enum
+{
+ NO_SENSE = 0x00,
+ RECOVERED_ERROR = 0x01,
+ NOT_READY = 0x02,
+ MEDIUM_ERROR = 0x03,
+ ILLEGAL_REQUEST = 0x04,
+ UNIT_ATTENTION = 0x05,
+ DATA_PROTECT = 0x06,
+ BLANK_CHECK = 0x08,
+ COPY_ABORTED = 0x0a,
+ ABORTED_COMMAND = 0x0b,
+ VOLUME_OVERFLOW = 0x0d,
+ MISCOMPARE = 0x0e
+} SenseKey;
+
+
+typedef gboolean (*CommandHandler) (RBCDisk *disk,
+ guint8 *cmd,
+ RBCBuffer *buffer,
+ guint8 *sense);
+
+
+static gboolean handle_inquiry (RBCDisk *disk,
+ guint8 *cmd,
+ RBCBuffer *buffer,
+ guint8 *sense);
+static gboolean handle_mode_select (RBCDisk *disk,
+ guint8 *cmd,
+ RBCBuffer *buffer,
+ guint8 *sense);
+static gboolean handle_mode_sense (RBCDisk *disk,
+ guint8 *cmd,
+ RBCBuffer *buffer,
+ guint8 *sense);
+static gboolean handle_read (RBCDisk *disk,
+ guint8 *cmd,
+ RBCBuffer *buffer,
+ guint8 *sense);
+static gboolean handle_read_capacity (RBCDisk *disk,
+ guint8 *cmd,
+ RBCBuffer *buffer,
+ guint8 *sense);
+static gboolean handle_start_stop_unit (RBCDisk *disk,
+ guint8 *cmd,
+ RBCBuffer *buffer,
+ guint8 *sense);
+static gboolean handle_test_unit_ready (RBCDisk *disk,
+ guint8 *cmd,
+ RBCBuffer *buffer,
+ guint8 *sense);
+static gboolean handle_verify (RBCDisk *disk,
+ guint8 *cmd,
+ RBCBuffer *buffer,
+ guint8 *sense);
+static gboolean handle_write (RBCDisk *disk,
+ guint8 *cmd,
+ RBCBuffer *buffer,
+ guint8 *sense);
+static gboolean handle_write_buffer (RBCDisk *disk,
+ guint8 *cmd,
+ RBCBuffer *buffer,
+ guint8 *sense);
+
+
+static inline void
+fill_sense_buffer (guint8 *sense,
+ Status status,
+ SenseKey key,
+ gint asc,
+ gint asq)
+{
+ g_return_if_fail (sense != NULL);
+
+ sense[0] = status;
+ sense[1] = key;
+ sense[2] = asc;
+ sense[3] = asq;
+}
+
+
+gboolean
+rbc_disk_command (RBCDisk *disk,
+ guint8 *cmd,
+ RBCBuffer *buffer,
+ guint8 *sense)
+{
+ CommandHandler handler;
+ RBCBuffer sg_buffer;
+ gboolean process_sg = TRUE;
+ gboolean no_empty = TRUE;
+
+ g_return_val_if_fail (disk != NULL, FALSE);
+ g_return_val_if_fail (cmd != NULL, FALSE);
+ g_return_val_if_fail (buffer != NULL, FALSE);
+ g_return_val_if_fail (sense != NULL, FALSE);
+
+ switch (cmd[0])
+ {
+ case INQUIRY:
+ handler = handle_inquiry;
+ break;
+
+ case MODE_SELECT:
+ handler = handle_mode_select;
+ no_empty = FALSE;
+ break;
+
+ case MODE_SENSE:
+ handler = handle_mode_sense;
+ no_empty = FALSE;
+ break;
+
+ case READ:
+ handler = handle_read;
+ process_sg = FALSE;
+ break;
+
+ case READ_CAPACITY:
+ handler = handle_read_capacity;
+ break;
+
+ case START_STOP_UNIT:
+ handler = handle_start_stop_unit;
+ no_empty = FALSE;
+ break;
+
+ case TEST_UNIT_READY:
+ handler = handle_test_unit_ready;
+ no_empty = FALSE;
+ break;
+
+ case VERIFY:
+ handler = handle_verify;
+ process_sg = FALSE;
+ break;
+
+ case WRITE:
+ handler = handle_write;
+ process_sg = FALSE;
+ break;
+
+ case WRITE_BUFFER:
+ handler = handle_write_buffer;
+ no_empty = FALSE;
+ break;
+
+ default:
+ fill_sense_buffer (sense, CHECK_CONDITION, ILLEGAL_REQUEST, 0x20, 0);
+ return FALSE;
+ break;
+ }
+
+ if (no_empty && buffer->type == RBC_BUFFER_EMPTY)
+ {
+ fill_sense_buffer (sense, CHECK_CONDITION, ILLEGAL_REQUEST, 0x20, 0);
+ return FALSE;
+ }
+
+ if (process_sg)
+ {
+ if (buffer->type == RBC_BUFFER_PAGE_TABLE)
+ {
+ RBCPage *page = buffer->data;
+
+ rbc_buffer_fill_from_page (&sg_buffer, page);
+ buffer = &sg_buffer;
+ }
+ }
+
+ return handler (disk, cmd, buffer, sense);
+}
+
+static gboolean
+handle_inquiry (RBCDisk *disk,
+ guint8 *cmd,
+ RBCBuffer *buffer,
+ guint8 *sense)
+{
+ guint8 *data = buffer->data;
+
+ memset (buffer->data, 0, buffer->length);
+
+ data[0] = 0xe;
+
+ memcpy (&data[8], VENDOR_ID, 8);
+ memcpy (&data[16], PRODUCT_ID, 16);
+ memcpy (&data[32], PRODUCT_REV, 4);
+
+ return TRUE;
+}
+
+static gboolean
+handle_mode_select (RBCDisk *disk,
+ guint8 *cmd,
+ RBCBuffer *buffer,
+ guint8 *sense)
+{
+ /* TODO: implement */
+
+ fill_sense_buffer (sense, CHECK_CONDITION, ILLEGAL_REQUEST, 0x20, 0);
+ return FALSE;
+}
+
+static gboolean
+handle_mode_sense (RBCDisk *disk,
+ guint8 *cmd,
+ RBCBuffer *buffer,
+ guint8 *sense)
+{
+ /* TODO: implement */
+
+ fill_sense_buffer (sense, CHECK_CONDITION, ILLEGAL_REQUEST, 0x20, 0);
+ return FALSE;
+}
+
+static gboolean
+handle_read (RBCDisk *disk,
+ guint8 *cmd,
+ RBCBuffer *buffer,
+ guint8 *sense)
+{
+ gsize block;
+ gsize num;
+ off_t offset;
+ gsize length;
+
+ block = (cmd[2] << 24) + (cmd[3] << 16) + (cmd[4] << 8) + cmd[5];
+ num = (cmd[7] << 8) + cmd[8];
+
+ if (block + num > disk->capacity)
+ {
+ fill_sense_buffer (sense, CHECK_CONDITION, ILLEGAL_REQUEST, 0x21, 0);
+ return FALSE;
+ }
+
+ if (num == 0)
+ return TRUE;
+
+ offset = (off_t) block * RBC_BLOCK_SIZE;
+ length = num * RBC_BLOCK_SIZE;
+
+ if (buffer->type == RBC_BUFFER_PAGE_TABLE)
+ {
+ lseek (disk->fd, offset, SEEK_SET);
+ readv (disk->fd, buffer->data, buffer->length);
+ }
+ else
+ pread (disk->fd, buffer->data, length, offset);
+
+ return TRUE;
+}
+
+static gboolean
+handle_read_capacity (RBCDisk *disk,
+ guint8 *cmd,
+ RBCBuffer *buffer,
+ guint8 *sense)
+{
+ guint8 *data = buffer->data;
+ gsize capacity = disk->capacity - 1;
+
+ memset (buffer->data, 0, buffer->length);
+
+ data[0] = (capacity >> 24);
+ data[1] = (capacity >> 16) & 0xff;
+ data[2] = (capacity >> 8) & 0xff;
+ data[3] = capacity & 0xff;
+ data[6] = (RBC_BLOCK_SIZE >> 8) & 0xff;
+ data[7] = RBC_BLOCK_SIZE & 0xff;
+
+ return TRUE;
+}
+
+static gboolean
+handle_start_stop_unit (RBCDisk *disk,
+ guint8 *cmd,
+ RBCBuffer *buffer,
+ guint8 *sense)
+{
+ /* Power condition requests are unsupported, ignore */
+ return TRUE;
+}
+
+static gboolean
+handle_test_unit_ready (RBCDisk *disk,
+ guint8 *cmd,
+ RBCBuffer *buffer,
+ guint8 *sense)
+{
+ /* We're always ready */
+ return TRUE;
+}
+
+static gboolean
+handle_verify (RBCDisk *disk,
+ guint8 *cmd,
+ RBCBuffer *buffer,
+ guint8 *sense)
+{
+ /* TODO: Implement */
+ return TRUE;
+}
+
+static gboolean
+handle_write (RBCDisk *disk,
+ guint8 *cmd,
+ RBCBuffer *buffer,
+ guint8 *sense)
+{
+ gsize block;
+ gsize num;
+ off_t offset;
+ gsize length;
+
+ block = (cmd[2] << 24) + (cmd[3] << 16) + (cmd[4] << 8) + cmd[5];
+ num = (cmd[7] << 8) + cmd[8];
+
+ if (block + num > disk->capacity)
+ {
+ fill_sense_buffer (sense, CHECK_CONDITION, ILLEGAL_REQUEST, 0x21, 0);
+ return FALSE;
+ }
+
+ if (num == 0)
+ return TRUE;
+
+ offset = (off_t) block * RBC_BLOCK_SIZE;
+ length = num * RBC_BLOCK_SIZE;
+
+ if (buffer->type == RBC_BUFFER_PAGE_TABLE)
+ {
+ lseek (disk->fd, offset, SEEK_SET);
+ writev (disk->fd, buffer->data, buffer->length);
+ }
+ else
+ pwrite (disk->fd, buffer->data, length, offset);
+
+ return TRUE;
+}
+
+static gboolean
+handle_write_buffer (RBCDisk *disk,
+ guint8 *cmd,
+ RBCBuffer *buffer,
+ guint8 *sense)
+{
+ /* Unsupported, always succeed */
+ return TRUE;
+}
Added: trunk/librbc/rbccommand.h
==============================================================================
--- trunk/librbc/rbccommand.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/librbc/rbccommand.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,40 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __RBC_COMMAND_H__
+#define __RBC_COMMAND_H__
+
+
+#include <glib.h>
+
+#include <librbc/rbcbuffer.h>
+#include <librbc/rbcdisk.h>
+
+
+gboolean rbc_disk_command (RBCDisk *disk,
+ guint8 *cmd,
+ RBCBuffer *buffer,
+ guint8 *sense);
+
+
+#endif /* __RBC_COMMAND_H__ */
Added: trunk/librbc/rbcdisk.c
==============================================================================
--- trunk/librbc/rbcdisk.c 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/librbc/rbcdisk.c 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,286 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <glib.h>
+
+#include "rbcdisk.h"
+#include "rbcprivate.h"
+
+
+static gsize process_filename (const gchar *filename,
+ gint *out_fd);
+
+static gint partition_order (const RBCPartition *a,
+ const RBCPartition *b);
+
+
+RBCDisk *
+rbc_disk_new (RBCDiskType type)
+{
+ RBCDisk *disk;
+
+ disk = g_new (RBCDisk, 1);
+
+ disk->type = type;
+
+ disk->filename = NULL;
+ disk->partitions = NULL;
+
+ disk->fd = -1;
+ disk->capacity = 0;
+
+ disk->active = FALSE;
+
+ return disk;
+}
+
+void
+rbc_disk_destroy (RBCDisk *disk)
+{
+ GList *list;
+ RBCPartition *partition;
+
+ g_return_if_fail (disk != NULL);
+
+ if (disk->fd != -1)
+ close (disk->fd);
+
+ if (disk->filename)
+ g_free (disk->filename);
+
+ if (disk->partitions)
+ {
+ list = disk->partitions;
+
+ while (list)
+ {
+ partition = list->data;
+
+ if (partition->fd != -1)
+ close (partition->fd);
+
+ if (partition->filename)
+ g_free (partition->filename);
+
+ list = list->next;
+ }
+
+ g_list_free (disk->partitions);
+ }
+
+ g_free (disk);
+}
+
+RBCDiskType
+rbc_disk_get_type (RBCDisk *disk)
+{
+ g_return_val_if_fail (disk != NULL, RBC_DISK_PHYSICAL);
+
+ return disk->type;
+}
+
+gboolean
+rbc_device_is_equal (RBCDisk *a,
+ RBCDisk *b)
+{
+ g_return_val_if_fail (a != NULL, FALSE);
+ g_return_val_if_fail (b != NULL, FALSE);
+
+ /* TODO: implement */
+
+ return a == b;
+}
+
+gboolean
+rbc_disk_set_filename (RBCDisk *disk,
+ const gchar *filename)
+{
+ gsize capacity;
+
+ g_return_val_if_fail (disk != NULL, FALSE);
+ g_return_val_if_fail (disk->type == RBC_DISK_PHYSICAL, FALSE);
+ g_return_val_if_fail (disk->active == FALSE, FALSE);
+ g_return_val_if_fail (filename != NULL, FALSE);
+ g_return_val_if_fail (disk->filename == NULL, FALSE);
+
+ capacity = process_filename (filename, NULL);
+
+ if (capacity == 0)
+ return FALSE;
+
+ disk->filename = g_strdup (filename);
+ disk->capacity = capacity;
+
+ return TRUE;
+}
+
+gboolean
+rbc_disk_add_partition (RBCDisk *disk,
+ const gchar *filename,
+ guint order)
+{
+ gsize capacity;
+ RBCPartition *partition;
+
+ g_return_val_if_fail (disk != NULL, FALSE);
+ g_return_val_if_fail (disk->type == RBC_DISK_VIRTUAL, FALSE);
+ g_return_val_if_fail (disk->active == FALSE, FALSE);
+ g_return_val_if_fail (filename != NULL, FALSE);
+
+ capacity = process_filename (filename, NULL);
+
+ if (capacity == 0)
+ return FALSE;
+
+ partition = g_new (RBCPartition, 1);
+
+ partition->filename = g_strdup (filename);
+ partition->order = order;
+
+ partition->fd = -1;
+ partition->capacity = capacity;
+
+ disk->partitions = g_list_insert_sorted (disk->partitions, partition,
+ (GCompareFunc) partition_order);
+
+ return TRUE;
+}
+
+gsize
+rbc_disk_get_capacity (RBCDisk *disk)
+{
+ g_return_val_if_fail (disk != NULL, 0);
+
+ return disk->capacity;
+}
+
+gsize
+rbc_disk_get_block_size (RBCDisk *disk)
+{
+ g_return_val_if_fail (disk != NULL, 0);
+
+ return RBC_BLOCK_SIZE;
+}
+
+gboolean
+rbc_disk_activate (RBCDisk *disk)
+{
+ GList *list;
+ RBCPartition *partition;
+
+ g_return_val_if_fail (disk != NULL, FALSE);
+
+ switch (disk->type)
+ {
+ case RBC_DISK_PHYSICAL:
+ g_return_val_if_fail (disk->filename != NULL, FALSE);
+
+ disk->capacity = process_filename (disk->filename, &disk->fd);
+
+ if (disk->capacity == 0)
+ return FALSE;
+
+ break;
+
+ case RBC_DISK_VIRTUAL:
+ g_return_val_if_fail (disk->partitions != NULL, FALSE);
+
+ list = disk->partitions;
+
+ while (list)
+ {
+ partition = list->data;
+
+ partition->capacity = process_filename (partition->filename,
+ &partition->fd);
+
+ if (partition->capacity == 0)
+ goto cleanup;
+
+ list = list->next;
+ }
+
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ return TRUE;
+
+cleanup:
+ list = list->prev;
+
+ while (list)
+ {
+ partition = list->data;
+
+ close (partition->fd);
+
+ list = list->prev;
+ }
+
+ return FALSE;
+}
+
+static gsize
+process_filename (const gchar *filename,
+ gint *out_fd)
+{
+ gint fd;
+ gsize capacity;
+
+ g_return_val_if_fail (filename != NULL, 0);
+
+ fd = open (filename, O_RDWR);
+
+ if (fd == -1)
+ return 0;
+
+ capacity = lseek (fd, 0, SEEK_END) / RBC_BLOCK_SIZE;
+
+ if (out_fd)
+ *out_fd = fd;
+ else
+ close (fd);
+
+ return capacity;
+}
+
+static gint
+partition_order (const RBCPartition *a,
+ const RBCPartition *b)
+{
+ if (a->order < b->order)
+ return -1;
+ else if (a->order > b->order)
+ return 1;
+
+ return 0;
+}
Added: trunk/librbc/rbcdisk.h
==============================================================================
--- trunk/librbc/rbcdisk.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/librbc/rbcdisk.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,55 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __RBC_DISK_H__
+#define __RBC_DISK_H__
+
+
+#include <glib.h>
+
+#include <librbc/rbctypes.h>
+
+
+RBCDisk *rbc_disk_new (RBCDiskType type);
+
+void rbc_disk_destroy (RBCDisk *disk);
+
+RBCDiskType rbc_disk_get_type (RBCDisk *disk);
+
+gboolean rbc_disk_is_equal (RBCDisk *a,
+ RBCDisk *b);
+
+gboolean rbc_disk_set_filename (RBCDisk *disk,
+ const gchar *filename);
+
+gboolean rbc_disk_add_partition (RBCDisk *disk,
+ const gchar *filename,
+ guint order);
+
+gsize rbc_disk_get_capacity (RBCDisk *disk);
+gsize rbc_disk_get_block_size (RBCDisk *disk);
+
+gboolean rbc_disk_activate (RBCDisk *disk);
+
+
+#endif /* __RBC_DISK_H__ */
Added: trunk/librbc/rbcprivate.h
==============================================================================
--- trunk/librbc/rbcprivate.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/librbc/rbcprivate.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,62 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __RBC_PRIVATE_H__
+#define __RBC_PRIVATE_H__
+
+
+#include <glib.h>
+
+#include <librbc/rbctypes.h>
+
+
+#define RBC_BLOCK_SIZE 512
+
+
+typedef struct _RBCPartition RBCPartition;
+
+struct _RBCPartition
+{
+ gchar *filename;
+ guint order;
+
+ gint fd;
+ gsize capacity;
+};
+
+struct _RBCDisk
+{
+ RBCDiskType type;
+
+ gchar *filename;
+
+ GList *partitions;
+
+ gint fd;
+ gsize capacity;
+
+ gboolean active;
+};
+
+
+#endif /* __RBC_PRIVATE_H__ */
Added: trunk/librbc/rbctypes.h
==============================================================================
--- trunk/librbc/rbctypes.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/librbc/rbctypes.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,38 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __RBC_TYPES_H__
+#define __RBC_TYPES_H__
+
+
+typedef enum
+{
+ RBC_DISK_PHYSICAL,
+ RBC_DISK_VIRTUAL
+} RBCDiskType;
+
+
+typedef struct _RBCDisk RBCDisk;
+
+
+#endif /* __RBC_TYPES_H__ */
Added: trunk/libsbp2/Makefile.am
==============================================================================
--- trunk/libsbp2/Makefile.am 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libsbp2/Makefile.am 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,31 @@
+noinst_LIBRARIES = libsbp2.a
+
+INCLUDES = \
+ -I$(top_srcdir) \
+ $(GLIB_CFLAGS) \
+ $(LIBRAW1394_CPPFLAGS) \
+ -I$(includedir)
+
+libsbp2_a_SOURCES = \
+ sbp2byteswap.h \
+ sbp2configrom.c \
+ sbp2configrom.h \
+ sbp2constants.h \
+ sbp2csr.h \
+ sbp2debug.h \
+ sbp2manager.c \
+ sbp2manager.h \
+ sbp2main.c \
+ sbp2main.h \
+ sbp2login.h \
+ sbp2logout.h \
+ sbp2pagetable.h \
+ sbp2pointer.h \
+ sbp2querylogins.h \
+ sbp2raw1394.c \
+ sbp2raw1394.h \
+ sbp2reconnect.h \
+ sbp2scsicommand.h \
+ sbp2status.h \
+ sbp2worker.c \
+ sbp2worker.h
Added: trunk/libsbp2/sbp2byteswap.h
==============================================================================
--- trunk/libsbp2/sbp2byteswap.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libsbp2/sbp2byteswap.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,51 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __SBP2_BYTESWAP_H__
+#define __SBP2_BYTESWAP_H__
+
+
+#include <glib.h>
+
+
+static inline void
+sbp2_byteswap_data (gpointer data,
+ gint length)
+{
+ guint32 *temp = data;
+
+ for (length = (length >> 2); length--; )
+ temp[length] = GUINT32_FROM_BE (temp[length]);
+}
+
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define sbp2_be32_to_cpu_data(b, l) sbp2_byteswap_data((b), (l))
+#define sbp2_cpu_to_be32_data(b, l) sbp2_byteswap_data((b), (l))
+#else /* G_BIG_ENDIAN */
+#define sbp2_be32_to_cpu_data(b, l) G_STMT_START { (void)0; } G_STMT_END
+#define sbp2_cpu_to_be32_data(b, l) G_STMT_START { (void)0; } G_STMT_END
+#endif
+
+
+#endif /* __SBP2_BYTESWAP_H__ */
Added: trunk/libsbp2/sbp2configrom.c
==============================================================================
--- trunk/libsbp2/sbp2configrom.c 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libsbp2/sbp2configrom.c 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,117 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#include <glib.h>
+
+#include <libraw1394/raw1394.h>
+
+#include "sbp2configrom.h"
+#include "sbp2csr.h"
+
+
+#define ROM_BUF_SIZE 256
+
+
+static guint16 crc16 (guint32 *buffer,
+ gint length);
+
+
+gboolean
+sbp2_setup_config_rom (raw1394handle_t handle)
+{
+ quadlet_t rom[ROM_BUF_SIZE];
+ gsize rom_size;
+ guchar rom_version;
+ gint ret, i;
+
+ g_return_val_if_fail (handle != NULL, FALSE);
+
+ ret = raw1394_get_config_rom (handle, rom, ROM_BUF_SIZE,
+ &rom_size, &rom_version);
+
+ if (ret != 0)
+ return FALSE;
+
+ if (rom[9] == GUINT32_FROM_BE(0xd1000008))
+ return TRUE;
+
+ for (i = 15; i > 8; i--)
+ rom[i + 1] = rom[i];
+
+ rom[7] = GUINT32_FROM_BE(0x81000003);
+ rom[9] = GUINT32_FROM_BE(0xd1000008);
+
+ rom[5] = GUINT32_FROM_BE(4 << 16 | crc16 (&rom[6], 4));
+
+ rom[18] = GUINT32_FROM_BE(0x1200609e);
+ rom[19] = GUINT32_FROM_BE(0x13010483);
+ rom[20] = GUINT32_FROM_BE(0x3800609e); /* IEEE/RAC */
+ rom[21] = GUINT32_FROM_BE(0x390104d8); /* IEEE/RAC */
+ rom[22] = GUINT32_FROM_BE(0x3b000000); /* IEEE/RAC */
+ rom[23] = GUINT32_FROM_BE(0x3c000001); /* IEEE/RAC */
+ rom[24] = GUINT32_FROM_BE(0x54000000 + SBP2_CSR_MANANGEMENT_OFFSET);
+ rom[25] = GUINT32_FROM_BE(0x3a003c08); /* unit characteristics */
+ rom[26] = GUINT32_FROM_BE(0x3d000003); /* reconnect timeout */
+ rom[27] = GUINT32_FROM_BE(0x144e0000); /* logical unit number */
+
+ rom[17] = GUINT32_FROM_BE(10 << 16 | crc16 (&rom[18], 10));
+
+ rom_size += 12 * 4;
+
+ ret = raw1394_update_config_rom (handle, rom, rom_size, rom_version);
+
+ if (ret == -1)
+ return FALSE;
+
+ return TRUE;
+}
+
+static guint16
+crc16 (guint32 *buffer,
+ gint length)
+{
+ gint shift;
+ guint32 crc, sum, data;
+
+ g_return_val_if_fail (buffer != NULL, 0);
+
+ crc = 0;
+
+ for (; length > 0; length--)
+ {
+ data = GUINT32_FROM_BE (*buffer);
+
+ for (shift = 28; shift >= 0; shift -= 4)
+ {
+ sum = ((crc >> 12) ^ (data >> shift)) & 0x000f;
+ crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum;
+ }
+
+ crc &= 0xffff;
+
+ buffer++;
+ }
+
+ return crc;
+}
+
Added: trunk/libsbp2/sbp2configrom.h
==============================================================================
--- trunk/libsbp2/sbp2configrom.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libsbp2/sbp2configrom.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,34 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __SBP2_CONFIGROM_H__
+#define __SBP2_CONFIGROM_H__
+
+
+#include <libraw1394/raw1394.h>
+
+
+gboolean sbp2_setup_config_rom (raw1394handle_t handle);
+
+
+#endif /* __SBP2_CONFIGROM_H__ */
Added: trunk/libsbp2/sbp2constants.h
==============================================================================
--- trunk/libsbp2/sbp2constants.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libsbp2/sbp2constants.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,31 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __SBP2_CONSTANTS_H__
+#define __SBP2_CONSTANTS_H__
+
+
+#define SBP2_RECONNECT_HOLD 3
+
+
+#endif /* __SBP2_CONSTANTS_H__ */
Added: trunk/libsbp2/sbp2csr.h
==============================================================================
--- trunk/libsbp2/sbp2csr.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libsbp2/sbp2csr.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,36 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __SBP2_CSR_H__
+#define __SBP2_CSR_H__
+
+
+#define SBP2_CSR_MANANGEMENT_AGENT 0x30000
+#define SBP2_CSR_COMMAND_BLOCK_AGENT_BASE 0x40000
+
+#define SBP2_CSR_COMMAND_BLOCK_AGENT_SIZE 0x20
+
+#define SBP2_CSR_MANANGEMENT_OFFSET (SBP2_CSR_MANANGEMENT_AGENT / 4)
+
+
+#endif /* __SBP2_CSR_H__ */
Added: trunk/libsbp2/sbp2login.h
==============================================================================
--- trunk/libsbp2/sbp2login.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libsbp2/sbp2login.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,82 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __SBP2_LOGIN_H__
+#define __SBP2_LOGIN_H__
+
+
+#include <glib.h>
+
+#include <libsbp2/sbp2pointer.h>
+
+
+typedef struct _SBP2LoginORB SBP2LoginORB;
+typedef struct _SBP2LoginResponse SBP2LoginResponse;
+
+struct _SBP2LoginORB
+{
+ SBP2Pointer password;
+ SBP2Pointer login_resp;
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+ guint notify : 1;
+ guint req_fmt : 2;
+ guint exclusive : 1;
+ guint reserved : 4;
+ guint reconnect : 4;
+ guint function : 4;
+ guint lun : 16;
+ guint password_length : 16;
+ guint resp_length : 16;
+#else
+ guint lun : 16;
+ guint function : 4;
+ guint reconnect : 4;
+ guint reserved : 4;
+ guint exclusive : 1;
+ guint req_fmt : 2;
+ guint notify : 1;
+ guint resp_length : 16;
+ guint password_length : 16;
+#endif
+ SBP2Pointer status_FIFO;
+};
+
+struct _SBP2LoginResponse
+{
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+ guint length : 16;
+ guint login_ID : 16;
+ SBP2Pointer command_block_agent;
+ guint reserved : 16;
+ guint reconnect_hold : 16;
+#else
+ guint login_ID : 16;
+ guint length : 16;
+ SBP2Pointer command_block_agent;
+ guint reconnect_hold : 16;
+ guint reserved : 16;
+#endif
+};
+
+
+#endif /* __SBP2_LOGIN_H__ */
Added: trunk/libsbp2/sbp2logout.h
==============================================================================
--- trunk/libsbp2/sbp2logout.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libsbp2/sbp2logout.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,59 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __SBP2_LOGOUT_H__
+#define __SBP2_LOGOUT_H__
+
+
+#include <glib.h>
+
+#include <libsbp2/sbp2pointer.h>
+
+
+typedef struct _SBP2LogoutORB SBP2LogoutORB;
+
+struct _SBP2LogoutORB
+{
+ guint32 reserved1;
+ guint32 reserved2;
+ guint32 reserved3;
+ guint32 reserved4;
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+ guint notify : 1;
+ guint req_fmt : 2;
+ guint reserved5 : 9;
+ guint function : 4;
+ guint login_ID : 16;
+#else
+ guint login_ID : 16;
+ guint function : 4;
+ guint reserved5 : 9;
+ guint req_fmt : 2;
+ guint notify : 1;
+#endif
+ guint32 reserved6;
+ SBP2Pointer status_FIFO;
+};
+
+
+#endif /* __SBP2_LOGOUT_H__ */
Added: trunk/libsbp2/sbp2main.c
==============================================================================
--- trunk/libsbp2/sbp2main.c 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libsbp2/sbp2main.c 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,235 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#include <glib.h>
+
+#include <libraw1394/raw1394.h>
+
+#include "sbp2main.h"
+
+
+typedef gint (*ReadWriteFunc) (raw1394handle_t handle,
+ nodeid_t node,
+ nodeaddr_t address,
+ gsize length,
+ quadlet_t *buffer,
+ gulong tag);
+
+struct _SBP2Tag
+{
+ guint ref_count;
+
+ SBP2TagProcessFunc process;
+ SBP2TagFreeFunc free;
+
+ gpointer data;
+};
+
+
+static gboolean raw_activity (GIOChannel *source,
+ GIOCondition condition,
+ gpointer data);
+
+static gint tag_handler (raw1394handle_t handle,
+ gulong the_tag,
+ raw1394_errcode_t errcode);
+
+static void read_write_data (ReadWriteFunc read_write_func,
+ raw1394handle_t handle,
+ gsize chunk_size,
+ nodeid_t node,
+ SBP2Pointer *pointer,
+ gpointer data,
+ gsize length,
+ SBP2Tag *tag);
+
+
+guint
+sbp2_watch_handle (raw1394handle_t handle,
+ GMainContext *context)
+{
+ gint fd;
+ GIOChannel *channel;
+ GSource *source;
+ guint id;
+
+ g_return_val_if_fail (handle != NULL, 0);
+ g_return_val_if_fail (context != NULL, 0);
+
+ raw1394_set_tag_handler (handle, tag_handler);
+
+ fd = raw1394_get_fd (handle);
+
+ channel = g_io_channel_unix_new (fd);
+
+ g_io_channel_set_encoding (channel, NULL, NULL);
+ g_io_channel_set_buffered (channel, FALSE);
+
+ source = g_io_create_watch (channel, G_IO_IN | G_IO_PRI);
+ g_io_channel_unref (channel);
+
+ g_source_set_priority (source, G_PRIORITY_HIGH_IDLE);
+
+ g_source_set_callback (source, (GSourceFunc) raw_activity, handle, NULL);
+ id = g_source_attach (source, context);
+
+ return id;
+}
+
+SBP2Tag *
+sbp2_tag_new (SBP2TagProcessFunc process,
+ SBP2TagFreeFunc free,
+ gpointer data)
+{
+ SBP2Tag *tag;
+
+ tag = g_new (SBP2Tag, 1);
+
+ tag->ref_count = 0;
+
+ tag->process = process;
+ tag->free = free;
+ tag->data = data;
+
+ return tag;
+}
+
+void
+sbp2_write_data (raw1394handle_t handle,
+ gsize chunk_size,
+ nodeid_t node,
+ SBP2Pointer *pointer,
+ gpointer data,
+ gsize length)
+{
+ SBP2Tag *tag;
+
+ tag = sbp2_tag_new (NULL, g_free, data);
+
+ read_write_data (raw1394_start_write, handle, chunk_size, node, pointer,
+ data, length, tag);
+}
+
+void
+sbp2_read_data (raw1394handle_t handle,
+ gsize chunk_size,
+ nodeid_t node,
+ SBP2Pointer *pointer,
+ gpointer data,
+ gsize length,
+ SBP2Tag *tag)
+{
+ read_write_data (raw1394_start_read, handle, chunk_size, node, pointer,
+ data, length, tag);
+}
+
+static gboolean
+raw_activity (GIOChannel *channel,
+ GIOCondition condition,
+ gpointer data)
+{
+ raw1394handle_t handle = data;
+
+ g_return_val_if_fail (channel != NULL, FALSE);
+ g_return_val_if_fail (handle != NULL, FALSE);
+
+ raw1394_loop_iterate (handle);
+
+ return TRUE;
+}
+
+static gint
+tag_handler (raw1394handle_t handle,
+ gulong the_tag,
+ raw1394_errcode_t errcode)
+{
+ SBP2Tag *tag = (SBP2Tag *) the_tag;
+
+ g_return_val_if_fail (handle != NULL, -1);
+ g_return_val_if_fail (tag != NULL, -1);
+ g_return_val_if_fail (tag->ref_count > 0, -1);
+
+ tag->ref_count--;
+
+ if (tag->ref_count == 0)
+ {
+ gboolean free_data = TRUE;
+
+ if (errcode != 0 && tag->process)
+ free_data = tag->process (tag->data);
+
+ if (free_data && tag->free)
+ tag->free (tag->data);
+
+ g_free (tag);
+ }
+
+ return 0;
+}
+
+static void
+read_write_data (ReadWriteFunc read_write_func,
+ raw1394handle_t handle,
+ gsize chunk_size,
+ nodeid_t node,
+ SBP2Pointer *pointer,
+ gpointer data,
+ gsize length,
+ SBP2Tag *tag)
+{
+ nodeaddr_t address;
+ guint8 *buffer;
+ gsize left;
+
+ g_return_if_fail (handle != NULL);
+ g_return_if_fail (pointer != NULL);
+ g_return_if_fail (data != NULL);
+ g_return_if_fail (length > 0);
+ g_return_if_fail (tag != NULL);
+
+ if (chunk_size == 0)
+ chunk_size = length;
+
+ address = sbp2_pointer_to_1394_address (pointer);
+
+ buffer = data;
+ left = length;
+
+ while (left > chunk_size)
+ {
+ tag->ref_count++;
+
+ read_write_func (handle, node, address, chunk_size,
+ (quadlet_t *) buffer, (gulong) tag);
+
+ buffer += chunk_size;
+ address += chunk_size;
+
+ left -= chunk_size;
+ }
+
+ tag->ref_count++;
+
+ read_write_func (handle, node, address, left,
+ (quadlet_t *) buffer, (gulong) tag);
+}
Added: trunk/libsbp2/sbp2main.h
==============================================================================
--- trunk/libsbp2/sbp2main.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libsbp2/sbp2main.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,65 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ *
+ */
+
+#ifndef __SBP2_MAIN_H__
+#define __SBP2_MAIN_H__
+
+
+#include <glib.h>
+
+#include <libraw1394/raw1394.h>
+
+#include <libsbp2/sbp2pointer.h>
+
+
+typedef struct _SBP2Tag SBP2Tag;
+
+typedef gboolean (*SBP2TagProcessFunc) (gpointer data);
+typedef void (*SBP2TagFreeFunc) (gpointer data);
+
+
+guint sbp2_watch_handle (raw1394handle_t handle,
+ GMainContext *context);
+
+SBP2Tag *sbp2_tag_new (SBP2TagProcessFunc process,
+ SBP2TagFreeFunc free,
+ gpointer data);
+
+void sbp2_write_data (raw1394handle_t handle,
+ gsize chunk_size,
+ nodeid_t node,
+ SBP2Pointer *pointer,
+ gpointer data,
+ gsize length);
+
+void sbp2_read_data (raw1394handle_t handle,
+ gsize chunk_size,
+ nodeid_t node,
+ SBP2Pointer *pointer,
+ gpointer data,
+ gsize length,
+ SBP2Tag *tag);
+
+
+#endif /* __SBP2_MAIN_H__ */
Added: trunk/libsbp2/sbp2manager.c
==============================================================================
--- trunk/libsbp2/sbp2manager.c 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libsbp2/sbp2manager.c 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,423 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#include <string.h>
+
+#include <glib.h>
+
+#include <libraw1394/raw1394.h>
+#include <libraw1394/csr.h>
+
+#include "sbp2byteswap.h"
+#include "sbp2configrom.h"
+#include "sbp2csr.h"
+#include "sbp2manager.h"
+#include "sbp2main.h"
+#include "sbp2raw1394.h"
+
+
+enum
+{
+ FUNC_LOGIN_REQUEST = 0x0,
+ FUNC_QUERY_LOGINS_REQUEST = 0x1,
+ FUNC_RECONNECT_REQUEST = 0x3,
+ FUNC_SET_PASSWORD_REQUEST = 0x4,
+ FUNC_LOGOUT_REQUEST = 0x7,
+ FUNC_ABORT_TASK_REQUEST = 0xb,
+ FUNC_ABORT_TASK_SET = 0xc,
+ FUNC_LOGICAL_UNIT_RESET = 0xe,
+ FUNC_TARGET_RESET_REQUEST = 0xf
+};
+
+
+typedef struct raw1394_arm_request ARMRequest;
+typedef struct raw1394_arm_request_response ARMReqResp;
+
+typedef struct _SBP2ManagementORB SBP2ManagementORB;
+typedef struct _ORBData ORBData;
+
+struct _SBP2ManagementORB
+{
+ guint32 reserved1;
+ guint32 reserved2;
+ guint32 reserved3;
+ guint32 reserved4;
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+ guint notify : 1;
+ guint req_fmt : 2;
+ guint reserved5 : 9;
+ guint function : 4;
+ guint reserved6 : 16;
+#else
+ guint reserved6 : 16;
+ guint function : 4;
+ guint reserved5 : 9;
+ guint req_fmt : 2;
+ guint notify : 1;
+#endif
+ guint32 reserved7;
+ SBP2Pointer status_FIFO;
+};
+
+struct _ORBData
+{
+ SBP2Manager *manager;
+
+ nodeid_t node;
+ SBP2Pointer pointer;
+
+ SBP2ManagementORB orb;
+};
+
+struct _SBP2Manager
+{
+ raw1394handle_t handle;
+ guint id;
+
+ struct raw1394_arm_reqhandle arm_management_agent;
+
+ SBP2ManagerFuncs *funcs;
+ gpointer user_data;
+};
+
+
+static gint management_agent (raw1394handle_t handle,
+ ARMReqResp *arm_req_resp,
+ guint requested_length,
+ gpointer manager,
+ guint8 request_type);
+
+static void fetch_orb (SBP2Manager *manager,
+ nodeid_t node,
+ SBP2Pointer *pointer);
+static gboolean process_orb (gpointer data);
+
+static gboolean login (SBP2ManagerAction *action);
+static gboolean query_logins (SBP2ManagerAction *action);
+static gboolean reconnect (SBP2ManagerAction *action);
+static gboolean logout (SBP2ManagerAction *action);
+
+static gint bus_reset_handler (raw1394handle_t handle,
+ guint generation);
+
+
+SBP2Manager *
+sbp2_manager_new (SBP2ManagerFuncs *funcs,
+ GMainContext *context,
+ gint port,
+ gpointer user_data)
+{
+ SBP2Manager *manager = NULL;
+ raw1394handle_t handle = NULL;
+ gint ret;
+
+ handle = sbp2_raw1394_handle ();
+
+ if (!handle)
+ goto fail;
+
+ if (raw1394_set_port (handle, port) != 0)
+ goto fail;
+
+ if (!sbp2_setup_config_rom (handle))
+ goto fail;
+
+ manager = g_new (SBP2Manager, 1);
+
+ manager->arm_management_agent.arm_callback = management_agent;
+ manager->arm_management_agent.pcontext = manager;
+
+ ret = raw1394_arm_register (handle,
+ CSR_REGISTER_BASE + SBP2_CSR_MANANGEMENT_AGENT,
+ 8, NULL,
+ (gulong) &manager->arm_management_agent,
+ RAW1394_ARM_READ | RAW1394_ARM_WRITE,
+ RAW1394_ARM_WRITE,
+ 0);
+ if (ret < 0)
+ goto fail;
+
+ raw1394_set_userdata (handle, manager);
+ raw1394_set_bus_reset_handler (handle, bus_reset_handler);
+
+ manager->handle = handle;
+ manager->id = sbp2_watch_handle (handle, context);
+
+ manager->funcs = funcs;
+ manager->user_data = user_data;
+
+ return manager;
+
+fail:
+ g_free (manager);
+ raw1394_destroy_handle (handle);
+
+ return NULL;
+}
+
+void
+sbp2_manager_destroy (SBP2Manager *manager)
+{
+ g_return_if_fail (manager != NULL);
+
+ g_source_remove (manager->id);
+
+ raw1394_destroy_handle (manager->handle);
+
+ g_free (manager);
+}
+
+void
+sbp2_manager_write_status (SBP2Manager *manager,
+ nodeid_t node,
+ SBP2Pointer *pointer,
+ SBP2Status *status)
+{
+ gsize length;
+
+ g_return_if_fail (manager != NULL);
+ g_return_if_fail (pointer != NULL);
+ g_return_if_fail (status != NULL);
+
+ length = (status->len + 1) * 4;
+
+ sbp2_cpu_to_be32_data (status, length);
+ sbp2_write_data (manager->handle, 0, node, pointer, status, length);
+}
+
+void
+sbp2_manager_reset_bus (SBP2Manager *manager)
+{
+ g_return_if_fail (manager != NULL);
+
+ raw1394_reset_bus (manager->handle);
+}
+
+static gint
+management_agent (raw1394handle_t handle,
+ ARMReqResp *arm_req_resp,
+ guint requested_length,
+ gpointer manager,
+ guint8 request_type)
+{
+ ARMRequest *request;
+ SBP2Pointer *pointer;
+
+ g_return_val_if_fail (manager != NULL, -1);
+
+ request = arm_req_resp->request;
+
+ pointer = (SBP2Pointer *) request->buffer;
+ sbp2_be32_to_cpu_data (pointer, sizeof (*pointer));
+
+ fetch_orb (manager, request->source_nodeid, pointer);
+
+ return 0;
+}
+
+static void
+fetch_orb (SBP2Manager *manager,
+ nodeid_t node,
+ SBP2Pointer *pointer)
+{
+ ORBData *orb_data;
+ SBP2Tag *tag;
+
+ g_return_if_fail (manager != NULL);
+ g_return_if_fail (pointer != NULL);
+
+ orb_data = g_new (ORBData, 1);
+
+ orb_data->manager = manager;
+
+ orb_data->node = node;
+ memcpy (&orb_data->pointer, pointer, sizeof (orb_data->pointer));
+
+ tag = sbp2_tag_new (process_orb, g_free, orb_data);
+
+ sbp2_read_data (manager->handle, 0, node, pointer,
+ &orb_data->orb, sizeof (orb_data->orb),
+ tag);
+}
+
+static gboolean
+process_orb (gpointer data)
+{
+ ORBData *orb_data = data;
+ nodeid_t node;
+ SBP2Pointer *pointer;
+ SBP2ManagementORB *orb;
+ SBP2Manager *manager;
+ SBP2Status *status;
+ SBP2ManagerAction action;
+ gboolean ret;
+
+ g_return_val_if_fail (orb_data != NULL, FALSE);
+
+ manager = orb_data->manager;
+
+ node = orb_data->node;
+ pointer = &orb_data->pointer;
+
+ orb = &orb_data->orb;
+
+ sbp2_be32_to_cpu_data (orb, sizeof (*orb));
+
+ status = g_new0 (SBP2Status, 1);
+
+ sbp2_status_fill_pointer (status, pointer);
+
+ status->len = 1;
+ status->src = SBP2_STATUS_ORIGIN_NULL;
+ status->resp = SBP2_STATUS_RESP_REQUEST_COMPLETE;
+
+ action.manager = manager;
+ action.node = node;
+ action.pointer = pointer;
+ action.status = status;
+ action.orb = orb;
+ action.user_data = manager->user_data;
+
+ switch (orb->function)
+ {
+ case FUNC_LOGIN_REQUEST:
+ ret = login (&action);
+ break;
+
+ case FUNC_QUERY_LOGINS_REQUEST:
+ ret = query_logins (&action);
+ break;
+
+ case FUNC_RECONNECT_REQUEST:
+ ret = reconnect (&action);
+ break;
+
+ case FUNC_LOGOUT_REQUEST:
+ ret = logout (&action);
+ break;
+
+ case FUNC_SET_PASSWORD_REQUEST:
+ case FUNC_ABORT_TASK_REQUEST:
+ case FUNC_ABORT_TASK_SET:
+ case FUNC_LOGICAL_UNIT_RESET:
+ case FUNC_TARGET_RESET_REQUEST:
+ default:
+ status->resp = SBP2_STATUS_RESP_ILLEGAL_REQUEST;
+ ret = TRUE;
+ break;
+ }
+
+ if (ret)
+ sbp2_manager_write_status (manager, node, &orb->status_FIFO, status);
+ else
+ g_free (status);
+
+ return TRUE;
+}
+
+static gboolean
+login (SBP2ManagerAction *action)
+{
+ SBP2LoginORB *orb = action->orb;
+ SBP2LoginResponse *resp;
+ SBP2Manager *manager = action->manager;
+ gint length;
+
+ resp = g_new0 (SBP2LoginResponse, 1);
+
+ if (!manager->funcs->login (action, orb, resp))
+ {
+ g_free (resp);
+ return FALSE;
+ }
+
+ length = resp->length;
+
+ sbp2_cpu_to_be32_data (resp, length);
+ sbp2_write_data (manager->handle, 0, action->node, &orb->login_resp,
+ resp, length);
+
+ return TRUE;
+}
+
+static gboolean
+query_logins (SBP2ManagerAction *action)
+{
+ SBP2QueryLoginsORB *orb = action->orb;
+ SBP2QueryLoginsResponse *resp;
+ SBP2Manager *manager = action->manager;
+ gsize length;
+
+ resp = g_new0 (SBP2QueryLoginsResponse, 1);
+
+ if (!manager->funcs->query_logins (action, orb, resp))
+ {
+ g_free (resp);
+ return FALSE;
+ }
+
+ length = 4; /* TODO: use resp->length */
+
+ sbp2_cpu_to_be32_data (resp, length);
+ sbp2_write_data (manager->handle, 0, action->node, &orb->query_resp,
+ resp, length);
+
+ return TRUE;
+}
+
+static gboolean
+reconnect (SBP2ManagerAction *action)
+{
+ SBP2ReconnectORB *orb = action->orb;
+ SBP2Manager *manager = action->manager;
+
+ return manager->funcs->reconnect (action, orb);
+}
+
+static gboolean
+logout (SBP2ManagerAction *action)
+{
+ SBP2LogoutORB *orb = action->orb;
+ SBP2Manager *manager = action->manager;
+
+ return manager->funcs->logout (action, orb);
+}
+
+static gint
+bus_reset_handler (raw1394handle_t handle,
+ guint generation)
+{
+ SBP2Manager *manager;
+
+ g_return_val_if_fail (handle != NULL, -1);
+
+ raw1394_update_generation (handle, generation);
+
+ manager = raw1394_get_userdata (handle);
+
+ g_return_val_if_fail (manager != NULL, -1);
+
+ manager->funcs->bus_reset (manager, manager->user_data);
+
+ return 0;
+}
Added: trunk/libsbp2/sbp2manager.h
==============================================================================
--- trunk/libsbp2/sbp2manager.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libsbp2/sbp2manager.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,91 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __SBP2_MANAGER_H__
+#define __SBP2_MANAGER_H__
+
+
+#include <glib.h>
+
+#include <libraw1394/raw1394.h>
+
+#include <libsbp2/sbp2login.h>
+#include <libsbp2/sbp2logout.h>
+#include <libsbp2/sbp2querylogins.h>
+#include <libsbp2/sbp2reconnect.h>
+#include <libsbp2/sbp2status.h>
+
+
+typedef struct _SBP2Manager SBP2Manager;
+typedef struct _SBP2ManagerAction SBP2ManagerAction;
+typedef struct _SBP2ManagerFuncs SBP2ManagerFuncs;
+
+struct _SBP2ManagerAction
+{
+ SBP2Manager *manager;
+
+ nodeid_t node;
+ SBP2Pointer *pointer;
+
+ SBP2Status *status;
+
+ gpointer orb;
+ gpointer user_data;
+};
+
+struct _SBP2ManagerFuncs
+{
+ void (*bus_reset) (SBP2Manager *manager,
+ gpointer user_data);
+
+ gboolean (*login) (SBP2ManagerAction *action,
+ SBP2LoginORB *orb,
+ SBP2LoginResponse *resp);
+ gboolean (*query_logins) (SBP2ManagerAction *action,
+ SBP2QueryLoginsORB *orb,
+ SBP2QueryLoginsResponse *resp);
+ gboolean (*reconnect) (SBP2ManagerAction *action,
+ SBP2ReconnectORB *orb);
+ gboolean (*logout) (SBP2ManagerAction *action,
+ SBP2LogoutORB *orb);
+
+ /* TODO: task_management */
+};
+
+
+SBP2Manager *sbp2_manager_new (SBP2ManagerFuncs *funcs,
+ GMainContext *context,
+ gint port,
+ gpointer user_data);
+
+void sbp2_manager_destroy (SBP2Manager *manager);
+
+void sbp2_manager_write_status (SBP2Manager *manager,
+ nodeid_t node,
+ SBP2Pointer *pointer,
+ SBP2Status *status);
+
+void sbp2_manager_reset_bus (SBP2Manager *manager);
+
+
+#endif /* __SBP2_MANAGER_H__ */
Added: trunk/libsbp2/sbp2pagetable.h
==============================================================================
--- trunk/libsbp2/sbp2pagetable.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libsbp2/sbp2pagetable.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,63 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __SBP2_PAGE_TABLE_H__
+#define __SBP2_PAGE_TABLE_H__
+
+
+#include <glib.h>
+
+
+typedef struct _SBP2Page SBP2Page;
+typedef struct _SBP2PageNormalized SBP2PageNormalized;
+
+struct _SBP2Page
+{
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+ guint segment_length : 16;
+ guint segment_base_hi : 16;
+#else
+ guint segment_base_hi : 16;
+ guint segment_length : 16;
+#endif
+ guint32 segment_base_lo;
+};
+
+struct _SBP2PageNormalized
+{
+ /* TODO */
+ guint32 unimplmented1;
+ guint32 unimplmented2;
+};
+
+
+static inline void
+sbp2_pointer_from_page (SBP2Pointer *p,
+ SBP2Page *page)
+{
+ p->addr_lo = page->segment_base_lo;
+ p->addr_hi = page->segment_base_hi;
+}
+
+
+#endif /* __SBP2_PAGE_TABLE_H__ */
Added: trunk/libsbp2/sbp2pointer.h
==============================================================================
--- trunk/libsbp2/sbp2pointer.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libsbp2/sbp2pointer.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,73 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __SBP2_POINTER_H__
+#define __SBP2_POINTER_H__
+
+
+#include <glib.h>
+
+
+typedef struct _SBP2Pointer SBP2Pointer;
+
+struct _SBP2Pointer
+{
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+ guint node : 16;
+ guint addr_hi : 16;
+#else
+ guint addr_hi : 16;
+ guint node : 16;
+#endif
+ guint32 addr_lo;
+};
+
+
+static inline guint64
+sbp2_pointer_to_1394_address (SBP2Pointer *p)
+{
+ guint64 address;
+
+ address = p->addr_lo;
+ address |= (guint64) p->addr_hi << 32;
+
+ return address;
+}
+
+static inline void
+sbp2_pointer_from_1394_address (SBP2Pointer *p,
+ guint64 address)
+{
+ p->addr_lo = address & 0xffffffff;
+ p->addr_hi |= (address >> 32) & 0xffff;
+}
+
+
+static inline gboolean
+sbp2_pointer_is_null_orb (SBP2Pointer *p)
+{
+ return p->node & 0x8000;
+}
+
+
+#endif /* __SBP2_POINTER_H__ */
Added: trunk/libsbp2/sbp2querylogins.h
==============================================================================
--- trunk/libsbp2/sbp2querylogins.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libsbp2/sbp2querylogins.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,75 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __SBP2_QUERY_LOGINS_H__
+#define __SBP2_QUERY_LOGINS_H__
+
+
+#include <glib.h>
+
+#include <libsbp2/sbp2pointer.h>
+
+
+typedef struct _SBP2QueryLoginsORB SBP2QueryLoginsORB;
+typedef struct _SBP2QueryLoginsResponse SBP2QueryLoginsResponse;
+
+struct _SBP2QueryLoginsORB
+{
+ guint32 reserved1;
+ guint32 reserved2;
+ SBP2Pointer query_resp;
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+ guint notify : 1;
+ guint req_fmt : 2;
+ guint reserved3 : 9;
+ guint function : 4;
+ guint lun : 16;
+ guint reserved4 : 16;
+ guint resp_length : 16;
+#else
+ guint lun : 16;
+ guint function : 4;
+ guint reserved3 : 9;
+ guint req_fmt : 2;
+ guint notify : 1;
+ guint resp_length : 16;
+ guint reserved4 : 16;
+#endif
+ SBP2Pointer status_FIFO;
+};
+
+struct _SBP2QueryLoginsResponse
+{
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+ guint length : 16;
+ guint max_logins : 16;
+#else
+ guint max_logins : 16;
+ guint length : 16;
+#endif
+
+ /* TODO: Logged in initiator listing here, ignored for now */
+};
+
+
+#endif /* __SBP2_QUERY_LOGINS_H__ */
Added: trunk/libsbp2/sbp2raw1394.c
==============================================================================
--- trunk/libsbp2/sbp2raw1394.c 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libsbp2/sbp2raw1394.c 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,89 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#include <errno.h>
+
+#include <glib.h>
+
+#include <libraw1394/raw1394.h>
+
+#include "sbp2raw1394.h"
+
+
+static const gchar *errmsg_not_compatible =
+"This libraw1394 does not work with your version of Linux. You need a "
+"different version that matches your kernel (see kernel help text for the "
+"raw1394 option to find out which is the correct version).";
+
+static const gchar *errmsg_not_loaded =
+"This probably means that you don't have raw1394 support in the kernel or "
+"that you haven't loaded the raw1394 module.";
+
+
+raw1394handle_t
+sbp2_raw1394_handle (void)
+{
+ raw1394handle_t handle;
+
+ handle = raw1394_new_handle ();
+
+ if (!handle)
+ {
+ if (!errno)
+ {
+ g_critical (errmsg_not_compatible);
+ }
+ else
+ {
+ g_critical ("Couldn't get handle");
+ g_critical (errmsg_not_loaded);
+ }
+ }
+
+ return handle;
+}
+
+gint
+sbp2_raw1394_get_num_ports (void)
+{
+ raw1394handle_t handle;
+ gint num_ports;
+
+ handle = sbp2_raw1394_handle ();
+
+ if (!handle)
+ return 0;
+
+ num_ports = raw1394_get_port_info (handle, NULL, 0);
+
+ raw1394_destroy_handle (handle);
+
+ return num_ports;
+}
+
+guint64
+sbp2_raw1394_get_guid (raw1394handle_t handle,
+ nodeid_t node)
+{
+ return 0;
+}
Added: trunk/libsbp2/sbp2raw1394.h
==============================================================================
--- trunk/libsbp2/sbp2raw1394.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libsbp2/sbp2raw1394.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,41 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __SBP2_RAW1394_H__
+#define __SBP2_RAW1394_H__
+
+
+#include <glib.h>
+
+#include <libraw1394/raw1394.h>
+
+
+raw1394handle_t sbp2_raw1394_handle (void);
+
+gint sbp2_raw1394_get_num_ports (void);
+
+guint64 sbp2_raw1394_get_guid (raw1394handle_t handle,
+ nodeid_t node);
+
+
+#endif /* __SBP2_RAW1394_H__ */
Added: trunk/libsbp2/sbp2reconnect.h
==============================================================================
--- trunk/libsbp2/sbp2reconnect.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libsbp2/sbp2reconnect.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,59 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __SBP2_RECONNECT_H__
+#define __SBP2_RECONNECT_H__
+
+
+#include <glib.h>
+
+#include <libsbp2/sbp2pointer.h>
+
+
+typedef struct _SBP2ReconnectORB SBP2ReconnectORB;
+
+struct _SBP2ReconnectORB
+{
+ guint32 reserved1;
+ guint32 reserved2;
+ guint32 reserved3;
+ guint32 reserved4;
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+ guint notify : 1;
+ guint req_fmt : 2;
+ guint reserved5 : 9;
+ guint function : 4;
+ guint login_ID : 16;
+#else
+ guint login_ID : 16;
+ guint function : 4;
+ guint reserved5 : 9;
+ guint req_fmt : 2;
+ guint notify : 1;
+#endif
+ guint32 reserved6;
+ SBP2Pointer status_FIFO;
+};
+
+
+#endif /* __SBP2_RECONNECT_H__ */
Added: trunk/libsbp2/sbp2scsicommand.h
==============================================================================
--- trunk/libsbp2/sbp2scsicommand.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libsbp2/sbp2scsicommand.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,64 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __SBP2_SCSI_COMMAND_H__
+#define __SBP2_SCSI_COMMAND_H__
+
+
+#include <glib.h>
+
+#include <libsbp2/sbp2pointer.h>
+
+
+typedef struct _SBP2ScsiCommandORB SBP2ScsiCommandORB;
+
+struct _SBP2ScsiCommandORB
+{
+ SBP2Pointer next_ORB;
+ SBP2Pointer data_desc;
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+ guint notify : 1;
+ guint req_fmt : 2;
+ guint reserved : 1;
+ guint direction : 1;
+ guint speed : 3;
+ guint max_payload : 4;
+ guint has_page_table : 1;
+ guint page_size : 3;
+ guint data_size : 16;
+#else
+ guint data_size : 16;
+ guint page_size : 3;
+ guint has_page_table : 1;
+ guint max_payload : 4;
+ guint speed : 3;
+ guint direction : 1;
+ guint reserved : 1;
+ guint req_fmt : 2;
+ guint notify : 1;
+#endif
+ guint8 cdb[12];
+};
+
+
+#endif /* __SBP2_SCSI_COMMAND_H__ */
Added: trunk/libsbp2/sbp2scsistatus.h
==============================================================================
--- trunk/libsbp2/sbp2scsistatus.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libsbp2/sbp2scsistatus.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,81 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __SBP2_SCSI_STATUS_H__
+#define __SBP2_SCSI_STATUS_H__
+
+
+#include <glib.h>
+
+
+typedef struct _SBP2ScsiStatus SBP2ScsiStatus;
+
+struct _SBP2ScsiStatus
+{
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+ guint src : 2;
+ guint resp : 2;
+ guint dead : 1;
+ guint len : 3;
+ guint sbp_status : 8;
+ guint ORB_hi : 16;
+ guint32 ORB_lo;
+ guint sfmt : 2;
+ guint status : 6;
+ guint valid : 1;
+ guint mark : 1;
+ guint eom : 1;
+ guint ili : 1;
+ guint sense_key : 4;
+ guint sense_code : 8;
+ guint sense_qualifier : 8;
+ guint32 information;
+ guint32 cdb_dependent;
+ guint fru : 8;
+ guint sense_key_dep : 12;
+#else
+ guint ORB_hi : 16;
+ guint sbp_status : 8;
+ guint len : 3;
+ guint dead : 1;
+ guint resp : 2;
+ guint src : 2;
+ guint32 ORB_lo;
+ guint sense_qualifier : 8;
+ guint sense_code : 8;
+ guint sense_key : 4;
+ guint ili : 1;
+ guint eom : 1;
+ guint mark : 1;
+ guint valid : 1;
+ guint status : 6;
+ guint sfmt : 2;
+ guint32 information;
+ guint32 cdb_dependent;
+ guint sense_key_dep : 12;
+ guint fru : 8;
+#endif
+};
+
+
+#endif /* __SBP2_SCSI_STATUS_H__ */
Added: trunk/libsbp2/sbp2status.h
==============================================================================
--- trunk/libsbp2/sbp2status.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libsbp2/sbp2status.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,102 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __SBP2_STATUS_H__
+#define __SBP2_STATUS_H__
+
+
+#include <glib.h>
+
+#include <libsbp2/sbp2pointer.h>
+
+
+typedef enum
+{
+ SBP2_STATUS_ORIGIN_NON_NULL = 0x0,
+ SBP2_STATUS_ORIGIN_NULL = 0x1,
+ SBP2_STATUS_ORIGIN_UNSOLICITED = 0x2,
+ SBP2_STATUS_ORIGIN_RESERVED = 0x3
+} SBP2StatusOrigin;
+
+typedef enum
+{
+ SBP2_STATUS_RESP_REQUEST_COMPLETE = 0x0,
+ SBP2_STATUS_RESP_TRANSPORT_FAILURE = 0x1,
+ SBP2_STATUS_RESP_ILLEGAL_REQUEST = 0x2,
+ SBP2_STATUS_RESP_VENDOR_DEPENDENT = 0x3
+} SBP2StatusResponse;
+
+typedef enum
+{
+ SBP2_STATUS_REQUEST_NO_ADDITIONAL_INFO = 0x0,
+ SBP2_STATUS_REQUEST_REQ_TYPE_NOT_SUPPORTED = 0x1,
+ SBP2_STATUS_REQUEST_SPEED_NOT_SUPPORTED = 0x2,
+ SBP2_STATUS_REQUEST_PAGE_SIZE_NOT_SUPPORTED = 0x3,
+ SBP2_STATUS_REQUEST_ACCESS_DENIED = 0x4,
+ SBP2_STATUS_REQUEST_LU_NOT_SUPPORTED = 0x5,
+ SBP2_STATUS_REQUEST_MAX_PAYLOAD_TOO_SMALL = 0x6,
+ SBP2_STATUS_REQUEST_RESOURCES_UNAVAILABLE = 0x8,
+ SBP2_STATUS_REQUEST_FUNCTION_REJECTED = 0x9,
+ SBP2_STATUS_REQUEST_LOGIN_ID_NOT_RECOGNIZED = 0xa,
+ SBP2_STATUS_REQUEST_DUMMY_ORB_COMPLETED = 0xb,
+ SBP2_STATUS_REQUEST_REQUEST_ABORTED = 0xc,
+ SBP2_STATUS_REQUEST_UNSPECIFIED_ERROR = 0xff
+} SBP2StatusRequest;
+
+/* TODO: transport failure error codes */
+
+
+typedef struct _SBP2Status SBP2Status;
+
+struct _SBP2Status
+{
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+ guint src : 2;
+ guint resp : 2;
+ guint dead : 1;
+ guint len : 3;
+ guint sbp_status : 8;
+ guint ORB_hi : 16;
+#else
+ guint ORB_hi : 16;
+ guint sbp_status : 8;
+ guint len : 3;
+ guint dead : 1;
+ guint resp : 2;
+ guint src : 2;
+#endif
+ guint32 ORB_lo;
+ guint8 sense[24];
+};
+
+
+static inline void
+sbp2_status_fill_pointer (SBP2Status *s,
+ SBP2Pointer *p)
+{
+ s->ORB_hi = p->addr_hi;
+ s->ORB_lo = p->addr_lo;
+}
+
+
+#endif /* __SBP2_STATUS_H__ */
Added: trunk/libsbp2/sbp2worker.c
==============================================================================
--- trunk/libsbp2/sbp2worker.c 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libsbp2/sbp2worker.c 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,832 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#include <string.h>
+
+#include <glib.h>
+
+#include <libraw1394/raw1394.h>
+#include <libraw1394/csr.h>
+
+#include <librbc/rbcdisk.h>
+#include <librbc/rbccommand.h>
+
+#include "sbp2byteswap.h"
+#include "sbp2constants.h"
+#include "sbp2csr.h"
+#include "sbp2main.h"
+#include "sbp2pagetable.h"
+#include "sbp2raw1394.h"
+#include "sbp2scsicommand.h"
+#include "sbp2status.h"
+#include "sbp2worker.h"
+
+
+enum
+{
+ CMD_AGENT_STATE = 0x00,
+ CMD_AGENT_RESET = 0x04,
+ CMD_ORB_POINTER = 0x08,
+ CMD_DOORBELL = 0x10,
+ CMD_UNSOLICITED_STATUS_ENABLE = 0x14
+};
+
+typedef enum
+{
+ STATE_RESET = 0x0,
+ STATE_ACTIVE = 0x1,
+ STATE_SUSPENDED = 0x2,
+ STATE_DEAD = 0x3
+} State;
+
+
+typedef struct raw1394_arm_request ARMRequest;
+typedef struct raw1394_arm_request_response ARMReqResp;
+
+typedef struct _ORBData ORBData;
+
+struct _ORBData
+{
+ SBP2Worker *worker;
+
+ gsize chunk_size;
+
+ nodeid_t node;
+ SBP2Pointer pointer;
+
+ SBP2ScsiCommandORB orb;
+ SBP2Status *status;
+
+ RBCBuffer *buffer;
+
+ SBP2Pointer *page_pointers;
+};
+
+struct _SBP2Worker
+{
+ raw1394handle_t handle;
+ guint id;
+
+ RBCDisk *disk;
+
+ gboolean unattached;
+
+ State state;
+ gboolean doorbell;
+
+ guint login_ID;
+
+ SBP2Pointer *pointer;
+
+ nodeaddr_t csr_address;
+ SBP2Pointer status_FIFO;
+
+ struct raw1394_arm_reqhandle arm_agent_state;
+ struct raw1394_arm_reqhandle arm_agent_reset;
+ struct raw1394_arm_reqhandle arm_orb_pointer;
+ struct raw1394_arm_reqhandle arm_doorbell;
+ struct raw1394_arm_reqhandle arm_unsolicited_status_enable;
+};
+
+
+static gint agent_reset (raw1394handle_t handle,
+ ARMReqResp *arm_req_resp,
+ guint requested_length,
+ gpointer pcontext,
+ guint8 request_type);
+static gint orb_pointer (raw1394handle_t handle,
+ ARMReqResp *arm_req_resp,
+ guint requested_length,
+ gpointer pcontext,
+ guint8 request_type);
+static gint doorbell (raw1394handle_t handle,
+ ARMReqResp *arm_req_resp,
+ guint requested_length,
+ gpointer pcontext,
+ guint8 request_type);
+static gint unsolicited_status_enable (raw1394handle_t handle,
+ ARMReqResp *arm_req_resp,
+ guint requested_length,
+ gpointer pcontext,
+ guint8 request_type);
+
+static void fetch_orb (SBP2Worker *worker,
+ nodeid_t node,
+ SBP2Pointer *pointer);
+static gboolean process_orb (gpointer data);
+
+static gboolean fetch_data (gpointer data);
+static gboolean process_data (gpointer data);
+
+static gboolean fetch_page_table (gpointer data);
+static gboolean process_page_table (gpointer data);
+
+static gboolean fetch_page_table_data (gpointer data);
+
+static void complete_orb (ORBData *orb_data);
+
+static void write_orb_data_buffer (ORBData *orb_data);
+
+static void free_orb_data (gpointer data);
+
+static gint bus_reset_handler (raw1394handle_t handle,
+ guint generation);
+
+
+SBP2Worker *
+sbp2_worker_new (RBCDisk *disk,
+ GMainContext *context,
+ gint port,
+ guint login_ID)
+{
+ SBP2Worker *worker = NULL;
+ raw1394handle_t handle;
+ nodeaddr_t csr_address;
+ gint ret;
+
+ handle = sbp2_raw1394_handle ();
+
+ if (!handle)
+ return NULL;
+
+ if (raw1394_set_port (handle, port) != 0)
+ goto fail;
+
+ csr_address = CSR_REGISTER_BASE + SBP2_CSR_COMMAND_BLOCK_AGENT_BASE +
+ (SBP2_CSR_COMMAND_BLOCK_AGENT_SIZE * login_ID);
+
+ worker = g_new (SBP2Worker, 1);
+
+ /* TODO: Way to update the register */
+ ret = raw1394_arm_register (handle,
+ csr_address + CMD_AGENT_STATE,
+ 4, NULL,
+ 0,
+ RAW1394_ARM_READ,
+ 0,
+ 0);
+ if (ret < 0)
+ goto fail;
+
+ worker->arm_agent_reset.arm_callback = agent_reset;
+ worker->arm_agent_reset.pcontext = worker;
+
+ ret = raw1394_arm_register (handle,
+ csr_address + CMD_AGENT_RESET,
+ 4, NULL,
+ (gulong) &worker->arm_agent_reset,
+ RAW1394_ARM_WRITE,
+ RAW1394_ARM_WRITE,
+ 0);
+ if (ret < 0)
+ goto fail;
+
+ worker->arm_orb_pointer.arm_callback = orb_pointer;
+ worker->arm_orb_pointer.pcontext = worker;
+
+ ret = raw1394_arm_register (handle,
+ csr_address + CMD_ORB_POINTER,
+ 8, NULL,
+ (gulong) &worker->arm_orb_pointer,
+ RAW1394_ARM_READ | RAW1394_ARM_WRITE,
+ RAW1394_ARM_WRITE,
+ 0);
+ if (ret < 0)
+ goto fail;
+
+ worker->arm_doorbell.arm_callback = doorbell;
+ worker->arm_doorbell.pcontext = worker;
+
+ ret = raw1394_arm_register (handle,
+ csr_address + CMD_DOORBELL,
+ 4, NULL,
+ (gulong) &worker->arm_doorbell,
+ RAW1394_ARM_WRITE,
+ RAW1394_ARM_WRITE,
+ 0);
+ if (ret < 0)
+ goto fail;
+
+ worker->arm_unsolicited_status_enable.arm_callback = unsolicited_status_enable;
+ worker->arm_unsolicited_status_enable.pcontext = worker;
+
+ ret = raw1394_arm_register (handle,
+ csr_address + CMD_UNSOLICITED_STATUS_ENABLE,
+ 4, NULL,
+ (gulong) &worker->arm_unsolicited_status_enable,
+ RAW1394_ARM_WRITE,
+ RAW1394_ARM_WRITE,
+ 0);
+ if (ret < 0)
+ goto fail;
+
+ raw1394_set_userdata (handle, worker);
+ raw1394_set_bus_reset_handler (handle, bus_reset_handler);
+
+ worker->disk = disk;
+
+ worker->unattached = TRUE;
+
+ worker->state = STATE_RESET;
+
+ worker->csr_address = csr_address;
+
+ worker->handle = handle;
+ worker->id = sbp2_watch_handle (handle, context);
+
+ return worker;
+
+fail:
+ g_free (worker);
+ raw1394_destroy_handle (handle);
+
+ return NULL;
+}
+
+void
+sbp2_worker_destroy (SBP2Worker *worker)
+{
+ g_source_remove (worker->id);
+
+ raw1394_destroy_handle (worker->handle);
+
+ g_free (worker);
+}
+
+gboolean
+sbp2_worker_login (SBP2Worker *worker,
+ nodeid_t node,
+ SBP2Pointer *pointer,
+ SBP2LoginORB *orb)
+{
+ SBP2LoginResponse *resp;
+ SBP2Status *status;
+ guint length;
+
+ memcpy (&worker->status_FIFO, &orb->status_FIFO,
+ sizeof (worker->status_FIFO));
+
+ resp = g_new (SBP2LoginResponse, 1);
+
+ if (orb->resp_length >= 16)
+ length = 16;
+ else
+ length = 12;
+
+ resp->length = length;
+
+ resp->login_ID = worker->login_ID;
+
+ resp->reconnect_hold = SBP2_RECONNECT_HOLD;
+
+ resp->command_block_agent.node = raw1394_get_local_id (worker->handle);
+
+ sbp2_pointer_from_1394_address (&resp->command_block_agent,
+ worker->csr_address);
+
+ sbp2_cpu_to_be32_data (resp, length);
+ sbp2_write_data (worker->handle, 0, node, &orb->login_resp, resp, length);
+
+ status = g_new0 (SBP2Status, 1);
+
+ sbp2_status_fill_pointer (status, pointer);
+
+ status->len = 1;
+ status->src = SBP2_STATUS_ORIGIN_NULL;
+ status->resp = SBP2_STATUS_RESP_REQUEST_COMPLETE;
+
+ sbp2_cpu_to_be32_data (status, 8);
+ sbp2_write_data (worker->handle, 0, node, &orb->status_FIFO, status, 8);
+
+ worker->unattached = FALSE;
+
+ return TRUE;
+}
+
+gboolean
+sbp2_worker_reconnect (SBP2Worker *worker,
+ nodeid_t node)
+{
+ g_return_val_if_fail (worker != NULL, FALSE);
+
+ worker->unattached = FALSE;
+
+ return TRUE;
+}
+
+static gint
+agent_reset (raw1394handle_t handle,
+ ARMReqResp *arm_req_resp,
+ guint requested_length,
+ gpointer pcontext,
+ guint8 request_type)
+{
+ SBP2Worker *worker = pcontext;
+
+ g_return_val_if_fail (worker != NULL, -1);
+
+ if (worker->unattached)
+ return 0;
+
+ worker->state = STATE_RESET;
+ worker->doorbell = 0;
+
+ return 0;
+}
+
+static gint
+orb_pointer (raw1394handle_t handle,
+ ARMReqResp *arm_req_resp,
+ guint requested_length,
+ gpointer pcontext,
+ guint8 request_type)
+{
+ ARMRequest *request;
+ SBP2Worker *worker = pcontext;
+ SBP2Pointer *pointer;
+
+ g_return_val_if_fail (worker != NULL, -1);
+
+ if (worker->state == STATE_DEAD)
+ return 0;
+
+ request = arm_req_resp->request;
+
+ worker->state = STATE_ACTIVE;
+ worker->doorbell = 0;
+
+ pointer = (SBP2Pointer *) request->buffer;
+ sbp2_be32_to_cpu_data (pointer, sizeof (*pointer));
+
+ fetch_orb (worker, request->source_nodeid, pointer);
+
+ return 0;
+}
+
+static gint
+doorbell (raw1394handle_t handle,
+ ARMReqResp *arm_req_resp,
+ guint requested_length,
+ gpointer pcontext,
+ guint8 request_type)
+{
+ ARMRequest *request;
+ SBP2Worker *worker = pcontext;
+
+ g_return_val_if_fail (worker != NULL, -1);
+
+ if (worker->state != STATE_SUSPENDED)
+ return 0;
+
+ request = arm_req_resp->request;
+
+ worker->state = STATE_ACTIVE;
+
+ fetch_orb (worker, request->source_nodeid, worker->pointer);
+
+ return 0;
+}
+
+
+static gint
+unsolicited_status_enable (raw1394handle_t handle,
+ ARMReqResp *arm_req_resp,
+ guint requested_length,
+ gpointer pcontext,
+ guint8 request_type)
+{
+ /* TODO */
+ return 0;
+}
+
+static void
+fetch_orb (SBP2Worker *worker,
+ nodeid_t node,
+ SBP2Pointer *pointer)
+{
+ ORBData *orb_data;
+ SBP2Tag *tag;
+
+ g_return_if_fail (worker != NULL);
+ g_return_if_fail (pointer != NULL);
+
+ orb_data = g_new0 (ORBData, 1);
+
+ orb_data->worker = worker;
+
+ orb_data->node = node;
+ memcpy (&orb_data->pointer, pointer, sizeof (orb_data->pointer));
+
+ tag = sbp2_tag_new (process_orb, free_orb_data, orb_data);
+
+ sbp2_read_data (worker->handle, 0, node, pointer,
+ &orb_data->orb, sizeof (orb_data->orb),
+ tag);
+}
+
+static gboolean
+process_orb (gpointer data)
+{
+ ORBData *orb_data = data;
+ SBP2Worker *worker;
+ nodeid_t node;
+ SBP2Pointer *pointer;
+ SBP2ScsiCommandORB *orb;
+ SBP2Status *status;
+ RBCBuffer *buffer;
+
+ g_return_val_if_fail (orb_data != NULL, FALSE);
+
+ worker = orb_data->worker;
+
+ node = orb_data->node;
+ pointer = &orb_data->pointer;
+ orb = &orb_data->orb;
+
+ sbp2_be32_to_cpu_data (orb, 20);
+
+ orb_data->chunk_size = 1 << (orb->max_payload + 2);
+
+ orb_data->status = status = g_new0 (SBP2Status, 1);
+
+ sbp2_status_fill_pointer (status, pointer);
+
+ status->len = 1;
+ status->resp = SBP2_STATUS_RESP_REQUEST_COMPLETE;
+
+ if (orb->req_fmt == 0x0)
+ {
+ if (orb->has_page_table)
+ {
+ if (orb->page_size == 0)
+ return fetch_page_table (orb_data);
+ else
+ status->sbp_status = SBP2_STATUS_REQUEST_PAGE_SIZE_NOT_SUPPORTED;
+ }
+ else
+ {
+ if (orb->data_size != 0)
+ {
+ if (!orb->direction)
+ return fetch_data (orb_data);
+ else
+ buffer = rbc_buffer_simple_new (orb->data_size);
+ }
+ else
+ buffer = rbc_buffer_empty_new ();
+
+ orb_data->buffer = buffer;
+
+ if (rbc_disk_command (worker->disk, orb->cdb, buffer, status->sense))
+ write_orb_data_buffer (orb_data);
+ else
+ status->len = 7;
+ }
+ }
+ else
+ status->sbp_status = SBP2_STATUS_REQUEST_DUMMY_ORB_COMPLETED;
+
+ complete_orb (orb_data);
+
+ return TRUE;
+}
+
+static gboolean
+fetch_data (gpointer data)
+{
+ ORBData *orb_data = data;
+ SBP2Worker *worker;
+ SBP2ScsiCommandORB *orb;
+ RBCBuffer *buffer;
+ gsize chunk_size;
+ SBP2Tag *tag;
+
+ g_return_val_if_fail (orb_data != NULL, FALSE);
+
+ worker = orb_data->worker;
+
+ orb = &orb_data->orb;
+
+ chunk_size = orb_data->chunk_size;
+
+ orb_data->buffer = buffer = rbc_buffer_simple_new (orb->data_size);
+
+ tag = sbp2_tag_new (process_data, free_orb_data, data);
+
+ sbp2_read_data (worker->handle, chunk_size, orb_data->node, &orb->data_desc,
+ buffer->data, buffer->length,
+ tag);
+
+ return FALSE;
+}
+
+static gboolean
+process_data (gpointer data)
+{
+ ORBData *orb_data = data;
+ SBP2Worker *worker;
+ SBP2ScsiCommandORB *orb;
+ RBCBuffer *buffer;
+ SBP2Status *status;
+
+ g_return_val_if_fail (orb_data != NULL, FALSE);
+ g_return_val_if_fail (orb_data->status != NULL, FALSE);
+
+ worker = orb_data->worker;
+
+ orb = &orb_data->orb;
+ status = orb_data->status;
+
+ buffer = orb_data->buffer;
+
+ if (!rbc_disk_command (worker->disk, orb->cdb, buffer, status->sense))
+ status->len = 7;
+
+ complete_orb (orb_data);
+
+ return TRUE;
+}
+
+static gboolean
+fetch_page_table (gpointer data)
+{
+ ORBData *orb_data = data;
+ SBP2Worker *worker;
+ SBP2ScsiCommandORB *orb;
+ gsize chunk_size;
+ gsize length;
+ RBCBuffer *buffer;
+ SBP2Tag *tag;
+
+ g_return_val_if_fail (orb_data != NULL, FALSE);
+
+ worker = orb_data->worker;
+
+ orb = &orb_data->orb;
+
+ chunk_size = orb_data->chunk_size;
+
+ length = sizeof (SBP2Page) * orb->data_size;
+
+ orb_data->buffer = buffer = rbc_buffer_simple_new (length);
+
+ tag = sbp2_tag_new (process_page_table, free_orb_data, data);
+
+ sbp2_read_data (worker->handle, chunk_size, orb_data->node, &orb->data_desc,
+ buffer->data, length,
+ tag);
+
+ return FALSE;
+}
+
+static gboolean
+process_page_table (gpointer data)
+{
+ ORBData *orb_data = data;
+ SBP2Worker *worker;
+ SBP2ScsiCommandORB *orb;
+ gsize data_size;
+ RBCBuffer *buffer;
+ SBP2Page *ext_page;
+ RBCPage *page;
+ SBP2Pointer *page_pointer;
+ gsize i;
+ SBP2Status *status;
+
+ g_return_val_if_fail (orb_data != NULL, TRUE);
+
+ worker = orb_data->worker;
+
+ orb = &orb_data->orb;
+ data_size = orb->data_size;
+
+ ext_page = orb_data->buffer->data;
+ sbp2_be32_to_cpu_data (ext_page, orb_data->buffer->length);
+
+ buffer = rbc_buffer_page_table_new (data_size);
+ page = buffer->data;
+
+ orb_data->page_pointers = page_pointer = g_new (SBP2Pointer, data_size);
+
+ for (i = data_size; i > 0; i--, page++, page_pointer++, ext_page++)
+ {
+ page->length = ext_page->segment_length;
+ page->data = g_malloc (page->length);
+
+ sbp2_pointer_from_page (page_pointer, ext_page);
+ }
+
+ rbc_buffer_destroy (orb_data->buffer);
+
+ orb_data->buffer = buffer;
+
+ if (orb->direction)
+ {
+ status = orb_data->status;
+
+ if (rbc_disk_command (worker->disk, orb->cdb, buffer, status->sense))
+ write_orb_data_buffer (orb_data);
+ else
+ status->len = 7;
+
+ complete_orb (orb_data);
+
+ return TRUE;
+ }
+
+ return fetch_page_table_data (orb_data);
+}
+
+static gboolean
+fetch_page_table_data (gpointer data)
+{
+ ORBData *orb_data = data;
+ SBP2Worker *worker;
+ raw1394handle_t handle;
+ nodeid_t node;
+ SBP2ScsiCommandORB *orb;
+ gsize chunk_size;
+ RBCBuffer *buffer;
+ RBCPage *page;
+ SBP2Pointer *page_pointer;
+ gsize i;
+ SBP2Tag *tag;
+
+ g_return_val_if_fail (orb_data != NULL, FALSE);
+
+ worker = orb_data->worker;
+ handle = worker->handle;
+
+ node = orb_data->node;
+ orb = &orb_data->orb;
+
+ chunk_size = orb_data->chunk_size;
+
+ buffer = orb_data->buffer;
+
+ page = buffer->data;
+ page_pointer = orb_data->page_pointers;
+
+ tag = sbp2_tag_new (process_data, free_orb_data, data);
+
+ for (i = buffer->length; i > 0; i--, page++, page_pointer++)
+ sbp2_read_data (handle, chunk_size, node, page_pointer,
+ page->data, page->length,
+ tag);
+
+ return FALSE;
+}
+
+static void
+complete_orb (ORBData *orb_data)
+{
+ SBP2Worker *worker;
+ nodeid_t node;
+ SBP2ScsiCommandORB *orb;
+ SBP2Status *status;
+ gsize length;
+
+ g_return_if_fail (orb_data != NULL);
+ g_return_if_fail (orb_data->status != NULL);
+
+ worker = orb_data->worker;
+
+ node = orb_data->node;
+ orb = &orb_data->orb;
+ status = orb_data->status;
+
+ length = (status->len + 1) * 4;
+
+ if (!sbp2_pointer_is_null_orb (&orb->next_ORB))
+ {
+ status->src = SBP2_STATUS_ORIGIN_NON_NULL;
+ fetch_orb (worker, node, &orb->next_ORB);
+ }
+ else
+ status->src = SBP2_STATUS_ORIGIN_NULL;
+
+ sbp2_cpu_to_be32_data (status, length);
+ sbp2_write_data (worker->handle, 0, node, &worker->status_FIFO,
+ status, length);
+
+ orb_data->status = NULL;
+}
+
+static void
+write_orb_data_buffer (ORBData *orb_data)
+{
+ SBP2Worker *worker;
+ raw1394handle_t handle;
+ nodeid_t node;
+ SBP2ScsiCommandORB *orb;
+ gsize chunk_size;
+ RBCBuffer *buffer;
+ SBP2Pointer *page_pointer;
+ RBCPage *page;
+ gsize i;
+
+ g_return_if_fail (orb_data != NULL);
+ g_return_if_fail (orb_data->buffer != NULL);
+
+ worker = orb_data->worker;
+ handle = worker->handle;
+
+ node = orb_data->node;
+ orb = &orb_data->orb;
+
+ chunk_size = orb_data->chunk_size;
+
+ buffer = orb_data->buffer;
+ page_pointer = orb_data->page_pointers;
+
+ switch (buffer->type)
+ {
+ case RBC_BUFFER_PAGE_TABLE:
+ page = buffer->data;
+
+ for (i = buffer->length; i > 0; i--, page++, page_pointer++)
+ {
+ sbp2_write_data (handle, chunk_size, node, page_pointer,
+ page->data, page->length);
+
+ page->data = NULL;
+ }
+
+ break;
+
+ case RBC_BUFFER_SIMPLE:
+ sbp2_write_data (handle, chunk_size, node, &orb->data_desc,
+ buffer->data, buffer->length);
+
+ buffer->data = NULL;
+ break;
+
+ case RBC_BUFFER_EMPTY:
+ /* do nothing */
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+static void
+free_orb_data (gpointer data)
+{
+ ORBData *orb_data = data;
+
+ g_return_if_fail (orb_data != NULL);
+
+ if (orb_data->status)
+ g_free (orb_data->status);
+
+ if (orb_data->buffer)
+ rbc_buffer_destroy (orb_data->buffer);
+
+ if (orb_data->page_pointers)
+ g_free (orb_data->page_pointers);
+
+ g_free (orb_data);
+}
+
+static gint
+bus_reset_handler (raw1394handle_t handle,
+ guint generation)
+{
+ SBP2Worker *worker;
+
+ g_return_val_if_fail (handle != NULL, -1);
+
+ raw1394_update_generation (handle, generation);
+
+ worker = raw1394_get_userdata (handle);
+
+ g_return_val_if_fail (worker != NULL, -1);
+
+ worker->state = STATE_RESET;
+
+ worker->unattached = TRUE;
+
+ return 0;
+}
Added: trunk/libsbp2/sbp2worker.h
==============================================================================
--- trunk/libsbp2/sbp2worker.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/libsbp2/sbp2worker.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,57 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __SBP2_WORKER_H__
+#define __SBP2_WORKER_H__
+
+
+#include <glib.h>
+
+#include <libraw1394/raw1394.h>
+
+#include <librbc/rbcdisk.h>
+
+#include <libsbp2/sbp2pointer.h>
+#include <libsbp2/sbp2login.h>
+
+
+typedef struct _SBP2Worker SBP2Worker;
+
+
+SBP2Worker *sbp2_worker_new (RBCDisk *disk,
+ GMainContext *context,
+ gint port,
+ guint login_ID);
+
+void sbp2_worker_destroy (SBP2Worker *worker);
+
+gboolean sbp2_worker_login (SBP2Worker *worker,
+ nodeid_t node,
+ SBP2Pointer *pointer,
+ SBP2LoginORB *orb);
+
+gboolean sbp2_worker_reconnect (SBP2Worker *worker,
+ nodeid_t node);
+
+
+#endif /* __SBP2_WORKER_H__ */
Added: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/src/Makefile.am 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,35 @@
+bin_PROGRAMS = endpoint
+
+AM_CPPFLAGS = \
+ -DSYSCONFDIR=\""$(sysconfdir)"\"
+
+INCLUDES = \
+ -I$(top_srcdir) \
+ $(GLIB_CFLAGS) \
+ $(LIBRAW1394_CPPFLAGS) \
+ -I$(includedir)
+
+endpoint_SOURCES = \
+ app.c \
+ app.h \
+ cleanup.c \
+ cleanup.h \
+ main.c \
+ manager.c \
+ manager.h \
+ process.c \
+ process.h \
+ util.c \
+ util.h \
+ wire.c \
+ wire.h \
+ worker.c \
+ worker.h
+
+endpoint_LDADD = \
+ $(top_builddir)/libsbp2/libsbp2.a \
+ $(top_builddir)/librbc/librbc.a \
+ $(top_builddir)/libjconfig/libjconfig.a \
+ $(GLIB_LIBS) \
+ $(LIBRAW1394_LIBS)
+
Added: trunk/src/app.c
==============================================================================
--- trunk/src/app.c 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/src/app.c 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,354 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#include <stdlib.h>
+
+#include <glib.h>
+
+#include <libjconfig/jiterator.h>
+#include <libjconfig/jconfig.h>
+
+#include <librbc/rbcdisk.h>
+
+#include "app.h"
+
+
+#define MAX_LOGINS_MIN 1
+#define MAX_LOGINS_MAX 64
+#define MAX_LOGINS_DEFAULT 12
+
+#define MAX_LOGINS_PER_PORT_MIN 1
+#define MAX_LOGINS_PER_PORT_MAX 64
+#define MAX_LOGINS_PER_PORT_DEFAULT 4
+
+#define DISK_NUMBER_MIN 0
+#define DISK_NUMBER_MAX 15
+
+#define ORDER_MIN 0
+#define ORDER_MAX 1048576
+
+
+static gboolean load_global_options (EndpointApp *app,
+ JConfig *cf);
+static gboolean load_disks (EndpointApp *app,
+ JConfig *cf);
+static gboolean load_partitions (EndpointApp *app,
+ JConfig *cf);
+
+static gboolean get_int_attribute (JConfigStanza *cfs,
+ const gchar *name,
+ gint *value,
+ gint min,
+ gint max);
+static gboolean get_boolean_attribute (JConfigStanza *cfs,
+ const gchar *name,
+ gboolean *value);
+
+
+EndpointApp *
+endpoint_app_new (const gchar *configfile)
+{
+ EndpointApp *app;
+ JConfig *cf;
+
+ g_return_val_if_fail (configfile != NULL, NULL);
+
+ cf = j_config_parse_file (configfile);
+
+ if (!cf)
+ return NULL;
+
+ app = g_new0 (EndpointApp, 1);
+
+ app->max_logins = MAX_LOGINS_DEFAULT;
+ app->max_logins_per_port = MAX_LOGINS_PER_PORT_DEFAULT;
+ app->honor_exclusive = FALSE;
+
+ app->disks = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify) rbc_disk_destroy);
+
+ if (!load_global_options (app, cf) || !load_disks (app, cf))
+ {
+ endpoint_app_destroy (app);
+ app = NULL;
+ }
+
+ j_config_free (cf);
+
+ /* TODO: multiple LUN */
+ {
+ RBCDisk *disk;
+
+ disk = g_hash_table_lookup (app->disks, GINT_TO_POINTER (0));
+
+ if (disk == NULL || rbc_disk_get_type (disk) == RBC_DISK_VIRTUAL)
+ {
+ endpoint_app_destroy (app);
+ app = NULL;
+ }
+ }
+
+ return app;
+}
+
+void
+endpoint_app_destroy (EndpointApp *app)
+{
+ g_return_if_fail (app != NULL);
+
+ g_hash_table_destroy (app->disks);
+ g_free (app);
+
+ return;
+}
+
+#define CHECK(cond) G_STMT_START { \
+ if (!(cond)) \
+ { \
+ ret = FALSE; \
+ break; \
+ } \
+} G_STMT_END
+
+static gboolean
+load_global_options (EndpointApp *app,
+ JConfig *cf)
+{
+ JIterator *iter;
+ JConfigStanza *cfs;
+ gboolean ret = TRUE;
+
+ g_return_val_if_fail (app != NULL, FALSE);
+ g_return_val_if_fail (cf != NULL, FALSE);
+
+ iter = j_config_get_stanzas (cf, "global", NULL, 0);
+
+ /* FIXME: hmm, allow only one global stanza? */
+ while (j_iterator_has_more (iter))
+ {
+ cfs = j_iterator_get_next (iter);
+
+ CHECK (get_int_attribute (cfs, "max_logins",
+ &app->max_logins,
+ MAX_LOGINS_MIN,
+ MAX_LOGINS_MAX));
+ CHECK (get_int_attribute (cfs, "max_logins_per_port",
+ &app->max_logins_per_port,
+ MAX_LOGINS_PER_PORT_MIN,
+ MAX_LOGINS_PER_PORT_MAX));
+
+ CHECK (get_boolean_attribute (cfs, "honor_exclusive_login",
+ &app->honor_exclusive));
+ }
+
+ j_iterator_free (iter);
+
+ if (ret && app->max_logins < app->max_logins_per_port)
+ {
+ /* ERROR MESSAGE */
+ return FALSE;
+ }
+
+ return ret;
+}
+
+static gboolean
+load_disks (EndpointApp *app,
+ JConfig *cf)
+{
+ JIterator *iter;
+ JConfigStanza *cfs;
+ gchar *type_string;
+ RBCDiskType type;
+ gint number;
+ gchar *filename;
+ RBCDisk *disk = NULL;
+ gboolean ret = TRUE;
+
+ iter = j_config_get_stanzas (cf, "disk", NULL, 0);
+
+ while (j_iterator_has_more (iter))
+ {
+ cfs = j_iterator_get_next (iter);
+
+ disk = NULL;
+
+ CHECK (type_string = j_config_get_attribute (cfs, "type"));
+
+ if (g_ascii_strcasecmp (type_string, "physical") == 0)
+ {
+ type = RBC_DISK_PHYSICAL;
+ }
+ else if (g_ascii_strcasecmp (type_string, "virtual") == 0)
+ {
+ type = RBC_DISK_VIRTUAL;
+ }
+ else
+ {
+ ret = FALSE;
+ break;
+ }
+
+ CHECK (get_int_attribute (cfs, "number",
+ &number,
+ DISK_NUMBER_MIN,
+ DISK_NUMBER_MAX));
+
+ disk = rbc_disk_new (type);
+
+ if (type == RBC_DISK_PHYSICAL)
+ {
+ CHECK (filename = j_config_get_attribute (cfs, "filename"));
+ CHECK (rbc_disk_set_filename (disk, filename));
+ }
+
+ /* FIXME: hmm, check for dupes? */
+ g_hash_table_insert (app->disks, GINT_TO_POINTER (number), disk);
+ }
+
+ if (!ret)
+ {
+ if (disk)
+ rbc_disk_destroy (disk);
+
+ return FALSE;
+ }
+ else
+ return load_partitions (app, cf);
+}
+
+static gboolean
+load_partitions (EndpointApp *app,
+ JConfig *cf)
+{
+ JIterator *iter;
+ JConfigStanza *cfs;
+ gint number;
+ gchar *filename;
+ gint order;
+ RBCDisk *disk;
+ gboolean ret = TRUE;
+
+ g_return_val_if_fail (app != NULL, FALSE);
+ g_return_val_if_fail (cf != NULL, FALSE);
+
+ iter = j_config_get_stanzas (cf, "partition", NULL, 0);
+
+ while (j_iterator_has_more (iter))
+ {
+ cfs = j_iterator_get_next (iter);
+
+ CHECK (get_int_attribute (cfs, "disk",
+ &number,
+ DISK_NUMBER_MIN,
+ DISK_NUMBER_MAX));
+
+ CHECK (filename = j_config_get_attribute (cfs, "filename"));
+
+ CHECK (order = get_int_attribute (cfs, "order",
+ &order,
+ ORDER_MIN,
+ ORDER_MAX));
+
+ CHECK (disk = g_hash_table_lookup (app->disks, GINT_TO_POINTER (number)));
+
+ CHECK (rbc_disk_get_type (disk) == RBC_DISK_VIRTUAL);
+
+ rbc_disk_add_partition (disk, filename, order);
+ }
+
+ j_iterator_free (iter);
+
+ return ret;
+}
+
+static gboolean
+get_int_attribute (JConfigStanza *cfs,
+ const gchar *name,
+ gint *value,
+ gint min,
+ gint max)
+{
+ gchar *buf, *end;
+ glong number;
+ gboolean ret = TRUE;
+
+ g_return_val_if_fail (cfs != NULL, FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ buf = j_config_get_attribute (cfs, name);
+
+ if (buf)
+ {
+ number = strtol (buf, &end, 0);
+
+ if (*buf && !*end && number >= min && number <= max)
+ *value = number;
+ else
+ ret = FALSE;
+ }
+
+ g_free (buf);
+
+ return ret;
+}
+
+static gboolean
+get_boolean_attribute (JConfigStanza *cfs,
+ const gchar *name,
+ gboolean *value)
+{
+ gchar *buf;
+ gboolean ret = TRUE;
+
+ g_return_val_if_fail (cfs != NULL, FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ buf = j_config_get_attribute (cfs, name);
+
+ if (buf)
+ {
+ if ((g_ascii_strcasecmp (buf, "on") == 0) ||
+ (g_ascii_strcasecmp (buf, "true") == 0) ||
+ (g_ascii_strcasecmp (buf, "yes") == 0) ||
+ (g_ascii_strcasecmp (buf, "1") == 0))
+ {
+ *value = TRUE;
+ }
+ else if ((g_ascii_strcasecmp (buf, "off") == 0) ||
+ (g_ascii_strcasecmp (buf, "false") == 0) ||
+ (g_ascii_strcasecmp (buf, "no") == 0) ||
+ (g_ascii_strcasecmp (buf, "0") == 0))
+ {
+ *value = FALSE;
+ }
+ else
+ ret = FALSE;
+ }
+
+ g_free (buf);
+
+ return ret;
+}
Added: trunk/src/app.h
==============================================================================
--- trunk/src/app.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/src/app.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,59 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __APP_H__
+#define __APP_H__
+
+
+#include <glib.h>
+
+
+typedef struct _EndpointApp EndpointApp;
+
+struct _EndpointApp
+{
+ GMainContext *context;
+ GMainLoop *loop;
+
+ gchar *ps_name;
+ gint ps_len;
+
+ gint max_logins;
+ gint max_logins_per_port;
+ gboolean honor_exclusive;
+
+ GHashTable *disks;
+
+ gpointer cleanup;
+ gpointer wire_funcs;
+
+ gpointer user_data;
+};
+
+
+EndpointApp *endpoint_app_new (const gchar *configfile);
+
+void endpoint_app_destroy (EndpointApp *app);
+
+
+#endif /* __APP_H__ */
Added: trunk/src/cleanup.c
==============================================================================
--- trunk/src/cleanup.c 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/src/cleanup.c 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,131 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#include <unistd.h>
+#include <signal.h>
+
+#include <glib.h>
+
+#include "app.h"
+#include "cleanup.h"
+#include "util.h"
+
+
+static gboolean do_cleanup (GIOChannel *channel,
+ GIOCondition condition,
+ EndpointApp *app);
+
+static void trigger_cleanup (gint signum);
+
+
+static gint cleanup_signum = SIGTERM;
+static gint cleanup_fd = -1;
+
+
+gboolean
+cleanup_register (EndpointApp *app,
+ CleanupFunc cleanup)
+{
+ gint cpipe[2];
+ GIOChannel *channel;
+
+ g_return_val_if_fail (app != NULL, FALSE);
+ g_return_val_if_fail (cleanup != NULL, FALSE);
+
+ cleanup_unregister (app);
+
+ if (pipe (cpipe) < 0)
+ return FALSE;
+
+ app->cleanup = cleanup;
+
+ cleanup_fd = cpipe[1];
+
+ channel = util_io_channel_new (cpipe[0]);
+
+ util_io_add_watch (app->context, channel,
+ G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) do_cleanup, app);
+
+ signal (SIGINT, trigger_cleanup);
+ signal (SIGQUIT, trigger_cleanup);
+ signal (SIGABRT, trigger_cleanup);
+ signal (SIGTERM, trigger_cleanup);
+
+ return TRUE;
+}
+
+void
+cleanup_unregister (EndpointApp *app)
+{
+ g_return_if_fail (app != NULL);
+
+ if (app->cleanup)
+ {
+ signal (SIGINT, SIG_DFL);
+ signal (SIGQUIT, SIG_DFL);
+ signal (SIGABRT, SIG_DFL);
+ signal (SIGTERM, SIG_DFL);
+
+ app->cleanup = NULL;
+
+ g_return_if_fail (cleanup_fd > 0);
+
+ close (cleanup_fd);
+ cleanup_fd = -1;
+ }
+}
+
+static gboolean
+do_cleanup (GIOChannel *channel,
+ GIOCondition condition,
+ EndpointApp *app)
+{
+ CleanupFunc cleanup;
+ gint signum;
+
+ g_return_val_if_fail (channel != NULL, FALSE);
+ g_return_val_if_fail (app != NULL, FALSE);
+ g_return_val_if_fail (app->cleanup != NULL, FALSE);
+
+ signum = cleanup_signum;
+
+ signal (signum, SIG_IGN);
+
+ cleanup = app->cleanup;
+ cleanup (app, signum);
+
+ app->context = NULL;
+ g_main_loop_quit (app->loop);
+
+ signal (signum, SIG_DFL);
+
+ return FALSE;
+}
+
+static void
+trigger_cleanup (gint signum)
+{
+ cleanup_signum = signum;
+ write (cleanup_fd, "C", 1);
+}
Added: trunk/src/cleanup.h
==============================================================================
--- trunk/src/cleanup.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/src/cleanup.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,42 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __CLEANUP_H__
+#define __CLEANUP_H__
+
+
+#include <glib.h>
+
+#include "app.h"
+
+
+typedef void (*CleanupFunc) (EndpointApp *app,
+ gint signum);
+
+
+gboolean cleanup_register (EndpointApp *app,
+ CleanupFunc cleanup);
+void cleanup_unregister (EndpointApp *app);
+
+
+#endif /* __CLEANUP_H__ */
Added: trunk/src/main.c
==============================================================================
--- trunk/src/main.c 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/src/main.c 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,441 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <glib.h>
+
+#include "app.h"
+#include "cleanup.h"
+#include "manager.h"
+#include "process.h"
+#include "util.h"
+#include "wire.h"
+#include "worker.h"
+
+
+#define CONFIG_FILE SYSCONFDIR "/endpoint.conf"
+
+#define MASTER_NAME "endpoint"
+#define MANAGER_NAME "endptmgr"
+#define WORKER_NAME "endptio"
+
+
+/* #define DEBUG_MANAGER */
+/* #define DEBUG_WORKER */
+
+
+typedef struct _ProcessInfo ProcessInfo;
+
+struct _ProcessInfo
+{
+ Process *manager;
+ GHashTable *workers;
+};
+
+
+static gboolean start_manager (EndpointApp *app);
+
+static gboolean login_worker (EndpointApp *app,
+ WireLogin *message);
+static gboolean reconnect_worker (EndpointApp *app,
+ WireReconnect *message);
+static gboolean logout_worker (EndpointApp *app,
+ WireLogout *message);
+
+static gboolean worker_active (EndpointApp *app,
+ WireWorkerActive *message);
+
+static void manager_reap (Process *process,
+ gint status);
+static void worker_reap (Process *process,
+ gint status);
+
+static void kill_all_processes (EndpointApp *app,
+ gint signum);
+
+static void set_ps_name (EndpointApp *app,
+ const gchar *name);
+
+
+static WireMsgFuncs wire_funcs = {
+ .login = login_worker,
+ .reconnect = reconnect_worker,
+ .logout = logout_worker,
+ .worker_active = worker_active
+};
+
+
+#ifdef DEBUG_MANAGER
+#define debug_manager() debug_process ()
+#else
+#define debug_manager() G_STMT_START{ (void)0; }G_STMT_END
+#endif
+
+#ifdef DEBUG_WORKER
+#define debug_worker() debug_process ()
+#else
+#define debug_worker() G_STMT_START{ (void)0; }G_STMT_END
+#endif
+
+
+static inline void
+debug_process (void)
+{
+ GLogLevelFlags fatal_mask;
+
+ fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
+ fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
+ g_log_set_always_fatal (fatal_mask);
+
+ raise (SIGSTOP);
+}
+
+
+int
+main (int argc,
+ char *argv[])
+{
+ EndpointApp *app;
+ gchar *configfile = CONFIG_FILE;
+ ProcessInfo *pinfo;
+
+ if (argc > 1)
+ configfile = argv[1];
+
+ app = endpoint_app_new (configfile);
+
+ if (!app)
+ {
+ /* ERROR MESSAGE */
+ exit (1);
+ }
+
+ app->ps_name = argv[0];
+ app->ps_len = strlen(argv[0]);
+
+ if (app->ps_len < strlen (MASTER_NAME))
+ {
+ /* ERROR MESSAGE */
+ exit (1);
+ }
+
+ set_ps_name (app, MASTER_NAME);
+
+ app->wire_funcs = &wire_funcs;
+
+ if (!wire_init ())
+ {
+ /* ERROR MESSAGE */
+ exit (1);
+ }
+
+ pinfo = g_new (ProcessInfo, 1);
+
+ pinfo->manager = NULL;
+ pinfo->workers = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL, g_free);
+
+ app->user_data = pinfo;
+
+ app->context = g_main_context_new ();
+
+ setpgid (0, 0);
+
+#if 0
+ if (!cleanup_register (app, kill_all_processes))
+ {
+ /* ERROR MESSAGE */
+ exit (1);
+ }
+#endif
+
+ signal (SIGPIPE, SIG_IGN);
+
+ util_run_first_add (app->context, (GSourceFunc) start_manager, app);
+
+ while (app->context)
+ {
+ app->loop = g_main_loop_new (app->context, TRUE);
+ g_main_context_unref (app->context);
+
+ g_main_loop_run (app->loop);
+ g_main_loop_unref (app->loop);
+
+ if (pinfo)
+ {
+ g_hash_table_destroy (pinfo->workers);
+ g_free (pinfo->manager);
+
+ g_free (pinfo);
+ pinfo = NULL;
+ }
+ }
+
+ while (wait (NULL) > 0);
+
+ return 0;
+}
+
+static gboolean
+start_manager (EndpointApp *app)
+{
+ Process *process;
+
+ g_return_val_if_fail (app != NULL, FALSE);
+ g_return_val_if_fail (app->user_data != NULL, FALSE);
+
+ process = process_start (app, manager_reap);
+
+ if (!process)
+ {
+ /* ERROR MESSAGE */
+ exit (1);
+ }
+
+ if (process->pid == 0)
+ {
+ set_ps_name (app, MANAGER_NAME);
+
+ debug_manager ();
+
+ manager_process (app, process);
+ g_free (process);
+ }
+ else
+ {
+ ProcessInfo *pinfo;
+
+ pinfo = app->user_data;
+ pinfo->manager = process;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+login_worker (EndpointApp *app,
+ WireLogin *message)
+{
+ Process *process;
+ ProcessInfo *pinfo;
+ gpointer ret_message;
+
+ g_return_val_if_fail (app != NULL, FALSE);
+ g_return_val_if_fail (app->user_data != NULL, FALSE);
+ g_return_val_if_fail (message != NULL, FALSE);
+
+ pinfo = app->user_data;
+
+ process = process_start (app, worker_reap);
+
+ if (!process)
+ {
+ ret_message = wire_message_worker_died (message->login_ID);
+ wire_message_send (pinfo->manager->writer, ret_message, app);
+
+ return TRUE;
+ }
+
+ if (process->pid == 0)
+ {
+ set_ps_name (app, WORKER_NAME);
+
+ debug_worker ();
+
+ worker_process (app, process, message);
+ g_free (process);
+ }
+ else
+ {
+ process->login_ID = message->login_ID;
+
+ g_hash_table_insert (pinfo->workers,
+ GUINT_TO_POINTER (message->login_ID), process);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+reconnect_worker (EndpointApp *app,
+ WireReconnect *message)
+{
+ Process *process;
+ ProcessInfo *pinfo;
+
+ g_return_val_if_fail (app != NULL, FALSE);
+ g_return_val_if_fail (app->user_data != NULL, FALSE);
+ g_return_val_if_fail (message != NULL, FALSE);
+
+ pinfo = app->user_data;
+
+ process = g_hash_table_lookup (pinfo->workers,
+ GUINT_TO_POINTER (message->login_ID));
+
+ if (process)
+ {
+ WireReconnect *copy;
+
+ copy = wire_message_copy (message);
+ wire_message_send (process->writer, copy, app);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+logout_worker (EndpointApp *app,
+ WireLogout *message)
+{
+ Process *process;
+ ProcessInfo *pinfo;
+
+ g_return_val_if_fail (app != NULL, FALSE);
+ g_return_val_if_fail (app->user_data != NULL, FALSE);
+ g_return_val_if_fail (message != NULL, FALSE);
+
+ pinfo = app->user_data;
+
+ process = g_hash_table_lookup (pinfo->workers,
+ GUINT_TO_POINTER (message->login_ID));
+
+ if (process)
+ kill (process->pid, SIGTERM);
+
+ return TRUE;
+}
+
+static gboolean
+worker_active (EndpointApp *app,
+ WireWorkerActive *message)
+{
+ ProcessInfo *pinfo;
+ WireWorkerActive *copy;
+
+ g_return_val_if_fail (app != NULL, FALSE);
+ g_return_val_if_fail (app->user_data != NULL, FALSE);
+ g_return_val_if_fail (message != NULL, FALSE);
+
+ pinfo = app->user_data;
+
+ copy = wire_message_copy (message);
+ wire_message_send (pinfo->manager->writer, copy, app);
+
+ return TRUE;
+}
+
+static void
+manager_reap (Process *process,
+ gint status)
+{
+ ProcessInfo *pinfo;
+
+ g_return_if_fail (process != NULL);
+ g_return_if_fail (process->app != NULL);
+ g_return_if_fail (process->app->user_data != NULL);
+
+ pinfo = process->app->user_data;
+
+ if (WIFEXITED (status))
+ {
+ gint exit_status = WEXITSTATUS (status);
+
+ if (exit_status != 0)
+ {
+ /* ERROR MESSAGE */
+ }
+
+ exit (exit_status);
+ }
+ else if (WIFSIGNALED (status))
+ {
+ gint signum = WTERMSIG (status);
+
+ g_printerr ("Manager exited (%s)\n", g_strsignal (signum));
+ exit (5);
+ }
+ else
+ exit (6);
+}
+
+static void
+worker_reap (Process *process,
+ gint status)
+{
+ ProcessInfo *pinfo;
+ gpointer message;
+
+ g_return_if_fail (process != NULL);
+ g_return_if_fail (process->app != NULL);
+ g_return_if_fail (process->app->user_data != NULL);
+
+ pinfo = process->app->user_data;
+
+ message = wire_message_worker_died (process->login_ID);
+ wire_message_send (pinfo->manager->writer, message, process->app);
+
+ g_hash_table_steal (pinfo->workers, GUINT_TO_POINTER (process->login_ID));
+
+ if (WIFEXITED (status))
+ {
+ g_printerr ("Worker exited: %d\n", WEXITSTATUS (status));
+ }
+ else if (WIFSIGNALED (status))
+ {
+ gint signum = WTERMSIG (status);
+
+ g_printerr ("Worker exited (%s)\n", g_strsignal (signum));
+ }
+}
+
+static void
+kill_all_processes (EndpointApp *app,
+ gint signum)
+{
+ kill (0, signum);
+
+ app->context = NULL;
+ g_main_loop_quit (app->loop);
+}
+
+static void
+set_ps_name (EndpointApp *app,
+ const gchar *name)
+{
+ gint len;
+
+ g_return_if_fail (app != NULL);
+ g_return_if_fail (name != NULL);
+
+ len = strlen (name);
+
+ strcpy (app->ps_name, name);
+ memset (app->ps_name + len, 0, app->ps_len - len);
+}
Added: trunk/src/manager.c
==============================================================================
--- trunk/src/manager.c 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/src/manager.c 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,538 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <libsbp2/sbp2byteswap.h>
+#include <libsbp2/sbp2constants.h>
+#include <libsbp2/sbp2main.h>
+#include <libsbp2/sbp2manager.h>
+#include <libsbp2/sbp2raw1394.h>
+
+#include "app.h"
+#include "cleanup.h"
+#include "manager.h"
+#include "util.h"
+#include "wire.h"
+
+
+typedef enum
+{
+ LOGIN_EMPTY,
+ LOGIN_PENDING,
+ LOGIN_ACTIVE,
+ LOGIN_RECONNECT,
+ LOGIN_DEAD
+} LoginStatus;
+
+
+typedef struct _ManagerState ManagerState;
+typedef struct _Port Port;
+typedef struct _Login Login;
+
+struct _ManagerState
+{
+ EndpointApp *app;
+
+ gint num_ports;
+ Port *ports;
+
+ gint num_logins;
+ Login *logins;
+
+ gboolean exclusive;
+
+ GIOChannel *reader;
+ GIOChannel *writer;
+};
+
+struct _Port
+{
+ ManagerState *state;
+
+ gint number;
+
+ SBP2Manager *manager;
+
+ gint num_logins;
+};
+
+struct _Login
+{
+ LoginStatus status;
+
+ guint login_ID;
+ Port *port;
+
+ guint timeout;
+
+ guint64 EUI_64;
+
+ nodeid_t node;
+ SBP2Pointer status_FIFO;
+
+ guint8 sbp2_status[8];
+};
+
+
+static gboolean query_logins (SBP2ManagerAction *action,
+ SBP2QueryLoginsORB *orb,
+ SBP2QueryLoginsResponse *resp);
+static gboolean login (SBP2ManagerAction *action,
+ SBP2LoginORB *orb,
+ SBP2LoginResponse *resp);
+static gboolean reconnect (SBP2ManagerAction *action,
+ SBP2ReconnectORB *orb);
+static gboolean logout (SBP2ManagerAction *action,
+ SBP2LogoutORB *orb);
+
+static gboolean worker_active (EndpointApp *app,
+ WireWorkerActive *message);
+static gboolean worker_died (EndpointApp *app,
+ WireWorkerDied *message);
+
+static gboolean find_free_login_ID (ManagerState *state,
+ guint *login_ID);
+static gboolean expire_login (Login *login);
+
+static void bus_reset (SBP2Manager *manager,
+ gpointer user_data);
+
+
+static SBP2ManagerFuncs manager_funcs = {
+ .bus_reset = bus_reset,
+
+ .login = login,
+ .query_logins = query_logins,
+ .reconnect = reconnect,
+ .logout = logout
+};
+
+static WireMsgFuncs wire_funcs = {
+ .worker_active = worker_active,
+ .worker_died = worker_died
+};
+
+
+void
+manager_process (EndpointApp *app,
+ Process *process)
+{
+ ManagerState *state;
+ gint num_ports, i;
+ Port *port;
+
+ g_return_if_fail (app != NULL);
+ g_return_if_fail (process != NULL);
+
+ num_ports = sbp2_raw1394_get_num_ports ();
+
+ if (num_ports < 1)
+ exit (1);
+
+ app->wire_funcs = &wire_funcs;
+
+ state = g_new (ManagerState, 1);
+
+ state->app = app;
+
+ state->num_ports = num_ports;
+ state->ports = g_new0 (Port, num_ports);
+
+ state->num_logins = 0;
+ state->logins = g_new0 (Login, app->max_logins);
+
+ state->reader = process->reader;
+ state->writer = process->writer;
+
+ app->user_data = state;
+
+ for (i = 0; i < num_ports; i++)
+ {
+ port = &state->ports[i];
+
+ port->state = state;
+
+ port->number = i;
+
+ port->manager = sbp2_manager_new (&manager_funcs, app->context, i, port);
+
+ if (!port->manager)
+ exit (2);
+
+ port->num_logins = 0;
+ }
+}
+
+static gboolean
+query_logins (SBP2ManagerAction *action,
+ SBP2QueryLoginsORB *orb,
+ SBP2QueryLoginsResponse *resp)
+{
+ Port *port;
+
+ g_return_val_if_fail (action != NULL, FALSE);
+ g_return_val_if_fail (action->user_data != NULL, FALSE);
+ g_return_val_if_fail (orb != NULL, FALSE);
+ g_return_val_if_fail (resp != NULL, FALSE);
+
+ port = action->user_data;
+
+ resp->length = 4 + 12 * port->num_logins;
+ resp->max_logins = port->state->app->max_logins_per_port;
+
+ return TRUE;
+}
+
+static gboolean
+login (SBP2ManagerAction *action,
+ SBP2LoginORB *orb,
+ SBP2LoginResponse *resp)
+{
+ Port *port;
+ ManagerState *state;
+ EndpointApp *app;
+ guint login_ID;
+ Login *login;
+ gpointer message;
+
+ g_return_val_if_fail (action != NULL, FALSE);
+ g_return_val_if_fail (action->user_data != NULL, FALSE);
+ g_return_val_if_fail (orb != NULL, FALSE);
+ g_return_val_if_fail (resp != NULL, FALSE);
+
+ port = action->user_data;
+
+ state = port->state;
+ app = state->app;
+
+ if (app->honor_exclusive && state->num_logins > 0 &&
+ (orb->exclusive || state->exclusive))
+ {
+ action->status->sbp_status = SBP2_STATUS_REQUEST_ACCESS_DENIED;
+ return TRUE;
+ }
+
+ if (port->num_logins == app->max_logins_per_port)
+ {
+ action->status->sbp_status = SBP2_STATUS_REQUEST_ACCESS_DENIED;
+ return TRUE;
+ }
+
+ if (!find_free_login_ID (state, &login_ID))
+ {
+ action->status->sbp_status = SBP2_STATUS_REQUEST_RESOURCES_UNAVAILABLE;
+ return TRUE;
+ }
+
+ orb->lun = 0; /* TODO: multiple LUN */
+
+ if (!g_hash_table_lookup (app->disks, GINT_TO_POINTER (orb->lun)))
+ {
+ action->status->sbp_status = SBP2_STATUS_REQUEST_LU_NOT_SUPPORTED;
+ return TRUE;
+ }
+
+ if (app->honor_exclusive)
+ state->exclusive = orb->exclusive;
+
+ login = &state->logins[login_ID];
+
+ login->status = LOGIN_PENDING;
+
+ login->login_ID = login_ID;
+ login->port = port;
+
+ login->node = action->node;
+ memcpy (&login->status_FIFO, &orb->status_FIFO, sizeof (login->status_FIFO));
+
+ memcpy (&login->sbp2_status, action->status, sizeof (login->sbp2_status));
+
+ port->num_logins++;
+ state->num_logins++;
+
+ message = wire_message_login (login_ID, port->number,
+ action->node, action->pointer, orb);
+ wire_message_send (state->writer, message, app);
+
+ return FALSE;
+}
+
+static gboolean
+reconnect (SBP2ManagerAction *action,
+ SBP2ReconnectORB *orb)
+{
+ Port *port;
+ ManagerState *state;
+ EndpointApp *app;
+ guint login_ID;
+ Login *login;
+
+ g_return_val_if_fail (action != NULL, FALSE);
+ g_return_val_if_fail (action->user_data != NULL, FALSE);
+ g_return_val_if_fail (orb != NULL, FALSE);
+
+ port = action->user_data;
+
+ state = port->state;
+ app = state->app;
+
+ login_ID = orb->login_ID;
+
+ if (login_ID >= app->max_logins)
+ {
+ action->status->sbp_status = SBP2_STATUS_REQUEST_LOGIN_ID_NOT_RECOGNIZED;
+ return TRUE;
+ }
+
+ login = &state->logins[login_ID];
+
+ if (login->status != LOGIN_RECONNECT)
+ {
+ action->status->sbp_status = SBP2_STATUS_REQUEST_LOGIN_ID_NOT_RECOGNIZED;
+ return TRUE;
+ }
+
+ if (login->timeout != 0)
+ {
+ util_source_remove (app->context, login->timeout);
+ login->timeout = 0;
+ }
+
+ login->status = LOGIN_ACTIVE;
+
+ return TRUE;
+}
+
+static gboolean
+logout (SBP2ManagerAction *action,
+ SBP2LogoutORB *orb)
+{
+ Port *port;
+ ManagerState *state;
+ EndpointApp *app;
+ guint login_ID;
+ Login *login;
+
+ g_return_val_if_fail (action != NULL, FALSE);
+ g_return_val_if_fail (action->user_data != NULL, FALSE);
+ g_return_val_if_fail (orb != NULL, FALSE);
+
+ port = action->user_data;
+
+ state = port->state;
+ app = state->app;
+
+ login_ID = orb->login_ID;
+
+ if (login_ID >= app->max_logins)
+ {
+ action->status->sbp_status = SBP2_STATUS_REQUEST_LOGIN_ID_NOT_RECOGNIZED;
+ return TRUE;
+ }
+
+ login = &state->logins[login_ID];
+
+ if (login->status == LOGIN_EMPTY)
+ {
+ action->status->sbp_status = SBP2_STATUS_REQUEST_LOGIN_ID_NOT_RECOGNIZED;
+ return TRUE;
+ }
+
+ if (login->timeout != 0)
+ {
+ util_source_remove (app->context, login->timeout);
+ login->timeout = 0;
+ }
+
+ expire_login (login);
+
+ return TRUE;
+}
+
+static gboolean
+worker_active (EndpointApp *app,
+ WireWorkerActive *message)
+{
+ ManagerState *state;
+ Login *login;
+
+ g_return_val_if_fail (app != NULL, FALSE);
+ g_return_val_if_fail (app->user_data != NULL, FALSE);
+ g_return_val_if_fail (message != NULL, FALSE);
+ g_return_val_if_fail (message->login_ID < app->max_logins, FALSE);
+
+ state = app->user_data;
+
+ login = &state->logins[message->login_ID];
+
+ login->status = LOGIN_ACTIVE;
+
+ return TRUE;
+}
+
+static gboolean
+worker_died (EndpointApp *app,
+ WireWorkerDied *message)
+{
+ ManagerState *state;
+ Login *login;
+ Port *port;
+ SBP2Status *status;
+
+ g_return_val_if_fail (app != NULL, FALSE);
+ g_return_val_if_fail (app->user_data != NULL, FALSE);
+ g_return_val_if_fail (message != NULL, FALSE);
+ g_return_val_if_fail (message->login_ID < app->max_logins, FALSE);
+
+ state = app->user_data;
+
+ login = &state->logins[message->login_ID];
+
+ port = login->port;
+
+ switch (login->status)
+ {
+ case LOGIN_PENDING:
+ status = g_memdup (&login->sbp2_status, sizeof (login->sbp2_status));
+ status->sbp_status = SBP2_STATUS_REQUEST_RESOURCES_UNAVAILABLE;
+
+ sbp2_manager_write_status (port->manager,
+ login->node, &login->status_FIFO,
+ status);
+ break;
+
+ case LOGIN_ACTIVE:
+ /* sbp2_manager_reset_bus (port->manager); */
+ break;
+
+ case LOGIN_RECONNECT:
+ /*
+ status = g_memdup (&login->sbp2_status, sizeof (login->sbp2_status));
+ status->sbp_status = SBP2_STATUS_REQUEST_RESOURCES_UNAVAILABLE;
+
+ sbp2_manager_write_status (port->manager,
+ login->node, &login->status_FIFO,
+ status);
+ */
+ break;
+
+ case LOGIN_DEAD:
+ /* do nothing */
+ break;
+
+ case LOGIN_EMPTY:
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ login->status = LOGIN_EMPTY;
+
+ port->num_logins--;
+ state->num_logins--;
+
+ login->port = NULL;
+
+ return TRUE;
+}
+
+static gboolean
+find_free_login_ID (ManagerState *state,
+ guint *login_ID)
+{
+ gint i;
+
+ g_return_val_if_fail (state != NULL, FALSE);
+ g_return_val_if_fail (login_ID != NULL, FALSE);
+
+ for (i = 0; i < state->app->max_logins; i++)
+ {
+ if (state->logins[i].status == LOGIN_EMPTY)
+ {
+ *login_ID = i;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean
+expire_login (Login *login)
+{
+ ManagerState *state;
+ gpointer message;
+
+ g_return_val_if_fail (login != NULL, FALSE);
+
+ state = login->port->state;
+
+ login->status = LOGIN_DEAD;
+
+ message = wire_message_logout (login->login_ID);
+ wire_message_send (state->writer, message, state->app);
+
+ login->timeout = 0;
+
+ return FALSE;
+}
+
+static void
+bus_reset (SBP2Manager *manager,
+ gpointer user_data)
+{
+ Port *port = user_data;
+ ManagerState *state;
+ EndpointApp *app;
+ gint i;
+ Login *login;
+
+ g_return_if_fail (manager != NULL);
+ g_return_if_fail (port != NULL);
+
+ state = port->state;
+ app = state->app;
+
+ for (i = 0; i < app->max_logins; i++)
+ {
+ login = &state->logins[i];
+
+ if (login->port != port)
+ continue;
+
+ if (login->status == LOGIN_ACTIVE)
+ {
+ login->status = LOGIN_RECONNECT;
+
+ login->timeout = util_timeout_add (app->context,
+ (SBP2_RECONNECT_HOLD + 1) * 1000,
+ (GSourceFunc) expire_login, login);
+ }
+ else if (login->status == LOGIN_PENDING)
+ expire_login (login);
+ }
+}
Added: trunk/src/manager.h
==============================================================================
--- trunk/src/manager.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/src/manager.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,36 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __MANAGER_H__
+#define __MANAGER_H__
+
+
+#include "app.h"
+#include "process.h"
+
+
+void manager_process (EndpointApp *app,
+ Process *process);
+
+
+#endif /* __MANAGER_H__ */
Added: trunk/src/process.c
==============================================================================
--- trunk/src/process.c 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/src/process.c 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,206 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <sys/wait.h>
+#include <signal.h>
+
+#include <glib.h>
+
+#include "app.h"
+#include "cleanup.h"
+#include "process.h"
+#include "util.h"
+#include "wire.h"
+
+
+#define REAP_DELAY 1000
+#define REAP_RETRY_COUNT 5
+
+
+static void close_descriptors (gint except_reader,
+ gint except_writer);
+
+static gboolean reap_process (GIOChannel *channel,
+ GIOCondition condition,
+ Process *process);
+static gboolean waitpid_timeout (Process *process);
+
+
+static inline void
+close_fd (gint fd)
+{
+ if (fd != -1)
+ close (fd);
+}
+
+Process *
+process_start (EndpointApp *app,
+ ProcessReapNotify notify)
+{
+ gint ipipe[2] = { -1, -1 };
+ gint opipe[2] = { -1, -1 };
+ gint my_reader, sub_reader;
+ gint my_writer, sub_writer;
+ GIOChannel *reader;
+ GIOChannel *writer;
+ gint pid;
+ Process *process;
+
+ g_return_val_if_fail (app != NULL, NULL);
+
+ if (pipe (ipipe) < 0 || pipe (opipe) < 0)
+ goto fail;
+
+ my_reader = ipipe[0];
+ my_writer = opipe[1];
+ sub_reader = opipe[0];
+ sub_writer = ipipe[1];
+
+ pid = fork ();
+
+ if (pid < 0)
+ goto fail;
+
+ process = g_new (Process, 1);
+
+ if (pid == 0)
+ {
+ //close_descriptors (sub_reader, sub_writer);
+
+ cleanup_unregister (app);
+
+ reader = util_io_channel_new (sub_reader);
+ writer = util_io_channel_new (sub_writer);
+
+ g_main_loop_quit (app->loop);
+
+ app->context = g_main_context_new ();
+
+ app->wire_funcs = NULL;
+ app->user_data = NULL;
+ }
+ else
+ {
+ close (sub_reader);
+ close (sub_writer);
+
+ reader = util_io_channel_new (my_reader);
+ writer = util_io_channel_new (my_writer);
+
+ util_io_add_watch (app->context, writer,
+ G_IO_ERR | G_IO_HUP,
+ (GIOFunc) reap_process, process);
+ }
+
+ util_io_add_watch (app->context, reader,
+ G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) wire_message_process, app);
+
+ process->app = app;
+
+ process->pid = pid;
+
+ process->reader = reader;
+ process->writer = writer;
+
+ process->notify = notify;
+ process->count = REAP_RETRY_COUNT;
+
+ return process;
+
+fail:
+ close_fd (ipipe[0]);
+ close_fd (ipipe[1]);
+ close_fd (opipe[0]);
+ close_fd (opipe[1]);
+
+ return NULL;
+}
+
+static void
+close_descriptors (gint except_reader,
+ gint except_writer)
+{
+ glong open_max;
+ gint i;
+
+ g_return_if_fail (except_reader > 3);
+ g_return_if_fail (except_writer > 3);
+
+ open_max = sysconf(_SC_OPEN_MAX);
+
+ for (i = 3; i < open_max; i++)
+ if (i != except_reader && i != except_writer)
+ close (i);
+}
+
+static gboolean
+reap_process (GIOChannel *channel,
+ GIOCondition condition,
+ Process *process)
+{
+ g_return_val_if_fail (channel != NULL, FALSE);
+ g_return_val_if_fail (process != NULL, FALSE);
+ g_return_val_if_fail (process->app->context != NULL, FALSE);
+
+ util_timeout_add (process->app->context, REAP_DELAY,
+ (GSourceFunc) waitpid_timeout, process);
+
+ return FALSE;
+}
+
+static gboolean
+waitpid_timeout (Process *process)
+{
+ gint pid;
+ gint status;
+
+ g_return_val_if_fail (process != NULL, TRUE);
+ g_return_val_if_fail (process->pid > 0, TRUE);
+
+ process->count--;
+
+ pid = waitpid (process->pid, &status, WNOHANG);
+
+ if (pid == -1)
+ {
+ /* ERROR MESSAGE */
+ }
+ else if (pid == 0)
+ {
+ if (process->count == 0)
+ kill (process->pid, SIGTERM);
+ else if (process->count < 0)
+ kill (process->pid, SIGKILL);
+
+ return TRUE;
+ }
+
+ process->notify (process, status);
+ g_free (process);
+
+ return FALSE;
+}
Added: trunk/src/process.h
==============================================================================
--- trunk/src/process.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/src/process.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,58 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __PROCESS_H__
+#define __PROCESS_H__
+
+
+#include <glib.h>
+
+#include "app.h"
+
+
+typedef struct _Process Process;
+
+typedef void (*ProcessReapNotify) (Process *process,
+ gint status);
+
+struct _Process
+{
+ EndpointApp *app;
+
+ gint pid;
+ guint login_ID;
+
+ GIOChannel *reader;
+ GIOChannel *writer;
+
+ /* private */
+ ProcessReapNotify notify;
+ gint count;
+};
+
+
+Process *process_start (EndpointApp *app,
+ ProcessReapNotify notify);
+
+
+#endif /* __PROCESS_H__ */
Added: trunk/src/util.c
==============================================================================
--- trunk/src/util.c 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/src/util.c 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,130 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#include <glib.h>
+
+
+static guint attach_source (GSource *source,
+ GMainContext *context,
+ GSourceFunc function,
+ gpointer data);
+
+
+GIOChannel *
+util_io_channel_new (gint fd)
+{
+ GIOChannel *channel;
+
+ g_return_val_if_fail (fd >= 0, NULL);
+
+ channel = g_io_channel_unix_new (fd);
+
+ g_io_channel_set_encoding (channel, NULL, NULL);
+ g_io_channel_set_buffered (channel, FALSE);
+ g_io_channel_set_close_on_unref (channel, TRUE);
+
+ return channel;
+}
+
+guint
+util_run_first_add (GMainContext *context,
+ GSourceFunc function,
+ gpointer data)
+{
+ GSource *source;
+
+ g_return_val_if_fail (function != NULL, 0);
+
+ source = g_idle_source_new ();
+ g_source_set_priority (source, G_PRIORITY_HIGH);
+
+ return attach_source (source, context, function, data);
+}
+
+guint
+util_timeout_add (GMainContext *context,
+ guint interval,
+ GSourceFunc function,
+ gpointer data)
+{
+ GSource *source;
+
+ g_return_val_if_fail (function != NULL, 0);
+
+ source = g_timeout_source_new (interval);
+
+ return attach_source (source, context, function, data);
+}
+
+guint
+util_io_add_watch (GMainContext *context,
+ GIOChannel *channel,
+ GIOCondition condition,
+ GIOFunc function,
+ gpointer data)
+{
+ GSource *source;
+
+ g_return_val_if_fail (channel != NULL, 0);
+ g_return_val_if_fail (function != NULL, 0);
+
+ source = g_io_create_watch (channel, condition);
+ g_io_channel_unref (channel);
+
+ return attach_source (source, context, (GSourceFunc) function, data);
+}
+
+static guint
+attach_source (GSource *source,
+ GMainContext *context,
+ GSourceFunc function,
+ gpointer data)
+{
+ guint id;
+
+ g_return_val_if_fail (source != NULL, 0);
+ g_return_val_if_fail (function != NULL, 0);
+
+ g_source_set_callback (source, function, data, NULL);
+
+ id = g_source_attach (source, context);
+ g_source_unref (source);
+
+ return id;
+}
+
+gboolean
+util_source_remove (GMainContext *context,
+ guint tag)
+{
+ GSource *source;
+
+ g_return_val_if_fail (context != NULL, FALSE);
+
+ source = g_main_context_find_source_by_id (context, tag);
+
+ if (source)
+ g_source_destroy (source);
+
+ return source != NULL;
+}
Added: trunk/src/util.h
==============================================================================
--- trunk/src/util.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/src/util.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,50 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __UTIL_H__
+#define __UTIL_H__
+
+
+#include <glib.h>
+
+
+GIOChannel *util_io_channel_new (gint fd);
+
+guint util_run_first_add (GMainContext *context,
+ GSourceFunc function,
+ gpointer data);
+guint util_timeout_add (GMainContext *context,
+ guint interval,
+ GSourceFunc function,
+ gpointer data);
+guint util_io_add_watch (GMainContext *context,
+ GIOChannel *channel,
+ GIOCondition condition,
+ GIOFunc function,
+ gpointer data);
+
+gboolean util_source_remove (GMainContext *context,
+ guint tag);
+
+
+#endif /* __UTIL_H__ */
Added: trunk/src/wire.c
==============================================================================
--- trunk/src/wire.c 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/src/wire.c 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,376 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#include <string.h>
+#include <limits.h>
+
+#include <glib.h>
+
+#include <libraw1394/raw1394.h>
+
+#include <libsbp2/sbp2login.h>
+
+#include "app.h"
+#include "util.h"
+#include "wire.h"
+
+
+/* Keep this updated with the biggest wire message structure */
+#define MAX_MESSAGE_LENGTH (sizeof (WireLogin))
+
+
+typedef struct _WireLoginID WireLoginID;
+
+typedef struct _WireBuffer WireBuffer;
+
+struct _WireBuffer
+{
+ gpointer message;
+
+ gchar *buffer;
+ gsize length;
+};
+
+
+static gboolean read_data (GIOChannel *channel,
+ WireBuffer *wire_buffer);
+static gboolean write_data (GIOChannel *channel,
+ GIOCondition condition,
+ WireBuffer *wire_buffer);
+
+static void dispatch_message (EndpointApp *app,
+ gpointer message);
+
+
+static inline WireMessageType
+get_message_type (gpointer message)
+{
+ return ((WireHeader *) message)->type;
+}
+
+static inline gpointer
+alloc_message (WireMessageType type)
+{
+ WireHeader *header;
+
+ header = g_malloc0 (MAX_MESSAGE_LENGTH); /* valgrind safe */
+ header->type = type;
+
+ return header;
+}
+
+static inline gpointer
+alloc_message_login_ID (WireMessageType type,
+ guint login_ID)
+{
+ WireLoginID *message;
+
+ message = alloc_message (type);
+ message->login_ID = login_ID;
+
+ return message;
+}
+
+
+gboolean
+wire_init (void)
+{
+ return PIPE_BUF >= MAX_MESSAGE_LENGTH;
+}
+
+gboolean
+wire_message_send (GIOChannel *channel,
+ gpointer message,
+ EndpointApp *app)
+{
+ WireBuffer *wire_buffer;
+
+ g_return_val_if_fail (channel != NULL, FALSE);
+ g_return_val_if_fail (message != NULL, FALSE);
+ g_return_val_if_fail (app != NULL, FALSE);
+ g_return_val_if_fail (app->context != NULL, FALSE);
+
+ wire_buffer = g_new0 (WireBuffer, 1);
+
+ wire_buffer->message = message;
+ wire_buffer->buffer = message;
+ wire_buffer->length = MAX_MESSAGE_LENGTH;
+
+ /* util_io_add_watch (app->context, channel,
+ G_IO_OUT | G_IO_ERR | G_IO_HUP,
+ (GIOFunc) write_data, wire_buffer); */
+
+ return write_data (channel, 0, wire_buffer);
+}
+
+gboolean
+wire_message_process (GIOChannel *channel,
+ GIOCondition condition,
+ EndpointApp *app)
+{
+ WireBuffer *buffer;
+
+ g_return_val_if_fail (channel != NULL, FALSE);
+ g_return_val_if_fail (app != NULL, FALSE);
+ g_return_val_if_fail (app->wire_funcs != NULL, FALSE);
+
+ if (condition & G_IO_ERR || condition & G_IO_HUP)
+ return FALSE;
+
+ buffer = g_new0 (WireBuffer, 1);
+
+ buffer->message = g_new (guint8, MAX_MESSAGE_LENGTH);
+ buffer->buffer = buffer->message;
+ buffer->length = MAX_MESSAGE_LENGTH;
+
+ if (!read_data (channel, buffer))
+ return FALSE;
+
+ dispatch_message (app, buffer->message);
+
+ g_free (buffer->message);
+ g_free (buffer);
+
+ return TRUE;
+}
+
+gpointer
+wire_message_copy (gpointer message)
+{
+ return g_memdup (message, MAX_MESSAGE_LENGTH);
+}
+
+gpointer
+wire_message_login (guint login_ID,
+ gint port,
+ nodeid_t node,
+ SBP2Pointer *pointer,
+ SBP2LoginORB *orb)
+{
+ WireLogin *message;
+
+ g_return_val_if_fail (pointer != NULL, NULL);
+ g_return_val_if_fail (orb != NULL, NULL);
+
+ message = alloc_message (WIRE_LOGIN);
+ message->login_ID = login_ID;
+
+ message->node = node;
+
+ memcpy (&message->pointer, pointer, sizeof (SBP2Pointer));
+ memcpy (&message->orb, orb, sizeof (SBP2LoginORB));
+
+ return message;
+}
+
+gpointer
+wire_message_reconnect (guint login_ID,
+ nodeid_t node)
+{
+ WireReconnect *message;
+
+ message = alloc_message (WIRE_RECONNECT);
+ message->login_ID = login_ID;
+
+ message->node = node;
+
+ return message;
+}
+
+gpointer
+wire_message_logout (guint login_ID)
+{
+ return alloc_message_login_ID (WIRE_LOGOUT, login_ID);
+}
+
+gpointer
+wire_message_worker_active (guint login_ID)
+{
+ return alloc_message_login_ID (WIRE_WORKER_ACTIVE, login_ID);
+}
+
+gpointer
+wire_message_worker_died (guint login_ID)
+{
+ return alloc_message_login_ID (WIRE_WORKER_DIED, login_ID);
+}
+
+static gboolean
+read_data (GIOChannel *channel,
+ WireBuffer *wire_buffer)
+{
+ gchar *buffer;
+ gsize length;
+ gsize bytes;
+ GIOStatus status;
+ GError *error = NULL;
+
+ g_return_val_if_fail (channel != NULL, FALSE);
+ g_return_val_if_fail (wire_buffer != NULL, FALSE);
+
+ buffer = wire_buffer->buffer;
+ length = wire_buffer->length;
+
+ g_return_val_if_fail (channel != NULL, FALSE);
+ g_return_val_if_fail (buffer != NULL, FALSE);
+
+ while (length > 0)
+ {
+ do
+ {
+ bytes = 0;
+ status = g_io_channel_read_chars (channel,
+ buffer, length,
+ &bytes, &error);
+ }
+ while (status == G_IO_STATUS_AGAIN);
+
+ if (status != G_IO_STATUS_NORMAL)
+ {
+ if (error)
+ {
+ g_warning ("wire read data: error: %s", error->message);
+ g_error_free (error);
+ }
+ else
+ {
+ g_warning ("wire read data: error");
+ }
+
+ return FALSE;
+ }
+
+ if (bytes == 0)
+ {
+ g_warning ("wire read data: unexpected EOF");
+ return FALSE;
+ }
+
+ length -= bytes;
+ buffer += bytes;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+write_data (GIOChannel *channel,
+ GIOCondition condition,
+ WireBuffer *wire_buffer)
+{
+ gsize bytes;
+ GIOStatus status;
+ GError *error = NULL;
+
+ g_return_val_if_fail (channel != NULL, FALSE);
+ g_return_val_if_fail (wire_buffer != NULL, FALSE);
+ g_return_val_if_fail (wire_buffer->message != NULL, FALSE);
+ g_return_val_if_fail (wire_buffer->buffer != NULL, FALSE);
+ g_return_val_if_fail (wire_buffer->length > 0, FALSE);
+
+ if (condition & G_IO_ERR || condition & G_IO_HUP)
+ goto free_and_stop;
+
+ bytes = 0;
+ status = g_io_channel_write_chars (channel,
+ wire_buffer->buffer, wire_buffer->length,
+ &bytes, &error);
+
+ if (status == G_IO_STATUS_AGAIN)
+ return TRUE;
+
+ if (status != G_IO_STATUS_NORMAL)
+ {
+ if (error)
+ {
+ g_warning ("wire write data: error: %s", error->message);
+ g_error_free (error);
+ }
+ else
+ g_warning ("wire write data: error");
+
+ goto free_and_stop;
+ }
+
+ wire_buffer->length -= bytes;
+ wire_buffer->buffer += bytes;
+
+ if (wire_buffer->length > 0)
+ return TRUE;
+
+free_and_stop:
+ g_free (wire_buffer->message);
+ g_free (wire_buffer);
+
+ return FALSE;
+}
+
+static void
+dispatch_message (EndpointApp *app,
+ gpointer message)
+{
+ WireMsgFuncs *funcs;
+
+ g_return_if_fail (app != NULL);
+ g_return_if_fail (app->wire_funcs != NULL);
+ g_return_if_fail (message != NULL);
+
+ funcs = app->wire_funcs;
+
+ switch (get_message_type (message))
+ {
+ case WIRE_LOGIN:
+ g_return_if_fail (funcs->login != NULL);
+
+ funcs->login (app, message);
+ break;
+
+ case WIRE_RECONNECT:
+ g_return_if_fail (funcs->reconnect != NULL);
+
+ funcs->reconnect (app, message);
+ break;
+
+ case WIRE_LOGOUT:
+ g_return_if_fail (funcs->logout != NULL);
+
+ funcs->logout (app, message);
+ break;
+
+ case WIRE_WORKER_ACTIVE:
+ g_return_if_fail (funcs->worker_active != NULL);
+
+ funcs->worker_active (app, message);
+ break;
+
+ case WIRE_WORKER_DIED:
+ g_return_if_fail (funcs->worker_died != NULL);
+
+ funcs->worker_died (app, message);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
Added: trunk/src/wire.h
==============================================================================
--- trunk/src/wire.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/src/wire.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,131 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __WIRE_MESSAGES_H__
+#define __WIRE_MESSAGES_H__
+
+
+#include <glib.h>
+
+#include <libraw1394/raw1394.h>
+
+#include <libsbp2/sbp2login.h>
+
+#include "app.h"
+
+
+typedef enum
+{
+ WIRE_LOGIN,
+ WIRE_RECONNECT,
+ WIRE_LOGOUT,
+
+ WIRE_WORKER_ACTIVE,
+ WIRE_WORKER_DIED
+} WireMessageType;
+
+
+typedef struct _WireHeader WireHeader;
+
+typedef struct _WireLogin WireLogin;
+typedef struct _WireReconnect WireReconnect;
+
+typedef struct _WireLoginID WireLogout;
+typedef struct _WireLoginID WireWorkerActive;
+typedef struct _WireLoginID WireWorkerDied;
+
+typedef struct _WireMsgFuncs WireMsgFuncs;
+
+struct _WireHeader
+{
+ WireMessageType type;
+};
+
+struct _WireLogin
+{
+ WireHeader header;
+
+ guint login_ID;
+ gint port;
+
+ nodeid_t node;
+ SBP2Pointer pointer;
+ SBP2LoginORB orb;
+};
+
+struct _WireReconnect
+{
+ WireHeader header;
+
+ guint login_ID;
+ nodeid_t node;
+};
+
+struct _WireLoginID
+{
+ WireHeader header;
+
+ guint login_ID;
+};
+
+struct _WireMsgFuncs
+{
+ gboolean (*login) (EndpointApp *app,
+ WireLogin *message);
+ gboolean (*reconnect) (EndpointApp *app,
+ WireReconnect *message);
+ gboolean (*logout) (EndpointApp *app,
+ WireLogout *message);
+
+ gboolean (*worker_active) (EndpointApp *app,
+ WireWorkerActive *message);
+ gboolean (*worker_died) (EndpointApp *app,
+ WireWorkerDied *message);
+};
+
+
+gboolean wire_init (void);
+
+gboolean wire_message_send (GIOChannel *channel,
+ gpointer message,
+ EndpointApp *app);
+gboolean wire_message_process (GIOChannel *channel,
+ GIOCondition condition,
+ EndpointApp *app);
+
+gpointer wire_message_copy (gpointer message);
+
+gpointer wire_message_login (guint login_ID,
+ gint port,
+ nodeid_t node,
+ SBP2Pointer *pointer,
+ SBP2LoginORB *orb);
+gpointer wire_message_reconnect (guint login_ID,
+ nodeid_t node);
+gpointer wire_message_logout (guint login_ID);
+
+gpointer wire_message_worker_active (guint login_ID);
+gpointer wire_message_worker_died (guint login_ID);
+
+
+#endif /* __WIRE_MESSAGES_H__ */
Added: trunk/src/worker.c
==============================================================================
--- trunk/src/worker.c 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/src/worker.c 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,129 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#include <stdlib.h>
+
+#include <glib.h>
+
+#include <libraw1394/raw1394.h>
+
+#include <librbc/rbcdisk.h>
+
+#include <libsbp2/sbp2login.h>
+#include <libsbp2/sbp2worker.h>
+
+#include "app.h"
+#include "worker.h"
+
+
+typedef struct _WorkerState WorkerState;
+
+struct _WorkerState
+{
+ EndpointApp *app;
+
+ RBCDisk *disk;
+ SBP2Worker *worker;
+
+ GIOChannel *reader;
+ GIOChannel *writer;
+};
+
+
+static gboolean reconnect (EndpointApp *app,
+ WireReconnect *message);
+
+
+static WireMsgFuncs wire_funcs = {
+ .reconnect = reconnect
+};
+
+void
+worker_process (EndpointApp *app,
+ Process *process,
+ WireLogin *message)
+{
+ WorkerState *state;
+ RBCDisk *disk;
+ SBP2Worker *worker;
+ WireWorkerActive *ret_message;
+
+ g_return_if_fail (app != NULL);
+ g_return_if_fail (process != NULL);
+
+ disk = g_hash_table_lookup (app->disks, GINT_TO_POINTER (message->orb.lun));
+
+ if (!rbc_disk_activate (disk))
+ exit (1);
+
+ worker = sbp2_worker_new (disk, app->context,
+ message->port, message->login_ID);
+
+ if (!worker)
+ exit (2);
+
+ if (!sbp2_worker_login (worker, message->node, &message->pointer,
+ &message->orb))
+ exit (3);
+
+ app->wire_funcs = &wire_funcs;
+
+ state = g_new (WorkerState, 1);
+
+ state->app = app;
+
+ state->disk = disk;
+ state->worker = worker;
+
+ state->reader = process->reader;
+ state->writer = process->writer;
+
+ app->user_data = state;
+
+ ret_message = wire_message_worker_active (message->login_ID);
+ wire_message_send (state->writer, ret_message, app);
+}
+
+static gboolean
+reconnect (EndpointApp *app,
+ WireReconnect *message)
+{
+ WorkerState *state;
+ WireWorkerActive *ret_message;
+
+ g_return_val_if_fail (app != NULL, FALSE);
+ g_return_val_if_fail (app->user_data != NULL, FALSE);
+ g_return_val_if_fail (message != NULL, FALSE);
+
+ state = app->user_data;
+
+ if (sbp2_worker_reconnect (state->worker, message->node))
+ {
+ ret_message = wire_message_worker_active (message->login_ID);
+ wire_message_send (state->writer, ret_message, app);
+ }
+ else
+ exit (4);
+
+ return TRUE;
+}
Added: trunk/src/worker.h
==============================================================================
--- trunk/src/worker.h 2003-07-17 19:25:32 UTC (rev 1)
+++ trunk/src/worker.h 2003-07-17 19:27:07 UTC (rev 2)
@@ -0,0 +1,38 @@
+/*
+ * Endpoint - Linux SBP2 Disk Target
+ *
+ * Copyright (C) 2003 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved 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 021110-1307, USA.
+ */
+
+#ifndef __WORKER_H__
+#define __WORKER_H__
+
+
+#include "app.h"
+#include "process.h"
+#include "wire.h"
+
+
+void worker_process (EndpointApp *app,
+ Process *process,
+ WireLogin *message);
+
+
+#endif /* __WORKER_H__ */
More information about the Endpoint-commits
mailing list