libiscsi-1.4.0/0000755000175000017500000000000011750707270011471 5ustar mjtmjtlibiscsi-1.4.0/LICENCE-LGPL-2.1.txt0000644000175000017500000006364211750443164014340 0ustar mjtmjt 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! libiscsi-1.4.0/win32/0000755000175000017500000000000011750443164012432 5ustar mjtmjtlibiscsi-1.4.0/win32/vsbuild.bat0000644000175000017500000000434011750443164014573 0ustar mjtmjtrem rem build script for win32 rem rem rem generate core part of library rem cl /I. /Iinclude -Zi -Od -c -D_U_="" -DWIN32 -D_WIN32_WINNT=0x0600 -MDd lib\connect.c -Folib\connect.obj cl /I. /Iinclude -Zi -Od -c -D_U_="" -DWIN32 -D_WIN32_WINNT=0x0600 -MDd lib\crc32c.c -Folib\crc32c.obj cl /I. /Iinclude -Zi -Od -c -D_U_="" -DWIN32 -D_WIN32_WINNT=0x0600 -MDd lib\discovery.c -Folib\discovery.obj cl /I. /Iinclude -Zi -Od -c -D_U_="" -DWIN32 -D_WIN32_WINNT=0x0600 -MDd lib\init.c -Folib\init.obj cl /I. /Iinclude -Zi -Od -c -D_U_="" -DWIN32 -D_WIN32_WINNT=0x0600 -MDd lib\login.c -Folib\login.obj cl /I. /Iinclude -Zi -Od -c -D_U_="" -DWIN32 -D_WIN32_WINNT=0x0600 -MDd lib\md5.c -Folib\md5.obj cl /I. /Iinclude -Zi -Od -c -D_U_="" -DWIN32 -D_WIN32_WINNT=0x0600 -MDd lib\nop.c -Folib\nop.obj cl /I. /Iinclude -Zi -Od -c -D_U_="" -DWIN32 -D_WIN32_WINNT=0x0600 -MDd lib\pdu.c -Folib\pdu.obj cl /I. /Iinclude -Zi -Od -c -D_U_="" -DWIN32 -D_WIN32_WINNT=0x0600 -MDd lib\scsi-command.c -Folib\scsi-command.obj cl /I. /Iinclude -Zi -Od -c -D_U_="" -DWIN32 -D_WIN32_WINNT=0x0600 -MDd lib\scsi-lowlevel.c -Folib\scsi-lowlevel.obj cl /I. /Iinclude -Zi -Od -c -D_U_="" -DWIN32 -D_WIN32_WINNT=0x0600 -MDd lib\socket.c -Folib\socket.obj cl /I. /Iinclude -Zi -Od -c -D_U_="" -DWIN32 -D_WIN32_WINNT=0x0600 -MDd lib\sync.c -Folib\sync.obj cl /I. /Iinclude -Zi -Od -c -D_U_="" -DWIN32 -D_WIN32_WINNT=0x0600 -MDd lib\task_mgmt.c -Folib\task_mgmt.obj rem rem create a linklibrary/dll rem lib /out:lib\libiscsi.lib /def:lib\libiscsi.def lib\connect.obj lib\crc32c.obj lib\discovery.obj lib\init.obj lib\login.obj lib\md5.obj lib\nop.obj lib\pdu.obj lib\scsi-command.obj lib\scsi-lowlevel.obj lib\socket.obj lib\sync.obj lib\task_mgmt.obj link /DLL /out:lib\libiscsi.dll /DEBUG /DEBUGTYPE:cv lib\libiscsi.exp lib\connect.obj lib\crc32c.obj lib\discovery.obj lib\init.obj lib\login.obj lib\md5.obj lib\nop.obj lib\pdu.obj lib\scsi-command.obj lib\scsi-lowlevel.obj lib\socket.obj lib\sync.obj lib\task_mgmt.obj ws2_32.lib rem rem build a test application rem cl /I. /Iinclude -Zi -Od -DWIN32 -D_WIN32_WINNT=0x0600 -MDd -D_U_="" examples\iscsiclient.c lib\libiscsi.lib WS2_32.lib kernel32.lib mswsock.lib advapi32.lib wsock32.lib advapi32.lib libiscsi-1.4.0/configure.ac0000644000175000017500000000556411750443164013770 0ustar mjtmjtAC_PREREQ(2.50) AC_INIT(libiscsi, m4_esyscmd([grep 'Version:' ./packaging/RPM/libiscsi.spec.in 2>/dev/null | head -1 | sed -e 's/[ \t]*Version:[ \t]*\([^ \t]*\)[ \t]*.*/\1/' | tr -d '\n'])) AC_CONFIG_SRCDIR([lib/init.c]) AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE AM_SILENT_RULES LT_INIT if test "${libdir}" = '${exec_prefix}/lib'; then case `uname -m` in x86_64|ppc64|powerpc64) libdir='${exec_prefix}/lib64' ;; *) libdir='${exec_prefix}/lib' ;; esac fi AC_CANONICAL_HOST AM_CONDITIONAL(LD_ISCSI, [expr "$host_os" : linux > /dev/null 2>&1]) if test "$ac_cv_prog_gcc" = yes; then WARN_CFLAGS="-Wall -W -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-align -Wwrite-strings" fi AC_SUBST(WARN_CFLAGS) AC_CONFIG_HEADER(config.h) AC_CACHE_CHECK([for sin_len in sock],libiscsi_cv_HAVE_SOCK_SIN_LEN,[ AC_TRY_COMPILE([#include #include #include ], [struct sockaddr_in sock; sock.sin_len = sizeof(sock);], libiscsi_cv_HAVE_SOCK_SIN_LEN=yes,libiscsi_cv_HAVE_SOCK_SIN_LEN=no)]) if test x"$libiscsi_cv_HAVE_SOCK_SIN_LEN" = x"yes"; then AC_DEFINE(HAVE_SOCK_SIN_LEN,1,[Whether the sockaddr_in struct has a sin_len property]) fi AC_CACHE_CHECK([for tcp keepalive],libiscsi_cv_HAVE_TCP_KEEPALIVE,[ AC_TRY_COMPILE([#include #include #include ], [int foo = TCP_KEEPCNT + TCP_KEEPIDLE + TCP_KEEPINTVL], libiscsi_cv_HAVE_TCP_KEEPALIVE=yes,libiscsi_cv_HAVE_TCP_KEEPALIVE=no)]) if test x"$libiscsi_cv_HAVE_TCP_KEEPALIVE" = x"yes"; then AC_DEFINE(HAVE_TCP_KEEPALIVE,1,[Whether we have support for tcp keepalive socket options]) fi AC_CACHE_CHECK([for sys filio.h],libiscsi_cv_NEED_SYS_FILIO_H,[ AC_TRY_COMPILE([#include #include ], [int foo = FIONREAD], libiscsi_cv_NEED_SYS_FILIO_H=yes,libiscsi_cv_NEED_SYS_FILIO_H=no)]) if test x"$libiscsi_cv_NEED_SYS_FILIO_H" = x"yes"; then AC_DEFINE(NEED_SYS_FILIO_H,1,[Whether we need sys/filio.h]) fi AC_MSG_CHECKING(whether libpopt is available) ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GLIB_CFLAGS" LIBS="$GLIB_LIBS $LIBS -lpopt" AC_TRY_RUN([ /* * Just see if we can compile/link with popt */ #include int main(int argc, const char *argv[]) { struct poptOption popt_options[] = { POPT_TABLEEND }; poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST); return 0; } ], ac_cv_have_popt=yes, ac_cv_have_popt=no, [echo $ac_n "compile with POPT. Assuming OK... $ac_c" ac_cv_have_popt=yes]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" if test "$ac_cv_have_popt" = yes ; then AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) AC_MSG_NOTICE(You need libpopt to compile the sample libiscsi clients.) AC_MSG_NOTICE(Only the library will be compiled and installed.) fi AM_CONDITIONAL(PROGRAMS, [test "$ac_cv_have_popt" = yes]) AC_CONFIG_FILES(Makefile) AC_OUTPUT libiscsi-1.4.0/m4/0000755000175000017500000000000011750443164012010 5ustar mjtmjtlibiscsi-1.4.0/m4/.gitignore0000644000175000017500000000010411750443164013773 0ustar mjtmjt/libtool.m4 /ltoptions.m4 /ltsugar.m4 /ltversion.m4 /lt~obsolete.m4 libiscsi-1.4.0/packaging/0000755000175000017500000000000011750443164013414 5ustar mjtmjtlibiscsi-1.4.0/packaging/RPM/0000755000175000017500000000000011750443164014052 5ustar mjtmjtlibiscsi-1.4.0/packaging/RPM/libiscsi.spec.in0000644000175000017500000000542511750443164017142 0ustar mjtmjtName: libiscsi Summary: iSCSI client library Version: 1.4.0 Release: 1GITHASH%{?dist} License: LGPLv2+ Group: System Environment/Libraries URL: https://github.com/sahlberg/libiscsi Source: libiscsi-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-root BuildRequires: autoconf BuildRequires: automake BuildRequires: libtool BuildRequires: popt-devel %description libiscsi is a library for attaching to iSCSI resources across a network. ####################################################################### %prep %setup -q # setup the init script and sysconfig file %setup -T -D -n libiscsi-%{version} -q %build CC="gcc" export CC ## always run autogen.sh ./autogen.sh %configure make %{?_smp_mflags} %install # Clean up in case there is trash left from a previous build rm -rf $RPM_BUILD_ROOT make DESTDIR=$RPM_BUILD_ROOT install %{?_smp_mflags} rm $RPM_BUILD_ROOT/%{_libdir}/libiscsi.a rm $RPM_BUILD_ROOT/%{_libdir}/libiscsi.la # Remove "*.old" files find $RPM_BUILD_ROOT -name "*.old" -exec rm -f {} \; %clean rm -rf $RPM_BUILD_ROOT %post -p /sbin/ldconfig %postun -p /sbin/ldconfig %files %defattr(-,root,root) %doc COPYING LICENCE-LGPL-2.1.txt README TODO %{_libdir}/libiscsi.so.* %package utils Summary: iSCSI Client Utilities Group: Applications/System %description utils The libiscsi-utils package provides a set of assorted utilities to connect to iSCSI servers without having to set up the Linux iSCSI initiator. %files utils %doc COPYING LICENCE-GPL-2.txt LICENCE-LGPL-2.1.txt README TODO %{_bindir}/ld_iscsi.so %{_bindir}/iscsi-ls %{_bindir}/iscsi-inq %package devel Summary: iSCSI client development libraries Group: Development/Libraries Requires: libiscsi = %{version}-%{release} %description devel The libiscsi-devel package includes the header files for libiscsi. %files devel %defattr(-,root,root) %doc COPYING LICENCE-LGPL-2.1.txt README TODO %{_includedir}/iscsi/iscsi.h %{_includedir}/iscsi/scsi-lowlevel.h %{_libdir}/libiscsi.so %changelog * Thu May 3 2012 : 1.4.0 - Add WRITESAME10/16 and tests for them - Add READ/WRITE12/16 and tests for them - Add PREFETCH10/16 and tests for them - Add automatic reconnect. If being logged in to a target and the tcp session is torn down, then try to reconnect and re-drive the i/o in flight. * Mon Apr 23 2012 : 1.3.0 - Add READCAPACITY16 support - Add VPD pages for thin-provisioning - Add support for UNMAP command for thin provisioning - Add tests for RC16 and UNMAP * Wed Mar 7 2012 : 1.2.0 - rename library back to libiscsi and release it as 1.2.0 * Sun Dec 25 2011 : 1.1.0 - Fix TaskManagement AbortTask/AbortTaskSet to send to correct LUN * Fri Oct 28 2011 Paolo Bonzini - 1.0.0-2 - Fixed rpmlint problems * Sat Dec 4 2010 Ronnie Sahlberg - 1.0.0-1 - Initial version libiscsi-1.4.0/packaging/RPM/makerpms.sh0000755000175000017500000000473711750443164016243 0ustar mjtmjt#!/bin/sh # # makerpms.sh - build RPM packages from the git sources # # Copyright (C) John H Terpstra 1998-2002 # Copyright (C) Gerald (Jerry) Carter 2003 # Copyright (C) Jim McDonough 2007 # Copyright (C) Andrew Tridgell 2007 # Copyright (C) Michael Adam 2008-2009 # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free # Software Foundation; either version 3 of the License, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # more details. # # You should have received a copy of the GNU General Public License along with # this program; if not, see . # # # The following allows environment variables to override the target directories # the alternative is to have a file in your home directory calles .rpmmacros # containing the following: # %_topdir /home/mylogin/redhat # # Note: Under this directory rpm expects to find the same directories that are under the # /usr/src/redhat directory # EXTRA_OPTIONS="$1" DIRNAME=$(dirname $0) TOPDIR=${DIRNAME}/../.. SPECDIR=`rpm --eval %_specdir` SRCDIR=`rpm --eval %_sourcedir` SPECFILE="libiscsi.spec" SPECFILE_IN="libiscsi.spec.in" RPMBUILD="rpmbuild" GITHASH=".$(git log --pretty=format:%h -1)" if test "x$USE_GITHASH" = "xno" ; then GITHASH="" fi sed -e s/GITHASH/${GITHASH}/g \ < ${DIRNAME}/${SPECFILE_IN} \ > ${DIRNAME}/${SPECFILE} VERSION=$(grep ^Version ${DIRNAME}/${SPECFILE} | sed -e 's/^Version:\ \+//') RELEASE=$(grep ^Release ${DIRNAME}/${SPECFILE} | sed -e 's/^Release:\ \+//') if echo | gzip -c --rsyncable - > /dev/null 2>&1 ; then GZIP_ENV="-9 --rsyncable" else GZIP_ENV="-9" fi pushd ${TOPDIR} echo -n "Creating libiscsi-${VERSION}.tar.gz ... " sh autogen.sh make dist GZIP_ENV="\"$GZIP_ENV\"" RC=$? popd echo "Done." if [ $RC -ne 0 ]; then echo "Build failed!" exit 1 fi # At this point the SPECDIR and SRCDIR vaiables must have a value! ## ## copy additional source files ## cp -p ${TOPDIR}/libiscsi-${VERSION}.tar.gz ${SRCDIR} cp -p ${DIRNAME}/${SPECFILE} ${SPECDIR} ## ## Build ## echo "$(basename $0): Getting Ready to build release package" ${RPMBUILD} -ba --clean --rmsource ${EXTRA_OPTIONS} ${SPECDIR}/${SPECFILE} || exit 1 echo "$(basename $0): Done." exit 0 libiscsi-1.4.0/packaging/RPM/.gitignore0000644000175000017500000000001011750443164016031 0ustar mjtmjt/*.spec libiscsi-1.4.0/patches/0000755000175000017500000000000011750443164013117 5ustar mjtmjtlibiscsi-1.4.0/patches/sg3_utils-1.32.patch0000644000175000017500000004754111750443164016450 0ustar mjtmjtcommit 0fbfdc4cb083c0a077f719e78658bc80b2123f83 Author: Ronnie Sahlberg Date: Tue Jan 17 20:29:11 2012 +1100 iscsi support diff --git a/README b/README index 46d8f94..7b8736a 100644 --- a/README +++ b/README @@ -7,6 +7,8 @@ command set. Apart from SCSI parallel interface (SPI) devices, the SCSI command set is used by ATAPI devices (CD/DVDs and tapes), USB mass storage devices, Fibre Channel disks, IEEE 1394 storage devices (that use the "SBP" protocol), SAS, iSCSI and FCoE devices (amongst others). +On some platforms the package can also access iSCSI devices directly +using a built-in iscsi client. See the iSCSI section below for more info. This package originally targeted the Linux SCSI subsystem. Since most operating systems contain a SCSI command pass-through mechanism, many @@ -335,6 +337,44 @@ The more recent utilities that use "getopt_long" only are: sg_wr_mode +iSCSI support +============= +On some platforms (Linux) sg3_utils can be built with iSCSI support. +When built with iSCSI support, the utilities will be able to access iSCSI +devices directly using a built-in iSCSI client, without having to first make +the devices visible to the host. +This is very useful for cases where you have very many iSCSI targets you want +to manage and very many LUNs, in which case it may be impractical to make all +those devices visible to the local host. + +In order to get access to the iSCSI functionality, the sg3_utils package must +be built and linked against the iscsi client library from : + https://github.com/sahlberg/libiscsi +When configuring and building sg3_utils, the build process will detect if +this library is available and if it is build a version of sg3_utils with +iSCSI support. + +With iSCSI support, you can specify a iSCSI URL instead of the /dev/sg* +device that most of the utilities take. + +Example: + sudo sg_inq iscsi://karelin/iqn.ronnie.test/1 +Which means : Use LUN 1 on the target with the name "iqn.ronnie.test" +that is available on network host "karelin". + +The full form of the iSCSI URL is : + iscsi://[[%]@][:]// + +iSCSI Authentication: +The package supports normal iSCSI CHAP authentication to those targets that +require it. +This is done by specifying hte CHAP username and password as part of the iSCSI +URL. + +Example: + sudo sg_inq iscsi://ronnie%secret@karelin/iqn.ronnie.test/1 + + Dangerous code ============== This code: diff --git a/configure.ac b/configure.ac index 355ca84..1916603 100644 --- a/configure.ac +++ b/configure.ac @@ -76,4 +76,34 @@ AC_ARG_ENABLE([win32-spt-direct], AC_DEFINE_UNQUOTED(WIN32_SPT_DIRECT, 1, [enable Win32 SPT Direct], ) ) + +AC_MSG_CHECKING(if libiscsi is available) +ac_save_CFLAGS="$CFLAGS" +ac_save_LIBS="$LIBS" +CFLAGS="" +LIBS="-liscsi" +AC_TRY_RUN([ +/* + * Just see if we can compile/link with libiscsi + */ +#include +int main(int argc, const char *argv[]) +{ + iscsi_create_context(""); + return 0; +} +], ac_cv_have_libiscsi=yes, ac_cv_have_libiscsi=no, + [echo $ac_n "compile with LIBISCSI. Assuming OK... $ac_c" + ac_cv_have_libiscsi=yes]) +CFLAGS="$ac_save_CFLAGS" +LIBS="$ac_save_LIBS" +if test "$ac_cv_have_libiscsi" = yes ; then + AC_MSG_RESULT(yes) + AC_SUBST([libiscsi], ['-liscsi']) + AC_DEFINE_UNQUOTED(CONFIG_LIBISCSI, 1, [we have libiscsi support], ) +else + AC_MSG_RESULT(no) + AC_SUBST([libiscsi], ['']) +fi + AC_OUTPUT(Makefile include/Makefile lib/Makefile src/Makefile doc/Makefile) diff --git a/lib/Makefile.am b/lib/Makefile.am index 3d5213e..6990f12 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -8,6 +8,7 @@ libsgutils2_la_SOURCES = \ sg_cmds_extra.c \ sg_cmds_mmc.c \ sg_pt_common.c \ + sg_pt_iscsi.c \ sg_pt_linux.c \ sg_io_linux.c @@ -33,6 +34,7 @@ libsgutils2_la_SOURCES = \ sg_pt_win32.c EXTRA_libsgutils2_la_SOURCES = \ + sg_pt_iscsi.c \ sg_pt_linux.c \ sg_io_linux.c \ sg_pt_freebsd.c \ @@ -55,6 +57,7 @@ libsgutils2_la_SOURCES = \ sg_pt_win32.c EXTRA_libsgutils2_la_SOURCES = \ + sg_pt_iscsi.c \ sg_pt_linux.c \ sg_io_linux.c \ sg_pt_freebsd.c \ @@ -77,6 +80,7 @@ libsgutils2_la_SOURCES = \ sg_pt_freebsd.c EXTRA_libsgutils2_la_SOURCES = \ + sg_pt_iscsi.c \ sg_pt_linux.c \ sg_io_linux.c \ sg_linux_inc.h \ @@ -100,6 +104,7 @@ libsgutils2_la_SOURCES = \ sg_pt_solaris.c EXTRA_libsgutils2_la_SOURCES = \ + sg_pt_iscsi.c \ sg_pt_linux.c \ sg_io_linux.c \ sg_linux_inc.h \ @@ -123,6 +128,7 @@ libsgutils2_la_SOURCES = \ sg_pt_osf1.c EXTRA_libsgutils2_la_SOURCES = \ + sg_pt_iscsi.c \ sg_pt_linux.c \ sg_io_linux.c \ sg_pt_freebsd.c \ @@ -140,7 +146,7 @@ lib_LTLIBRARIES = libsgutils2.la libsgutils2_la_LDFLAGS = -version-info 2:0:0 -libsgutils2_la_LIBADD = @GETOPT_O_FILES@ @os_libs@ +libsgutils2_la_LIBADD = @GETOPT_O_FILES@ @os_libs@ @libiscsi@ libsgutils2_la_DEPENDENCIES = @GETOPT_O_FILES@ diff --git a/lib/sg_pt_linux.c b/lib/sg_pt_linux.c index 0a5216e..6be755e 100644 --- a/lib/sg_pt_linux.c +++ b/lib/sg_pt_linux.c @@ -27,6 +27,10 @@ #include "sg_lib.h" #include "sg_linux_inc.h" +#ifdef CONFIG_LIBISCSI +#include "sg_pt_iscsi.h" +#endif + #define DEF_TIMEOUT 60000 /* 60,000 millisecs (60 seconds) */ static const char * linux_host_bytes[] = { @@ -117,6 +121,12 @@ scsi_pt_open_flags(const char * device_name, int flags, int verbose) { int fd; +#ifdef CONFIG_LIBISCSI + if (!strncmp(device_name, "iscsi://", 8)) { + return iscsi_pt_open_device(device_name, flags, verbose); + } +#endif + if (verbose > 1) { if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; @@ -135,6 +145,12 @@ scsi_pt_close_device(int device_fd) { int res; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return iscsi_pt_close_device(device_fd); + } +#endif + res = close(device_fd); if (res < 0) res = -errno; @@ -147,6 +163,12 @@ construct_scsi_pt_obj() { struct sg_pt_linux_scsi * ptp; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return construct_iscsi_pt_obj(); + } +#endif + ptp = (struct sg_pt_linux_scsi *) calloc(1, sizeof(struct sg_pt_linux_scsi)); if (ptp) { @@ -161,6 +183,12 @@ destruct_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return destruct_iscsi_pt_obj(vp); + } +#endif + if (ptp) free(ptp); } @@ -170,6 +198,12 @@ clear_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return clear_iscsi_pt_obj(vp); + } +#endif + if (ptp) { memset(ptp, 0, sizeof(struct sg_pt_linux_scsi)); ptp->io_hdr.interface_id = 'S'; @@ -183,6 +217,12 @@ set_scsi_pt_cdb(struct sg_pt_base * vp, const unsigned char * cdb, { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return set_iscsi_pt_cdb(vp, cdb, cdb_len); + } +#endif + if (ptp->io_hdr.cmdp) ++ptp->in_err; ptp->io_hdr.cmdp = (unsigned char *)cdb; @@ -195,6 +235,12 @@ set_scsi_pt_sense(struct sg_pt_base * vp, unsigned char * sense, { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return set_iscsi_pt_sense(vp, sense, max_sense_len); + } +#endif + if (ptp->io_hdr.sbp) ++ptp->in_err; memset(sense, 0, max_sense_len); @@ -209,6 +255,12 @@ set_scsi_pt_data_in(struct sg_pt_base * vp, unsigned char * dxferp, { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return set_iscsi_pt_data_in(vp, dxferp, dxfer_len); + } +#endif + if (ptp->io_hdr.dxferp) ++ptp->in_err; if (dxfer_len > 0) { @@ -225,6 +277,12 @@ set_scsi_pt_data_out(struct sg_pt_base * vp, const unsigned char * dxferp, { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return set_iscsi_pt_data_out(vp, dxferp, dxfer_len); + } +#endif + if (ptp->io_hdr.dxferp) ++ptp->in_err; if (dxfer_len > 0) { @@ -239,6 +297,13 @@ set_scsi_pt_packet_id(struct sg_pt_base * vp, int pack_id) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + set_iscsi_pt_packet_id(vp, pack_id); + return; + } +#endif + ptp->io_hdr.pack_id = pack_id; } @@ -247,6 +312,13 @@ set_scsi_pt_tag(struct sg_pt_base * vp, uint64_t tag) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + set_iscsi_pt_tag(vp, tag); + return; + } +#endif + ++ptp->in_err; tag = tag; /* dummy to silence compiler */ } @@ -257,6 +329,13 @@ set_scsi_pt_task_management(struct sg_pt_base * vp, int tmf_code) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + set_iscsi_pt_task_management(vp, tmf_code); + return; + } +#endif + ++ptp->in_err; tmf_code = tmf_code; /* dummy to silence compiler */ } @@ -266,6 +345,13 @@ set_scsi_pt_task_attr(struct sg_pt_base * vp, int attribute, int priority) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + set_iscsi_pt_task_attr(vp, attribute, priority); + return; + } +#endif + ++ptp->in_err; attribute = attribute; /* dummy to silence compiler */ priority = priority; /* dummy to silence compiler */ @@ -303,6 +389,12 @@ do_scsi_pt(struct sg_pt_base * vp, int fd, int time_secs, int verbose) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return do_iscsi_pt(vp, fd, time_secs, verbose); + } +#endif + if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; ptp->os_err = 0; @@ -339,6 +431,12 @@ get_scsi_pt_result_category(const struct sg_pt_base * vp) int dr_st = ptp->io_hdr.driver_status & SG_LIB_DRIVER_MASK; int scsi_st = ptp->io_hdr.status & 0x7e; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_result_category(vp); + } +#endif + if (ptp->os_err) return SCSI_PT_RESULT_OS_ERR; else if (ptp->io_hdr.host_status) @@ -360,6 +458,12 @@ get_scsi_pt_resid(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_resid(vp); + } +#endif + return ptp->io_hdr.resid; } @@ -368,6 +472,12 @@ get_scsi_pt_status_response(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_status_response(vp); + } +#endif + return ptp->io_hdr.status; } @@ -376,6 +486,12 @@ get_scsi_pt_sense_len(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_sense_len(vp); + } +#endif + return ptp->io_hdr.sb_len_wr; } @@ -384,6 +500,12 @@ get_scsi_pt_duration_ms(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_duration_ms(vp); + } +#endif + return ptp->io_hdr.duration; } @@ -392,6 +514,12 @@ get_scsi_pt_transport_err(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_transport_err(vp); + } +#endif + return (ptp->io_hdr.host_status << 8) + ptp->io_hdr.driver_status; } @@ -400,6 +528,12 @@ get_scsi_pt_os_err(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_os_err(vp); + } +#endif + return ptp->os_err; } @@ -416,6 +550,12 @@ get_scsi_pt_transport_err_str(const struct sg_pt_base * vp, int max_b_len, const char * driv_cp = "invalid"; const char * sugg_cp = "invalid"; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_transport_err_str(vp, max_b_len, b); + } +#endif + m = max_b_len; n = 0; if (hs) { @@ -451,6 +591,12 @@ get_scsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b) const struct sg_pt_linux_scsi * ptp = &vp->impl; const char * cp; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_os_err_str(vp, max_b_len, b); + } +#endif + cp = safe_strerror(ptp->os_err); strncpy(b, cp, max_b_len); if ((int)strlen(cp) >= max_b_len) @@ -567,6 +713,12 @@ scsi_pt_open_flags(const char * device_name, int flags, int verbose) { int fd; +#ifdef CONFIG_LIBISCSI + if (!strncmp(device_name, "iscsi://", 8)) { + return iscsi_pt_open_device(device_name, flags, verbose); + } +#endif + if (! bsg_major_checked) { bsg_major_checked = 1; find_bsg_major(verbose); @@ -589,6 +741,12 @@ scsi_pt_close_device(int device_fd) { int res; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return iscsi_pt_close_device(device_fd); + } +#endif + res = close(device_fd); if (res < 0) res = -errno; @@ -601,6 +759,12 @@ construct_scsi_pt_obj() { struct sg_pt_linux_scsi * ptp; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return construct_iscsi_pt_obj(); + } +#endif + ptp = (struct sg_pt_linux_scsi *) calloc(1, sizeof(struct sg_pt_linux_scsi)); if (ptp) { @@ -620,6 +784,12 @@ destruct_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return destruct_iscsi_pt_obj(vp); + } +#endif + if (ptp) free(ptp); } @@ -629,6 +799,12 @@ clear_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return clear_iscsi_pt_obj(vp); + } +#endif + if (ptp) { memset(ptp, 0, sizeof(struct sg_pt_linux_scsi)); ptp->io_hdr.guard = 'Q'; @@ -647,6 +823,12 @@ set_scsi_pt_cdb(struct sg_pt_base * vp, const unsigned char * cdb, { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return set_iscsi_pt_cdb(vp, cdb, cdb_len); + } +#endif + if (ptp->io_hdr.request) ++ptp->in_err; /* C99 has intptr_t instead of long */ @@ -660,6 +842,12 @@ set_scsi_pt_sense(struct sg_pt_base * vp, unsigned char * sense, { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return set_iscsi_pt_sense(vp, sense, max_sense_len); + } +#endif + if (ptp->io_hdr.response) ++ptp->in_err; memset(sense, 0, max_sense_len); @@ -674,6 +862,12 @@ set_scsi_pt_data_in(struct sg_pt_base * vp, unsigned char * dxferp, { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return set_iscsi_pt_data_in(vp, dxferp, dxfer_len); + } +#endif + if (ptp->io_hdr.din_xferp) ++ptp->in_err; if (dxfer_len > 0) { @@ -689,6 +883,12 @@ set_scsi_pt_data_out(struct sg_pt_base * vp, const unsigned char * dxferp, { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return set_iscsi_pt_data_out(vp, dxferp, dxfer_len); + } +#endif + if (ptp->io_hdr.dout_xferp) ++ptp->in_err; if (dxfer_len > 0) { @@ -702,6 +902,13 @@ set_scsi_pt_packet_id(struct sg_pt_base * vp, int pack_id) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + set_iscsi_pt_packet_id(vp, pack_id); + return; + } +#endif + ptp->io_hdr.spare_in = pack_id; } @@ -710,6 +917,13 @@ set_scsi_pt_tag(struct sg_pt_base * vp, uint64_t tag) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + set_iscsi_pt_tag(vp, tag); + return; + } +#endif + ptp->io_hdr.request_tag = tag; } @@ -719,6 +933,13 @@ set_scsi_pt_task_management(struct sg_pt_base * vp, int tmf_code) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + set_iscsi_pt_task_management(vp, tmf_code); + return; + } +#endif + ptp->io_hdr.subprotocol = 1; /* SCSI task management function */ ptp->tmf_request[0] = (unsigned char)tmf_code; /* assume it fits */ ptp->io_hdr.request = (__u64)(long)(&(ptp->tmf_request[0])); @@ -730,6 +951,12 @@ set_scsi_pt_task_attr(struct sg_pt_base * vp, int attribute, int priority) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + set_iscsi_pt_task_attr(vp, attribute, priority); + return; + } +#endif ptp->io_hdr.request_attr = attribute; ptp->io_hdr.request_priority = priority; } @@ -756,6 +983,12 @@ get_scsi_pt_resid(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_resid(vp); + } +#endif + return ptp->io_hdr.din_resid; } @@ -764,6 +997,12 @@ get_scsi_pt_status_response(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_status_response(vp); + } +#endif + return ptp->io_hdr.device_status; } @@ -772,6 +1011,12 @@ get_scsi_pt_sense_len(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_sense_len(vp); + } +#endif + return ptp->io_hdr.response_len; } @@ -780,6 +1025,12 @@ get_scsi_pt_duration_ms(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_duration_ms(vp); + } +#endif + return ptp->io_hdr.duration; } @@ -788,6 +1039,12 @@ get_scsi_pt_transport_err(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_transport_err(vp); + } +#endif + return ptp->io_hdr.transport_status; } @@ -805,6 +1062,12 @@ get_scsi_pt_transport_err_str(const struct sg_pt_base * vp, int max_b_len, const char * driv_cp = "invalid"; const char * sugg_cp = "invalid"; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_transport_err_str(vp, max_b_len, b); + } +#endif + m = max_b_len; n = 0; if (hs) { @@ -841,6 +1104,12 @@ get_scsi_pt_result_category(const struct sg_pt_base * vp) int dr_st = ptp->io_hdr.driver_status & SG_LIB_DRIVER_MASK; int scsi_st = ptp->io_hdr.device_status & 0x7e; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_result_category(vp); + } +#endif + if (ptp->os_err) return SCSI_PT_RESULT_OS_ERR; else if (ptp->io_hdr.transport_status) @@ -862,6 +1131,12 @@ get_scsi_pt_os_err(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_os_err(vp); + } +#endif + return ptp->os_err; } @@ -871,6 +1146,12 @@ get_scsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b) const struct sg_pt_linux_scsi * ptp = &vp->impl; const char * cp; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_os_err_str(vp, max_b_len, b); + } +#endif + cp = safe_strerror(ptp->os_err); strncpy(b, cp, max_b_len); if ((int)strlen(cp) >= max_b_len) @@ -944,6 +1225,12 @@ do_scsi_pt(struct sg_pt_base * vp, int fd, int time_secs, int verbose) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return do_iscsi_pt(vp, fd, time_secs, verbose); + } +#endif + if (! bsg_major_checked) { bsg_major_checked = 1; find_bsg_major(verbose); libiscsi-1.4.0/patches/mtx-iscsi.diff0000644000175000017500000001673111750443164015701 0ustar mjtmjtdiff --git a/Makefile.in b/Makefile.in index 6b967cf..fe81280 100644 --- a/Makefile.in +++ b/Makefile.in @@ -26,7 +26,7 @@ INSTALL = @INSTALL@ CFLAGS = @CFLAGS@ CPPFLAGS = @CPPFLAGS@ -DVERSION="\"$(VERSION)\"" -I$(srcdir) -I. LDFLAGS = @LDFLAGS@ -LIBS = @LIBS@ +LIBS = @LIBS@ @libiscsi@ USE_OBJCOPY = @USE_OBJCOPY@ INSTALL_DOC = $(INSTALL) -m 644 diff --git a/config.h.in b/config.h.in index 7282e46..81ce3d4 100644 --- a/config.h.in +++ b/config.h.in @@ -30,8 +30,8 @@ #define HAVE_SYS_IOCTL_H 0 #define HAVE_SYS_MTIO_H 0 #define HAVE_DDK_NTDDSCSI_H 0 +#define HAVE_LIBISCSI 0 #define WORDS_BIGENDIAN 0 #endif - diff --git a/configure.in b/configure.in index 10aa09d..b8b79e7 100755 --- a/configure.in +++ b/configure.in @@ -110,4 +110,50 @@ AC_FUNC_VPRINTF dnl Check for files +dnl Check for libiscsi +use_libiscsi="" +AC_ARG_ENABLE([libiscsi], + AC_HELP_STRING([--enable-libiscsi], [enable iscsi support]), + use_libiscsi="$enableval" +) + +AC_MSG_CHECKING(if libiscsi is available) +if test "$use_libiscsi" = "yes" ; then + AC_MSG_RESULT(enabled) + AC_SUBST([libiscsi], ['-liscsi']) + AC_DEFINE_UNQUOTED(HAVE_LIBISCSI, 1, [we have libiscsi support], ) +elif test "$use_libiscsi" = "no" ; then + AC_MSG_RESULT(disabled) + AC_SUBST([libiscsi], ['']) +else +ac_save_CFLAGS="$CFLAGS" +ac_save_LIBS="$LIBS" +CFLAGS="" +LIBS="-liscsi" +AC_TRY_RUN([ +/* + * Just see if we can compile/link with libiscsi + */ +#include +int main(int argc, const char *argv[]) +{ + iscsi_create_context(""); + return 0; +} +], ac_cv_have_libiscsi=yes, ac_cv_have_libiscsi=no, + [echo $ac_n "compile with LIBISCSI. Assuming OK... $ac_c" + ac_cv_have_libiscsi=yes]) +CFLAGS="$ac_save_CFLAGS" +LIBS="$ac_save_LIBS" +if test "$ac_cv_have_libiscsi" = yes ; then + AC_MSG_RESULT(yes) + AC_SUBST([libiscsi], ['-liscsi']) + AC_DEFINE_UNQUOTED(HAVE_LIBISCSI, 1, [we have libiscsi support], ) +else + AC_MSG_RESULT(no) + AC_SUBST([libiscsi], ['']) +fi +fi + + AC_OUTPUT(Makefile) diff --git a/mtxl.h b/mtxl.h index 073f4fa..84510cc 100644 --- a/mtxl.h +++ b/mtxl.h @@ -26,6 +26,10 @@ #ifndef MTXL_H #define MTXL_H 1 +#if HAVE_LIBISCSI +#define ISCSI_FD 0x7fffffff +#endif + #include "mtx.h" #undef min diff --git a/scsi_linux.c b/scsi_linux.c index cc14ebf..099cdb4 100644 --- a/scsi_linux.c +++ b/scsi_linux.c @@ -58,14 +58,128 @@ $Revision: 193 $ static int pack_id; static int sg_timeout; + +#if HAVE_LIBISCSI +#include +#include +#include +struct iscsi_lun { + struct iscsi_context *context; + int lun; +}; +static struct iscsi_lun iscsi_lun; + +static int +do_iscsi_io(Direction_T Direction, + CDB_T *CDB, + int CDB_Length, + void *DataBuffer, + int DataBufferLength, + RequestSense_T *RequestSense) +{ + struct scsi_task *task; + struct iscsi_data outdata, *data = NULL; + + task = malloc(sizeof(struct scsi_task)); + if (task == NULL) { + FatalError("Out-of-memory: Failed to allocate iscsi task structure\n"); + } + memset(task, 0, sizeof(struct scsi_task)); + + task->cdb_size = CDB_Length; + memcpy(&task->cdb[0], CDB, task->cdb_size); + + switch (Direction) { + case Input: + task->xfer_dir = SCSI_XFER_READ; + task->expxferlen = DataBufferLength; + break; + case Output: + task->xfer_dir = SCSI_XFER_WRITE; + task->expxferlen = DataBufferLength; + outdata.size = DataBufferLength; + outdata.data = DataBuffer; + data = &outdata; + break; + } + + if (iscsi_scsi_command_sync(iscsi_lun.context, iscsi_lun.lun, task, data) == NULL) { + FatalError("Failed to do iscsi i/o : %s\n", iscsi_get_error(iscsi_lun.context)); + scsi_free_scsi_task(task); + return -1; + } + + if (task->status == SCSI_STATUS_GOOD) { + if (task->xfer_dir == SCSI_XFER_READ) { + memcpy(DataBuffer, task->datain.data, DataBufferLength); + } + } + if (task->status == SCSI_STATUS_CHECK_CONDITION) { + memcpy(RequestSense, task->datain.data+2, task->datain.size-2); + } + scsi_free_scsi_task(task); + + return 0; + } + +static DEVICE_TYPE OpenISCSI(char *DeviceName) +{ + char *portal = NULL; + char *target = NULL; + char *lun = NULL; + + portal = strdup(DeviceName + 8); + if (portal == NULL) { + FatalError("Out-of-memory. Failed to strdup %s\n", DeviceName); + } + target = index(portal, '/'); + if (target == NULL) { + FatalError("Invalid iSCSI URL : %s.\nURL must be specified as \"iscsi://[:]//\"\n", DeviceName); + } + *target++ = 0; + + lun = index(target, '/'); + if (lun == NULL) { + FatalError("Invalid iSCSI URL : %s.\nURL must be specified as \"iscsi://[:]//\"\n", DeviceName); + } + *lun++ = 0; + + iscsi_lun.context = iscsi_create_context("iqn.1999-08.net.sourceforge.mtx"); + if (iscsi_lun.context == NULL) { + FatalError("Failed to create iSCSI context for %s. (%s)\n", DeviceName, + iscsi_get_error(iscsi_lun.context)); + } + iscsi_set_targetname(iscsi_lun.context, target); + iscsi_set_session_type(iscsi_lun.context, ISCSI_SESSION_NORMAL); + iscsi_set_header_digest(iscsi_lun.context, ISCSI_HEADER_DIGEST_NONE_CRC32C); + + iscsi_lun.lun = atoi(lun); + if (iscsi_full_connect_sync(iscsi_lun.context, portal, iscsi_lun.lun) != 0) { + FatalError("Failed to connect to %s. (%s)\n", DeviceName, + iscsi_get_error(iscsi_lun.context)); + iscsi_destroy_context(iscsi_lun.context); + iscsi_lun.context = NULL; + } + + return ISCSI_FD; +} +#endif + DEVICE_TYPE SCSI_OpenDevice(char *DeviceName) { int timeout = SG_SCSI_DEFAULT_TIMEOUT; #ifdef SG_IO int k; /* version */ #endif - int DeviceFD = open(DeviceName, O_RDWR); + int DeviceFD; + +#if HAVE_LIBISCSI + if (!strncmp(DeviceName, "iscsi://", 8)) { + return OpenISCSI(DeviceName); + } +#endif + DeviceFD = open(DeviceName, O_RDWR); if (DeviceFD < 0) FatalError("cannot open SCSI device '%s' - %m\n", DeviceName); @@ -98,6 +212,14 @@ void SCSI_Default_Timeout(void) void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD) { +#if HAVE_LIBISCSI + if (iscsi_lun.context != NULL && DeviceFD == ISCSI_FD) { + iscsi_logout_sync(iscsi_lun.context); + iscsi_destroy_context(iscsi_lun.context); + iscsi_lun.context = NULL; + return; + } +#endif if (close(DeviceFD) < 0) FatalError("cannot close SCSI device '%s' - %m\n", DeviceName); } @@ -118,6 +240,16 @@ scsi_id_t *SCSI_GetIDLun(DEVICE_TYPE fd) int word2; } idlun; +#if HAVE_LIBISCSI + if (fd == ISCSI_FD) { + /* we only need the lun */ + retval = (scsi_id_t *)xmalloc(sizeof(scsi_id_t)); + retval->id = 0; + retval->lun = iscsi_lun.lun; + return retval; + } +#endif + status = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &idlun); if (status) { @@ -157,6 +289,13 @@ int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD, unsigned int status; sg_io_hdr_t io_hdr; +#if HAVE_LIBISCSI + if (DeviceFD == ISCSI_FD) { + return do_iscsi_io(Direction, CDB, CDB_Length, + DataBuffer, DataBufferLength, + RequestSense); + } +#endif memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); memset(RequestSense, 0, sizeof(RequestSense_T)); @@ -261,6 +400,13 @@ int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD, struct sg_header *Header; /* we actually point this into Command... */ struct sg_header *ResultHeader; /* we point this into ResultBuf... */ +#if HAVE_LIBISCSI + if (DeviceFD == ISCSI_FD) { + return do_iscsi_io(Direction, CDB, CDB_Length, + DataBuffer, DataBufferLength, + RequestSense); + } +#endif /* First, see if we need to set our SCSI timeout to something different */ if (sg_timeout != SG_SCSI_DEFAULT_TIMEOUT) { libiscsi-1.4.0/patches/README0000644000175000017500000000173211750443164014002 0ustar mjtmjtThis directory contains patches to other packages to make them iSCSI aware. sg3_utils-1.32.patch ==================== This patch adds iscsi support to the SG3 package. This is only added for the Linux platform, but adding to other platforms supported by SG3 should be trivial. $ ./src/sg_inq iscsi://127.0.0.1/iqn.ronnie.test/1 standard INQUIRY: PQual=0 Device_type=0 RMB=0 version=0x05 [SPC-3] [AERC=0] [TrmTsk=1] NormACA=0 HiSUP=0 Resp_data_format=2 SCCS=0 ACC=0 TPGS=0 3PC=0 Protect=0 BQue=0 EncServ=0 MultiP=0 [MChngr=0] [ACKREQQ=0] Addr16=0 [RelAdr=0] WBus16=0 Sync=0 Linked=0 [TranDis=0] CmdQue=1 [SPI: Clocking=0x0 QAS=0 IUS=0] length=66 (0x42) Peripheral device type: disk Vendor identification: IET Product identification: VIRTUAL-DISK Product revision level: 0001 Unit serial number: beaf11 mtx-iscsi.diff ============== Adds iscsi support to the MTX package to manage media changer devices. libiscsi-1.4.0/Makefile.am0000644000175000017500000000751511750443164013534 0ustar mjtmjt# Generic definitions ACLOCAL_AMFLAGS =-I m4 AUTOMAKE_OPTIONS = foreign subdir-objects AM_CPPFLAGS=-I. -I$(srcdir)/include "-D_U_=__attribute__((unused))" AM_CFLAGS=$(WARN_CFLAGS) LDADD = lib/libiscsi.la -lpopt EXTRA_DIST = autogen.sh COPYING LICENCE-GPL-2.txt LICENCE-LGPL-2.1.txt \ packaging/RPM/libiscsi.spec.in packaging/RPM/makerpms.sh # Simplify conditions below by declaring variables as empty bin_PROGRAMS = noinst_PROGRAMS = EXTRA_PROGRAMS = # libiscsi shared library iscsi_includedir = $(includedir)/iscsi dist_iscsi_include_HEADERS = include/iscsi.h include/scsi-lowlevel.h dist_noinst_HEADERS = include/iscsi-private.h include/md5.h include/slist.h lib_LTLIBRARIES = lib/libiscsi.la lib_libiscsi_la_SOURCES = \ lib/connect.c lib/crc32c.c lib/discovery.c lib/init.c \ lib/login.c lib/md5.c lib/nop.c lib/pdu.c lib/scsi-command.c \ lib/scsi-lowlevel.c lib/socket.c lib/sync.c lib/task_mgmt.c SONAME=$(firstword $(subst ., ,$(VERSION))) SOREL=$(shell printf "%d%02d%02d" $(subst ., ,$(VERSION))) lib_libiscsi_la_LDFLAGS = \ -version-info $(SONAME):$(SOREL):0 -bindir $(bindir) -no-undefined # libiscsi utilities if PROGRAMS bin_PROGRAMS += bin/iscsi-inq bin/iscsi-ls bin_iscsi_inq_SOURCES = src/iscsi-inq.c bin_iscsi_ls_SOURCES = src/iscsi-ls.c # Other examples noinst_PROGRAMS += bin/iscsiclient bin_iscsiclient_SOURCES = examples/iscsiclient.c EXTRA_PROGRAMS += bin/iscsi-dd bin_iscsi_dd_SOURCES = examples/iscsi-dd.c # libiscsi test tool noinst_PROGRAMS += bin/iscsi-test dist_noinst_HEADERS += test-tool/iscsi-test.h bin_iscsi_test_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/test-tool bin_iscsi_test_SOURCES = test-tool/iscsi-test.c \ test-tool/0100_read10_simple.c test-tool/0101_read10_beyond_eol.c \ test-tool/0102_read10_0blocks.c test-tool/0103_read10_rdprotect.c \ test-tool/0104_read10_flags.c test-tool/0105_read10_invalid.c \ test-tool/0110_readcapacity10_simple.c \ test-tool/0111_readcapacity10_pmi.c test-tool/0120_read6_simple.c \ test-tool/0121_read6_beyond_eol.c test-tool/0122_read6_invalid.c \ test-tool/0130_verify10_simple.c test-tool/0131_verify10_mismatch.c \ test-tool/0132_verify10_mismatch_no_cmp.c \ test-tool/0160_readcapacity16_simple.c \ test-tool/0170_unmap_simple.c test-tool/0171_unmap_zero.c \ test-tool/0180_writesame10_unmap.c test-tool/0181_writesame10_unmap_unaligned.c \ test-tool/0190_writesame16_unmap.c test-tool/0191_writesame16_unmap_unaligned.c \ test-tool/0200_read16_simple.c test-tool/0201_read16_rdprotect.c \ test-tool/0202_read16_flags.c test-tool/0203_read16_0blocks.c \ test-tool/0204_read16_beyondeol.c \ test-tool/0210_read12_simple.c test-tool/0211_read12_rdprotect.c \ test-tool/0212_read12_flags.c test-tool/0213_read12_0blocks.c \ test-tool/0214_read12_beyondeol.c \ test-tool/0220_write16_simple.c test-tool/0221_write16_wrprotect.c \ test-tool/0222_write16_flags.c test-tool/0223_write16_0blocks.c \ test-tool/0224_write16_beyondeol.c \ test-tool/0230_write12_simple.c test-tool/0231_write12_wrprotect.c \ test-tool/0232_write12_flags.c test-tool/0233_write12_0blocks.c \ test-tool/0234_write12_beyondeol.c \ test-tool/0240_prefetch10_simple.c \ test-tool/0250_prefetch16_simple.c endif # LD_PRELOAD library. if LD_ISCSI EXTRA_PROGRAMS += bin/ld_iscsi CLEANFILES = bin/ld_iscsi.o bin/ld_iscsi.so # This gets a bit messy: # # 1) let automake compile the sources bin_ld_iscsi_SOURCES = src/ld_iscsi.c bin_ld_iscsi_CFLAGS = $(AM_CFLAGS) -fPIC # 2) let libtool link in the static version of the library noinst_LTLIBRARIES = lib/libiscsi_convenience.la lib_libiscsi_convenience_la_SOURCES = $(lib_libiscsi_la_SOURCES) bin/ld_iscsi.o: src/bin_ld_iscsi-ld_iscsi.o lib/libiscsi_convenience.la $(LIBTOOL) --mode=link $(CC) -o $@ $^ # 3) Manually create the .so file. bin_SCRIPTS = bin/ld_iscsi.so bin/ld_iscsi.so: bin/ld_iscsi.o $(CC) -shared -o bin/ld_iscsi.so bin/ld_iscsi.o -ldl endif libiscsi-1.4.0/TODO0000644000175000017500000000111011750443164012151 0ustar mjtmjtSome features that should be added * More efficient api for read/write commands where we read/write straight from the socket into the buffer the application specified instead of as now we pass the data to a callback and then copy it. * More scsi marshalling and unmarshalling functions in scsi-lowlevel * Autoconnect for session faiulures. When the tcp session fail, try several times to reconnect and relogin. If successful re-issue any commands that were in flight. * Redirects * Integrate with other relevant utilities such as dvdrecord, ... * Data Digest libiscsi-1.4.0/lib/0000755000175000017500000000000011750443164012236 5ustar mjtmjtlibiscsi-1.4.0/lib/scsi-command.c0000644000175000017500000007035111750443164014765 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program 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 program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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, see . */ #if defined(WIN32) #include #else #include #endif #include #include #include #include "iscsi.h" #include "iscsi-private.h" #include "scsi-lowlevel.h" #include "slist.h" struct iscsi_scsi_cbdata { struct iscsi_scsi_cbdata *prev, *next; iscsi_command_cb callback; void *private_data; struct scsi_task *task; }; void iscsi_free_scsi_cbdata(struct iscsi_scsi_cbdata *scsi_cbdata) { if (scsi_cbdata == NULL) { return; } if (scsi_cbdata->task != NULL) { scsi_cbdata->task = NULL; } free(scsi_cbdata); } static void iscsi_scsi_response_cb(struct iscsi_context *iscsi, int status, void *command_data _U_, void *private_data) { struct iscsi_scsi_cbdata *scsi_cbdata = (struct iscsi_scsi_cbdata *)private_data; switch (status) { case SCSI_STATUS_RESERVATION_CONFLICT: case SCSI_STATUS_CHECK_CONDITION: case SCSI_STATUS_GOOD: case SCSI_STATUS_ERROR: case SCSI_STATUS_CANCELLED: scsi_cbdata->callback(iscsi, status, scsi_cbdata->task, scsi_cbdata->private_data); return; default: iscsi_set_error(iscsi, "Cant handle scsi status %d yet.", status); scsi_cbdata->callback(iscsi, SCSI_STATUS_ERROR, scsi_cbdata->task, scsi_cbdata->private_data); } } static int iscsi_send_data_out(struct iscsi_context *iscsi, struct iscsi_pdu *cmd_pdu, uint32_t ttt, uint32_t offset, uint32_t tot_len) { while (tot_len > 0) { uint32_t len = tot_len; struct iscsi_pdu *pdu; int flags; if (len > iscsi->target_max_recv_data_segment_length) { len = iscsi->target_max_recv_data_segment_length; } pdu = iscsi_allocate_pdu_with_itt_flags(iscsi, ISCSI_PDU_DATA_OUT, ISCSI_PDU_NO_PDU, cmd_pdu->itt, ISCSI_PDU_DELETE_WHEN_SENT|ISCSI_PDU_NO_CALLBACK); if (pdu == NULL) { iscsi_set_error(iscsi, "Out-of-memory, Failed to allocate " "scsi data out pdu."); SLIST_REMOVE(&iscsi->outqueue, cmd_pdu); SLIST_REMOVE(&iscsi->waitpdu, cmd_pdu); cmd_pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, cmd_pdu->private_data); iscsi_free_pdu(iscsi, cmd_pdu); return -1; } if (tot_len == len) { flags = ISCSI_PDU_SCSI_FINAL; } else { flags = 0; } /* flags */ iscsi_pdu_set_pduflags(pdu, flags); /* lun */ iscsi_pdu_set_lun(pdu, cmd_pdu->lun); /* ttt */ iscsi_pdu_set_ttt(pdu, ttt); /* exp statsn */ iscsi_pdu_set_expstatsn(pdu, iscsi->statsn+1); /* data sn */ iscsi_pdu_set_datasn(pdu, 0); /* buffer offset */ iscsi_pdu_set_bufferoffset(pdu, offset); if (iscsi_pdu_add_data(iscsi, pdu, cmd_pdu->nidata.data + offset, len) != 0) { iscsi_set_error(iscsi, "Out-of-memory: Failed to " "add outdata to the pdu."); SLIST_REMOVE(&iscsi->outqueue, cmd_pdu); SLIST_REMOVE(&iscsi->waitpdu, cmd_pdu); cmd_pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, cmd_pdu->private_data); iscsi_free_pdu(iscsi, cmd_pdu); iscsi_free_pdu(iscsi, pdu); return -1; } pdu->callback = cmd_pdu->callback; pdu->private_data = cmd_pdu->private_data;; if (iscsi_queue_pdu(iscsi, pdu) != 0) { iscsi_set_error(iscsi, "Out-of-memory: failed to queue iscsi " "scsi pdu."); SLIST_REMOVE(&iscsi->outqueue, cmd_pdu); SLIST_REMOVE(&iscsi->waitpdu, cmd_pdu); cmd_pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, cmd_pdu->private_data); iscsi_free_pdu(iscsi, cmd_pdu); iscsi_free_pdu(iscsi, pdu); return -1; } tot_len -= len; offset += len; } return 0; } int iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun, struct scsi_task *task, iscsi_command_cb cb, struct iscsi_data *d, void *private_data) { struct iscsi_pdu *pdu; struct iscsi_scsi_cbdata *scsi_cbdata; struct iscsi_data data; uint32_t offset = 0; int flags; data.data = (d != NULL) ? d->data : NULL; data.size = (d != NULL) ? d->size : 0; if (iscsi->session_type != ISCSI_SESSION_NORMAL) { iscsi_set_error(iscsi, "Trying to send command on " "discovery session."); return -1; } if (iscsi->is_loggedin == 0) { iscsi_set_error(iscsi, "Trying to send command while " "not logged in."); return -1; } scsi_cbdata = malloc(sizeof(struct iscsi_scsi_cbdata)); if (scsi_cbdata == NULL) { iscsi_set_error(iscsi, "Out-of-memory: failed to allocate " "scsi cbdata."); return -1; } memset(scsi_cbdata, 0, sizeof(struct iscsi_scsi_cbdata)); scsi_cbdata->task = task; scsi_cbdata->callback = cb; scsi_cbdata->private_data = private_data; scsi_set_task_private_ptr(task, scsi_cbdata); pdu = iscsi_allocate_pdu(iscsi, ISCSI_PDU_SCSI_REQUEST, ISCSI_PDU_SCSI_RESPONSE); if (pdu == NULL) { iscsi_set_error(iscsi, "Out-of-memory, Failed to allocate " "scsi pdu."); iscsi_free_scsi_cbdata(scsi_cbdata); return -1; } pdu->scsi_cbdata = scsi_cbdata; /* flags */ flags = ISCSI_PDU_SCSI_FINAL|ISCSI_PDU_SCSI_ATTR_SIMPLE; switch (task->xfer_dir) { case SCSI_XFER_NONE: break; case SCSI_XFER_READ: flags |= ISCSI_PDU_SCSI_READ; break; case SCSI_XFER_WRITE: flags |= ISCSI_PDU_SCSI_WRITE; if (data.size == 0) { iscsi_set_error(iscsi, "DATA-OUT command but data " "== NULL."); iscsi_free_pdu(iscsi, pdu); return -1; } if (data.size != task->expxferlen) { iscsi_set_error(iscsi, "Data size:%d is not same as " "expected data transfer " "length:%d.", data.size, task->expxferlen); iscsi_free_pdu(iscsi, pdu); return -1; } /* Assume all data is non-immediate data */ pdu->nidata.data = data.data; pdu->nidata.size = data.size; /* Are we allowed to send immediate data ? */ if (iscsi->use_immediate_data == ISCSI_IMMEDIATE_DATA_YES) { uint32_t len = data.size; if (len > iscsi->target_max_recv_data_segment_length) { len = iscsi->target_max_recv_data_segment_length; } if (iscsi_pdu_add_data(iscsi, pdu, data.data, len) != 0) { iscsi_set_error(iscsi, "Out-of-memory: Failed to " "add outdata to the pdu."); iscsi_free_pdu(iscsi, pdu); return -1; } offset = len; if (len == (uint32_t)data.size) { /* We managed to send it all as immediate data, so there is no non-immediate data left */ pdu->nidata.data = NULL; pdu->nidata.size = 0; } } if (pdu->nidata.size > 0 && iscsi->use_initial_r2t == ISCSI_INITIAL_R2T_NO) { /* We have more data to send, and we are allowed to send * unsolicited data, so dont flag this PDU as final. */ flags &= ~ISCSI_PDU_SCSI_FINAL; } break; } iscsi_pdu_set_pduflags(pdu, flags); /* lun */ iscsi_pdu_set_lun(pdu, lun); pdu->lun = lun; /* expxferlen */ iscsi_pdu_set_expxferlen(pdu, task->expxferlen); /* cmdsn */ iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn); pdu->cmdsn = iscsi->cmdsn; iscsi->cmdsn++; /* exp statsn */ iscsi_pdu_set_expstatsn(pdu, iscsi->statsn+1); /* cdb */ iscsi_pdu_set_cdb(pdu, task); pdu->callback = iscsi_scsi_response_cb; pdu->private_data = scsi_cbdata; if (iscsi_queue_pdu(iscsi, pdu) != 0) { iscsi_set_error(iscsi, "Out-of-memory: failed to queue iscsi " "scsi pdu."); iscsi_free_pdu(iscsi, pdu); return -1; } /* Can we send some unsolicited data ? */ if (pdu->nidata.size != 0 && iscsi->use_initial_r2t == ISCSI_INITIAL_R2T_NO) { uint32_t len = pdu->nidata.size - offset; if (len > iscsi->first_burst_length) { len = iscsi->first_burst_length; } iscsi_send_data_out(iscsi, pdu, 0xffffffff, offset, len); } /* remember cmdsn and itt so we can use task management */ task->cmdsn = pdu->cmdsn; task->itt = pdu->itt; task->lun = lun; return 0; } int iscsi_process_scsi_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, struct iscsi_in_pdu *in) { int statsn, flags, status; struct iscsi_scsi_cbdata *scsi_cbdata = pdu->scsi_cbdata; struct scsi_task *task = scsi_cbdata->task; statsn = ntohl(*(uint32_t *)&in->hdr[24]); if (statsn > (int)iscsi->statsn) { iscsi->statsn = statsn; } flags = in->hdr[1]; if ((flags&ISCSI_PDU_DATA_FINAL) == 0) { iscsi_set_error(iscsi, "scsi response pdu but Final bit is " "not set: 0x%02x.", flags); pdu->callback(iscsi, SCSI_STATUS_ERROR, task, pdu->private_data); return -1; } if ((flags&ISCSI_PDU_DATA_ACK_REQUESTED) != 0) { iscsi_set_error(iscsi, "scsi response asked for ACK " "0x%02x.", flags); pdu->callback(iscsi, SCSI_STATUS_ERROR, task, pdu->private_data); return -1; } status = in->hdr[3]; switch (status) { case SCSI_STATUS_GOOD: task->datain.data = pdu->indata.data; task->datain.size = pdu->indata.size; task->residual_status = SCSI_RESIDUAL_NO_RESIDUAL; task->residual = 0; /* * These flags should only be set if the S flag is also set */ if (flags & (ISCSI_PDU_DATA_RESIDUAL_OVERFLOW|ISCSI_PDU_DATA_RESIDUAL_UNDERFLOW)) { task->residual = ntohl(*((uint32_t *)&in->hdr[44])); if (flags & ISCSI_PDU_DATA_RESIDUAL_UNDERFLOW) { task->residual_status = SCSI_RESIDUAL_UNDERFLOW; } else { task->residual_status = SCSI_RESIDUAL_OVERFLOW; } } pdu->indata.data = NULL; pdu->indata.size = 0; pdu->callback(iscsi, SCSI_STATUS_GOOD, task, pdu->private_data); break; case SCSI_STATUS_CHECK_CONDITION: task->datain.size = in->data_pos; task->datain.data = malloc(task->datain.size); if (task->datain.data == NULL) { iscsi_set_error(iscsi, "failed to allocate blob for " "sense data"); } memcpy(task->datain.data, in->data, task->datain.size); task->sense.error_type = task->datain.data[2] & 0x7f; task->sense.key = task->datain.data[4] & 0x0f; task->sense.ascq = ntohs(*(uint16_t *) &(task->datain.data[14])); iscsi_set_error(iscsi, "SENSE KEY:%s(%d) ASCQ:%s(0x%04x)", scsi_sense_key_str(task->sense.key), task->sense.key, scsi_sense_ascq_str(task->sense.ascq), task->sense.ascq); pdu->callback(iscsi, SCSI_STATUS_CHECK_CONDITION, task, pdu->private_data); break; case SCSI_STATUS_RESERVATION_CONFLICT: iscsi_set_error(iscsi, "RESERVATION CONFLICT"); pdu->callback(iscsi, SCSI_STATUS_RESERVATION_CONFLICT, task, pdu->private_data); break; default: iscsi_set_error(iscsi, "Unknown SCSI status :%d.", status); pdu->callback(iscsi, SCSI_STATUS_ERROR, task, pdu->private_data); return -1; } return 0; } int iscsi_process_scsi_data_in(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, struct iscsi_in_pdu *in, int *is_finished) { int statsn, flags, status; struct iscsi_scsi_cbdata *scsi_cbdata = pdu->scsi_cbdata; struct scsi_task *task = scsi_cbdata->task; int dsl; statsn = ntohl(*(uint32_t *)&in->hdr[24]); if (statsn > (int)iscsi->statsn) { iscsi->statsn = statsn; } flags = in->hdr[1]; if ((flags&ISCSI_PDU_DATA_ACK_REQUESTED) != 0) { iscsi_set_error(iscsi, "scsi response asked for ACK " "0x%02x.", flags); pdu->callback(iscsi, SCSI_STATUS_ERROR, task, pdu->private_data); return -1; } dsl = ntohl(*(uint32_t *)&in->hdr[4])&0x00ffffff; /* Dont add to reassembly buffer if we already have a user buffer */ if (scsi_task_get_data_in_buffer(task, 0, NULL) == NULL) { if (iscsi_add_data(iscsi, &pdu->indata, in->data, dsl, 0) != 0) { iscsi_set_error(iscsi, "Out-of-memory: failed to add data " "to pdu in buffer."); return -1; } } if ((flags&ISCSI_PDU_DATA_FINAL) == 0) { *is_finished = 0; } if ((flags&ISCSI_PDU_DATA_CONTAINS_STATUS) == 0) { *is_finished = 0; } if (*is_finished == 0) { return 0; } task->residual_status = SCSI_RESIDUAL_NO_RESIDUAL; task->residual = 0; /* * These flags should only be set if the S flag is also set */ if (flags & (ISCSI_PDU_DATA_RESIDUAL_OVERFLOW|ISCSI_PDU_DATA_RESIDUAL_UNDERFLOW)) { task->residual = ntohl(*((uint32_t *)&in->hdr[44])); if (flags & ISCSI_PDU_DATA_RESIDUAL_UNDERFLOW) { task->residual_status = SCSI_RESIDUAL_UNDERFLOW; } else { task->residual_status = SCSI_RESIDUAL_OVERFLOW; } } /* this was the final data-in packet in the sequence and it has * the s-bit set, so invoke the callback. */ status = in->hdr[3]; task->datain.data = pdu->indata.data; task->datain.size = pdu->indata.size; pdu->indata.data = NULL; pdu->indata.size = 0; pdu->callback(iscsi, status, task, pdu->private_data); return 0; } int iscsi_process_r2t(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, struct iscsi_in_pdu *in) { uint32_t ttt, offset, len; ttt = ntohl(*(uint32_t *)&in->hdr[20]); offset = ntohl(*(uint32_t *)&in->hdr[40]); len = ntohl(*(uint32_t *)&in->hdr[44]); iscsi_send_data_out(iscsi, pdu, ttt, offset, len); return 0; } /* * SCSI commands */ struct scsi_task * iscsi_testunitready_task(struct iscsi_context *iscsi, int lun, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; task = scsi_cdb_testunitready(); if (task == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to create " "testunitready cdb."); return NULL; } if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } return task; } struct scsi_task * iscsi_reportluns_task(struct iscsi_context *iscsi, int report_type, int alloc_len, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; if (alloc_len < 16) { iscsi_set_error(iscsi, "Minimum allowed alloc len for " "reportluns is 16. You specified %d.", alloc_len); return NULL; } task = scsi_reportluns_cdb(report_type, alloc_len); if (task == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to create " "reportluns cdb."); return NULL; } /* report luns are always sent to lun 0 */ if (iscsi_scsi_command_async(iscsi, 0, task, cb, NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } return task; } struct scsi_task * iscsi_inquiry_task(struct iscsi_context *iscsi, int lun, int evpd, int page_code, int maxsize, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; task = scsi_cdb_inquiry(evpd, page_code, maxsize); if (task == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to create " "inquiry cdb."); return NULL; } if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } return task; } struct scsi_task * iscsi_readcapacity10_task(struct iscsi_context *iscsi, int lun, int lba, int pmi, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; task = scsi_cdb_readcapacity10(lba, pmi); if (task == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to create " "readcapacity10 cdb."); return NULL; } if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } return task; } struct scsi_task * iscsi_readcapacity16_task(struct iscsi_context *iscsi, int lun, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; task = scsi_cdb_readcapacity16(); if (task == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to create " "readcapacity16 cdb."); return NULL; } if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } return task; } struct scsi_task * iscsi_read6_task(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; if (datalen % blocksize != 0) { iscsi_set_error(iscsi, "Datalen:%d is not a multiple of " "the blocksize:%d.", datalen, blocksize); return NULL; } task = scsi_cdb_read6(lba, datalen, blocksize); if (task == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to create " "read6 cdb."); return NULL; } if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } return task; } struct scsi_task * iscsi_read10_task(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; if (datalen % blocksize != 0) { iscsi_set_error(iscsi, "Datalen:%d is not a multiple of " "the blocksize:%d.", datalen, blocksize); return NULL; } task = scsi_cdb_read10(lba, datalen, blocksize); if (task == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to create " "read10 cdb."); return NULL; } if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } return task; } struct scsi_task * iscsi_read12_task(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, int rdprotect, int dpo, int fua, int fua_nv, int group_number, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; if (datalen % blocksize != 0) { iscsi_set_error(iscsi, "Datalen:%d is not a multiple of " "the blocksize:%d.", datalen, blocksize); return NULL; } task = scsi_cdb_read12(lba, datalen, blocksize, rdprotect, dpo, fua, fua_nv, group_number); if (task == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to create " "read12 cdb."); return NULL; } if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } return task; } struct scsi_task * iscsi_read16_task(struct iscsi_context *iscsi, int lun, uint64_t lba, uint32_t datalen, int blocksize, int rdprotect, int dpo, int fua, int fua_nv, int group_number, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; if (datalen % blocksize != 0) { iscsi_set_error(iscsi, "Datalen:%d is not a multiple of " "the blocksize:%d.", datalen, blocksize); return NULL; } task = scsi_cdb_read16(lba, datalen, blocksize, rdprotect, dpo, fua, fua_nv, group_number); if (task == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to create " "read16 cdb."); return NULL; } if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } return task; } struct scsi_task * iscsi_write10_task(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int fua, int fuanv, int blocksize, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; struct iscsi_data outdata; if (datalen % blocksize != 0) { iscsi_set_error(iscsi, "Datalen:%d is not a multiple of the " "blocksize:%d.", datalen, blocksize); return NULL; } task = scsi_cdb_write10(lba, datalen, fua, fuanv, blocksize); if (task == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to create " "write10 cdb."); return NULL; } outdata.data = data; outdata.size = datalen; if (iscsi_scsi_command_async(iscsi, lun, task, cb, &outdata, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } return task; } struct scsi_task * iscsi_write12_task(struct iscsi_context *iscsi, int lun, uint32_t lba, unsigned char *data, uint32_t datalen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; struct iscsi_data outdata; if (datalen % blocksize != 0) { iscsi_set_error(iscsi, "Datalen:%d is not a multiple of the " "blocksize:%d.", datalen, blocksize); return NULL; } task = scsi_cdb_write12(lba, datalen, blocksize, wrprotect, dpo, fua, fua_nv, group_number); if (task == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to create " "write12 cdb."); return NULL; } outdata.data = data; outdata.size = datalen; if (iscsi_scsi_command_async(iscsi, lun, task, cb, &outdata, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } return task; } struct scsi_task * iscsi_write16_task(struct iscsi_context *iscsi, int lun, uint64_t lba, unsigned char *data, uint32_t datalen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; struct iscsi_data outdata; if (datalen % blocksize != 0) { iscsi_set_error(iscsi, "Datalen:%d is not a multiple of the " "blocksize:%d.", datalen, blocksize); return NULL; } task = scsi_cdb_write16(lba, datalen, blocksize, wrprotect, dpo, fua, fua_nv, group_number); if (task == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to create " "write16 cdb."); return NULL; } outdata.data = data; outdata.size = datalen; if (iscsi_scsi_command_async(iscsi, lun, task, cb, &outdata, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } return task; } struct scsi_task * iscsi_verify10_task(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; struct iscsi_data outdata; if (datalen % blocksize != 0) { iscsi_set_error(iscsi, "Datalen:%d is not a multiple of the " "blocksize:%d.", datalen, blocksize); return NULL; } task = scsi_cdb_verify10(lba, datalen, vprotect, dpo, bytchk, blocksize); if (task == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to create " "verify10 cdb."); return NULL; } outdata.data = data; outdata.size = datalen; if (iscsi_scsi_command_async(iscsi, lun, task, cb, &outdata, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } return task; } struct scsi_task * iscsi_modesense6_task(struct iscsi_context *iscsi, int lun, int dbd, int pc, int page_code, int sub_page_code, unsigned char alloc_len, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; task = scsi_cdb_modesense6(dbd, pc, page_code, sub_page_code, alloc_len); if (task == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to create " "modesense6 cdb."); return NULL; } if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } return task; } struct scsi_task * iscsi_synchronizecache10_task(struct iscsi_context *iscsi, int lun, int lba, int num_blocks, int syncnv, int immed, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; task = scsi_cdb_synchronizecache10(lba, num_blocks, syncnv, immed); if (task == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to create " "synchronizecache10 cdb."); return NULL; } if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } return task; } struct scsi_task * iscsi_prefetch10_task(struct iscsi_context *iscsi, int lun, uint32_t lba, int num_blocks, int immed, int group, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; task = scsi_cdb_prefetch10(lba, num_blocks, immed, group); if (task == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to create " "prefetch10 cdb."); return NULL; } if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } return task; } struct scsi_task * iscsi_prefetch16_task(struct iscsi_context *iscsi, int lun, uint64_t lba, int num_blocks, int immed, int group, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; task = scsi_cdb_prefetch16(lba, num_blocks, immed, group); if (task == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to create " "prefetch16 cdb."); return NULL; } if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } return task; } struct scsi_task * iscsi_writesame10_task(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, uint16_t num_blocks, int anchor, int unmap, int pbdata, int lbdata, int wrprotect, int group, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; struct iscsi_data outdata; task = scsi_cdb_writesame10(wrprotect, anchor, unmap, pbdata, lbdata, lba, group, num_blocks); if (task == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to create " "writesame10 cdb."); return NULL; } if (datalen) { outdata.data = data; outdata.size = datalen; task->expxferlen = datalen; if (iscsi_scsi_command_async(iscsi, lun, task, cb, &outdata, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } } else { task->expxferlen = 0; task->xfer_dir = SCSI_XFER_NONE; if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } } return task; } struct scsi_task * iscsi_writesame16_task(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint64_t lba, uint32_t num_blocks, int anchor, int unmap, int pbdata, int lbdata, int wrprotect, int group, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; struct iscsi_data outdata; task = scsi_cdb_writesame16(wrprotect, anchor, unmap, pbdata, lbdata, lba, group, num_blocks); if (task == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to create " "writesame16 cdb."); return NULL; } if (datalen) { outdata.data = data; outdata.size = datalen; task->expxferlen = datalen; if (iscsi_scsi_command_async(iscsi, lun, task, cb, &outdata, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } } else { task->expxferlen = 0; task->xfer_dir = SCSI_XFER_NONE; if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } } return task; } struct scsi_task * iscsi_unmap_task(struct iscsi_context *iscsi, int lun, int anchor, int group, struct unmap_list *list, int list_len, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; struct iscsi_data outdata; unsigned char *data; int xferlen; int i; xferlen = 8 + list_len * 16; task = scsi_cdb_unmap(anchor, group, xferlen); if (task == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to create " "unmap cdb."); return NULL; } data = scsi_malloc(task, xferlen); if (data == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to create " "unmap parameters."); scsi_free_scsi_task(task); return NULL; } *((uint16_t *)&data[0]) = htons(xferlen - 2); *((uint16_t *)&data[2]) = htons(xferlen - 8); for (i = 0; i < list_len; i++) { *((uint32_t *)&data[8 + 16 * i]) = htonl(list[0].lba >> 32); *((uint32_t *)&data[8 + 16 * i + 4]) = htonl(list[0].lba & 0xffffffff); *((uint32_t *)&data[8 + 16 * i + 8]) = htonl(list[0].num); } outdata.data = data; outdata.size = xferlen; if (iscsi_scsi_command_async(iscsi, lun, task, cb, &outdata, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } return task; } unsigned char * iscsi_get_user_in_buffer(struct iscsi_context *iscsi, struct iscsi_in_pdu *in, uint32_t pos, ssize_t *count) { struct iscsi_pdu *pdu; uint32_t offset; uint32_t itt; if ((in->hdr[0] & 0x3f) != ISCSI_PDU_DATA_IN) { return NULL; } offset = ntohl(*(uint32_t *)&in->hdr[40]); itt = ntohl(*(uint32_t *)&in->hdr[16]); for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) { if (pdu->itt == itt) { break; } } if (pdu == NULL) { return NULL; } return scsi_task_get_data_in_buffer(pdu->scsi_cbdata->task, offset + pos, count); } struct scsi_task * iscsi_scsi_get_task_from_pdu(struct iscsi_pdu *pdu) { return pdu->scsi_cbdata->task; } libiscsi-1.4.0/lib/md5.c0000644000175000017500000001630511750443164013074 0ustar mjtmjt/* * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD5Context structure, pass it to MD5Init, call MD5Update as * needed on buffers full of bytes, and then call MD5Final, which * will fill a supplied 16-byte array with the digest. * * Changed so as no longer to depend on Colin Plumb's `usual.h' header * definitions; now uses stuff from dpkg's config.h. * - Ian Jackson . * Still in the public domain. */ #include "md5.h" #ifdef WORDS_BIGENDIAN void byteSwap(UWORD32 *buf, unsigned words) { md5byte *p = (md5byte *)buf; do { *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 | ((unsigned)p[1] << 8 | p[0]); p += 4; } while (--words); } #else #define byteSwap(buf,words) #endif /* * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. */ void MD5Init(struct MD5Context *ctx) { ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; ctx->buf[3] = 0x10325476; ctx->bytes[0] = 0; ctx->bytes[1] = 0; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ void MD5Update(struct MD5Context *ctx, md5byte const *buf, unsigned len) { UWORD32 t; /* Update byte count */ t = ctx->bytes[0]; if ((ctx->bytes[0] = t + len) < t) ctx->bytes[1]++; /* Carry from low to high */ t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ if (t > len) { memcpy((md5byte *)ctx->in + 64 - t, buf, len); return; } /* First chunk is an odd size */ memcpy((md5byte *)ctx->in + 64 - t, buf, t); byteSwap(ctx->in, 16); MD5Transform(ctx->buf, ctx->in); buf += t; len -= t; /* Process data in 64-byte chunks */ while (len >= 64) { memcpy(ctx->in, buf, 64); byteSwap(ctx->in, 16); MD5Transform(ctx->buf, ctx->in); buf += 64; len -= 64; } /* Handle any remaining bytes of data. */ memcpy(ctx->in, buf, len); } /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ void MD5Final(md5byte digest[16], struct MD5Context *ctx) { int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ md5byte *p = (md5byte *)ctx->in + count; /* Set the first char of padding to 0x80. There is always room. */ *p++ = 0x80; /* Bytes of padding needed to make 56 bytes (-8..55) */ count = 56 - 1 - count; if (count < 0) { /* Padding forces an extra block */ memset(p, 0, count + 8); byteSwap(ctx->in, 16); MD5Transform(ctx->buf, ctx->in); p = (md5byte *)ctx->in; count = 56; } memset(p, 0, count); byteSwap(ctx->in, 14); /* Append length in bits and transform */ ctx->in[14] = ctx->bytes[0] << 3; ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; MD5Transform(ctx->buf, ctx->in); byteSwap(ctx->buf, 4); memcpy(digest, ctx->buf, 16); memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ } #ifndef ASM_MD5 /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f,w,x,y,z,in,s) \ (w += f(x,y,z) + in, w = (w<>(32-s)) + x) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) { register UWORD32 a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } #endif libiscsi-1.4.0/lib/socket.c0000644000175000017500000003207211750443164013676 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program 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 program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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, see . */ #if defined(WIN32) #include #include #define ioctl ioctlsocket #define close closesocket #else #include "config.h" #include #include #include #include #include #include #include #include #include #endif #ifdef NEED_SYS_FILIO_H #include #endif #include #include #include #include #include #include "iscsi.h" #include "iscsi-private.h" #include "slist.h" static void set_nonblocking(int fd) { #if defined(WIN32) #else unsigned v; v = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, v | O_NONBLOCK); #endif } int iscsi_connect_async(struct iscsi_context *iscsi, const char *portal, iscsi_command_cb cb, void *private_data) { int port = 3260; char *str; char *addr, *host; struct addrinfo *ai = NULL; int socksize; if (iscsi->fd != -1) { iscsi_set_error(iscsi, "Trying to connect but already connected."); return -1; } addr = strdup(portal); if (addr == NULL) { iscsi_set_error(iscsi, "Out-of-memory: " "Failed to strdup portal address."); return -1; } host = addr; /* check if we have a target portal group tag */ str = strrchr(host, ','); if (str != NULL) { str[0] = 0; } str = strrchr(host, ':'); if (str != NULL) { if (strchr(str, ']') == NULL) { if (str != NULL) { port = atoi(str+1); str[0] = 0; } } } /* ipv6 in [...] form ? */ if (host[0] == '[') { host ++; str = strchr(host, ']'); if (str == NULL) { free(addr); iscsi_set_error(iscsi, "Invalid target:%s " "Missing ']' in IPv6 address", portal); return -1; } *str = 0; } /* is it a hostname ? */ if (getaddrinfo(host, NULL, NULL, &ai) != 0) { free(addr); iscsi_set_error(iscsi, "Invalid target:%s " "Can not resolv into IPv4/v6.", portal); return -1; } free(addr); switch (ai->ai_family) { case AF_INET: socksize = sizeof(struct sockaddr_in); ((struct sockaddr_in *)(ai->ai_addr))->sin_port = htons(port); #ifdef HAVE_SOCK_SIN_LEN ((struct sockaddr_in *)(ai->ai_addr))->sin_len = socksize; #endif break; case AF_INET6: socksize = sizeof(struct sockaddr_in6); ((struct sockaddr_in6 *)(ai->ai_addr))->sin6_port = htons(port); #ifdef HAVE_SOCK_SIN_LEN ((struct sockaddr_in6 *)(ai->ai_addr))->sin6_len = socksize; #endif break; default: iscsi_set_error(iscsi, "Unknown address family :%d. " "Only IPv4/IPv6 supported so far.", ai->ai_family); freeaddrinfo(ai); return -1; } iscsi->fd = socket(ai->ai_family, SOCK_STREAM, 0); if (iscsi->fd == -1) { freeaddrinfo(ai); iscsi_set_error(iscsi, "Failed to open iscsi socket. " "Errno:%s(%d).", strerror(errno), errno); return -1; } iscsi->socket_status_cb = cb; iscsi->connect_data = private_data; set_nonblocking(iscsi->fd); if (connect(iscsi->fd, ai->ai_addr, socksize) != 0 && errno != EINPROGRESS) { iscsi_set_error(iscsi, "Connect failed with errno : " "%s(%d)", strerror(errno), errno); close(iscsi->fd); iscsi->fd = -1; freeaddrinfo(ai); return -1; } freeaddrinfo(ai); return 0; } int iscsi_disconnect(struct iscsi_context *iscsi) { if (iscsi->fd == -1) { iscsi_set_error(iscsi, "Trying to disconnect " "but not connected"); return -1; } close(iscsi->fd); iscsi->fd = -1; iscsi->is_connected = 0; return 0; } int iscsi_get_fd(struct iscsi_context *iscsi) { return iscsi->fd; } int iscsi_which_events(struct iscsi_context *iscsi) { int events = iscsi->is_connected ? POLLIN : POLLOUT; if (iscsi->outqueue) { events |= POLLOUT; } return events; } int iscsi_queue_length(struct iscsi_context *iscsi) { int i = 0; struct iscsi_pdu *pdu; for (pdu = iscsi->outqueue; pdu; pdu = pdu->next) { i++; } for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) { i++; } if (iscsi->is_connected == 0) { i++; } return i; } static int iscsi_read_from_socket(struct iscsi_context *iscsi) { struct iscsi_in_pdu *in; ssize_t data_size, count; int socket_count = 0; if (ioctl(iscsi->fd, FIONREAD, &socket_count) != 0) { iscsi_set_error(iscsi, "Socket failure. Socket FIONREAD failed"); return -1; } if (socket_count == 0) { iscsi_set_error(iscsi, "Socket failure. Socket is readable but no bytes available in FIONREAD"); return -1; } if (iscsi->incoming == NULL) { iscsi->incoming = malloc(sizeof(struct iscsi_in_pdu)); if (iscsi->incoming == NULL) { iscsi_set_error(iscsi, "Out-of-memory: failed to malloc iscsi_in_pdu"); return -1; } memset(iscsi->incoming, 0, sizeof(struct iscsi_in_pdu)); } in = iscsi->incoming; /* first we must read the header, including any digests */ if (in->hdr_pos < ISCSI_HEADER_SIZE) { /* try to only read the header, and make sure we don't * read more than is available in the socket; */ count = ISCSI_HEADER_SIZE - in->hdr_pos; if (socket_count < count) { count = socket_count; } count = recv(iscsi->fd, &in->hdr[in->hdr_pos], count, 0); if (count < 0) { if (errno == EINTR) { return 0; } iscsi_set_error(iscsi, "read from socket failed, " "errno:%d", errno); return -1; } if (count == 0) { return 0; } in->hdr_pos += count; socket_count -= count; } if (in->hdr_pos < ISCSI_HEADER_SIZE) { /* we dont have the full header yet, so return */ return 0; } data_size = iscsi_get_pdu_data_size(&in->hdr[0]); if (data_size != 0) { unsigned char *buf = NULL; /* No more data right now */ if (socket_count == 0) { return 0; } count = data_size - in->data_pos; if (count > socket_count) { count = socket_count; } /* first try to see if we already have a user buffer */ buf = iscsi_get_user_in_buffer(iscsi, in, in->data_pos, &count); /* if not, allocate one */ if (buf == NULL) { if (in->data == NULL) { in->data = malloc(data_size); if (in->data == NULL) { iscsi_set_error(iscsi, "Out-of-memory: failed to malloc iscsi_in_pdu->data(%d)", (int)data_size); return -1; } } buf = &in->data[in->data_pos]; } count = recv(iscsi->fd, buf, count, 0); if (count < 0) { if (errno == EINTR) { return 0; } iscsi_set_error(iscsi, "read from socket failed, " "errno:%d", errno); return -1; } if (count == 0) { return 0; } in->data_pos += count; socket_count -= count; } if (in->data_pos < data_size) { return 0; } SLIST_ADD_END(&iscsi->inqueue, in); iscsi->incoming = NULL; while (iscsi->inqueue != NULL) { struct iscsi_in_pdu *current = iscsi->inqueue; if (iscsi_process_pdu(iscsi, current) != 0) { return -1; } SLIST_REMOVE(&iscsi->inqueue, current); iscsi_free_iscsi_in_pdu(current); } return 0; } static int iscsi_write_to_socket(struct iscsi_context *iscsi) { ssize_t count; if (iscsi->fd == -1) { iscsi_set_error(iscsi, "trying to write but not connected"); return -1; } while (iscsi->outqueue != NULL) { ssize_t total; total = iscsi->outqueue->outdata.size; total = (total + 3) & 0xfffffffc; count = send(iscsi->fd, iscsi->outqueue->outdata.data + iscsi->outqueue->written, total - iscsi->outqueue->written, 0); if (count == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { return 0; } iscsi_set_error(iscsi, "Error when writing to " "socket :%d", errno); return -1; } iscsi->outqueue->written += count; if (iscsi->outqueue->written == total) { struct iscsi_pdu *pdu = iscsi->outqueue; SLIST_REMOVE(&iscsi->outqueue, pdu); if (pdu->flags & ISCSI_PDU_DELETE_WHEN_SENT) { iscsi_free_pdu(iscsi, pdu); } else { SLIST_ADD_END(&iscsi->waitpdu, pdu); } } } return 0; } int iscsi_service(struct iscsi_context *iscsi, int revents) { if (revents & POLLERR) { int err = 0; socklen_t err_size = sizeof(err); if (getsockopt(iscsi->fd, SOL_SOCKET, SO_ERROR, &err, &err_size) != 0 || err != 0) { if (err == 0) { err = errno; } iscsi_set_error(iscsi, "iscsi_service: socket error " "%s(%d).", strerror(err), err); } else { iscsi_set_error(iscsi, "iscsi_service: POLLERR, " "Unknown socket error."); } iscsi->socket_status_cb(iscsi, SCSI_STATUS_ERROR, NULL, iscsi->connect_data); if (iscsi->is_loggedin) { if (iscsi_reconnect(iscsi) == 0) { return 0; } } return -1; } if (revents & POLLHUP) { iscsi_set_error(iscsi, "iscsi_service: POLLHUP, " "socket error."); iscsi->socket_status_cb(iscsi, SCSI_STATUS_ERROR, NULL, iscsi->connect_data); if (iscsi->is_loggedin) { if (iscsi_reconnect(iscsi) == 0) { return 0; } } return -1; } if (iscsi->is_connected == 0 && iscsi->fd != -1 && revents&POLLOUT) { int err = 0; socklen_t err_size = sizeof(err); if (getsockopt(iscsi->fd, SOL_SOCKET, SO_ERROR, &err, &err_size) != 0 || err != 0) { if (err == 0) { err = errno; } iscsi_set_error(iscsi, "iscsi_service: socket error " "%s(%d) while connecting.", strerror(err), err); iscsi->socket_status_cb(iscsi, SCSI_STATUS_ERROR, NULL, iscsi->connect_data); if (iscsi->is_loggedin) { if (iscsi_reconnect(iscsi) == 0) { return 0; } } return -1; } #ifdef HAVE_TCP_KEEPALIVE iscsi_set_tcp_keepalive(iscsi, 30, 3, 30); #endif iscsi->is_connected = 1; iscsi->socket_status_cb(iscsi, SCSI_STATUS_GOOD, NULL, iscsi->connect_data); return 0; } if (revents & POLLOUT && iscsi->outqueue != NULL) { if (iscsi_write_to_socket(iscsi) != 0) { if (iscsi->is_loggedin) { if (iscsi_reconnect(iscsi) == 0) { return 0; } } return -1; } } if (revents & POLLIN) { if (iscsi_read_from_socket(iscsi) != 0) { if (iscsi->is_loggedin) { if (iscsi_reconnect(iscsi) == 0) { return 0; } } return -1; } } return 0; } int iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { if (pdu == NULL) { iscsi_set_error(iscsi, "trying to queue NULL pdu"); return -1; } if (iscsi->header_digest != ISCSI_HEADER_DIGEST_NONE) { unsigned long crc; if (pdu->outdata.size < ISCSI_RAW_HEADER_SIZE + 4) { iscsi_set_error(iscsi, "PDU too small (%d) to contain header digest", pdu->outdata.size); return -1; } crc = crc32c((char *)pdu->outdata.data, ISCSI_RAW_HEADER_SIZE); pdu->outdata.data[ISCSI_RAW_HEADER_SIZE+3] = (crc >> 24)&0xff; pdu->outdata.data[ISCSI_RAW_HEADER_SIZE+2] = (crc >> 16)&0xff; pdu->outdata.data[ISCSI_RAW_HEADER_SIZE+1] = (crc >> 8)&0xff; pdu->outdata.data[ISCSI_RAW_HEADER_SIZE+0] = (crc) &0xff; } SLIST_ADD_END(&iscsi->outqueue, pdu); return 0; } void iscsi_free_iscsi_in_pdu(struct iscsi_in_pdu *in) { free(in->data); free(in); } void iscsi_free_iscsi_inqueue(struct iscsi_in_pdu *inqueue) { while (inqueue != NULL) { struct iscsi_in_pdu *next = inqueue->next; iscsi_free_iscsi_in_pdu(inqueue); inqueue = next; } } #ifdef HAVE_TCP_KEEPALIVE int iscsi_set_tcp_keepalive(struct iscsi_context *iscsi, int idle, int count, int interval) { int value; value =1; if (setsockopt(iscsi->fd, SOL_SOCKET, SO_KEEPALIVE, &value, sizeof(value)) != 0) { iscsi_set_error(iscsi, "TCP: Failed to set socket option SO_KEEPALIVE. Error %s(%d)", strerror(errno), errno); return -1; } value = count; if (setsockopt(iscsi->fd, SOL_TCP, TCP_KEEPCNT, &value, sizeof(value)) != 0) { iscsi_set_error(iscsi, "TCP: Failed to set tcp keepalive count. Error %s(%d)", strerror(errno), errno); return -1; } value = interval; if (setsockopt(iscsi->fd, SOL_TCP, TCP_KEEPINTVL, &value, sizeof(value)) != 0) { iscsi_set_error(iscsi, "TCP: Failed to set tcp keepalive interval. Error %s(%d)", strerror(errno), errno); return -1; } value = idle; if (setsockopt(iscsi->fd, SOL_TCP, TCP_KEEPIDLE, &value, sizeof(value)) != 0) { iscsi_set_error(iscsi, "TCP: Failed to set tcp keepalive idle. Error %s(%d)", strerror(errno), errno); return -1; } return 0; } #endif #if defined(WIN32) int poll(struct pollfd *fds, int nfsd, int timeout) { fd_set rfds, wfds, efds; int ret; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); if (fds->events & POLLIN) { FD_SET(fds->fd, &rfds); } if (fds->events & POLLOUT) { FD_SET(fds->fd, &wfds); } FD_SET(fds->fd, &efds); select(fds->fd + 1, &rfds, &wfds, &efds, NULL); fds->revents = 0; if (FD_ISSET(fds->fd, &rfds)) { fds->revents |= POLLIN; } if (FD_ISSET(fds->fd, &wfds)) { fds->revents |= POLLOUT; } if (FD_ISSET(fds->fd, &efds)) { fds->revents |= POLLHUP; } return 1; } #endif libiscsi-1.4.0/lib/crc32c.c0000644000175000017500000001316311750443164013465 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program 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 program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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, see . */ #if defined(WIN32) #else #include #endif #include "iscsi.h" #include "iscsi-private.h" /*****************************************************************/ /* */ /* CRC LOOKUP TABLE */ /* ================ */ /* The following CRC lookup table was generated automagically */ /* by the Rocksoft^tm Model CRC Algorithm Table Generation */ /* Program V1.0 using the following model parameters: */ /* */ /* Width : 4 bytes. */ /* Poly : 0x1EDC6F41L */ /* Reverse : TRUE. */ /* */ /* For more information on the Rocksoft^tm Model CRC Algorithm, */ /* see the document titled "A Painless Guide to CRC Error */ /* Detection Algorithms" by Ross Williams */ /* (ross@guest.adelaide.edu.au.). This document is likely to be */ /* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft". */ /* */ /*****************************************************************/ static unsigned long crctable[256] = { 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL, 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L, 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL, 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L, 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L, 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL, 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL, 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L, 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L, 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL, 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L, 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL, 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL, 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L, 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L, 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L, 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L, 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L, 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L, 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L, 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L, 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L, 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L, 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L, 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L, 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L, 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L, 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L, 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L, 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L, 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL, 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L, 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L, 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL, 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L, 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL, 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL, 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L, 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L, 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL, 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL, 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L, 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL, 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L, 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L, 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL, 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L, 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL, 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL, 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L, 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL, 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L, 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L, 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL, 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL, 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L, 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L, 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL, 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L, 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL, 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L }; unsigned long crc32c(char *buf, int len) { unsigned long crc = 0xffffffff; while (len-- > 0) { crc = (crc>>8) ^ crctable[(crc ^ (*buf++)) & 0xFF]; } return crc^0xffffffff; } libiscsi-1.4.0/lib/sync.c0000644000175000017500000003242711750443164013366 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program 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 program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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, see . */ #if defined(WIN32) #include #else #include #endif #include #include #include #include "iscsi.h" #include "iscsi-private.h" #include "scsi-lowlevel.h" struct iscsi_sync_state { int finished; int status; struct scsi_task *task; }; static void event_loop(struct iscsi_context *iscsi, struct iscsi_sync_state *state) { struct pollfd pfd; int ret; while (state->finished == 0) { pfd.fd = iscsi_get_fd(iscsi); pfd.events = iscsi_which_events(iscsi); if ((ret = poll(&pfd, 1, 1000)) < 0) { iscsi_set_error(iscsi, "Poll failed"); return; } if (ret == 0) { /* poll timedout, try again */ continue; } if (iscsi_service(iscsi, pfd.revents) < 0) { /* if we are reconnecting we just try and try again */ if (iscsi->is_reconnecting) { continue; } iscsi_set_error(iscsi, "iscsi_service failed with : %s", iscsi_get_error(iscsi)); return; } } } /* * Synchronous iSCSI commands */ static void iscsi_sync_cb(struct iscsi_context *iscsi _U_, int status, void *command_data _U_, void *private_data) { struct iscsi_sync_state *state = private_data; state->status = status; state->finished = 1; } int iscsi_connect_sync(struct iscsi_context *iscsi, const char *portal) { struct iscsi_sync_state state; memset(&state, 0, sizeof(state)); if (iscsi_connect_async(iscsi, portal, iscsi_sync_cb, &state) != 0) { iscsi_set_error(iscsi, "Failed to start connect() %s", iscsi_get_error(iscsi)); return -1; } event_loop(iscsi, &state); return state.status; } int iscsi_full_connect_sync(struct iscsi_context *iscsi, const char *portal, int lun) { struct iscsi_sync_state state; memset(&state, 0, sizeof(state)); if (iscsi_full_connect_async(iscsi, portal, lun, iscsi_sync_cb, &state) != 0) { iscsi_set_error(iscsi, "Failed to start full connect %s", iscsi_get_error(iscsi)); return -1; } event_loop(iscsi, &state); return state.status; } int iscsi_login_sync(struct iscsi_context *iscsi) { struct iscsi_sync_state state; memset(&state, 0, sizeof(state)); if (iscsi_login_async(iscsi, iscsi_sync_cb, &state) != 0) { iscsi_set_error(iscsi, "Failed to login. %s", iscsi_get_error(iscsi)); return -1; } event_loop(iscsi, &state); return state.status; } int iscsi_logout_sync(struct iscsi_context *iscsi) { struct iscsi_sync_state state; memset(&state, 0, sizeof(state)); if (iscsi_logout_async(iscsi, iscsi_sync_cb, &state) != 0) { iscsi_set_error(iscsi, "Failed to start logout() %s", iscsi_get_error(iscsi)); return -1; } event_loop(iscsi, &state); return state.status; } /* * Synchronous SCSI commands */ static void scsi_sync_cb(struct iscsi_context *iscsi _U_, int status, void *command_data, void *private_data) { struct scsi_task *task = command_data; struct iscsi_sync_state *state = private_data; task->status = status; state->status = status; state->finished = 1; state->task = task; } struct scsi_task * iscsi_reportluns_sync(struct iscsi_context *iscsi, int report_type, int alloc_len) { struct iscsi_sync_state state; memset(&state, 0, sizeof(state)); if (iscsi_reportluns_task(iscsi, report_type, alloc_len, scsi_sync_cb, &state) == NULL) { iscsi_set_error(iscsi, "Failed to send ReportLuns command"); return NULL; } event_loop(iscsi, &state); return state.task; } struct scsi_task * iscsi_testunitready_sync(struct iscsi_context *iscsi, int lun) { struct iscsi_sync_state state; memset(&state, 0, sizeof(state)); if (iscsi_testunitready_task(iscsi, lun, scsi_sync_cb, &state) == NULL) { iscsi_set_error(iscsi, "Failed to send TestUnitReady command"); return NULL; } event_loop(iscsi, &state); return state.task; } struct scsi_task * iscsi_inquiry_sync(struct iscsi_context *iscsi, int lun, int evpd, int page_code, int maxsize) { struct iscsi_sync_state state; memset(&state, 0, sizeof(state)); if (iscsi_inquiry_task(iscsi, lun, evpd, page_code, maxsize, scsi_sync_cb, &state) == NULL) { iscsi_set_error(iscsi, "Failed to send Inquiry command"); return NULL; } event_loop(iscsi, &state); return state.task; } struct scsi_task * iscsi_read6_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize) { struct iscsi_sync_state state; memset(&state, 0, sizeof(state)); if (iscsi_read6_task(iscsi, lun, lba, datalen, blocksize, scsi_sync_cb, &state) == NULL) { iscsi_set_error(iscsi, "Failed to send Read6 command"); return NULL; } event_loop(iscsi, &state); return state.task; } struct scsi_task * iscsi_read10_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize) { struct iscsi_sync_state state; memset(&state, 0, sizeof(state)); if (iscsi_read10_task(iscsi, lun, lba, datalen, blocksize, scsi_sync_cb, &state) == NULL) { iscsi_set_error(iscsi, "Failed to send Read10 command"); return NULL; } event_loop(iscsi, &state); return state.task; } struct scsi_task * iscsi_read12_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, int rdprotect, int dpo, int fua, int fua_nv, int group_number) { struct iscsi_sync_state state; memset(&state, 0, sizeof(state)); if (iscsi_read12_task(iscsi, lun, lba, datalen, blocksize, rdprotect, dpo, fua, fua_nv, group_number, scsi_sync_cb, &state) == NULL) { iscsi_set_error(iscsi, "Failed to send Read12 command"); return NULL; } event_loop(iscsi, &state); return state.task; } struct scsi_task * iscsi_read16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba, uint32_t datalen, int blocksize, int rdprotect, int dpo, int fua, int fua_nv, int group_number) { struct iscsi_sync_state state; memset(&state, 0, sizeof(state)); if (iscsi_read16_task(iscsi, lun, lba, datalen, blocksize, rdprotect, dpo, fua, fua_nv, group_number, scsi_sync_cb, &state) == NULL) { iscsi_set_error(iscsi, "Failed to send Read16 command"); return NULL; } event_loop(iscsi, &state); return state.task; } struct scsi_task * iscsi_readcapacity10_sync(struct iscsi_context *iscsi, int lun, int lba, int pmi) { struct iscsi_sync_state state; memset(&state, 0, sizeof(state)); if (iscsi_readcapacity10_task(iscsi, lun, lba, pmi, scsi_sync_cb, &state) == NULL) { iscsi_set_error(iscsi, "Failed to send ReadCapacity10 command"); return NULL; } event_loop(iscsi, &state); return state.task; } struct scsi_task * iscsi_readcapacity16_sync(struct iscsi_context *iscsi, int lun) { struct iscsi_sync_state state; memset(&state, 0, sizeof(state)); if (iscsi_readcapacity16_task(iscsi, lun, scsi_sync_cb, &state) == NULL) { iscsi_set_error(iscsi, "Failed to send ReadCapacity16 command"); return NULL; } event_loop(iscsi, &state); return state.task; } struct scsi_task * iscsi_synchronizecache10_sync(struct iscsi_context *iscsi, int lun, int lba, int num_blocks, int syncnv, int immed) { struct iscsi_sync_state state; memset(&state, 0, sizeof(state)); if (iscsi_synchronizecache10_task(iscsi, lun, lba, num_blocks, syncnv, immed, scsi_sync_cb, &state) == NULL) { iscsi_set_error(iscsi, "Failed to send SynchronizeCache10 command"); return NULL; } event_loop(iscsi, &state); return state.task; } struct scsi_task * iscsi_prefetch10_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, int num_blocks, int immed, int group) { struct iscsi_sync_state state; memset(&state, 0, sizeof(state)); if (iscsi_prefetch10_task(iscsi, lun, lba, num_blocks, immed, group, scsi_sync_cb, &state) == NULL) { iscsi_set_error(iscsi, "Failed to send PreFetch10 command"); return NULL; } event_loop(iscsi, &state); return state.task; } struct scsi_task * iscsi_prefetch16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba, int num_blocks, int immed, int group) { struct iscsi_sync_state state; memset(&state, 0, sizeof(state)); if (iscsi_prefetch16_task(iscsi, lun, lba, num_blocks, immed, group, scsi_sync_cb, &state) == NULL) { iscsi_set_error(iscsi, "Failed to send PreFetch16 command"); return NULL; } event_loop(iscsi, &state); return state.task; } struct scsi_task * iscsi_write10_sync(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int fua, int fuanv, int blocksize) { struct iscsi_sync_state state; memset(&state, 0, sizeof(state)); if (iscsi_write10_task(iscsi, lun, data, datalen, lba, fua, fuanv, blocksize, scsi_sync_cb, &state) == NULL) { iscsi_set_error(iscsi, "Failed to send Write10 command"); return NULL; } event_loop(iscsi, &state); return state.task; } struct scsi_task * iscsi_write12_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, unsigned char *data, uint32_t datalen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number) { struct iscsi_sync_state state; memset(&state, 0, sizeof(state)); if (iscsi_write12_task(iscsi, lun, lba, data, datalen, blocksize, wrprotect, dpo, fua, fua_nv, group_number, scsi_sync_cb, &state) == NULL) { iscsi_set_error(iscsi, "Failed to send Write12 command"); return NULL; } event_loop(iscsi, &state); return state.task; } struct scsi_task * iscsi_write16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba, unsigned char *data, uint32_t datalen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number) { struct iscsi_sync_state state; memset(&state, 0, sizeof(state)); if (iscsi_write16_task(iscsi, lun, lba, data, datalen, blocksize, wrprotect, dpo, fua, fua_nv, group_number, scsi_sync_cb, &state) == NULL) { iscsi_set_error(iscsi, "Failed to send Write16 command"); return NULL; } event_loop(iscsi, &state); return state.task; } struct scsi_task * iscsi_verify10_sync(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize) { struct iscsi_sync_state state; memset(&state, 0, sizeof(state)); if (iscsi_verify10_task(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize, scsi_sync_cb, &state) == NULL) { iscsi_set_error(iscsi, "Failed to send Verify10 command"); return NULL; } event_loop(iscsi, &state); return state.task; } struct scsi_task * iscsi_writesame10_sync(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, uint16_t num_blocks, int anchor, int unmap, int pbdata, int lbdata, int wrprotect, int group) { struct iscsi_sync_state state; memset(&state, 0, sizeof(state)); if (iscsi_writesame10_task(iscsi, lun, data, datalen, lba, num_blocks, anchor, unmap, pbdata, lbdata, wrprotect, group, scsi_sync_cb, &state) == NULL) { iscsi_set_error(iscsi, "Failed to send WRITESAME10 command"); return NULL; } event_loop(iscsi, &state); return state.task; } struct scsi_task * iscsi_writesame16_sync(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint64_t lba, uint32_t num_blocks, int anchor, int unmap, int pbdata, int lbdata, int wrprotect, int group) { struct iscsi_sync_state state; memset(&state, 0, sizeof(state)); if (iscsi_writesame16_task(iscsi, lun, data, datalen, lba, num_blocks, anchor, unmap, pbdata, lbdata, wrprotect, group, scsi_sync_cb, &state) == NULL) { iscsi_set_error(iscsi, "Failed to send WRITESAME16 command"); return NULL; } event_loop(iscsi, &state); return state.task; } struct scsi_task * iscsi_unmap_sync(struct iscsi_context *iscsi, int lun, int anchor, int group, struct unmap_list *list, int list_len) { struct iscsi_sync_state state; memset(&state, 0, sizeof(state)); if (iscsi_unmap_task(iscsi, lun, anchor, group, list, list_len, scsi_sync_cb, &state) == NULL) { iscsi_set_error(iscsi, "Failed to send UNMAP command"); return NULL; } event_loop(iscsi, &state); return state.task; } struct scsi_task * iscsi_scsi_command_sync(struct iscsi_context *iscsi, int lun, struct scsi_task *task, struct iscsi_data *data) { struct iscsi_sync_state state; memset(&state, 0, sizeof(state)); if (iscsi_scsi_command_async(iscsi, lun, task, scsi_sync_cb, data, &state) != 0) { iscsi_set_error(iscsi, "Failed to send SCSI command"); return NULL; } event_loop(iscsi, &state); return state.task; } libiscsi-1.4.0/lib/scsi-lowlevel.c0000644000175000017500000012434611750443164015204 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program 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 program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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, see . */ /* * would be nice if this could grow into a full blown library for scsi to * 1, build a CDB * 2, check how big a complete data-in structure needs to be * 3, unmarshall data-in into a real structure * 4, marshall a real structure into a data-out blob */ #if defined(WIN32) #include #else #include #include #endif #include #include #include #include #include #include "slist.h" #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-private.h" void scsi_free_scsi_task(struct scsi_task *task) { struct scsi_allocated_memory *mem; while ((mem = task->mem)) { SLIST_REMOVE(&task->mem, mem); free(mem->ptr); free(mem); } free(task->datain.data); free(task); } void * scsi_malloc(struct scsi_task *task, size_t size) { struct scsi_allocated_memory *mem; mem = malloc(sizeof(struct scsi_allocated_memory)); if (mem == NULL) { return NULL; } memset(mem, 0, sizeof(struct scsi_allocated_memory)); mem->ptr = malloc(size); if (mem->ptr == NULL) { free(mem); return NULL; } memset(mem->ptr, 0, size); SLIST_ADD(&task->mem, mem); return mem->ptr; } struct value_string { int value; const char *string; }; static const char * value_string_find(struct value_string *values, int value) { for (; values->value; values++) { if (value == values->value) { return values->string; } } return NULL; } const char * scsi_sense_key_str(int key) { struct value_string keys[] = { {SCSI_SENSE_HARDWARE_ERROR, "HARDWARE_ERROR"}, {SCSI_SENSE_ILLEGAL_REQUEST, "ILLEGAL_REQUEST"}, {SCSI_SENSE_UNIT_ATTENTION, "UNIT_ATTENTION"}, {0, NULL} }; return value_string_find(keys, key); } const char * scsi_sense_ascq_str(int ascq) { struct value_string ascqs[] = { {SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE, "INVALID_OPERATION_CODE"}, {SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE, "LBA_OUT_OF_RANGE"}, {SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB, "INVALID_FIELD_IN_CDB"}, {SCSI_SENSE_ASCQ_LOGICAL_UNIT_NOT_SUPPORTED, "LOGICAL_UNIT_NOT_SUPPORTED"}, {SCSI_SENSE_ASCQ_BUS_RESET, "BUS_RESET"}, {SCSI_SENSE_ASCQ_INTERNAL_TARGET_FAILURE, "INTERNAL_TARGET_FAILURE"}, {0, NULL} }; return value_string_find(ascqs, ascq); } /* * TESTUNITREADY */ struct scsi_task * scsi_cdb_testunitready(void) { struct scsi_task *task; task = malloc(sizeof(struct scsi_task)); if (task == NULL) { return NULL; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_TESTUNITREADY; task->cdb_size = 6; task->xfer_dir = SCSI_XFER_NONE; task->expxferlen = 0; return task; } /* * REPORTLUNS */ struct scsi_task * scsi_reportluns_cdb(int report_type, int alloc_len) { struct scsi_task *task; task = malloc(sizeof(struct scsi_task)); if (task == NULL) { return NULL; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_REPORTLUNS; task->cdb[2] = report_type; *(uint32_t *)&task->cdb[6] = htonl(alloc_len); task->cdb_size = 12; task->xfer_dir = SCSI_XFER_READ; task->expxferlen = alloc_len; task->params.reportluns.report_type = report_type; return task; } /* * parse the data in blob and calcualte the size of a full report luns * datain structure */ static int scsi_reportluns_datain_getfullsize(struct scsi_task *task) { uint32_t list_size; list_size = htonl(*(uint32_t *)&(task->datain.data[0])) + 8; return list_size; } /* * unmarshall the data in blob for reportluns into a structure */ static struct scsi_reportluns_list * scsi_reportluns_datain_unmarshall(struct scsi_task *task) { struct scsi_reportluns_list *list; int list_size; int i, num_luns; if (task->datain.size < 4) { return NULL; } list_size = htonl(*(uint32_t *)&(task->datain.data[0])) + 8; if (list_size < task->datain.size) { return NULL; } num_luns = list_size / 8 - 1; list = scsi_malloc(task, offsetof(struct scsi_reportluns_list, luns) + sizeof(uint16_t) * num_luns); if (list == NULL) { return NULL; } list->num = num_luns; for (i = 0; i < num_luns; i++) { list->luns[i] = htons(*(uint16_t *) &(task->datain.data[i*8+8])); } return list; } /* * READCAPACITY10 */ struct scsi_task * scsi_cdb_readcapacity10(int lba, int pmi) { struct scsi_task *task; task = malloc(sizeof(struct scsi_task)); if (task == NULL) { return NULL; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_READCAPACITY10; *(uint32_t *)&task->cdb[2] = htonl(lba); if (pmi) { task->cdb[8] |= 0x01; } task->cdb_size = 10; task->xfer_dir = SCSI_XFER_READ; task->expxferlen = 8; task->params.readcapacity10.lba = lba; task->params.readcapacity10.pmi = pmi; return task; } /* * service_action_in unmarshall */ static void * scsi_serviceactionin_datain_unmarshall(struct scsi_task *task) { struct scsi_readcapacity16 *rc16; switch (task->params.serviceactionin.sa) { case SCSI_READCAPACITY16: rc16 = scsi_malloc(task, sizeof(struct scsi_readcapacity16)); if (rc16 == NULL) { return NULL; } rc16->returned_lba = htonl(*(uint32_t *)&(task->datain.data[0])); rc16->returned_lba = (rc16->returned_lba << 32) | htonl(*(uint32_t *)&(task->datain.data[4])); rc16->block_length = htonl(*(uint32_t *)&(task->datain.data[8])); rc16->p_type = (task->datain.data[12] >> 1) & 0x07; rc16->prot_en = task->datain.data[12] & 0x01; rc16->p_i_exp = (task->datain.data[13] >> 4) & 0x0f; rc16->lbppbe = task->datain.data[13] & 0x0f; rc16->lbpme = !!(task->datain.data[14] & 0x80); rc16->lbprz = !!(task->datain.data[14] & 0x40); rc16->lalba = htons(*(uint16_t *)&(task->datain.data[14])) & 0x3fff; return rc16; } return NULL; } /* * parse the data in blob and calcualte the size of a full * readcapacity10 datain structure */ static int scsi_readcapacity10_datain_getfullsize(struct scsi_task *task _U_) { return 8; } /* * unmarshall the data in blob for readcapacity10 into a structure */ static struct scsi_readcapacity10 * scsi_readcapacity10_datain_unmarshall(struct scsi_task *task) { struct scsi_readcapacity10 *rc10; if (task->datain.size < 8) { return NULL; } rc10 = scsi_malloc(task, sizeof(struct scsi_readcapacity10)); if (rc10 == NULL) { return NULL; } rc10->lba = htonl(*(uint32_t *)&(task->datain.data[0])); rc10->block_size = htonl(*(uint32_t *)&(task->datain.data[4])); return rc10; } /* * INQUIRY */ struct scsi_task * scsi_cdb_inquiry(int evpd, int page_code, int alloc_len) { struct scsi_task *task; task = malloc(sizeof(struct scsi_task)); if (task == NULL) { return NULL; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_INQUIRY; if (evpd) { task->cdb[1] |= 0x01; } task->cdb[2] = page_code; *(uint16_t *)&task->cdb[3] = htons(alloc_len); task->cdb_size = 6; task->xfer_dir = SCSI_XFER_READ; task->expxferlen = alloc_len; task->params.inquiry.evpd = evpd; task->params.inquiry.page_code = page_code; return task; } /* * parse the data in blob and calcualte the size of a full * inquiry datain structure */ static int scsi_inquiry_datain_getfullsize(struct scsi_task *task) { if (task->params.inquiry.evpd == 0) { return task->datain.data[4] + 3; } switch (task->params.inquiry.page_code) { case SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES: case SCSI_INQUIRY_PAGECODE_BLOCK_DEVICE_CHARACTERISTICS: case SCSI_INQUIRY_PAGECODE_UNIT_SERIAL_NUMBER: return task->datain.data[3] + 4; case SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION: case SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS: case SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING: return ntohs(*(uint16_t *)&task->datain.data[2]) + 4; default: return -1; } } /* * unmarshall the data in blob for inquiry into a structure */ static void * scsi_inquiry_datain_unmarshall(struct scsi_task *task) { if (task->params.inquiry.evpd == 0) { struct scsi_inquiry_standard *inq; /* standard inquiry */ inq = scsi_malloc(task, sizeof(struct scsi_inquiry_standard)); if (inq == NULL) { return NULL; } inq->periperal_qualifier = (task->datain.data[0]>>5)&0x07; inq->periperal_device_type = task->datain.data[0]&0x1f; inq->rmb = !!(task->datain.data[1]&0x80); inq->version = task->datain.data[2]; inq->normaca = !!(task->datain.data[3]&0x20); inq->hisup = !!(task->datain.data[3]&0x10); inq->response_data_format = task->datain.data[3]&0x0f; inq->sccs = !!(task->datain.data[5]&0x80); inq->acc = !!(task->datain.data[5]&0x40); inq->tpgs = (task->datain.data[5]>>4)&0x03; inq->threepc = !!(task->datain.data[5]&0x08); inq->protect = !!(task->datain.data[5]&0x01); inq->encserv = !!(task->datain.data[6]&0x40); inq->multip = !!(task->datain.data[6]&0x10); inq->addr16 = !!(task->datain.data[6]&0x01); inq->wbus16 = !!(task->datain.data[7]&0x20); inq->sync = !!(task->datain.data[7]&0x10); inq->cmdque = !!(task->datain.data[7]&0x02); memcpy(&inq->vendor_identification[0], &task->datain.data[8], 8); memcpy(&inq->product_identification[0], &task->datain.data[16], 16); memcpy(&inq->product_revision_level[0], &task->datain.data[32], 4); inq->clocking = (task->datain.data[56]>>2)&0x03; inq->qas = !!(task->datain.data[56]&0x02); inq->ius = !!(task->datain.data[56]&0x01); return inq; } if (task->params.inquiry.page_code == SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES) { struct scsi_inquiry_supported_pages *inq; inq = scsi_malloc(task, sizeof(struct scsi_inquiry_supported_pages)); if (inq == NULL) { return NULL; } inq->periperal_qualifier = (task->datain.data[0]>>5)&0x07; inq->periperal_device_type = task->datain.data[0]&0x1f; inq->pagecode = task->datain.data[1]; inq->num_pages = task->datain.data[3]; inq->pages = scsi_malloc(task, inq->num_pages); if (inq->pages == NULL) { return NULL; } memcpy(inq->pages, &task->datain.data[4], inq->num_pages); return inq; } else if (task->params.inquiry.page_code == SCSI_INQUIRY_PAGECODE_UNIT_SERIAL_NUMBER) { struct scsi_inquiry_unit_serial_number *inq; inq = scsi_malloc(task, sizeof(struct scsi_inquiry_unit_serial_number)); if (inq == NULL) { return NULL; } inq->periperal_qualifier = (task->datain.data[0]>>5)&0x07; inq->periperal_device_type = task->datain.data[0]&0x1f; inq->pagecode = task->datain.data[1]; inq->usn = scsi_malloc(task, task->datain.data[3]+1); if (inq->usn == NULL) { return NULL; } memcpy(inq->usn, &task->datain.data[4], task->datain.data[3]); inq->usn[task->datain.data[3]] = 0; return inq; } else if (task->params.inquiry.page_code == SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION) { struct scsi_inquiry_device_identification *inq; int remaining = ntohs(*(uint16_t *)&task->datain.data[2]); unsigned char *dptr; inq = scsi_malloc(task, sizeof(struct scsi_inquiry_device_identification)); if (inq == NULL) { return NULL; } inq->periperal_qualifier = (task->datain.data[0]>>5)&0x07; inq->periperal_device_type = task->datain.data[0]&0x1f; inq->pagecode = task->datain.data[1]; dptr = &task->datain.data[4]; while (remaining > 0) { struct scsi_inquiry_device_designator *dev; dev = scsi_malloc(task, sizeof(struct scsi_inquiry_device_designator)); if (dev == NULL) { return NULL; } dev->next = inq->designators; inq->designators = dev; dev->protocol_identifier = (dptr[0]>>4) & 0x0f; dev->code_set = dptr[0] & 0x0f; dev->piv = !!(dptr[1]&0x80); dev->association = (dptr[1]>>4)&0x03; dev->designator_type = dptr[1]&0x0f; dev->designator_length = dptr[3]; dev->designator = scsi_malloc(task, dev->designator_length+1); if (dev->designator == NULL) { return NULL; } dev->designator[dev->designator_length] = 0; memcpy(dev->designator, &dptr[4], dev->designator_length); remaining -= 4; remaining -= dev->designator_length; dptr += dev->designator_length + 4; } return inq; } else if (task->params.inquiry.page_code == SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS) { struct scsi_inquiry_block_limits *inq; inq = scsi_malloc(task, sizeof(struct scsi_inquiry_block_limits)); if (inq == NULL) { return NULL; } inq->periperal_qualifier = (task->datain.data[0]>>5)&0x07; inq->periperal_device_type = task->datain.data[0]&0x1f; inq->pagecode = task->datain.data[1]; inq->wsnz = task->datain.data[4] & 0x01; inq->max_cmp = task->datain.data[5]; inq->opt_gran = ntohs(*(uint16_t *)&task->datain.data[6]); inq->max_xfer_len = ntohl(*(uint32_t *)&task->datain.data[8]); inq->opt_xfer_len = ntohl(*(uint32_t *)&task->datain.data[12]); inq->max_prefetch = ntohl(*(uint32_t *)&task->datain.data[16]); inq->max_unmap = ntohl(*(uint32_t *)&task->datain.data[20]); inq->max_unmap_bdc = ntohl(*(uint32_t *)&task->datain.data[24]); inq->opt_unmap_gran = ntohl(*(uint32_t *)&task->datain.data[28]); inq->ugavalid = !!(task->datain.data[32]&0x80); inq->unmap_gran_align = ntohl(*(uint32_t *)&task->datain.data[32]) & 0x7fffffff; inq->max_ws_len = ntohl(*(uint32_t *)&task->datain.data[36]); inq->max_ws_len = (inq->max_ws_len << 32) | ntohl(*(uint32_t *)&task->datain.data[40]); return inq; } else if (task->params.inquiry.page_code == SCSI_INQUIRY_PAGECODE_BLOCK_DEVICE_CHARACTERISTICS) { struct scsi_inquiry_block_device_characteristics *inq; inq = scsi_malloc(task, sizeof(struct scsi_inquiry_block_device_characteristics)); if (inq == NULL) { return NULL; } inq->periperal_qualifier = (task->datain.data[0]>>5)&0x07; inq->periperal_device_type = task->datain.data[0]&0x1f; inq->pagecode = task->datain.data[1]; inq->medium_rotation_rate = ntohs(*(uint16_t *)&task->datain.data[4]); return inq; } else if (task->params.inquiry.page_code == SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING) { struct scsi_inquiry_logical_block_provisioning *inq; inq = scsi_malloc(task, sizeof(struct scsi_inquiry_logical_block_provisioning)); if (inq == NULL) { return NULL; } inq->periperal_qualifier = (task->datain.data[0]>>5)&0x07; inq->periperal_device_type = task->datain.data[0]&0x1f; inq->pagecode = task->datain.data[1]; inq->threshold_exponent = task->datain.data[4]; inq->lbpu = !!(task->datain.data[5] & 0x80); inq->lbpws = !!(task->datain.data[5] & 0x40); inq->lbpws10 = !!(task->datain.data[5] & 0x20); inq->lbprz = !!(task->datain.data[5] & 0x04); inq->anc_sup = !!(task->datain.data[5] & 0x02); inq->dp = !!(task->datain.data[5] & 0x01); inq->provisioning_type = task->datain.data[6] & 0x07; return inq; } return NULL; } /* * READ6 */ struct scsi_task * scsi_cdb_read6(uint32_t lba, uint32_t xferlen, int blocksize) { struct scsi_task *task; int num_blocks; num_blocks = xferlen/blocksize; if (num_blocks > 265) { return NULL; } if (lba > 0x1fffff) { return NULL; } task = malloc(sizeof(struct scsi_task)); if (task == NULL) { return NULL; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_READ6; task->cdb_size = 6; task->cdb[1] = (lba>>16)&0x1f; task->cdb[2] = (lba>> 8)&0xff; task->cdb[3] = (lba )&0xff; if (num_blocks < 256) { task->cdb[4] = num_blocks; } task->xfer_dir = SCSI_XFER_READ; task->expxferlen = xferlen; task->params.read6.lba = lba; task->params.read6.num_blocks = num_blocks; return task; } /* * READ10 */ struct scsi_task * scsi_cdb_read10(uint32_t lba, uint32_t xferlen, int blocksize) { struct scsi_task *task; task = malloc(sizeof(struct scsi_task)); if (task == NULL) { return NULL; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_READ10; *(uint32_t *)&task->cdb[2] = htonl(lba); *(uint16_t *)&task->cdb[7] = htons(xferlen/blocksize); task->cdb_size = 10; if (xferlen != 0) { task->xfer_dir = SCSI_XFER_READ; } else { task->xfer_dir = SCSI_XFER_NONE; } task->expxferlen = xferlen; task->params.read10.lba = lba; task->params.read10.num_blocks = xferlen/blocksize; return task; } /* * READ12 */ struct scsi_task * scsi_cdb_read12(uint32_t lba, uint32_t xferlen, int blocksize, int rdprotect, int dpo, int fua, int fua_nv, int group_number) { struct scsi_task *task; task = malloc(sizeof(struct scsi_task)); if (task == NULL) { return NULL; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_READ12; task->cdb[1] |= ((rdprotect & 0x07) << 5); if (dpo) { task->cdb[1] |= 0x10; } if (fua) { task->cdb[1] |= 0x08; } if (fua_nv) { task->cdb[1] |= 0x02; } *(uint32_t *)&task->cdb[2] = htonl(lba); *(uint32_t *)&task->cdb[6] = htonl(xferlen/blocksize); task->cdb[10] |= (group_number & 0x1f); task->cdb_size = 12; if (xferlen != 0) { task->xfer_dir = SCSI_XFER_READ; } else { task->xfer_dir = SCSI_XFER_NONE; } task->expxferlen = xferlen; task->params.read12.lba = lba; task->params.read12.num_blocks = xferlen/blocksize; return task; } /* * READ16 */ struct scsi_task * scsi_cdb_read16(uint64_t lba, uint32_t xferlen, int blocksize, int rdprotect, int dpo, int fua, int fua_nv, int group_number) { struct scsi_task *task; task = malloc(sizeof(struct scsi_task)); if (task == NULL) { return NULL; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_READ16; task->cdb[1] |= ((rdprotect & 0x07) << 5); if (dpo) { task->cdb[1] |= 0x10; } if (fua) { task->cdb[1] |= 0x08; } if (fua_nv) { task->cdb[1] |= 0x02; } *(uint32_t *)&task->cdb[2] = htonl(lba >> 32); *(uint32_t *)&task->cdb[6] = htonl(lba & 0xffffffff); *(uint32_t *)&task->cdb[10] = htonl(xferlen/blocksize); task->cdb[14] |= (group_number & 0x1f); task->cdb_size = 16; if (xferlen != 0) { task->xfer_dir = SCSI_XFER_READ; } else { task->xfer_dir = SCSI_XFER_NONE; } task->expxferlen = xferlen; task->params.read16.lba = lba; task->params.read16.num_blocks = xferlen/blocksize; return task; } /* * WRITE10 */ struct scsi_task * scsi_cdb_write10(uint32_t lba, uint32_t xferlen, int fua, int fua_nv, int blocksize) { struct scsi_task *task; task = malloc(sizeof(struct scsi_task)); if (task == NULL) { return NULL; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_WRITE10; if (fua) { task->cdb[1] |= 0x08; } if (fua_nv) { task->cdb[1] |= 0x02; } *(uint32_t *)&task->cdb[2] = htonl(lba); *(uint16_t *)&task->cdb[7] = htons(xferlen/blocksize); task->cdb_size = 10; if (xferlen != 0) { task->xfer_dir = SCSI_XFER_WRITE; } else { task->xfer_dir = SCSI_XFER_NONE; } task->expxferlen = xferlen; task->params.write10.lba = lba; task->params.write10.num_blocks = xferlen/blocksize; return task; } /* * WRITE12 */ struct scsi_task * scsi_cdb_write12(uint32_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number) { struct scsi_task *task; task = malloc(sizeof(struct scsi_task)); if (task == NULL) { return NULL; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_WRITE12; task->cdb[1] |= ((wrprotect & 0x07) << 5); if (dpo) { task->cdb[1] |= 0x10; } if (fua) { task->cdb[1] |= 0x08; } if (fua_nv) { task->cdb[1] |= 0x02; } *(uint32_t *)&task->cdb[2] = htonl(lba); *(uint32_t *)&task->cdb[6] = htonl(xferlen/blocksize); task->cdb[10] |= (group_number & 0x1f); task->cdb_size = 12; if (xferlen != 0) { task->xfer_dir = SCSI_XFER_WRITE; } else { task->xfer_dir = SCSI_XFER_NONE; } task->expxferlen = xferlen; task->params.write12.lba = lba; task->params.write12.num_blocks = xferlen/blocksize; return task; } /* * WRITE16 */ struct scsi_task * scsi_cdb_write16(uint64_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number) { struct scsi_task *task; task = malloc(sizeof(struct scsi_task)); if (task == NULL) { return NULL; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_WRITE16; task->cdb[1] |= ((wrprotect & 0x07) << 5); if (dpo) { task->cdb[1] |= 0x10; } if (fua) { task->cdb[1] |= 0x08; } if (fua_nv) { task->cdb[1] |= 0x02; } *(uint32_t *)&task->cdb[2] = htonl(lba >> 32); *(uint32_t *)&task->cdb[6] = htonl(lba & 0xffffffff); *(uint32_t *)&task->cdb[10] = htonl(xferlen/blocksize); task->cdb[14] |= (group_number & 0x1f); task->cdb_size = 16; if (xferlen != 0) { task->xfer_dir = SCSI_XFER_WRITE; } else { task->xfer_dir = SCSI_XFER_NONE; } task->expxferlen = xferlen; task->params.write16.lba = lba; task->params.write16.num_blocks = xferlen/blocksize; return task; } /* * VERIFY10 */ struct scsi_task * scsi_cdb_verify10(uint32_t lba, uint32_t xferlen, int vprotect, int dpo, int bytchk, int blocksize) { struct scsi_task *task; task = malloc(sizeof(struct scsi_task)); if (task == NULL) { return NULL; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_VERIFY10; if (vprotect) { task->cdb[1] |= ((vprotect << 5) & 0xe0); } if (dpo) { task->cdb[1] |= 0x10; } if (bytchk) { task->cdb[1] |= 0x02; } *(uint32_t *)&task->cdb[2] = htonl(lba); *(uint16_t *)&task->cdb[7] = htons(xferlen/blocksize); task->cdb_size = 10; if (xferlen != 0) { task->xfer_dir = SCSI_XFER_WRITE; } else { task->xfer_dir = SCSI_XFER_NONE; } task->expxferlen = xferlen; task->params.verify10.lba = lba; task->params.verify10.num_blocks = xferlen/blocksize; task->params.verify10.vprotect = vprotect; task->params.verify10.dpo = dpo; task->params.verify10.bytchk = bytchk; return task; } /* * UNMAP */ struct scsi_task * scsi_cdb_unmap(int anchor, int group, uint16_t xferlen) { struct scsi_task *task; task = malloc(sizeof(struct scsi_task)); if (task == NULL) { return NULL; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_UNMAP; if (anchor) { task->cdb[1] |= 0x01; } task->cdb[6] |= group & 0x1f; *(uint16_t *)&task->cdb[7] = htons(xferlen); task->cdb_size = 10; task->xfer_dir = SCSI_XFER_WRITE; task->expxferlen = xferlen; return task; } /* * WRITE_SAME10 */ struct scsi_task * scsi_cdb_writesame10(int wrprotect, int anchor, int unmap, int pbdata, int lbdata, uint32_t lba, int group, uint16_t num_blocks) { struct scsi_task *task; task = malloc(sizeof(struct scsi_task)); if (task == NULL) { return NULL; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_WRITE_SAME10; if (wrprotect) { task->cdb[1] |= ((wrprotect & 0x7) << 5); } if (anchor) { task->cdb[1] |= 0x10; } if (unmap) { task->cdb[1] |= 0x08; } if (pbdata) { task->cdb[1] |= 0x04; } if (lbdata) { task->cdb[1] |= 0x02; } *(uint32_t *)&task->cdb[2] = htonl(lba); if (group) { task->cdb[6] |= (group & 0x1f); } *(uint16_t *)&task->cdb[7] = htons(num_blocks); task->cdb_size = 10; task->xfer_dir = SCSI_XFER_WRITE; task->expxferlen = 512; return task; } /* * WRITE_SAME16 */ struct scsi_task * scsi_cdb_writesame16(int wrprotect, int anchor, int unmap, int pbdata, int lbdata, uint64_t lba, int group, uint32_t num_blocks) { struct scsi_task *task; task = malloc(sizeof(struct scsi_task)); if (task == NULL) { return NULL; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_WRITE_SAME16; if (wrprotect) { task->cdb[1] |= ((wrprotect & 0x7) << 5); } if (anchor) { task->cdb[1] |= 0x10; } if (unmap) { task->cdb[1] |= 0x08; } if (pbdata) { task->cdb[1] |= 0x04; } if (lbdata) { task->cdb[1] |= 0x02; } *(uint32_t *)&task->cdb[2] = htonl(lba >> 32); *(uint32_t *)&task->cdb[6] = htonl(lba & 0xffffffff); *(uint32_t *)&task->cdb[10] = htonl(num_blocks); if (group) { task->cdb[14] |= (group & 0x1f); } task->cdb_size = 16; task->xfer_dir = SCSI_XFER_WRITE; task->expxferlen = 512; return task; } /* * MODESENSE6 */ struct scsi_task * scsi_cdb_modesense6(int dbd, enum scsi_modesense_page_control pc, enum scsi_modesense_page_code page_code, int sub_page_code, unsigned char alloc_len) { struct scsi_task *task; task = malloc(sizeof(struct scsi_task)); if (task == NULL) { return NULL; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_MODESENSE6; if (dbd) { task->cdb[1] |= 0x08; } task->cdb[2] = pc<<6 | page_code; task->cdb[3] = sub_page_code; task->cdb[4] = alloc_len; task->cdb_size = 6; task->xfer_dir = SCSI_XFER_READ; task->expxferlen = alloc_len; task->params.modesense6.dbd = dbd; task->params.modesense6.pc = pc; task->params.modesense6.page_code = page_code; task->params.modesense6.sub_page_code = sub_page_code; return task; } /* * parse the data in blob and calcualte the size of a full * modesense6 datain structure */ static int scsi_modesense6_datain_getfullsize(struct scsi_task *task) { int len; len = task->datain.data[0] + 1; return len; } static void scsi_parse_mode_caching(struct scsi_task *task, int pos, struct scsi_mode_page *mp) { mp->caching.ic = task->datain.data[pos] & 0x80; mp->caching.abpf = task->datain.data[pos] & 0x40; mp->caching.cap = task->datain.data[pos] & 0x20; mp->caching.disc = task->datain.data[pos] & 0x10; mp->caching.size = task->datain.data[pos] & 0x08; mp->caching.wce = task->datain.data[pos] & 0x04; mp->caching.mf = task->datain.data[pos] & 0x02; mp->caching.rcd = task->datain.data[pos] & 0x01; mp->caching.demand_read_retention_priority = (task->datain.data[pos+1] >> 4) & 0x0f; mp->caching.write_retention_priority = task->datain.data[pos+1] & 0x0f; mp->caching.disable_prefetch_transfer_length = htons(*(uint16_t *)&(task->datain.data[pos+2])); mp->caching.minimum_prefetch = htons(*(uint16_t *)&(task->datain.data[pos+4])); mp->caching.maximum_prefetch = htons(*(uint16_t *)&(task->datain.data[pos+6])); mp->caching.maximum_prefetch_ceiling = htons(*(uint16_t *)&(task->datain.data[pos+8])); mp->caching.fsw = task->datain.data[pos+10] & 0x80; mp->caching.lbcss = task->datain.data[pos+10] & 0x40; mp->caching.dra = task->datain.data[pos+10] & 0x20; mp->caching.nv_dis = task->datain.data[pos+10] & 0x01; mp->caching.number_of_cache_segments = task->datain.data[pos+11]; mp->caching.cache_segment_size = htons(*(uint16_t *)&(task->datain.data[pos+12])); } static void scsi_parse_mode_disconnect_reconnect(struct scsi_task *task, int pos, struct scsi_mode_page *mp) { mp->disconnect_reconnect.buffer_full_ratio = task->datain.data[pos]; mp->disconnect_reconnect.buffer_empty_ratio = task->datain.data[pos+1]; mp->disconnect_reconnect.bus_inactivity_limit = htons(*(uint16_t *)&(task->datain.data[pos+2])); mp->disconnect_reconnect.disconnect_time_limit = htons(*(uint16_t *)&(task->datain.data[pos+4])); mp->disconnect_reconnect.connect_time_limit = htons(*(uint16_t *)&(task->datain.data[pos+6])); mp->disconnect_reconnect.maximum_burst_size = htons(*(uint16_t *)&(task->datain.data[pos+8])); mp->disconnect_reconnect.emdp = task->datain.data[pos+10] & 0x80; mp->disconnect_reconnect.fair_arbitration = (task->datain.data[pos+10]>>4) & 0x0f; mp->disconnect_reconnect.dimm = task->datain.data[pos+10] & 0x08; mp->disconnect_reconnect.dtdc = task->datain.data[pos+10] & 0x07; mp->disconnect_reconnect.first_burst_size = htons(*(uint16_t *)&(task->datain.data[pos+12])); } static void scsi_parse_mode_informational_exceptions_control(struct scsi_task *task, int pos, struct scsi_mode_page *mp) { mp->iec.perf = task->datain.data[pos] & 0x80; mp->iec.ebf = task->datain.data[pos] & 0x20; mp->iec.ewasc = task->datain.data[pos] & 0x10; mp->iec.dexcpt = task->datain.data[pos] & 0x08; mp->iec.test = task->datain.data[pos] & 0x04; mp->iec.ebackerr = task->datain.data[pos] & 0x02; mp->iec.logerr = task->datain.data[pos] & 0x01; mp->iec.mrie = task->datain.data[pos+1] & 0x0f; mp->iec.interval_timer = htonl(*(uint32_t *)&(task->datain.data[pos+2])); mp->iec.report_count = htonl(*(uint32_t *)&(task->datain.data[pos+6])); } /* * parse and unmarshall the mode sense data in buffer */ static struct scsi_mode_sense * scsi_modesense_datain_unmarshall(struct scsi_task *task) { struct scsi_mode_sense *ms; int pos; if (task->datain.size < 4) { return NULL; } ms = scsi_malloc(task, sizeof(struct scsi_mode_sense)); if (ms == NULL) { return NULL; } ms->mode_data_length = task->datain.data[0]; ms->medium_type = task->datain.data[1]; ms->device_specific_parameter = task->datain.data[2]; ms->block_descriptor_length = task->datain.data[3]; ms->pages = NULL; if (ms->mode_data_length + 1 > task->datain.size) { return NULL; } pos = 4 + ms->block_descriptor_length; while (pos < task->datain.size) { struct scsi_mode_page *mp; mp = scsi_malloc(task, sizeof(struct scsi_mode_page)); if (mp == NULL) { return ms; } mp->ps = task->datain.data[pos] & 0x80; mp->spf = task->datain.data[pos] & 0x40; mp->page_code = task->datain.data[pos] & 0x3f; pos++; if (mp->spf) { mp->subpage_code = task->datain.data[pos++]; mp->len = ntohs(*(uint16_t *)&task->datain.data[pos]); pos += 2; } else { mp->subpage_code = 0; mp->len = task->datain.data[pos++]; } switch (mp->page_code) { case SCSI_MODESENSE_PAGECODE_CACHING: scsi_parse_mode_caching(task, pos, mp); break; case SCSI_MODESENSE_PAGECODE_DISCONNECT_RECONNECT: scsi_parse_mode_disconnect_reconnect(task, pos, mp); break; case SCSI_MODESENSE_PAGECODE_INFORMATIONAL_EXCEPTIONS_CONTROL: scsi_parse_mode_informational_exceptions_control(task, pos, mp); break; default: /* TODO: process other pages, or add raw data to struct * scsi_mode_page. */ break; } mp->next = ms->pages; ms->pages = mp; pos += mp->len; } return ms; } /* * SYNCHRONIZECACHE10 */ struct scsi_task * scsi_cdb_synchronizecache10(int lba, int num_blocks, int syncnv, int immed) { struct scsi_task *task; task = malloc(sizeof(struct scsi_task)); if (task == NULL) { return NULL; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_SYNCHRONIZECACHE10; if (syncnv) { task->cdb[1] |= 0x04; } if (immed) { task->cdb[1] |= 0x02; } *(uint32_t *)&task->cdb[2] = htonl(lba); *(uint16_t *)&task->cdb[7] = htons(num_blocks); task->cdb_size = 10; task->xfer_dir = SCSI_XFER_NONE; task->expxferlen = 0; return task; } /* * PREFETCH10 */ struct scsi_task * scsi_cdb_prefetch10(uint32_t lba, int num_blocks, int immed, int group) { struct scsi_task *task; task = malloc(sizeof(struct scsi_task)); if (task == NULL) { return NULL; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_PREFETCH10; if (immed) { task->cdb[1] |= 0x02; } *(uint32_t *)&task->cdb[2] = htonl(lba); task->cdb[6] |= group & 0x1f; *(uint16_t *)&task->cdb[7] = htons(num_blocks); task->cdb_size = 10; task->xfer_dir = SCSI_XFER_NONE; task->expxferlen = 0; return task; } /* * PREFETCH16 */ struct scsi_task * scsi_cdb_prefetch16(uint64_t lba, int num_blocks, int immed, int group) { struct scsi_task *task; task = malloc(sizeof(struct scsi_task)); if (task == NULL) { return NULL; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_PREFETCH16; if (immed) { task->cdb[1] |= 0x02; } *(uint32_t *)&task->cdb[2] = htonl(lba >> 32); *(uint32_t *)&task->cdb[6] = htonl(lba & 0xffffffff); *(uint32_t *)&task->cdb[10] = htonl(num_blocks); task->cdb[14] |= group & 0x1f; task->cdb_size = 16; task->xfer_dir = SCSI_XFER_NONE; task->expxferlen = 0; return task; } /* * SERVICEACTIONIN16 */ struct scsi_task * scsi_cdb_serviceactionin16(enum scsi_service_action_in sa, uint32_t xferlen) { struct scsi_task *task; task = malloc(sizeof(struct scsi_task)); if (task == NULL) { return NULL; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_SERVICE_ACTION_IN; task->cdb[1] = sa; *(uint32_t *)&task->cdb[10] = htonl(xferlen); task->cdb_size = 16; task->xfer_dir = SCSI_XFER_READ; task->expxferlen = xferlen; task->params.serviceactionin.sa = sa; return task; } /* * READCAPACITY16 */ struct scsi_task * scsi_cdb_readcapacity16(void) { return scsi_cdb_serviceactionin16(SCSI_READCAPACITY16, 32); } int scsi_datain_getfullsize(struct scsi_task *task) { switch (task->cdb[0]) { case SCSI_OPCODE_TESTUNITREADY: return 0; case SCSI_OPCODE_INQUIRY: return scsi_inquiry_datain_getfullsize(task); case SCSI_OPCODE_MODESENSE6: return scsi_modesense6_datain_getfullsize(task); case SCSI_OPCODE_READCAPACITY10: return scsi_readcapacity10_datain_getfullsize(task); case SCSI_OPCODE_SYNCHRONIZECACHE10: return 0; case SCSI_OPCODE_REPORTLUNS: return scsi_reportluns_datain_getfullsize(task); } return -1; } void * scsi_datain_unmarshall(struct scsi_task *task) { switch (task->cdb[0]) { case SCSI_OPCODE_TESTUNITREADY: return NULL; case SCSI_OPCODE_INQUIRY: return scsi_inquiry_datain_unmarshall(task); case SCSI_OPCODE_MODESENSE6: return scsi_modesense_datain_unmarshall(task); case SCSI_OPCODE_READCAPACITY10: return scsi_readcapacity10_datain_unmarshall(task); case SCSI_OPCODE_SYNCHRONIZECACHE10: return NULL; case SCSI_OPCODE_REPORTLUNS: return scsi_reportluns_datain_unmarshall(task); case SCSI_OPCODE_SERVICE_ACTION_IN: return scsi_serviceactionin_datain_unmarshall(task); } return NULL; } const char * scsi_devtype_to_str(enum scsi_inquiry_peripheral_device_type type) { switch (type) { case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS: return "DIRECT_ACCESS"; case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_SEQUENTIAL_ACCESS: return "SEQUENTIAL_ACCESS"; case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_PRINTER: return "PRINTER"; case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_PROCESSOR: return "PROCESSOR"; case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_WRITE_ONCE: return "WRITE_ONCE"; case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_MMC: return "MMC"; case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_SCANNER: return "SCANNER"; case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_OPTICAL_MEMORY: return "OPTICAL_MEMORY"; case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_MEDIA_CHANGER: return "MEDIA_CHANGER"; case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_COMMUNICATIONS: return "COMMUNICATIONS"; case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_STORAGE_ARRAY_CONTROLLER: return "STORAGE_ARRAY_CONTROLLER"; case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_ENCLOSURE_SERVICES: return "ENCLOSURE_SERVICES"; case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_SIMPLIFIED_DIRECT_ACCESS: return "SIMPLIFIED_DIRECT_ACCESS"; case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_OPTICAL_CARD_READER: return "OPTICAL_CARD_READER"; case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_BRIDGE_CONTROLLER: return "BRIDGE_CONTROLLER"; case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_OSD: return "OSD"; case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_AUTOMATION: return "AUTOMATION"; case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_SEQURITY_MANAGER: return "SEQURITY_MANAGER"; case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_WELL_KNOWN_LUN: return "WELL_KNOWN_LUN"; case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_UNKNOWN: return "UNKNOWN"; } return "unknown"; } const char * scsi_devqualifier_to_str(enum scsi_inquiry_peripheral_qualifier qualifier) { switch (qualifier) { case SCSI_INQUIRY_PERIPHERAL_QUALIFIER_CONNECTED: return "CONNECTED"; case SCSI_INQUIRY_PERIPHERAL_QUALIFIER_DISCONNECTED: return "DISCONNECTED"; case SCSI_INQUIRY_PERIPHERAL_QUALIFIER_NOT_SUPPORTED: return "NOT_SUPPORTED"; } return "unknown"; } const char * scsi_version_to_str(enum scsi_version version) { switch (version) { case SCSI_VERSION_SPC: return "ANSI INCITS 301-1997 (SPC)"; case SCSI_VERSION_SPC2: return "ANSI INCITS 351-2001 (SPC-2)"; case SCSI_VERSION_SPC3: return "ANSI INCITS 408-2005 (SPC-3)"; } return "unknown"; } const char * scsi_inquiry_pagecode_to_str(int pagecode) { switch (pagecode) { case SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES: return "SUPPORTED_VPD_PAGES"; case SCSI_INQUIRY_PAGECODE_UNIT_SERIAL_NUMBER: return "UNIT_SERIAL_NUMBER"; case SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION: return "DEVICE_IDENTIFICATION"; case SCSI_INQUIRY_PAGECODE_BLOCK_DEVICE_CHARACTERISTICS: return "BLOCK_DEVICE_CHARACTERISTICS"; } return "unknown"; } const char * scsi_protocol_identifier_to_str(int identifier) { switch (identifier) { case SCSI_PROTOCOL_IDENTIFIER_FIBRE_CHANNEL: return "FIBRE_CHANNEL"; case SCSI_PROTOCOL_IDENTIFIER_PARALLEL_SCSI: return "PARALLEL_SCSI"; case SCSI_PROTOCOL_IDENTIFIER_SSA: return "SSA"; case SCSI_PROTOCOL_IDENTIFIER_IEEE_1394: return "IEEE_1394"; case SCSI_PROTOCOL_IDENTIFIER_RDMA: return "RDMA"; case SCSI_PROTOCOL_IDENTIFIER_ISCSI: return "ISCSI"; case SCSI_PROTOCOL_IDENTIFIER_SAS: return "SAS"; case SCSI_PROTOCOL_IDENTIFIER_ADT: return "ADT"; case SCSI_PROTOCOL_IDENTIFIER_ATA: return "ATA"; } return "unknown"; } const char * scsi_codeset_to_str(int codeset) { switch (codeset) { case SCSI_CODESET_BINARY: return "BINARY"; case SCSI_CODESET_ASCII: return "ASCII"; case SCSI_CODESET_UTF8: return "UTF8"; } return "unknown"; } const char * scsi_association_to_str(int association) { switch (association) { case SCSI_ASSOCIATION_LOGICAL_UNIT: return "LOGICAL_UNIT"; case SCSI_ASSOCIATION_TARGET_PORT: return "TARGET_PORT"; case SCSI_ASSOCIATION_TARGET_DEVICE: return "TARGET_DEVICE"; } return "unknown"; } const char * scsi_designator_type_to_str(int type) { switch (type) { case SCSI_DESIGNATOR_TYPE_VENDOR_SPECIFIC: return "VENDOR_SPECIFIC"; case SCSI_DESIGNATOR_TYPE_T10_VENDORT_ID: return "T10_VENDORT_ID"; case SCSI_DESIGNATOR_TYPE_EUI_64: return "EUI_64"; case SCSI_DESIGNATOR_TYPE_NAA: return "NAA"; case SCSI_DESIGNATOR_TYPE_RELATIVE_TARGET_PORT: return "RELATIVE_TARGET_PORT"; case SCSI_DESIGNATOR_TYPE_TARGET_PORT_GROUP: return "TARGET_PORT_GROUP"; case SCSI_DESIGNATOR_TYPE_LOGICAL_UNIT_GROUP: return "LOGICAL_UNIT_GROUP"; case SCSI_DESIGNATOR_TYPE_MD5_LOGICAL_UNIT_IDENTIFIER: return "MD5_LOGICAL_UNIT_IDENTIFIER"; case SCSI_DESIGNATOR_TYPE_SCSI_NAME_STRING: return "SCSI_NAME_STRING"; } return "unknown"; } void scsi_set_task_private_ptr(struct scsi_task *task, void *ptr) { task->ptr = ptr; } void * scsi_get_task_private_ptr(struct scsi_task *task) { return task->ptr; } struct scsi_data_buffer { struct scsi_data_buffer *next; uint32_t len; unsigned char *data; }; int scsi_task_add_data_in_buffer(struct scsi_task *task, int len, unsigned char *buf) { struct scsi_data_buffer *data_buf; if (len < 0) { return -1; } data_buf = scsi_malloc(task, sizeof(struct scsi_data_buffer)); if (data_buf == NULL) { return -1; } data_buf->len = len; data_buf->data = buf; SLIST_ADD_END(&task->in_buffers, data_buf); return 0; } unsigned char * scsi_task_get_data_in_buffer(struct scsi_task *task, uint32_t pos, ssize_t *count) { struct scsi_data_buffer *sdb; sdb = task->in_buffers; if (sdb == NULL) { return NULL; } while (pos >= sdb->len) { pos -= sdb->len; sdb = sdb->next; if (sdb == NULL) { /* someone issued a read but did not provide enough user buffers for all the data. * maybe someone tried to read just 512 bytes off a MMC device? */ return NULL; } } if (count && *count > (ssize_t)(sdb->len - pos)) { *count = sdb->len - pos; } return &sdb->data[pos]; } int iscsi_scsi_task_cancel(struct iscsi_context *iscsi, struct scsi_task *task) { struct iscsi_pdu *pdu; for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) { if (pdu->itt == task->itt) { while(task->in_buffers != NULL) { struct scsi_data_buffer *ptr = task->in_buffers; SLIST_REMOVE(&task->in_buffers, ptr); } SLIST_REMOVE(&iscsi->waitpdu, pdu); if ( !(pdu->flags & ISCSI_PDU_NO_CALLBACK)) { pdu->callback(iscsi, SCSI_STATUS_CANCELLED, NULL, pdu->private_data); } iscsi_free_pdu(iscsi, pdu); return 0; } } for (pdu = iscsi->outqueue; pdu; pdu = pdu->next) { if (pdu->itt == task->itt) { while(task->in_buffers != NULL) { struct scsi_data_buffer *ptr = task->in_buffers; SLIST_REMOVE(&task->in_buffers, ptr); } SLIST_REMOVE(&iscsi->outqueue, pdu); if ( !(pdu->flags & ISCSI_PDU_NO_CALLBACK)) { pdu->callback(iscsi, SCSI_STATUS_CANCELLED, NULL, pdu->private_data); } iscsi_free_pdu(iscsi, pdu); return 0; } } return -1; } void iscsi_scsi_cancel_all_tasks(struct iscsi_context *iscsi) { struct iscsi_pdu *pdu; for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) { struct scsi_task *task = iscsi_scsi_get_task_from_pdu(pdu); while(task->in_buffers != NULL) { struct scsi_data_buffer *ptr = task->in_buffers; SLIST_REMOVE(&task->in_buffers, ptr); } SLIST_REMOVE(&iscsi->waitpdu, pdu); if ( !(pdu->flags & ISCSI_PDU_NO_CALLBACK)) { pdu->callback(iscsi, SCSI_STATUS_CANCELLED, NULL, pdu->private_data); } iscsi_free_pdu(iscsi, pdu); } for (pdu = iscsi->outqueue; pdu; pdu = pdu->next) { struct scsi_task *task = iscsi_scsi_get_task_from_pdu(pdu); while(task->in_buffers != NULL) { struct scsi_data_buffer *ptr = task->in_buffers; SLIST_REMOVE(&task->in_buffers, ptr); } SLIST_REMOVE(&iscsi->outqueue, pdu); if ( !(pdu->flags & ISCSI_PDU_NO_CALLBACK)) { pdu->callback(iscsi, SCSI_STATUS_CANCELLED, NULL, pdu->private_data); } iscsi_free_pdu(iscsi, pdu); } } libiscsi-1.4.0/lib/libiscsi.def0000644000175000017500000000435211750443164014523 0ustar mjtmjtLIBRARY libiscsi EXPORTS iscsi_get_fd iscsi_which_events iscsi_service iscsi_queue_length iscsi_parse_full_url iscsi_destroy_url iscsi_parse_portal_url iscsi_get_error iscsi_create_context iscsi_destroy_context iscsi_set_alias iscsi_set_targetname iscsi_get_target_address iscsi_set_session_type iscsi_set_header_digest iscsi_set_initiator_username_pwd iscsi_is_logged_in iscsi_connect_async iscsi_connect_sync iscsi_full_connect_async iscsi_full_connect_sync iscsi_disconnect iscsi_login_async iscsi_login_sync iscsi_logout_async iscsi_logout_sync iscsi_discovery_async iscsi_nop_out_async iscsi_task_mgmt_async iscsi_task_mgmt_abort_task_async iscsi_task_mgmt_abort_task_set_async iscsi_task_mgmt_lun_reset_async iscsi_task_mgmt_target_warm_reset_async iscsi_task_mgmt_target_cold_reset_async iscsi_set_isid_oui iscsi_set_isid_en iscsi_set_isid_random iscsi_set_isid_reserved iscsi_scsi_command_async iscsi_reportluns_task iscsi_testunitready_task iscsi_inquiry_task iscsi_readcapacity10_task iscsi_readcapacity16_task iscsi_synchronizecache10_task iscsi_read6_task iscsi_read10_task iscsi_read12_task iscsi_verify10_task iscsi_write10_task iscsi_write12_task iscsi_writesame10_task iscsi_writesame16_task iscsi_modesense6_task iscsi_scsi_command_sync iscsi_reportluns_sync iscsi_testunitready_sync iscsi_inquiry_sync iscsi_readcapacity10_sync iscsi_readcapacity16_sync iscsi_synchronizecache10_sync iscsi_read6_sync iscsi_read10_sync iscsi_read12_sync iscsi_verify10_sync iscsi_write10_sync iscsi_write12_sync iscsi_writesame10_sync iscsi_writesame16_sync iscsi_scsi_task_cancel iscsi_scsi_cancel_all_tasks poll scsi_task_add_data_in_buffer scsi_sense_key_str scsi_sense_ascq_str scsi_free_scsi_task scsi_set_task_private_ptr scsi_get_task_private_ptr scsi_cdb_testunitready scsi_reportluns_cdb scsi_cdb_readcapacity10 scsi_devtype_to_str scsi_version_to_str scsi_inquiry_pagecode_to_str scsi_cdb_inquiry scsi_protocol_identifier_to_str scsi_codeset_to_str scsi_association_to_str scsi_designator_type_to_str scsi_cdb_modesense6 scsi_datain_getfullsize scsi_datain_unmarshall scsi_cdb_read6 scsi_cdb_read10 scsi_cdb_verify10 scsi_cdb_write10 scsi_cdb_writesame10 scsi_cdb_writesame16 scsi_cdb_synchronizecache10 scsi_cdb_readcapacity16 scsi_cdb_serviceactionin16 scsi_cdb_unmap libiscsi-1.4.0/lib/nop.c0000644000175000017500000000637711750443164013213 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program 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 program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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, see . */ #if defined(WIN32) #else #include #endif #include #include "iscsi.h" #include "iscsi-private.h" int iscsi_nop_out_async(struct iscsi_context *iscsi, iscsi_command_cb cb, unsigned char *data, int len, void *private_data) { struct iscsi_pdu *pdu; if (iscsi->is_loggedin == 0) { iscsi_set_error(iscsi, "trying to send nop-out while not " "logged in"); return -1; } pdu = iscsi_allocate_pdu(iscsi, ISCSI_PDU_NOP_OUT, ISCSI_PDU_NOP_IN); if (pdu == NULL) { iscsi_set_error(iscsi, "Failed to allocate nop-out pdu"); return -1; } /* immediate flag */ iscsi_pdu_set_immediate(pdu); /* flags */ iscsi_pdu_set_pduflags(pdu, 0x80); /* ttt */ iscsi_pdu_set_ttt(pdu, 0xffffffff); /* lun */ iscsi_pdu_set_lun(pdu, 0); /* cmdsn is not increased if Immediate delivery*/ iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn); pdu->cmdsn = iscsi->cmdsn; /* exp statsn */ iscsi_pdu_set_expstatsn(pdu, iscsi->statsn+1); pdu->callback = cb; pdu->private_data = private_data; if (iscsi_pdu_add_data(iscsi, pdu, data, len) != 0) { iscsi_set_error(iscsi, "Failed to add outdata to nop-out"); iscsi_free_pdu(iscsi, pdu); return -1; } if (iscsi_queue_pdu(iscsi, pdu) != 0) { iscsi_set_error(iscsi, "failed to queue iscsi nop-out pdu"); iscsi_free_pdu(iscsi, pdu); return -1; } return 0; } int iscsi_send_target_nop_out(struct iscsi_context *iscsi, uint32_t ttt) { struct iscsi_pdu *pdu; pdu = iscsi_allocate_pdu_with_itt_flags(iscsi, ISCSI_PDU_NOP_OUT, ISCSI_PDU_NO_PDU, 0xffffffff,ISCSI_PDU_DELETE_WHEN_SENT|ISCSI_PDU_NO_CALLBACK); if (pdu == NULL) { iscsi_set_error(iscsi, "Failed to allocate nop-out pdu"); return -1; } /* immediate flag */ iscsi_pdu_set_immediate(pdu); /* flags */ iscsi_pdu_set_pduflags(pdu, 0x80); /* ttt */ iscsi_pdu_set_ttt(pdu, ttt); /* lun */ iscsi_pdu_set_lun(pdu, 0); /* cmdsn is not increased if Immediate delivery*/ iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn); pdu->cmdsn = iscsi->cmdsn; /* exp statsn */ iscsi_pdu_set_expstatsn(pdu, iscsi->statsn+1); if (iscsi_queue_pdu(iscsi, pdu) != 0) { iscsi_set_error(iscsi, "failed to queue iscsi nop-out pdu"); iscsi_free_pdu(iscsi, pdu); return -1; } return 0; } int iscsi_process_nop_out_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, struct iscsi_in_pdu *in) { struct iscsi_data data; data.data = NULL; data.size = 0; if (in->data_pos > ISCSI_HEADER_SIZE) { data.data = in->data; data.size = in->data_pos; } pdu->callback(iscsi, SCSI_STATUS_GOOD, &data, pdu->private_data); return 0; } libiscsi-1.4.0/lib/init.c0000644000175000017500000003050711750443164013352 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program 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 program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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, see . */ #define _GNU_SOURCE #if defined(WIN32) #else #include #include #endif #include #include #include #include #include #include #include #include "iscsi.h" #include "iscsi-private.h" #include "slist.h" struct iscsi_context * iscsi_create_context(const char *initiator_name) { struct iscsi_context *iscsi; iscsi = malloc(sizeof(struct iscsi_context)); if (iscsi == NULL) { return NULL; } memset(iscsi, 0, sizeof(struct iscsi_context)); iscsi->initiator_name = strdup(initiator_name); if (iscsi->initiator_name == NULL) { free(iscsi); return NULL; } iscsi->fd = -1; /* initialize to a "random" isid */ iscsi_set_isid_random(iscsi, rand(), 0); /* assume we start in security negotiation phase */ iscsi->current_phase = ISCSI_PDU_LOGIN_CSG_SECNEG; iscsi->next_phase = ISCSI_PDU_LOGIN_NSG_OPNEG; iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP; iscsi->max_burst_length = 262144; iscsi->first_burst_length = 262144; iscsi->initiator_max_recv_data_segment_length = 262144; iscsi->target_max_recv_data_segment_length = 8192; iscsi->want_initial_r2t = ISCSI_INITIAL_R2T_NO; iscsi->use_initial_r2t = ISCSI_INITIAL_R2T_NO; iscsi->want_immediate_data = ISCSI_IMMEDIATE_DATA_YES; iscsi->use_immediate_data = ISCSI_IMMEDIATE_DATA_YES; iscsi->want_header_digest = ISCSI_HEADER_DIGEST_NONE_CRC32C; return iscsi; } int iscsi_set_isid_oui(struct iscsi_context *iscsi, uint32_t oui, uint32_t qualifier) { iscsi->isid[0] = (oui >> 16) & 0x3f; iscsi->isid[1] = (oui >> 8) & 0xff; iscsi->isid[2] = (oui ) & 0xff; iscsi->isid[3] = (qualifier >> 16) & 0xff; iscsi->isid[4] = (qualifier >> 8) & 0xff; iscsi->isid[5] = (qualifier ) & 0xff; return 0; } int iscsi_set_isid_en(struct iscsi_context *iscsi, uint32_t en, uint32_t qualifier) { iscsi->isid[0] = 0x40; iscsi->isid[1] = (en >> 16) & 0xff; iscsi->isid[2] = (en >> 8) & 0xff; iscsi->isid[3] = (en ) & 0xff; iscsi->isid[4] = (qualifier >> 8) & 0xff; iscsi->isid[5] = (qualifier ) & 0xff; return 0; } int iscsi_set_isid_random(struct iscsi_context *iscsi, uint32_t rnd, uint32_t qualifier) { iscsi->isid[0] = 0x80; iscsi->isid[1] = (rnd >> 16) & 0xff; iscsi->isid[2] = (rnd >> 8) & 0xff; iscsi->isid[3] = (rnd ) & 0xff; iscsi->isid[4] = (qualifier >> 8) & 0xff; iscsi->isid[5] = (qualifier ) & 0xff; return 0; } int iscsi_set_isid_reserved(struct iscsi_context *iscsi) { iscsi->isid[0] = 0xc0; iscsi->isid[1] = 0x00; iscsi->isid[2] = 0x00; iscsi->isid[3] = 0x00; iscsi->isid[4] = 0x00; iscsi->isid[5] = 0x00; return 0; } int iscsi_set_alias(struct iscsi_context *iscsi, const char *alias) { if (iscsi->is_loggedin != 0) { iscsi_set_error(iscsi, "Already logged in when adding alias"); return -1; } free(discard_const(iscsi->alias)); iscsi->alias = strdup(alias); if (iscsi->alias == NULL) { iscsi_set_error(iscsi, "Failed to allocate alias name"); return -1; } return 0; } int iscsi_set_targetname(struct iscsi_context *iscsi, const char *target_name) { if (iscsi->is_loggedin != 0) { iscsi_set_error(iscsi, "Already logged in when adding " "targetname"); return -1; } free(discard_const(iscsi->target_name)); iscsi->target_name = strdup(target_name); if (iscsi->target_name == NULL) { iscsi_set_error(iscsi, "Failed to allocate target name"); return -1; } return 0; } int iscsi_destroy_context(struct iscsi_context *iscsi) { struct iscsi_pdu *pdu; if (iscsi == NULL) { return 0; } if (iscsi->fd != -1) { iscsi_disconnect(iscsi); } while ((pdu = iscsi->outqueue)) { SLIST_REMOVE(&iscsi->outqueue, pdu); if ( !(pdu->flags & ISCSI_PDU_NO_CALLBACK)) { /* If an error happened during connect/login, we dont want to call any of the callbacks. */ if (iscsi->is_loggedin) { pdu->callback(iscsi, SCSI_STATUS_CANCELLED, NULL, pdu->private_data); } } iscsi_free_pdu(iscsi, pdu); } while ((pdu = iscsi->waitpdu)) { SLIST_REMOVE(&iscsi->waitpdu, pdu); /* If an error happened during connect/login, we dont want to call any of the callbacks. */ if (iscsi->is_loggedin) { pdu->callback(iscsi, SCSI_STATUS_CANCELLED, NULL, pdu->private_data); } iscsi_free_pdu(iscsi, pdu); } free(discard_const(iscsi->initiator_name)); iscsi->initiator_name = NULL; free(discard_const(iscsi->target_name)); iscsi->target_name = NULL; free(discard_const(iscsi->target_address)); iscsi->target_address = NULL; free(discard_const(iscsi->alias)); iscsi->alias = NULL; free(discard_const(iscsi->portal)); iscsi->portal = NULL; if (iscsi->incoming != NULL) { iscsi_free_iscsi_in_pdu(iscsi->incoming); } if (iscsi->inqueue != NULL) { iscsi_free_iscsi_inqueue(iscsi->inqueue); } free(iscsi->error_string); iscsi->error_string = NULL; free(discard_const(iscsi->user)); iscsi->user = NULL; free(discard_const(iscsi->passwd)); iscsi->passwd = NULL; free(discard_const(iscsi->chap_c)); iscsi->chap_c = NULL; free(iscsi); return 0; } void iscsi_set_error(struct iscsi_context *iscsi, const char *error_string, ...) { va_list ap; char *str; va_start(ap, error_string); str = malloc(1024); if (vsnprintf(str, 1024, error_string, ap) < 0) { /* not much we can do here */ free(str); str = NULL; } free(iscsi->error_string); iscsi->error_string = str; va_end(ap); } const char * iscsi_get_error(struct iscsi_context *iscsi) { return iscsi->error_string; } const char * iscsi_get_target_address(struct iscsi_context *iscsi) { return iscsi->target_address; } int iscsi_set_header_digest(struct iscsi_context *iscsi, enum iscsi_header_digest header_digest) { if (iscsi->is_loggedin) { iscsi_set_error(iscsi, "trying to set header digest while " "logged in"); return -1; } if ((unsigned)header_digest > ISCSI_HEADER_DIGEST_LAST) { iscsi_set_error(iscsi, "invalid header digest value"); return -1; } iscsi->want_header_digest = header_digest; return 0; } int iscsi_is_logged_in(struct iscsi_context *iscsi) { return iscsi->is_loggedin; } struct iscsi_url * iscsi_parse_full_url(struct iscsi_context *iscsi, const char *url) { struct iscsi_url *iscsi_url; char *str; char *portal; char *user = NULL; char *passwd = NULL; char *target; char *lun; char *tmp; int l; if (strncmp(url, "iscsi://", 8)) { iscsi_set_error(iscsi, "Invalid URL %s\niSCSI URL must be of " "the form: %s", url, ISCSI_URL_SYNTAX); return NULL; } str = strdup(url + 8); if (str == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup url %s", url); return NULL; } portal = str; user = getenv("LIBISCSI_CHAP_USERNAME"); passwd = getenv("LIBISCSI_CHAP_PASSWORD"); tmp = strchr(portal, '@'); if (tmp != NULL) { user = portal; *tmp++ = 0; portal = tmp; tmp = strchr(user, '%'); if (tmp == NULL) { tmp = strchr(user, ':'); } if (tmp != NULL) { *tmp++ = 0; passwd = tmp; } } target = strchr(portal, '/'); if (target == NULL) { iscsi_set_error(iscsi, "Invalid URL %s\nCould not parse " "''\niSCSI URL must be of the " "form: %s", url, ISCSI_URL_SYNTAX); free(str); return NULL; } *target++ = 0; if (*target == 0) { iscsi_set_error(iscsi, "Invalid URL %s\nCould not parse " "\n" "iSCSI URL must be of the form: %s", url, ISCSI_URL_SYNTAX); free(str); return NULL; } lun = strchr(target, '/'); if (lun == NULL) { iscsi_set_error(iscsi, "Invalid URL %s\nCould not parse \n" "iSCSI URL must be of the form: %s", url, ISCSI_URL_SYNTAX); free(str); return NULL; } *lun++ = 0; l = strtol(lun, &tmp, 10); if (*lun == 0 || *tmp != 0) { iscsi_set_error(iscsi, "Invalid URL %s\nCould not parse \n" "iSCSI URL must be of the form: %s", url, ISCSI_URL_SYNTAX); free(str); return NULL; } iscsi_url = malloc(sizeof(struct iscsi_url)); if (iscsi_url == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to allocate iscsi_url structure"); free(str); return NULL; } memset(iscsi_url, 0, sizeof(struct iscsi_url)); iscsi_url->portal = strdup(portal); if (iscsi_url->portal == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup portal string"); iscsi_destroy_url(iscsi_url); free(str); return NULL; } iscsi_url->target = strdup(target); if (iscsi_url->target == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup target string"); iscsi_destroy_url(iscsi_url); free(str); return NULL; } if (user != NULL && passwd != NULL) { iscsi_url->user = strdup(user); if (iscsi_url->user == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup username string"); iscsi_destroy_url(iscsi_url); free(str); return NULL; } iscsi_url->passwd = strdup(passwd); if (iscsi_url->passwd == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup password string"); iscsi_destroy_url(iscsi_url); free(str); return NULL; } } iscsi_url->lun = l; free(str); return iscsi_url; } struct iscsi_url * iscsi_parse_portal_url(struct iscsi_context *iscsi, const char *url) { struct iscsi_url *iscsi_url; char *str; char *portal; char *user = NULL; char *passwd = NULL; char *tmp; if (strncmp(url, "iscsi://", 8)) { iscsi_set_error(iscsi, "Invalid URL %s\niSCSI Portal URL must be of " "the form: %s", url, ISCSI_PORTAL_URL_SYNTAX); return NULL; } str = strdup(url + 8); if (str == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup url %s", url); return NULL; } portal = str; user = getenv("LIBISCSI_CHAP_USERNAME"); passwd = getenv("LIBISCSI_CHAP_PASSWORD"); tmp = strchr(portal, '@'); if (tmp != NULL) { user = portal; *tmp++ = 0; portal = tmp; tmp = strchr(user, '%'); if (tmp != NULL) { *tmp++ = 0; passwd = tmp; } } iscsi_url = malloc(sizeof(struct iscsi_url)); if (iscsi_url == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to allocate iscsi_url structure"); free(str); return NULL; } memset(iscsi_url, 0, sizeof(struct iscsi_url)); iscsi_url->portal = strdup(portal); if (iscsi_url->portal == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup portal string"); iscsi_destroy_url(iscsi_url); free(str); return NULL; } if (user != NULL && passwd != NULL) { iscsi_url->user = strdup(user); if (iscsi_url->user == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup username string"); iscsi_destroy_url(iscsi_url); free(str); return NULL; } iscsi_url->passwd = strdup(passwd); if (iscsi_url->passwd == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup password string"); iscsi_destroy_url(iscsi_url); free(str); return NULL; } } free(str); return iscsi_url; } void iscsi_destroy_url(struct iscsi_url *iscsi_url) { if (iscsi_url == NULL) { return; } free(discard_const(iscsi_url->portal)); free(discard_const(iscsi_url->target)); free(discard_const(iscsi_url->user)); free(discard_const(iscsi_url->passwd)); free(iscsi_url); } int iscsi_set_initiator_username_pwd(struct iscsi_context *iscsi, const char *user, const char *passwd) { free(discard_const(iscsi->user)); iscsi->user = strdup(user); if (iscsi->user == NULL) { iscsi_set_error(iscsi, "Out-of-memory: failed to strdup username"); return -1; } free(discard_const(iscsi->passwd)); iscsi->passwd = strdup(passwd); if (iscsi->passwd == NULL) { iscsi_set_error(iscsi, "Out-of-memory: failed to strdup password"); return -1; } return 0; } libiscsi-1.4.0/lib/task_mgmt.c0000644000175000017500000000737411750443164014403 0ustar mjtmjt/* Copyright (C) 2011 by Ronnie Sahlberg This program 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 program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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, see . */ #if defined(WIN32) #else #include #endif #include #include "iscsi.h" #include "iscsi-private.h" #include "scsi-lowlevel.h" int iscsi_task_mgmt_async(struct iscsi_context *iscsi, int lun, enum iscsi_task_mgmt_funcs function, uint32_t ritt, uint32_t rcmdsn, iscsi_command_cb cb, void *private_data) { struct iscsi_pdu *pdu; if (iscsi->is_loggedin == 0) { iscsi_set_error(iscsi, "trying to send task-mgmt while not " "logged in"); return -1; } pdu = iscsi_allocate_pdu(iscsi, ISCSI_PDU_SCSI_TASK_MANAGEMENT_REQUEST, ISCSI_PDU_SCSI_TASK_MANAGEMENT_RESPONSE); if (pdu == NULL) { iscsi_set_error(iscsi, "Failed to allocate task mgmt pdu"); return -1; } /* immediate flag */ iscsi_pdu_set_immediate(pdu); /* flags */ iscsi_pdu_set_pduflags(pdu, 0x80 | function); /* lun */ iscsi_pdu_set_lun(pdu, lun); /* ritt */ iscsi_pdu_set_ritt(pdu, ritt); /* cmdsn is not increased if Immediate delivery*/ iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn); pdu->cmdsn = iscsi->cmdsn; /* rcmdsn */ iscsi_pdu_set_rcmdsn(pdu, rcmdsn); pdu->callback = cb; pdu->private_data = private_data; if (iscsi_queue_pdu(iscsi, pdu) != 0) { iscsi_set_error(iscsi, "failed to queue iscsi taskmgmt pdu"); iscsi_free_pdu(iscsi, pdu); return -1; } return 0; } int iscsi_process_task_mgmt_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, struct iscsi_in_pdu *in) { uint32_t response; response = in->hdr[2]; pdu->callback(iscsi, SCSI_STATUS_GOOD, &response, pdu->private_data); return 0; } int iscsi_task_mgmt_abort_task_async(struct iscsi_context *iscsi, struct scsi_task *task, iscsi_command_cb cb, void *private_data) { iscsi_scsi_task_cancel(iscsi, task); return iscsi_task_mgmt_async(iscsi, task->lun, ISCSI_TM_ABORT_TASK, task->itt, task->cmdsn, cb, private_data); } int iscsi_task_mgmt_abort_task_set_async(struct iscsi_context *iscsi, uint32_t lun, iscsi_command_cb cb, void *private_data) { iscsi_scsi_cancel_all_tasks(iscsi); return iscsi_task_mgmt_async(iscsi, lun, ISCSI_TM_ABORT_TASK_SET, 0xffffffff, 0, cb, private_data); } int iscsi_task_mgmt_lun_reset_async(struct iscsi_context *iscsi, uint32_t lun, iscsi_command_cb cb, void *private_data) { iscsi_scsi_cancel_all_tasks(iscsi); return iscsi_task_mgmt_async(iscsi, lun, ISCSI_TM_LUN_RESET, 0xffffffff, 0, cb, private_data); } int iscsi_task_mgmt_target_warm_reset_async(struct iscsi_context *iscsi, iscsi_command_cb cb, void *private_data) { iscsi_scsi_cancel_all_tasks(iscsi); return iscsi_task_mgmt_async(iscsi, 0, ISCSI_TM_TARGET_WARM_RESET, 0xffffffff, 0, cb, private_data); } int iscsi_task_mgmt_target_cold_reset_async(struct iscsi_context *iscsi, iscsi_command_cb cb, void *private_data) { iscsi_scsi_cancel_all_tasks(iscsi); return iscsi_task_mgmt_async(iscsi, 0, ISCSI_TM_TARGET_COLD_RESET, 0xffffffff, 0, cb, private_data); } libiscsi-1.4.0/lib/discovery.c0000644000175000017500000001173111750443164014414 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program 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 program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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, see . */ #if defined(WIN32) #else #include #endif #include #include #include #include "iscsi.h" #include "iscsi-private.h" int iscsi_discovery_async(struct iscsi_context *iscsi, iscsi_command_cb cb, void *private_data) { struct iscsi_pdu *pdu; char *str; if (iscsi->session_type != ISCSI_SESSION_DISCOVERY) { iscsi_set_error(iscsi, "Trying to do discovery on " "non-discovery session."); return -1; } pdu = iscsi_allocate_pdu(iscsi, ISCSI_PDU_TEXT_REQUEST, ISCSI_PDU_TEXT_RESPONSE); if (pdu == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to allocate " "text pdu."); return -1; } /* immediate */ iscsi_pdu_set_immediate(pdu); /* flags */ iscsi_pdu_set_pduflags(pdu, ISCSI_PDU_TEXT_FINAL); /* target transfer tag */ iscsi_pdu_set_ttt(pdu, 0xffffffff); /* sendtargets */ str = (char *)"SendTargets=All"; if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); iscsi_free_pdu(iscsi, pdu); return -1; } pdu->callback = cb; pdu->private_data = private_data; if (iscsi_queue_pdu(iscsi, pdu) != 0) { iscsi_set_error(iscsi, "Out-of-memory: failed to queue iscsi " "text pdu."); iscsi_free_pdu(iscsi, pdu); return -1; } return 0; } static void iscsi_free_discovery_addresses(struct iscsi_discovery_address *addresses) { while (addresses != NULL) { struct iscsi_discovery_address *next = addresses->next; free(discard_const(addresses->target_name)); addresses->target_name = NULL; free(discard_const(addresses->target_address)); addresses->target_address = NULL; addresses->next = NULL; free(addresses); addresses = next; } } int iscsi_process_text_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, struct iscsi_in_pdu *in) { struct iscsi_discovery_address *targets = NULL; unsigned char *ptr = in->data; int size = in->data_pos; /* verify the response looks sane */ if (in->hdr[1] != ISCSI_PDU_TEXT_FINAL) { iscsi_set_error(iscsi, "unsupported flags in text " "reply %02x", in->hdr[1]); pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); return -1; } while (size > 0) { int len; len = strlen((char *)ptr); if (len == 0) { break; } if (len > size) { iscsi_set_error(iscsi, "len > size when parsing " "discovery data %d>%d", len, size); pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); iscsi_free_discovery_addresses(targets); return -1; } /* parse the strings */ if (!strncmp((char *)ptr, "TargetName=", 11)) { struct iscsi_discovery_address *target; target = malloc(sizeof(struct iscsi_discovery_address)); if (target == NULL) { iscsi_set_error(iscsi, "Failed to allocate " "data for new discovered " "target"); pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); iscsi_free_discovery_addresses(targets); return -1; } memset(target, 0, sizeof(struct iscsi_discovery_address)); target->target_name = strdup((char *)ptr+11); if (target->target_name == NULL) { iscsi_set_error(iscsi, "Failed to allocate " "data for new discovered " "target name"); pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); free(target); target = NULL; iscsi_free_discovery_addresses(targets); return -1; } target->next = targets; targets = target; } else if (!strncmp((char *)ptr, "TargetAddress=", 14)) { targets->target_address = strdup((char *)ptr+14); if (targets->target_address == NULL) { iscsi_set_error(iscsi, "Failed to allocate " "data for new discovered " "target address"); pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); iscsi_free_discovery_addresses(targets); return -1; } } else { iscsi_set_error(iscsi, "Dont know how to handle " "discovery string : %s", ptr); pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); iscsi_free_discovery_addresses(targets); return -1; } ptr += len + 1; size -= len + 1; } pdu->callback(iscsi, SCSI_STATUS_GOOD, targets, pdu->private_data); iscsi_free_discovery_addresses(targets); return 0; } libiscsi-1.4.0/lib/login.c0000644000175000017500000006723711750443164013531 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program 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 program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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, see . */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #if defined(WIN32) #include #else #include #endif #include #include #include #include "iscsi.h" #include "iscsi-private.h" #include "md5.h" static int iscsi_login_add_initiatorname(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { char *str; /* We only send InitiatorName during opneg or the first leg of secneg */ if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG && iscsi->secneg_phase != ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP) { return 0; } str = malloc(1024); #if defined(WIN32) if (_snprintf_s(str, 1024, 1024, "InitiatorName=%s", iscsi->initiator_name) == -1) { #else if (snprintf(str, 1024, "InitiatorName=%s", iscsi->initiator_name) == -1) { #endif iscsi_set_error(iscsi, "Out-of-memory: aprintf failed."); free(str); return -1; } if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); free(str); return -1; } free(str); return 0; } static int iscsi_login_add_alias(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { char *str; /* We only send InitiatorAlias during opneg or the first leg of secneg */ if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG && iscsi->secneg_phase != ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP) { return 0; } str = malloc(1024); #if defined(WIN32) if (_snprintf_s(str, 1024, 1024, "InitiatorAlias=%s", iscsi->alias) == -1) { #else if (snprintf(str, 1024, "InitiatorAlias=%s", iscsi->alias) == -1) { #endif iscsi_set_error(iscsi, "Out-of-memory: aprintf failed."); free(str); return -1; } if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); free(str); return -1; } free(str); return 0; } static int iscsi_login_add_targetname(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { char *str; /* We only send TargetName during opneg or the first leg of secneg */ if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG && iscsi->secneg_phase != ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP) { return 0; } if (iscsi->target_name == NULL) { iscsi_set_error(iscsi, "Trying normal connect but " "target name not set."); return -1; } str = malloc(1024); #if defined(WIN32) if (_snprintf_s(str, 1024, 1024, "TargetName=%s", iscsi->target_name) == -1) { #else if (snprintf(str, 1024, "TargetName=%s", iscsi->target_name) == -1) { #endif iscsi_set_error(iscsi, "Out-of-memory: aprintf failed."); free(str); return -1; } if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); free(str); return -1; } free(str); return 0; } static int iscsi_login_add_sessiontype(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { char *str; /* We only send TargetName during opneg or the first leg of secneg */ if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG && iscsi->secneg_phase != ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP) { return 0; } switch (iscsi->session_type) { case ISCSI_SESSION_DISCOVERY: str = (char *)"SessionType=Discovery"; break; case ISCSI_SESSION_NORMAL: str = (char *)"SessionType=Normal"; break; default: iscsi_set_error(iscsi, "Can not handle sessions %d yet.", iscsi->session_type); return -1; } if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); return -1; } return 0; } static int iscsi_login_add_headerdigest(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { char *str; /* We only send HeaderDigest during opneg */ if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) { return 0; } switch (iscsi->want_header_digest) { case ISCSI_HEADER_DIGEST_NONE: str = (char *)"HeaderDigest=None"; break; case ISCSI_HEADER_DIGEST_NONE_CRC32C: str = (char *)"HeaderDigest=None,CRC32C"; break; case ISCSI_HEADER_DIGEST_CRC32C_NONE: str = (char *)"HeaderDigest=CRC32C,None"; break; case ISCSI_HEADER_DIGEST_CRC32C: str = (char *)"HeaderDigest=CRC32C"; break; default: iscsi_set_error(iscsi, "invalid header digest value"); return -1; } if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); return -1; } return 0; } static int iscsi_login_add_datadigest(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { char *str; /* We only send DataDigest during opneg */ if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) { return 0; } str = (char *)"DataDigest=None"; if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); return -1; } return 0; } static int iscsi_login_add_initialr2t(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { char *str; /* We only send InitialR2T during opneg */ if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) { return 0; } str = malloc(1024); #if defined(WIN32) if (_snprintf_s(str, 1024, 1024, "InitialR2T=%s", iscsi->want_initial_r2t == ISCSI_INITIAL_R2T_NO ? #else if (snprintf(str, 1024, "InitialR2T=%s", iscsi->want_initial_r2t == ISCSI_INITIAL_R2T_NO ? #endif "No" : "Yes") == -1) { iscsi_set_error(iscsi, "Out-of-memory: aprintf failed."); free(str); return -1; } if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); free(str); return -1; } free(str); return 0; } static int iscsi_login_add_immediatedata(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { char *str; /* We only send ImmediateData during opneg */ if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) { return 0; } str = malloc(1024); #if defined(WIN32) if (_snprintf_s(str, 1024, 1024, "ImmediateData=%s", iscsi->want_immediate_data == ISCSI_IMMEDIATE_DATA_NO ? #else if (snprintf(str, 1024, "ImmediateData=%s", iscsi->want_immediate_data == ISCSI_IMMEDIATE_DATA_NO ? #endif "No" : "Yes") == -1) { iscsi_set_error(iscsi, "Out-of-memory: aprintf failed."); free(str); return -1; } if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); free(str); return -1; } free(str); return 0; } static int iscsi_login_add_maxburstlength(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { char *str; /* We only send MaxBurstLength during opneg */ if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) { return 0; } str = malloc(1024); #if defined(WIN32) if (_snprintf_s(str, 1024, 1024, "MaxBurstLength=%d", iscsi->max_burst_length) == -1) { #else if (snprintf(str, 1024, "MaxBurstLength=%d", iscsi->max_burst_length) == -1) { #endif iscsi_set_error(iscsi, "Out-of-memory: aprintf failed."); free(str); return -1; } if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); free(str); return -1; } free(str); return 0; } static int iscsi_login_add_firstburstlength(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { char *str; /* We only send FirstBurstLength during opneg */ if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) { return 0; } str = malloc(1024); #if defined(WIN32) if (_snprintf_s(str, 1024, 1024, "FirstBurstLength=%d", iscsi->first_burst_length) == -1) { #else if (snprintf(str, 1024, "FirstBurstLength=%d", iscsi->first_burst_length) == -1) { #endif iscsi_set_error(iscsi, "Out-of-memory: aprintf failed."); free(str); return -1; } if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); free(str); return -1; } free(str); return 0; } static int iscsi_login_add_maxrecvdatasegmentlength(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { char *str; /* We only send MaxRecvDataSegmentLength during opneg */ if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) { return 0; } str = malloc(1024); #if defined(WIN32) if (_snprintf_s(str, 1024, 1024, "MaxRecvDataSegmentLength=%d", iscsi->initiator_max_recv_data_segment_length) == -1) { #else if (snprintf(str, 1024, "MaxRecvDataSegmentLength=%d", iscsi->initiator_max_recv_data_segment_length) == -1) { #endif iscsi_set_error(iscsi, "Out-of-memory: aprintf failed."); free(str); return -1; } if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); free(str); return -1; } free(str); return 0; } static int iscsi_login_add_datapduinorder(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { char *str; /* We only send DataPduInOrder during opneg */ if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) { return 0; } str = (char *)"DataPDUInOrder=Yes"; if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); return -1; } return 0; } static int iscsi_login_add_defaulttime2wait(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { char *str; /* We only send DefaultTime2Wait during opneg */ if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) { return 0; } str = (char *)"DefaultTime2Wait=2"; if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); return -1; } return 0; } static int iscsi_login_add_defaulttime2retain(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { char *str; /* We only send DefaultTime2Retain during opneg */ if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) { return 0; } str = (char *)"DefaultTime2Retain=0"; if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); return -1; } return 0; } static int iscsi_login_add_ifmarker(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { char *str; /* We only send IFMarker during opneg */ if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) { return 0; } str = (char *)"IFMarker=No"; if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); return -1; } return 0; } static int iscsi_login_add_ofmarker(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { char *str; /* We only send OFMarker during opneg */ if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) { return 0; } str = (char *)"OFMarker=No"; if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); return -1; } return 0; } static int iscsi_login_add_maxconnections(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { char *str; /* We only send MaxConnections during opneg */ if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) { return 0; } str = (char *)"MaxConnections=1"; if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); return -1; } return 0; } static int iscsi_login_add_maxoutstandingr2t(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { char *str; /* We only send MaxOutstandingR2T during opneg */ if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) { return 0; } str = (char *)"MaxOutstandingR2T=1"; if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); return -1; } return 0; } static int iscsi_login_add_errorrecoverylevel(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { char *str; /* We only send ErrorRecoveryLevel during opneg */ if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) { return 0; } str = (char *)"ErrorRecoveryLevel=0"; if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); return -1; } return 0; } static int iscsi_login_add_datasequenceinorder(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { char *str; /* We only send DataSequenceInOrder during opneg */ if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) { return 0; } str = (char *)"DataSequenceInOrder=Yes"; if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); return -1; } return 0; } static int iscsi_login_add_authmethod(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { char *str; if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_SECNEG || iscsi->secneg_phase != ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP) { return 0; } str = (char *)"AuthMethod=CHAP,None"; if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); return -1; } return 0; } static int iscsi_login_add_authalgorithm(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { char *str; if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_SECNEG || iscsi->secneg_phase != ISCSI_LOGIN_SECNEG_PHASE_SELECT_ALGORITHM) { return 0; } str = (char *)"CHAP_A=5"; if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); return -1; } return 0; } static int iscsi_login_add_chap_username(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { char *str; if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_SECNEG || iscsi->secneg_phase != ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE) { return 0; } str = (char *)"CHAP_N="; if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); return -1; } if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)iscsi->user, strlen(iscsi->user) +1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data " "failed."); return -1; } return 0; } static int h2i(int h) { if (h >= 'a' && h <= 'f') { return h - 'a' + 10; } if (h >= 'A' && h <= 'F') { return h - 'A' + 10; } return h - '0'; } static int i2h(int i) { if (i >= 10) { return i - 10 + 'A'; } return i + '0'; } static int iscsi_login_add_chap_response(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { char *str; unsigned char c, cc[2]; unsigned char digest[16]; struct MD5Context ctx; int i; if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_SECNEG || iscsi->secneg_phase != ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE) { return 0; } if (iscsi->chap_c == NULL) { iscsi_set_error(iscsi, "No CHAP challenge found"); return -1; } MD5Init(&ctx); c = iscsi->chap_i; MD5Update(&ctx, &c, 1); MD5Update(&ctx, (unsigned char *)iscsi->passwd, strlen(iscsi->passwd)); str = iscsi->chap_c; while (*str != 0) { c = (h2i(str[0]) << 4) | h2i(str[1]); str += 2; MD5Update(&ctx, &c, 1); } MD5Final(digest, &ctx); str = (char *)"CHAP_R=0x"; if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); return -1; } for (i=0; i<16; i++) { c = digest[i]; cc[0] = i2h((c >> 4)&0x0f); cc[1] = i2h((c )&0x0f); if (iscsi_pdu_add_data(iscsi, pdu, &cc[0], 2) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data " "failed."); return -1; } } c = 0; if (iscsi_pdu_add_data(iscsi, pdu, &c, 1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data " "failed."); return -1; } return 0; } int iscsi_login_async(struct iscsi_context *iscsi, iscsi_command_cb cb, void *private_data) { struct iscsi_pdu *pdu; int transit; if (iscsi->login_attempts++ > 10) { iscsi_set_error(iscsi, "login took too many tries." " giving up."); return -1; } if (iscsi->is_loggedin != 0) { iscsi_set_error(iscsi, "Trying to login while already logged " "in."); return -1; } switch (iscsi->session_type) { case ISCSI_SESSION_DISCOVERY: case ISCSI_SESSION_NORMAL: break; default: iscsi_set_error(iscsi, "trying to login without setting " "session type."); return -1; } pdu = iscsi_allocate_pdu(iscsi, ISCSI_PDU_LOGIN_REQUEST, ISCSI_PDU_LOGIN_RESPONSE); if (pdu == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to allocate " "login pdu."); return -1; } /* login request */ iscsi_pdu_set_immediate(pdu); if (iscsi->user == NULL) { iscsi->current_phase = ISCSI_PDU_LOGIN_CSG_OPNEG; } if (iscsi->current_phase == ISCSI_PDU_LOGIN_CSG_SECNEG) { iscsi->next_phase = ISCSI_PDU_LOGIN_NSG_OPNEG; } if (iscsi->current_phase == ISCSI_PDU_LOGIN_CSG_OPNEG) { iscsi->next_phase = ISCSI_PDU_LOGIN_NSG_FF; } transit = 0; if (iscsi->current_phase == ISCSI_PDU_LOGIN_CSG_OPNEG) { transit = ISCSI_PDU_LOGIN_TRANSIT; } if (iscsi->current_phase == ISCSI_PDU_LOGIN_CSG_SECNEG) { if (iscsi->secneg_phase == ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP) { transit = ISCSI_PDU_LOGIN_TRANSIT; } if (iscsi->secneg_phase == ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE) { transit = ISCSI_PDU_LOGIN_TRANSIT; } } /* flags */ iscsi_pdu_set_pduflags(pdu, transit | iscsi->current_phase | iscsi->next_phase); /* initiator name */ if (iscsi_login_add_initiatorname(iscsi, pdu) != 0) { iscsi_free_pdu(iscsi, pdu); return -1; } /* optional alias */ if (iscsi->alias) { if (iscsi_login_add_alias(iscsi, pdu) != 0) { iscsi_free_pdu(iscsi, pdu); return -1; } } /* target name */ if (iscsi->session_type == ISCSI_SESSION_NORMAL) { if (iscsi_login_add_targetname(iscsi, pdu) != 0) { iscsi_free_pdu(iscsi, pdu); return -1; } } /* session type */ if (iscsi_login_add_sessiontype(iscsi, pdu) != 0) { iscsi_free_pdu(iscsi, pdu); return -1; } /* header digest */ if (iscsi_login_add_headerdigest(iscsi, pdu) != 0) { iscsi_free_pdu(iscsi, pdu); return -1; } /* auth method */ if (iscsi_login_add_authmethod(iscsi, pdu) != 0) { iscsi_free_pdu(iscsi, pdu); return -1; } /* auth algorithm */ if (iscsi_login_add_authalgorithm(iscsi, pdu) != 0) { iscsi_free_pdu(iscsi, pdu); return -1; } /* chap username */ if (iscsi_login_add_chap_username(iscsi, pdu) != 0) { iscsi_free_pdu(iscsi, pdu); return -1; } /* chap response */ if (iscsi_login_add_chap_response(iscsi, pdu) != 0) { iscsi_free_pdu(iscsi, pdu); return -1; } /* data digest */ if (iscsi_login_add_datadigest(iscsi, pdu) != 0) { iscsi_free_pdu(iscsi, pdu); return -1; } /* initial r2t */ if (iscsi_login_add_initialr2t(iscsi, pdu) != 0) { iscsi_free_pdu(iscsi, pdu); return -1; } /* immediate data */ if (iscsi_login_add_immediatedata(iscsi, pdu) != 0) { iscsi_free_pdu(iscsi, pdu); return -1; } /* max burst length */ if (iscsi_login_add_maxburstlength(iscsi, pdu) != 0) { iscsi_free_pdu(iscsi, pdu); return -1; } /* first burst length */ if (iscsi_login_add_firstburstlength(iscsi, pdu) != 0) { iscsi_free_pdu(iscsi, pdu); return -1; } /* default time 2 wait */ if (iscsi_login_add_defaulttime2wait(iscsi, pdu) != 0) { iscsi_free_pdu(iscsi, pdu); return -1; } /* default time 2 retain */ if (iscsi_login_add_defaulttime2retain(iscsi, pdu) != 0) { iscsi_free_pdu(iscsi, pdu); return -1; } /* max outstanding r2t */ if (iscsi_login_add_maxoutstandingr2t(iscsi, pdu) != 0) { iscsi_free_pdu(iscsi, pdu); return -1; } /* errorrecoverylevel */ if (iscsi_login_add_errorrecoverylevel(iscsi, pdu) != 0) { iscsi_free_pdu(iscsi, pdu); return -1; } /* ifmarker */ if (iscsi_login_add_ifmarker(iscsi, pdu) != 0) { iscsi_free_pdu(iscsi, pdu); return -1; } /* ofmarker */ if (iscsi_login_add_ofmarker(iscsi, pdu) != 0) { iscsi_free_pdu(iscsi, pdu); return -1; } /* maxconnections */ if (iscsi_login_add_maxconnections(iscsi, pdu) != 0) { iscsi_free_pdu(iscsi, pdu); return -1; } /* max recv data segment length */ if (iscsi_login_add_maxrecvdatasegmentlength(iscsi, pdu) != 0) { iscsi_free_pdu(iscsi, pdu); return -1; } /* data pdu in order */ if (iscsi_login_add_datapduinorder(iscsi, pdu) != 0) { iscsi_free_pdu(iscsi, pdu); return -1; } /* data sequence in order */ if (iscsi_login_add_datasequenceinorder(iscsi, pdu) != 0) { iscsi_free_pdu(iscsi, pdu); return -1; } pdu->callback = cb; pdu->private_data = private_data; if (iscsi_queue_pdu(iscsi, pdu) != 0) { iscsi_set_error(iscsi, "Out-of-memory: failed to queue iscsi " "pdu."); iscsi_free_pdu(iscsi, pdu); return -1; } return 0; } static const char *login_error_str(int status) { switch (status) { case 0x0100: return "Target moved (unknown)"; /* Some don't set the detail */ case 0x0101: return "Target moved temporarily"; case 0x0102: return "Target moved permanently"; case 0x0200: return "Initiator error"; case 0x0201: return "Authentication failure"; case 0x0202: return "Authorization failure"; case 0x0203: return "Target not found"; case 0x0204: return "Target removed"; case 0x0205: return "Unsupported version"; case 0x0206: return "Too many connections"; case 0x0207: return "Missing parameter"; case 0x0208: return "Can't include in session"; case 0x0209: return "Session type not supported"; case 0x020a: return "Session does not exist"; case 0x020b: return "Invalid during login"; case 0x0300: return "Target error"; case 0x0301: return "Service unavailable"; case 0x0302: return "Out of resources"; } return "Unknown login error"; } int iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, struct iscsi_in_pdu *in) { int status; char *ptr = (char *)in->data; int size = in->data_pos; status = ntohs(*(uint16_t *)&in->hdr[36]); iscsi->statsn = ntohs(*(uint16_t *)&in->hdr[24]); /* XXX here we should parse the data returned in case the target * renegotiated some some parameters. * we should also do proper handshaking if the target is not yet * prepared to transition to the next stage */ while (size > 0) { int len; len = strlen(ptr); if (len == 0) { break; } if (len > size) { iscsi_set_error(iscsi, "len > size when parsing " "login data %d>%d", len, size); pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); return -1; } /* parse the strings */ if (!strncmp(ptr, "TargetAddress=", 14)) { free(discard_const(iscsi->target_address)); iscsi->target_address = strdup(ptr+14); if (iscsi->target_address == NULL) { iscsi_set_error(iscsi, "Failed to allocate" " target address"); pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); return -1; } } if (!strncmp(ptr, "HeaderDigest=", 13)) { if (!strcmp(ptr + 13, "CRC32C")) { iscsi->header_digest = ISCSI_HEADER_DIGEST_CRC32C; iscsi->want_header_digest = ISCSI_HEADER_DIGEST_CRC32C; } else { iscsi->header_digest = ISCSI_HEADER_DIGEST_NONE; iscsi->want_header_digest = ISCSI_HEADER_DIGEST_NONE; } } if (!strncmp(ptr, "FirstBurstLength=", 17)) { iscsi->first_burst_length = strtol(ptr + 17, NULL, 10); } if (!strncmp(ptr, "InitialR2T=", 11)) { if (!strcmp(ptr + 11, "No")) { iscsi->use_initial_r2t = ISCSI_INITIAL_R2T_NO; } else { iscsi->use_initial_r2t = ISCSI_INITIAL_R2T_YES; } } if (!strncmp(ptr, "ImmediateData=", 14)) { if (!strcmp(ptr + 14, "No")) { iscsi->use_immediate_data = ISCSI_IMMEDIATE_DATA_NO; } else { iscsi->use_immediate_data = ISCSI_IMMEDIATE_DATA_YES; } } if (!strncmp(ptr, "MaxBurstLength=", 15)) { iscsi->max_burst_length = strtol(ptr + 15, NULL, 10); } if (!strncmp(ptr, "MaxRecvDataSegmentLength=", 25)) { iscsi->target_max_recv_data_segment_length = strtol(ptr + 25, NULL, 10); } if (!strncmp(ptr, "AuthMethod=", 11)) { if (!strcmp(ptr + 11, "CHAP")) { iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_SELECT_ALGORITHM; } } if (!strncmp(ptr, "CHAP_A=", 7)) { iscsi->chap_a = atoi(ptr+7); iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE; } if (!strncmp(ptr, "CHAP_I=", 7)) { iscsi->chap_i = atoi(ptr+7); iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE; } if (!strncmp(ptr, "CHAP_C=0x", 9)) { free(iscsi->chap_c); iscsi->chap_c = strdup(ptr+9); if (iscsi->chap_c == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup CHAP challenge."); pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); return -1; } iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE; } ptr += len + 1; size -= len + 1; } if (status != 0) { iscsi_set_error(iscsi, "Failed to log in to target. Status: %s(%d)", login_error_str(status), status); pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); return 0; } if (in->hdr[1] & ISCSI_PDU_LOGIN_TRANSIT) { iscsi->current_phase = (in->hdr[1] & ISCSI_PDU_LOGIN_NSG_FF) << 2; } if ((in->hdr[1] & ISCSI_PDU_LOGIN_TRANSIT) && (in->hdr[1] & ISCSI_PDU_LOGIN_NSG_FF) == ISCSI_PDU_LOGIN_NSG_FF) { iscsi->is_loggedin = 1; pdu->callback(iscsi, SCSI_STATUS_GOOD, NULL, pdu->private_data); } else { if (iscsi_login_async(iscsi, pdu->callback, pdu->private_data) != 0) { iscsi_set_error(iscsi, "Failed to send continuation login pdu"); pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); } } return 0; } int iscsi_logout_async(struct iscsi_context *iscsi, iscsi_command_cb cb, void *private_data) { struct iscsi_pdu *pdu; iscsi->login_attempts = 0; if (iscsi->is_loggedin == 0) { iscsi_set_error(iscsi, "Trying to logout while not logged in."); return -1; } pdu = iscsi_allocate_pdu(iscsi, ISCSI_PDU_LOGOUT_REQUEST, ISCSI_PDU_LOGOUT_RESPONSE); if (pdu == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to allocate " "logout pdu."); return -1; } /* logout request has the immediate flag set */ iscsi_pdu_set_immediate(pdu); /* flags : close the session */ iscsi_pdu_set_pduflags(pdu, 0x80); /* cmdsn is not increased if Immediate delivery*/ iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn); pdu->cmdsn = iscsi->cmdsn; /* exp statsn */ iscsi_pdu_set_expstatsn(pdu, iscsi->statsn+1); pdu->callback = cb; pdu->private_data = private_data; if (iscsi_queue_pdu(iscsi, pdu) != 0) { iscsi_set_error(iscsi, "Out-of-memory: failed to queue iscsi " "logout pdu."); iscsi_free_pdu(iscsi, pdu); return -1; } return 0; } int iscsi_process_logout_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, struct iscsi_in_pdu *in _U_) { iscsi->is_loggedin = 0; pdu->callback(iscsi, SCSI_STATUS_GOOD, NULL, pdu->private_data); return 0; } int iscsi_set_session_type(struct iscsi_context *iscsi, enum iscsi_session_type session_type) { if (iscsi->is_loggedin) { iscsi_set_error(iscsi, "trying to set session type while " "logged in"); return -1; } iscsi->session_type = session_type; return 0; } libiscsi-1.4.0/lib/connect.c0000644000175000017500000001351511750443164014040 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program 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 program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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, see . */ #include #include #include #include #include #include "slist.h" #include "iscsi.h" #include "iscsi-private.h" #include "scsi-lowlevel.h" struct connect_task { iscsi_command_cb cb; void *private_data; int lun; }; static void iscsi_testunitready_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) { struct connect_task *ct = private_data; struct scsi_task *task = command_data; if (status != 0) { if (task->sense.key == SCSI_SENSE_UNIT_ATTENTION && task->sense.ascq == SCSI_SENSE_ASCQ_BUS_RESET) { /* This is just the normal unitattention/busreset * you always get just after a fresh login. Try * again. */ if (iscsi_testunitready_task(iscsi, ct->lun, iscsi_testunitready_cb, ct) == NULL) { iscsi_set_error(iscsi, "iscsi_testunitready " "failed."); ct->cb(iscsi, SCSI_STATUS_ERROR, NULL, ct->private_data); free(ct); } scsi_free_scsi_task(task); return; } } ct->cb(iscsi, status?SCSI_STATUS_ERROR:SCSI_STATUS_GOOD, NULL, ct->private_data); free(ct); scsi_free_scsi_task(task); } static void iscsi_login_cb(struct iscsi_context *iscsi, int status, void *command_data _U_, void *private_data) { struct connect_task *ct = private_data; if (status != 0) { ct->cb(iscsi, SCSI_STATUS_ERROR, NULL, ct->private_data); free(ct); return; } if (iscsi_testunitready_task(iscsi, ct->lun, iscsi_testunitready_cb, ct) == NULL) { iscsi_set_error(iscsi, "iscsi_testunitready_async failed."); ct->cb(iscsi, SCSI_STATUS_ERROR, NULL, ct->private_data); free(ct); } } static void iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data _U_, void *private_data) { struct connect_task *ct = private_data; if (status != 0) { iscsi_set_error(iscsi, "Failed to connect to iSCSI socket. " "%s", iscsi_get_error(iscsi)); ct->cb(iscsi, SCSI_STATUS_ERROR, NULL, ct->private_data); free(ct); return; } if (iscsi_login_async(iscsi, iscsi_login_cb, ct) != 0) { iscsi_set_error(iscsi, "iscsi_login_async failed."); ct->cb(iscsi, SCSI_STATUS_ERROR, NULL, ct->private_data); free(ct); } } int iscsi_full_connect_async(struct iscsi_context *iscsi, const char *portal, int lun, iscsi_command_cb cb, void *private_data) { struct connect_task *ct; iscsi->lun = lun; iscsi->portal = strdup(portal); ct = malloc(sizeof(struct connect_task)); if (ct == NULL) { iscsi_set_error(iscsi, "Out-of-memory. Failed to allocate " "connect_task structure."); return -ENOMEM; } ct->cb = cb; ct->lun = lun; ct->private_data = private_data; if (iscsi_connect_async(iscsi, portal, iscsi_connect_cb, ct) != 0) { free(ct); return -ENOMEM; } return 0; } int iscsi_reconnect(struct iscsi_context *old_iscsi) { struct iscsi_context *iscsi; try_again: iscsi = iscsi_create_context(old_iscsi->initiator_name); iscsi->is_reconnecting = 1; iscsi_set_targetname(iscsi, old_iscsi->target_name); iscsi_set_header_digest(iscsi, old_iscsi->want_header_digest); if (old_iscsi->user != NULL) { iscsi_set_initiator_username_pwd(iscsi, old_iscsi->user, old_iscsi->passwd); } iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL); iscsi->lun = old_iscsi->lun; iscsi->portal = strdup(old_iscsi->portal); if (iscsi_full_connect_sync(iscsi, iscsi->portal, iscsi->lun) != 0) { iscsi_destroy_context(iscsi); sleep(1); goto try_again; } while (old_iscsi->waitpdu) { struct iscsi_pdu *pdu = old_iscsi->waitpdu; SLIST_REMOVE(&old_iscsi->waitpdu, pdu); if (pdu->itt == 0xffffffff) { continue; } pdu->itt = iscsi->itt++; iscsi_pdu_set_itt(pdu, pdu->itt); pdu->cmdsn = iscsi->cmdsn++; iscsi_pdu_set_cmdsn(pdu, pdu->cmdsn); iscsi_pdu_set_expstatsn(pdu, iscsi->statsn); iscsi->statsn++; pdu->written = 0; SLIST_ADD_END(&iscsi->outqueue, pdu); } while (old_iscsi->outqueue) { struct iscsi_pdu *pdu = old_iscsi->outqueue; SLIST_REMOVE(&old_iscsi->outqueue, pdu); if (pdu->itt == 0xffffffff) { continue; } pdu->itt = iscsi->itt++; iscsi_pdu_set_itt(pdu, pdu->itt); pdu->cmdsn = iscsi->cmdsn++; iscsi_pdu_set_cmdsn(pdu, pdu->cmdsn); iscsi_pdu_set_expstatsn(pdu, iscsi->statsn); iscsi->statsn++; pdu->written = 0; SLIST_ADD_END(&iscsi->outqueue, pdu); } if (dup2(iscsi->fd, old_iscsi->fd) == -1) { iscsi_destroy_context(iscsi); goto try_again; } free(discard_const(old_iscsi->initiator_name)); free(discard_const(old_iscsi->target_name)); free(discard_const(old_iscsi->target_address)); free(discard_const(old_iscsi->alias)); free(discard_const(old_iscsi->portal)); if (old_iscsi->incoming != NULL) { iscsi_free_iscsi_in_pdu(old_iscsi->incoming); } if (old_iscsi->inqueue != NULL) { iscsi_free_iscsi_inqueue(old_iscsi->inqueue); } free(old_iscsi->error_string); free(discard_const(old_iscsi->user)); free(discard_const(old_iscsi->passwd)); free(discard_const(old_iscsi->chap_c)); close(iscsi->fd); iscsi->fd = old_iscsi->fd; memcpy(old_iscsi, iscsi, sizeof(struct iscsi_context)); free(iscsi); old_iscsi->is_reconnecting = 0; return 0; } libiscsi-1.4.0/lib/pdu.c0000644000175000017500000003040611750443164013175 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program 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 program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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, see . */ #if defined(WIN32) #include #else #include #include #endif #include #include #include #include "iscsi.h" #include "iscsi-private.h" #include "scsi-lowlevel.h" #include "slist.h" struct iscsi_pdu * iscsi_allocate_pdu_with_itt_flags(struct iscsi_context *iscsi, enum iscsi_opcode opcode, enum iscsi_opcode response_opcode, uint32_t itt, uint32_t flags) { struct iscsi_pdu *pdu; pdu = malloc(sizeof(struct iscsi_pdu)); if (pdu == NULL) { iscsi_set_error(iscsi, "failed to allocate pdu"); return NULL; } memset(pdu, 0, sizeof(struct iscsi_pdu)); pdu->outdata.size = ISCSI_HEADER_SIZE; pdu->outdata.data = malloc(pdu->outdata.size); if (pdu->outdata.data == NULL) { iscsi_set_error(iscsi, "failed to allocate pdu header"); free(pdu); return NULL; } memset(pdu->outdata.data, 0, pdu->outdata.size); /* opcode */ pdu->outdata.data[0] = opcode; pdu->response_opcode = response_opcode; /* isid */ if (opcode == ISCSI_PDU_LOGIN_REQUEST) { memcpy(&pdu->outdata.data[8], &iscsi->isid[0], 6); } /* itt */ iscsi_pdu_set_itt(pdu, itt); pdu->itt = itt; /* flags */ pdu->flags = flags; return pdu; } struct iscsi_pdu * iscsi_allocate_pdu(struct iscsi_context *iscsi, enum iscsi_opcode opcode, enum iscsi_opcode response_opcode) { return iscsi_allocate_pdu_with_itt_flags(iscsi, opcode, response_opcode, iscsi->itt++, 0); } void iscsi_free_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { if (pdu == NULL) { iscsi_set_error(iscsi, "trying to free NULL pdu"); return; } free(pdu->outdata.data); pdu->outdata.data = NULL; free(pdu->indata.data); pdu->indata.data = NULL; if (pdu->scsi_cbdata) { iscsi_free_scsi_cbdata(pdu->scsi_cbdata); pdu->scsi_cbdata = NULL; } free(pdu); } int iscsi_add_data(struct iscsi_context *iscsi, struct iscsi_data *data, unsigned char *dptr, int dsize, int pdualignment) { int len, aligned; unsigned char *buf; if (dsize == 0) { iscsi_set_error(iscsi, "Trying to append zero size data to " "iscsi_data"); return -1; } len = data->size + dsize; aligned = len; if (pdualignment) { aligned = (aligned+3)&0xfffffffc; } buf = malloc(aligned); if (buf == NULL) { iscsi_set_error(iscsi, "failed to allocate buffer for %d " "bytes", len); return -1; } if (data->size > 0) { memcpy(buf, data->data, data->size); } memcpy(buf + data->size, dptr, dsize); if (len != aligned) { /* zero out any padding at the end */ memset(buf+len, 0, aligned-len); } free(data->data); data->data = buf; data->size = len; return 0; } int iscsi_pdu_add_data(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, unsigned char *dptr, int dsize) { if (pdu == NULL) { iscsi_set_error(iscsi, "trying to add data to NULL pdu"); return -1; } if (dsize == 0) { iscsi_set_error(iscsi, "Trying to append zero size data to " "pdu"); return -1; } if (iscsi_add_data(iscsi, &pdu->outdata, dptr, dsize, 1) != 0) { iscsi_set_error(iscsi, "failed to add data to pdu buffer"); return -1; } /* update data segment length */ *(uint32_t *)&pdu->outdata.data[4] = htonl(pdu->outdata.size - ISCSI_HEADER_SIZE); return 0; } int iscsi_get_pdu_data_size(const unsigned char *hdr) { int size; size = (ntohl(*(uint32_t *)&hdr[4])&0x00ffffff); size = (size+3)&0xfffffffc; return size; } enum iscsi_reject_reason { ISCSI_REJECT_RESERVED = 0x01, ISCSI_REJECT_DATA_DIGEST_ERROR = 0x02, ISCSI_REJECT_SNACK_REJECT = 0x03, ISCSI_REJECT_PROTOCOL_ERROR = 0x04, ISCSI_REJECT_COMMAND_NOT_SUPPORTED = 0x05, ISCSI_REJECT_IMMEDIATE_COMMAND_REJECT = 0x06, ISCSI_REJECT_TASK_IN_PROCESS = 0x07, ISCSI_REJECT_INVALID_DATA_ACK = 0x08, ISCSI_REJECT_INVALID_PDU_FIELD = 0x09, ISCSI_REJECT_LONG_OPERATION_REJECT = 0x0a, ISCSI_REJECT_NEGOTIATION_RESET = 0x0b, ISCSI_REJECT_WAITING_FOR_LOGOUT = 0x0c }; static const char *iscsi_reject_reason_str(enum iscsi_reject_reason reason) { switch (reason) { case ISCSI_REJECT_RESERVED: return "Reserved"; case ISCSI_REJECT_DATA_DIGEST_ERROR: return "Data Digest Error"; case ISCSI_REJECT_SNACK_REJECT: return "SNACK Reject"; case ISCSI_REJECT_PROTOCOL_ERROR: return "Protocol Error"; case ISCSI_REJECT_COMMAND_NOT_SUPPORTED: return "Command Not Supported"; case ISCSI_REJECT_IMMEDIATE_COMMAND_REJECT: return "Immediate Command Reject"; case ISCSI_REJECT_TASK_IN_PROCESS: return "Task In Process"; case ISCSI_REJECT_INVALID_DATA_ACK: return "Invalid Data ACK"; case ISCSI_REJECT_INVALID_PDU_FIELD: return "Invalid PDU Field"; case ISCSI_REJECT_LONG_OPERATION_REJECT: return "Long Operation Reject"; case ISCSI_REJECT_NEGOTIATION_RESET: return "Negotiation Reset"; case ISCSI_REJECT_WAITING_FOR_LOGOUT: return "Waiting For Logout"; } return "Unknown"; } int iscsi_process_target_nop_in(struct iscsi_context *iscsi, struct iscsi_in_pdu *in) { uint32_t ttt; uint32_t statsn; ttt = ntohl(*(uint32_t *)&in->hdr[20]); statsn = ntohl(*(uint32_t *)&in->hdr[24]); if (statsn > iscsi->statsn) { iscsi->statsn = statsn; } /* if the server does not want a response */ if (ttt == 0xffffffff) { return 0; } iscsi_send_target_nop_out(iscsi, ttt); return 0; } int iscsi_process_reject(struct iscsi_context *iscsi, struct iscsi_in_pdu *in) { int size = in->data_pos; uint32_t itt; struct iscsi_pdu *pdu; if (size < ISCSI_RAW_HEADER_SIZE) { iscsi_set_error(iscsi, "size of REJECT payload is too small." "Need >= %d bytes but got %d.", ISCSI_RAW_HEADER_SIZE, (int)size); return -1; } itt = ntohl(*(uint32_t *)&in->data[16]); for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) { if (pdu->itt == itt) { break; } } if (pdu == NULL) { iscsi_set_error(iscsi, "Can not match REJECT with" "any outstanding pdu with itt:0x%08x", itt); return -1; } pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); SLIST_REMOVE(&iscsi->waitpdu, pdu); iscsi_free_pdu(iscsi, pdu); return 0; } int iscsi_process_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in) { uint32_t itt; enum iscsi_opcode opcode; struct iscsi_pdu *pdu; uint8_t ahslen; opcode = in->hdr[0] & 0x3f; ahslen = in->hdr[4]; itt = ntohl(*(uint32_t *)&in->hdr[16]); if (ahslen != 0) { iscsi_set_error(iscsi, "cant handle expanded headers yet"); return -1; } if (opcode == ISCSI_PDU_REJECT) { iscsi_set_error(iscsi, "Request was rejected with reason: 0x%02x (%s)", in->hdr[2], iscsi_reject_reason_str(in->hdr[2])); if (iscsi_process_reject(iscsi, in) != 0) { return -1; } return 0; } if (opcode == ISCSI_PDU_NOP_IN && itt == 0xffffffff) { if (iscsi_process_target_nop_in(iscsi, in) != 0) { return -1; } return 0; } for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) { enum iscsi_opcode expected_response = pdu->response_opcode; int is_finished = 1; if (pdu->itt != itt) { continue; } /* we have a special case with scsi-command opcodes, * they are replied to by either a scsi-response * or a data-in, or a combination of both. */ if (opcode == ISCSI_PDU_DATA_IN && expected_response == ISCSI_PDU_SCSI_RESPONSE) { expected_response = ISCSI_PDU_DATA_IN; } /* Another special case is if we get a R2T. * In this case we should find the original request and just send an additional * DATAOUT segment for this task. */ if (opcode == ISCSI_PDU_R2T) { expected_response = ISCSI_PDU_R2T; } if (opcode != expected_response) { iscsi_set_error(iscsi, "Got wrong opcode back for " "itt:%d got:%d expected %d", itt, opcode, pdu->response_opcode); return -1; } switch (opcode) { case ISCSI_PDU_LOGIN_RESPONSE: if (iscsi_process_login_reply(iscsi, pdu, in) != 0) { SLIST_REMOVE(&iscsi->waitpdu, pdu); iscsi_free_pdu(iscsi, pdu); iscsi_set_error(iscsi, "iscsi login reply " "failed"); return -1; } break; case ISCSI_PDU_TEXT_RESPONSE: if (iscsi_process_text_reply(iscsi, pdu, in) != 0) { SLIST_REMOVE(&iscsi->waitpdu, pdu); iscsi_free_pdu(iscsi, pdu); iscsi_set_error(iscsi, "iscsi text reply " "failed"); return -1; } break; case ISCSI_PDU_LOGOUT_RESPONSE: if (iscsi_process_logout_reply(iscsi, pdu, in) != 0) { SLIST_REMOVE(&iscsi->waitpdu, pdu); iscsi_free_pdu(iscsi, pdu); iscsi_set_error(iscsi, "iscsi logout reply " "failed"); return -1; } break; case ISCSI_PDU_SCSI_RESPONSE: if (iscsi_process_scsi_reply(iscsi, pdu, in) != 0) { SLIST_REMOVE(&iscsi->waitpdu, pdu); iscsi_free_pdu(iscsi, pdu); iscsi_set_error(iscsi, "iscsi response reply " "failed"); return -1; } break; case ISCSI_PDU_DATA_IN: if (iscsi_process_scsi_data_in(iscsi, pdu, in, &is_finished) != 0) { SLIST_REMOVE(&iscsi->waitpdu, pdu); iscsi_free_pdu(iscsi, pdu); iscsi_set_error(iscsi, "iscsi data in " "failed"); return -1; } break; case ISCSI_PDU_NOP_IN: if (iscsi_process_nop_out_reply(iscsi, pdu, in) != 0) { SLIST_REMOVE(&iscsi->waitpdu, pdu); iscsi_free_pdu(iscsi, pdu); iscsi_set_error(iscsi, "iscsi nop-in failed"); return -1; } break; case ISCSI_PDU_SCSI_TASK_MANAGEMENT_RESPONSE: if (iscsi_process_task_mgmt_reply(iscsi, pdu, in) != 0) { SLIST_REMOVE(&iscsi->waitpdu, pdu); iscsi_free_pdu(iscsi, pdu); iscsi_set_error(iscsi, "iscsi task-mgmt failed"); return -1; } break; case ISCSI_PDU_R2T: if (iscsi_process_r2t(iscsi, pdu, in) != 0) { SLIST_REMOVE(&iscsi->waitpdu, pdu); iscsi_free_pdu(iscsi, pdu); iscsi_set_error(iscsi, "iscsi r2t " "failed"); return -1; } is_finished = 0; break; default: iscsi_set_error(iscsi, "Dont know how to handle " "opcode 0x%02x", opcode); return -1; } if (is_finished) { SLIST_REMOVE(&iscsi->waitpdu, pdu); iscsi_free_pdu(iscsi, pdu); } return 0; } return 0; } void iscsi_pdu_set_itt(struct iscsi_pdu *pdu, uint32_t itt) { *(uint32_t *)&pdu->outdata.data[16] = htonl(itt); } void iscsi_pdu_set_ritt(struct iscsi_pdu *pdu, uint32_t ritt) { *(uint32_t *)&pdu->outdata.data[20] = htonl(ritt); } void iscsi_pdu_set_pduflags(struct iscsi_pdu *pdu, unsigned char flags) { pdu->outdata.data[1] = flags; } void iscsi_pdu_set_immediate(struct iscsi_pdu *pdu) { pdu->outdata.data[0] |= ISCSI_PDU_IMMEDIATE; } void iscsi_pdu_set_ttt(struct iscsi_pdu *pdu, uint32_t ttt) { *(uint32_t *)&pdu->outdata.data[20] = htonl(ttt); } void iscsi_pdu_set_cmdsn(struct iscsi_pdu *pdu, uint32_t cmdsn) { *(uint32_t *)&pdu->outdata.data[24] = htonl(cmdsn); } void iscsi_pdu_set_rcmdsn(struct iscsi_pdu *pdu, uint32_t rcmdsn) { *(uint32_t *)&pdu->outdata.data[32] = htonl(rcmdsn); } void iscsi_pdu_set_datasn(struct iscsi_pdu *pdu, uint32_t datasn) { *(uint32_t *)&pdu->outdata.data[36] = htonl(datasn); } void iscsi_pdu_set_expstatsn(struct iscsi_pdu *pdu, uint32_t expstatsnsn) { *(uint32_t *)&pdu->outdata.data[28] = htonl(expstatsnsn); } void iscsi_pdu_set_bufferoffset(struct iscsi_pdu *pdu, uint32_t bufferoffset) { *(uint32_t *)&pdu->outdata.data[40] = htonl(bufferoffset); } void iscsi_pdu_set_cdb(struct iscsi_pdu *pdu, struct scsi_task *task) { memset(&pdu->outdata.data[32], 0, 16); memcpy(&pdu->outdata.data[32], task->cdb, task->cdb_size); } void iscsi_pdu_set_lun(struct iscsi_pdu *pdu, uint32_t lun) { pdu->outdata.data[9] = lun; } void iscsi_pdu_set_expxferlen(struct iscsi_pdu *pdu, uint32_t expxferlen) { *(uint32_t *)&pdu->outdata.data[20] = htonl(expxferlen); } libiscsi-1.4.0/README0000644000175000017500000001222511750443164012352 0ustar mjtmjtLibiscsi is a clientside library to implement the iSCSI protocol that can be used to access resource of an iSCSI Target. The library is fully async with regards to iscsi commands and scsi tasks, but a sync layer is also provided for ease of use for simpler applications. The src directory contain a handful of useful iscsi utilities such as logging in to and enumerating all targets on a portal and all devices of a target. The examples directory contain example implementation of how to access both the sync and acync api of libiscsi. Libiscsi is a work in progress. It aims to become a full async library for iscsi functionality, including all features required to establish and maintain a iscsi session, as well as a low level scsi library to create scsi cdb's and parse/unmarshall data-in structures. Installation ============ ./autogen.sh ./configure make sudo make install Build RPM ========= To build RPMs run the following script from the libiscsi root directory ./packaging/RPM/makerpms.sh iSCSI URL Format ================ iSCSI devices are specified by a URL format on the following form : iscsi://[[%]@][:]// Example: iscsi://server/iqn.ronnie.test/1 When using CHAP authentication, username and password can be specified as part of the URL iscsi://ronnie%password@server/iqn.ronnie.test/1 but this may make the user and password visible in log files as well as in ps aux output. So it is also possible to provide either just the password or both the password and username via environment variables. The username and/or password can be set via LIBISCSI_CHAP_USERNAME=ronnie LIBISCSI_CHAP_PASSWORD=password Example: LIBISCSI_CHAP_PASSWORD=password iscsi-inq iscsi://ronnie@10.1.1.27/iqn.ronnie.test/1 IPv6 support ============ Libiscsi supports IPv6, either as names resolving into IPv6 addresses or when IPv6 addresses are explicitely set in the URL. When specifying IPv6 addresses in the URL, they have to be specified in [...] bracket form. Example: iscsi://[fec0:2727::3]:3260/iqn.ronnie.test/1 Header Digest ============= Libiscsi supports HeaderDigest. By default, libiscsi will offer None,CRC32C and let the target pick whether Header digest is to be used or not. This can be overridden by an application by calling iscsi_set_header_digest() if the application wants to force a specific setting. Patches ======= The patches subdirectory contains patches to make some external packages iscsi aware and make them use libiscsi. Currently we have SG3-UTILS and MTX. Patches for other packages would be welcome. ISCSI-TEST ========== The test-tool subdirectory contains a iscsi/scsi test tool. This is a tool that is aimed at providing a comprehensive iscsi and scsi emulation test suite. Run 'make iscsi-test' to compile it. Run ./test-tool/iscsi-test --help and Run ./test-tool/iscsi-test --list for instructions Example: $ ./test-tool/iscsi-test --initiator-name=iqn.ronnie.test --test=T0105_read10_invalid iscsi://127.0.0.1/iqn.ronnie.test/1 ========= Running test T0105_read10_invalid Read10 1 block but with iscsi ExpectedDataTransferLength==0 ... [FAILED] Read10 of 1 block with iscsi ExpectedDataTransferLength==0 should fail. TEST T0105_read10_invalid [FAILED] LD_PRELOAD FUN ============== There is a small LD_PRELOAD hack in the src directory that intercepts a handful of system calls and converts ISCSI URLs to look and behave as if they are normal read-only files. This allows using standard unix tools to become iscsi aware with no modifications. For example: The stat command: this shows the size of the iSCSI LUN as if it was a normal file: $ LD_PRELOAD=./bin/ld_iscsi.so stat iscsi://127.0.0.1:3262/iqn.ronnie.test/2 File: `iscsi://127.0.0.1:3262/iqn.ronnie.test/2' Size: 3431540736 Blocks: 0 IO Block: 0 regular file Device: 0h/0d Inode: 0 Links: 0 Access: (0444/-r--r--r--) Uid: ( 0/ root) Gid: ( 0/ root) Access: 1970-01-01 10:00:00.000000000 +1000 Modify: 1970-01-01 10:00:00.000000000 +1000 Change: 1970-01-01 10:00:00.000000000 +1000 The cat command, which allows you to read/dump a iSCSI LUN to a file : $ LD_PRELOAD=./bin/ld_iscsi.so cat iscsi://127.0.0.1:3262/iqn.ronnie.test/2 >copy_of_iscsi_lun Or using dd even : LD_PRELOAD=./bin/ld_iscsi.so dd if=iscsi://127.0.0.1:3262/iqn.ronnie.test/2 of=copy_of_LUN bs=10M count=1 The LD_PRELOAD hack is incomplete and needs more functions to be intercepted before becomming fully functional. Patches welcome! For now, it is sufficiently complete for trivial commands like stat and cat. You probably need to implement at least lseek, pread, pwrite before it becomes really useful. SUPPORTED PLATFORMS =================== libiscsi is pure posix and should with some tweaks run on any host that provides a posix-like environment. Libiscsi has been tested on: * Linux (32 and 64 bit) * Cygwin * FreeBSD * Windows (Win7-VisualStudio10) * OpenSolaris RELEASE TARBALLS ================ Release tarballs are available at https://github.com/sahlberg/libiscsi/downloads MAILINGLIST =========== A libiscsi mailinglist is available at http://groups.google.com/group/libiscsi Announcements of new versions of libiscsi will be posted to this list. libiscsi-1.4.0/LICENCE-GPL-2.txt0000644000175000017500000004325411750443164014062 0ustar mjtmjt GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 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. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. libiscsi-1.4.0/COPYING0000644000175000017500000000323611750443164012527 0ustar mjtmjtLibiscsi components fall under two separate licences The lib and include directories =============================== The iscsi client library itself, i.e. the lib and include directories, is licenced under 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. The library also contains one file : lib/md5.c that is under Public Domain. A copy of LGPL 2.1 is included in the file LICENCE-LGPL-2.1.txt but can also be downloaded from http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html This is the licence that applies to the libiscsi library and its use. src/ld_iscsi.c ============== This LD_PRELOAD utility is licenced under 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. The src, examples and test-tool directories EXCEPT src/ld_iscsi.c ============================================================= The utility and example applications using this library, i.e. the src and the examples directories, are licenced under the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. These are executable applications that link with the libiscsi library. A copy of GPL 2 is included in the file LICENCE-GPL-2.txt but can also be downloaded from http://www.gnu.org/licenses/old-licenses/gpl-2.0.html This licence applies only to the source code for the provided applications that link to and use libiscsi. To avoid any confusion, every source file also contain a licence boilerplate. libiscsi-1.4.0/INSTALL0000644000175000017500000000033311750443164012520 0ustar mjtmjtThis installs a new shared library under /usr/lib[64] and executables under /usr/bin From source: ============ ./autogen.sh ./configure make sudo make install Building RPM: ============= ./packaging/RPM/makerpms.sh libiscsi-1.4.0/include/0000755000175000017500000000000011750443164013113 5ustar mjtmjtlibiscsi-1.4.0/include/slist.h0000644000175000017500000000303311750443164014421 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program 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 program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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, see . */ #define SLIST_ADD(list, item) \ do { \ (item)->next = (*list); \ (*list) = (item); \ } while (0); #define SLIST_ADD_END(list, item) \ if ((*list) == NULL) { \ SLIST_ADD((list), (item)); \ } else { \ void *head = (*list); \ while ((*list)->next) \ (*list) = (*list)->next; \ (*list)->next = (item); \ (item)->next = NULL; \ (*list) = head; \ } #define SLIST_REMOVE(list, item) \ if ((*list) == (item)) { \ (*list) = (item)->next; \ } else { \ void *head = (*list); \ while ((*list)->next && (*list)->next != (item)) \ (*list) = (*list)->next; \ if ((*list)->next != NULL) { \ (*list)->next = (*list)->next->next; \ } \ (*list) = head; \ } libiscsi-1.4.0/include/scsi-lowlevel.h0000644000175000017500000004353511750443164016066 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program 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 program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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, see . */ #ifndef __scsi_lowlevel_h__ #define __scsi_lowlevel_h__ #define SCSI_CDB_MAX_SIZE 16 enum scsi_opcode { SCSI_OPCODE_TESTUNITREADY = 0x00, SCSI_OPCODE_READ6 = 0x08, SCSI_OPCODE_INQUIRY = 0x12, SCSI_OPCODE_MODESENSE6 = 0x1a, SCSI_OPCODE_READCAPACITY10 = 0x25, SCSI_OPCODE_READ10 = 0x28, SCSI_OPCODE_WRITE10 = 0x2A, SCSI_OPCODE_VERIFY10 = 0x2F, SCSI_OPCODE_PREFETCH10 = 0x34, SCSI_OPCODE_SYNCHRONIZECACHE10 = 0x35, SCSI_OPCODE_WRITE_SAME10 = 0x41, SCSI_OPCODE_UNMAP = 0x42, SCSI_OPCODE_READ16 = 0x88, SCSI_OPCODE_WRITE16 = 0x8A, SCSI_OPCODE_PREFETCH16 = 0x90, SCSI_OPCODE_WRITE_SAME16 = 0x93, SCSI_OPCODE_SERVICE_ACTION_IN = 0x9E, SCSI_OPCODE_REPORTLUNS = 0xA0, SCSI_OPCODE_READ12 = 0xA8, SCSI_OPCODE_WRITE12 = 0xAA }; enum scsi_service_action_in { SCSI_READCAPACITY16 = 0x10 }; /* sense keys */ enum scsi_sense_key { SCSI_SENSE_NO_SENSE = 0x00, SCSI_SENSE_RECOVERED_ERROR = 0x01, SCSI_SENSE_NOT_READY = 0x02, SCSI_SENSE_MEDIUM_ERROR = 0x03, SCSI_SENSE_HARDWARE_ERROR = 0x04, SCSI_SENSE_ILLEGAL_REQUEST = 0x05, SCSI_SENSE_UNIT_ATTENTION = 0x06, SCSI_SENSE_DATA_PROTECTION = 0x07, SCSI_SENSE_BLANK_CHECK = 0x08, SCSI_SENSE_VENDOR_SPECIFIC = 0x09, SCSI_SENSE_COPY_ABORTED = 0x0a, SCSI_SENSE_COMMAND_ABORTED = 0x0b, SCSI_SENSE_OBSOLETE_ERROR_CODE = 0x0c, SCSI_SENSE_OVERFLOW_COMMAND = 0x0d, SCSI_SENSE_MISCOMPARE = 0x0e }; EXTERN const char *scsi_sense_key_str(int key); /* ascq */ #define SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE 0x2000 #define SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE 0x2100 #define SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB 0x2400 #define SCSI_SENSE_ASCQ_LOGICAL_UNIT_NOT_SUPPORTED 0x2500 #define SCSI_SENSE_ASCQ_BUS_RESET 0x2900 #define SCSI_SENSE_ASCQ_INTERNAL_TARGET_FAILURE 0x4400 EXTERN const char *scsi_sense_ascq_str(int ascq); enum scsi_xfer_dir { SCSI_XFER_NONE = 0, SCSI_XFER_READ = 1, SCSI_XFER_WRITE = 2 }; struct scsi_reportluns_params { int report_type; }; struct scsi_read6_params { uint32_t lba; uint32_t num_blocks; }; struct scsi_read10_params { uint32_t lba; uint32_t num_blocks; }; struct scsi_read12_params { uint32_t lba; uint32_t num_blocks; }; struct scsi_read16_params { uint64_t lba; uint32_t num_blocks; }; struct scsi_write10_params { uint32_t lba; uint32_t num_blocks; }; struct scsi_write12_params { uint32_t lba; uint32_t num_blocks; }; struct scsi_write16_params { uint64_t lba; uint32_t num_blocks; }; struct scsi_verify10_params { uint32_t lba; uint32_t num_blocks; int vprotect; int dpo; int bytchk; }; struct scsi_readcapacity10_params { int lba; int pmi; }; struct scsi_inquiry_params { int evpd; int page_code; }; struct scsi_modesense6_params { int dbd; int pc; int page_code; int sub_page_code; }; struct scsi_serviceactionin_params { enum scsi_service_action_in sa; }; struct scsi_sense { unsigned char error_type; enum scsi_sense_key key; int ascq; }; struct scsi_data { int size; unsigned char *data; }; struct scsi_allocated_memory { struct scsi_allocated_memory *next; void *ptr; }; enum scsi_residual { SCSI_RESIDUAL_NO_RESIDUAL = 0, SCSI_RESIDUAL_UNDERFLOW, SCSI_RESIDUAL_OVERFLOW }; struct scsi_task { int status; int cdb_size; int xfer_dir; int expxferlen; unsigned char cdb[SCSI_CDB_MAX_SIZE]; union { struct scsi_read6_params read6; struct scsi_read10_params read10; struct scsi_read12_params read12; struct scsi_read16_params read16; struct scsi_write10_params write10; struct scsi_write12_params write12; struct scsi_write16_params write16; struct scsi_verify10_params verify10; struct scsi_readcapacity10_params readcapacity10; struct scsi_reportluns_params reportluns; struct scsi_inquiry_params inquiry; struct scsi_modesense6_params modesense6; struct scsi_serviceactionin_params serviceactionin; } params; enum scsi_residual residual_status; int residual; struct scsi_sense sense; struct scsi_data datain; struct scsi_allocated_memory *mem; void *ptr; uint32_t itt; uint32_t cmdsn; uint32_t lun; struct scsi_data_buffer *in_buffers; }; EXTERN void scsi_free_scsi_task(struct scsi_task *task); EXTERN void scsi_set_task_private_ptr(struct scsi_task *task, void *ptr); EXTERN void *scsi_get_task_private_ptr(struct scsi_task *task); /* * TESTUNITREADY */ EXTERN struct scsi_task *scsi_cdb_testunitready(void); /* * REPORTLUNS */ #define SCSI_REPORTLUNS_REPORT_ALL_LUNS 0x00 #define SCSI_REPORTLUNS_REPORT_WELL_KNOWN_ONLY 0x01 #define SCSI_REPORTLUNS_REPORT_AVAILABLE_LUNS_ONLY 0x02 struct scsi_reportluns_list { uint32_t num; uint16_t luns[0]; }; EXTERN struct scsi_task *scsi_reportluns_cdb(int report_type, int alloc_len); /* * READCAPACITY10 */ struct scsi_readcapacity10 { uint32_t lba; uint32_t block_size; }; EXTERN struct scsi_task *scsi_cdb_readcapacity10(int lba, int pmi); /* * INQUIRY */ enum scsi_inquiry_peripheral_qualifier { SCSI_INQUIRY_PERIPHERAL_QUALIFIER_CONNECTED = 0x00, SCSI_INQUIRY_PERIPHERAL_QUALIFIER_DISCONNECTED = 0x01, SCSI_INQUIRY_PERIPHERAL_QUALIFIER_NOT_SUPPORTED = 0x03 }; const char *scsi_devqualifier_to_str( enum scsi_inquiry_peripheral_qualifier qualifier); enum scsi_inquiry_peripheral_device_type { SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS = 0x00, SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_SEQUENTIAL_ACCESS = 0x01, SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_PRINTER = 0x02, SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_PROCESSOR = 0x03, SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_WRITE_ONCE = 0x04, SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_MMC = 0x05, SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_SCANNER = 0x06, SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_OPTICAL_MEMORY = 0x07, SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_MEDIA_CHANGER = 0x08, SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_COMMUNICATIONS = 0x09, SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_STORAGE_ARRAY_CONTROLLER = 0x0c, SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_ENCLOSURE_SERVICES = 0x0d, SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_SIMPLIFIED_DIRECT_ACCESS = 0x0e, SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_OPTICAL_CARD_READER = 0x0f, SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_BRIDGE_CONTROLLER = 0x10, SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_OSD = 0x11, SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_AUTOMATION = 0x12, SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_SEQURITY_MANAGER = 0x13, SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_WELL_KNOWN_LUN = 0x1e, SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_UNKNOWN = 0x1f }; EXTERN const char *scsi_devtype_to_str(enum scsi_inquiry_peripheral_device_type type); enum scsi_version { SCSI_VERSION_SPC = 0x03, SCSI_VERSION_SPC2 = 0x04, SCSI_VERSION_SPC3 = 0x05 }; EXTERN const char *scsi_version_to_str(enum scsi_version version); enum scsi_inquiry_tpgs { SCSI_INQUIRY_TPGS_NO_SUPPORT = 0x00, SCSI_INQUIRY_TPGS_IMPLICIT = 0x01, SCSI_INQUIRY_TPGS_EXPLICIT = 0x02, SCSI_INQUIRY_TPGS_IMPLICIT_AND_EXPLICIT = 0x03 }; struct scsi_inquiry_standard { enum scsi_inquiry_peripheral_qualifier periperal_qualifier; enum scsi_inquiry_peripheral_device_type periperal_device_type; int rmb; int version; int normaca; int hisup; int response_data_format; int sccs; int acc; int tpgs; int threepc; int protect; int encserv; int multip; int addr16; int wbus16; int sync; int cmdque; int clocking; int qas; int ius; char vendor_identification[8+1]; char product_identification[16+1]; char product_revision_level[4+1]; }; enum scsi_inquiry_pagecode { SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES = 0x00, SCSI_INQUIRY_PAGECODE_UNIT_SERIAL_NUMBER = 0x80, SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION = 0x83, SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS = 0xB0, SCSI_INQUIRY_PAGECODE_BLOCK_DEVICE_CHARACTERISTICS = 0xB1, SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING = 0xB2 }; EXTERN const char *scsi_inquiry_pagecode_to_str(int pagecode); struct scsi_inquiry_supported_pages { enum scsi_inquiry_peripheral_qualifier periperal_qualifier; enum scsi_inquiry_peripheral_device_type periperal_device_type; enum scsi_inquiry_pagecode pagecode; int num_pages; unsigned char *pages; }; struct scsi_inquiry_block_limits { enum scsi_inquiry_peripheral_qualifier periperal_qualifier; enum scsi_inquiry_peripheral_device_type periperal_device_type; enum scsi_inquiry_pagecode pagecode; int wsnz; /* write same no zero */ uint8_t max_cmp; /* maximum_compare_and_write_length */ uint16_t opt_gran; /* optimal_transfer_length_granularity */ uint32_t max_xfer_len; /* maximum_transfer_length */ uint32_t opt_xfer_len; /* optimal_transfer_length */ uint32_t max_prefetch; /* maximum_prefetched_xdread_xdwrite_transfer_length */ uint32_t max_unmap; /* maximum_unmap_lba_count */ uint32_t max_unmap_bdc; /* maximum_unmap_block_descriptor_count */ uint32_t opt_unmap_gran; /* optimal_unmap_granularity */ int ugavalid; uint32_t unmap_gran_align; /* unmap_granularity_alignment */ uint64_t max_ws_len; /* maximum_write_same_length */ }; struct scsi_inquiry_block_device_characteristics { enum scsi_inquiry_peripheral_qualifier periperal_qualifier; enum scsi_inquiry_peripheral_device_type periperal_device_type; enum scsi_inquiry_pagecode pagecode; int medium_rotation_rate; }; enum scsi_inquiry_provisioning_type { PROVISIONING_TYPE_NONE = 0, PROVISIONING_TYPE_RESOURCE = 1, PROVISIONING_TYPE_THIN = 2 }; struct scsi_inquiry_logical_block_provisioning { enum scsi_inquiry_peripheral_qualifier periperal_qualifier; enum scsi_inquiry_peripheral_device_type periperal_device_type; enum scsi_inquiry_pagecode pagecode; int threshold_exponent; int lbpu; int lbpws; int lbpws10; int lbprz; int anc_sup; int dp; enum scsi_inquiry_provisioning_type provisioning_type; }; EXTERN struct scsi_task *scsi_cdb_inquiry(int evpd, int page_code, int alloc_len); struct scsi_inquiry_unit_serial_number { enum scsi_inquiry_peripheral_qualifier periperal_qualifier; enum scsi_inquiry_peripheral_device_type periperal_device_type; enum scsi_inquiry_pagecode pagecode; char *usn; }; enum scsi_protocol_identifier { SCSI_PROTOCOL_IDENTIFIER_FIBRE_CHANNEL = 0x00, SCSI_PROTOCOL_IDENTIFIER_PARALLEL_SCSI = 0x01, SCSI_PROTOCOL_IDENTIFIER_SSA = 0x02, SCSI_PROTOCOL_IDENTIFIER_IEEE_1394 = 0x03, SCSI_PROTOCOL_IDENTIFIER_RDMA = 0x04, SCSI_PROTOCOL_IDENTIFIER_ISCSI = 0x05, SCSI_PROTOCOL_IDENTIFIER_SAS = 0x06, SCSI_PROTOCOL_IDENTIFIER_ADT = 0x07, SCSI_PROTOCOL_IDENTIFIER_ATA = 0x08 }; EXTERN const char *scsi_protocol_identifier_to_str(int identifier); enum scsi_codeset { SCSI_CODESET_BINARY = 0x01, SCSI_CODESET_ASCII = 0x02, SCSI_CODESET_UTF8 = 0x03 }; EXTERN const char *scsi_codeset_to_str(int codeset); enum scsi_association { SCSI_ASSOCIATION_LOGICAL_UNIT = 0x00, SCSI_ASSOCIATION_TARGET_PORT = 0x01, SCSI_ASSOCIATION_TARGET_DEVICE = 0x02 }; EXTERN const char *scsi_association_to_str(int association); enum scsi_designator_type { SCSI_DESIGNATOR_TYPE_VENDOR_SPECIFIC = 0x00, SCSI_DESIGNATOR_TYPE_T10_VENDORT_ID = 0x01, SCSI_DESIGNATOR_TYPE_EUI_64 = 0x02, SCSI_DESIGNATOR_TYPE_NAA = 0x03, SCSI_DESIGNATOR_TYPE_RELATIVE_TARGET_PORT = 0x04, SCSI_DESIGNATOR_TYPE_TARGET_PORT_GROUP = 0x05, SCSI_DESIGNATOR_TYPE_LOGICAL_UNIT_GROUP = 0x06, SCSI_DESIGNATOR_TYPE_MD5_LOGICAL_UNIT_IDENTIFIER = 0x07, SCSI_DESIGNATOR_TYPE_SCSI_NAME_STRING = 0x08 }; EXTERN const char *scsi_designator_type_to_str(int association); struct scsi_inquiry_device_designator { struct scsi_inquiry_device_designator *next; enum scsi_protocol_identifier protocol_identifier; enum scsi_codeset code_set; int piv; enum scsi_association association; enum scsi_designator_type designator_type; int designator_length; char *designator; }; struct scsi_inquiry_device_identification { enum scsi_inquiry_peripheral_qualifier periperal_qualifier; enum scsi_inquiry_peripheral_device_type periperal_device_type; enum scsi_inquiry_pagecode pagecode; struct scsi_inquiry_device_designator *designators; }; /* * MODESENSE6 */ enum scsi_modesense_page_control { SCSI_MODESENSE_PC_CURRENT = 0x00, SCSI_MODESENSE_PC_CHANGEABLE = 0x01, SCSI_MODESENSE_PC_DEFAULT = 0x02, SCSI_MODESENSE_PC_SAVED = 0x03 }; struct scsi_mode_page_caching { int ic; int abpf; int cap; int disc; int size; int wce; int mf; int rcd; int demand_read_retention_priority; int write_retention_priority; int disable_prefetch_transfer_length; int minimum_prefetch; int maximum_prefetch; int maximum_prefetch_ceiling; int fsw; int lbcss; int dra; int nv_dis; int number_of_cache_segments; int cache_segment_size; }; struct scsi_mode_page_disconnect_reconnect { int buffer_full_ratio; int buffer_empty_ratio; int bus_inactivity_limit; int disconnect_time_limit; int connect_time_limit; int maximum_burst_size; int emdp; int fair_arbitration; int dimm; int dtdc; int first_burst_size; }; struct scsi_mode_page_informational_exceptions_control { int perf; int ebf; int ewasc; int dexcpt; int test; int ebackerr; int logerr; int mrie; int interval_timer; int report_count; }; enum scsi_modesense_page_code { SCSI_MODESENSE_PAGECODE_READ_WRITE_ERROR_RECOVERY = 0x01, SCSI_MODESENSE_PAGECODE_DISCONNECT_RECONNECT = 0x02, SCSI_MODESENSE_PAGECODE_VERIFY_ERROR_RECOVERY = 0x07, SCSI_MODESENSE_PAGECODE_CACHING = 0x08, SCSI_MODESENSE_PAGECODE_XOR_CONTROL = 0x10, SCSI_MODESENSE_PAGECODE_INFORMATIONAL_EXCEPTIONS_CONTROL = 0x1c, SCSI_MODESENSE_PAGECODE_RETURN_ALL_PAGES = 0x3f }; struct scsi_mode_page { struct scsi_mode_page *next; int ps; int spf; enum scsi_modesense_page_code page_code; int subpage_code; int len; union { struct scsi_mode_page_caching caching; struct scsi_mode_page_disconnect_reconnect disconnect_reconnect; struct scsi_mode_page_informational_exceptions_control iec; }; }; struct scsi_mode_sense { uint8_t mode_data_length; uint8_t medium_type; uint8_t device_specific_parameter; uint8_t block_descriptor_length; struct scsi_mode_page *pages; }; EXTERN struct scsi_task *scsi_cdb_modesense6(int dbd, enum scsi_modesense_page_control pc, enum scsi_modesense_page_code page_code, int sub_page_code, unsigned char alloc_len); struct scsi_readcapacity16 { uint64_t returned_lba; uint32_t block_length; uint8_t p_type; uint8_t prot_en; uint8_t p_i_exp; uint8_t lbppbe; uint8_t lbpme; uint8_t lbprz; uint16_t lalba; }; EXTERN int scsi_datain_getfullsize(struct scsi_task *task); EXTERN void *scsi_datain_unmarshall(struct scsi_task *task); EXTERN struct scsi_task *scsi_cdb_read6(uint32_t lba, uint32_t xferlen, int blocksize); EXTERN struct scsi_task *scsi_cdb_read10(uint32_t lba, uint32_t xferlen, int blocksize); EXTERN struct scsi_task *scsi_cdb_read12(uint32_t lba, uint32_t xferlen, int blocksize, int rdprotect, int dpo, int fua, int fua_nv, int group_number); EXTERN struct scsi_task *scsi_cdb_read16(uint64_t lba, uint32_t xferlen, int blocksize, int rdprotect, int dpo, int fua, int fua_nv, int group_number); EXTERN struct scsi_task *scsi_cdb_write10(uint32_t lba, uint32_t xferlen, int fua, int fuanv, int blocksize); EXTERN struct scsi_task *scsi_cdb_write12(uint32_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number); EXTERN struct scsi_task *scsi_cdb_write16(uint64_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number); EXTERN struct scsi_task *scsi_cdb_verify10(uint32_t lba, uint32_t xferlen, int vprotect, int dpo, int bytchk, int blocksize); EXTERN struct scsi_task *scsi_cdb_synchronizecache10(int lba, int num_blocks, int syncnv, int immed); EXTERN struct scsi_task *scsi_cdb_serviceactionin16(enum scsi_service_action_in sa, uint32_t xferlen); EXTERN struct scsi_task *scsi_cdb_readcapacity16(void); EXTERN struct scsi_task *scsi_cdb_unmap(int anchor, int group, uint16_t xferlen); EXTERN struct scsi_task *scsi_cdb_writesame10(int wrprotect, int anchor, int unmap, int pbdata, int lbdata, uint32_t lba, int group, uint16_t num_blocks); EXTERN struct scsi_task *scsi_cdb_writesame16(int wrprotect, int anchor, int unmap, int pbdata, int lbdata, uint64_t lba, int group, uint32_t num_blocks); EXTERN struct scsi_task *scsi_cdb_prefetch10(uint32_t lba, int num_blocks, int immed, int group); EXTERN struct scsi_task *scsi_cdb_prefetch16(uint64_t lba, int num_blocks, int immed, int group); void *scsi_malloc(struct scsi_task *task, size_t size); #endif /* __scsi_lowlevel_h__ */ libiscsi-1.4.0/include/iscsi.h0000644000175000017500000006726211750443164014413 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program 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 program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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, see . */ #ifndef __iscsi_h__ #define __iscsi_h__ #include #if defined(WIN32) #define EXTERN __declspec( dllexport ) EXTERN int poll(struct pollfd *fds, int nfsd, int timeout); #else #define EXTERN #endif struct iscsi_context; struct sockaddr; /* * Syntax for normal and portal/discovery URLs. */ #define ISCSI_URL_SYNTAX "\"iscsi://[[%]@]" \ "[:]//\"" #define ISCSI_PORTAL_URL_SYNTAX "\"iscsi://[[%]@]" \ "[:]\"" /* * The following three functions are used to integrate libiscsi in an event * system. */ /* * Returns the file descriptor that libiscsi uses. */ EXTERN int iscsi_get_fd(struct iscsi_context *iscsi); /* * Returns which events that we need to poll for for the iscsi file descriptor. */ EXTERN int iscsi_which_events(struct iscsi_context *iscsi); /* * Called to process the events when events become available for the iscsi * file descriptor. */ EXTERN int iscsi_service(struct iscsi_context *iscsi, int revents); /* * How many commands are in flight. */ EXTERN int iscsi_queue_length(struct iscsi_context *iscsi); /* * To set tcp keepalive for the session * ONLY available on platforms with tcp keepalive socket options */ int iscsi_set_tcp_keepalive(struct iscsi_context *iscsi, int idle, int count, int interval); struct iscsi_url { const char *portal; const char *target; const char *user; const char *passwd; int lun; }; /* * This function is used to parse an iSCSI URL into a iscsi_url structure. * iSCSI URL format : * iscsi://[[%]@][:]// * * Function will return a pointer to an iscsi url structure if successful, * or it will return NULL and set iscsi_get_error() accrodingly if there was a problem * with the URL. * * CHAP username/password can also be provided via environment variables * LIBISCSI_CHAP_USERNAME=ronnie * LIBISCSI_CHAP_PASSWORD=password * * The returned structure is freed by calling iscsi_destroy_url() */ EXTERN struct iscsi_url *iscsi_parse_full_url(struct iscsi_context *iscsi, const char *url); EXTERN void iscsi_destroy_url(struct iscsi_url *iscsi_url); /* * This function is used to parse an iSCSI Portal URL into a iscsi_url structure. * iSCSI Portal URL format : * iscsi://[[%]@][:] * * iSCSI Portal URL is used when describing a discovery session, where the target-iqn and the * lun is not yet known. * * Function will return a pointer to an iscsi url structure if successful, * or it will return NULL and set iscsi_get_error() accrodingly if there was a problem * with the URL. * * CHAP username/password can also be provided via environment variables * LIBISCSI_CHAP_USERNAME=ronnie * LIBISCSI_CHAP_PASSWORD=password * * The returned structure is freed by calling iscsi_destroy_url() */ EXTERN struct iscsi_url * iscsi_parse_portal_url(struct iscsi_context *iscsi, const char *url); /* * This function returns a description of the last encountered error. */ EXTERN const char *iscsi_get_error(struct iscsi_context *iscsi); /* * Create a context for an ISCSI session. * Initiator_name is the iqn name we want to identify to the target as. * * Returns: * 0: success * <0: error */ EXTERN struct iscsi_context *iscsi_create_context(const char *initiator_name); /* * Destroy an existing ISCSI context and tear down any existing connection. * Callbacks for any command in flight will be invoked with * ISCSI_STATUS_CANCELLED. * * Returns: * 0: success * <0: error */ EXTERN int iscsi_destroy_context(struct iscsi_context *iscsi); /* * Set an optional alias name to identify with when connecting to the target * * Returns: * 0: success * <0: error */ EXTERN int iscsi_set_alias(struct iscsi_context *iscsi, const char *alias); /* * Set the iqn name of the taqget to login to. * The target name must be set before a normal-login can be initiated. * Only discovery-logins are possible without setting the target iqn name. * * Returns: * 0: success * <0: error */ EXTERN int iscsi_set_targetname(struct iscsi_context *iscsi, const char *targetname); /* * This function returns any target address supplied in a login response when * the target has moved. */ EXTERN const char *iscsi_get_target_address(struct iscsi_context *iscsi); /* Type of iscsi sessions. Discovery sessions are used to query for what * targets exist behind the portal connected to. Normal sessions are used to * log in and do I/O to the SCSI LUNs */ enum iscsi_session_type { ISCSI_SESSION_DISCOVERY = 1, ISCSI_SESSION_NORMAL = 2 }; /* * Set the session type for a scsi context. * Session type can only be set/changed before the context * is logged in to the target. * * Returns: * 0: success * <0: error */ EXTERN int iscsi_set_session_type(struct iscsi_context *iscsi, enum iscsi_session_type session_type); /* * Types of header digest we support. Default is NONE */ enum iscsi_header_digest { ISCSI_HEADER_DIGEST_NONE = 0, ISCSI_HEADER_DIGEST_NONE_CRC32C = 1, ISCSI_HEADER_DIGEST_CRC32C_NONE = 2, ISCSI_HEADER_DIGEST_CRC32C = 3, ISCSI_HEADER_DIGEST_LAST = ISCSI_HEADER_DIGEST_CRC32C }; /* * Set the desired header digest for a scsi context. * Header digest can only be set/changed before the context * is logged in to the target. * * Returns: * 0: success * <0: error */ EXTERN int iscsi_set_header_digest(struct iscsi_context *iscsi, enum iscsi_header_digest header_digest); /* * Specify the username and password to use for chap authentication */ EXTERN int iscsi_set_initiator_username_pwd(struct iscsi_context *iscsi, const char *user, const char *passwd); /* * check if the context is logged in or not */ EXTERN int iscsi_is_logged_in(struct iscsi_context *iscsi); enum scsi_status { SCSI_STATUS_GOOD = 0, SCSI_STATUS_CHECK_CONDITION = 2, SCSI_STATUS_RESERVATION_CONFLICT = 0x18, SCSI_STATUS_CANCELLED = 0x0f000000, SCSI_STATUS_ERROR = 0x0f000001 }; /* * Generic callback for completion of iscsi_*_async(). * command_data depends on status. */ typedef void (*iscsi_command_cb)(struct iscsi_context *iscsi, int status, void *command_data, void *private_data); /* * Asynchronous call to connect a TCP connection to the target-host/port * * Returns: * 0 if the call was initiated and a connection will be attempted. Result of * the connection will be reported through the callback function. * <0 if there was an error. The callback function will not be invoked. * * This command is unique in that the callback can be invoked twice. * * Callback parameters : * status can be either of : * ISCSI_STATUS_GOOD : Connection was successful. Command_data is NULL. * In this case the callback will be invoked a * second time once the connection is torn down. * * ISCSI_STATUS_ERROR : Either failed to establish the connection, or * an already established connection has failed * with an error. * * The callback will NOT be invoked if the session is explicitely torn down * through a call to iscsi_disconnect() or iscsi_destroy_context(). */ EXTERN int iscsi_connect_async(struct iscsi_context *iscsi, const char *portal, iscsi_command_cb cb, void *private_data); /* * Synchronous call to connect a TCP connection to the target-host/port * * Returns: * 0 if connected successfully. * <0 if there was an error. * */ EXTERN int iscsi_connect_sync(struct iscsi_context *iscsi, const char *portal); /* * Asynchronous call to connect a lun * This function will connect to the portal, login, and verify that the lun * is available. * * Returns: * 0 if the call was initiated and a connection will be attempted. Result * of the connection will be reported through the callback function. * <0 if there was an error. The callback function will not be invoked. * * This command is unique in that the callback can be invoked twice. * * Callback parameters : * status can be either of : * ISCSI_STATUS_GOOD : Connection was successful. Command_data is NULL. * In this case the callback will be invoked a * second time once the connection is torn down. * * ISCSI_STATUS_ERROR : Either failed to establish the connection, or * an already established connection has failed * with an error. * * The callback will NOT be invoked if the session is explicitely torn down * through a call to iscsi_disconnect() or iscsi_destroy_context(). */ EXTERN int iscsi_full_connect_async(struct iscsi_context *iscsi, const char *portal, int lun, iscsi_command_cb cb, void *private_data); /* * Synchronous call to connect a lun * This function will connect to the portal, login, and verify that the lun * is available. * * Returns: * 0 if the cconnect was successful. * <0 if there was an error. */ EXTERN int iscsi_full_connect_sync(struct iscsi_context *iscsi, const char *portal, int lun); /* * Disconnect a connection to a target. * You can not disconnect while being logged in to a target. * * Returns: * 0 disconnect was successful * <0 error */ EXTERN int iscsi_disconnect(struct iscsi_context *iscsi); /* * Asynchronous call to perform an ISCSI login. * * Returns: * 0 if the call was initiated and a login will be attempted. Result of the * login will be reported through the callback function. * <0 if there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * ISCSI_STATUS_GOOD : login was successful. Command_data is always * NULL. * ISCSI_STATUS_CANCELLED: login was aborted. Command_data is NULL. * ISCSI_STATUS_ERROR : login failed. Command_data is NULL. */ EXTERN int iscsi_login_async(struct iscsi_context *iscsi, iscsi_command_cb cb, void *private_data); /* * Synchronous call to perform an ISCSI login. * * Returns: * 0 if the login was successful * <0 if there was an error. */ EXTERN int iscsi_login_sync(struct iscsi_context *iscsi); /* * Asynchronous call to perform an ISCSI logout. * * Returns: * 0 if the call was initiated and a logout will be attempted. Result of the * logout will be reported through the callback function. * <0 if there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * ISCSI_STATUS_GOOD : logout was successful. Command_data is always * NULL. * ISCSI_STATUS_CANCELLED: logout was aborted. Command_data is NULL. */ EXTERN int iscsi_logout_async(struct iscsi_context *iscsi, iscsi_command_cb cb, void *private_data); /* * Synchronous call to perform an ISCSI logout. * * Returns: * 0 if the logout was successful * <0 if there was an error. */ EXTERN int iscsi_logout_sync(struct iscsi_context *iscsi); /* * Asynchronous call to perform an ISCSI discovery. * * discoveries can only be done on connected and logged in discovery sessions. * * Returns: * 0 if the call was initiated and a discovery will be attempted. Result * of the logout will be reported through the callback function. * <0 if there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * ISCSI_STATUS_GOOD : Discovery was successful. Command_data is a * pointer to a iscsi_discovery_address list of * structures. * This list of structures is only valid for the * duration of the callback and all data will be * freed once the callback returns. * ISCSI_STATUS_CANCELLED: Discovery was aborted. Command_data is NULL. */ EXTERN int iscsi_discovery_async(struct iscsi_context *iscsi, iscsi_command_cb cb, void *private_data); struct iscsi_discovery_address { struct iscsi_discovery_address *next; const char *target_name; const char *target_address; }; /* * Asynchronous call to perform an ISCSI NOP-OUT call * * Returns: * 0 if the call was initiated and a nop-out will be attempted. Result will * be reported through the callback function. * <0 if there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * ISCSI_STATUS_GOOD : NOP-OUT was successful and the server responded * with a NOP-IN callback_data is a iscsi_data * structure containing the data returned from * the server. * ISCSI_STATUS_CANCELLED: Discovery was aborted. Command_data is NULL. */ EXTERN int iscsi_nop_out_async(struct iscsi_context *iscsi, iscsi_command_cb cb, unsigned char *data, int len, void *private_data); struct scsi_task; enum iscsi_task_mgmt_funcs { ISCSI_TM_ABORT_TASK = 0x01, ISCSI_TM_ABORT_TASK_SET = 0x02, ISCSI_TM_CLEAR_ACA = 0x03, ISCSI_TM_CLEAR_TASK_SET = 0x04, ISCSI_TM_LUN_RESET = 0x05, ISCSI_TM_TARGET_WARM_RESET = 0x06, ISCSI_TM_TARGET_COLD_RESET = 0x07, ISCSI_TM_TASK_REASSIGN = 0x08 }; /* * Asynchronous call for task management * * Returns: * 0 if the call was initiated and the task mgmt function will be invoked. * the connection will be reported through the callback function. * <0 if there was an error. The callback function will not be invoked. * * Callback parameters : * status can be either of : * ISCSI_STATUS_GOOD : Connection was successful. Command_data is a pointer to uint32_t * containing the response code as per RFC3720/10.6.1 * * ISCSI_STATUS_ERROR : Error. * * The callback will NOT be invoked if the session is explicitely torn down * through a call to iscsi_disconnect() or iscsi_destroy_context(). * * abort_task will also cancel the scsi task. The callback for the scsi task will be invoked with * SCSI_STATUS_CANCELLED * abort_task_set, lun_reset, target_warn_reset, target_cold_reset will cancel all tasks. The callback for * all tasks will be invoked with SCSI_STATUS_CANCELLED */ EXTERN int iscsi_task_mgmt_async(struct iscsi_context *iscsi, int lun, enum iscsi_task_mgmt_funcs function, uint32_t ritt, uint32_t rcmdscn, iscsi_command_cb cb, void *private_data); EXTERN int iscsi_task_mgmt_abort_task_async(struct iscsi_context *iscsi, struct scsi_task *task, iscsi_command_cb cb, void *private_data); EXTERN int iscsi_task_mgmt_abort_task_set_async(struct iscsi_context *iscsi, uint32_t lun, iscsi_command_cb cb, void *private_data); EXTERN int iscsi_task_mgmt_lun_reset_async(struct iscsi_context *iscsi, uint32_t lun, iscsi_command_cb cb, void *private_data); EXTERN int iscsi_task_mgmt_target_warm_reset_async(struct iscsi_context *iscsi, iscsi_command_cb cb, void *private_data); EXTERN int iscsi_task_mgmt_target_cold_reset_async(struct iscsi_context *iscsi, iscsi_command_cb cb, void *private_data); /* These are the possible status values for the callbacks for scsi commands. * The content of command_data depends on the status type. * * status : * ISCSI_STATUS_GOOD the scsi command completed successfullt on the target. * If this scsi command returns DATA-IN, that data is stored in an scsi_task * structure returned in the command_data parameter. This buffer will be * automatically freed once the callback returns. * * ISCSI_STATUS_CHECK_CONDITION the scsi command failed with a scsi sense. * Command_data contains a struct scsi_task. When the callback returns, * this buffer will automatically become freed. * * ISCSI_STATUS_CANCELLED the scsi command was aborted. Command_data is * NULL. * * ISCSI_STATUS_ERROR the command failed. Command_data is NULL. */ struct iscsi_data { int size; unsigned char *data; }; /* * These functions will set the ISID type and value. * By default, contexts will automatically be assigned a 'random' * type and value on creation, but this can be overridden * by an appplication using these functions. * * Setting the ISID can only be done before loggin in to the target. */ EXTERN int iscsi_set_isid_oui(struct iscsi_context *iscsi, uint32_t oui, uint32_t qualifier); EXTERN int iscsi_set_isid_en(struct iscsi_context *iscsi, uint32_t en, uint32_t qualifier); EXTERN int iscsi_set_isid_random(struct iscsi_context *iscsi, uint32_t rnd, uint32_t qualifier); EXTERN int iscsi_set_isid_reserved(struct iscsi_context *iscsi); /* * The scsi commands use/return a scsi_task structure when invoked * and also through the callback. * * You must release this structure when you are finished with the task * by calling scsi_free_scsi_task(). * Most of the time this means you should call this function before returning * from the callback. */ EXTERN int iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun, struct scsi_task *task, iscsi_command_cb cb, struct iscsi_data *data, void *private_data); /* * Async commands for SCSI * * These async functions return a scsi_task structure, or NULL if the command failed. * This structure can be used by task management functions to abort the task or a whole task set. */ EXTERN struct scsi_task * iscsi_reportluns_task(struct iscsi_context *iscsi, int report_type, int alloc_len, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * iscsi_testunitready_task(struct iscsi_context *iscsi, int lun, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * iscsi_inquiry_task(struct iscsi_context *iscsi, int lun, int evpd, int page_code, int maxsize, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * iscsi_readcapacity10_task(struct iscsi_context *iscsi, int lun, int lba, int pmi, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * iscsi_readcapacity16_task(struct iscsi_context *iscsi, int lun, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * iscsi_synchronizecache10_task(struct iscsi_context *iscsi, int lun, int lba, int num_blocks, int syncnv, int immed, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * iscsi_prefetch10_task(struct iscsi_context *iscsi, int lun, uint32_t lba, int num_blocks, int immed, int group, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * iscsi_prefetch16_task(struct iscsi_context *iscsi, int lun, uint64_t lba, int num_blocks, int immed, int group, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * iscsi_read6_task(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * iscsi_read10_task(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * iscsi_write10_task(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int fua, int fua_nv, int blocksize, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * iscsi_read12_task(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, int rdprotect, int dpo, int fua, int fua_nv, int group_number, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * iscsi_write12_task(struct iscsi_context *iscsi, int lun, uint32_t lba, unsigned char *data, uint32_t datalen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * iscsi_read16_task(struct iscsi_context *iscsi, int lun, uint64_t lba, uint32_t datalen, int blocksize, int rdprotect, int dpo, int fua, int fua_nv, int group_number, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * iscsi_write16_task(struct iscsi_context *iscsi, int lun, uint64_t lba, unsigned char *data, uint32_t datalen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * iscsi_verify10_task(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * iscsi_writesame10_task(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, uint16_t num_blocks, int anchor, int unmap, int pbdata, int lbdata, int wrprotect, int group, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * iscsi_writesame16_task(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint64_t lba, uint32_t num_blocks, int anchor, int unmap, int pbdata, int lbdata, int wrprotect, int group, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * iscsi_modesense6_task(struct iscsi_context *iscsi, int lun, int dbd, int pc, int page_code, int sub_page_code, unsigned char alloc_len, iscsi_command_cb cb, void *private_data); struct unmap_list { uint64_t lba; uint32_t num; }; EXTERN struct scsi_task * iscsi_unmap_task(struct iscsi_context *iscsi, int lun, int anchor, int group, struct unmap_list *list, int list_len, iscsi_command_cb cb, void *private_data); /* * Sync commands for SCSI */ EXTERN struct scsi_task * iscsi_scsi_command_sync(struct iscsi_context *iscsi, int lun, struct scsi_task *task, struct iscsi_data *data); EXTERN struct scsi_task * iscsi_reportluns_sync(struct iscsi_context *iscsi, int report_type, int alloc_len); EXTERN struct scsi_task * iscsi_testunitready_sync(struct iscsi_context *iscsi, int lun); EXTERN struct scsi_task * iscsi_inquiry_sync(struct iscsi_context *iscsi, int lun, int evpd, int page_code, int maxsize); EXTERN struct scsi_task * iscsi_read6_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize); EXTERN struct scsi_task * iscsi_read10_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize); EXTERN struct scsi_task * iscsi_write10_sync(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int fua, int fua_nv, int blocksize); EXTERN struct scsi_task * iscsi_read12_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, int rdprotect, int dpo, int fua, int fua_nv, int group_number); EXTERN struct scsi_task * iscsi_write12_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, unsigned char *data, uint32_t datalen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number); EXTERN struct scsi_task * iscsi_read16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba, uint32_t datalen, int blocksize, int rdprotect, int dpo, int fua, int fua_nv, int group_number); EXTERN struct scsi_task * iscsi_write16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba, unsigned char *data, uint32_t datalen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number); EXTERN struct scsi_task * iscsi_readcapacity10_sync(struct iscsi_context *iscsi, int lun, int lba, int pmi); EXTERN struct scsi_task * iscsi_readcapacity16_sync(struct iscsi_context *iscsi, int lun); EXTERN struct scsi_task * iscsi_synchronizecache10_sync(struct iscsi_context *iscsi, int lun, int lba, int num_blocks, int syncnv, int immed); EXTERN struct scsi_task * iscsi_prefetch10_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, int num_blocks, int immed, int group); EXTERN struct scsi_task * iscsi_prefetch16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba, int num_blocks, int immed, int group); EXTERN struct scsi_task * iscsi_verify10_sync(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize); EXTERN struct scsi_task * iscsi_writesame10_sync(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, uint16_t num_blocks, int anchor, int unmap, int pbdata, int lbdata, int wrprotect, int group); EXTERN struct scsi_task * iscsi_writesame16_sync(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint64_t lba, uint32_t num_blocks, int anchor, int unmap, int pbdata, int lbdata, int wrprotect, int group); EXTERN struct scsi_task * iscsi_unmap_sync(struct iscsi_context *iscsi, int lun, int anchor, int group, struct unmap_list *list, int list_len); /* * This function is used when the application wants to specify its own buffers to read the data * from the DATA-IN PDUs into. * The main use is for SCSI read operations to have them write directly into the application buffers to * avoid the two copies that would occur otherwise. * First copy from the individual DATA-IN blobs to linearize the buffer and the second in the callback * to copy the data from the linearized buffer into the application buffer. * * This also supports reading into a vector of buffers by calling this function multiple times. * The individual buffers will be filled in the same order as they were created. * * Example: * task = iscsi_read10_task( ( 2 512byte blocks into two buffers) * scsi_task_add_data_in_buffer(task, first_buffer, 512 * scsi_task_add_data_in_buffer(task, second_buffer, 512 * * * If you use this function you can not use task->datain in the callback. * task->datain.size will be 0 and * task->datain.data will be NULL */ EXTERN int scsi_task_add_data_in_buffer(struct scsi_task *task, int len, unsigned char *buf); /* * This function is used when you want to cancel a scsi task. * The callback for the task will immediately be invoked with SCSI_STATUS_CANCELLED. * The cancellation is only local in libiscsi. If the task is already in-flight * this call will not cancel the task at the target. * To cancel the task also a the target you need to call the task management functions. */ EXTERN int iscsi_scsi_task_cancel(struct iscsi_context *iscsi, struct scsi_task *task); /* * This function is used when you want to cancel all scsi tasks. * The callback for the tasks will immediately be invoked with SCSI_STATUS_CANCELLED. * The cancellation is only local in libiscsi. If the tasks are already in-flight * this call will not cancel the tasks at the target. * To cancel the tasks also a the target you need to call the task management functions. */ EXTERN void iscsi_scsi_cancel_all_tasks(struct iscsi_context *iscsi); #endif /* __iscsi_h__ */ libiscsi-1.4.0/include/md5.h0000644000175000017500000000310711750443164013752 0ustar mjtmjt/* * This is the header file for the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD5Context structure, pass it to MD5Init, call MD5Update as * needed on buffers full of bytes, and then call MD5Final, which * will fill a supplied 16-byte array with the digest. * * Changed so as no longer to depend on Colin Plumb's `usual.h' * header definitions; now uses stuff from dpkg's config.h * - Ian Jackson . * Still in the public domain. */ #ifndef MD5_H #define MD5_H #if defined(WIN32) #else #include #endif #include #include #include #if (__BYTE_ORDER == __BIG_ENDIAN) # define WORDS_BIGENDIAN 1 #endif typedef uint32_t UWORD32; #ifdef __cplusplus extern "C" { #endif #define md5byte unsigned char struct MD5Context { UWORD32 buf[4]; UWORD32 bytes[2]; UWORD32 in[16]; }; void MD5Init(struct MD5Context *context); void MD5Update(struct MD5Context *context, md5byte const *buf, unsigned len); void MD5Final(unsigned char digest[16], struct MD5Context *context); void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]); #ifdef __cplusplus } #endif #endif /* !MD5_H */ libiscsi-1.4.0/include/iscsi-private.h0000644000175000017500000002177511750443164016062 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program 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 program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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, see . */ #ifndef __iscsi_private_h__ #define __iscsi_private_h__ #include #if defined(WIN32) #include #define ssize_t SSIZE_T #endif #ifndef discard_const #define discard_const(ptr) ((void *)((intptr_t)(ptr))) #endif #define ISCSI_RAW_HEADER_SIZE 48 #define ISCSI_DIGEST_SIZE 4 #define ISCSI_HEADER_SIZE (ISCSI_RAW_HEADER_SIZE \ + (iscsi->header_digest == ISCSI_HEADER_DIGEST_NONE?0:ISCSI_DIGEST_SIZE)) struct iscsi_in_pdu { struct iscsi_in_pdu *next; long long hdr_pos; unsigned char hdr[ISCSI_RAW_HEADER_SIZE + ISCSI_DIGEST_SIZE]; long long data_pos; unsigned char *data; }; void iscsi_free_iscsi_in_pdu(struct iscsi_in_pdu *in); void iscsi_free_iscsi_inqueue(struct iscsi_in_pdu *inqueue); enum iscsi_initial_r2t { ISCSI_INITIAL_R2T_NO = 0, ISCSI_INITIAL_R2T_YES = 1 }; enum iscsi_immediate_data { ISCSI_IMMEDIATE_DATA_NO = 0, ISCSI_IMMEDIATE_DATA_YES = 1 }; struct iscsi_context { const char *initiator_name; const char *target_name; const char *target_address; /* If a redirect */ const char *alias; const char *user; const char *passwd; enum iscsi_session_type session_type; unsigned char isid[6]; uint32_t itt; uint32_t cmdsn; uint32_t statsn; enum iscsi_header_digest want_header_digest; enum iscsi_header_digest header_digest; char *error_string; int fd; int is_connected; int current_phase; int next_phase; #define ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP 0 #define ISCSI_LOGIN_SECNEG_PHASE_SELECT_ALGORITHM 1 #define ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE 2 int secneg_phase; int login_attempts; int is_loggedin; int is_reconnecting; int chap_a; int chap_i; char *chap_c; iscsi_command_cb socket_status_cb; void *connect_data; struct iscsi_pdu *outqueue; struct iscsi_pdu *waitpdu; struct iscsi_in_pdu *incoming; struct iscsi_in_pdu *inqueue; uint32_t max_burst_length; uint32_t first_burst_length; uint32_t initiator_max_recv_data_segment_length; uint32_t target_max_recv_data_segment_length; enum iscsi_initial_r2t want_initial_r2t; enum iscsi_initial_r2t use_initial_r2t; enum iscsi_immediate_data want_immediate_data; enum iscsi_immediate_data use_immediate_data; int lun; const char *portal; }; #define ISCSI_PDU_IMMEDIATE 0x40 #define ISCSI_PDU_TEXT_FINAL 0x80 #define ISCSI_PDU_TEXT_CONTINUE 0x40 #define ISCSI_PDU_LOGIN_TRANSIT 0x80 #define ISCSI_PDU_LOGIN_CONTINUE 0x40 #define ISCSI_PDU_LOGIN_CSG_SECNEG 0x00 #define ISCSI_PDU_LOGIN_CSG_OPNEG 0x04 #define ISCSI_PDU_LOGIN_CSG_FF 0x0c #define ISCSI_PDU_LOGIN_NSG_SECNEG 0x00 #define ISCSI_PDU_LOGIN_NSG_OPNEG 0x01 #define ISCSI_PDU_LOGIN_NSG_FF 0x03 #define ISCSI_PDU_SCSI_FINAL 0x80 #define ISCSI_PDU_SCSI_READ 0x40 #define ISCSI_PDU_SCSI_WRITE 0x20 #define ISCSI_PDU_SCSI_ATTR_UNTAGGED 0x00 #define ISCSI_PDU_SCSI_ATTR_SIMPLE 0x01 #define ISCSI_PDU_SCSI_ATTR_ORDERED 0x02 #define ISCSI_PDU_SCSI_ATTR_HEADOFQUEUE 0x03 #define ISCSI_PDU_SCSI_ATTR_ACA 0x04 #define ISCSI_PDU_DATA_FINAL 0x80 #define ISCSI_PDU_DATA_ACK_REQUESTED 0x40 #define ISCSI_PDU_DATA_BIDIR_OVERFLOW 0x10 #define ISCSI_PDU_DATA_BIDIR_UNDERFLOW 0x08 #define ISCSI_PDU_DATA_RESIDUAL_OVERFLOW 0x04 #define ISCSI_PDU_DATA_RESIDUAL_UNDERFLOW 0x02 #define ISCSI_PDU_DATA_CONTAINS_STATUS 0x01 enum iscsi_opcode { ISCSI_PDU_NOP_OUT = 0x00, ISCSI_PDU_SCSI_REQUEST = 0x01, ISCSI_PDU_SCSI_TASK_MANAGEMENT_REQUEST = 0x02, ISCSI_PDU_LOGIN_REQUEST = 0x03, ISCSI_PDU_TEXT_REQUEST = 0x04, ISCSI_PDU_DATA_OUT = 0x05, ISCSI_PDU_LOGOUT_REQUEST = 0x06, ISCSI_PDU_NOP_IN = 0x20, ISCSI_PDU_SCSI_RESPONSE = 0x21, ISCSI_PDU_SCSI_TASK_MANAGEMENT_RESPONSE = 0x22, ISCSI_PDU_LOGIN_RESPONSE = 0x23, ISCSI_PDU_TEXT_RESPONSE = 0x24, ISCSI_PDU_DATA_IN = 0x25, ISCSI_PDU_LOGOUT_RESPONSE = 0x26, ISCSI_PDU_R2T = 0x31, ISCSI_PDU_REJECT = 0x3f, ISCSI_PDU_NO_PDU = 0xff }; struct iscsi_pdu { struct iscsi_pdu *next; /* There will not be a response to this pdu, so delete it once it is sent on the wire. Dont put it on the wait-queue */ #define ISCSI_PDU_DELETE_WHEN_SENT 0x00000001 /* Dont call the CANCEL callback when the context is destroyed */ #define ISCSI_PDU_NO_CALLBACK 0x00000002 uint32_t flags; uint32_t lun; uint32_t itt; uint32_t cmdsn; enum iscsi_opcode response_opcode; iscsi_command_cb callback; void *private_data; int written; struct iscsi_data outdata; /* Header and Immediate Data */ struct iscsi_data indata; struct iscsi_data nidata; /* Non-Immediate Data */ struct iscsi_scsi_cbdata *scsi_cbdata; }; void iscsi_free_scsi_cbdata(struct iscsi_scsi_cbdata *scsi_cbdata); struct iscsi_pdu *iscsi_allocate_pdu(struct iscsi_context *iscsi, enum iscsi_opcode opcode, enum iscsi_opcode response_opcode); struct iscsi_pdu *iscsi_allocate_pdu_with_itt_flags(struct iscsi_context *iscsi, enum iscsi_opcode opcode, enum iscsi_opcode response_opcode, uint32_t itt, uint32_t flags); void iscsi_free_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); void iscsi_pdu_set_pduflags(struct iscsi_pdu *pdu, unsigned char flags); void iscsi_pdu_set_immediate(struct iscsi_pdu *pdu); void iscsi_pdu_set_ttt(struct iscsi_pdu *pdu, uint32_t ttt); void iscsi_pdu_set_cmdsn(struct iscsi_pdu *pdu, uint32_t cmdsn); void iscsi_pdu_set_rcmdsn(struct iscsi_pdu *pdu, uint32_t rcmdsn); void iscsi_pdu_set_lun(struct iscsi_pdu *pdu, uint32_t lun); void iscsi_pdu_set_expstatsn(struct iscsi_pdu *pdu, uint32_t expstatsnsn); void iscsi_pdu_set_expxferlen(struct iscsi_pdu *pdu, uint32_t expxferlen); void iscsi_pdu_set_itt(struct iscsi_pdu *pdu, uint32_t itt); void iscsi_pdu_set_ritt(struct iscsi_pdu *pdu, uint32_t ritt); void iscsi_pdu_set_datasn(struct iscsi_pdu *pdu, uint32_t datasn); void iscsi_pdu_set_bufferoffset(struct iscsi_pdu *pdu, uint32_t bufferoffset); int iscsi_pdu_add_data(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, unsigned char *dptr, int dsize); int iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); int iscsi_add_data(struct iscsi_context *iscsi, struct iscsi_data *data, unsigned char *dptr, int dsize, int pdualignment); struct scsi_task; void iscsi_pdu_set_cdb(struct iscsi_pdu *pdu, struct scsi_task *task); int iscsi_get_pdu_data_size(const unsigned char *hdr); int iscsi_process_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in); int iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, struct iscsi_in_pdu *in); int iscsi_process_text_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, struct iscsi_in_pdu *in); int iscsi_process_logout_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, struct iscsi_in_pdu *in); int iscsi_process_scsi_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, struct iscsi_in_pdu *in); int iscsi_process_scsi_data_in(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, struct iscsi_in_pdu *in, int *is_finished); int iscsi_process_nop_out_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, struct iscsi_in_pdu *in); int iscsi_process_task_mgmt_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, struct iscsi_in_pdu *in); int iscsi_process_r2t(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, struct iscsi_in_pdu *in); int iscsi_process_reject(struct iscsi_context *iscsi, struct iscsi_in_pdu *in); int iscsi_send_target_nop_out(struct iscsi_context *iscsi, uint32_t ttt); void iscsi_set_error(struct iscsi_context *iscsi, const char *error_string, ...); unsigned char *iscsi_get_user_in_buffer(struct iscsi_context *iscsi, struct iscsi_in_pdu *in, uint32_t pos, ssize_t *count); unsigned char *scsi_task_get_data_in_buffer(struct scsi_task *task, uint32_t pos, ssize_t *count); unsigned long crc32c(char *buf, int len); struct scsi_task *iscsi_scsi_get_task_from_pdu(struct iscsi_pdu *pdu); int iscsi_reconnect(struct iscsi_context *iscsi); #endif /* __iscsi_private_h__ */ libiscsi-1.4.0/autogen.sh0000755000175000017500000000052611750443164013474 0ustar mjtmjt#!/bin/sh rm -rf autom4te.cache rm -f depcomp aclocal.m4 missing config.guess config.sub install-sh rm -f configure config.h.in config.h.in~ m4/libtool.m4 m4/lt*.m4 Makefile.in autoreconf -fvi (cd m4 && for i in libtool.m4 lt*.m4; do echo /$i done) > m4/.gitignore rm -rf autom4te.cache echo "Now run ./configure and then make." exit 0 libiscsi-1.4.0/src/0000755000175000017500000000000011750443164012257 5ustar mjtmjtlibiscsi-1.4.0/src/iscsi-ls.c0000644000175000017500000002504711750443164014161 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include #include #include #include #include #include "iscsi.h" #include "scsi-lowlevel.h" int showluns; const char *initiator = "iqn.2010-11.ronnie:iscsi-ls"; struct client_state { int finished; int status; int lun; int type; const char *username; const char *password; }; void event_loop(struct iscsi_context *iscsi, struct client_state *state) { struct pollfd pfd; while (state->finished == 0) { pfd.fd = iscsi_get_fd(iscsi); pfd.events = iscsi_which_events(iscsi); if (poll(&pfd, 1, -1) < 0) { fprintf(stderr, "Poll failed"); exit(10); } if (iscsi_service(iscsi, pfd.revents) < 0) { fprintf(stderr, "iscsi_service failed with : %s\n", iscsi_get_error(iscsi)); exit(10); } } } void show_lun(struct iscsi_context *iscsi, int lun) { struct scsi_task *task; struct scsi_inquiry_standard *inq; int type; long long size = 0; int size_pf = 0; static const char sf[] = {' ', 'k', 'M', 'G', 'T' }; /* check we can talk to the lun */ tur_try_again: if ((task = iscsi_testunitready_sync(iscsi, lun)) == NULL) { fprintf(stderr, "testunitready failed\n"); exit(10); } if (task->status == SCSI_STATUS_CHECK_CONDITION) { if (task->sense.key == SCSI_SENSE_UNIT_ATTENTION && task->sense.ascq == SCSI_SENSE_ASCQ_BUS_RESET) { scsi_free_scsi_task(task); goto tur_try_again; } } if (task->status != SCSI_STATUS_GOOD) { fprintf(stderr, "TESTUNITREADY failed with %s\n", iscsi_get_error(iscsi)); exit(10); } scsi_free_scsi_task(task); /* check what type of lun we have */ task = iscsi_inquiry_sync(iscsi, lun, 0, 0, 64); if (task == NULL || task->status != SCSI_STATUS_GOOD) { fprintf(stderr, "failed to send inquiry command : %s\n", iscsi_get_error(iscsi)); exit(10); } inq = scsi_datain_unmarshall(task); if (inq == NULL) { fprintf(stderr, "failed to unmarshall inquiry datain blob\n"); exit(10); } type = inq->periperal_device_type; scsi_free_scsi_task(task); if (type == SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS) { struct scsi_readcapacity10 *rc10; task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0); if (task == NULL || task->status != SCSI_STATUS_GOOD) { fprintf(stderr, "failed to send readcapacity command\n"); exit(10); } rc10 = scsi_datain_unmarshall(task); if (rc10 == NULL) { fprintf(stderr, "failed to unmarshall readcapacity10 data\n"); exit(10); } size = rc10->block_size; size *= rc10->lba; for (size_pf=0; size_pf<4 && size > 1024; size_pf++) { size /= 1024; } scsi_free_scsi_task(task); } printf("Lun:%-4d Type:%s", lun, scsi_devtype_to_str(type)); if (type == SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS) { printf(" (Size:%lld%c)", size, sf[size_pf]); } printf("\n"); } void list_luns(struct client_state *clnt, const char *target, const char *portal) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_reportluns_list *list; int full_report_size; int i; iscsi = iscsi_create_context(initiator); if (iscsi == NULL) { printf("Failed to create context\n"); exit(10); } if (clnt->username != NULL) { if (iscsi_set_initiator_username_pwd(iscsi, clnt->username, clnt->password) != 0) { fprintf(stderr, "Failed to set initiator username and password\n"); exit(10); } } if (iscsi_set_targetname(iscsi, target)) { fprintf(stderr, "Failed to set target name\n"); exit(10); } iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL); iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C); if (iscsi_connect_sync(iscsi, portal) != 0) { printf("iscsi_connect failed. %s\n", iscsi_get_error(iscsi)); exit(10); } if (iscsi_login_sync(iscsi) != 0) { fprintf(stderr, "login failed :%s\n", iscsi_get_error(iscsi)); exit(10); } /* get initial reportluns data, all targets can report 16 bytes but some * fail if we ask for too much. */ if ((task = iscsi_reportluns_sync(iscsi, 0, 16)) == NULL) { fprintf(stderr, "reportluns failed : %s\n", iscsi_get_error(iscsi)); exit(10); } full_report_size = scsi_datain_getfullsize(task); if (full_report_size > task->datain.size) { scsi_free_scsi_task(task); /* we need more data for the full list */ if ((task = iscsi_reportluns_sync(iscsi, 0, full_report_size)) == NULL) { fprintf(stderr, "reportluns failed : %s\n", iscsi_get_error(iscsi)); exit(10); } } list = scsi_datain_unmarshall(task); if (list == NULL) { fprintf(stderr, "failed to unmarshall reportluns datain blob\n"); exit(10); } for (i=0; i < (int)list->num; i++) { show_lun(iscsi, list->luns[i]); } scsi_free_scsi_task(task); iscsi_destroy_context(iscsi); } void discoverylogout_cb(struct iscsi_context *iscsi, int status, void *command_data _U_, void *private_data) { struct client_state *state = (struct client_state *)private_data; if (status != 0) { fprintf(stderr, "Failed to logout from target. : %s\n", iscsi_get_error(iscsi)); exit(10); } if (iscsi_disconnect(iscsi) != 0) { fprintf(stderr, "Failed to disconnect old socket\n"); exit(10); } state->finished = 1; } void discovery_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) { struct iscsi_discovery_address *addr; if (status != 0) { fprintf(stderr, "Failed to do discovery on target. : %s\n", iscsi_get_error(iscsi)); exit(10); } for(addr=command_data; addr; addr=addr->next) { printf("Target:%s Portal:%s\n", addr->target_name, addr->target_address); if (showluns != 0) { list_luns(private_data, addr->target_name, addr->target_address); } } if (iscsi_logout_async(iscsi, discoverylogout_cb, private_data) != 0) { fprintf(stderr, "iscsi_logout_async failed : %s\n", iscsi_get_error(iscsi)); exit(10); } } void discoverylogin_cb(struct iscsi_context *iscsi, int status, void *command_data _U_, void *private_data) { if (status != 0) { fprintf(stderr, "Login failed. %s\n", iscsi_get_error(iscsi)); exit(10); } if (iscsi_discovery_async(iscsi, discovery_cb, private_data) != 0) { fprintf(stderr, "failed to send discovery command : %s\n", iscsi_get_error(iscsi)); exit(10); } } void discoveryconnect_cb(struct iscsi_context *iscsi, int status, void *command_data _U_, void *private_data) { if (status != 0) { fprintf(stderr, "discoveryconnect_cb: connection failed : %s\n", iscsi_get_error(iscsi)); exit(10); } if (iscsi_login_async(iscsi, discoverylogin_cb, private_data) != 0) { fprintf(stderr, "iscsi_login_async failed : %s\n", iscsi_get_error(iscsi)); exit(10); } } void print_usage(void) { fprintf(stderr, "Usage: iscsi-ls [-?s] [-?|--help] [--usage] [-i|--initiator-name=iqn-name]\n" "\t\t[-s|--show-luns] \n"); } void print_help(void) { fprintf(stderr, "Usage: iscsi-ls [OPTION...] \n"); fprintf(stderr, " -i, --initiator-name=iqn-name Initiatorname to use\n"); fprintf(stderr, " -s, --show-luns Show the luns for each target\n"); fprintf(stderr, "\n"); fprintf(stderr, "Help options:\n"); fprintf(stderr, " -?, --help Show this help message\n"); fprintf(stderr, " --usage Display brief usage message\n"); fprintf(stderr, "\n"); fprintf(stderr, "iSCSI Portal URL format : %s\n", ISCSI_PORTAL_URL_SYNTAX); fprintf(stderr, "\n"); fprintf(stderr, " is either of:\n"); fprintf(stderr, " \"hostname\" iscsi.example\n"); fprintf(stderr, " \"ipv4-address\" 10.1.1.27\n"); fprintf(stderr, " \"ipv6-address\" [fce0::1]\n"); } int main(int argc, const char *argv[]) { struct iscsi_context *iscsi; struct iscsi_url *iscsi_url = NULL; struct client_state state; const char **extra_argv; int extra_argc = 0; const char *url = NULL; poptContext pc; int res; int show_help = 0, show_usage = 0; struct poptOption popt_options[] = { { "help", '?', POPT_ARG_NONE, &show_help, 0, "Show this help message", NULL }, { "usage", 0, POPT_ARG_NONE, &show_usage, 0, "Display brief usage message", NULL }, { "initiator-name", 'i', POPT_ARG_STRING, &initiator, 0, "Initiatorname to use", "iqn-name" }, { "show-luns", 's', POPT_ARG_NONE, &showluns, 0, "Show the luns for each target", NULL }, POPT_TABLEEND }; memset(&state, 0, sizeof(state)); pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_POSIXMEHARDER); if ((res = poptGetNextOpt(pc)) < -1) { fprintf(stderr, "Failed to parse option : %s %s\n", poptBadOption(pc, 0), poptStrerror(res)); exit(10); } extra_argv = poptGetArgs(pc); if (extra_argv) { url = *extra_argv; extra_argv++; while (extra_argv[extra_argc]) { extra_argc++; } } if (show_help != 0) { print_help(); exit(0); } if (show_usage != 0) { print_usage(); exit(0); } poptFreeContext(pc); if (url == NULL) { fprintf(stderr, "You must specify iscsi target portal.\n"); print_usage(); exit(10); } iscsi = iscsi_create_context(initiator); if (iscsi == NULL) { printf("Failed to create context\n"); exit(10); } iscsi_url = iscsi_parse_portal_url(iscsi, url); if (iscsi_url == NULL) { fprintf(stderr, "Failed to parse URL: %s\n", iscsi_get_error(iscsi)); exit(10); } iscsi_set_session_type(iscsi, ISCSI_SESSION_DISCOVERY); if (iscsi_url->user != NULL) { state.username = iscsi_url->user; state.password = iscsi_url->passwd; if (iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user, iscsi_url->passwd) != 0) { fprintf(stderr, "Failed to set initiator username and password\n"); exit(10); } } if (iscsi_connect_async(iscsi, iscsi_url->portal, discoveryconnect_cb, &state) != 0) { fprintf(stderr, "iscsi_connect failed. %s\n", iscsi_get_error(iscsi)); exit(10); } event_loop(iscsi, &state); iscsi_destroy_url(iscsi_url); iscsi_destroy_context(iscsi); return 0; } libiscsi-1.4.0/src/iscsi-inq.c0000644000175000017500000002313411750443164014325 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include #include #include #include #include #include "iscsi.h" #include "scsi-lowlevel.h" const char *initiator = "iqn.2010-11.ronnie:iscsi-inq"; void inquiry_block_limits(struct scsi_inquiry_block_limits *inq) { printf("wsnz:%d\n", inq->wsnz); printf("maximum compare and write length:%d\n", inq->max_cmp); printf("optimal transfer length granularity:%d\n", inq->opt_gran); printf("maximum transfer length:%d\n", inq->max_xfer_len); printf("optimal transfer length:%d\n",inq->opt_xfer_len); printf("maximum prefetch xdread xdwrite transfer length:%d\n", inq->max_prefetch); printf("maximum unmap lba count:%d\n", inq->max_unmap); printf("maximum unmap block descriptor count:%d\n", inq->max_unmap_bdc); printf("optimal unmap granularity:%d\n", inq->opt_unmap_gran); printf("ugavalid:%d\n", inq->ugavalid); printf("unmap granularity alignment:%d\n", inq->unmap_gran_align); printf("maximum write same length:%d\n", (int)inq->max_ws_len); } void inquiry_logical_block_provisioning(struct scsi_inquiry_logical_block_provisioning *inq) { printf("Threshold Exponent:%d\n", inq->threshold_exponent); printf("lbpu:%d\n", inq->lbpu); printf("lbpws:%d\n", inq->lbpws); printf("lbpws10:%d\n", inq->lbpws10); printf("lbprz:%d\n", inq->lbprz); printf("anc_sup:%d\n", inq->anc_sup); printf("dp:%d\n", inq->dp); printf("provisioning type:%d\n", inq->provisioning_type); } void inquiry_block_device_characteristics(struct scsi_inquiry_block_device_characteristics *inq) { printf("Medium Rotation Rate:%dRPM\n", inq->medium_rotation_rate); } void inquiry_device_identification(struct scsi_inquiry_device_identification *inq) { struct scsi_inquiry_device_designator *dev; int i; printf("Peripheral Qualifier:%s\n", scsi_devqualifier_to_str(inq->periperal_qualifier)); printf("Peripheral Device Type:%s\n", scsi_devtype_to_str(inq->periperal_device_type)); printf("Page Code:(0x%02x) %s\n", inq->pagecode, scsi_inquiry_pagecode_to_str(inq->pagecode)); for (i=0, dev = inq->designators; dev; i++, dev = dev->next) { printf("DEVICE DESIGNATOR #%d\n", i); if (dev->piv != 0) { printf("Device Protocol Identifier:(%d) %s\n", dev->protocol_identifier, scsi_protocol_identifier_to_str(dev->protocol_identifier)); } printf("Code Set:(%d) %s\n", dev->code_set, scsi_codeset_to_str(dev->code_set)); printf("PIV:%d\n", dev->piv); printf("Association:(%d) %s\n", dev->association, scsi_association_to_str(dev->association)); printf("Designator Type:(%d) %s\n", dev->designator_type, scsi_designator_type_to_str(dev->designator_type)); printf("Designator:[%s]\n", dev->designator); } } void inquiry_unit_serial_number(struct scsi_inquiry_unit_serial_number *inq) { printf("Unit Serial Number:[%s]\n", inq->usn); } void inquiry_supported_pages(struct scsi_inquiry_supported_pages *inq) { int i; for (i = 0; i < inq->num_pages; i++) { printf("Page:0x%02x %s\n", inq->pages[i], scsi_inquiry_pagecode_to_str(inq->pages[i])); } } void inquiry_standard(struct scsi_inquiry_standard *inq) { printf("Peripheral Qualifier:%s\n", scsi_devqualifier_to_str(inq->periperal_qualifier)); printf("Peripheral Device Type:%s\n", scsi_devtype_to_str(inq->periperal_device_type)); printf("Removable:%d\n", inq->rmb); printf("Version:%d %s\n", inq->version, scsi_version_to_str(inq->version)); printf("NormACA:%d\n", inq->normaca); printf("HiSup:%d\n", inq->hisup); printf("ReponseDataFormat:%d\n", inq->response_data_format); printf("SCCS:%d\n", inq->sccs); printf("ACC:%d\n", inq->acc); printf("TPGS:%d\n", inq->tpgs); printf("3PC:%d\n", inq->threepc); printf("Protect:%d\n", inq->protect); printf("EncServ:%d\n", inq->encserv); printf("MultiP:%d\n", inq->multip); printf("SYNC:%d\n", inq->sync); printf("CmdQue:%d\n", inq->cmdque); printf("Vendor:%s\n", inq->vendor_identification); printf("Product:%s\n", inq->product_identification); printf("Revision:%s\n", inq->product_revision_level); } void do_inquiry(struct iscsi_context *iscsi, int lun, int evpd, int pc) { struct scsi_task *task; int full_size; void *inq; /* See how big this inquiry data is */ task = iscsi_inquiry_sync(iscsi, lun, evpd, pc, 64); if (task == NULL || task->status != SCSI_STATUS_GOOD) { fprintf(stderr, "Inquiry command failed : %s\n", iscsi_get_error(iscsi)); exit(10); } full_size = scsi_datain_getfullsize(task); if (full_size > task->datain.size) { scsi_free_scsi_task(task); /* we need more data for the full list */ if ((task = iscsi_inquiry_sync(iscsi, lun, evpd, pc, full_size)) == NULL) { fprintf(stderr, "Inquiry command failed : %s\n", iscsi_get_error(iscsi)); exit(10); } } inq = scsi_datain_unmarshall(task); if (inq == NULL) { fprintf(stderr, "failed to unmarshall inquiry datain blob\n"); exit(10); } if (evpd == 0) { inquiry_standard(inq); } else { switch (pc) { case SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES: inquiry_supported_pages(inq); break; case SCSI_INQUIRY_PAGECODE_UNIT_SERIAL_NUMBER: inquiry_unit_serial_number(inq); break; case SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION: inquiry_device_identification(inq); break; case SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS: inquiry_block_limits(inq); break; case SCSI_INQUIRY_PAGECODE_BLOCK_DEVICE_CHARACTERISTICS: inquiry_block_device_characteristics(inq); break; case SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING: inquiry_logical_block_provisioning(inq); break; default: fprintf(stderr, "Usupported pagecode:0x%02x\n", pc); } } scsi_free_scsi_task(task); } void print_usage(void) { fprintf(stderr, "Usage: iscsi-inq [-?] [-?|--help] [--usage] [-i|--initiator-name=iqn-name]\n" "\t\t[-e|--evpd=integer] [-c|--pagecode=integer] \n"); } void print_help(void) { fprintf(stderr, "Usage: iscsi-inq [OPTION...] \n"); fprintf(stderr, " -i, --initiator-name=iqn-name Initiatorname to use\n"); fprintf(stderr, " -e, --evpd=integer evpd\n"); fprintf(stderr, " -c, --pagecode=integer page code\n"); fprintf(stderr, "\n"); fprintf(stderr, "Help options:\n"); fprintf(stderr, " -?, --help Show this help message\n"); fprintf(stderr, " --usage Display brief usage message\n"); fprintf(stderr, "\n"); fprintf(stderr, "iSCSI URL format : %s\n", ISCSI_URL_SYNTAX); fprintf(stderr, "\n"); fprintf(stderr, " is either of:\n"); fprintf(stderr, " \"hostname\" iscsi.example\n"); fprintf(stderr, " \"ipv4-address\" 10.1.1.27\n"); fprintf(stderr, " \"ipv6-address\" [fce0::1]\n"); } int main(int argc, const char *argv[]) { poptContext pc; struct iscsi_context *iscsi; const char **extra_argv; int extra_argc = 0; const char *url = NULL; struct iscsi_url *iscsi_url = NULL; int evpd = 0, pagecode = 0; int show_help = 0, show_usage = 0; int res; struct poptOption popt_options[] = { { "help", '?', POPT_ARG_NONE, &show_help, 0, "Show this help message", NULL }, { "usage", 0, POPT_ARG_NONE, &show_usage, 0, "Display brief usage message", NULL }, { "initiator-name", 'i', POPT_ARG_STRING, &initiator, 0, "Initiatorname to use", "iqn-name" }, { "evpd", 'e', POPT_ARG_INT, &evpd, 0, "evpd", "integer" }, { "pagecode", 'c', POPT_ARG_INT, &pagecode, 0, "page code", "integer" }, POPT_TABLEEND }; pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_POSIXMEHARDER); if ((res = poptGetNextOpt(pc)) < -1) { fprintf(stderr, "Failed to parse option : %s %s\n", poptBadOption(pc, 0), poptStrerror(res)); exit(10); } extra_argv = poptGetArgs(pc); if (extra_argv) { url = *extra_argv; extra_argv++; while (extra_argv[extra_argc]) { extra_argc++; } } if (show_help != 0) { print_help(); exit(0); } if (show_usage != 0) { print_usage(); exit(0); } poptFreeContext(pc); iscsi = iscsi_create_context(initiator); if (iscsi == NULL) { fprintf(stderr, "Failed to create context\n"); exit(10); } if (url == NULL) { fprintf(stderr, "You must specify the URL\n"); print_usage(); exit(10); } iscsi_url = iscsi_parse_full_url(iscsi, url); if (iscsi_url == NULL) { fprintf(stderr, "Failed to parse URL: %s\n", iscsi_get_error(iscsi)); exit(10); } iscsi_set_targetname(iscsi, iscsi_url->target); iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL); iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C); if (iscsi_url->user != NULL) { if (iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user, iscsi_url->passwd) != 0) { fprintf(stderr, "Failed to set initiator username and password\n"); exit(10); } } if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun) != 0) { fprintf(stderr, "Login Failed. %s\n", iscsi_get_error(iscsi)); iscsi_destroy_url(iscsi_url); iscsi_destroy_context(iscsi); exit(10); } do_inquiry(iscsi, iscsi_url->lun, evpd, pagecode); iscsi_destroy_url(iscsi_url); iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return 0; } libiscsi-1.4.0/src/ld_iscsi.c0000644000175000017500000002131711750443164014220 0ustar mjtmjt/* Copyright (C) 2011, 2012 by Ronnie Sahlberg This program 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 program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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, see . */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include "iscsi.h" #include "iscsi-private.h" #include "scsi-lowlevel.h" #include #include static const char *initiator = "iqn.2011-02.ronnie:ld_iscsi"; #define ISCSI_MAX_FD 255 struct iscsi_fd_list { int is_iscsi; int dup2fd; int in_flight; struct iscsi_context *iscsi; int lun; uint32_t block_size; uint64_t num_blocks; off_t offset; }; static struct iscsi_fd_list iscsi_fd_list[ISCSI_MAX_FD]; int (*real_open)(__const char *path, int flags, mode_t mode); int open(const char *path, int flags, mode_t mode) { int fd; if (!strncmp(path, "iscsi:", 6)) { struct iscsi_context *iscsi; struct iscsi_url *iscsi_url; struct scsi_task *task; struct scsi_readcapacity10 *rc10; iscsi = iscsi_create_context(initiator); if (iscsi == NULL) { fprintf(stderr, "ld-iscsi: Failed to create context\n"); errno = ENOMEM; return -1; } iscsi_url = iscsi_parse_full_url(iscsi, path); if (iscsi_url == NULL) { fprintf(stderr, "ld-iscsi: Failed to parse URL: %s\n", iscsi_get_error(iscsi)); iscsi_destroy_context(iscsi); errno = EINVAL; return -1; } iscsi_set_targetname(iscsi, iscsi_url->target); iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL); iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C); if (iscsi_url->user != NULL) { if (iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user, iscsi_url->passwd) != 0) { fprintf(stderr, "Failed to set initiator username and password\n"); iscsi_destroy_context(iscsi); errno = ENOMEM; return -1; } } if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun) != 0) { fprintf(stderr, "ld-iscsi: Login Failed. %s\n", iscsi_get_error(iscsi)); iscsi_destroy_url(iscsi_url); iscsi_destroy_context(iscsi); errno = EIO; return -1; } task = iscsi_readcapacity10_sync(iscsi, iscsi_url->lun, 0, 0); if (task == NULL || task->status != SCSI_STATUS_GOOD) { fprintf(stderr, "ld-iscsi: failed to send readcapacity command\n"); iscsi_destroy_url(iscsi_url); iscsi_destroy_context(iscsi); errno = EIO; return -1; } rc10 = scsi_datain_unmarshall(task); if (rc10 == NULL) { fprintf(stderr, "ld-iscsi: failed to unmarshall readcapacity10 data\n"); scsi_free_scsi_task(task); iscsi_destroy_url(iscsi_url); iscsi_destroy_context(iscsi); errno = EIO; return -1; } fd = iscsi_get_fd(iscsi); if (fd >= ISCSI_MAX_FD) { fprintf(stderr, "ld-iscsi: Too many files open\n"); iscsi_destroy_url(iscsi_url); iscsi_destroy_context(iscsi); errno = ENFILE; return -1; } iscsi_fd_list[fd].is_iscsi = 1; iscsi_fd_list[fd].dup2fd = -1; iscsi_fd_list[fd].iscsi = iscsi; iscsi_fd_list[fd].block_size = rc10->block_size; iscsi_fd_list[fd].num_blocks = rc10->lba; iscsi_fd_list[fd].offset = 0; iscsi_fd_list[fd].lun = iscsi_url->lun; scsi_free_scsi_task(task); iscsi_destroy_url(iscsi_url); return fd; } return real_open(path, flags, mode); } int (*real_close)(int fd); int close(int fd) { if (iscsi_fd_list[fd].is_iscsi == 1) { int i; if (iscsi_fd_list[fd].dup2fd >= 0) { iscsi_fd_list[fd].is_iscsi = 0; iscsi_fd_list[fd].dup2fd = -1; real_close(fd); return 0; } /* are there any FDs dup2ed onto this ? */ for(i = 0; i < ISCSI_MAX_FD; i++) { if (iscsi_fd_list[i].dup2fd == fd) { break; } } if (i < ISCSI_MAX_FD) { int j; /* yes there are DUPs onto fd, make i the new real device and repoint all other * duplicates */ memcpy(&iscsi_fd_list[i], &iscsi_fd_list[fd], sizeof(struct iscsi_fd_list)); iscsi_fd_list[i].dup2fd = -1; memset(&iscsi_fd_list[fd], 0, sizeof(struct iscsi_fd_list)); iscsi_fd_list[fd].dup2fd = -1; iscsi_fd_list[i].iscsi->fd = i; real_close(fd); for(j = 0; j < ISCSI_MAX_FD; j++) { if (j != i && iscsi_fd_list[j].dup2fd == fd) { iscsi_fd_list[j].dup2fd = i; } } return 0; } iscsi_fd_list[fd].is_iscsi = 0; iscsi_fd_list[fd].dup2fd = -1; iscsi_destroy_context(iscsi_fd_list[fd].iscsi); iscsi_fd_list[fd].iscsi = NULL; return 0; } return real_close(fd); } int (*real_fxstat)(int ver, int fd, struct stat *buf); int __fxstat(int ver, int fd, struct stat *buf) { if (iscsi_fd_list[fd].is_iscsi == 1) { if (iscsi_fd_list[fd].dup2fd >= 0) { return __fxstat(ver, iscsi_fd_list[fd].dup2fd, buf); } memset(buf, 0, sizeof(struct stat)); buf->st_mode = S_IRUSR | S_IRGRP | S_IROTH | S_IFREG; buf->st_size = iscsi_fd_list[fd].num_blocks * iscsi_fd_list[fd].block_size; return 0; } return real_fxstat(ver, fd, buf); } int (*real_lxstat)(int ver, __const char *path, struct stat *buf); int __lxstat(int ver, const char *path, struct stat *buf) { if (!strncmp(path, "iscsi:", 6)) { int fd, ret; fd = open(path, 0, 0); if (fd == -1) { return fd; } ret = __fxstat(ver, fd, buf); close(fd); return ret; } return real_lxstat(ver, path, buf); } int (*real_xstat)(int ver, __const char *path, struct stat *buf); int __xstat(int ver, const char *path, struct stat *buf) { return __lxstat(ver, path, buf); } ssize_t (*real_read)(int fd, void *buf, size_t count); ssize_t read(int fd, void *buf, size_t count) { if ((iscsi_fd_list[fd].is_iscsi == 1) && (iscsi_fd_list[fd].in_flight == 0)) { uint64_t offset; uint32_t num_blocks; struct scsi_task *task; if (iscsi_fd_list[fd].dup2fd >= 0) { return read(iscsi_fd_list[fd].dup2fd, buf, count); } offset = iscsi_fd_list[fd].offset / iscsi_fd_list[fd].block_size * iscsi_fd_list[fd].block_size; num_blocks = (iscsi_fd_list[fd].offset - offset + count + iscsi_fd_list[fd].block_size - 1) / iscsi_fd_list[fd].block_size; iscsi_fd_list[fd].in_flight = 1; task = iscsi_read10_sync(iscsi_fd_list[fd].iscsi, iscsi_fd_list[fd].lun, offset / iscsi_fd_list[fd].block_size, num_blocks * iscsi_fd_list[fd].block_size, iscsi_fd_list[fd].block_size); iscsi_fd_list[fd].in_flight = 0; if (task == NULL || task->status != SCSI_STATUS_GOOD) { fprintf(stderr, "ld-iscsi: failed to send read10 command\n"); errno = EIO; return -1; } memcpy(buf, &task->datain.data[iscsi_fd_list[fd].offset - offset], count); iscsi_fd_list[fd].offset += count; scsi_free_scsi_task(task); return count; } return real_read(fd, buf, count); } int (*real_dup2)(int oldfd, int newfd); int dup2(int oldfd, int newfd) { close(newfd); if (iscsi_fd_list[oldfd].is_iscsi == 1) { int ret; if (iscsi_fd_list[oldfd].dup2fd >= 0) { return dup2(iscsi_fd_list[oldfd].dup2fd, newfd); } ret = real_dup2(oldfd, newfd); if (ret < 0) { return ret; } iscsi_fd_list[newfd].is_iscsi = 1; iscsi_fd_list[newfd].dup2fd = oldfd; return newfd; } return real_dup2(oldfd, newfd); } static void __attribute__((constructor)) _init(void) { int i; for(i = 0; i < ISCSI_MAX_FD; i++) { iscsi_fd_list[i].dup2fd = -1; } real_open = dlsym(RTLD_NEXT, "open"); if (real_open == NULL) { fprintf(stderr, "ld_iscsi: Failed to dlsym(open)\n"); exit(10); } real_close = dlsym(RTLD_NEXT, "close"); if (real_close == NULL) { fprintf(stderr, "ld_iscsi: Failed to dlsym(close)\n"); exit(10); } real_fxstat = dlsym(RTLD_NEXT, "__fxstat"); if (real_fxstat == NULL) { fprintf(stderr, "ld_iscsi: Failed to dlsym(__fxstat)\n"); exit(10); } real_lxstat = dlsym(RTLD_NEXT, "__lxstat"); if (real_lxstat == NULL) { fprintf(stderr, "ld_iscsi: Failed to dlsym(__lxstat)\n"); exit(10); } real_xstat = dlsym(RTLD_NEXT, "__xstat"); if (real_xstat == NULL) { fprintf(stderr, "ld_iscsi: Failed to dlsym(__xstat)\n"); exit(10); } real_read = dlsym(RTLD_NEXT, "read"); if (real_read == NULL) { fprintf(stderr, "ld_iscsi: Failed to dlsym(read)\n"); exit(10); } real_dup2 = dlsym(RTLD_NEXT, "dup2"); if (real_dup2 == NULL) { fprintf(stderr, "ld_iscsi: Failed to dlsym(dup2)\n"); exit(10); } } libiscsi-1.4.0/.gitignore0000644000175000017500000000040111750443164013453 0ustar mjtmjt/autom4te.cache /depcomp /aclocal.m4 /missing /config.guess /config.sub /install-sh /configure /config.h.in /Makefile.in /Makefile .deps .libs /stamp-h1 *.o *.lo *.la bin /config.h /config.log /config.status .dirstamp /libtool /ltmain.sh libiscsi-*.tar.gz libiscsi-1.4.0/examples/0000755000175000017500000000000011750443164013306 5ustar mjtmjtlibiscsi-1.4.0/examples/iscsi-dd.c0000644000175000017500000002077011750443164015157 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include #include #include #include #include #include "iscsi.h" #include "scsi-lowlevel.h" char *initiator = "iqn.2010-11.ronnie:iscsi-inq"; int max_in_flight = 50; int blocks_per_io = 200; struct client { int finished; int in_flight; struct iscsi_context *src_iscsi; int src_lun; int src_blocksize; uint64_t src_num_blocks; uint64_t pos; struct iscsi_context *dst_iscsi; int dst_lun; int dst_blocksize; uint64_t dst_num_blocks; }; void fill_read_queue(struct client *client); struct write_task { struct scsi_task *rt; struct client *client; }; void write10_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) { struct write_task *wt = (struct write_task *)private_data; struct scsi_task *task = command_data; struct client *client = wt->client; if (status == SCSI_STATUS_CHECK_CONDITION) { printf("Write10 failed with sense key:%d ascq:%04x\n", task->sense.key, task->sense.ascq); scsi_free_scsi_task(task); exit(10); } if (status != SCSI_STATUS_GOOD) { printf("Write10 failed with %s\n", iscsi_get_error(iscsi)); scsi_free_scsi_task(task); exit(10); } client->in_flight--; fill_read_queue(client); if ((client->in_flight == 0) && (client->pos == client->src_num_blocks)) { client->finished = 1; } scsi_free_scsi_task(wt->rt); scsi_free_scsi_task(task); free(wt); } void read10_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) { struct client *client = (struct client *)private_data; struct scsi_task *task = command_data; struct write_task *wt; if (status == SCSI_STATUS_CHECK_CONDITION) { printf("Read10 failed with sense key:%d ascq:%04x\n", task->sense.key, task->sense.ascq); exit(10); } wt = malloc(sizeof(struct write_task)); wt->rt = task; wt->client = client; if (iscsi_write10_async(client->dst_iscsi, client->dst_lun, task->datain.data, task->datain.size, task->params.read10.lba, 0, 0, client->dst_blocksize, write10_cb, wt) != 0) { printf("failed to send read10 command\n"); scsi_free_scsi_task(task); exit(10); } } void fill_read_queue(struct client *client) { int num_blocks; while(client->in_flight < max_in_flight && client->pos < client->src_num_blocks) { client->in_flight++; num_blocks = client->src_num_blocks - client->pos; if (num_blocks > blocks_per_io) { num_blocks = blocks_per_io; } if (iscsi_read10_async(client->src_iscsi, client->src_lun, client->pos, num_blocks * client->src_blocksize, client->src_blocksize, read10_cb, client) != 0) { printf("failed to send read10 command\n"); exit(10); } client->pos += num_blocks; } } int main(int argc, const char *argv[]) { poptContext pc; const char **extra_argv; char *src_url = NULL; char *dst_url = NULL; struct iscsi_url *iscsi_url; struct scsi_task *task; struct scsi_readcapacity10 *rc10; int extra_argc = 0; int res; struct pollfd pfd[2]; struct client client; struct poptOption popt_options[] = { POPT_AUTOHELP { "initiator-name", 'i', POPT_ARG_STRING, &initiator, 0, "Initiatorname to use", "iqn-name" }, { "src", 0, POPT_ARG_STRING, &src_url, 0, "SRC lun", "iscsi url" }, { "dst", 0, POPT_ARG_STRING, &dst_url, 0, "DST lun", "iscsi url" }, POPT_TABLEEND }; pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_POSIXMEHARDER); if ((res = poptGetNextOpt(pc)) < -1) { fprintf(stderr, "Failed to parse option : %s %s\n", poptBadOption(pc, 0), poptStrerror(res)); exit(10); } extra_argv = poptGetArgs(pc); poptFreeContext(pc); if (src_url == NULL) { fprintf(stderr, "You must specify source url\n"); fprintf(stderr, " --src iscsi://[:]//\n", argv[0]); exit(10); } if (dst_url == NULL) { fprintf(stderr, "You must specify destination url\n"); fprintf(stderr, " --dst iscsi://[:]//\n", argv[0]); exit(10); } memset(&client, 0, sizeof(client)); client.src_iscsi = iscsi_create_context(initiator); if (client.src_iscsi == NULL) { fprintf(stderr, "Failed to create context\n"); exit(10); } iscsi_url = iscsi_parse_full_url(client.src_iscsi, src_url); if (iscsi_url == NULL) { fprintf(stderr, "Failed to parse URL: %s\n", iscsi_get_error(client.src_iscsi)); exit(10); } iscsi_set_targetname(client.src_iscsi, iscsi_url->target); iscsi_set_session_type(client.src_iscsi, ISCSI_SESSION_NORMAL); iscsi_set_header_digest(client.src_iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C); if (iscsi_url->user != NULL) { if (iscsi_set_initiator_username_pwd(client.src_iscsi, iscsi_url->user, iscsi_url->passwd) != 0) { fprintf(stderr, "Failed to set initiator username and password\n"); exit(10); } } if (iscsi_full_connect_sync(client.src_iscsi, iscsi_url->portal, iscsi_url->lun) != 0) { fprintf(stderr, "Login Failed. %s\n", iscsi_get_error(client.src_iscsi)); iscsi_destroy_url(iscsi_url); iscsi_destroy_context(client.src_iscsi); exit(10); } client.src_lun = iscsi_url->lun; iscsi_destroy_url(iscsi_url); task = iscsi_readcapacity10_sync(client.src_iscsi, client.src_lun, 0, 0); if (task == NULL || task->status != SCSI_STATUS_GOOD) { fprintf(stderr, "failed to send readcapacity command\n"); exit(10); } rc10 = scsi_datain_unmarshall(task); if (rc10 == NULL) { fprintf(stderr, "failed to unmarshall readcapacity10 data\n"); exit(10); } client.src_blocksize = rc10->block_size; client.src_num_blocks = rc10->lba; scsi_free_scsi_task(task); client.dst_iscsi = iscsi_create_context(initiator); if (client.dst_iscsi == NULL) { fprintf(stderr, "Failed to create context\n"); exit(10); } iscsi_url = iscsi_parse_full_url(client.dst_iscsi, dst_url); if (iscsi_url == NULL) { fprintf(stderr, "Failed to parse URL: %s\n", iscsi_get_error(client.dst_iscsi)); exit(10); } iscsi_set_targetname(client.dst_iscsi, iscsi_url->target); iscsi_set_session_type(client.dst_iscsi, ISCSI_SESSION_NORMAL); iscsi_set_header_digest(client.dst_iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C); if (iscsi_url->user != NULL) { if (iscsi_set_initiator_username_pwd(client.dst_iscsi, iscsi_url->user, iscsi_url->passwd) != 0) { fprintf(stderr, "Failed to set initiator username and password\n"); exit(10); } } if (iscsi_full_connect_sync(client.dst_iscsi, iscsi_url->portal, iscsi_url->lun) != 0) { fprintf(stderr, "Login Failed. %s\n", iscsi_get_error(client.dst_iscsi)); iscsi_destroy_url(iscsi_url); iscsi_destroy_context(client.dst_iscsi); exit(10); } client.dst_lun = iscsi_url->lun; iscsi_destroy_url(iscsi_url); task = iscsi_readcapacity10_sync(client.dst_iscsi, client.dst_lun, 0, 0); if (task == NULL || task->status != SCSI_STATUS_GOOD) { fprintf(stderr, "failed to send readcapacity command\n"); exit(10); } rc10 = scsi_datain_unmarshall(task); if (rc10 == NULL) { fprintf(stderr, "failed to unmarshall readcapacity10 data\n"); exit(10); } client.dst_blocksize = rc10->block_size; client.dst_num_blocks = rc10->lba; scsi_free_scsi_task(task); fill_read_queue(&client); while (client.finished == 0) { pfd[0].fd = iscsi_get_fd(client.src_iscsi); pfd[0].events = iscsi_which_events(client.src_iscsi); pfd[1].fd = iscsi_get_fd(client.dst_iscsi); pfd[1].events = iscsi_which_events(client.dst_iscsi); if (poll(&pfd[0], 2, -1) < 0) { printf("Poll failed"); exit(10); } if (iscsi_service(client.src_iscsi, pfd[0].revents) < 0) { printf("iscsi_service failed with : %s\n", iscsi_get_error(client.src_iscsi)); break; } if (iscsi_service(client.dst_iscsi, pfd[1].revents) < 0) { printf("iscsi_service failed with : %s\n", iscsi_get_error(client.dst_iscsi)); break; } } iscsi_logout_sync(client.src_iscsi); iscsi_destroy_context(client.src_iscsi); iscsi_logout_sync(client.dst_iscsi); iscsi_destroy_context(client.dst_iscsi); return 0; } libiscsi-1.4.0/examples/iscsiclient.c0000644000175000017500000004253411750443164015773 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ /* This is an example of using libiscsi. * It basically logs in to the the target and performs a discovery. * It then selects the last target in the returned list and * starts a normal login to that target. * Once logged in it issues a REPORTLUNS call and selects the last returned lun in the list. * This LUN is then used to send INQUIRY, READCAPACITY10 and READ10 test calls to. */ /* The reason why we have to specify an allocation length and sometimes probe, starting with a small value, probing how big the buffer * should be, and asking again with a bigger buffer. * Why not just always ask with a buffer that is big enough? * The reason is that a lot of scsi targets are "sensitive" and ""buggy"" * many targets will just fail the operation completely if they thing alloc len is unreasonably big. */ /* This is the host/port we connect to.*/ #define TARGET "10.1.1.116:3260" #if defined(WIN32) #include #pragma comment(lib, "ws2_32.lib") WSADATA wsaData; #else #include #endif #include #include #include #include #include "iscsi.h" #include "scsi-lowlevel.h" struct client_state { int finished; char *message; int has_discovered_target; char *target_name; char *target_address; int lun; int block_size; }; unsigned char small_buffer[512]; void tm_at_cb(struct iscsi_context *iscsi _U_, int status _U_, void *command_data _U_, void *private_data) { struct client_state *clnt = (struct client_state *)private_data; printf("tm at cb !\n"); printf("response : %d\n", *((uint32_t *)command_data)); clnt->finished = 1; } void synccache10_cb(struct iscsi_context *iscsi _U_, int status, void *command_data _U_, void *private_data _U_) { printf("SYNCCACHE10 status:%d\n", status); } void nop_out_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) { struct iscsi_data *data = command_data; struct scsi_task *task; printf("NOP-IN status:%d\n", status); if (data->size > 0) { printf("NOP-IN data:%s\n", data->data); } printf("Send SYNCHRONIZECACHE10\n"); task = iscsi_synchronizecache10_task(iscsi, 2, 0, 0, 0, 0, synccache10_cb, private_data); if (task == NULL) { printf("failed to send sync cache10\n"); exit(10); } printf("send task management to try to abort the sync10 task\n"); if (iscsi_task_mgmt_abort_task_async(iscsi, task, tm_at_cb, private_data) != 0) { printf("failed to send task management to abort the sync10 task\n"); exit(10); } } void write10_cb(struct iscsi_context *iscsi _U_, int status, void *command_data, void *private_data _U_) { struct scsi_task *task = command_data; if (status == SCSI_STATUS_CHECK_CONDITION) { printf("Write10 failed with sense key:%d ascq:%04x\n", task->sense.key, task->sense.ascq); scsi_free_scsi_task(task); exit(10); } if (status != SCSI_STATUS_GOOD) { printf("Write10 failed with %s\n", iscsi_get_error(iscsi)); scsi_free_scsi_task(task); exit(10); } printf("Write successful :%d\n", status); scsi_free_scsi_task(task); exit(10); } void read10_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) { struct scsi_task *task = command_data; int i; if (status == SCSI_STATUS_CHECK_CONDITION) { printf("Read10 failed with sense key:%d ascq:%04x\n", task->sense.key, task->sense.ascq); scsi_free_scsi_task(task); exit(10); } printf("READ10 successful. Block content:\n"); for (i=0;i<512;i++) { printf("%02x ", small_buffer[i]); if (i%16==15) printf("\n"); if (i==69) break; } printf("...\n"); printf("Finished, wont try to write data since that will likely destroy your LUN :-(\n"); printf("Send NOP-OUT\n"); if (iscsi_nop_out_async(iscsi, nop_out_cb, (unsigned char *)"Ping!", 6, private_data) != 0) { printf("failed to send nop-out\n"); scsi_free_scsi_task(task); exit(10); } // printf("write the block back\n"); // if (iscsi_write10_async(iscsi, clnt->lun, task->data.datain, task->datain.size, 0, 0, 0, clnt->block_size, write10_cb, private_data) != 0) { // printf("failed to send write10 command\n"); // scsi_free_scsi_task(task); // exit(10); // } scsi_free_scsi_task(task); } void read6_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) { struct client_state *clnt = (struct client_state *)private_data; struct scsi_task *task = command_data; int i; if (status == SCSI_STATUS_CHECK_CONDITION) { printf("Read6 failed with sense key:%d ascq:%04x\n", task->sense.key, task->sense.ascq); scsi_free_scsi_task(task); exit(10); } printf("READ6 successful. Block content:\n"); for (i=0;idatain.size;i++) { printf("%02x ", task->datain.data[i]); if (i%16==15) printf("\n"); if (i==69) break; } printf("...\n"); scsi_free_scsi_task(task); if ((task = iscsi_read10_task(iscsi, clnt->lun, 0, clnt->block_size, clnt->block_size, read10_cb, private_data)) == NULL) { printf("failed to send read10 command\n"); exit(10); } /* provide a buffer from the application to read into instead * of copying and linearizing the data. This saves two copies * of the data. One in libiscsi and one in the application * callback. */ scsi_task_add_data_in_buffer(task, 128, &small_buffer[0]); scsi_task_add_data_in_buffer(task, 512-128, &small_buffer[128]); } void readcapacity10_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) { struct client_state *clnt = (struct client_state *)private_data; struct scsi_task *task = command_data; struct scsi_readcapacity10 *rc10; int full_size; if (status == SCSI_STATUS_CHECK_CONDITION) { printf("Readcapacity10 failed with sense key:%d ascq:%04x\n", task->sense.key, task->sense.ascq); scsi_free_scsi_task(task); exit(10); } full_size = scsi_datain_getfullsize(task); if (full_size < task->datain.size) { printf("not enough data for full size readcapacity10\n"); scsi_free_scsi_task(task); exit(10); } rc10 = scsi_datain_unmarshall(task); if (rc10 == NULL) { printf("failed to unmarshall readcapacity10 data\n"); scsi_free_scsi_task(task); exit(10); } clnt->block_size = rc10->block_size; printf("READCAPACITY10 successful. Size:%d blocks blocksize:%d. Read first block\n", rc10->lba, rc10->block_size); if (iscsi_read6_task(iscsi, clnt->lun, 0, clnt->block_size, clnt->block_size, read6_cb, private_data) == NULL) { printf("failed to send read6 command\n"); scsi_free_scsi_task(task); exit(10); } scsi_free_scsi_task(task); } void modesense6_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) { struct client_state *clnt = (struct client_state *)private_data; struct scsi_task *task = command_data; struct scsi_mode_sense *ms; int full_size; if (status == SCSI_STATUS_CHECK_CONDITION) { printf("Modesense6 failed with sense key:%d ascq:%04x\n", task->sense.key, task->sense.ascq); exit(10); } else { full_size = scsi_datain_getfullsize(task); if (full_size > task->datain.size) { printf("did not get enough data for mode sense, sening modesense again asking for bigger buffer\n"); if (iscsi_modesense6_task(iscsi, clnt->lun, 0, SCSI_MODESENSE_PC_CURRENT, SCSI_MODESENSE_PAGECODE_RETURN_ALL_PAGES, 0, full_size, modesense6_cb, private_data) == NULL) { printf("failed to send modesense6 command\n"); scsi_free_scsi_task(task); exit(10); } scsi_free_scsi_task(task); return; } } printf("MODESENSE6 successful.\n"); ms = scsi_datain_unmarshall(task); if (ms == NULL) { printf("failed to unmarshall mode sense datain blob\n"); scsi_free_scsi_task(task); exit(10); } printf("Send READCAPACITY10\n"); if (iscsi_readcapacity10_task(iscsi, clnt->lun, 0, 0, readcapacity10_cb, private_data) == NULL) { printf("failed to send readcapacity command\n"); scsi_free_scsi_task(task); exit(10); } scsi_free_scsi_task(task); } void inquiry_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) { struct client_state *clnt = (struct client_state *)private_data; struct scsi_task *task = command_data; struct scsi_inquiry_standard *inq; if (status == SCSI_STATUS_CHECK_CONDITION) { printf("Inquiry failed with sense key:%d ascq:%04x\n", task->sense.key, task->sense.ascq); scsi_free_scsi_task(task); exit(10); } printf("INQUIRY successful for standard data.\n"); inq = scsi_datain_unmarshall(task); if (inq == NULL) { printf("failed to unmarshall inquiry datain blob\n"); scsi_free_scsi_task(task); exit(10); } printf("Device Type is %d. VendorId:%s ProductId:%s\n", inq->periperal_device_type, inq->vendor_identification, inq->product_identification); printf("Send MODESENSE6\n"); if (iscsi_modesense6_task(iscsi, clnt->lun, 0, SCSI_MODESENSE_PC_CURRENT, SCSI_MODESENSE_PAGECODE_RETURN_ALL_PAGES, 0, 4, modesense6_cb, private_data) == NULL) { printf("failed to send modesense6 command\n"); scsi_free_scsi_task(task); exit(10); } scsi_free_scsi_task(task); } void testunitready_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) { struct client_state *clnt = (struct client_state *)private_data; struct scsi_task *task = command_data; if (status == SCSI_STATUS_CHECK_CONDITION) { printf("First testunitready failed with sense key:%d ascq:%04x\n", task->sense.key, task->sense.ascq); if (task->sense.key == SCSI_SENSE_UNIT_ATTENTION && task->sense.ascq == SCSI_SENSE_ASCQ_BUS_RESET) { printf("target device just came online, try again\n"); if (iscsi_testunitready_task(iscsi, clnt->lun, testunitready_cb, private_data) == NULL) { printf("failed to send testunitready command\n"); scsi_free_scsi_task(task); exit(10); } } scsi_free_scsi_task(task); return; } printf("TESTUNITREADY successful, do an inquiry on lun:%d\n", clnt->lun); if (iscsi_inquiry_task(iscsi, clnt->lun, 0, 0, 64, inquiry_cb, private_data) == NULL) { printf("failed to send inquiry command : %s\n", iscsi_get_error(iscsi)); scsi_free_scsi_task(task); exit(10); } scsi_free_scsi_task(task); } void reportluns_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) { struct client_state *clnt = (struct client_state *)private_data; struct scsi_task *task = command_data; struct scsi_reportluns_list *list; int full_report_size; int i; if (status != SCSI_STATUS_GOOD) { printf("Reportluns failed with : %s\n", iscsi_get_error(iscsi)); scsi_free_scsi_task(task); return; } full_report_size = scsi_datain_getfullsize(task); printf("REPORTLUNS status:%d data size:%d, full reports luns data size:%d\n", status, task->datain.size, full_report_size); if (full_report_size > task->datain.size) { printf("We did not get all the data we need in reportluns, ask again\n"); if (iscsi_reportluns_task(iscsi, 0, full_report_size, reportluns_cb, private_data) == NULL) { printf("failed to send reportluns command\n"); scsi_free_scsi_task(task); exit(10); } scsi_free_scsi_task(task); return; } list = scsi_datain_unmarshall(task); if (list == NULL) { printf("failed to unmarshall reportluns datain blob\n"); scsi_free_scsi_task(task); exit(10); } for (i=0; i < (int)list->num; i++) { printf("LUN:%d found\n", list->luns[i]); clnt->lun = list->luns[i]; } printf("Will use LUN:%d\n", clnt->lun); printf("Send testunitready to lun %d\n", clnt->lun); if (iscsi_testunitready_task(iscsi, clnt->lun, testunitready_cb, private_data) == NULL) { printf("failed to send testunitready command : %s\n", iscsi_get_error(iscsi)); scsi_free_scsi_task(task); exit(10); } scsi_free_scsi_task(task); } void normallogin_cb(struct iscsi_context *iscsi, int status, void *command_data _U_, void *private_data) { if (status != 0) { printf("Failed to log in to target : %s\n", iscsi_get_error(iscsi)); exit(10); } printf("Logged in normal session, send reportluns\n"); if (iscsi_reportluns_task(iscsi, 0, 16, reportluns_cb, private_data) == NULL) { printf("failed to send reportluns command : %s\n", iscsi_get_error(iscsi)); exit(10); } } void normalconnect_cb(struct iscsi_context *iscsi, int status, void *command_data _U_, void *private_data) { printf("Connected to iscsi socket\n"); if (status != 0) { printf("normalconnect_cb: connection failed status:%d\n", status); exit(10); } printf("connected, send login command\n"); iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL); iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_CRC32C_NONE); if (iscsi_login_async(iscsi, normallogin_cb, private_data) != 0) { printf("iscsi_login_async failed\n"); exit(10); } } void discoverylogout_cb(struct iscsi_context *iscsi, int status, void *command_data _U_, void *private_data) { struct client_state *clnt = (struct client_state *)private_data; printf("discovery session logged out, Message from main() was:[%s]\n", clnt->message); if (status != 0) { printf("Failed to logout from target. : %s\n", iscsi_get_error(iscsi)); exit(10); } printf("disconnect socket\n"); if (iscsi_disconnect(iscsi) != 0) { printf("Failed to disconnect old socket\n"); exit(10); } printf("reconnect with normal login to [%s]\n", clnt->target_address); printf("Use targetname [%s] when connecting\n", clnt->target_name); if (iscsi_set_targetname(iscsi, clnt->target_name)) { printf("Failed to set target name\n"); exit(10); } if (iscsi_set_alias(iscsi, "ronnie") != 0) { printf("Failed to add alias\n"); exit(10); } if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) != 0) { printf("Failed to set settion type to normal\n"); exit(10); } if (iscsi_connect_async(iscsi, clnt->target_address, normalconnect_cb, clnt) != 0) { printf("iscsi_connect failed : %s\n", iscsi_get_error(iscsi)); exit(10); } } void discovery_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) { struct client_state *clnt = (struct client_state *)private_data; struct iscsi_discovery_address *addr; printf("discovery callback status:%04x\n", status); if (status != 0) { printf("Failed to do discovery on target. : %s\n", iscsi_get_error(iscsi)); exit(10); } for(addr=command_data; addr; addr=addr->next) { printf("Target:%s Address:%s\n", addr->target_name, addr->target_address); } addr=command_data; clnt->has_discovered_target = 1; clnt->target_name = strdup(addr->target_name); clnt->target_address = strdup(addr->target_address); printf("discovery complete, send logout command\n"); if (iscsi_logout_async(iscsi, discoverylogout_cb, private_data) != 0) { printf("iscsi_logout_async failed : %s\n", iscsi_get_error(iscsi)); exit(10); } } void discoverylogin_cb(struct iscsi_context *iscsi, int status, void *command_data _U_, void *private_data) { if (status != 0) { printf("Failed to log in to target. : %s\n", iscsi_get_error(iscsi)); exit(10); } printf("Logged in to target, send discovery command\n"); if (iscsi_discovery_async(iscsi, discovery_cb, private_data) != 0) { printf("failed to send discovery command : %s\n", iscsi_get_error(iscsi)); exit(10); } } void discoveryconnect_cb(struct iscsi_context *iscsi, int status, void *command_data _U_, void *private_data) { printf("Connected to iscsi socket status:0x%08x\n", status); if (status != 0) { printf("discoveryconnect_cb: connection failed : %s\n", iscsi_get_error(iscsi)); exit(10); } printf("connected, send login command\n"); iscsi_set_session_type(iscsi, ISCSI_SESSION_DISCOVERY); if (iscsi_login_async(iscsi, discoverylogin_cb, private_data) != 0) { printf("iscsi_login_async failed : %s\n", iscsi_get_error(iscsi)); exit(10); } } int main(int argc _U_, char *argv[] _U_) { struct iscsi_context *iscsi; struct pollfd pfd; struct client_state clnt; printf("iscsi client\n"); #if defined(WIN32) if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { printf("Failed to start Winsock2\n"); exit(10); } #endif memset(&clnt, 0, sizeof(clnt)); iscsi = iscsi_create_context("iqn.2002-10.com.ronnie:client"); if (iscsi == NULL) { printf("Failed to create context\n"); exit(10); } if (iscsi_set_alias(iscsi, "ronnie") != 0) { printf("Failed to add alias\n"); exit(10); } clnt.message = "Hello iSCSI"; clnt.has_discovered_target = 0; if (iscsi_connect_async(iscsi, TARGET, discoveryconnect_cb, &clnt) != 0) { printf("iscsi_connect failed. %s\n", iscsi_get_error(iscsi)); exit(10); } while (clnt.finished == 0) { pfd.fd = iscsi_get_fd(iscsi); pfd.events = iscsi_which_events(iscsi); if (poll(&pfd, 1, -1) < 0) { printf("Poll failed"); exit(10); } if (iscsi_service(iscsi, pfd.revents) < 0) { printf("iscsi_service failed with : %s\n", iscsi_get_error(iscsi)); break; } } iscsi_destroy_context(iscsi); if (clnt.target_name != NULL) { free(clnt.target_name); } if (clnt.target_address != NULL) { free(clnt.target_address); } printf("ok\n"); return 0; } libiscsi-1.4.0/test-tool/0000755000175000017500000000000011750443164013422 5ustar mjtmjtlibiscsi-1.4.0/test-tool/0231_write12_wrprotect.c0000644000175000017500000000564411750443164017652 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0231_write12_wrprotect(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret = 0, i, lun; uint32_t block_size, num_blocks; unsigned char data[256 * 512]; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall READCAPACITY16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; if(rc16->prot_en != 0) { printf("device is formatted with protection information, skipping test\n"); scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); if (!data_loss) { printf("--dataloss flag is not set. Skipping test\n"); ret = -1; goto finished; } printf("Write12 with RDPROTECT "); for (i = 1; i <= 7; i++) { task = iscsi_write12_sync(iscsi, lun, 0, data, block_size, block_size, i, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send write12 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST || task->sense.ascq != SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB) { printf("[FAILED]\n"); printf("Write12 with RDPROTECT!=0 should have failed with CHECK_CONDITION/ILLEGAL_REQUEST/INVALID_FIELD_IN_CDB\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0233_write12_0blocks.c0000644000175000017500000000706711750443164017161 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0233_write12_0blocks(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret = 0, i, lun; uint32_t block_size; uint64_t num_blocks; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall READCAPACITY16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; num_blocks = rc16->returned_lba; scsi_free_scsi_task(task); if (!data_loss) { printf("--dataloss flag is not set. Skipping test\n"); ret = -1; goto finished; } printf("Write12 0blocks at LBA:0 "); task = iscsi_write12_sync(iscsi, lun, 0, NULL, 0, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send write12 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Write12 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); printf("Write12 0blocks at LBA: "); task = iscsi_write12_sync(iscsi, lun, num_blocks, NULL, 0, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send write12 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Write12 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); printf("Write12 0blocks at LBA: "); task = iscsi_write12_sync(iscsi, lun, num_blocks + 1, NULL, 0, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send write12 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Write12 command: Should fail when writing 0blocks beyond end\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0105_read10_invalid.c0000644000175000017500000001543611750443164017026 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0105_read10_invalid(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct iscsi_data data; char buf[512]; int ret, lun; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } ret = 0; /* Try a read of 1 block but xferlength == 0 */ printf("Read10 1 block but with iscsi ExpectedDataTransferLength==0 ... "); task = malloc(sizeof(struct scsi_task)); if (task == NULL) { printf("Failed to allocate task structure\n"); ret = -1; goto finished; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_READ10; task->cdb[8] = 1; task->cdb_size = 10; task->xfer_dir = SCSI_XFER_READ; task->expxferlen = 0; if (iscsi_scsi_command_sync(iscsi, lun, task, NULL) == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read10 of 1 block with iscsi ExpectedDataTransferLength==0 should not fail.\n"); ret = -1; scsi_free_scsi_task(task); goto test2; } if (task->residual_status != SCSI_RESIDUAL_OVERFLOW || task->residual != 512) { printf("[FAILED]\n"); printf("Read10 returned incorrect residual overflow.\n"); ret = -1; scsi_free_scsi_task(task); goto test5; } scsi_free_scsi_task(task); printf("[OK]\n"); test2: /* Try a read of 1 block but xferlength == 1024 */ printf("Read10 1 block but with iscsi ExpectedDataTransferLength==1024 ... "); task = malloc(sizeof(struct scsi_task)); if (task == NULL) { printf("Failed to allocate task structure\n"); ret = -1; goto finished; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_READ10; task->cdb[8] = 1; task->cdb_size = 10; task->xfer_dir = SCSI_XFER_READ; task->expxferlen = 1024; if (iscsi_scsi_command_sync(iscsi, lun, task, NULL) == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read10 of 1 block with iscsi ExpectedDataTransferLength==1024 should not fail.\n"); ret = -1; scsi_free_scsi_task(task); goto test3; } if (task->residual_status != SCSI_RESIDUAL_UNDERFLOW || task->residual != 512) { printf("[FAILED]\n"); printf("Read10 returned incorrect residual underflow.\n"); ret = -1; scsi_free_scsi_task(task); goto test5; } scsi_free_scsi_task(task); printf("[OK]\n"); test3: /* Try a read of 1 block but xferlength == 200 */ printf("Read10 1 block but with iscsi ExpectedDataTransferLength==200 ... "); task = malloc(sizeof(struct scsi_task)); if (task == NULL) { printf("Failed to allocate task structure\n"); ret = -1; goto finished; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_READ10; task->cdb[8] = 1; task->cdb_size = 10; task->xfer_dir = SCSI_XFER_READ; task->expxferlen = 200; if (iscsi_scsi_command_sync(iscsi, lun, task, NULL) == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read10 of 1 block with iscsi ExpectedDataTransferLength==200 should not fail.\n"); ret = -1; scsi_free_scsi_task(task); goto test4; } if (task->residual_status != SCSI_RESIDUAL_OVERFLOW || task->residual != 312) { printf("[FAILED]\n"); printf("Read10 returned incorrect residual overflow.\n"); ret = -1; scsi_free_scsi_task(task); goto test5; } scsi_free_scsi_task(task); printf("[OK]\n"); test4: /* Try a read of 2 blocks but xferlength == 512 */ printf("Read10 2 blocks but with iscsi ExpectedDataTransferLength==512 ... "); task = malloc(sizeof(struct scsi_task)); if (task == NULL) { printf("Failed to allocate task structure\n"); ret = -1; goto finished; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_READ10; task->cdb[8] = 2; task->cdb_size = 10; task->xfer_dir = SCSI_XFER_READ; task->expxferlen = 512; if (iscsi_scsi_command_sync(iscsi, lun, task, NULL) == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read10 of 2 blocks with iscsi ExpectedDataTransferLength==512 should succeed.\n"); ret = -1; scsi_free_scsi_task(task); goto test5; } if (task->residual_status != SCSI_RESIDUAL_OVERFLOW || task->residual != 512) { printf("[FAILED]\n"); printf("Read10 returned incorrect residual overflow.\n"); ret = -1; scsi_free_scsi_task(task); goto test5; } scsi_free_scsi_task(task); printf("[OK]\n"); test5: /* Try a read of 1 block but make it a data-out write on the iscsi layer */ printf("Read10 of 1 block but sent as data-out write in iscsi layer ... "); task = malloc(sizeof(struct scsi_task)); if (task == NULL) { printf("Failed to allocate task structure\n"); ret = -1; goto finished; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_READ10; task->cdb[8] = 1; task->cdb_size = 10; task->xfer_dir = SCSI_XFER_WRITE; task->expxferlen = sizeof(buf); data.size = sizeof(buf); data.data = (unsigned char *)&buf[0]; if (iscsi_scsi_command_sync(iscsi, lun, task, &data) == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read10 of 1 block but iscsi data-out write should fail.\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0160_readcapacity16_simple.c0000644000175000017500000000371111750443164020407 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0160_readcapacity16_simple(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret, lun; ret = 0; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } printf("Test that Readcapacity10 is supported ... "); task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send readcapacity16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Readcapacity command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("[FAILED]\n"); printf("failed to unmarshall readcapacity16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0222_write16_flags.c0000644000175000017500000000776111750443164016723 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0222_write16_flags(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret = 0, lun; uint32_t block_size; unsigned char data[256 * 512]; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall READCAPACITY16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; scsi_free_scsi_task(task); printf("Write16 with DPO "); task = iscsi_write16_sync(iscsi, lun, 0, data, block_size, block_size, 0, 1, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send write16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Write16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); if (!data_loss) { printf("--dataloss flag is not set. Skipping test\n"); ret = -1; goto finished; } printf("Write16 with FUA "); task = iscsi_write16_sync(iscsi, lun, 0, data, block_size, block_size, 0, 0, 1, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send write16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Write16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); printf("Write16 with FUA_NV "); task = iscsi_write16_sync(iscsi, lun, 0, data, block_size, block_size, 0, 0, 0, 1, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send write16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Write16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); printf("Write16 with FUA+FUA_NV "); task = iscsi_write16_sync(iscsi, lun, 0, data, block_size, block_size, 0, 0, 1, 1, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send write16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Write16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/iscsi-test.h0000644000175000017500000000732611750443164015672 0ustar mjtmjt/* iscsi-test tool Copyright (C) 2010 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ struct iscsi_context *iscsi_context_login(const char *initiatorname, const char *url, int *lun); extern int data_loss; int T0100_read10_simple(const char *initiator, const char *url); int T0101_read10_beyond_eol(const char *initiator, const char *url); int T0102_read10_0blocks(const char *initiator, const char *url); int T0103_read10_rdprotect(const char *initiator, const char *url); int T0104_read10_flags(const char *initiator, const char *url); int T0105_read10_invalid(const char *initiator, const char *url); int T0110_readcapacity10_simple(const char *initiator, const char *url); int T0111_readcapacity10_pmi(const char *initiator, const char *url); int T0120_read6_simple(const char *initiator, const char *url); int T0121_read6_beyond_eol(const char *initiator, const char *url); int T0122_read6_invalid(const char *initiator, const char *url); int T0130_verify10_simple(const char *initiator, const char *url); int T0131_verify10_mismatch(const char *initiator, const char *url); int T0132_verify10_mismatch_no_cmp(const char *initiator, const char *url); int T0160_readcapacity16_simple(const char *initiator, const char *url); int T0170_unmap_simple(const char *initiator, const char *url); int T0171_unmap_zero(const char *initiator, const char *url); int T0180_writesame10_unmap(const char *initiator, const char *url); int T0181_writesame10_unmap_unaligned(const char *initiator, const char *url); int T0190_writesame16_unmap(const char *initiator, const char *url); int T0191_writesame16_unmap_unaligned(const char *initiator, const char *url); int T0200_read16_simple(const char *initiator, const char *url); int T0201_read16_rdprotect(const char *initiator, const char *url); int T0202_read16_flags(const char *initiator, const char *url); int T0203_read16_0blocks(const char *initiator, const char *url); int T0204_read16_beyondeol(const char *initiator, const char *url); int T0210_read12_simple(const char *initiator, const char *url); int T0211_read12_rdprotect(const char *initiator, const char *url); int T0212_read12_flags(const char *initiator, const char *url); int T0213_read12_0blocks(const char *initiator, const char *url); int T0214_read12_beyondeol(const char *initiator, const char *url); int T0220_write16_simple(const char *initiator, const char *url); int T0221_write16_wrprotect(const char *initiator, const char *url); int T0222_write16_flags(const char *initiator, const char *url); int T0223_write16_0blocks(const char *initiator, const char *url); int T0224_write16_beyondeol(const char *initiator, const char *url); int T0230_write12_simple(const char *initiator, const char *url); int T0231_write12_wrprotect(const char *initiator, const char *url); int T0232_write12_flags(const char *initiator, const char *url); int T0233_write12_0blocks(const char *initiator, const char *url); int T0234_write12_beyondeol(const char *initiator, const char *url); int T0240_prefetch10_simple(const char *initiator, const char *url); int T0250_prefetch16_simple(const char *initiator, const char *url); libiscsi-1.4.0/test-tool/0130_verify10_simple.c0000644000175000017500000000656111750443164017257 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0130_verify10_simple(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_task *vtask; struct scsi_readcapacity10 *rc10; int ret, i, lun; uint32_t block_size, num_blocks; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0); if (task == NULL) { printf("Failed to send readcapacity10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("Readcapacity command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc10 = scsi_datain_unmarshall(task); if (rc10 == NULL) { printf("failed to unmarshall readcapacity10 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc10->block_size; num_blocks = rc10->lba; scsi_free_scsi_task(task); ret = 0; /* read and verify the first 1 - 256 blocks at the start of the LUN */ printf("Read+verify first 1-256 blocks ... "); for (i = 1; i <= 256; i++) { unsigned char *buf; task = iscsi_read10_sync(iscsi, lun, 0, i * block_size, block_size); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read10 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } buf = task->datain.data; if (buf == NULL) { printf("[FAILED]\n"); printf("Failed to access DATA-IN buffer %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } vtask = iscsi_verify10_sync(iscsi, lun, buf, i * block_size, 0, 0, 1, 1, block_size); if (vtask == NULL) { printf("[FAILED]\n"); printf("Failed to send verify10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } if (vtask->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Verify10 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); scsi_free_scsi_task(vtask); goto finished; } scsi_free_scsi_task(task); scsi_free_scsi_task(vtask); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0200_read16_simple.c0000644000175000017500000000627511750443164016674 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0200_read16_simple(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity10 *rc10; int ret, i, lun; uint32_t block_size, num_blocks; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0); if (task == NULL) { printf("Failed to send readcapacity10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("Readcapacity command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc10 = scsi_datain_unmarshall(task); if (rc10 == NULL) { printf("failed to unmarshall readcapacity10 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc10->block_size; num_blocks = rc10->lba; scsi_free_scsi_task(task); ret = 0; /* read the first 1 - 256 blocks at the start of the LUN */ printf("Reading first 1-256 blocks ... "); for (i=1; i<=256; i++) { task = iscsi_read16_sync(iscsi, lun, 0, i * block_size, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); /* read the last 1 - 256 blocks at the end of the LUN */ printf("Reading last 1-256 blocks ... "); for (i=1; i<=256; i++) { task = iscsi_read16_sync(iscsi, lun, num_blocks +1 - i, i * block_size, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0213_read12_0blocks.c0000644000175000017500000000665311750443164016740 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0213_read12_0blocks(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret = 0, i, lun; uint32_t block_size; uint64_t num_blocks; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall READCAPACITY16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; num_blocks = rc16->returned_lba; scsi_free_scsi_task(task); printf("Read12 0blocks at LBA:0 "); task = iscsi_read12_sync(iscsi, lun, 0, 0, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read12 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read12 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); printf("Read12 0blocks at LBA: "); task = iscsi_read12_sync(iscsi, lun, num_blocks, 0, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read12 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read12 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); printf("Read12 0blocks at LBA: "); task = iscsi_read12_sync(iscsi, lun, num_blocks + 1, 0, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read12 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read12 command: Should fail when reading 0blocks beyond end\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/iscsi-test.c0000644000175000017500000001761111750443164015663 0ustar mjtmjt/* iscsi-test tool Copyright (C) 2010 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include #include #include #include #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi.h" #include "iscsi-test.h" const char *initiator = "iqn.2010-11.iscsi-test"; int data_loss = 0; struct scsi_test { const char *name; int (*test)(const char *initiator, const char *url); }; struct scsi_test tests[] = { /* read10*/ { "T0100_read10_simple", T0100_read10_simple }, { "T0101_read10_beyond_eol", T0101_read10_beyond_eol }, { "T0102_read10_0blocks", T0102_read10_0blocks }, { "T0103_read10_rdprotect", T0103_read10_rdprotect }, { "T0104_read10_flags", T0104_read10_flags }, { "T0105_read10_invalid", T0105_read10_invalid }, /* readcapacity10*/ { "T0110_readcapacity10_simple", T0110_readcapacity10_simple }, { "T0111_readcapacity10_pmi", T0111_readcapacity10_pmi }, /* read6*/ { "T0120_read6_simple", T0120_read6_simple }, { "T0121_read6_beyond_eol", T0121_read6_beyond_eol }, { "T0122_read6_invalid", T0122_read6_invalid }, /* verify10*/ { "T0130_verify10_simple", T0130_verify10_simple }, { "T0131_verify10_mismatch", T0131_verify10_mismatch }, { "T0132_verify10_mismatch_no_cmp", T0132_verify10_mismatch_no_cmp }, /* readcapacity16*/ { "T0160_readcapacity16_simple", T0160_readcapacity16_simple }, /* unmap*/ { "T0170_unmap_simple", T0170_unmap_simple }, { "T0171_unmap_zero", T0171_unmap_zero }, /* writesame10*/ { "T0180_writesame10_unmap", T0180_writesame10_unmap }, { "T0181_writesame10_unmap_unaligned", T0181_writesame10_unmap_unaligned }, /* writesame16*/ { "T0190_writesame16_unmap", T0190_writesame16_unmap }, { "T0191_writesame16_unmap_unaligned", T0191_writesame16_unmap_unaligned }, /* read16*/ { "T0200_read16_simple", T0200_read16_simple }, { "T0201_read16_rdprotect", T0201_read16_rdprotect }, { "T0202_read16_flags", T0202_read16_flags }, { "T0203_read16_0blocks", T0203_read16_0blocks }, { "T0204_read16_beyondeol", T0204_read16_beyondeol }, /* read12*/ { "T0210_read12_simple", T0210_read12_simple }, { "T0211_read12_rdprotect", T0211_read12_rdprotect }, { "T0212_read12_flags", T0212_read12_flags }, { "T0213_read12_0blocks", T0213_read12_0blocks }, { "T0214_read12_beyondeol", T0214_read12_beyondeol }, /* write16*/ { "T0220_write16_simple", T0220_write16_simple }, { "T0221_write16_wrprotect", T0221_write16_wrprotect }, { "T0222_write16_flags", T0222_write16_flags }, { "T0223_write16_0blocks", T0223_write16_0blocks }, { "T0224_write16_beyondeol", T0224_write16_beyondeol }, /* write12*/ { "T0230_write12_simple", T0230_write12_simple }, { "T0231_write12_wrprotect", T0231_write12_wrprotect }, { "T0232_write12_flags", T0232_write12_flags }, { "T0233_write12_0blocks", T0233_write12_0blocks }, { "T0234_write12_beyondeol", T0234_write12_beyondeol }, /* prefetch10*/ { "T0240_prefetch10_simple", T0240_prefetch10_simple }, /* prefetch16*/ { "T0250_prefetch16_simple", T0250_prefetch16_simple }, { NULL, NULL } }; void print_usage(void) { fprintf(stderr, "Usage: iscsi-test [-?] [-?|--help] [--usage] [-t|--test=]\n" "\t\t[-l|--list] [-i|--initiator-name=]\n" "\t\t\n"); } void print_help(void) { fprintf(stderr, "Usage: iscsi-test [OPTION...] \n"); fprintf(stderr, " -i, --initiator-name=iqn-name Initiatorname to use\n"); fprintf(stderr, " -t, --test=test-name Which test to run. Default is to run all tests.\n"); fprintf(stderr, " -l, --list List all tests.\n"); fprintf(stderr, "\n"); fprintf(stderr, "Help options:\n"); fprintf(stderr, " -?, --help Show this help message\n"); fprintf(stderr, " --usage Display brief usage message\n"); fprintf(stderr, "\n"); fprintf(stderr, "iSCSI URL format : %s\n", ISCSI_URL_SYNTAX); fprintf(stderr, "\n"); fprintf(stderr, " is either of:\n"); fprintf(stderr, " \"hostname\" iscsi.example\n"); fprintf(stderr, " \"ipv4-address\" 10.1.1.27\n"); fprintf(stderr, " \"ipv6-address\" [fce0::1]\n"); } struct iscsi_context *iscsi_context_login(const char *initiatorname, const char *url, int *lun) { struct iscsi_context *iscsi; struct iscsi_url *iscsi_url; iscsi = iscsi_create_context(initiatorname); if (iscsi == NULL) { fprintf(stderr, "Failed to create context\n"); return NULL; } iscsi_url = iscsi_parse_full_url(iscsi, url); if (iscsi_url == NULL) { fprintf(stderr, "Failed to parse URL: %s\n", iscsi_get_error(iscsi)); iscsi_destroy_context(iscsi); return NULL; } iscsi_set_targetname(iscsi, iscsi_url->target); iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL); iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C); if (iscsi_url->user != NULL) { if (iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user, iscsi_url->passwd) != 0) { fprintf(stderr, "Failed to set initiator username and password\n"); iscsi_destroy_url(iscsi_url); iscsi_destroy_context(iscsi); return NULL; } } if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun) != 0) { fprintf(stderr, "Login Failed. %s\n", iscsi_get_error(iscsi)); iscsi_destroy_url(iscsi_url); iscsi_destroy_context(iscsi); return NULL; } if (lun != NULL) { *lun = iscsi_url->lun; } iscsi_destroy_url(iscsi_url); return iscsi; } int main(int argc, const char *argv[]) { poptContext pc; const char **extra_argv; int extra_argc = 0; const char *url = NULL; int show_help = 0, show_usage = 0, list_tests = 0; int res; struct scsi_test *test; char *testname = NULL; struct poptOption popt_options[] = { { "help", '?', POPT_ARG_NONE, &show_help, 0, "Show this help message", NULL }, { "usage", 0, POPT_ARG_NONE, &show_usage, 0, "Display brief usage message", NULL }, { "list", 'l', POPT_ARG_NONE, &list_tests, 0, "List all tests", NULL }, { "initiator-name", 'i', POPT_ARG_STRING, &initiator, 0, "Initiatorname to use", "iqn-name" }, { "test", 't', POPT_ARG_STRING, &testname, 0, "Which test to run", "testname" }, { "dataloss", 0, POPT_ARG_NONE, &data_loss, 0, "Allow destructuve tests", NULL }, POPT_TABLEEND }; pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_POSIXMEHARDER); if ((res = poptGetNextOpt(pc)) < -1) { fprintf(stderr, "Failed to parse option : %s %s\n", poptBadOption(pc, 0), poptStrerror(res)); exit(10); } extra_argv = poptGetArgs(pc); if (extra_argv) { url = *extra_argv; extra_argv++; while (extra_argv[extra_argc]) { extra_argc++; } } if (show_help != 0) { print_help(); exit(0); } if (show_usage != 0) { print_usage(); exit(0); } if (list_tests != 0) { for (test = &tests[0]; test->name; test++) { printf("%s\n", test->name); } exit(0); } poptFreeContext(pc); if (url == NULL) { fprintf(stderr, "You must specify the URL\n"); print_usage(); exit(10); } for (test = &tests[0]; test->name; test++) { if (testname != NULL && strcmp(testname, test->name)) { continue; } printf("=========\n"); printf("Running test %s\n", test->name); res = test->test(initiator, url); if (res == 0) { printf("TEST %s [OK]\n", test->name); } else { printf("TEST %s [FAILED]\n", test->name); } printf("\n"); } return 0; } libiscsi-1.4.0/test-tool/0240_prefetch10_simple.c0000644000175000017500000000627011750443164017552 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0240_prefetch10_simple(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret, i, lun; uint32_t block_size; uint64_t num_blocks; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall READCAPACITY16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; num_blocks = rc16->returned_lba; scsi_free_scsi_task(task); ret = 0; /* prefetch the first 1 - 256 blocks at the start of the LUN */ printf("Prefetching first 1-256 blocks ... "); for (i = 1; i <= 256; i++) { task = iscsi_prefetch10_sync(iscsi, lun, 0, i, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send prefetch10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Prefetch10 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); /* Prefetch the last 0 - 255 blocks at the end of the LUN */ printf("Prefetching last 0-255 blocks ... "); for (i = 0; i < 256; i++) { task = iscsi_prefetch10_sync(iscsi, lun, num_blocks - i, i, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send prefetch10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Prefetch10 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0103_read10_rdprotect.c0000644000175000017500000000670211750443164017400 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0103_read10_rdprotect(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; int full_size; struct scsi_inquiry_standard *inq; int ret, i, lun; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* See how big this inquiry data is */ task = iscsi_inquiry_sync(iscsi, lun, 0, 0, 64); if (task == NULL || task->status != SCSI_STATUS_GOOD) { printf("Inquiry command failed : %s\n", iscsi_get_error(iscsi)); return -1; } full_size = scsi_datain_getfullsize(task); if (full_size > task->datain.size) { scsi_free_scsi_task(task); /* we need more data for the full list */ if ((task = iscsi_inquiry_sync(iscsi, lun, 0, 0, full_size)) == NULL) { printf("Inquiry command failed : %s\n", iscsi_get_error(iscsi)); return -1; } } inq = scsi_datain_unmarshall(task); if (inq == NULL) { printf("failed to unmarshall inquiry datain blob\n"); scsi_free_scsi_task(task); return -1; } if (inq->periperal_device_type != SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS) { printf("LUN is not SBC device. Skipping test\n"); scsi_free_scsi_task(task); return -1; } if (inq->protect) { printf("LUN is formatted with protection information. Skipping test\n"); scsi_free_scsi_task(task); return -1; } scsi_free_scsi_task(task); ret = 0; /* Try out Different non-zero values for RDPROTECT. They should all fail */ printf("Read10 with non-zero RDPROTECT ... "); for (i = 1; i < 8; i++) { task = malloc(sizeof(struct scsi_task)); if (task == NULL) { printf("Failed to allocate task structure\n"); ret = -1; goto finished; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_READ10; task->cdb[1] = (i<<5)&0xe0; task->cdb[8] = 1; task->cdb_size = 10; task->xfer_dir = SCSI_XFER_READ; task->expxferlen = 512; if (iscsi_scsi_command_sync(iscsi, lun, task, NULL) == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST || task->sense.ascq != SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB) { printf("[FAILED]\n"); printf("Read10 with rdprotect should fail with ILLEGAL REQUEST/INVALID OPCODE\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0121_read6_beyond_eol.c0000644000175000017500000001234511750443164017436 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0121_read6_beyond_eol(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity10 *rc10; int ret, i, lun; uint32_t block_size, num_blocks; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0); if (task == NULL) { printf("Failed to send readcapacity10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("Readcapacity command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc10 = scsi_datain_unmarshall(task); if (rc10 == NULL) { printf("failed to unmarshall readcapacity10 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc10->block_size; num_blocks = rc10->lba; scsi_free_scsi_task(task); ret = 0; if (num_blocks > 0x1fffff) { printf("[SKIPPED]\n"); printf("Lun is too big for read-beyond-eol tests with read6\n"); goto finished; } /* read 1-256 blocks, one block beyond the end-of-lun */ printf("Reading last 1-256 blocks one block beyond eol ... "); for (i=1; i<=256; i++) { task = iscsi_read6_sync(iscsi, lun, num_blocks + 2 - i, i * block_size, block_size); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read6 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto test_2; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read6 beyond end-of-lun did not fail with sense.\n"); ret = -1; scsi_free_scsi_task(task); goto test_2; } if (task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST) { printf("[FAILED]\n"); printf("Read6 beyond end-of-lun did not return sense key ILLEGAL_REQUEST.\n"); ret = -1; scsi_free_scsi_task(task); goto test_2; } if (task->sense.ascq != SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE) { printf("[FAILED]\n"); printf("Read6 beyond end-of-lun did not return sense ascq LBA OUT OF RANGE.\n"); ret = -1; scsi_free_scsi_task(task); goto test_2; } scsi_free_scsi_task(task); } printf("[OK]\n"); test_2: /* read 2-256 blocks, all but one block beyond the eol */ printf("Reading 1-255 blocks beyond eol starting at last block ... "); for (i=2; i<=256; i++) { task = iscsi_read6_sync(iscsi, lun, num_blocks, i * block_size, block_size); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read6 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto test_3; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read6 beyond end-of-lun did not return sense.\n"); ret = -1; scsi_free_scsi_task(task); goto test_3; } if (task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST) { printf("[FAILED]\n"); printf("Read6 beyond end-of-lun did not return sense key ILLEGAL_REQUEST.\n"); ret = -1; scsi_free_scsi_task(task); goto test_3; } if (task->sense.ascq != SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE) { printf("[FAILED]\n"); printf("Read6 beyond end-of-lun did not return sense ascq LBA OUT OF RANGE.\n"); ret = -1; scsi_free_scsi_task(task); goto test_3; } scsi_free_scsi_task(task); } printf("[OK]\n"); test_3: /* read 0 (==256) blocks 128 blocks from eol */ printf("Reading 0(==256) blocks beyond eol starting at 128 blocks before eol ... "); task = iscsi_read6_sync(iscsi, lun, num_blocks-128, i * block_size, block_size); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read6 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read6 beyond end-of-lun did not return sense.\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } if (task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST) { printf("[FAILED]\n"); printf("Read6 beyond end-of-lun did not return sense key ILLEGAL_REQUEST.\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } if (task->sense.ascq != SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE) { printf("[FAILED]\n"); printf("Read6 beyond end-of-lun did not return sense ascq LBA OUT OF RANGE.\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0230_write12_simple.c0000644000175000017500000000657111750443164017111 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0230_write12_simple(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret, i, lun; uint32_t block_size; uint64_t num_blocks; unsigned char data[512 * 256]; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall READCAPACITY16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; num_blocks = rc16->returned_lba; scsi_free_scsi_task(task); if (!data_loss) { printf("--dataloss flag is not set. Skipping test\n"); ret = -1; goto finished; } ret = 0; /* write the first 1 - 256 blocks at the start of the LUN */ printf("Writing first 1-256 blocks ... "); for (i = 1; i <= 256; i++) { task = iscsi_write12_sync(iscsi, lun, 0, data, i * block_size, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send write12 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Write12 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); /* write the last 1 - 256 blocks at the end of the LUN */ printf("Writing last 1-256 blocks ... "); for (i = 1; i <= 256; i++) { task = iscsi_write12_sync(iscsi, lun, num_blocks +1 - i, data, i * block_size, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send write12 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Write12 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0202_read16_flags.c0000644000175000017500000000747511750443164016504 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0202_read16_flags(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret = 0, i, lun; uint32_t block_size; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall READCAPACITY16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; scsi_free_scsi_task(task); printf("Read16 with DPO "); task = iscsi_read16_sync(iscsi, lun, 0, block_size, block_size, 0, 1, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); printf("Read16 with FUA "); task = iscsi_read16_sync(iscsi, lun, 0, block_size, block_size, 0, 0, 1, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); printf("Read16 with FUA_NV "); task = iscsi_read16_sync(iscsi, lun, 0, block_size, block_size, 0, 0, 0, 1, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); printf("Read16 with FUA+FUA_NV "); task = iscsi_read16_sync(iscsi, lun, 0, block_size, block_size, 0, 0, 1, 1, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0171_unmap_zero.c0000644000175000017500000001233311750443164016417 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0171_unmap_zero(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret, i, lun; uint32_t block_size, num_blocks; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send readcapacity16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("Readcapacity command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall readcapacity16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } if (rc16->lbpme == 0){ printf("Logical unit is fully provisioned. Skipping test\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; num_blocks = rc16->returned_lba; scsi_free_scsi_task(task); if (!data_loss) { printf("data_loss flag is not set. Skipping test\n"); ret = -1; goto finished; } ret = 0; /* unmap no blocks at the first 0 - 256 blocks at the start of the LUN */ printf("Unmapping of no block at lbas 0-255 blocks ... "); for (i=0; i<=255; i++) { struct unmap_list list[1]; list[0].lba = i; list[0].num = 0; task = iscsi_unmap_sync(iscsi, lun, 0, 0, &list[0], 1); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send UNMAP command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("UNMAP command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); /* unmap no blocks at the last 0 - 255 blocks at the end of the LUN */ printf("Unmapping last 1-256 blocks ... "); for (i=0; i<=255; i++) { struct unmap_list list[1]; list[0].lba = num_blocks + 1 - i; list[0].num = 0; task = iscsi_unmap_sync(iscsi, lun, 0, 0, &list[0], 1); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send UNMAP command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("UNMAP command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); /* unmap no blocks 1-256 blocks beyond the end of the LUN */ printf("Unmapping no blocks but 1-256 blocks beyong end of LUN... "); for (i=1; i<=256; i++) { struct unmap_list list[1]; list[0].lba = num_blocks + 1 + i; list[0].num = 0; task = iscsi_unmap_sync(iscsi, lun, 0, 0, &list[0], 1); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send UNMAP command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("STATUS==GOOD. UNMAP command should fail with ILLEGAL_REQUEST/LBA_OUT_OF_RANGE.\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST || task->sense.ascq != SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE) { printf("[FAILED]\n"); printf("UNMAP fail but ascq was wrong. Should have failed with ILLEGAL_REQUEST/LBA_OUT_OF_RANGE.\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); /* unmap with no block descriptors at all */ printf("Unmap without any block descriptors ... "); task = iscsi_unmap_sync(iscsi, lun, 0, 0, NULL, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send UNMAP command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("UNMAP command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0170_unmap_simple.c0000644000175000017500000000702711750443164016734 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0170_unmap_simple(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret, i, lun; uint32_t block_size, num_blocks; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send readcapacity16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("Readcapacity command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall readcapacity16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } if (rc16->lbpme == 0){ printf("Logical unit is fully provisioned. Skipping test\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; num_blocks = rc16->returned_lba; scsi_free_scsi_task(task); if (!data_loss) { printf("data_loss flag is not set. Skipping test\n"); ret = -1; goto finished; } ret = 0; /* unmap the first 1 - 256 blocks at the start of the LUN */ printf("Unmapping first 1-256 blocks ... "); for (i=1; i<=256; i++) { struct unmap_list list[1]; list[0].lba = 0; list[0].num = i; task = iscsi_unmap_sync(iscsi, lun, 0, 0, &list[0], 1); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send UNMAP command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("UNMAP command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); /* unmap the last 1 - 256 blocks at the end of the LUN */ printf("Unmapping last 1-256 blocks ... "); for (i=1; i<=256; i++) { struct unmap_list list[1]; list[0].lba = num_blocks + 1 - i; list[0].num = i; task = iscsi_unmap_sync(iscsi, lun, 0, 0, &list[0], 1); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send UNMAP command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("UNMAP command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0122_read6_invalid.c0000644000175000017500000001540011750443164016741 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0122_read6_invalid(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct iscsi_data data; char buf[512]; int ret, lun; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } ret = 0; /* Try a read of 1 block but xferlength == 0 */ printf("Read6 1 block but with iscsi ExpectedDataTransferLength==0 ... "); task = malloc(sizeof(struct scsi_task)); if (task == NULL) { printf("Failed to allocate task structure\n"); ret = -1; goto finished; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_READ6; task->cdb[4] = 1; task->cdb_size = 6; task->xfer_dir = SCSI_XFER_READ; task->expxferlen = 0; if (iscsi_scsi_command_sync(iscsi, lun, task, NULL) == NULL) { printf("[FAILED]\n"); printf("Failed to send read6 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read6 of 1 block with iscsi ExpectedDataTransferLength==0 should not fail.\n"); ret = -1; scsi_free_scsi_task(task); goto test2; } if (task->residual_status != SCSI_RESIDUAL_OVERFLOW || task->residual != 512) { printf("[FAILED]\n"); printf("Read6 returned incorrect residual overflow.\n"); ret = -1; scsi_free_scsi_task(task); goto test5; } scsi_free_scsi_task(task); printf("[OK]\n"); test2: /* Try a read of 1 block but xferlength == 1024 */ printf("Read6 1 block but with iscsi ExpectedDataTransferLength==1024 ... "); task = malloc(sizeof(struct scsi_task)); if (task == NULL) { printf("Failed to allocate task structure\n"); ret = -1; goto finished; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_READ6; task->cdb[4] = 1; task->cdb_size = 6; task->xfer_dir = SCSI_XFER_READ; task->expxferlen = 1024; if (iscsi_scsi_command_sync(iscsi, lun, task, NULL) == NULL) { printf("[FAILED]\n"); printf("Failed to send read6 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read6 of 1 block with iscsi ExpectedDataTransferLength==1024 should not fail.\n"); ret = -1; scsi_free_scsi_task(task); goto test3; } if (task->residual_status != SCSI_RESIDUAL_UNDERFLOW || task->residual != 512) { printf("[FAILED]\n"); printf("Read6 returned incorrect residual underflow.\n"); ret = -1; scsi_free_scsi_task(task); goto test5; } scsi_free_scsi_task(task); printf("[OK]\n"); test3: /* Try a read of 1 block but xferlength == 200 */ printf("Read6 1 block but with iscsi ExpectedDataTransferLength==200 ... "); task = malloc(sizeof(struct scsi_task)); if (task == NULL) { printf("Failed to allocate task structure\n"); ret = -1; goto finished; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_READ6; task->cdb[4] = 1; task->cdb_size = 6; task->xfer_dir = SCSI_XFER_READ; task->expxferlen = 200; if (iscsi_scsi_command_sync(iscsi, lun, task, NULL) == NULL) { printf("[FAILED]\n"); printf("Failed to send read6 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read6 of 1 block with iscsi ExpectedDataTransferLength==200 should not fail.\n"); ret = -1; scsi_free_scsi_task(task); goto test4; } if (task->residual_status != SCSI_RESIDUAL_OVERFLOW || task->residual != 312) { printf("[FAILED]\n"); printf("Read6 returned incorrect residual overflow.\n"); ret = -1; scsi_free_scsi_task(task); goto test5; } scsi_free_scsi_task(task); printf("[OK]\n"); test4: /* Try a read of 2 blocks but xferlength == 512 */ printf("Read6 2 blocks but with iscsi ExpectedDataTransferLength==512 ... "); task = malloc(sizeof(struct scsi_task)); if (task == NULL) { printf("Failed to allocate task structure\n"); ret = -1; goto finished; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_READ6; task->cdb[4] = 2; task->cdb_size = 6; task->xfer_dir = SCSI_XFER_READ; task->expxferlen = 512; if (iscsi_scsi_command_sync(iscsi, lun, task, NULL) == NULL) { printf("[FAILED]\n"); printf("Failed to send read6 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read6 of 2 blocks with iscsi ExpectedDataTransferLength==512 should succeed.\n"); ret = -1; scsi_free_scsi_task(task); goto test5; } if (task->residual_status != SCSI_RESIDUAL_OVERFLOW || task->residual != 512) { printf("[FAILED]\n"); printf("Read6 returned incorrect residual overflow.\n"); ret = -1; scsi_free_scsi_task(task); goto test5; } scsi_free_scsi_task(task); printf("[OK]\n"); test5: /* Try a read of 1 block but make it a data-out write on the iscsi layer */ printf("Read6 of 1 block but sent as data-out write in iscsi layer ... "); task = malloc(sizeof(struct scsi_task)); if (task == NULL) { printf("Failed to allocate task structure\n"); ret = -1; goto finished; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_READ6; task->cdb[4] = 1; task->cdb_size = 6; task->xfer_dir = SCSI_XFER_WRITE; task->expxferlen = sizeof(buf); data.size = sizeof(buf); data.data = (unsigned char *)&buf[0]; if (iscsi_scsi_command_sync(iscsi, lun, task, &data) == NULL) { printf("[FAILED]\n"); printf("Failed to send read6 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read6 of 1 block but iscsi data-out write should fail.\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0104_read10_flags.c0000644000175000017500000001305011750443164016461 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0104_read10_flags(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; int ret, lun; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } ret = 0; /* Try out DPO : 1 */ printf("Read10 with DPO==1 ... "); task = malloc(sizeof(struct scsi_task)); if (task == NULL) { printf("Failed to allocate task structure\n"); ret = -1; goto finished; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_READ10; task->cdb[1] = 0x10; task->cdb[8] = 1; task->cdb_size = 10; task->xfer_dir = SCSI_XFER_READ; task->expxferlen = 512; if (iscsi_scsi_command_sync(iscsi, lun, task, NULL) == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read10 with DPO==1 Failed. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* Try out FUA : 1 FUA_NV : 0 */ printf("Read10 with FUA==1 FUA_NV==0 ... "); task = malloc(sizeof(struct scsi_task)); if (task == NULL) { printf("Failed to allocate task structure\n"); ret = -1; goto finished; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_READ10; task->cdb[1] = 0x08; task->cdb[8] = 1; task->cdb_size = 10; task->xfer_dir = SCSI_XFER_READ; task->expxferlen = 512; if (iscsi_scsi_command_sync(iscsi, lun, task, NULL) == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read10 with FUA==1 FUA_NV==0 Failed. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* Try out FUA : 1 FUA_NV : 1 */ printf("Read10 with FUA==1 FUA_NV==1 ... "); task = malloc(sizeof(struct scsi_task)); if (task == NULL) { printf("Failed to allocate task structure\n"); ret = -1; goto finished; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_READ10; task->cdb[1] = 0x0a; task->cdb[8] = 1; task->cdb_size = 10; task->xfer_dir = SCSI_XFER_READ; task->expxferlen = 512; if (iscsi_scsi_command_sync(iscsi, lun, task, NULL) == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read10 with FUA==1 FUA_NV==1 Failed. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* Try out FUA : 0 FUA_NV : 1 */ printf("Read10 with FUA==0 FUA_NV==1 ... "); task = malloc(sizeof(struct scsi_task)); if (task == NULL) { printf("Failed to allocate task structure\n"); ret = -1; goto finished; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_READ10; task->cdb[1] = 0x02; task->cdb[8] = 1; task->cdb_size = 10; task->xfer_dir = SCSI_XFER_READ; task->expxferlen = 512; if (iscsi_scsi_command_sync(iscsi, lun, task, NULL) == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read10 with FUA==0 FUA_NV==1 Failed. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* Try out DPO : 1 FUA : 1 FUA_NV : 1 */ printf("Read10 with DPO==1 FUA==1 FUA_NV==1 ... "); task = malloc(sizeof(struct scsi_task)); if (task == NULL) { printf("Failed to allocate task structure\n"); ret = -1; goto finished; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_READ10; task->cdb[1] = 0x18; task->cdb[8] = 1; task->cdb_size = 10; task->xfer_dir = SCSI_XFER_READ; task->expxferlen = 512; if (iscsi_scsi_command_sync(iscsi, lun, task, NULL) == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read10 with DPO==1 FUA==1 FUA_NV==0Failed. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0224_write16_beyondeol.c0000644000175000017500000000534711750443164017607 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0224_write16_beyondeol(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret, i, lun; uint32_t block_size; uint64_t num_blocks; unsigned char data[258 * 512]; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall READCAPACITY10 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; num_blocks = rc16->returned_lba; scsi_free_scsi_task(task); if (!data_loss) { printf("--dataloss flag is not set. Skipping test\n"); ret = -1; goto finished; } ret = 0; /* read 1 - 256 blocks beyond the end of the device */ printf("Writing 1-256 blocks beyond end-of-device ... "); for (i = 2; i <= 257; i++) { task = iscsi_write16_sync(iscsi, lun, num_blocks, data, i * block_size, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send write16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Write16 command should fail when writing beyond end of device\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0191_writesame16_unmap_unaligned.c0000644000175000017500000000577711750443164021655 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0191_writesame16_unmap_unaligned(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret, i, lun; uint32_t block_size, num_blocks; int lbppb; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send readcapacity16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("Readcapacity command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall readcapacity16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } if (rc16->lbpme == 0){ printf("Logical unit is fully provisioned. Skipping test\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; num_blocks = rc16->returned_lba; lbppb = 1 << rc16->lbppbe; scsi_free_scsi_task(task); if (lbppb < 2) { printf("LBPPB==%d Can not unmap fractional physical block\n", lbppb); ret = -1; goto finished; } if (!data_loss) { printf("--dataloss flag is not set. Skipping test\n"); ret = -1; goto finished; } ret = 0; /* unmap the first 1 - lbppb blocks at the start of the LUN */ printf("Unmapping first 1 - (LBPPB-1) blocks ... "); for (i=1; i < lbppb; i++) { task = iscsi_writesame16_sync(iscsi, lun, NULL, 0, 0, i, 0, 1, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send WRITESAME16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("WRITESAME16 command to unmap a fractional physical block should fail\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0211_read12_rdprotect.c0000644000175000017500000000541511750443164017402 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0211_read12_rdprotect(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret = 0, i, lun; uint32_t block_size, num_blocks; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall READCAPACITY16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; if(rc16->prot_en != 0) { printf("device is formatted with protection information, skipping test\n"); scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("Read12 with RDPROTECT "); for (i = 1; i <= 7; i++) { task = iscsi_read12_sync(iscsi, lun, 0, block_size, block_size, i, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read12 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST || task->sense.ascq != SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB) { printf("[FAILED]\n"); printf("Read12 with RDPROTECT!=0 should have failed with CHECK_CONDITION/ILLEGAL_REQUEST/INVALID_FIELD_IN_CDB\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0221_write16_wrprotect.c0000644000175000017500000000564411750443164017655 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0221_write16_wrprotect(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret = 0, i, lun; uint32_t block_size, num_blocks; unsigned char data[256 * 512]; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall READCAPACITY16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; if(rc16->prot_en != 0) { printf("device is formatted with protection information, skipping test\n"); scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); if (!data_loss) { printf("--dataloss flag is not set. Skipping test\n"); ret = -1; goto finished; } printf("Write16 with RDPROTECT "); for (i = 1; i <= 7; i++) { task = iscsi_write16_sync(iscsi, lun, 0, data, block_size, block_size, i, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send write16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST || task->sense.ascq != SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB) { printf("[FAILED]\n"); printf("Write16 with RDPROTECT!=0 should have failed with CHECK_CONDITION/ILLEGAL_REQUEST/INVALID_FIELD_IN_CDB\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0214_read12_beyondeol.c0000644000175000017500000000512111750443164017351 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0214_read12_beyondeol(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret, i, lun; uint32_t block_size; uint64_t num_blocks; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall READCAPACITY10 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; num_blocks = rc16->returned_lba; scsi_free_scsi_task(task); ret = 0; /* read 1 - 256 blocks beyond the end of the device */ printf("Reading 1-256 blocks beyond end-of-device ... "); for (i = 2; i <= 257; i++) { task = iscsi_read12_sync(iscsi, lun, num_blocks, i * block_size, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read12 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read12 command should fail when reading beyond end of device\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0201_read16_rdprotect.c0000644000175000017500000000541511750443164017405 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0201_read16_rdprotect(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret = 0, i, lun; uint32_t block_size, num_blocks; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall READCAPACITY16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; if(rc16->prot_en != 0) { printf("device is formatted with protection information, skipping test\n"); scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("Read16 with RDPROTECT "); for (i = 1; i <= 7; i++) { task = iscsi_read16_sync(iscsi, lun, 0, block_size, block_size, i, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST || task->sense.ascq != SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB) { printf("[FAILED]\n"); printf("Read16 with RDPROTECT!=0 should have failed with CHECK_CONDITION/ILLEGAL_REQUEST/INVALID_FIELD_IN_CDB\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0111_readcapacity10_pmi.c0000644000175000017500000001223611750443164017673 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0111_readcapacity10_pmi(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; int ret, lun; struct scsi_readcapacity10 *rc10; uint32_t block_size, num_blocks; ret = 0; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0); if (task == NULL) { printf("Failed to send readcapacity10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("Readcapacity command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc10 = scsi_datain_unmarshall(task); if (rc10 == NULL) { printf("failed to unmarshall readcapacity10 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc10->block_size; num_blocks = rc10->lba; scsi_free_scsi_task(task); /* lba != 0 and pmi == 0 is an error */ printf("Readcapacity10 PMI==0 LBA!=0 ... "); task = iscsi_readcapacity10_sync(iscsi, lun, 10, 0); if (task == NULL) { printf("Failed to send readcapacity10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST || task->sense.ascq !=SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB ) { printf("[FAILED]\n"); printf("Readcapacity10 PMI==0 and LBA!=0 should fail with sense code.\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* PMI==1 LBA==0 */ printf("Readcapacity10 PMI==1 LBA==0 ... "); task = iscsi_readcapacity10_sync(iscsi, lun, 0, 1); if (task == NULL) { printf("Failed to send readcapacity10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Readcapacity10 PMI==1 and LBA==0 should not fail with sense code.\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* PMI==1 LBA==EOL-1 */ printf("Readcapacity10 PMI==1 LBA==EOL-1 ... "); task = iscsi_readcapacity10_sync(iscsi, lun, num_blocks-1, 1); if (task == NULL) { printf("Failed to send readcapacity10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Readcapacity10 PMI==1 and LBA==EOL-1 should not fail with sense code.\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* PMI==1 LBA==EOL */ printf("Readcapacity10 PMI==1 LBA==EOL ... "); task = iscsi_readcapacity10_sync(iscsi, lun, num_blocks, 1); if (task == NULL) { printf("Failed to send readcapacity10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Readcapacity10 PMI==1 and LBA==EOL should not fail with sense code.\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* PMI==1 LBA==EOL+1 */ printf("Readcapacity10 PMI==1 LBA==EOL+1 ... "); task = iscsi_readcapacity10_sync(iscsi, lun, num_blocks+1, 1); if (task == NULL) { printf("Failed to send readcapacity10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Readcapacity10 PMI==1 and LBA==EOL+1 should not fail with sense code.\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* PMI==1 LBA==-1 */ printf("Readcapacity10 PMI==1 LBA==-1 ... "); task = iscsi_readcapacity10_sync(iscsi, lun, 0xffffffff, 1); if (task == NULL) { printf("Failed to send readcapacity10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Readcapacity10 PMI==1 and LBA==-1 should not fail with sense code.\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0100_read10_simple.c0000644000175000017500000000623711750443164016663 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0100_read10_simple(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity10 *rc10; int ret, i, lun; uint32_t block_size, num_blocks; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0); if (task == NULL) { printf("Failed to send readcapacity10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("Readcapacity command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc10 = scsi_datain_unmarshall(task); if (rc10 == NULL) { printf("failed to unmarshall readcapacity10 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc10->block_size; num_blocks = rc10->lba; scsi_free_scsi_task(task); ret = 0; /* read the first 1 - 256 blocks at the start of the LUN */ printf("Reading first 1-256 blocks ... "); for (i=1; i<=256; i++) { task = iscsi_read10_sync(iscsi, lun, 0, i * block_size, block_size); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read10 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); /* read the last 1 - 256 blocks at the end of the LUN */ printf("Reading last 1-256 blocks ... "); for (i=1; i<=256; i++) { task = iscsi_read10_sync(iscsi, lun, num_blocks +1 - i, i * block_size, block_size); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read10 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0234_write12_beyondeol.c0000644000175000017500000000534711750443164017604 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0234_write12_beyondeol(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret, i, lun; uint32_t block_size; uint64_t num_blocks; unsigned char data[258 * 512]; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall READCAPACITY10 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; num_blocks = rc16->returned_lba; scsi_free_scsi_task(task); if (!data_loss) { printf("--dataloss flag is not set. Skipping test\n"); ret = -1; goto finished; } ret = 0; /* read 1 - 256 blocks beyond the end of the device */ printf("Writing 1-256 blocks beyond end-of-device ... "); for (i = 2; i <= 257; i++) { task = iscsi_write12_sync(iscsi, lun, num_blocks, data, i * block_size, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send write12 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Write12 command should fail when writing beyond end of device\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0190_writesame16_unmap.c0000644000175000017500000000727411750443164017620 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0190_writesame16_unmap(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret, i, lun; uint32_t block_size, num_blocks; int lbppb; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send readcapacity16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("Readcapacity command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall readcapacity16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } if (rc16->lbpme == 0){ printf("Logical unit is fully provisioned. Skipping test\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; num_blocks = rc16->returned_lba; lbppb = 1 << rc16->lbppbe; scsi_free_scsi_task(task); if (!data_loss) { printf("--dataloss flag is not set. Skipping test\n"); ret = -1; goto finished; } ret = 0; /* unmap the first 1 - 256 blocks at the start of the LUN */ printf("Unmapping first 1-256 blocks ... "); for (i=1; i<=256; i++) { /* only try unmapping whole physical blocks */ if (i % lbppb) { continue; } task = iscsi_writesame16_sync(iscsi, lun, NULL, 0, 0, i, 0, 1, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send WRITESAME16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("WRITESAME16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); /* unmap the last 1 - 256 blocks at the end of the LUN */ printf("Unmapping last 1-256 blocks ... "); for (i=1; i<=256; i++) { /* only try unmapping whole physical blocks */ if (i % lbppb) { continue; } task = iscsi_writesame16_sync(iscsi, lun, NULL, 0, num_blocks + 1 - i, i, 0, 1, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send WRITESAME16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("WRITESAME16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0212_read12_flags.c0000644000175000017500000000747511750443164016501 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0212_read12_flags(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret = 0, i, lun; uint32_t block_size; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall READCAPACITY16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; scsi_free_scsi_task(task); printf("Read12 with DPO "); task = iscsi_read12_sync(iscsi, lun, 0, block_size, block_size, 0, 1, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read12 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read12 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); printf("Read12 with FUA "); task = iscsi_read12_sync(iscsi, lun, 0, block_size, block_size, 0, 0, 1, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read12 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read12 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); printf("Read12 with FUA_NV "); task = iscsi_read12_sync(iscsi, lun, 0, block_size, block_size, 0, 0, 0, 1, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read12 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read12 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); printf("Read12 with FUA+FUA_NV "); task = iscsi_read12_sync(iscsi, lun, 0, block_size, block_size, 0, 0, 1, 1, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read12 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read12 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0101_read10_beyond_eol.c0000644000175000017500000001010711750443164017501 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0101_read10_beyond_eol(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity10 *rc10; int ret, i, lun; uint32_t block_size, num_blocks; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0); if (task == NULL) { printf("Failed to send readcapacity10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("Readcapacity command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc10 = scsi_datain_unmarshall(task); if (rc10 == NULL) { printf("failed to unmarshall readcapacity10 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc10->block_size; num_blocks = rc10->lba; scsi_free_scsi_task(task); ret = 0; /* read 1-256 blocks, one block beyond the end-of-lun */ printf("Reading last 1-256 blocks one block beyond eol ... "); for (i=1; i<=256; i++) { task = iscsi_read10_sync(iscsi, lun, num_blocks + 2 - i, i * block_size, block_size); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read10 beyond end-of-lun did not fail with sense.\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } if (task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST) { printf("[FAILED]\n"); printf("Read10 beyond end-of-lun did not return sense key ILLEGAL_REQUEST.\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } if (task->sense.ascq != SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE) { printf("[FAILED]\n"); printf("Read10 beyond end-of-lun did not return sense ascq LBA OUT OF RANGE.\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); /* read 2-256 blocks, all but one block beyond the eol */ printf("Reading 1-255 blocks beyond eol starting at last block ... "); for (i=2; i<=256; i++) { task = iscsi_read10_sync(iscsi, lun, num_blocks, i * block_size, block_size); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read10 beyond end-of-lun did not return sense.\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } if (task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST) { printf("[FAILED]\n"); printf("Read10 beyond end-of-lun did not return sense key ILLEGAL_REQUEST.\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } if (task->sense.ascq != SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE) { printf("[FAILED]\n"); printf("Read10 beyond end-of-lun did not return sense ascq LBA OUT OF RANGE.\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0181_writesame10_unmap_unaligned.c0000644000175000017500000000577711750443164021646 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0181_writesame10_unmap_unaligned(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret, i, lun; uint32_t block_size, num_blocks; int lbppb; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send readcapacity16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("Readcapacity command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall readcapacity16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } if (rc16->lbpme == 0){ printf("Logical unit is fully provisioned. Skipping test\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; num_blocks = rc16->returned_lba; lbppb = 1 << rc16->lbppbe; scsi_free_scsi_task(task); if (lbppb < 2) { printf("LBPPB==%d Can not unmap fractional physical block\n", lbppb); ret = -1; goto finished; } if (!data_loss) { printf("--dataloss flag is not set. Skipping test\n"); ret = -1; goto finished; } ret = 0; /* unmap the first 1 - lbppb blocks at the start of the LUN */ printf("Unmapping first 1 - (LBPPB-1) blocks ... "); for (i=1; i < lbppb; i++) { task = iscsi_writesame10_sync(iscsi, lun, NULL, 0, 0, i, 0, 1, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send WRITESAME10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("WRITESAME10 command to unmap a fractional physical block should fail\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0110_readcapacity10_simple.c0000644000175000017500000000371711750443164020402 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0110_readcapacity10_simple(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity10 *rc10; int ret, lun; ret = 0; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } printf("Test that Readcapacity10 is supported ... "); task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send readcapacity10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Readcapacity command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc10 = scsi_datain_unmarshall(task); if (rc10 == NULL) { printf("[FAILED]\n"); printf("failed to unmarshall readcapacity10 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0210_read12_simple.c0000644000175000017500000000627511750443164016671 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0210_read12_simple(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity10 *rc10; int ret, i, lun; uint32_t block_size, num_blocks; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0); if (task == NULL) { printf("Failed to send readcapacity10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("Readcapacity command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc10 = scsi_datain_unmarshall(task); if (rc10 == NULL) { printf("failed to unmarshall readcapacity10 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc10->block_size; num_blocks = rc10->lba; scsi_free_scsi_task(task); ret = 0; /* read the first 1 - 256 blocks at the start of the LUN */ printf("Reading first 1-256 blocks ... "); for (i=1; i<=256; i++) { task = iscsi_read12_sync(iscsi, lun, 0, i * block_size, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read12 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read12 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); /* read the last 1 - 256 blocks at the end of the LUN */ printf("Reading last 1-256 blocks ... "); for (i=1; i<=256; i++) { task = iscsi_read12_sync(iscsi, lun, num_blocks +1 - i, i * block_size, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read12 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read12 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0232_write12_flags.c0000644000175000017500000000776111750443164016720 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0232_write12_flags(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret = 0, lun; uint32_t block_size; unsigned char data[256 * 512]; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall READCAPACITY16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; scsi_free_scsi_task(task); printf("Write12 with DPO "); task = iscsi_write12_sync(iscsi, lun, 0, data, block_size, block_size, 0, 1, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send write12 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Write12 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); if (!data_loss) { printf("--dataloss flag is not set. Skipping test\n"); ret = -1; goto finished; } printf("Write12 with FUA "); task = iscsi_write12_sync(iscsi, lun, 0, data, block_size, block_size, 0, 0, 1, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send write12 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Write12 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); printf("Write12 with FUA_NV "); task = iscsi_write12_sync(iscsi, lun, 0, data, block_size, block_size, 0, 0, 0, 1, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send write12 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Write12 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); printf("Write12 with FUA+FUA_NV "); task = iscsi_write12_sync(iscsi, lun, 0, data, block_size, block_size, 0, 0, 1, 1, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send write12 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Write12 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0203_read16_0blocks.c0000644000175000017500000000665311750443164016743 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0203_read16_0blocks(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret = 0, i, lun; uint32_t block_size; uint64_t num_blocks; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall READCAPACITY16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; num_blocks = rc16->returned_lba; scsi_free_scsi_task(task); printf("Read16 0blocks at LBA:0 "); task = iscsi_read16_sync(iscsi, lun, 0, 0, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); printf("Read16 0blocks at LBA: "); task = iscsi_read16_sync(iscsi, lun, num_blocks, 0, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); printf("Read16 0blocks at LBA: "); task = iscsi_read16_sync(iscsi, lun, num_blocks + 1, 0, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read16 command: Should fail when reading 0blocks beyond end\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0204_read16_beyondeol.c0000644000175000017500000000512111750443164017354 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0204_read16_beyondeol(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret, i, lun; uint32_t block_size; uint64_t num_blocks; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall READCAPACITY10 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; num_blocks = rc16->returned_lba; scsi_free_scsi_task(task); ret = 0; /* read 1 - 256 blocks beyond the end of the device */ printf("Reading 1-256 blocks beyond end-of-device ... "); for (i = 2; i <= 257; i++) { task = iscsi_read16_sync(iscsi, lun, num_blocks, i * block_size, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read16 command should fail when reading beyond end of device\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0220_write16_simple.c0000644000175000017500000000657111750443164017114 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0220_write16_simple(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret, i, lun; uint32_t block_size; uint64_t num_blocks; unsigned char data[512 * 256]; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall READCAPACITY16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; num_blocks = rc16->returned_lba; scsi_free_scsi_task(task); if (!data_loss) { printf("--dataloss flag is not set. Skipping test\n"); ret = -1; goto finished; } ret = 0; /* write the first 1 - 256 blocks at the start of the LUN */ printf("Writing first 1-256 blocks ... "); for (i = 1; i <= 256; i++) { task = iscsi_write16_sync(iscsi, lun, 0, data, i * block_size, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send write16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Write16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); /* write the last 1 - 256 blocks at the end of the LUN */ printf("Writing last 1-256 blocks ... "); for (i = 1; i <= 256; i++) { task = iscsi_write16_sync(iscsi, lun, num_blocks +1 - i, data, i * block_size, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send write16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Write16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0102_read10_0blocks.c0000644000175000017500000001015011750443164016716 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0102_read10_0blocks(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity10 *rc10; int ret, lun; uint32_t block_size, num_blocks; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0); if (task == NULL) { printf("Failed to send readcapacity10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("Readcapacity command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc10 = scsi_datain_unmarshall(task); if (rc10 == NULL) { printf("failed to unmarshall readcapacity10 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc10->block_size; num_blocks = rc10->lba; scsi_free_scsi_task(task); ret = 0; /* read10 0 blocks one block at lba 0 */ printf("Reading 0 blocks at lba:0 ... "); task = iscsi_read10_sync(iscsi, lun, 0, 0, block_size); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read10 of 0 at lba:0 failed with sense.\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* read10 0 blocks one block beyond the eol */ printf("Reading 0 blocks at one block beyond end ... "); task = iscsi_read10_sync(iscsi, lun, num_blocks + 1, 0, block_size); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read10 of 0 one block beyond end-of-lun failed with sense.\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* read10 0 blocks two blocks beyond the eol */ printf("Reading 0 blocks at two blocks beyond end ... "); task = iscsi_read10_sync(iscsi, lun, num_blocks + 1, 0, block_size); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read10 of 0 two blocks beyond end-of-lun failed with sense.\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* read10 0 at lba -1 */ printf("Reading 0 blocks at lba:-1 ... "); task = iscsi_read10_sync(iscsi, lun, 0xffffff, 0, block_size); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read10 of 0 at lba:-1 failed with sense.\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0132_verify10_mismatch_no_cmp.c0000644000175000017500000000707411750443164021130 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0132_verify10_mismatch_no_cmp(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_task *vtask; struct scsi_readcapacity10 *rc10; int ret, i, lun; uint32_t block_size, num_blocks; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0); if (task == NULL) { printf("Failed to send readcapacity10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("Readcapacity command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc10 = scsi_datain_unmarshall(task); if (rc10 == NULL) { printf("failed to unmarshall readcapacity10 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc10->block_size; num_blocks = rc10->lba; scsi_free_scsi_task(task); ret = 0; /* read and verify the first 1 - 256 blocks at the start of the LUN */ printf("Read+verify first 1-256 blocks ... "); for (i = 1; i <= 256; i++) { char *buf; task = iscsi_read10_sync(iscsi, lun, 0, i * block_size, block_size); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read10 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } buf = task->datain.data; if (buf == NULL) { printf("[FAILED]\n"); printf("Failed to access DATA-IN buffer %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } /* flip a random byte in the data */ buf[random() % task->datain.size] ^= 'X'; /* bytechk == 0 ==> target should NOT compate the data so should not detect the mismatch. */ vtask = iscsi_verify10_sync(iscsi, lun, buf, i * block_size, 0, 0, 1, 0, block_size); if (vtask == NULL) { printf("[FAILED]\n"); printf("Failed to send verify10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } if (vtask->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Verify10 returned sense but BYTCHK==1 means it should not check/compare the data.\n"); ret = -1; scsi_free_scsi_task(task); scsi_free_scsi_task(vtask); goto finished; } scsi_free_scsi_task(task); scsi_free_scsi_task(vtask); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0131_verify10_mismatch.c0000644000175000017500000000743511750443164017575 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0131_verify10_mismatch(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_task *vtask; struct scsi_readcapacity10 *rc10; int ret, i, lun; uint32_t block_size, num_blocks; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0); if (task == NULL) { printf("Failed to send readcapacity10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("Readcapacity command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc10 = scsi_datain_unmarshall(task); if (rc10 == NULL) { printf("failed to unmarshall readcapacity10 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc10->block_size; num_blocks = rc10->lba; scsi_free_scsi_task(task); ret = 0; /* read and verify the first 1 - 256 blocks at the start of the LUN */ printf("Read+verify first 1-256 blocks ... "); for (i = 1; i <= 256; i++) { unsigned char *buf; task = iscsi_read10_sync(iscsi, lun, 0, i * block_size, block_size); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read10 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } buf = task->datain.data; if (buf == NULL) { printf("[FAILED]\n"); printf("Failed to access DATA-IN buffer %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } /* flip a random byte in the data */ buf[random() % task->datain.size] ^= 'X'; vtask = iscsi_verify10_sync(iscsi, lun, buf, i * block_size, 0, 0, 1, 1, block_size); if (vtask == NULL) { printf("[FAILED]\n"); printf("Failed to send verify10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } if (vtask->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Verify10 command returned sense ok but the data is not matching.\n"); ret = -1; scsi_free_scsi_task(task); scsi_free_scsi_task(vtask); goto finished; } if (vtask->sense.key != SCSI_SENSE_MISCOMPARE) { printf("[FAILED]\n"); printf("Verify10 command returned wrong sense key. MISCOMPARE 0x%x expected but got key 0x%x\n", SCSI_SENSE_MISCOMPARE, vtask->sense.key); ret = -1; scsi_free_scsi_task(task); scsi_free_scsi_task(vtask); goto finished; } scsi_free_scsi_task(task); scsi_free_scsi_task(vtask); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0180_writesame10_unmap.c0000644000175000017500000000727411750443164017611 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0180_writesame10_unmap(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret, i, lun; uint32_t block_size, num_blocks; int lbppb; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send readcapacity16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("Readcapacity command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall readcapacity16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } if (rc16->lbpme == 0){ printf("Logical unit is fully provisioned. Skipping test\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; num_blocks = rc16->returned_lba; lbppb = 1 << rc16->lbppbe; scsi_free_scsi_task(task); if (!data_loss) { printf("--dataloss flag is not set. Skipping test\n"); ret = -1; goto finished; } ret = 0; /* unmap the first 1 - 256 blocks at the start of the LUN */ printf("Unmapping first 1-256 blocks ... "); for (i=1; i<=256; i++) { /* only try unmapping whole physical blocks */ if (i % lbppb) { continue; } task = iscsi_writesame10_sync(iscsi, lun, NULL, 0, 0, i, 0, 1, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send WRITESAME10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("WRITESAME10 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); /* unmap the last 1 - 256 blocks at the end of the LUN */ printf("Unmapping last 1-256 blocks ... "); for (i=1; i<=256; i++) { /* only try unmapping whole physical blocks */ if (i % lbppb) { continue; } task = iscsi_writesame10_sync(iscsi, lun, NULL, 0, num_blocks + 1 - i, i, 0, 1, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send WRITESAME10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("WRITESAME10 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0223_write16_0blocks.c0000644000175000017500000000706711750443164017164 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0223_write16_0blocks(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret = 0, i, lun; uint32_t block_size; uint64_t num_blocks; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall READCAPACITY16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; num_blocks = rc16->returned_lba; scsi_free_scsi_task(task); if (!data_loss) { printf("--dataloss flag is not set. Skipping test\n"); ret = -1; goto finished; } printf("Write16 0blocks at LBA:0 "); task = iscsi_write16_sync(iscsi, lun, 0, NULL, 0, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send write16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Write16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); printf("Write16 0blocks at LBA: "); task = iscsi_write16_sync(iscsi, lun, num_blocks, NULL, 0, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send write16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Write16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); printf("Write16 0blocks at LBA: "); task = iscsi_write16_sync(iscsi, lun, num_blocks + 1, NULL, 0, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send write16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Write16 command: Should fail when writing 0blocks beyond end\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0120_read6_simple.c0000644000175000017500000000502711750443164016606 0ustar mjtmjt/* Copyright (C) 2010 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0120_read6_simple(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity10 *rc10; int ret, i, lun; uint32_t block_size, num_blocks; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0); if (task == NULL) { printf("Failed to send readcapacity10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("Readcapacity command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc10 = scsi_datain_unmarshall(task); if (rc10 == NULL) { printf("failed to unmarshall readcapacity10 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc10->block_size; num_blocks = rc10->lba; scsi_free_scsi_task(task); ret = 0; /* read the first 1 - 256 blocks at the start of the LUN */ printf("Reading first 1-256 blocks ... "); for (i = 1; i <= 256; i++) { task = iscsi_read6_sync(iscsi, lun, 0, i * block_size, block_size); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send read6 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Read6 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; } libiscsi-1.4.0/test-tool/0250_prefetch16_simple.c0000644000175000017500000000627211750443164017563 0ustar mjtmjt/* Copyright (C) 2012 by Ronnie Sahlberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" int T0250_prefetch16_simple(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret, i, lun; uint32_t block_size; uint64_t num_blocks; iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall READCAPACITY16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; num_blocks = rc16->returned_lba; scsi_free_scsi_task(task); ret = 0; /* prefetch the first 1 - 256 blocks at the start of the LUN */ printf("Prefetching first 1-256 blocks ... "); for (i = 1; i <= 256; i++) { task = iscsi_prefetch16_sync(iscsi, lun, 0, i, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send prefetch16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Prefetch16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); /* Prefetch the last 0 - 255 blocks at the end of the LUN */ printf("Prefetching last 0-255 blocks ... "); for (i = 0; i < 256; i++) { task = iscsi_prefetch16_sync(iscsi, lun, num_blocks - i, i, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send prefetch16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Prefetch16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; }