pax_global_header00006660000000000000000000000064121475165440014523gustar00rootroot0000000000000052 comment=ef676c703d5f82fe44cf00f187e53056d9140043 libhbalinux-1.0.16/000077500000000000000000000000001214751654400141115ustar00rootroot00000000000000libhbalinux-1.0.16/.gitignore000066400000000000000000000005371214751654400161060ustar00rootroot00000000000000# standard autotools stuff .deps/ Makefile Makefile.in aclocal.m4 autom4te.cache/ config.guess config.log config.status config.sub configure depcomp install-sh libtool ltmain.sh missing # other autoconf generated files libhbalinux.spec # compile generated files *.o *.lo *.la .libs # build.sh generated files libhbalinux-*.tar.gz libhbalinux-*.rpm libhbalinux-1.0.16/CONFIGURE000066400000000000000000000224501214751654400153600ustar00rootroot00000000000000Installation Instructions ************************* Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. This file is free documentation; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Basic Installation ================== Briefly, the shell commands `./configure; make; make install' should configure, build, and install this package. The following more-detailed instructions are generic; see the `README' file for instructions specific to this package. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale cache files. If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. Running `configure' might take a while. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. 6. Often, you can also type `make uninstall' to remove the installed files again. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you can use GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. With a non-GNU `make', it is safer to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' installs the package's commands under `/usr/local/bin', include files under `/usr/local/include', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PREFIX'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option `--exec-prefix=PREFIX' to `configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the option `--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc' to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for `CONFIG_SHELL' due to an Autoconf bug. Until the bug is fixed you can use this workaround: CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of the options to `configure', and exit. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. libhbalinux-1.0.16/COPYING000066400000000000000000000634731214751654400151610ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, 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 library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete 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 distribute a copy of this License along with the Library. 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 Library or any portion of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you 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. If distribution of 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 satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be 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. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library 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. 9. 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 Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library 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 with this License. 11. 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 Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library 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 Library. 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. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library 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. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library 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 Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, 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 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. 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 LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This 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.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! libhbalinux-1.0.16/INSTALL000066400000000000000000000005631214751654400151460ustar00rootroot00000000000000This document explains how to build the Linux vendor library for the HBA API. ## # libhbalinux ############## DEPENDENCIES * HBA API Wrapper Library * autoconf * autotools * sysconftool * automake * libtool * libpciaccess-devel PROCESS 1) Bootstrap, configure, make and make install # ./bootstrap.sh # rpm --eval "%configure" | sh # make # make install libhbalinux-1.0.16/Makefile.am000066400000000000000000000020171214751654400161450ustar00rootroot00000000000000AM_CFLAGS = $(HBAAPI_CFLAGS) $(PCIACCESS_CFLAGS) AM_LDFLAGS= $(PCIACCESS_LIBS) lib_LTLIBRARIES = libhbalinux.la libhbalinux_la_SOURCES = adapt.c adapt_impl.h api_lib.h bind.c bind_impl.h \ fc_scsi.h fc_types.h lib.c lport.c net_types.h pci.c rport.c scsi.c sg.c \ utils.c utils.h libhbalinux_la_LDFLAGS = -version-info 2:2:0 libhbalinux_la_LIBADD = $(PCIACCESS_LIBS) pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libhbalinux.pc dist_noinst_DATA = README COPYING INSTALL libhbalinux.pc.in libhbalinux.spec install-data-hook: libhbalinux.la . $${PWD}/$<; \ ORG=org.open-fcoe.libhbalinux; \ LIB=${libdir}/$${dlname}; \ STR="$$ORG $$LIB"; \ CONF=${sysconfdir}/hba.conf; \ if test -f $$CONF; then \ grep -E -q ^[[:space:]]*$$ORG[[:space:]]+$$LIB $$CONF; \ if test $$? -ne 0; then \ echo $$STR >> $$CONF; \ else \ echo "** $$CONF already configured"; \ echo "** system configuration not updated"; \ fi; \ else \ echo "** WARNING: $$CONF does not exist"; \ echo "** system configuration not updated"; \ fi libhbalinux-1.0.16/README000066400000000000000000000045271214751654400150010ustar00rootroot00000000000000 Linux* HBAAPI Vendor Library ============================ Introduction ------------ HBAAPI stands for Host Bus Adapter API (Applications Programming Interface). It is a C-level shared library to manage Fibre Channel Host Bus Adapters. The HBAAPI library source code may be downloaded from http://sourceforge.net/. For a detailed description of HBAAPI please see the FC-HBA working draft in http://www.t11.org/index.html. The HBAAPI shared library will also be built when the vendor library is built, and will be named as libHBAAPI.so. The HBAAPI vendor library is a shared library with functions that support the API routines in the HBAAPI library. The HBAAPI vendor library will be named as libhbalinux.so and is loaded by the HBAAPI library as a dynamic library when the HBAAPI library is initialized. The vendor library invokes the /sys file system for information of FCoE network adapters, local ports, remote ports and discovered LUNs. It also gets adapter information with the assistance from libpciaccess while the information are not available in /sys. The ioctl calls are only used for SG_IO to issue SCSI commands to generic scsi block devices. No ioctl are called to the libfc.ko or fcoe.ko modules. When applications are developed to link with libHBAAPI.so, they may indirectly invoke libhbalinux.so behind the libHBAAPI.so. For instructions of how to build and install the libraries, please see the file INSTALL. In This Release --------------- This release of the vendor library is implemented in association with the version 2.2 (August 2002) of HBAAPI code from Source Forge. The supported API's in this release are: HBA_GetVersion HBA_LoadLibrary HBA_FreeLibrary HBA_RegisterLibrary HBA_GetNumberOfAdapters HBA_GetAdapterName HBA_OpenAdapter HBA_CloseAdapter HBA_GetAdapterAttributes HBA_GetAdapterPortAttributes HBA_GetPortStatistics HBA_GetFC4Statistics HBA_GetFcpTargetMapping HBA_GetFcpTargetMappingV2 HBA_SendScsiInquiry HBA_SendReportLUNs HBA_SendReadCapacity HBA_ScsiInquiryV2 HBA_ScsiReportLUNsV2 HBA_ScsiReadCapacityV2 Libhbalinux is maintained at www.Open-FCoE.org and the latest version can be obtained there. Questions, comments and contributions should take place on the development mailing list at www.Open-FCoE.org as well. libhbalinux-1.0.16/adapt.c000066400000000000000000000204051214751654400153470ustar00rootroot00000000000000/* * Copyright (c) 2008, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU Lesser General Public License, * version 2.1, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include "utils.h" #include "api_lib.h" #include "adapt_impl.h" static struct sa_table adapter_table; static const u_int32_t adapter_handle_offset = 0x100; #define HBA_SHORT_NAME_LIMIT 64 /* * Support for adapter information. */ HBA_UINT32 adapter_get_count(void) { return adapter_table.st_limit; } /* * Get adapter name. */ HBA_STATUS adapter_get_name(HBA_UINT32 index, char *buf) { HBA_STATUS status; struct adapter_info *ap; status = HBA_STATUS_ERROR_ILLEGAL_INDEX; ap = sa_table_lookup(&adapter_table, index); if (ap != NULL) { snprintf(buf, HBA_SHORT_NAME_LIMIT, "%s-%u", ap->ad_name, index); status = HBA_STATUS_OK; } return status; } /* * Add an adapter to the table. */ HBA_STATUS adapter_create(struct adapter_info *ap) { int index; index = sa_table_append(&adapter_table, ap); if (index < 0) return HBA_STATUS_ERROR; ap->ad_index = index; return HBA_STATUS_OK; } void adapter_destroy(struct adapter_info *ap) { sa_table_destroy_all(&ap->ad_ports); free(ap); } void adapter_destroy_all(void) { struct adapter_info *ap; int i; for (i = 0; i < adapter_table.st_limit; i++) { ap = adapter_table.st_table[i]; if (ap) { adapter_table.st_table[i] = NULL; adapter_destroy(ap); } } sa_table_destroy(&adapter_table); } struct adapter_info * adapter_open_handle(HBA_HANDLE handle) { return sa_table_lookup(&adapter_table, handle - adapter_handle_offset); } struct port_info * adapter_get_port(HBA_HANDLE handle, HBA_UINT32 port) { struct adapter_info *ap; struct port_info *pp = NULL; ap = adapter_open_handle(handle); if (ap) pp = sa_table_lookup(&ap->ad_ports, port); return pp; } struct port_info * adapter_get_rport(HBA_HANDLE handle, HBA_UINT32 port, HBA_UINT32 rport) { struct port_info *pp; struct port_info *rp = NULL; pp = adapter_get_port(handle, port); if (pp) { get_rport_info(pp); rp = sa_table_lookup(&pp->ap_rports, rport); } return rp; } /* * Get the Nth discovered port information. */ struct port_info * adapter_get_rport_n(HBA_HANDLE handle, HBA_UINT32 port, HBA_UINT32 n) { struct port_info *pp; struct port_info *rp = NULL; pp = adapter_get_port(handle, port); if (pp) { get_rport_info(pp); rp = sa_table_lookup_n(&pp->ap_rports, n); } return rp; } static void * adapter_target_match(void *rp_arg, void *target_arg) { struct port_info *rp = rp_arg; if (rp->ap_scsi_target != *(u_int32_t *)target_arg) rp_arg = NULL; return rp_arg; } /* * Get the rport by scsi_target number. */ struct port_info * adapter_get_rport_target(HBA_HANDLE handle, HBA_UINT32 port, HBA_UINT32 n) { struct port_info *pp; struct port_info *rp = NULL; pp = adapter_get_port(handle, port); if (pp) { get_rport_info(pp); rp = sa_table_search(&pp->ap_rports, adapter_target_match, &n); } return rp; } static void * adapter_wwpn_match(void *rp_arg, void *wwpn_arg) { struct port_info *rp = rp_arg; if (memcmp(&rp->ap_attr.PortWWN, wwpn_arg, sizeof(HBA_WWN)) != 0) rp_arg = NULL; return rp_arg; } struct port_info * adapter_get_rport_by_wwn(struct port_info *pp, HBA_WWN wwpn) { struct port_info *rp; get_rport_info(pp); rp = sa_table_search(&pp->ap_rports, adapter_wwpn_match, &wwpn); return rp; } static void * adapter_fcid_match(void *rp_arg, void *fcid_arg) { struct port_info *rp = rp_arg; if (rp->ap_attr.PortFcId != *(fc_fid_t *)fcid_arg) rp_arg = NULL; return rp_arg; } struct port_info * adapter_get_rport_by_fcid(struct port_info *pp, fc_fid_t fcid) { struct port_info *rp; get_rport_info(pp); rp = sa_table_search(&pp->ap_rports, adapter_fcid_match, &fcid); return rp; } /* * Open adapter by name. */ HBA_HANDLE adapter_open(char *name) { char buf[256]; HBA_HANDLE i; HBA_STATUS status; for (i = 0; i < adapter_table.st_limit; i++) { status = adapter_get_name(i, buf); if (status != HBA_STATUS_OK) return 0; if (!strcmp(buf, name)) return adapter_handle_offset + i; } return 0; } /* * Get port by WWPN. * Returns NULL if WWN not unique. * If countp is non-NULL, the int it points to will be set to the * number found so that the caller can tell if the WWN was ambiguous. */ struct port_info * adapter_get_port_by_wwn(HBA_HANDLE handle, HBA_WWN wwn, int *countp) { struct adapter_info *ap; struct port_info *pp_found = NULL; struct port_info *pp; int count = 0; int p; ap = adapter_open_handle(handle); if (ap != NULL) { for (p = 0; p < ap->ad_ports.st_limit; p++) { pp = ap->ad_ports.st_table[p]; if (pp && !memcmp(&pp->ap_attr.PortWWN, &wwn, sizeof(wwn))) { count++; pp_found = pp; } } } if (count > 1) pp_found = NULL; if (countp != NULL) *countp = count; return pp_found; } /* * Open adapter by WWN. */ HBA_STATUS adapter_open_by_wwn(HBA_HANDLE *phandle, HBA_WWN wwn) { struct adapter_info *ap; struct port_info *pp; HBA_HANDLE found_handle = 0; int count = 0; HBA_STATUS status; int i; int p; for (i = 0; i < adapter_table.st_limit; i++) { ap = adapter_table.st_table[i]; if (!ap) continue; if (memcmp(&ap->ad_attr.NodeWWN, &wwn, sizeof(wwn)) == 0) { count++; found_handle = ap->ad_index + adapter_handle_offset; } else { for (p = 0; p < ap->ad_ports.st_limit; p++) { pp = ap->ad_ports.st_table[p]; if (!pp) continue; if (memcmp(&pp->ap_attr.PortWWN, &wwn, sizeof(wwn)) == 0) { count++; found_handle = ap->ad_index + adapter_handle_offset; } } } } *phandle = HBA_HANDLE_INVALID; if (count == 1) { status = HBA_STATUS_OK; *phandle = found_handle; } else if (count > 1) { status = HBA_STATUS_ERROR_AMBIGUOUS_WWN; } else { status = HBA_STATUS_ERROR_ILLEGAL_WWN; } return status; } /* * Close adapter. */ void adapter_close(HBA_HANDLE handle) { } /* * Get adapter attributes. */ HBA_STATUS adapter_get_attr(HBA_HANDLE handle, HBA_ADAPTERATTRIBUTES *pattr) { struct adapter_info *ap; ap = adapter_open_handle(handle); if (ap) { *pattr = ap->ad_attr; /* struct copy */ return HBA_STATUS_OK; } return HBA_STATUS_ERROR; } /* * Get adapter port attributes. */ HBA_STATUS adapter_get_port_attr(HBA_HANDLE handle, HBA_UINT32 port, HBA_PORTATTRIBUTES *pattr) { struct port_info *pp; pp = adapter_get_port(handle, port); if (pp) { *pattr = pp->ap_attr; /* struct copy */ return HBA_STATUS_OK; } return HBA_STATUS_ERROR; } /* * Get discovered (remote) port attributes. */ HBA_STATUS adapter_get_rport_attr(HBA_HANDLE handle, HBA_UINT32 port, HBA_UINT32 rport, HBA_PORTATTRIBUTES *pattr) { struct port_info *rp; rp = adapter_get_rport_n(handle, port, rport); if (rp) { *pattr = rp->ap_attr; /* struct copy */ return HBA_STATUS_OK; } return HBA_STATUS_ERROR; } /* * Get adapter port attributes. */ HBA_STATUS adapter_get_port_attr_by_wwn(HBA_HANDLE handle, HBA_WWN wwn, HBA_PORTATTRIBUTES *pattr) { struct adapter_info *ap; struct port_info *pp; struct port_info *pp_found = NULL; u_int32_t p; int count = 0; HBA_STATUS status; ap = adapter_open_handle(handle); if (ap != NULL) { for (p = 0; p < ap->ad_ports.st_limit; p++) { pp = ap->ad_ports.st_table[p]; if (pp == NULL) continue; if (!memcmp(&pp->ap_attr.PortWWN, &wwn, sizeof(wwn))) { count++; pp_found = pp; } pp = sa_table_search(&pp->ap_rports, adapter_wwpn_match, &wwn); if (pp) { count++; pp_found = pp; } } } pp = pp_found; if (pp != NULL) { if (count > 1) { status = HBA_STATUS_ERROR_AMBIGUOUS_WWN; } else { *pattr = pp->ap_attr; /* struct copy */ status = HBA_STATUS_OK; } } else { status = HBA_STATUS_ERROR_ILLEGAL_WWN; } return status; } libhbalinux-1.0.16/adapt_impl.h000066400000000000000000000140301214751654400163720ustar00rootroot00000000000000/* * Copyright (c) 2008, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU Lesser General Public License, * version 2.1, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef _ADAPT_IMPL_H_ #define _ADAPT_IMPL_H_ #define SYSFS_HOST_DIR "/sys/class/fc_host" #define SYSFS_HBA_DIR "/sys/class/net" #define SYSFS_LUN_DIR "/sys/class/scsi_device" #define SYSFS_MODULE "/driver/module" #define SYSFS_MODULE_VER "driver/module/version" #define SYSFS_RPORT_ROOT "/sys/class/fc_remote_ports" #define SYSFS_RPORT_DIR "rport-%u:%u-%u" /* host, chan, rport */ struct hba_info { u_int32_t domain; u_int32_t bus; u_int32_t dev; u_int32_t func; u_int32_t vendor_id; u_int32_t subsystem_vendor_id; u_int32_t subsystem_device_id; u_int32_t device_id; u_int32_t device_class; u_int32_t irq; char Manufacturer[64]; char SerialNumber[64]; char Model[256]; char ModelDescription[256]; char HardwareVersion[256]; char OptionROMVersion[256]; char FirmwareVersion[256]; u_int32_t VendorSpecificID; u_int32_t NumberOfPorts; }; #define MAX_DRIVER_NAME_LEN 20 #define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) HBA_STATUS sysfs_get_port_stats(char *dir, HBA_PORTSTATISTICS *sp); HBA_STATUS sysfs_get_port_fc4stats(char *dir, HBA_FC4STATISTICS *fc4sp); extern struct sa_nameval port_states_table[]; extern struct sa_nameval port_speeds_table[]; extern void adapter_scan(void); extern int sys_read_wwn(const char *, const char *, HBA_WWN *); extern HBA_STATUS find_pci_device(struct hba_info *); /* * per-adapter interface. */ /* * Information about a particular adapter. */ struct adapter_info { u_int32_t ad_index; /* adapter's library index */ u_int32_t ad_kern_index; /* adapter's kernel index */ const char *ad_name; /* adapter driver name */ struct sa_table ad_ports; /* table of ports */ u_int32_t ad_port_count; /* adapter's number of ports */ HBA_ADAPTERATTRIBUTES ad_attr; /* HBA-API attributes */ }; /* * Information about a port on an adapter or a discovered remote port. */ struct port_info { struct adapter_info *ap_adapt; u_int32_t ap_index; u_int32_t ap_disc_index; /* discovered port index */ u_int32_t ap_scsi_target; /* SCSI target index (rports) */ u_int32_t ap_kern_hba; /* kernel HBA index (rports) */ struct sa_table ap_rports; /* discovered ports */ HBA_PORTATTRIBUTES ap_attr; /* HBA-API port attributes */ char host_dir[80]; /* sysfs directory save area */ }; /* * Internal functions. */ HBA_UINT32 adapter_get_count(void); HBA_STATUS adapter_get_name(HBA_UINT32 index, char *); struct port_info *adapter_get_port_by_wwn(HBA_HANDLE, HBA_WWN, int *countp); HBA_STATUS adapter_create(struct adapter_info *); void adapter_destroy(struct adapter_info *); void adapter_destroy_all(void); struct adapter_info *adapter_open_handle(HBA_HANDLE); struct port_info *adapter_get_port(HBA_HANDLE, HBA_UINT32 port); struct port_info *adapter_get_rport(HBA_HANDLE, HBA_UINT32, HBA_UINT32); struct port_info *adapter_get_rport_n(HBA_HANDLE, HBA_UINT32, HBA_UINT32); struct port_info *adapter_get_rport_target(HBA_HANDLE, HBA_UINT32, HBA_UINT32); struct port_info *adapter_get_rport_by_wwn(struct port_info *, HBA_WWN); struct port_info *adapter_get_rport_by_fcid(struct port_info *, fc_fid_t); void get_rport_info(struct port_info *); void sg_get_dev_id(const char *name, char *buf, size_t result_len); void copy_wwn(HBA_WWN *dest, fc_wwn_t src); int is_wwn_nonzero(HBA_WWN *wwn); HBA_STATUS sg_issue_read_capacity(const char *, void *, HBA_UINT32 *, HBA_UINT8 *, void *, HBA_UINT32 *); HBA_STATUS sg_issue_report_luns(const char *, void *, HBA_UINT32 *, HBA_UINT8 *, void *, HBA_UINT32 *); /* * Library functions. */ HBA_HANDLE adapter_open(char *name); HBA_STATUS adapter_open_by_wwn(HBA_HANDLE *, HBA_WWN); void adapter_close(HBA_HANDLE); HBA_STATUS adapter_get_attr(HBA_HANDLE, HBA_ADAPTERATTRIBUTES *); HBA_STATUS adapter_get_port_attr(HBA_HANDLE, HBA_UINT32 port, HBA_PORTATTRIBUTES *); HBA_STATUS adapter_get_port_attr_by_wwn(HBA_HANDLE, HBA_WWN, HBA_PORTATTRIBUTES *); HBA_STATUS adapter_get_rport_attr(HBA_HANDLE, HBA_UINT32 port, HBA_UINT32 rport, HBA_PORTATTRIBUTES *); HBA_STATUS get_port_statistics(HBA_HANDLE, HBA_UINT32 port, HBA_PORTSTATISTICS *); HBA_STATUS get_port_fc4_statistics(HBA_HANDLE, HBA_WWN, HBA_UINT8 fc4_type, HBA_FC4STATISTICS *); HBA_STATUS scsi_read_capacity_v1(HBA_HANDLE, HBA_WWN, HBA_UINT64, void *, HBA_UINT32, void *, HBA_UINT32); HBA_STATUS scsi_read_capacity_v2(HBA_HANDLE, HBA_WWN, HBA_WWN, HBA_UINT64, void *, HBA_UINT32 *, HBA_UINT8 *, void *, HBA_UINT32 *); HBA_STATUS scsi_inquiry_v1(HBA_HANDLE, HBA_WWN, HBA_UINT64, HBA_UINT8, HBA_UINT32, void *, HBA_UINT32, void *, HBA_UINT32); HBA_STATUS scsi_inquiry_v2(HBA_HANDLE, HBA_WWN, HBA_WWN, HBA_UINT64, HBA_UINT8, HBA_UINT8, void *, HBA_UINT32 *, HBA_UINT8 *, void *, HBA_UINT32 *); HBA_STATUS scsi_report_luns_v1(HBA_HANDLE, HBA_WWN, void *, HBA_UINT32, void *, HBA_UINT32); HBA_STATUS scsi_report_luns_v2(HBA_HANDLE, HBA_WWN, HBA_WWN, void *, HBA_UINT32 *, HBA_UINT8 *, void *, HBA_UINT32 *); HBA_STATUS sg_issue_inquiry(const char *, HBA_UINT8, HBA_UINT8, void *, HBA_UINT32 *, HBA_UINT8 *, void *, HBA_UINT32 *); void adapter_init(void); void adapter_shutdown(void); /* struct port_stats; */ #endif /* _ADAPT_IMPL_H_ */ libhbalinux-1.0.16/api_lib.h000066400000000000000000000020061214751654400156570ustar00rootroot00000000000000/* * Copyright (c) 2008, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU Lesser General Public License, * version 2.1, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef _API_LIB_H_ #define _API_LIB_H_ /* * Definitions used by the OpenFC-specific library for the SNIA HBA-API. */ #define HBA_API_VENDOR "Open-FC.org" #define HBA_API_VERSION "2.2" #define HBA_API_VENDOR_RURL "org.open-fc" /* reversed URL */ #endif /* _API_LIB_H_ */ libhbalinux-1.0.16/bind.c000066400000000000000000000247731214751654400152060ustar00rootroot00000000000000/* * Copyright (c) 2008, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU Lesser General Public License, * version 2.1, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include "utils.h" #include "api_lib.h" #include "adapt_impl.h" #include "bind_impl.h" /* * Binding capabilities we understand. */ #define BINDING_CAPABILITIES (HBA_CAN_BIND_TO_D_ID | \ HBA_CAN_BIND_TO_WWPN | \ HBA_CAN_BIND_TO_WWNN) #define SYSFS_BIND "tgtid_bind_type" /* * Name-value strings for kernel bindings. * The first word of the strings must exactly match those in * Linux's drivers/scsi/scsi_transport_fc */ static struct sa_nameval binding_types_table[] = { { "none", 0 }, { "wwpn (World Wide Port Name)", HBA_CAN_BIND_TO_WWPN }, { "wwnn (World Wide Node Name)", HBA_CAN_BIND_TO_WWNN }, { "port_id (FC Address)", HBA_CAN_BIND_TO_D_ID }, { NULL, 0 } }; /* * Context for LUN binding reader. */ struct binding_context { HBA_HANDLE oc_handle; int oc_kern_hba; /* kernel HBA number */ int oc_port; int oc_target; int oc_lun; u_int32_t oc_count; u_int32_t oc_limit; u_int32_t oc_ver; void *oc_entries; HBA_STATUS oc_status; char oc_sg[32]; /* SCSI-generic dev name */ HBA_SCSIID *oc_scp; /* place for OS device name */ struct port_info *oc_rport; /* target remote port, if known */ char oc_path[256]; /* parent dir save area */ }; /* * Get binding capability. * We currently don't have a way to get this from the driver. * Instead, we hardcode what we know about Linux's capabilities. * We don't care which HBA is specified, except to return the correct error. */ HBA_STATUS get_binding_capability(HBA_HANDLE handle, HBA_WWN wwn, HBA_BIND_CAPABILITY *cp) { struct port_info *pp; int count = 0; pp = adapter_get_port_by_wwn(handle, wwn, &count); if (count > 1) return HBA_STATUS_ERROR_AMBIGUOUS_WWN; else if (pp == NULL) return HBA_STATUS_ERROR_ILLEGAL_WWN; *cp = BINDING_CAPABILITIES; return HBA_STATUS_OK; } /* * Get binding support. */ HBA_STATUS get_binding_support(HBA_HANDLE handle, HBA_WWN wwn, HBA_BIND_CAPABILITY *cp) { struct port_info *pp; char dir[50]; char bind[50]; int count = 0; pp = adapter_get_port_by_wwn(handle, wwn, &count); if (count > 1) return HBA_STATUS_ERROR_AMBIGUOUS_WWN; else if (pp == NULL) return HBA_STATUS_ERROR_ILLEGAL_WWN; snprintf(dir, sizeof(dir), SYSFS_HOST_DIR "/host%u", pp->ap_kern_hba); if (sa_sys_read_line(dir, SYSFS_BIND, bind, sizeof(bind)) == 0) sa_enum_encode(binding_types_table, bind, cp); return HBA_STATUS_OK; } /* * Set binding support. */ HBA_STATUS set_binding_support(HBA_HANDLE handle, HBA_WWN wwn, HBA_BIND_CAPABILITY flags) { struct port_info *pp; int count = 0; char dir[50]; char buf[50]; const char *bind; pp = adapter_get_port_by_wwn(handle, wwn, &count); if (count > 1) return HBA_STATUS_ERROR_AMBIGUOUS_WWN; if (pp == NULL) return HBA_STATUS_ERROR_ILLEGAL_WWN; if ((flags & BINDING_CAPABILITIES) != flags) return HBA_STATUS_ERROR_NOT_SUPPORTED; bind = sa_enum_decode(buf, sizeof(buf), binding_types_table, flags); snprintf(dir, sizeof(dir), SYSFS_HOST_DIR "/host%u", pp->ap_kern_hba); if (strstr(bind, "Unknown") != NULL) return HBA_STATUS_ERROR_NOT_SUPPORTED; if (sa_sys_write_line(dir, SYSFS_BIND, bind) == 0) return HBA_STATUS_ERROR_INCAPABLE; return HBA_STATUS_OK; } static int get_deprecated_device_name(struct dirent *dp, void *arg) { struct binding_context *cp = arg; if (strstr(cp->oc_path, "block")) snprintf(cp->oc_scp->OSDeviceName, sizeof(cp->oc_scp->OSDeviceName), "/dev/%s", dp->d_name); if (strstr(cp->oc_path, "scsi_generic")) snprintf(cp->oc_sg, sizeof(cp->oc_sg), "/dev/%s", dp->d_name); return 0; } static int get_binding_os_names(struct dirent *dp, void *arg) { struct binding_context *cp = arg; char *name = dp->d_name; char *sep; char buf[sizeof(cp->oc_scp->OSDeviceName)]; sep = strchr(name, ':'); if (dp->d_type == DT_LNK && sep != NULL) { *sep = '\0'; /* replace colon */ if (strcmp(name, "block") == 0) { snprintf(cp->oc_scp->OSDeviceName, sizeof(cp->oc_scp->OSDeviceName), "/dev/%s", sep + 1); } else if (strcmp(name, "scsi_generic") == 0) { snprintf(cp->oc_sg, sizeof(cp->oc_sg), "/dev/%s", sep + 1); } *sep = ':'; /* not really needed */ } else if (dp->d_type == DT_DIR && sep == NULL) { if ((!strcmp(name, "block")) || (!strcmp(name, "scsi_generic"))) { /* save the original path */ sa_strncpy_safe(buf, sizeof(buf), cp->oc_path, sizeof(cp->oc_path)); snprintf(cp->oc_path, sizeof(cp->oc_path), "%s/%s", buf, name); sa_dir_read(cp->oc_path, get_deprecated_device_name, cp); /* restore the original path */ sa_strncpy_safe(cp->oc_path, sizeof(cp->oc_path), buf, sizeof(buf)); } } return 0; } static int get_binding_target_mapping(struct dirent *dp, void *ctxt_arg) { struct binding_context *cp = ctxt_arg; struct port_info *pp; HBA_FCPSCSIENTRY *sp; HBA_FCPSCSIENTRYV2 *s2p; HBA_SCSIID *scp = NULL; HBA_FCPID *fcp = NULL; HBA_LUID *luid = NULL; char name[50]; u_int32_t hba = -1; u_int32_t port = -1; u_int32_t tgt = -1; u_int32_t lun = -1; /* * Parse directory entry name to see if it matches * :::. */ if (sscanf(dp->d_name, "%u:%u:%u:%u", &hba, &port, &tgt, &lun) != 4) return 0; if (hba != cp->oc_kern_hba || (port != cp->oc_port && cp->oc_port != -1) || (tgt != cp->oc_target && cp->oc_target != -1) || (lun != cp->oc_lun && cp->oc_lun != -1)) { return 0; } /* * Name matches. Add to count and to mapping list if there's room. */ if (cp->oc_count < cp->oc_limit) { switch (cp->oc_ver) { case 1: sp = &((HBA_FCPSCSIENTRY *) cp->oc_entries)[cp->oc_count]; scp = &sp->ScsiId; fcp = &sp->FcpId; luid = NULL; break; case 2: s2p = &((HBA_FCPSCSIENTRYV2 *) cp->oc_entries)[cp->oc_count]; scp = &s2p->ScsiId; fcp = &s2p->FcpId; luid = &s2p->LUID; break; default: fprintf(stderr, "*** Fatal! ***\n"); break; } pp = cp->oc_rport; if (pp == NULL) pp = adapter_get_rport_target(cp->oc_handle, port, tgt); if (pp != NULL) { fcp->FcId = pp->ap_attr.PortFcId; fcp->NodeWWN = pp->ap_attr.NodeWWN; fcp->PortWWN = pp->ap_attr.PortWWN; fcp->FcpLun = (HBA_UINT64) lun; } /* * Find OS device name by searching for symlink block: * and SG name by searching for scsi_generic: * in device subdirectory. */ snprintf(name, sizeof(name), SYSFS_LUN_DIR "/%s/device", dp->d_name); cp->oc_sg[0] = '\0'; cp->oc_scp = scp; scp->OSDeviceName[0] = '\0'; /* save a copy of the dir name */ sa_strncpy_safe(cp->oc_path, sizeof(cp->oc_path), name, sizeof(name)); sa_dir_read(name, get_binding_os_names, cp); scp->ScsiBusNumber = hba; scp->ScsiTargetNumber = tgt; scp->ScsiOSLun = lun; /* * find the LUN ID information by using scsi_generic I/O. */ if (luid != NULL && cp->oc_sg[0] != '\0') sg_get_dev_id(cp->oc_sg, luid->buffer, sizeof(luid->buffer)); } cp->oc_count++; return 0; } /* * Get FCP target mapping. */ HBA_STATUS get_binding_target_mapping_v1(HBA_HANDLE handle, HBA_FCPTARGETMAPPING *map) { struct binding_context ctxt; struct adapter_info *ap; ap = adapter_open_handle(handle); if (ap == NULL) return HBA_STATUS_ERROR_INVALID_HANDLE; memset(&ctxt, 0, sizeof(ctxt)); ctxt.oc_handle = handle; ctxt.oc_kern_hba = ap->ad_kern_index; ctxt.oc_port = -1; ctxt.oc_target = -1; ctxt.oc_lun = -1; ctxt.oc_limit = map->NumberOfEntries; ctxt.oc_ver = 1; ctxt.oc_entries = map->entry; ctxt.oc_status = HBA_STATUS_OK; memset(map->entry, 0, sizeof(map->entry[0]) * ctxt.oc_limit); sa_dir_read(SYSFS_LUN_DIR, get_binding_target_mapping, &ctxt); map->NumberOfEntries = ctxt.oc_count; if (ctxt.oc_status == HBA_STATUS_OK && ctxt.oc_count > ctxt.oc_limit) ctxt.oc_status = HBA_STATUS_ERROR_MORE_DATA; return ctxt.oc_status; } /* * Get FCP target mapping. */ HBA_STATUS get_binding_target_mapping_v2(HBA_HANDLE handle, HBA_WWN wwn, HBA_FCPTARGETMAPPINGV2 *map) { struct binding_context ctxt; struct adapter_info *ap; struct port_info *pp; pp = adapter_get_port_by_wwn(handle, wwn, NULL); if (pp == NULL) return HBA_STATUS_ERROR_INVALID_HANDLE; ap = pp->ap_adapt; if (ap == NULL) return HBA_STATUS_ERROR_INVALID_HANDLE; memset(&ctxt, 0, sizeof(ctxt)); ctxt.oc_handle = handle; ctxt.oc_kern_hba = ap->ad_kern_index; ctxt.oc_port = pp->ap_index; ctxt.oc_target = -1; ctxt.oc_lun = -1; ctxt.oc_limit = map->NumberOfEntries; ctxt.oc_ver = 2; ctxt.oc_entries = map->entry; ctxt.oc_status = HBA_STATUS_OK; memset(map->entry, 0, sizeof(map->entry[0]) * ctxt.oc_limit); sa_dir_read(SYSFS_LUN_DIR, get_binding_target_mapping, &ctxt); map->NumberOfEntries = ctxt.oc_count; if (ctxt.oc_status == HBA_STATUS_OK && ctxt.oc_count > ctxt.oc_limit) ctxt.oc_status = HBA_STATUS_ERROR_MORE_DATA; return ctxt.oc_status; } /* * Get LUN scsi-generic device name. */ int get_binding_sg_name(struct port_info *lp, HBA_WWN disc_wwpn, HBA_UINT64 fc_lun, char *buf, size_t len) { struct binding_context ctxt; struct port_info *rp; HBA_FCPSCSIENTRYV2 entry; /* * find discovered (remote) port. */ rp = adapter_get_rport_by_wwn(lp, disc_wwpn); if (rp == NULL) return HBA_STATUS_ERROR_ILLEGAL_WWN; memset(&ctxt, 0, sizeof(ctxt)); memset(&entry, 0, sizeof(entry)); ctxt.oc_rport = rp; ctxt.oc_kern_hba = rp->ap_kern_hba; ctxt.oc_port = rp->ap_index; ctxt.oc_target = rp->ap_scsi_target; if (ctxt.oc_target == -1) return ENOENT; ctxt.oc_lun = (int) fc_lun; ctxt.oc_limit = 1; ctxt.oc_ver = 1; ctxt.oc_entries = &entry; sa_dir_read(SYSFS_LUN_DIR, get_binding_target_mapping, &ctxt); if (ctxt.oc_count != 1) return ENOENT; sa_strncpy_safe(buf, len, ctxt.oc_sg, sizeof(ctxt.oc_sg)); return 0; } libhbalinux-1.0.16/bind_impl.h000066400000000000000000000024251214751654400162220ustar00rootroot00000000000000/* * Copyright (c) 2008, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU Lesser General Public License, * version 2.1, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef _BIND_IMPL_H_ #define _BIND_IMPL_H_ HBA_STATUS get_binding_capability(HBA_HANDLE, HBA_WWN, HBA_BIND_CAPABILITY *); HBA_STATUS get_binding_support(HBA_HANDLE, HBA_WWN, HBA_BIND_CAPABILITY *); HBA_STATUS set_binding_support(HBA_HANDLE, HBA_WWN, HBA_BIND_CAPABILITY); HBA_STATUS get_binding_target_mapping_v1(HBA_HANDLE, HBA_FCPTARGETMAPPING *); HBA_STATUS get_binding_target_mapping_v2(HBA_HANDLE, HBA_WWN, HBA_FCPTARGETMAPPINGV2 *); int get_binding_sg_name(struct port_info *, HBA_WWN, HBA_UINT64, char *, size_t); #endif /* _BIND_IMPL_H_ */ libhbalinux-1.0.16/bootstrap.sh000077500000000000000000000000501214751654400164600ustar00rootroot00000000000000#! /bin/sh exec autoreconf --install -s libhbalinux-1.0.16/build.sh000077500000000000000000000016011214751654400155450ustar00rootroot00000000000000#!/bin/sh # This script parses the package name and version out of configure.ac, # uses them to assemble the names of the distribution tar.gz and source rpm, # then calls make to generate those files. # Any arguments will be passed on to configure when building the tarball. AC_INIT=`grep AC_INIT configure.ac` PACKAGE=`echo ${AC_INIT} | awk 'BEGIN { FS="[][]" }; { print $2 };'` VERSION=`echo ${AC_INIT} | awk 'BEGIN { FS="[][]" }; { print $4 };'` tgz=${PACKAGE}-${VERSION}.tar.gz srpm=${PACKAGE}-${VERSION}-1.src.rpm rm -f ${tgz} ${srpm} make -f - <build_date) == NULL) memset(&ap->build_date, 0, sizeof(ap->build_date)); strcpy(ap->VName, HBA_API_VENDOR); strcpy(ap->VVersion, HBA_API_VERSION); return HBA_STATUS_OK; } #endif /* * initialize the library after load. */ static HBA_STATUS load_library(void) { adapter_init(); return HBA_STATUS_OK; } static HBA_STATUS free_library(void) { adapter_shutdown(); adapter_destroy_all(); return HBA_STATUS_OK; } static HBA_ENTRYPOINTSV2 vendor_lib_entrypoints = { .GetVersionHandler = get_library_version, .LoadLibraryHandler = load_library, .FreeLibraryHandler = free_library, .GetNumberOfAdaptersHandler = adapter_get_count, .GetAdapterNameHandler = adapter_get_name, .OpenAdapterHandler = adapter_open, .CloseAdapterHandler = adapter_close, .GetAdapterAttributesHandler = adapter_get_attr, .GetAdapterPortAttributesHandler = adapter_get_port_attr, .GetPortStatisticsHandler = get_port_statistics, .GetDiscoveredPortAttributesHandler = adapter_get_rport_attr, .GetPortAttributesByWWNHandler = NULL, /* adapter_get_port_attr_by_wwn, */ /* Next function deprecated but still supported */ .SendCTPassThruHandler = NULL, .RefreshInformationHandler = NULL, .ResetStatisticsHandler = NULL, /* Next function deprecated but still supported */ .GetFcpTargetMappingHandler = get_binding_target_mapping_v1, /* Next function depricated but still supported */ .GetFcpPersistentBindingHandler = NULL, .GetEventBufferHandler = NULL, .SetRNIDMgmtInfoHandler = NULL, .GetRNIDMgmtInfoHandler = NULL, /* Next function deprecated but still supported */ .SendRNIDHandler = NULL, .ScsiInquiryHandler = scsi_inquiry_v1, .ReportLUNsHandler = scsi_report_luns_v1, .ReadCapacityHandler = scsi_read_capacity_v1, /* V2 handlers */ .OpenAdapterByWWNHandler = NULL, /* adapter_open_by_wwn, */ .GetFcpTargetMappingV2Handler = get_binding_target_mapping_v2, .SendCTPassThruV2Handler = NULL, .RefreshAdapterConfigurationHandler = NULL, .GetBindingCapabilityHandler = NULL, /* get_binding_capability, */ .GetBindingSupportHandler = NULL, /* get_binding_support, */ .SetBindingSupportHandler = NULL, /* set_binding_support, */ .SetPersistentBindingV2Handler = NULL, .GetPersistentBindingV2Handler = NULL, .RemovePersistentBindingHandler = NULL, .RemoveAllPersistentBindingsHandler = NULL, .SendRNIDV2Handler = NULL, .ScsiInquiryV2Handler = scsi_inquiry_v2, .ScsiReportLUNsV2Handler = scsi_report_luns_v2, .ScsiReadCapacityV2Handler = scsi_read_capacity_v2, .GetVendorLibraryAttributesHandler = NULL, /* get_vendor_lib_attrs, */ .RemoveCallbackHandler = NULL, .RegisterForAdapterAddEventsHandler = NULL, .RegisterForAdapterEventsHandler = NULL, .RegisterForAdapterPortEventsHandler = NULL, .RegisterForAdapterPortStatEventsHandler = NULL, .RegisterForTargetEventsHandler = NULL, .RegisterForLinkEventsHandler = NULL, .SendRPLHandler = NULL, .SendRPSHandler = NULL, .SendSRLHandler = NULL, .SendLIRRHandler = NULL, .GetFC4StatisticsHandler = get_port_fc4_statistics, .GetFCPStatisticsHandler = NULL, .SendRLSHandler = NULL, }; /** * Function called by a version 1 common HBAAPI library to get our entry points. * * @arg ep pointer to entrypoints structure where we store our * function pointers. * @returns HBA_STATUS. */ HBA_STATUS HBA_RegisterLibrary(HBA_ENTRYPOINTS *ep) { memcpy(ep, &vendor_lib_entrypoints, sizeof(HBA_ENTRYPOINTS)); return HBA_STATUS_OK; } /** * Function called by the common HBAAPI library to get our entry points. * * @arg ep pointer to entrypoints structure where we store our * function pointers. * @returns HBA_STATUS. */ HBA_STATUS HBA_RegisterLibraryV2(HBA_ENTRYPOINTSV2 *ep) { *ep = vendor_lib_entrypoints; /* structure copy */ return HBA_STATUS_OK; } libhbalinux-1.0.16/libhbalinux.pc.in000066400000000000000000000003321214751654400173410ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: libhbalinux Description: SNIA HBA API vendor library for Linux Version: @VERSION@ Cflags: -I${includedir} Libs: -L${libdir} -ldl libhbalinux-1.0.16/libhbalinux.spec.in000066400000000000000000000021231214751654400176710ustar00rootroot00000000000000Name: libhbalinux Version: @PACKAGE_VERSION@ Release: 1%{?dist} Summary: FC-HBAAPI implementation using scsi_transport_fc interfaces Group: System Environment/Libraries License: LGPLv2 URL: http://www.open-fcoe.org Source0: http://www.open-fcoe.org/openfc/%{name}-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: libHBAAPI-devel libpciaccess-devel Requires: libHBAAPI %description SNIA HBAAPI vendor library built on top of the scsi_transport_fc interfaces %prep %setup -q %build %configure --disable-static make %{?_smp_mflags} %install rm -rf $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';' find $RPM_BUILD_ROOT -name '*.so' -exec rm -f {} ';' %clean rm -rf $RPM_BUILD_ROOT %post -p /sbin/ldconfig %postun -p /sbin/ldconfig %files %defattr(-,root,root,-) %doc README %doc COPYING %{_libdir}/*.so.* %changelog * Mon Mar 2 2009 Chris Leech - 1.0.7-1 - initial build libhbalinux-1.0.16/lport.c000066400000000000000000000500661214751654400154240ustar00rootroot00000000000000/* * Copyright (c) 2008, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU Lesser General Public License, * version 2.1, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include "utils.h" #include "api_lib.h" #include "adapt_impl.h" #ifndef HBA_STATUS_ERROR_ILLEGAL_FCID #define HBA_STATUS_ERROR_ILLEGAL_FCID 33 /* defined after HBA-API 2.2 */ #endif #define SEND_CT_TIMEOUT (3 * 1000) /* timeout in milliseconds */ /* * The following are temporary settings until we can find a way to * collect these information. */ #define HBA_ROM_VERSION "" #define HBA_FW_VERSION "" #define HBA_VENDOR_SPECIFIC_ID 0 /* * table of /sys port types strings to HBA-API values. */ struct sa_nameval port_types_table[] = { { "Unknown", HBA_PORTTYPE_UNKNOWN }, { "Other", HBA_PORTTYPE_OTHER }, { "Not Present", HBA_PORTTYPE_NOTPRESENT }, { "NPort (fabric via point-to-point)", HBA_PORTTYPE_NPORT }, { "NLPort (fabric via loop)", HBA_PORTTYPE_NLPORT }, { "LPort (private loop)", HBA_PORTTYPE_LPORT }, { "Point-To-Point (direct nport connection)", HBA_PORTTYPE_PTP }, { "NPIV VPORT", HBA_PORTTYPE_NPORT }, { NULL, 0 } }; /* * table of /sys port state strings to HBA-API values. */ struct sa_nameval port_states_table[] = { { "Not Present", HBA_PORTSTATE_UNKNOWN }, { "Online", HBA_PORTSTATE_ONLINE }, { "Offline", HBA_PORTSTATE_OFFLINE }, { "Blocked", HBA_PORTSTATE_UNKNOWN }, { "Bypassed", HBA_PORTSTATE_BYPASSED }, { "Diagnostics", HBA_PORTSTATE_DIAGNOSTICS }, { "Linkdown", HBA_PORTSTATE_LINKDOWN }, { "Error", HBA_PORTSTATE_ERROR }, { "Loopback", HBA_PORTSTATE_LOOPBACK }, { "Deleted", HBA_PORTSTATE_UNKNOWN }, { NULL, 0 } }; /* * table of /sys port speed strings to HBA-API values. */ struct sa_nameval port_speeds_table[] = { { "Unknown", HBA_PORTSPEED_UNKNOWN }, { "1 Gbit", HBA_PORTSPEED_1GBIT }, { "2 Gbit", HBA_PORTSPEED_2GBIT }, { "10 Gbit", HBA_PORTSPEED_10GBIT }, { "Not Negotiated", HBA_PORTSPEED_NOT_NEGOTIATED }, { NULL, 0 } }; /* * parse strings from /sys port speed/support_speeds files * and convert them to bitmasks for the HBA_PORTSPEED supported * Format expected: "1 Gbit[, 10 Gbit]", etc. */ static int sys_read_speed(const char *dir, const char *file, char *buf, size_t buflen, HBA_PORTSPEED *speeds) { int rc = 0; u_int32_t val = 0; int len = 0; char *cp; struct sa_nameval *tp = port_speeds_table; rc = sa_sys_read_line(dir, file, buf, buflen); if (rc == 0 && strstr(buf, "Unknown") == NULL) { for (cp = buf; *cp != '\0';) { for (; tp->nv_name != NULL; tp++) { len = strlen(tp->nv_name); if (strncasecmp(tp->nv_name, cp, len) == 0) { val |= tp->nv_val; cp += len; break; } } if (*cp == '\0') break; if (*cp == ',') { cp++; if (*cp == ' ') cp++; } else break; /* invalid string */ } } *speeds = val; return rc; } /* * Code for OpenFC-supported adapters. */ static int counting_rports(struct dirent *dp, void *arg) { int *count = (int *)arg; if (!strstr(dp->d_name, "rport-")) return HBA_STATUS_OK; (*count)++; return HBA_STATUS_OK; } static int check_ifindex(struct dirent *dp, void *arg) { char *ifindex = (char *)arg; char hba_dir[256]; char buf[256]; int rc; snprintf(hba_dir, sizeof(hba_dir), SYSFS_HBA_DIR "/%s", dp->d_name); memset(buf, 0, sizeof(buf)); rc = sa_sys_read_line(hba_dir, "ifindex", buf, sizeof(buf) - 1); if (rc) return 0; if (!strncmp(ifindex, buf, sizeof(buf))) { strcpy(arg, dp->d_name); return 1; } return 0; } /* * find_phys_if - find the regular network interface name that * has the ifindex that matches the specified iflink. * This ifname will be used to find the PCI info * of a VLAN interface. * hba_dir: hba_dir of VLAN interface. * buf: returns ifname of regular network interface. */ static int find_phys_if(char *hba_dir, char *buf, size_t len) { int rc; rc = sa_sys_read_line(hba_dir, "iflink", buf, len); if (rc) return 1; /* * Search for the regular network interface and * return the interface name in the buf. */ sa_dir_read(SYSFS_HBA_DIR, check_ifindex, buf); return 0; } static int sysfs_scan(struct dirent *dp, void *arg) { HBA_ADAPTERATTRIBUTES *atp; HBA_PORTATTRIBUTES *pap; HBA_WWN wwnn; struct hba_info hba_info; struct adapter_info *ap; struct port_info *pp; char host_dir[80], hba_dir[80], drv_dir[80]; char dev_dir[128]; char ifname[20], buf[256]; char *driverName; int data[32], rc, i; char *cp; char *saveptr; /* for strtok_r */ unsigned int ifindex; unsigned int iflink; memset(&hba_info, 0, sizeof(hba_info)); /* * Create a new HBA entry (ap) for the local port * We will create a new HBA entry for each local port. */ ap = malloc(sizeof(*ap)); if (!ap) { fprintf(stderr, "%s: malloc failed, errno=0x%x\n", __func__, errno); return HBA_STATUS_ERROR; } memset(ap, 0, sizeof(*ap)); ap->ad_kern_index = atoi(dp->d_name + sizeof("host") - 1); ap->ad_port_count = 1; /* atp points to the HBA attributes structure */ atp = &ap->ad_attr; /* * Create a new local port entry */ pp = malloc(sizeof(*pp)); if (pp == NULL) { fprintf(stderr, "%s: malloc for local port %d failed," " errno=0x%x\n", __func__, ap->ad_port_count - 1, errno); free(ap); return 0; } memset(pp, 0, sizeof(*pp)); pp->ap_adapt = ap; pp->ap_index = ap->ad_port_count - 1; pp->ap_kern_hba = atoi(dp->d_name + sizeof("host") - 1); /* pap points to the local port attributes structure */ pap = &pp->ap_attr; /* Construct the host directory name from the input name */ snprintf(host_dir, sizeof(host_dir), SYSFS_HOST_DIR "/%s", dp->d_name); rc = sa_sys_read_line(host_dir, "symbolic_name", buf, sizeof(buf)); /* Get PortSymbolicName */ sa_strncpy_safe(pap->PortSymbolicName, sizeof(pap->PortSymbolicName), buf, sizeof(buf)); /* Skip the HBA if it isn't OpenFC */ cp = strstr(pap->PortSymbolicName, " over "); if (!cp) goto skip; /* * See if /device is a PCI symlink. * If not, try it as a net device. */ snprintf(dev_dir, sizeof(dev_dir), "%s/device", host_dir); i = readlink(dev_dir, buf, sizeof(buf) - 1); if (i < 0) i = 0; buf[i] = '\0'; if (strstr(buf, "devices/pci") && !strstr(buf, "/net/")) { snprintf(hba_dir, sizeof(hba_dir), "%s/device/..", host_dir); } else { /* assume a net device */ cp += 6; sa_strncpy_safe(ifname, sizeof(ifname), cp, strlen(cp)); snprintf(hba_dir, sizeof(hba_dir), SYSFS_HBA_DIR "/%s", ifname); /* * Try as VLAN device or other virtual net device. * If this is the case, ifindex and iflink will be different. * iflink is the ifindex of the physical device. */ rc = sa_sys_read_u32(hba_dir, "ifindex", &ifindex); if (rc < 0) goto skip; rc = sa_sys_read_u32(hba_dir, "iflink", &iflink); if (rc < 0) goto skip; if (ifindex != iflink) { rc = find_phys_if(hba_dir, buf, sizeof(buf)); if (rc) goto skip; strncpy(ifname, buf, sizeof(ifname)); } snprintf(hba_dir, sizeof(hba_dir), SYSFS_HBA_DIR "/%s/device", ifname); i = readlink(hba_dir, buf, sizeof(buf) - 1); if (i < 0) goto skip; buf[i] = '\0'; } /* * Assume a PCI symlink value is in buf. * Back up to the last path component that looks like a PCI element. * A sample link value is like: * ../../devices/pci*.../0000:03:00.0 */ rc = 0; do { cp = strrchr(buf, '/'); if (!cp) break; rc = sscanf(cp + 1, "%x:%x:%x.%x", &hba_info.domain, &hba_info.bus, &hba_info.dev, &hba_info.func); if (rc == 4) break; *cp = '\0'; } while (cp && cp > buf); if (rc != 4) goto skip; /* * Save the host directory and the hba directory * in local port structure */ sa_strncpy_safe(pp->host_dir, sizeof(pp->host_dir), host_dir, sizeof(host_dir)); /* Get NodeWWN */ rc = sys_read_wwn(pp->host_dir, "node_name", &wwnn); memcpy(&pap->NodeWWN, &wwnn, sizeof(wwnn)); /* Get PortWWN */ rc = sys_read_wwn(pp->host_dir, "port_name", &pap->PortWWN); /* Get PortFcId */ rc = sa_sys_read_u32(pp->host_dir, "port_id", &pap->PortFcId); /* Get PortType */ rc = sa_sys_read_line(pp->host_dir, "port_type", buf, sizeof(buf)); rc = sa_enum_encode(port_types_table, buf, &pap->PortType); /* Get PortState */ rc = sa_sys_read_line(pp->host_dir, "port_state", buf, sizeof(buf)); rc = sa_enum_encode(port_states_table, buf, &pap->PortState); /* Get PortSpeed */ rc = sys_read_speed(pp->host_dir, "speed", buf, sizeof(buf), &pap->PortSpeed); /* Get PortSupportedSpeed */ rc = sys_read_speed(pp->host_dir, "supported_speeds", buf, sizeof(buf), &pap->PortSupportedSpeed); /* Get PortMaxFrameSize */ rc = sa_sys_read_line(pp->host_dir, "maxframe_size", buf, sizeof(buf)); sscanf(buf, "%d", &pap->PortMaxFrameSize); /* Get PortSupportedFc4Types */ rc = sa_sys_read_line(pp->host_dir, "supported_fc4s", buf, sizeof(buf)); sscanf(buf, "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x " "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x " "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x " "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", &data[0], &data[1], &data[2], &data[3], &data[4], &data[5], &data[6], &data[7], &data[8], &data[9], &data[10], &data[11], &data[12], &data[13], &data[14], &data[15], &data[16], &data[17], &data[18], &data[19], &data[20], &data[21], &data[22], &data[23], &data[24], &data[25], &data[26], &data[27], &data[28], &data[29], &data[30], &data[31]); for (i = 0; i < 32; i++) pap->PortSupportedFc4Types.bits[i] = data[i]; /* Get PortActiveFc4Types */ rc = sa_sys_read_line(pp->host_dir, "active_fc4s", buf, sizeof(buf)); sscanf(buf, "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x " "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x " "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x " "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", &data[0], &data[1], &data[2], &data[3], &data[4], &data[5], &data[6], &data[7], &data[8], &data[9], &data[10], &data[11], &data[12], &data[13], &data[14], &data[15], &data[16], &data[17], &data[18], &data[19], &data[20], &data[21], &data[22], &data[23], &data[24], &data[25], &data[26], &data[27], &data[28], &data[29], &data[30], &data[31]); for (i = 0; i < 32; i++) pap->PortActiveFc4Types.bits[i] = data[i]; /* Get FabricName */ rc = sys_read_wwn(pp->host_dir, "fabric_name", &pap->FabricName); /* Get PortSupportedClassofService */ rc = sa_sys_read_line(pp->host_dir, "supported_classes", buf, sizeof(buf)); cp = strstr(buf, "Class"); if (cp) pap->PortSupportedClassofService = *(cp + 6) - '0'; /* Get OSDeviceName */ sa_strncpy_safe(pap->OSDeviceName, sizeof(pap->OSDeviceName), dp->d_name, sizeof(dp->d_name)); /* Get NumberofDiscoveredPorts */ snprintf(buf, sizeof(buf), "%s/device", pp->host_dir); sa_dir_read(buf, counting_rports, &pap->NumberofDiscoveredPorts); /* * Add the local port structure into local port table within * the HBA structure. */ if (sa_table_insert(&ap->ad_ports, pp->ap_index, pp) < 0) { fprintf(stderr, "%s: insert of HBA %d port %d failed\n", __func__, ap->ad_kern_index, pp->ap_index); goto skip; } /* Create adapter name */ snprintf(buf, sizeof(buf), "fcoe:%s", ifname); ap->ad_name = strdup(buf); /* Get vendor_id */ rc = sa_sys_read_u32(hba_dir, "vendor", &hba_info.vendor_id); /* Get device_id */ rc = sa_sys_read_u32(hba_dir, "device", &hba_info.device_id); /* Get subsystem_vendor_id */ rc = sa_sys_read_u32(hba_dir, "subsystem_vendor", &hba_info.subsystem_vendor_id); /* Get subsystem_device_id */ rc = sa_sys_read_u32(hba_dir, "subsystem_device", &hba_info.subsystem_device_id); /* Get device_class */ rc = sa_sys_read_u32(hba_dir, "class", &hba_info.device_class); hba_info.device_class = hba_info.device_class>>8; /* * Get Hardware Information via PCI Library */ (void) find_pci_device(&hba_info); /* Get Number of Ports */ atp->NumberOfPorts = hba_info.NumberOfPorts; /* Get Manufacturer */ sa_strncpy_safe(atp->Manufacturer, sizeof(atp->Manufacturer), hba_info.Manufacturer, sizeof(hba_info.Manufacturer)); /* Get SerialNumber */ sa_strncpy_safe(atp->SerialNumber, sizeof(atp->SerialNumber), hba_info.SerialNumber, sizeof(hba_info.SerialNumber)); /* Get ModelDescription */ sa_strncpy_safe(atp->ModelDescription, sizeof(atp->ModelDescription), hba_info.ModelDescription, sizeof(hba_info.ModelDescription)); if (!strncmp(hba_info.ModelDescription, "Unknown", sizeof(hba_info.ModelDescription))) { snprintf(atp->ModelDescription, sizeof(atp->ModelDescription), "[%04x:%04x]-[%04x:%04x]-(%04x)", hba_info.vendor_id, hba_info.device_id, hba_info.subsystem_vendor_id, hba_info.subsystem_device_id, hba_info.device_class); /* * Get Model * * If the device is a newly developed product, and * the model description is not in pci.ids yet, use * the model description constructed above as the * model string. */ sa_strncpy_safe(atp->Model, sizeof(atp->Model), atp->ModelDescription, sizeof(atp->ModelDescription)); } /* * Get Model * * If the device name has already been added into * the pci.ids file, use the first word of the model * description as the model. If the space after the * first word is not found (new product), use the * model description as the model. */ sa_strncpy_safe(buf, sizeof(buf), atp->ModelDescription, sizeof(atp->ModelDescription)); if (strtok_r(buf, " ", &saveptr)) sa_strncpy_safe(atp->Model, sizeof(atp->Model), buf, strnlen(buf, sizeof(buf))); else sa_strncpy_safe(atp->Model, sizeof(atp->Model), atp->ModelDescription, sizeof(atp->ModelDescription)); /* Get HardwareVersion */ sa_strncpy_safe(atp->HardwareVersion, sizeof(atp->HardwareVersion), hba_info.HardwareVersion, sizeof(hba_info.HardwareVersion)); /* Get OptionROMVersion (TODO) */ sa_strncpy_safe(atp->OptionROMVersion, sizeof(atp->OptionROMVersion), HBA_ROM_VERSION, sizeof(HBA_ROM_VERSION)); /* Get FirmwareVersion (TODO) */ sa_strncpy_safe(atp->FirmwareVersion, sizeof(atp->FirmwareVersion), HBA_FW_VERSION, sizeof(HBA_FW_VERSION)); /* Get VendorSpecificID (TODO) */ atp->VendorSpecificID = HBA_VENDOR_SPECIFIC_ID; /* Get DriverVersion */ rc = sa_sys_read_line(hba_dir, SYSFS_MODULE_VER, atp->DriverVersion, sizeof(atp->DriverVersion)); /* Get NodeSymbolicName */ sa_strncpy_safe(atp->NodeSymbolicName, sizeof(atp->NodeSymbolicName), ap->ad_name, sizeof(atp->NodeSymbolicName)); /* Get NodeWWN - The NodeWWN is the same as * the NodeWWN of the local port. */ memcpy((char *)&atp->NodeWWN, (char *)&pap->NodeWWN, sizeof(pap->NodeWWN)); /* Get DriverName */ snprintf(drv_dir, sizeof(drv_dir), "%s" SYSFS_MODULE , hba_dir); i = readlink(drv_dir, buf, sizeof(buf)); if (i < 0) i = 0; buf[i] = '\0'; if (!strstr(buf, "module")) { /* * Does not find "module" in the string. * This should not happen. In this case, set * the driver name to "Unknown". */ driverName = "Unknown"; } else driverName = strstr(buf, "module") + 7; sa_strncpy_safe(atp->DriverName, sizeof(atp->DriverName), driverName, sizeof(atp->DriverName)); /* * Give HBA to library */ rc = adapter_create(ap); if (rc != HBA_STATUS_OK) { fprintf(stderr, "%s: adapter_create failed, status=%d\n", __func__, rc); adapter_destroy(ap); /* free adapter and ports */ } return 0; skip: free(pp); free(ap); return 0; } void copy_wwn(HBA_WWN *dest, fc_wwn_t src) { dest->wwn[0] = (u_char) (src >> 56); dest->wwn[1] = (u_char) (src >> 48); dest->wwn[2] = (u_char) (src >> 40); dest->wwn[3] = (u_char) (src >> 32); dest->wwn[4] = (u_char) (src >> 24); dest->wwn[5] = (u_char) (src >> 16); dest->wwn[6] = (u_char) (src >> 8); dest->wwn[7] = (u_char) src; } /* Test for a non-zero WWN */ int is_wwn_nonzero(HBA_WWN *wwn) { return (wwn->wwn[0] | wwn->wwn[1] | wwn->wwn[2] | wwn->wwn[3] | wwn->wwn[4] | wwn->wwn[5] | wwn->wwn[6] | wwn->wwn[7]) != 0; } int sys_read_wwn(const char *dir, const char *file, HBA_WWN *wwn) { int rc; u_int64_t val; rc = sa_sys_read_u64(dir, file, &val); if (rc == 0) copy_wwn(wwn, val); return rc; } /* Port Statistics */ HBA_STATUS sysfs_get_port_stats(char *dir, HBA_PORTSTATISTICS *sp) { int rc; rc = sa_sys_read_u64(dir, "seconds_since_last_reset", (u_int64_t *)&sp->SecondsSinceLastReset); rc |= sa_sys_read_u64(dir, "tx_frames", (u_int64_t *)&sp->TxFrames); rc |= sa_sys_read_u64(dir, "tx_words", (u_int64_t *)&sp->TxWords); rc |= sa_sys_read_u64(dir, "rx_frames", (u_int64_t *)&sp->RxFrames); rc |= sa_sys_read_u64(dir, "rx_words", (u_int64_t *)&sp->RxWords); rc |= sa_sys_read_u64(dir, "lip_count", (u_int64_t *)&sp->LIPCount); rc |= sa_sys_read_u64(dir, "nos_count", (u_int64_t *)&sp->NOSCount); rc |= sa_sys_read_u64(dir, "error_frames", (u_int64_t *)&sp->ErrorFrames); rc |= sa_sys_read_u64(dir, "dumped_frames", (u_int64_t *)&sp->DumpedFrames); rc |= sa_sys_read_u64(dir, "link_failure_count", (u_int64_t *)&sp->LinkFailureCount); rc |= sa_sys_read_u64(dir, "loss_of_sync_count", (u_int64_t *)&sp->LossOfSyncCount); rc |= sa_sys_read_u64(dir, "loss_of_signal_count", (u_int64_t *)&sp->LossOfSignalCount); rc |= sa_sys_read_u64(dir, "prim_seq_protocol_err_count", (u_int64_t *)&sp->PrimitiveSeqProtocolErrCount); rc |= sa_sys_read_u64(dir, "invalid_tx_word_count", (u_int64_t *)&sp->InvalidTxWordCount); rc |= sa_sys_read_u64(dir, "invalid_crc_count", (u_int64_t *)&sp->InvalidCRCCount); return rc; } /* Port FC-4 Statistics */ HBA_STATUS sysfs_get_port_fc4stats(char *dir, HBA_FC4STATISTICS *fc4sp) { int rc; rc = sa_sys_read_u64(dir, "fcp_input_requests", (u_int64_t *)&fc4sp->InputRequests); rc |= sa_sys_read_u64(dir, "fcp_output_requests", (u_int64_t *)&fc4sp->OutputRequests); rc |= sa_sys_read_u64(dir, "fcp_control_requests", (u_int64_t *)&fc4sp->ControlRequests); rc |= sa_sys_read_u64(dir, "fcp_input_megabytes", (u_int64_t *)&fc4sp->InputMegabytes); rc |= sa_sys_read_u64(dir, "fcp_output_megabytes", (u_int64_t *)&fc4sp->OutputMegabytes); return rc; } /* * Open device and read adapter info if available. */ void adapter_init(void) { sa_dir_read(SYSFS_HOST_DIR, sysfs_scan, NULL); } void adapter_shutdown(void) { } HBA_STATUS get_port_statistics(HBA_HANDLE handle, HBA_UINT32 port, HBA_PORTSTATISTICS *sp) { struct port_info *pp; char dir[80]; int rc; memset(sp, 0xff, sizeof(*sp)); /* unsupported statistics give -1 */ pp = adapter_get_port(handle, port); if (pp == NULL) { fprintf(stderr, "%s: lookup failed. handle 0x%x port 0x%x\n", __func__, handle, port); return HBA_STATUS_ERROR; } snprintf(dir, sizeof(dir), "%s/statistics", pp->host_dir); rc = sysfs_get_port_stats(dir, sp); if (rc != 0) { fprintf(stderr, "%s: sysfs_get_port_stats() failed," " hba index=%d port index=%d, -rc=0x%x\n", __func__, pp->ap_adapt->ad_kern_index, pp->ap_index, -rc); return HBA_STATUS_ERROR; } return HBA_STATUS_OK; } /* * Get FC4 statistics. */ HBA_STATUS get_port_fc4_statistics(HBA_HANDLE handle, HBA_WWN wwn, HBA_UINT8 fc4_type, HBA_FC4STATISTICS *sp) { struct port_info *pp; char dir[80]; int count; int rc; memset(sp, 0xff, sizeof(*sp)); /* unsupported statistics give -1 */ pp = adapter_get_port_by_wwn(handle, wwn, &count); if (count > 1) return HBA_STATUS_ERROR_AMBIGUOUS_WWN; else if (pp == NULL) return HBA_STATUS_ERROR_ILLEGAL_WWN; snprintf(dir, sizeof(dir), "%s/statistics", pp->host_dir); rc = sysfs_get_port_fc4stats(dir, sp); if (rc != 0) { fprintf(stderr, "%s: sysfs_get_port_fc4stats() failed," " hba index=%d port index=%d, -rc=0x%x\n", __func__, pp->ap_adapt->ad_kern_index, pp->ap_index, -rc); return HBA_STATUS_ERROR; } return HBA_STATUS_OK; } libhbalinux-1.0.16/net_types.h000066400000000000000000000267311214751654400163050ustar00rootroot00000000000000/* * Copyright (c) 2008, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU Lesser General Public License, * version 2.1, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef _LIBSA_NET_TYPES_H_ #define _LIBSA_NET_TYPES_H_ #if !defined(NTOHL) #include #endif /* NTOHL */ /* * Type definitions for network order fields in protocol packets. * The access functions below do gets and puts on these structures. */ typedef unsigned char net8_t; /* direct use and assignment allowed */ /* * Aligned network order types. */ typedef struct { u_int16_t net_data; } net16_t; typedef struct { u_int32_t net_data; } net32_t; /* * The 64-bit type only requires 32-bit alignment. */ typedef struct { u_int32_t net_data[2]; /* most significant word first */ } net64_t; /* * 24-bit type. Byte aligned, in spite of the name. */ typedef struct { unsigned char net_data[3]; } net24_t; /* * 48-bit type. Byte aligned. */ typedef struct { unsigned char net_data[6]; } net48_t; /* * Unaligned network order types. * Any of these structures can be byte aligned. No padding is implied. */ typedef struct { unsigned char net_data[2]; } ua_net16_t; typedef struct { unsigned char net_data[4]; } ua_net32_t; typedef struct { unsigned char net_data[8]; } ua_net64_t; /* * Accessor functions. */ /** * net8_get(net) - fetch from a network-order 8-bit field. * * @param net pointer to network-order 8-bit data. * @return the host-order value. */ static inline u_int8_t net8_get(const net8_t * net) { return *net; } /** * net8_put(net, val) - store to a network-order 8-bit field. * * @param net pointer to network-order 8-bit data. * @param val host-order value to be stored at net. */ static inline void net8_put(net8_t * net, u_int8_t val) { *net = val; } /** * net16_get(net) - fetch from a network-order 16-bit field. * * @param net pointer to type net16_t, network-order 16-bit data. * @return the host-order value. */ static inline u_int16_t net16_get(const net16_t * net) { return ntohs(net->net_data); } /** * net16_put(net, val) - store to a network-order 16-bit field. * * @param net pointer to a net16_t, network-order 16-bit data. * @param val host-order value to be stored at net. */ static inline void net16_put(net16_t * net, u_int16_t val) { net->net_data = htons(val); } /** * ua_net16_get(net) - fetch from an unaligned network-order 16-bit field. * * @param net pointer to type ua_net16_t, unaligned, network-order 16-bit data. * @return the host-order value. */ static inline u_int16_t ua_net16_get(const ua_net16_t * net) { return (net->net_data[0] << 8) | net->net_data[1]; } /** * ua_net16_put(net, val) - store to a network-order 16-bit field. * * @param net pointer to a ua_net16_t, network-order 16-bit data. * @param val host-order value to be stored at net. */ static inline void ua_net16_put(ua_net16_t * net, u_int16_t val) { net->net_data[0] = (u_int8_t)((val >> 8) & 0xFF); net->net_data[1] = (u_int8_t)(val & 0xFF); } /** * net24_get(net) - fetch from a network-order 24-bit field. * * @param net pointer to type net24_t, network-order 24-bit data. * @return the host-order value. */ static inline u_int32_t net24_get(const net24_t * net) { return (net->net_data[0] << 16) | (net->net_data[1] << 8) | net->net_data[2]; } /** * net24_put(net, val) - store to a network-order 24-bit field. * * @param net pointer to a net24_t, network-order 24-bit data. * @param val host-order value to be stored at net. */ static inline void net24_put(net24_t * net, u_int32_t val) { net->net_data[0] = (u_int8_t)((val >> 16) & 0xFF); net->net_data[1] = (u_int8_t)((val >> 8) & 0xFF); net->net_data[2] = (u_int8_t)(val & 0xFF); } /** * net32_get(net) - fetch from a network-order 32-bit field. * * @param net pointer to type net32_t, network-order 32-bit data. * @return the host-order value. */ static inline u_int32_t net32_get(const net32_t * net) { return ntohl(net->net_data); } /** * net32_put(net, val) - store to a network-order 32-bit field. * * @param net pointer to a net32_t, network-order 32-bit data. * @param val host-order value to be stored at net. */ static inline void net32_put(net32_t * net, u_int32_t val) { net->net_data = htonl(val); } /** * ua_net32_get(net) - fetch from an unaligned network-order 32-bit field. * * @param net pointer to type ua_net32_t, unaligned, network-order 32-bit data. * @return the host-order value. */ static inline u_int32_t ua_net32_get(const ua_net32_t * net) { return (net->net_data[0] << 24) | (net->net_data[1] << 16) | (net->net_data[2] << 8) | net->net_data[3]; } /** * ua_net32_put(net, val) - store to a network-order 32-bit field. * * @param net pointer to a ua_net32_t, network-order 32-bit data. * @param val host-order value to be stored at net. */ static inline void ua_net32_put(ua_net32_t * net, u_int32_t val) { net->net_data[0] = (u_int8_t)((val >> 24) & 0xFF); net->net_data[1] = (u_int8_t)((val >> 16) & 0xFF); net->net_data[2] = (u_int8_t)((val >> 8) & 0xFF); net->net_data[3] = (u_int8_t)(val & 0xFF); } /** * net48_get(net) - fetch from a network-order 48-bit field. * * @param net pointer to type net48_t, network-order 48-bit data. * @return the host-order value. */ static inline u_int64_t net48_get(const net48_t * net) { return ((u_int64_t) net->net_data[0] << 40) | ((u_int64_t) net->net_data[1] << 32) | ((u_int64_t) net->net_data[2] << 24) | ((u_int64_t) net->net_data[3] << 16) | ((u_int64_t) net->net_data[4] << 8) | (u_int64_t) net->net_data[5]; } /** * net48_put(net, val) - store to a network-order 48-bit field. * * @param net pointer to a net48_t, network-order 48-bit data. * @param val host-order value to be stored at net. */ static inline void net48_put(net48_t * net, u_int64_t val) { net->net_data[0] = (u_int8_t)((val >> 40) & 0xFF); net->net_data[1] = (u_int8_t)((val >> 32) & 0xFF); net->net_data[2] = (u_int8_t)((val >> 24) & 0xFF); net->net_data[3] = (u_int8_t)((val >> 16) & 0xFF); net->net_data[4] = (u_int8_t)((val >> 8) & 0xFF); net->net_data[5] = (u_int8_t)(val & 0xFF); } /** * net64_get(net) - fetch from a network-order 64-bit field. * * @param net pointer to type net64_t, network-order 64-bit data. * @return the host-order value. */ static inline u_int64_t net64_get(const net64_t * net) { return ((u_int64_t) ntohl(net->net_data[0]) << 32) | ntohl(net->net_data[1]); } /** * net64_put(net, val) - store to a network-order 64-bit field. * * @param net pointer to a net64_t, network-order 64-bit data. * @param val host-order value to be stored at net. */ static inline void net64_put(net64_t * net, u_int64_t val) { net->net_data[0] = (u_int32_t)htonl(val >> 32); net->net_data[1] = (u_int32_t)htonl((u_int32_t) val); } /** * ua_net64_get(net) - fetch from an unaligned network-order 64-bit field. * * @param net pointer to type ua_net64_t, unaligned, network-order 64-bit data. * @return the host-order value. */ static inline u_int64_t ua_net64_get(const ua_net64_t * net) { return ((u_int64_t) net->net_data[0] << 56) | ((u_int64_t) net->net_data[1] << 48) | ((u_int64_t) net->net_data[2] << 40) | ((u_int64_t) net->net_data[3] << 32) | ((u_int64_t) net->net_data[4] << 24) | ((u_int64_t) net->net_data[5] << 16) | ((u_int64_t) net->net_data[6] << 8) | (u_int64_t) net->net_data[7]; } /** * ua_net64_put(net, val) - store to a network-order 64-bit field. * * @param net pointer to a ua_net64_t, network-order 64-bit data. * @param val host-order value to be stored at net. */ static inline void ua_net64_put(ua_net64_t * net, u_int64_t val) { net->net_data[0] = (u_int8_t)((val >> 56) & 0xFF); net->net_data[1] = (u_int8_t)((val >> 48) & 0xFF); net->net_data[2] = (u_int8_t)((val >> 40) & 0xFF); net->net_data[3] = (u_int8_t)((val >> 32) & 0xFF); net->net_data[4] = (u_int8_t)((val >> 24) & 0xFF); net->net_data[5] = (u_int8_t)((val >> 16) & 0xFF); net->net_data[6] = (u_int8_t)((val >> 8) & 0xFF); net->net_data[7] = (u_int8_t)(val & 0xFF); } /* * Compile-time initializers for the network-order type structures. * Note that the upper byte of these values is not masked so the * compiler will catch initializers that don't fit in the field. */ /** * NET8_INIT(_val) - initialize a net8_t type. * * @param _val 8-bit value. * @return net8_t network-order value. */ #define NET8_INIT(_val) (_val) /** * NET24_INIT(_val) - initialize a net24_t type. * * @param _val host-order value. * @return net24_t network-order value. */ #define NET24_INIT(_val) { { \ ((_val) >> 16), \ ((_val) >> 8) & 0xff, \ ((_val) >> 0) & 0xff \ } } /** * NET48_INIT(_val) - initialize a net48_t type. * * @param _val host-order value. * @return net48_t network-order value. */ #define NET48_INIT(_val) { { \ ((_val) >> 40), \ ((_val) >> 32) & 0xff, \ ((_val) >> 24) & 0xff, \ ((_val) >> 16) & 0xff, \ ((_val) >> 8) & 0xff, \ ((_val) >> 0) & 0xff \ } } /** * NET16_INIT(_val) - initialize a net16_t type. * * @param _val host-order value. * @return net16_t network-order value. */ #define NET16_INIT(_val) { htons(_val) } /** * UA_NET16_INIT(_val) - initialize an unaligned 16-bit type. * * @param _val host-order value. * @return ua_net24_t network-order value. */ #define UA_NET16_INIT(_val) { { \ ((_val) >> 8), \ ((_val) >> 0) & 0xff \ } } /** * NET32_INIT(_val) - initialize a 32-bit type. * * @param _val host-order value. * @return net32_t network-order value. */ #define NET32_INIT(_val) { htonl(_val) } /** * UA_NET32_INIT(_val) - initialize an unaligned 32-bit type. * * @param _val host-order value. * @return ua_net32_t network-order value. */ #define UA_NET32_INIT(_val) { { \ ((_val) >> 24), \ ((_val) >> 16) & 0xff, \ ((_val) >> 8) & 0xff, \ ((_val) >> 0) & 0xff \ } } /** * UA_NET48_INIT(_val) - initialize an unaligned 48-bit type. * * @param _val host-order value. * @return ua_net48_t network-order value. */ #define UA_NET48_INIT(_val) { { \ ((_val) >> 40), \ ((_val) >> 32) & 0xff, \ ((_val) >> 24) & 0xff, \ ((_val) >> 16) & 0xff, \ ((_val) >> 8) & 0xff, \ ((_val) >> 0) & 0xff \ } } /** * NET64_INIT(_val) - initialize an unaligned 64-bit type. * * @param _val host-order value. * @return ua_net64_t network-order value. */ #define NET64_INIT(_val) { { \ htonl((_val) >> 32), \ htonl((_val) & 0xffffffff) \ } } /** * UA_NET64_INIT(_val) - initialize a 64-bit type. * * @param _val host-order value. * @return net64_t network-order value. */ #define UA_NET64_INIT(_val) { { \ ((_val) >> 56), \ ((_val) >> 48) & 0xff, \ ((_val) >> 40) & 0xff, \ ((_val) >> 32) & 0xff, \ ((_val) >> 24) & 0xff, \ ((_val) >> 16) & 0xff, \ ((_val) >> 8) & 0xff, \ ((_val) >> 0) & 0xff \ } } #endif /* _LIBSA_NET_TYPES_H_ */ libhbalinux-1.0.16/pci.c000066400000000000000000000126141214751654400150340ustar00rootroot00000000000000/* * Copyright (c) 2008, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU Lesser General Public License, * version 2.1, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include "utils.h" #include "adapt_impl.h" #include #include #include static void get_device_serial_number(struct pci_device *dev, struct hba_info *hba_info) { pciaddr_t offset; u_int32_t pcie_cap_header; u_int16_t pcie_cap_id; u_int16_t status; u_int8_t cap_ptr; u_int32_t dword_low = 0; u_int32_t dword_high = 0; int rc; /* Default */ snprintf(hba_info->SerialNumber, sizeof(hba_info->SerialNumber), "Unknown"); /* * Read the Status Register in the PCIe configuration * header space to see if the PCI Capability List is * supported by this device. */ rc = pci_device_cfg_read_u16(dev, &status, PCI_STATUS); if (rc) { fprintf(stderr, "Failed reading PCI Status Register\n"); return; } if (!(status & PCI_STATUS_CAP_LIST)) { printf("PCI capabilities are not supported\n"); return; } /* * Read the offset (cap_ptr) of first entry in the capability list in * the PCI configuration space. */ rc = pci_device_cfg_read_u8(dev, &cap_ptr, PCI_CAPABILITY_LIST); if (rc) { fprintf(stderr, "Failed reading PCI Capability List Register\n"); return; } offset = cap_ptr; /* Search for the PCIe capability */ while (offset) { u_int8_t cap_id; u_int8_t next_cap; rc = pci_device_cfg_read_u8(dev, &cap_id, offset + PCI_CAP_LIST_ID); if (rc) { #if defined(__x86_64__) fprintf(stderr, "Failed reading capability ID at 0x%lx\n", offset + PCI_CAP_LIST_ID); #elif defined(__i386__) fprintf(stderr, "Failed reading capability ID at 0x%llx\n", offset + PCI_CAP_LIST_ID); #endif return; } if (cap_id != PCI_CAP_ID_EXP) { rc = pci_device_cfg_read_u8(dev, &next_cap, offset + PCI_CAP_LIST_NEXT); if (rc) { #if defined(__x86_64__) fprintf(stderr, "Failed reading next capability " "offset at 0x%lx\n", offset + PCI_CAP_LIST_NEXT); #elif defined(__i386__) fprintf(stderr, "Failed reading next capability " "offset at 0x%llx\n", offset + PCI_CAP_LIST_NEXT); #endif return; } offset = (pciaddr_t)next_cap; continue; } /* * PCIe Capability Structure exists! */ /* * The first PCIe extended capability is located at * offset 0x100 in the device configuration space. */ offset = 0x100; do { rc = pci_device_cfg_read_u32(dev, &pcie_cap_header, offset); if (rc) { fprintf(stderr, "Failed reading PCIe config header\n"); return; } /* Get the PCIe Extended Capability ID */ pcie_cap_id = pcie_cap_header & 0xffff; if (pcie_cap_id != PCI_EXT_CAP_ID_DSN) { /* Get the offset of the next capability */ offset = (pciaddr_t)pcie_cap_header >> 20; continue; } /* * Found the serial number register! */ rc = pci_device_cfg_read_u32(dev, &dword_low, offset + 4); rc = pci_device_cfg_read_u32(dev, &dword_high, offset + 8); snprintf(hba_info->SerialNumber, sizeof(hba_info->SerialNumber), "%02X%02X%02X%02X%02X%02X\n", dword_high >> 24, (dword_high >> 16) & 0xff, (dword_high >> 8) & 0xff, (dword_low >> 16) & 0xff, (dword_low >> 8) & 0xff, dword_low & 0xff); break; } while (offset); break; } } static void get_pci_device_info(struct pci_device *dev, struct hba_info *hba_info) { const char *name; u_int8_t revision; char *unknown = "Unknown"; name = pci_device_get_vendor_name(dev); if (!name) name = unknown; sa_strncpy_safe(hba_info->Manufacturer, sizeof(hba_info->Manufacturer), name, sizeof(hba_info->Manufacturer)); name = pci_device_get_device_name(dev); if (!name) name = unknown; sa_strncpy_safe(hba_info->ModelDescription, sizeof(hba_info->ModelDescription), name, sizeof(hba_info->ModelDescription)); /* * Reading hardware revision from PCIe * configuration header space. */ pci_device_cfg_read_u8(dev, &revision, PCI_REVISION_ID); snprintf(hba_info->HardwareVersion, sizeof(hba_info->HardwareVersion), "%02x", revision); hba_info->NumberOfPorts = 1; /* * Searching for serial number in PCIe extended * capabilities space */ get_device_serial_number(dev, hba_info); } HBA_STATUS find_pci_device(struct hba_info *hba_info) { struct pci_device_iterator *iterator; struct pci_device *dev; struct pci_slot_match match; int rc; rc = pci_system_init(); if (rc) { fprintf(stderr, "pci_system_init failed\n"); return HBA_STATUS_ERROR; } match.domain = hba_info->domain; match.bus = hba_info->bus; match.dev = hba_info->dev; match.func = hba_info->func; iterator = pci_slot_match_iterator_create(&match); for (;;) { dev = pci_device_next(iterator); if (!dev) break; get_pci_device_info(dev, hba_info); } pci_system_cleanup(); return HBA_STATUS_OK; } libhbalinux-1.0.16/rport.c000066400000000000000000000124641214751654400154320ustar00rootroot00000000000000/* * Copyright (c) 2008, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU Lesser General Public License, * version 2.1, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include "utils.h" #include "api_lib.h" #include "adapt_impl.h" static int sys_read_port_state(const char *, const char *, u_int32_t *); static int sys_read_classes(const char *, const char *, u_int32_t *); static struct sa_table rports_table; /* table of discovered ports */ /* * Handle a single remote port from the /sys directory entry. * The return value is 0 unless an error is detected which should stop the * directory read. */ static int sysfs_get_rport(struct dirent *dp, void *arg) { struct port_info *rp; HBA_PORTATTRIBUTES *rpa; int rc; u_int32_t hba; u_int32_t port; u_int32_t rp_index; char *rport_dir; char buf[256]; /* * Parse name into bus number, channel number, and remote port number. */ hba = ~0; port = ~0; rp_index = ~0; rc = sscanf(dp->d_name, SYSFS_RPORT_DIR, &hba, &port, &rp_index); if (rc != 3) { fprintf(stderr, "%s: remote port %s didn't parse." " rc %d h 0x%x p 0x%x rp 0x%x\n", __func__, dp->d_name, rc, hba, port, rp_index); return 0; } /* * Allocate a remote port. */ rp = malloc(sizeof(*rp)); if (rp == NULL) { fprintf(stderr, "%s: malloc for remote port %s failed," " errno=0x%x\n", __func__, dp->d_name, errno); return ENOMEM; } memset(rp, 0, sizeof(*rp)); rp->ap_kern_hba = hba; rp->ap_index = port; rp->ap_disc_index = rp_index; rpa = &rp->ap_attr; snprintf(rpa->OSDeviceName, sizeof(rpa->OSDeviceName), "%s/%s", SYSFS_RPORT_ROOT, dp->d_name); rport_dir = rpa->OSDeviceName; rc = 0; rc |= sys_read_wwn(rport_dir, "node_name", &rpa->NodeWWN); rc |= sys_read_wwn(rport_dir, "port_name", &rpa->PortWWN); rc |= sa_sys_read_u32(rport_dir, "port_id", &rpa->PortFcId); rc |= sa_sys_read_u32(rport_dir, "scsi_target_id", &rp->ap_scsi_target); sa_sys_read_line(rport_dir, "maxframe_size", buf, sizeof(buf)); sscanf(buf, "%d", &rpa->PortMaxFrameSize); rc |= sys_read_port_state(rport_dir, "port_state", &rpa->PortState); rc |= sys_read_classes(rport_dir, "supported_classes", &rpa->PortSupportedClassofService); if (rc != 0 || sa_table_append(&rports_table, rp) < 0) { if (rc != 0) fprintf(stderr, "%s: errors (%x) from /sys reads in %s\n", __func__, rc, dp->d_name); else fprintf(stderr, "%s: sa_table_append error on rport %s\n", __func__, dp->d_name); free(rp); } return 0; } /* * Get remote port information from /sys. */ static void sysfs_find_rports(void) { sa_dir_read(SYSFS_RPORT_ROOT, sysfs_get_rport, NULL); } /* * Read port state as formatted by scsi_transport_fc.c in the linux kernel. */ static int sys_read_port_state(const char *dir, const char *file, u_int32_t *statep) { char buf[256]; int rc; rc = sa_sys_read_line(dir, file, buf, sizeof(buf)); if (rc == 0) { rc = sa_enum_encode(port_states_table, buf, statep); if (rc != 0) fprintf(stderr, "%s: parse error. file %s/%s line '%s'\n", __func__, dir, file, buf); } return rc; } /* * Read class list as formatted by scsi_transport_fc.c in the linux kernel. * Format is expected to be "Class 3[, Class 4]..." * Actually accepts "[Class ]3[,[ ][Class ]4]..." (i.e., "Class" and spaces * are optional). */ static int sys_read_classes(const char *dir, const char *file, u_int32_t *classp) { char buf[256]; int rc; u_int32_t val; char *cp; char *ep; *classp = 0; rc = sa_sys_read_line(dir, file, buf, sizeof(buf)); if (rc == 0 && strstr(buf, "unspecified") == NULL) { for (cp = buf; *cp != '\0'; cp = ep) { if (strncmp(cp, "Class ", 6) == 0) cp += 6; val = strtoul(cp, &ep, 10); *classp |= 1 << val; if (*ep == '\0') break; if (*ep == ',') { ep++; if (*ep == ' ') ep++; } else { fprintf(stderr, "%s: parse error. file %s/%s " "line '%s' ep '%c'\n", __func__, dir, file, buf, *ep); rc = -1; break; } } } return rc; } /* * Get all discovered ports for a particular port using /sys. */ void get_rport_info(struct port_info *pp) { struct port_info *rp; int rp_count = 0; int ri; if (rports_table.st_size == 0) sysfs_find_rports(); for (ri = 0; ri < rports_table.st_size; ri++) { rp = sa_table_lookup(&rports_table, ri); if (rp != NULL) { if (rp->ap_kern_hba == pp->ap_kern_hba && rp->ap_index == pp->ap_index && rp->ap_adapt == NULL) { rp->ap_adapt = pp->ap_adapt; if (sa_table_lookup(&pp->ap_rports, rp->ap_disc_index)) { fprintf(stderr, "%s: discovered port exists. " "hba %x port %x rport %x\n", __func__, pp->ap_kern_hba, pp->ap_index, rp->ap_disc_index); } sa_table_insert(&pp->ap_rports, rp->ap_disc_index, rp); } rp_count++; } } } libhbalinux-1.0.16/scsi.c000066400000000000000000000116141214751654400152210ustar00rootroot00000000000000/* * Copyright (c) 2008, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU Lesser General Public License, * version 2.1, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include "utils.h" #include "api_lib.h" #include "adapt_impl.h" #include "bind_impl.h" #include "fc_scsi.h" /* * Inquiry V1. */ HBA_STATUS scsi_inquiry_v1(HBA_HANDLE handle, HBA_WWN disc_wwpn, HBA_UINT64 fc_lun, HBA_UINT8 evpd, HBA_UINT32 page_code, void *resp, HBA_UINT32 resp_len, void *sense, HBA_UINT32 sense_len) { struct port_info *pp; char sg_name[50]; HBA_UINT8 stat; HBA_STATUS status; /* * Find port. */ pp = adapter_get_port(handle, 0); if (pp == NULL) return HBA_STATUS_ERROR_INVALID_HANDLE; if (get_binding_sg_name( pp, disc_wwpn, fc_lun, sg_name, sizeof(sg_name)) != 0) return HBA_STATUS_ERROR_TARGET_LUN; status = sg_issue_inquiry(sg_name, evpd ? SCSI_INQF_EVPD : 0, page_code, resp, &resp_len, &stat, sense, &sense_len); if (status == HBA_STATUS_OK && stat == SCSI_ST_CHECK) status = HBA_STATUS_SCSI_CHECK_CONDITION; return status; } /* * Inquiry V2. */ HBA_STATUS scsi_inquiry_v2(HBA_HANDLE handle, HBA_WWN wwpn, HBA_WWN disc_wwpn, HBA_UINT64 fc_lun, HBA_UINT8 cdb_byte1, HBA_UINT8 cdb_byte2, void *resp, HBA_UINT32 *resp_lenp, HBA_UINT8 *statp, void *sense, HBA_UINT32 *sense_lenp) { struct port_info *pp; char sg_name[50]; /* * Find port. */ pp = adapter_get_port_by_wwn(handle, wwpn, NULL); if (pp == NULL) return HBA_STATUS_ERROR_ILLEGAL_WWN; if (get_binding_sg_name( pp, disc_wwpn, fc_lun, sg_name, sizeof(sg_name)) != 0) return HBA_STATUS_ERROR_TARGET_LUN; return sg_issue_inquiry(sg_name, cdb_byte1, cdb_byte2, resp, resp_lenp, statp, sense, sense_lenp); } /* * Read capacity V1. */ HBA_STATUS scsi_read_capacity_v1(HBA_HANDLE handle, HBA_WWN disc_wwpn, HBA_UINT64 fc_lun, void *resp, HBA_UINT32 resp_len, void *sense, HBA_UINT32 sense_len) { struct port_info *pp; char sg_name[50]; HBA_UINT8 stat; HBA_STATUS status; /* * Find port. */ pp = adapter_get_port(handle, 0); if (pp == NULL) return HBA_STATUS_ERROR_INVALID_HANDLE; if (get_binding_sg_name( pp, disc_wwpn, fc_lun, sg_name, sizeof(sg_name)) != 0) return HBA_STATUS_ERROR_TARGET_LUN; status = sg_issue_read_capacity(sg_name, resp, &resp_len, &stat, sense, &sense_len); if (status == HBA_STATUS_OK && stat == SCSI_ST_CHECK) status = HBA_STATUS_SCSI_CHECK_CONDITION; return status; } /* * Read capacity V2. */ HBA_STATUS scsi_read_capacity_v2(HBA_HANDLE handle, HBA_WWN wwpn, HBA_WWN disc_wwpn, HBA_UINT64 fc_lun, void *resp, HBA_UINT32 *resp_lenp, HBA_UINT8 *statp, void *sense, HBA_UINT32 *sense_lenp) { struct port_info *pp; char sg_name[50]; /* * Find port. */ pp = adapter_get_port_by_wwn(handle, wwpn, NULL); if (pp == NULL) return HBA_STATUS_ERROR_ILLEGAL_WWN; if (get_binding_sg_name( pp, disc_wwpn, fc_lun, sg_name, sizeof(sg_name)) != 0) return HBA_STATUS_ERROR_TARGET_LUN; return sg_issue_read_capacity(sg_name, resp, resp_lenp, statp, sense, sense_lenp); } /* * Report LUNS V1. */ HBA_STATUS scsi_report_luns_v1(HBA_HANDLE handle, HBA_WWN disc_wwpn, void *resp, HBA_UINT32 resp_len, void *sense, HBA_UINT32 sense_len) { struct port_info *pp; char sg_name[50]; HBA_UINT8 stat; HBA_STATUS status; /* * Find port. */ pp = adapter_get_port(handle, 0); if (pp == NULL) return HBA_STATUS_ERROR_INVALID_HANDLE; if (get_binding_sg_name( pp, disc_wwpn, 0, sg_name, sizeof(sg_name)) != 0) return HBA_STATUS_ERROR_TARGET_PORT_WWN; status = sg_issue_report_luns(sg_name, resp, &resp_len, &stat, sense, &sense_len); if (status == HBA_STATUS_OK && stat == SCSI_ST_CHECK) status = HBA_STATUS_SCSI_CHECK_CONDITION; return status; } /* * Report LUNS V2. */ HBA_STATUS scsi_report_luns_v2(HBA_HANDLE handle, HBA_WWN wwpn, HBA_WWN disc_wwpn, void *resp, HBA_UINT32 *resp_lenp, HBA_UINT8 *statp, void *sense, HBA_UINT32 *sense_lenp) { struct port_info *pp; char sg_name[50]; /* * Find port. */ pp = adapter_get_port_by_wwn(handle, wwpn, NULL); if (pp == NULL) return HBA_STATUS_ERROR_ILLEGAL_WWN; if (get_binding_sg_name( pp, disc_wwpn, 0, sg_name, sizeof(sg_name)) != 0) return HBA_STATUS_ERROR_TARGET_PORT_WWN; return sg_issue_report_luns(sg_name, resp, resp_lenp, statp, sense, sense_lenp); } libhbalinux-1.0.16/sg.c000066400000000000000000000162421214751654400146730ustar00rootroot00000000000000/* * Copyright (c) 2008, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU Lesser General Public License, * version 2.1, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include #include "utils.h" #include "api_lib.h" #include "adapt_impl.h" #include "fc_scsi.h" /* * Perform INQUIRY of SCSI-generic device. */ HBA_STATUS sg_issue_inquiry(const char *file, HBA_UINT8 cdb_byte1, HBA_UINT8 cdb_byte2, void *buf, HBA_UINT32 *lenp, HBA_UINT8 *statp, void *sense, HBA_UINT32 *sense_lenp) { struct sg_io_hdr hdr; struct scsi_inquiry cmd; size_t len; HBA_UINT32 slen; int fd; int rc; len = *lenp; slen = *sense_lenp; if (slen > 255) slen = 255; /* must fit in an 8-bit field */ if (len > 255) len = 255; /* sometimes must fit in 8-byte field */ *lenp = 0; *statp = 0; fd = open(file, O_RDWR); if (fd < 0) { fprintf(stderr, "%s: open of %s failed, errno=0x%x\n", __func__, file, errno); return HBA_STATUS_ERROR; } memset(&hdr, 0, sizeof(hdr)); memset(&cmd, 0, sizeof(cmd)); memset(buf, 0, len); cmd.in_op = SCSI_OP_INQUIRY; cmd.in_flags = cdb_byte1; cmd.in_page_code = cdb_byte2; ua_net16_put(&cmd.in_alloc_len, len); /* field may actually be 8 bits */ hdr.interface_id = 'S'; hdr.dxfer_direction = SG_DXFER_FROM_DEV; hdr.cmd_len = sizeof(cmd); hdr.mx_sb_len = slen; hdr.dxfer_len = len; hdr.dxferp = (unsigned char *) buf; hdr.cmdp = (unsigned char *) &cmd; hdr.sbp = (unsigned char *) sense; hdr.timeout = 3000; /* mS to wait for result */ rc = ioctl(fd, SG_IO, &hdr); if (rc < 0) { rc = errno; fprintf(stderr, "%s: SG_IO error. file %s, errno=0x%x\n", __func__, file, errno); close(fd); return HBA_STATUS_ERROR; } close(fd); *lenp = len - hdr.resid; *sense_lenp = hdr.sb_len_wr; *statp = hdr.status; return HBA_STATUS_OK; } static inline unsigned int sg_get_id_type(struct scsi_inquiry_desc *dp) { return dp->id_type_flags & SCSI_INQT_TYPE_MASK; } /* * Get device ID information for HBA-API. * See the spec. We get the "best" information and leave the rest. * The buffer is left empty if nothing is gotten. */ void sg_get_dev_id(const char *name, char *buf, size_t result_len) { struct scsi_inquiry_dev_id *idp; struct scsi_inquiry_desc *dp; struct scsi_inquiry_desc *best = NULL; char sense[252]; HBA_UINT32 len; HBA_UINT32 slen; u_char scsi_stat; size_t rlen; size_t dlen; unsigned int type; memset(buf, 0, result_len); len = result_len; slen = sizeof(sense); idp = (struct scsi_inquiry_dev_id *) buf; sg_issue_inquiry(name, SCSI_INQF_EVPD, SCSI_INQP_DEV_ID, buf, &len, &scsi_stat, sense, &slen); if (len < sizeof(*idp)) return; if (idp->is_page_code != SCSI_INQP_DEV_ID) return; len -= sizeof(*idp); rlen = net16_get(&idp->is_page_len); if (rlen > len) rlen = len; dp = (struct scsi_inquiry_desc *) (idp + 1); for (; rlen >= sizeof(*dp); rlen -= dlen, dp = (struct scsi_inquiry_desc *) ((char *) dp + dlen)) { dlen = dp->id_designator_len + sizeof(*dp) - sizeof(dp->id_designator[0]); if (dlen > rlen) break; type = sg_get_id_type(dp); if (type > SCSI_DTYPE_NAA) continue; if (best == NULL) best = dp; else if (type == sg_get_id_type(best) && (dp->id_designator_len < best->id_designator_len || (dp->id_designator_len == best->id_designator_len && memcmp(dp->id_designator, best->id_designator, best->id_designator_len) < 0))) { best = dp; } else if (type > sg_get_id_type(best)) best = dp; } if (best) { dp = best; dlen = dp->id_designator_len + sizeof(*dp) - sizeof(dp->id_designator[0]); if (dlen > result_len) dlen = 0; /* can't happen */ else memmove(buf, dp, dlen); /* areas may overlap */ memset(buf + dlen, 0, result_len - dlen); } } /* * Read Capacity for HBA-API. */ HBA_STATUS sg_issue_read_capacity(const char *file, void *resp, HBA_UINT32 *resp_lenp, HBA_UINT8 *statp, void *sense, HBA_UINT32 *sense_lenp) { struct sg_io_hdr hdr; struct scsi_rcap10 cmd; struct scsi_rcap16 cmd_16; size_t len; int fd; int rc; len = *resp_lenp; *resp_lenp = 0; fd = open(file, O_RDWR); if (fd < 0) { fprintf(stderr, "%s: open of %s failed, errno=0x%x\n", __func__, file, errno); return errno; } memset(&hdr, 0, sizeof(hdr)); /* If the response buffer size is enough to * accomodate READ CAPACITY(16) response issue * SCSI READ CAPACITY(16) else issue * SCSI READ CAPACITY(10) */ if (len >= sizeof(struct scsi_rcap16_resp)) { memset(&cmd_16, 0, sizeof(cmd_16)); cmd_16.rc_op = SCSI_OP_SA_IN_16; cmd_16.rc_sa = SCSI_SA_READ_CAP16; ua_net32_put(&cmd_16.rc_alloc_len, len); hdr.cmd_len = sizeof(cmd_16); hdr.cmdp = (unsigned char *) &cmd_16; } else { memset(&cmd, 0, sizeof(cmd)); cmd.rc_op = SCSI_OP_READ_CAP10; hdr.cmd_len = sizeof(cmd); hdr.cmdp = (unsigned char *) &cmd; } hdr.interface_id = 'S'; hdr.dxfer_direction = SG_DXFER_FROM_DEV; hdr.mx_sb_len = *sense_lenp; hdr.dxfer_len = len; hdr.dxferp = (unsigned char *) resp; hdr.sbp = (unsigned char *) sense; hdr.timeout = UINT_MAX; hdr.timeout = 3000; /* mS to wait for result */ rc = ioctl(fd, SG_IO, &hdr); if (rc < 0) { rc = errno; fprintf(stderr, "%s: SG_IO error. file %s, errno=0x%x\n", __func__, file, errno); close(fd); return HBA_STATUS_ERROR; } close(fd); *resp_lenp = len - hdr.resid; *sense_lenp = hdr.sb_len_wr; *statp = hdr.status; return HBA_STATUS_OK; } /* * Report LUNs for HBA-API. */ HBA_STATUS sg_issue_report_luns(const char *file, void *resp, HBA_UINT32 *resp_lenp, HBA_UINT8 *statp, void *sense, HBA_UINT32 *sense_lenp) { struct sg_io_hdr hdr; struct scsi_report_luns cmd; size_t len; int fd; int rc; len = *resp_lenp; *resp_lenp = 0; fd = open(file, O_RDWR); if (fd < 0) { fprintf(stderr, "%s: open of %s failed, errno=0x%x\n", __func__, file, errno); return errno; } memset(&hdr, 0, sizeof(hdr)); memset(&cmd, 0, sizeof(cmd)); cmd.rl_op = SCSI_OP_REPORT_LUNS; ua_net32_put(&cmd.rl_alloc_len, len); hdr.interface_id = 'S'; hdr.dxfer_direction = SG_DXFER_FROM_DEV; hdr.cmd_len = sizeof(cmd); hdr.mx_sb_len = *sense_lenp; hdr.dxfer_len = len; hdr.dxferp = (unsigned char *) resp; hdr.cmdp = (unsigned char *) &cmd; hdr.sbp = (unsigned char *) sense; hdr.timeout = UINT_MAX; hdr.timeout = 3000; /* mS to wait for result */ rc = ioctl(fd, SG_IO, &hdr); if (rc < 0) { rc = errno; fprintf(stderr, "%s: SG_IO error. file %s, errno=0x%x\n", __func__, file, errno); close(fd); return HBA_STATUS_ERROR; } close(fd); *resp_lenp = len - hdr.resid; *sense_lenp = hdr.sb_len_wr; *statp = hdr.status; return HBA_STATUS_OK; } libhbalinux-1.0.16/utils.c000066400000000000000000000200101214751654400154060ustar00rootroot00000000000000/* * Copyright (c) 2008, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU Lesser General Public License, * version 2.1, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include "utils.h" /* * Read a line from the specified file in the specified directory * into the buffer. The file is opened and closed. * Any trailing white space is trimmed off. * This is useful for accessing /sys files. * Returns 0 or an error number. */ int sa_sys_read_line(const char *dir, const char *file, char *buf, size_t len) { FILE *fp; char file_name[256]; char *cp; int rc = 0; snprintf(file_name, sizeof(file_name), "%s/%s", dir, file); fp = fopen(file_name, "r"); if (fp == NULL) rc = -1; else { cp = fgets(buf, len, fp); if (cp == NULL) { fprintf(stderr, "%s: read error or empty file %s," " errno=0x%x\n", __func__, file_name, errno); rc = -1; } else { /* * Trim off trailing newline or other white space. */ cp = buf + strlen(buf); while (--cp >= buf && isspace(*cp)) *cp = '\0'; } fclose(fp); } return rc; } /* * Write a string to the specified file in the specified directory. * The file is opened and closed. * The string has a new-line appended to it. * This is useful for accessing /sys files. * Returns 0 or an error number. */ int sa_sys_write_line(const char *dir, const char *file, const char *string) { FILE *fp; char file_name[256]; int rc = 0; snprintf(file_name, sizeof(file_name), "%s/%s", dir, file); fp = fopen(file_name, "w"); if (fp == NULL) { fprintf(stderr, "%s: fopen of %s failed, errno=0x%x\n", __func__, file_name, errno); rc = -1; } else { rc = fprintf(fp, "%s\n", string); if (rc < 0) fprintf(stderr, "%s: write to %s of %s failed, errno=0x%x\n", __func__, file_name, string, errno); fclose(fp); } return rc; } int sa_sys_read_u32(const char *dir, const char *file, u_int32_t *vp) { char buf[256]; int rc; u_int32_t val; char *endptr; rc = sa_sys_read_line(dir, file, buf, sizeof(buf)); if (rc == 0) { val = strtoul(buf, &endptr, 0); if (*endptr != '\0') { fprintf(stderr, "%s: parse error. file %s/%s line '%s'\n", __func__, dir, file, buf); rc = -1; } else *vp = val; } return rc; } int sa_sys_read_u64(const char *dir, const char *file, u_int64_t *vp) { char buf[256]; int rc; u_int64_t val; char *endptr; rc = sa_sys_read_line(dir, file, buf, sizeof(buf)); if (rc == 0) { val = strtoull(buf, &endptr, 0); if (*endptr != '\0') { fprintf(stderr, "%s: parse error. file %s/%s line '%s'\n", __func__, dir, file, buf); rc = -1; } else *vp = val; } return rc; } /* * Make a printable NUL-terminated copy of the string. * The source buffer might not be NUL-terminated. */ char * sa_strncpy_safe(char *dest, size_t len, const char *src, size_t src_len) { char *dp = dest; const char *sp = src; while (len-- > 1 && src_len-- > 0 && *sp != '\0') { *dp++ = isprint(*sp) ? *sp : (isspace(*sp) ? ' ' : '.'); sp++; } *dp = '\0'; /* * Take off trailing blanks. */ while (--dp >= dest && isspace(*dp)) *dp = '\0'; return dest; } /** sa_enum_encode(tp, name, valp) * * @param tp pointer to table of names and values, struct sa_nameval. * @param name string to be encoded into a value * @returns zero on success, non-zero if no matching string found. */ int sa_enum_encode(const struct sa_nameval *tp, const char *name, u_int32_t *valp) { for (; tp->nv_name != NULL; tp++) { if (strcasecmp(tp->nv_name, name) == 0) { *valp = tp->nv_val; return 0; } } return -1; } /** sa_enum_decode(buf, len, tp, val) * * @param buf buffer for result (may be used or not). * @param len size of buffer (at least 32 bytes recommended). * @param tp pointer to table of names and values, struct sa_nameval. * @param val value to be decoded into a name. * @returns pointer to name string. Unknown values are put into buffer in hex. */ const char * sa_enum_decode(char *buf, size_t len, const struct sa_nameval *tp, u_int32_t val) { for (; tp->nv_name != NULL; tp++) { if (tp->nv_val == val) return tp->nv_name; } snprintf(buf, len, "Unknown (code 0x%X)", val); return buf; } /* * Read through a directory and call a function for each entry. */ int sa_dir_read(char *dir_name, int (*func)(struct dirent *dp, void *), void *arg) { DIR *dir; struct dirent *dp; int error = 0; dir = opendir(dir_name); if (dir == NULL) error = errno; else { while ((dp = readdir(dir)) != NULL && error == 0) { if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) continue; error = (*func)(dp, arg); } closedir(dir); } return error; } /* * Size of on-stack line buffers. * These shouldn't be to large for a kernel stack frame. */ #define SA_LOG_BUF_LEN 200 /* on-stack line buffer size */ static const u_int32_t sa_table_growth = 16; /* entries to grow by */ /** sa_table_grow(tp, index) - add space to a table for index. * * @param tp pointer to sa_table structure. * @param index - new index past the end of the current table. * @returns new index, or -1 if table couldn't be grown. * * Note: if the table has never been used, and is still all zero, this works. * * Note: perhaps not safe for multithreading. Caller can lock the table * externally, but reallocation can take a while, during which time the * caller may not wish to hold the lock. */ int sa_table_grow(struct sa_table *tp, u_int32_t index) { u_int32_t new_size; void **ap; if (index >= tp->st_size) { new_size = index + sa_table_growth; ap = realloc(tp->st_table, new_size * sizeof(*ap)); if (ap == NULL) return -1; memset(ap + tp->st_size, 0, (new_size - tp->st_size) * sizeof(*ap)); tp->st_table = ap; tp->st_size = new_size; } tp->st_limit = index + 1; return index; } /** sa_table_destroy(tp) - free memory used by table. * * @param tp pointer to sa_table structure. */ void sa_table_destroy(struct sa_table *tp) { if (tp->st_table) { free(tp->st_table); tp->st_table = NULL; } tp->st_limit = 0; tp->st_size = 0; } /** sa_table_destroy_all(tp) - free memory used by table, including entries. * * @param tp pointer to sa_table structure. */ void sa_table_destroy_all(struct sa_table *tp) { int i; if (tp->st_table) { for (i = 0; i < tp->st_limit; i++) { if (tp->st_table[i]) { free(tp->st_table[i]); tp->st_table[i] = NULL; } } } sa_table_destroy(tp); } /** sa_table_iterate(tp, handler, arg) * * @param tp pointer to sa_table structure. * @param handler function to be called for each non-NULL entry. * @param arg argument for function. */ void sa_table_iterate(struct sa_table *tp, void (*handler)(void *ep, void *arg), void *arg) { int i; void *ep; for (i = 0; i < tp->st_limit; i++) { ep = tp->st_table[i]; if (ep != NULL) (*handler)(ep, arg); } } /** sa_table_search(tp, match, arg) * * @param tp pointer to sa_table structure. * @param match function to compare entries with arg and * return non-NULL if match. * @param arg argument for match function. * * Note that the value found could actually be something not in the table * if the match function is doing something clever, like returning a * sub-structure of the table entry. */ void * sa_table_search(struct sa_table *tp, void *(*match)(void *ep, void *arg), void *arg) { int i; void *found = NULL; void *ep; for (i = 0; i < tp->st_limit; i++) { ep = tp->st_table[i]; if (ep != NULL) { found = (*match)(ep, arg); if (found != NULL) break; } } return found; } libhbalinux-1.0.16/utils.h000066400000000000000000000126061214751654400154270ustar00rootroot00000000000000/* * Copyright (c) 2008, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU Lesser General Public License, * version 2.1, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef _UTILS_H_ #define _UTILS_H_ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fc_types.h" /* * Structure for tables encoding and decoding name-value pairs such as enums. */ struct sa_nameval { char *nv_name; u_int32_t nv_val; }; /* * Structure for integer-indexed tables that can grow. */ struct sa_table { u_int32_t st_size; /* number of entries in table */ u_int32_t st_limit; /* end of valid entries in table (public) */ void **st_table; /* re-allocatable array of pointers */ }; /* * Function prototypes */ extern int sa_sys_read_line(const char *, const char *, char *, size_t); extern int sa_sys_write_line(const char *, const char *, const char *); extern int sa_sys_read_u32(const char *, const char *, u_int32_t *); extern int sa_sys_read_u64(const char *, const char *, u_int64_t *); extern int sa_dir_read(char *, int (*)(struct dirent *, void *), void *); extern char *sa_strncpy_safe(char *dest, size_t len, const char *src, size_t src_len); extern const char *sa_enum_decode(char *, size_t, const struct sa_nameval *, u_int32_t); extern int sa_enum_encode(const struct sa_nameval *tp, const char *, u_int32_t *); extern const char *sa_flags_decode(char *, size_t, const struct sa_nameval *, u_int32_t); extern int sa_table_grow(struct sa_table *, u_int32_t index); extern void sa_table_destroy_all(struct sa_table *); extern void sa_table_destroy(struct sa_table *); extern void sa_table_iterate(struct sa_table *tp, void (*handler)(void *ep, void *arg), void *arg); extern void *sa_table_search(struct sa_table *tp, void *(*match)(void *ep, void *arg), void *arg); /** sa_table_init(tp) - initialize a table. * @param tp table pointer. * * This just clears a table structure that was allocated by the caller. */ static inline void sa_table_init(struct sa_table *tp) { memset(tp, 0, sizeof(*tp)); } /** sa_table_lookup(tp, index) - lookup an entry in the table. * @param tp table pointer. * @param index the index in the table to access * @returns the entry, or NULL if the index wasn't valid. */ static inline void *sa_table_lookup(const struct sa_table *tp, u_int32_t index) { void *ep = NULL; if (index < tp->st_limit) ep = tp->st_table[index]; return ep; } /** sa_table_lookup_n(tp, n) - find Nth non-empty entry in a table. * @param tp table pointer. * @param n is the entry number, the first non-empty entry is 0. * @returns the entry, or NULL if the end of the table reached first. */ static inline void *sa_table_lookup_n(const struct sa_table *tp, u_int32_t n) { void *ep = NULL; u_int32_t i; for (i = 0; i < tp->st_limit; i++) { ep = tp->st_table[i]; if (ep != NULL && n-- == 0) return ep; } return NULL; } /** sa_table_insert(tp, index, ep) - Replace or insert an entry in the table. * @param tp table pointer. * @param index the index for the new entry. * @param ep entry pointer. * @returns index on success, or -1 if the insert failed. * * Note: if the table has never been used, and is still all zero, this works. * * Note: perhaps not safe for multithreading. Caller can lock the table * externally, but reallocation can take a while, during which time the * caller may not wish to hold the lock. */ static inline int sa_table_insert(struct sa_table *tp, u_int32_t index, void *ep) { if (index >= tp->st_limit && sa_table_grow(tp, index) < 0) return -1; tp->st_table[index] = ep; return index; } /** sa_table_append(tp, ep) - add entry to table and return index. * * @param tp pointer to sa_table structure. * @param ep pointer to new entry, to be added at the end of the table. * @returns new index, or -1 if table couldn't be grown. * * See notes on sa_table_insert(). */ static inline int sa_table_append(struct sa_table *tp, void *ep) { return sa_table_insert(tp, tp->st_limit, ep); } /** sa_table_sort(tp, compare) - sort table in place * * @param tp pointer to sa_table structure. * @param compare function to compare two entries. It is called with pointers * to the pointers to the entries to be compared. See qsort(3). */ static inline void sa_table_sort(struct sa_table *tp, int (*compare)(const void **, const void **)) { qsort(tp->st_table, tp->st_limit, sizeof(void *), (int (*)(const void *, const void *)) compare); } #endif /* _UTILS_H_ */