[
  {
    "path": ".clang-format",
    "content": "BasedOnStyle: LLVM\nIndentWidth: 4\nUseTab: Always\nTabWidth: 4\nColumnLimit: 0\n\n# --- Includes ---\nIncludeBlocks: Preserve\nSortIncludes: false\n\n# --- Initializers ---\nAllowShortBlocksOnASingleLine: Always\nAllowShortCaseLabelsOnASingleLine: true\nAllowShortFunctionsOnASingleLine: All\nAllowShortIfStatementsOnASingleLine: true\nAllowShortLoopsOnASingleLine: true\n\n# --- Alignement ---\nAlignConsecutiveAssignments: true\nAlignConsecutiveDeclarations: true\nAlignConsecutiveMacros: true\nBinPackArguments: true\nBinPackParameters: true"
  },
  {
    "path": ".github/workflows/codeql.yml",
    "content": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# You may wish to alter this file to override the set of languages analyzed,\n# or to provide custom queries or build logic.\n#\n# ******** NOTE ********\n# We have attempted to detect the languages in your repository. Please check\n# the `language` matrix defined below to confirm you have the correct set of\n# supported CodeQL languages.\n#\nname: \"CodeQL\"\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    # The branches below must be a subset of the branches above\n    branches: [ master ]\n  schedule:\n    - cron: '43 6 * * 5'\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-latest\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n\n    strategy:\n      fail-fast: false\n      matrix:\n        language: [ 'cpp' ]\n        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]\n        # Learn more about CodeQL language support at https://git.io/codeql-language-support\n\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v2\n\n    # Initializes the CodeQL tools for scanning.\n    - name: Initialize CodeQL\n      uses: github/codeql-action/init@v1\n      with:\n        languages: ${{ matrix.language }}\n        # If you wish to specify custom queries, you can do so here or in a config file.\n        # By default, queries listed here will override any specified in a config file.\n        # Prefix the list here with \"+\" to use these queries and those in the config file.\n        # queries: ./path/to/local/query, your-org/your-repo/queries@main\n\n    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).\n    # If this step fails, then you should remove it and run the build manually (see below)\n    - name: Autobuild\n      uses: github/codeql-action/autobuild@v1\n\n    # ℹ️ Command-line programs to run using the OS shell.\n    # 📚 https://git.io/JvXDl\n\n    # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines\n    #    and modify them (or add more) to build your code if your project\n    #    uses a compiled language\n\n    #- run: |\n    #   make bootstrap\n    #   make release\n\n    - name: Perform CodeQL Analysis\n      uses: github/codeql-action/analyze@v1\n"
  },
  {
    "path": ".gitignore",
    "content": "*.ko\n*.o\n*~\n/cscope.*\n/kernel/.*.ko.cmd\n/kernel/.*.o.cmd\n/kernel/.tmp_versions/\n/kernel/mhvtl.mod.c\n/kernel/Module.symvers\n/kernel/modules.order\n/kernel/config.h\n/scripts/update_device.conf\n/man/*.1\n/man/*.5\n/tcopy/tcopy\nlocal.mk\nmhvtl_kernel.tgz\n/usr/mhvtl_kernel_mod_build\n\n# Vagrant specific files\n/vagrant/.vagrant\n/vagrant/*.log\n"
  },
  {
    "path": "COPYING",
    "content": "\n Note that the GPL below is copyrighted by the Free Software\n Foundation, but the instance of code that it refers to\n (the 'mhvtl' user-space and kernel) is copyrighted by me and\n others who actually wrote it.\n\n Also note that the only valid version of the GPL as far as the kernel\n is concerned is _this_ particular version of the license (ie v2, not\n v2.2 or v3.x or whatever), unless explicitly otherwise stated.\n\n\t\t\tMark Harvey\n\n----------------------------------------\n\n\t\t    GNU GENERAL PUBLIC LICENSE\n\t\t       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n\t\t\t    Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Library General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\f\n\t\t    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\f\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\f\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\f\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n\t\t\t    NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n\t\t     END OF TERMS AND CONDITIONS\n\f\n\t    How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program; if not, write to the Free Software\n    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) year name of author\n    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may\nbe called something other than `show w' and `show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n  `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n  <signature of Ty Coon>, 1 April 1989\n  Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Library General\nPublic License instead of this License.\n"
  },
  {
    "path": "ChangeLog",
    "content": "* Tue Mar 10 17:30:00 AEST 2026 Mark Harvey <markh794@gmail.com>\n- A hugh patch set to add LTFS support. Many thanks to QuentinLoriaux\n\n* Tue Mar 10 16:30:00 AEST 2026 Mark Harvey <markh794@gmail.com>\n- mhvtl.ko: Various updates to keep track of recent mainline changes\n- add GET/SET TIMESTAMP OP code support\n- fix for Logical Block Protection\n\n* Mon Mar 10 12:11:00 AEST 2025 Mark Harvey <markh794@gmail.com>\n- Remove reference to Nutanix as I no longer work there\n- Implement Logical Block Protection for LTO emulations\n- mhvtl.ko: Update to support recent kernel changes\n- more 32/64bit cast fixes (Raspberry-Pi) & x86_64\n- Fix issue with helper script creating WORM media (Thanks Gaurav Malhotra)\n- Initial LTO-9 emulation (Thanks Gwen Dawes)\n- daemon exit strategy change - reduce possibility of shutdown during inflight I/O\n- Fix READ POSITION\n- Implement VHF log page\n- Reduce calls to fflush() unless in debug mode\n\n* Fri Mar 10 16:30:00 AEST 2023 Mark Harvey <markh794@gmail.com> <mark.harvey@nutanix.com>\n- review of all utilities and use '-m <barcode>' the standard option\n- Add support for 'INQUIRY_DATA_HAS_CHANGED'\n- Added 'Extended Inquiry Data VPD page for Ultrium\n- Add SELinux ACL so systemctl scripts will work if SELinux is enforcing\n- mhvtl.ko: Various improvements to suit recent kernel changes (thanks Lee Duncan and Tamas Revesz)\n- mhvtl.ko: Change initiator ID from 15 to -1 (resolves conflict if target also configured with ID 15)\n- mhvtl.ko: Remove printk in favour of pr_* calls\n- pre-package mhvtl.ko source into /usr/lib/firmware/mhvtl/ and add wrapper script 'mhvtl_kernel_mod_build' to extract, compile and install\n- Various 64bit/32bit casts fixed.\n- Updated Vagrant to use AlmaLinux, RockyLinux, CentOS, OpenSuse, Ubuntu\n\n* Thu Mar 10 10:30:00 AEST 2022 Mark Harvey <markh794@gmail.com> <mark.harvey@nutanix.com>\n- Updated default drives in library 10 from LTO4/LTO5 to LTO6 & LTO8\n- Added initial support for Data Integrity Validation (via Logical Block Protection) - IBM LTO6,LTO7 & LTO8 with this release.\n- mhvtl.ko: Various updates to match the latest kernels\n- Additional checks for Vagrant build on CentOS, Ubuntu and OpenSUSE\n- Improve tape load/unload handshake to make it more robust\n- Improve handling of missing slot numbers in library_contents.xx\n- Makefile - Move variables to a common location (config.mk)\n- SEND DIAGNOSTICS: Implement basic sanity check for SSC devices\n- VERIFY(6) op code support\n- Update install instructions with sg3_utils vs sg3-utils package names\n- LTO-6 media load to match LTO standards (LTO8 cannot read LTO6 media)\n- New utility 'preload_tape' bypassing need to write via /dev/st*\n- Add missing 'ENCRYPTION capable' bit for LTO6, 7 & 8 media\n- systemd device config: Best effort, log errors via klog\n- Obligatory spelling fixes\n- Bump version to 1.7 : Beginning of LBP, VERIFY(6) and SEND DIAGNOSTICS support\n\n* Thu Oct 07 10:40:00 AEST 2021 Mark Harvey <markh794@gmail.com> <mark.harvey@nutanix.com>\n- rename list.h to avoid generic name conflict\n- rename scsi.h to avoid generic name conflict\n- rename log.h to avoid generic name conflict\n- Exclude __builtin_cpu_supports() on non x86_64 CPU types\n- Fix spelling of retrieving\n- mhvtl.ko: Define SG_SEGMENT_SZ only if not defined\n- Increase default kmem_cache bounce buffer size to 64k\n- mhvtl.ko: kernel module oops on PPC\n- mhvtl.ko: Log errors if they occur\n- mhvtl.ko: Correct compiler warning about printf var sizes\n- mhvtl.ko: Simplify file_inode()\n- mhvtl.ko: Use _safe version of list_for_each_entry\n- mhvtl.ko: Limit number of outstanding queued commands\n- mhvtl.ko: Log minor number with other ioctl info\n- mhvtl.ko: clean up noisy logging at level 2\n- mhvtl.ko: Initialise outstanding op struct before adding to list\n- mktape: Set default version string based from MHVTL_VERSION\n- Update LTO-8 media denisty codes\n- Security Protocol OUT: Fix null pointer check\n- Fix routine to extract barcode from string\n- Fix typos in mktape man page\n- dump_tape: Fix segfault due to local variable conflict\n- Use bounce buffer if tape block size is larger than request buffer\n- Remove unused scsi_host_template field\n- mhvtl.ko: Compile on RedHat 8.x kernel\n- mhvtl.ko: reinstate HAVE_UNLOCKED_IOCTL\n- mhvtl.ko: Remove reference to DRIVER_SENSE\n- Update function names with 'mhvtl_' prefix\n- Update kernel /sys/ location to suit new pseudo name space\n- OOM: /proc/<pid>/oom_adj is deprecated. Using oom_score_adj.\n- systemd: Update Makefile to include systemd install path\n- mhvtl.spec: Update to build a package on CentOS8\n\n* Tue Mar 10 09:00:00 AEST 2020 Mark Harvey <markh794@gmail.com> <mark.harvey@nutanix.com>\n- Fix kernel module oops/panic due to race between placing OP ready for user space before all variable were initialised\n- Add ccan version of crc32c routine which includes CPU optimisations for sse4.2 capabile CPUs\n\n* Sun Oct 06 12:20:00 AEST 2019 Mark Harvey <markh794@gmail.com> <mark.harvey@nutanix.com>\n- Fix kernel copy_to_user()/copy_from_user() to use white-listed buffer\n- Fix kernel compile for 5.0+ kernels\n\n* Wed Apr 10 10:30:30 AEST 2019 Mark Marvey <markh794@gmail.com> <mark.harvey@nutanix.com>\n- Fix long standing bug on media unload\n- Added CRC32 checks for each block written/read\n- allow kernel module to compile on 5.0 kernels\n- Add example on how to configure LIO pscsi (passthru) driver with mhVTL\n- Fix parsing args in dump_tape\n\n* Thu Mar 28 14:30:30 AEST 2019 Mark Marvey <markh794@gmail.com> <mark.harvey@nutanix.com>\n- Create virtual media on rpm install\n- Fixed a couple typos in spec file (one from several years ago)\n- Don’t overwrite /etc/mhvtl/* but install as ‘rpmnew’\n- Replace SUSE specific rpm macros with hand crafted ’systemctl’ commands.\n- systems-generators dir needed munging for CentOS7\n- Include ‘ChangeLog’ as part of the tar ball - the time/date build on man pages is dependant\n\n* Thu Nov 29 15:42:24 PST 2018 Lee Duncan <lduncan@suse.com>\n- Many changes to support systemd:\n  - Removed /etc/init.d/mhvtl script\n  - Config files are now generated at install time, not the first\n    time the service is run\n  - Created service files and templates, and a generator\n  - Updated INSTALL file with sytemd info\n  - removed build_library_config and mhvtl init script\n  - Updated man pages and doc/index.html\n  - Updated make files\n  - created generate_device_conf and generate_library_contents, called at\n    'make install' time, to take the place of what the init file used to do\n  - updated SPEC file for systemd\n  - updated example scripts\n  - fixed asprintf calls to check return values (to make compiler happy)\n  - added some arguments and better arg parsing to vtltape and vtllibray\n- moved some .gitignore entries around, to be more local\n- Bumped version to 1.5-5\n- Fixed config file error in library_contents.* where VERSION was missing\n\n* Thu Sep 7 2014 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 1.5-2\n- Fix vtllibrary segfault using 'default' emulation\n- Correct slot mappings for L180/L700 emulation\n- Correct slot mappings for SL500 emulation\n- Increase max serial number length to 15 chars\n- More accurate emulation of IBM TS3100/3200 inquiry page bits\n- Fix bug with 'edit_tape' not understanding the 'null' media type\n\n* Thu May 1 2014 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 1.5-1\n- Fix bug with vpd pages 0x80 & 0x83 in library personality modules.\n\n* Sun Apr 13 2014 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 1.5-0\n- Introduce library personality modules - limited emulations\n- Resolve bug with more than 1260 slots\n- Rename mhvtl bus type so scsi_debug & mhvtl can load together.\n\n* Sun Oct 20 2013 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 1.4-10\n- Various cleanups due to static code check 'smatch'\n- Fix TapeAlert bit offsets\n- Return bit/byte offset for sense INVALID FIELD IN CDB/PARAMS\n- Fix returned data size when 0 data is requested (kernel module fix)\n- SSC - Fix op code 0Fh (read reverse) incorrectly set to 'reserve'\n- SMC - Ability to keep library media change persistant across restarts\n- SSC - Implement 'read media serial number' op code\n- Fix 'make_vtl_media' script to understand IBM 03592 media type\n\n* Thu Aug 29 2013 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 1.4-9\n- SSC -> MODE SELECT overhaul.\n- Sanitize delay values introduced in 1.4-8\n- daemons now open /dev/mhvtlXX nodes in exclusive mode\n- Code cleanup based on Valgrind - memory leaks and unused file handles\n- Correctly set SCSI revision field for T10000B\n- SMC -> Adjust behaviour if 'Scalar' library defined\n set 'BarC' field in inquiry page and\n pad \"Full Firmware Revision\" field with compile time/date\n\n* Sat Jun 29 2013 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 1.4-8\n- Add additional fields in MAM for multi-partition support capability\n- MODE SELECT fixes\n- Solaris 11.1 st mode select\n- Make virtual media more resilient against disk full conditions\n- Add additional error checking between kernel and userspace ioctl\n- Add ability to introduce delays in load/unload/position/thread/rewind op codes\n- Add 16byte CDB locate command support\n- Minor kernel module tweeks - increase timeout & error checking on ioctl()\n\n* Fri Mar 22 2013 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 1.4-7\n- Add DLT7000/DLT8000 emulation\n- Record 'last load' data in MAM\n- New utility 'edit_tape' which will allow modificiation of media 'meta data'\n- Prevent and log possibility of READ ELEMENT STATUS overflowing data buffer\n- Set 'POWERON-RESET' if library re-configured via HUP signal\n- Update 'minor' number from 'unsigned char' to 'unsigned int' which removes\n max number of device nodes at 256\n- Rework READ ELEMENT STATUS - Simplify code and correct bug where incorrect\n byte count returned.\n- Add 'support' for specifying 9x40 and DLT media via barcode suffix\n- Update kernel module to prevent overflow if DEF_MAX_MINOR_NO reached.\n- Update kernel module to allow up to 1024 minor numbers\n- Update kernel module vers to 0.18.12, vers date 20130310-0\n- off-by-one fix of compression mode page\n- Fix 'READ POSITION' ssc op code\n- Helper scripts for NetBackup added\n - drive_stats.pl (parse 'scsi_command' output and email on tape unload)\n - vlt_endeject_notify.pl (NetBackup Vault helper)\n\n* Sat Jan 31 2013 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 1.4-6\n- Return correct TAPE CAPACITY log page\n- Fix overflow TAPE CAPACITY log page\n- Fix potential vtltape segfault when 'block position back'\n- New utility 'edit_tape' to update virtual media metadata\n\n* Sat Jan 12 2013 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 1.4-5\n- Added support for LTO-6\n- Fix EOM handling\n- Fix data returned in TAPE CAPACITY log page\n\n* Thu Sep 13 2012 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 1.4-4\n- Fix a build issue on older (SLES9) linux distributions\n- Silence a compiler warning about uninitialised var 'month' in quantum PM\n- Note: 1.4-2 & 1.4-3 never made it as released packages.\n\n* Wed Sep 12 2012 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 1.4-3\n- Add 'performance' counter to vtllibrary\n- Fix off-by-one error in LOG SELECT\n- Implement LOG reset via PCR bit in LOG SELECT\n\n* Sat Sep 01 2012 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 1.4-2\n- Add 'performance' counter to each SCSI op code logged\n\n* Wed Aug 08 2012 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 1.4-1\n- Bug fix:\n  Fix dump_tape to understand new library subdirectory format\n  Fix vtlcmd to understand new library subdirectory format\n\n* Wed Aug 01 2012 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 1.4-0\n- Allow 'default' personality module to load all media R/W\n- Add IBM half-hight INQUIRY string match\n- vtltape: Update log entry regarding media capacity depending on capabilities\n- vtltape: Make the backoff algrithm value configurable\n- Add SDLT600 & SDLT320 personality module\n- mhvtl.ko: Silence install 'depmod' error\n- Move standard inquiry info into memory structure\n- Default media belonging to a library in a subdir\n- Remove kmod-mhvtl.spec\n- Rename 'mhvtl' package as 'mhvtl-utils'\n- Use ELRepo spec file\n- Move 'make install' from RPM to Makefile\n\n* Fri Jun 15 2012 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 1.3-0\n- Move 'on disk' unique functions into its own shared lib (libvtlcart.so)\n- HP Ultrium VPD page data update to match HP documentation\n- IBM Ultrium VPD page 0xC0 & 0xC1 update to match IBM documentation\n- Fix SPIN return status\n- Add helper functions for moving media within library\n  (in prep for library partition manager)\n- Add ability to set/clear APPEND ONLY status from user (vtlcmd)\n\n* Wed Apr 04 2012 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 1.2-3\n- Fix segfault in AIT4 when attempting to access Security Protocol IN/OUT\n- No need to fail in virtual media parent directory exists\n- Add more descriptive debug messages for log/mode page lookups\n\n* Thu Mar 22 2012 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 1.2-2\n- Changed defaults so fifo is not enabled. If fifo not used, it will\n  block writing process (i.e. hang daemons)\n- Improved MODE SELECT / SENSE to support 'changeable field bitmaps\n- Started implementing ALLOW OVERWRITE support (incomplete)\n- Fixed INQUIRY string match for STK T10000A\n\n* Sat Jan 21 2012 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 1.2-1\n- Fix memory leak in lzo decompression routine.\n\n* Fri Jan 20 2012 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 1.2-0\n- Ability to specify zlib or lzo compression.\n  via 'vtlcmd' at runtime.\n      'vtlcmd <> compression lzo'\n      'vtlcmd <> compression zlib'\n  /etc/mhvtl/device.conf entry\n      ' Compression type: lzo'\n      ' Compression type: zlib'\n\n* Sat Dec 24 2011 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 1.1-1\n- Clean up IPC resources when finished with them\n- Simplify fifo reference counting\n- Start including Scientific Linux patches (Still need to include kmod RPM)\n- Fix 'make install' on Ubuntu\n- Various log message cleanups\n\n* Sun Oct 09 2011 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 1.1\n- Added real time state notification.\n  '-f <fifo name>' (Set in build_library_config)\n  Defaults to all daemons using the same 'named pipe'\n  Each entry is prefixed with '<index>:' and text to the change of state.\n- MODE SENSE for LTO devices update the 'media type' field.\n- LOG SENSE page 0x0c (Sequential Access Device Page) updates with valid data\n\n* Sun Sep 11 2011 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 1.0.1\n- Added mode page 25h (vendor specific) for IBM LTO3/4/5\n  This allows the Windows IBM Tape Driver to load correctly (connected via\n  iSCSI)\n- Attempt to correct file permission/ownership when media is created manually\n- A HUP signal to the vtllibrary daemon will cause it to re-read its config\n  from the /etc/mhvtl/library_contents.XX file. (So you can change the slot\n  config without having to re-start the daemon).\n\n* Sun Sep 04 2011 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 1.00.00\n- Re-worked MODE SENSE/SELECT data structures into a linked list.\n- Re-worked LOG SENSE/SELECT data structures into a linked list.\n- Added support for sub-page MODE information.\n- Added STK 9x40 drive emulations.\n- Removed dead code from kernel driver.\n- Add working REPORT DENSITY support to the SSC.\n  This change required the personality modules to define the list of supported\n  densities. The media density is defined at 'mktape' time.\n  Hence, the optional 'media load' rules in device.conf are now redundent\n  and not used.\n  BUT: The option to load any media into any drive is also gone.\n\n* Sat Jun 25 2011 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.18.17\n- Improvements\n  - Kernel module compile warning since 2.6.33\n- Bug fixes\n  - Test MAP port open before moving media\n  - Fix buffer overflow in vtllibrary (product_id)\n  - Return correct sense from space op code\n\n* Sun May 22 2011 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.18.16\n- Improvements\n  - Cleaning media behaves more like real (IBM LTO4) drive.\n  - Implement OPEN/CLOSE IMPORT/EXPORT element OP code (Thanks Sebastian)\n  - Kernel module support for 2.6.39 (Thanks Sebastian)\n- Bug fixes\n  - SPACE op code - Space to end-of-data fixed (Thanks Sebastian)\n    This fixes an issue triggered using Oracle Backup\n  - REQUEST SENSE - Return correct data.\n  - SPOUT - Return check_condition on some error paths\n  - Cleaning Media - Return 'not ready' instead of 'good' when loaded\n  - Don't write FILEMARKS to WORM or Cleaning media\n\n* Wed May 04 2011 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.18.15\n- Improvements\n  - Implemented 'Personality Module' for each drive type\n    (many cleanups due to 'PM' change fallout thanks to Sebastian)\n  - Increase max barcode length to 16 chars\n- Bug fixes\n  - Inquiry no longer incorrectly reports support for TrmIOP and CmdQue\n  - Fixed block read/writes corruption if 'multiple blocks' specified\n  - Fix Device Capabilities mode page - Don't advertise EXCHANGE MEDIUM support\n\n* Thu Mar 17 2011 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.18.14\n- Bug fixes:\n  - kernel module build fixes for Linux kernel 2.6.37 and greater\n- Improvements\n  - Add STK T10000C media/drive support\n  - Always log 'fatal' errors\n  - Cleanup to mhvtl.spec\n  - Catch signals to prevent daemon terminating early.\n\n* Thu Jan 11 2011 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.18.13\n- Bug fixes:\n  - SMC read element status. Return correct length.\n  - SMC read element status. Handle request for 'any' slot type.\n  - SSC log page. Byte-swap Bytes Read/Written.\n  - vtltape: Return ILLEGAL REQUEST for unsupported OP codes.\n  - Density code updates.\n  - Increased sense buffer from 38 bytes to 96 bytes.\n\n* Wed Nov 17 2010 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.18.12\n- Bug fixes:\n  - Silence 'which setuidgid' test\n  - Fix compile on 2.6.34 kernel\n  - ERASE only from BOT\n  - Test SPACE '0' blocks/filemarks before moving\n  - Fix REQUEST SENSE returned size\n  - Implement SILI bit test\n  - Check if ERASE WORM media is allowed\n  - Only support SPIN/SPOUT for LTO-4/5, T10K and 3592E05/6 drive types\n  - Fix REQUEST SENSE page length. Previously only returning 8 bytes.\n- Improvements\n  - Re-organised code in vtllibrary to use a big jump table\n  - Fix LTO5 media density reporting\n  - Match HP ULTRIUM 4-SCSI\n  - Ability to create DDS specific media\n    (still need to find correct density codes for DDS)\n\n* Thu Sep 23 2010 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.18.11\n- Bug fix: Off-by-one if a re-position & then overwrite a filemark.\n  Caused TSM & HP Dataprotector all sorts of problems.\n- Export kernel module 'major' number via /sys/bus/pseudo/drivers/mhvtl/major\n- Remove external script to create device nodes. Each daemon creates its own\n  device node at startup. Uses 'kernel module' major no. sys interface.\n- Fix potential NULL pointer usage in REQUEST SENSE\n- VPD page 0x83 NAA field fix\n- VPD page length fix (only 0x50 bytes in size not 0x52)\n- Hopefully removed last reference to /proc\n- Use setuidgid if availble instead of 'su $USER -c <vtltape|vtllibrary>'\n- Add kernel module RPM spec file for RedHat\n- Add Gentoo build\n\n* Wed Sep 01 2010 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.18.10\n- Correct incorrect usage of & vs &&\n- Fix TapeAlert.\n  Error where the flags were not being set due to an earlier change.\n- Add extra verbage around positioning information. Trying to track down\n  a problem with HP Dataprotector when it spaces back a block.\n- Make tape media & drive type loading logs more readable.\n- New utility 'tapeexerciser' which I've been using to track down the\n  Dataprotector issue. A simple & basic 'st ioctl()' test utility.\n- Fix 'is vtl running' logic in rc script. Was broken if USER == root\n\n* Wed Jul 09 2010 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.18.9\n- Fix WORM media support - Bug report from Albert Pauw\n- Complete LTO5 media support\n\n* Wed Jun 23 2010 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.18.8\n- Several Security Protocol IN updates - thanks Albert Pauw\n  * Return certificate data\n  * Correct length for 'KEY FORMATS'\n  * Correct length for SPIN SUPPORTED PAGES\n- Fix kernel compile on RedHat AS4\n- Media/drive matching now 'dynamic' and defined in device.conf\n- Added man page for device.conf\n- Fix media corruption when media is 'formatted'\n- Add LTO5 & SDLT-S4 drive/media types\n- Handle INQUIRY correctly after media change (return SAM_STAT_GOOD)\n- Updated rc script so all devices created on Target & LUN. i.e. Don't use\n  channel. Some application software has trouble if only the channel is unique.\n\n* Sat May 08 2010 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.18.7\n- Allow media sizes larger than 2G on 32bit platforms\n- Implement STK vendor unique op code 'LOAD DISPLAY' -> logs via syslog.\n- Fix core dump on invalid data in NAA strings.\n- Support VENDOR ID for SMC device with embedded spaces\n\n* Thu May 02 2010 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.18.6\n- Support VENDOR ID with embedded spaces\n- Fix 'vtlcmd list map'\n- Fix import of media via MAP (off-by-one)\n- Return TapeCapacity LOG SENSE in bytes/KB/MB depending on drive type\n- Honour MAP status (return error if MAP is open and robot attempts to\n  move media in/out of MAP)\n- General cleanup of kernel module (thanks to Herbert Stadler)\n- Relax dependencies on /proc in faviour of /sys\n\n* Thu Apr 01 2010 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.18.5\n- Silence warning regarding local_irq_save() - Thanks to Norm Lunda\n- Re-work param parsing used by vtlcmd - Thanks to Herbert Stadler\n- Fix homepage URL\n\n* Fri Mar 05 2010 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.18.4\n- Fix syntax in rc script. Reported by Nabil\n  That's what I get for rushing a fix out (ELEMENT STATUS) without testing\n  everything..\n\n* Thu Mar 04 2010 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.18.3\n- Test media mounted before REWIND (TSM seems to ignore previous TUR)\n- Make creation of media home dir more robust\n- Add queue depth callback - Defaults to 32.\n- Conversion script of old config files to new format\n- Fix problem with size of ELEMENT STATUS DATA length. Thanks to Norm Lunde.\n\n* Thu Jan 28 2010 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.18.2\n- Add support for multiple libraries on single host\n- pack MAM struct so it's 1024 bytes on both 32 & 64bit hosts\n- Updated URL after google moved it\n\n* Wed Dec 16 2009 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.16.11\n- Add tests for media/drive type. i.e. Only allow LTO media in LTO drives.\n- New defination for 'Compression:' in device.conf (Thanks Kevan Rehm)\n  ' Compression: factor [1-9] enabled [0|1]'\n        Where factor : 1 Fastest compression -> 9 Best compression\n             enabled : 0 => Compression disabled, 1 => Compression enabled\n\n* Tue Dec 15 2009 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.18.1\n- Fix data silent data corruption.\n- Add tests for media/drive type. i.e. Only allow LTO media in LTO drives.\n- Increased max number of LUNs from 7 to 32\n- Changed ' Compression: factor X enabled Y' to same as 0.16 branch.\n  ' Compression: factor [1-9] enabled [0|1]'\n        Where factor : 1 Fastest compression -> 9 Best compression\n             enabled : 0 => Compression disabled, 1 => Compression enabled\n\n* Tue Dec 01 2009 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.18.0\n- Kevan Rehm reworked media format. The 'old' format suffered from performance\n  problems. The larger the defined tape capacity, the longer it took to\n  seek/position due to the sequential walk of header structures.\n\n  The new tape format consists of three files.\n   .data - Data file.\n   .indx - Arrary of one header structure per written tape block or filemark.\n   .meta - MAM, followed by meta header structure, followed by variable length\n           of filemark block numbers\n   Each Physical Cartridge Label (PCL) is located under its own directory\n   MHVTL_HOME_PATH/<PCL>/\n\n* Sun Nov 29 2009 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.16.9\n- Check string length in device.conf and abort if too long.\n- Compression now working.\n  Set up via MODE SELECT op code.\n  Set default compression in device.conf 'Compression: X'\n   Where 0 is off, 9 is max.\n- Defaults with SPECTRA/PYTHON library\n- Fix kernel module compile on 2.6.31+ (Ubuntu 9.10)\n- Fix kernel silent data corruption\n- Set kernel ENABLE_CLUSTERING to enable > 512k blocks on x86_64\n- SPIN/SPOUT: Return correct list of supported pages.\n\n* Tue Nov 10 2009 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.16.8\n- Reworked READ ELEMENT STATUS (Thanks to Kevan Rehm)\n- Fix EOD header size.\n- Makefile rework.\n  Honour PREFIX & DESTDIR.\n  User/group name defined.\n  Home paths for data files & config files defined.\n  Add compression support (disabled by default).\n\n* Thu Oct 9 2009 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.16.7\n  Fix REPORT ELMEMENT STATUS for All elements. TSM was core dumping.\n  Reported and fixed by Bernardo Clavijo.\n  Re-worked Media Access Port.\n   Now requires 'vtlcmd library open map' before media can be removed and\n   'vtlcmd library close map' for the Medium Transport Element to place\n   media into the MAP.\n\n* Thu Oct 1 2009 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.16.6\n  Fixed output of 'dump_tape' utility\n\n* Wed Sep 16 2009 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.16.5\n  Fixed verbosity test in MHVTL_DBG macro (again)\n\n* Tue Sep 15 2009 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.16.4\n  More logging cleanups\n  Fixed verbosity test in MHVTL_DBG macro\n\n* Wed Sep 02 2009 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.16.3\n  Reworked logging using a macros MHVTL_DBG.\n  Increased max block size to kernel max (from 256k)\n\n* Sat Aug 15 2009 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.16.2\n  Changed/updated load MAP() functionality.\n  Previous implementation re-read config file and parsed the MAP slots.\n  This is 'interactive' using the vtlcmd command.\n   e.g. vtlcmd library load map BARCODE\n  Corrected NAA field in VPD page 0x83. This was a hard coded string.\n   Now reads entry from /etc/mhvtl/device.conf\n\t' NAA: 11:22:33:44:ab:cd:ef:03' (8 octet value)\n  Remove dependency on sg3_utils\n\n* Wed Aug 05 2009 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.16.1\n  Fixed kernel module oops on lu removal - Many thanks to Jean-Francois\n  Added loadMap() to vtllibrary.\n\n* Tue Jul 09 2009 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.16.0\n- Moved INQUIRY into userspace.\n  Re-jigged all helper scripts.\n  Still need to do dynamic config of : vpd pages & mode pages.\n- Added pseudo encryption support (SPIN/SPOUT op codes)\n- kernel module will oops if unloaded and re-loaded..\n\n* Fri Jan 02 2009 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.15.10\n- Removed kfifo from data path for SCSI OP codes which originate at the target\n- Add simple SCSI Persistent Reserve\n- Major change to kernel module. Replaced queued_command_arr[] with linked list\n\n* Thu Nov 27 2008 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.15.9\n- Re-fixed WRITE ATTRIBUTE bug forcing a rewind of media.\n- Fixed build for PPC64 platform\n- Add special reserved barcode 'NOBAR' to indicate a slot is full but\n  contains no barcode.\n\n* Fri Nov 21 2008 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.15.8\n- Added initial SECURITY PROTOCOL code\n\n* Tue Nov 19 2008 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.15.7\n- Merge READ ATTRIBUTES fixes from Raymond Gilson\n\n* Sun Nov 16 2008 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.15.6\n- Fixed bug where WRITE ATTRIBUTE was causing media to rewind.\n- Increase default buffer size of SMC from 512k to 1024k - Ability to handle\n  more (twice the) slots\n\n* Fri Nov 14 2008 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.15.5\n- sg structure changed between 2.6.23 and 2.6.24 causing the kernel module\n  to no longer build on latest kernel.\n\n* Fri Apr 04 2008 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.15.4\n- Kernel module change. Default type is SDLT600 instead of IBM TD3 as there is\n  confusion on the windows side of things regarding IBM Drivers vs IBM for\n  Tivoli vs Symantec Tape Drivers.\n  Maybe the QUANTUM SDLT600 will behave better ??\n  Only time will tell...\n\n* Fri Mar 28 2008 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.15.3\n- Return 'block descriptor data' on a MODE SENSE 'page 0' instead of an error.\n\n* Mon Mar 10 2008 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.15.2\n  Re-org of the source code.\n  - Placed user-space code in directory ./usr\n  - Moved kernel drivers from ./kernel-driver/linux-2.6 to ./kernel\n  Yet another 'tunable' option. Set the firmware release to \"string\" by\n  # echo \"5400\" > /sys/bus/pseudo/drivers/vtl/firmware\n\n* Thu Mar 06 2008 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.15.1\n  Ability to define default media size in /etc/vtl/vtl.conf\n\n* Wed Mar 05 2008 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Name change as 'vtl' is was deemed too generic.\n  Renamed to 'mhvtl' as this is being used by Symantec's Roseville office and\n  is as good a name as any.\n- With the new name comes a new version 0.15.0\n\n* Tue Feb 19 2008 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.14.1\n  Cleaned up compile time warnings on x86_64 platform.\n  Added sg_utils and zlib as RPM 'requires' packages.\n\n* Thu Feb 14 2008 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.14.0\n- With the ability to define device serial numbers, I thought it was time\n  to increase vers from 0.12 to 0.14\n- Cleaned up helper scripts.\n\n* Fri Feb 08 2008 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12.37\n- Added ability to set serial number via new utility 'vtl_set_sn -q X'\n  The serial number is read from /etc/vtl/library_config for each 'Drive X:'\n  e.g.\n   Drive 2: SN20034\n   Drive 3: SN20035\n  If there is no serial number defined in library_config file, and the\n  serial prefix has been set, then this will be used. Otherwise the old &\n  trusted method of calculating based on HBA#, ID# & LUN.\n\n* Wed Feb 06 2008 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12.36\n- Added another config file /etc/vtl/vtl.conf\n- Added ability to set a serial number prefix for devices.\n- Added ability to set the buffer size used by SSC devices.\n- Added ability to set/clear logging levels within vtl.conf\n\n* Sat Feb 02 2008 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12-35\n- Fix post uninstall\n  check for group & passwd entries before attempting to run groupdel/userdel\n\n* Sat Jan 08 2008 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12-34\n  Changes to kernel module & rc scripts.\n- Default kernel module load reporting the library only.\n- The rc scripts now update the number of required tape devices depending on\n  the contents of /etc/vtl/library_contents\n- Using the max_luns or num_tgts the library can consist of different drives\n  or all the same drive type.\n- Deleted x86_64 patch as it is no longer needed.\n\n* Fri Jan 04 2008 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Reserved vers 0.12-33\n  A special build with only 5 IBM drives.\n\n* Wed Dec 19 2007 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12-32\n- Changed user 'vtl' home directory to /opt/vtl\n  Otherwise there can be problems starting the vtl s/w if /home is an\n  automount and can't mount /home.\n- Changed kernel module Makefile\n  To compile on Debian or Ubuntu systems \"make ubuntu=1\"\n  To compile on SuSE or RedHat systems \"make\"\n\n* Tue Oct 16 2007 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12-31\n- No code changes. As sysdup has crashed and management have decided not to\n  replaced the two failed drives in the RAID 5 system, I've changed the\n  home of this project to my google homepage.\n\n* Tue Oct 16 2007 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12-30\n- vtl kernel module: - bumped to 0.12.14 20071015-0\n- Another bug fix in the kernel module. This time copying data from user-space\n  in an unsafe manner. Last reason for kernel oops ??\n- Make library module startup more robust by clearing out message Q at start\n  time.\n- Set vtl startup to 'on' at package install time.\n\n* Wed Oct 10 2007 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12-28\n- vtl kernel module: - bumped to 0.12.14 20071010-0\n- Many updates to error handling condition.\n\n* Wed Sep 26 2007 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12-26\n- vtl kernel module: - bumped to 0.12.14 20070926-0\n  Moved memory alloc from devInfoReg() to vtl_slave_alloc() - I now don't get\n  those horrible \"Debug: sleeping function called from invalid context\"\n\n* Tue Sep 25 2007 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12-25\n- Resolved an issue where virtual media was being corrupted when performing\n  erase operation.\n\n* Sat Sep 22 2007 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12-24\n- On corrupt media load, return NOT READY/MEDIUM FORMAT CORRUPT\n\n* Fri Sep 21 2007 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12-23\n- vtl kernel module bug fix - resolved a race condition with my usage of\n  copy_to_user()/copy_from_user() and c_ioctl() routines.\n  Thanks to Ray Schafer for finding and being able to reproduce race.\n\n* Fri Aug 24 2007 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12-22\n- Set correct directory ownership and permissions at post install time\n  for /opt/vtl\n\n* Wed Aug 01 2007 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12-21\n- Corrected warnings identified by sparse\n\n* Sat Apr 07 2007 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12-20\n- Calls to tune kernel behaviour of out-of-memory always return 'success'.\n  Found out the hard way, earlier kernel versions do not support this feature.\n- Added check for return status from build_library_config in rc script\n\n* Sat Mar 31 2007 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12-19\n- Added conditional x86_64/amd64 to vtl.spec so it builds correctly on x86_64\n  platforms.\n\n* Wed Mar 28 2007 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12-18\n- Improved (slightly) checking of MAM header on media open.\n  At least made it 32/64 bit friendly.\n\n* Thu Mar 24 2007 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12-17\n- Added 'Out Of Memory killer tuning to both vtltape and vtllibrary.\n- Added 'tags' as a target in Makefile, i.e. 'make tags'\n  TAGS will be removed with a 'make distclean'\n\n* Thu Mar 13 2007 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12-16\n- Added -D_LARGEFILE64 switch to Makefile to allow a more portable way of\n  opening files > 2G. There should be no need for the x86_64 patch any more.\n  Needs testing.\n\n* Thu Feb 22 2007 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12-14\n- Added 'ERASE(6)' command as a result of bug report from Laurent Dongradi.\n  NetBackup \"bplabel -erase -l \" command failing.\n\n* Thu Sep 07 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12-13\n- Just updated some time/date in kernel module. Nothing major.\n\n* Tue Sep 05 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12-12\n  Shared library (libvxscsi.so) conflict with Symantec VRTSvxvm-common-4.1.20\n  so I've renamed mine to libvtlscsi.so\n  Should build correctly on an x86_64 RPM system now.\n\n* Thu Aug 31 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12-10 (skipped numbering between -5 & -10\n  Changed interface between user-space and kernel, hence need kernel module\n  version 0.12.10\n  The change is to support 'auto sense', where the sense buffer is sent straight\n  after the data (if sense data is valid).\n  Need to fix: Way of specifying size of sense buffer. Currently defined in\n  kernel src (vtl.c) and user-space header vx.h. It would be nice to have this\n  defined in one place only.\n- Updated rc script to check kernel version before starting user-space daemons.\n\n* Wed Jul 05 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12-5\n- Updated man pages to reflect name changes from vxtape/vxlibrary to\n  vtltape/vtllibrary\n- Removed any vxtape/vxlibrary binaries from build process\n\n* Tue Jul 04 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12-4\n- Fixed (Well tested) kernel makefile compile on SLES 9 and suse 9.3\n  i.e. Kernel versions 2.6.5-7.191-smp & 2.6.11.4-21.12-smp\n  Hacked scsi.h include file and added #if KERNEL_VERSION conditional compile\n  around kfifo.[ch] if below 2.6.10\n- Attempt to improve install/startup on RedHat AS4 + SLES9\n\n* Sun Jul 02 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.12-0\n- Forked this version from main tree. Main branch is 0.13.x which will continue\n  to be work-in-progress for removal of kfifo routines.\n- 0.12-x is to be current 'stable' branch.\n\n* Fri May 19 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.10-13\n- Added TapeUsage & TapeCapacity log parameters. Even thou I'm specifying these\n  pages are not supported, BackupExec still probes for them and barfs on the\n  scsi error returned.\n\n* Thu May 18 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.10-12\n- Re-worked the READ ELEMENT STATUS command with the idea of adding the extra\n  options which appear to be required by BackupExec.\n\n* Wed May 10 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped vers to 0.10-10\n- Fixed bug introduced in vtllibrary where I broke the inventory function.\n\n* Tue May 09 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Changed poll of 'getting SCSI command' to use ioctl instead of kfifo.\n  Requires kernel module dated > 20060503-0\n\n* Sun Apr 30 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Fixed typo in rc script where trying to set permissions on /dev/vx? instead\n  of /dev/vtl?\n\n* Sat Apr 29 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Changed logic on WIRTE-FILEMARK SCSI command. Now only attempts to write\n  filemarks if greater the 0 filemarks specified.\n- Added check for SuSE-release and use '{user|group}add --system' switch\n  otherwise {user|group}add without the --system switch.\n- Bumped version to 0.10-6\n\n* Thu Apr 27 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Seek to EndOfData bug where the tape daemon would loop over the last block\n  and never return.\n\n* Sat Apr  5 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Changed the kernel module from 'vx_tape' to vtl (no real impact to user space\n- daemons) however changing /dev/ entries from /dev/vx? to /dev/vtl due to name\n- space clash with VERITAS StorageFoundation (VxVM/VxFS)\n\n* Sat Apr  1 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Bumped version to 0.9 as this has the start of a working Solaris port.\n\n* Thu Mar 24 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Added extra logging for mode_sense command if verbose > 2\n\n* Thu Mar 10 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Start of Solaris kernel port.\n- Moved kernel driver into seperate subdir.\n- Added some 'ifdef Solaris' to source code.\n\n* Thu Feb 22 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Added check to make sure RPM_BUILD_ROOT is not / when attempting to remove.\n- Shutdown daemons before package removal\n\n* Thu Feb 16 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Added ALLOW/DENY MEDIUM REMOVAL SCSI cmd to vxlibrary daemon.\n- Added Extend/Retract checking to MOVE MEDIUM SCSI cmds.\n\n* Thu Feb 14 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Made RPM create system account of 'vtl' & group of 'vtl' before install.\n\n* Thu Feb 11 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- bump vers from 0.7 to 0.8\n- Rename /opt/vx_media to /opt/vtl\n- Rename /etc/vxlibrary to /etc/vtl\n- RPM install now creates vtl user & group\n- rc script now installs a default library config file in /etc/vtl/\n\n* Thu Feb  2 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Teach me for not testing fully. Resolved bug where no data was written.\n\n* Thu Feb  2 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Improvements to handling of cleaning media.\n\n* Wed Jan  3 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Added a new man page vtl, which aims to document how this package hangs\n  together.\n- Corrected a couple of hard-coded paths in rc scripts\n\n* Wed Jan  3 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Moved source man pages into separate man directory.\n- Updated version of user-mode utilities to that of the kernel module (v0.7)\n\n* Tue Jan  3 2006 Mark Harvey <markh794@gmail.com> <mark_harvey@symantec.com>\n- Added man pages.\n\n"
  },
  {
    "path": "INSTALL",
    "content": "mh virtual tape & library system.\n\n\nInstructions assume reader is familiar with the kernel build process.\n\nThere are two sections of code to build.\n- The kernel module\n- The user-space daemons.\n\nKernel module mhvtl:\n==================\n1) Make sure the kernel-devel package to match your running kernel is installed.\ne.g.\nRedHat AS 4 & 5:\n\n\tsh> rpm -qa|grep kernel\n\tkernel-2.6.9-34.0.1.EL\n\tkernel-devel-2.6.9-34.0.1.EL\n\tkernel-2.6.9-5.EL\n\tkernel-devel-2.6.9-5.EL\n\tkernel-utils-2.4-13.1.80\n\nSLES 9 & 10:\n\n\tsh> rpm -qa|grep kernel\n\n\n2) Extract the mhvtl source code.\n\n\tsh> tar xvfz mhvtl-2012-06-15.tgz\n\n3) Change directory into the kernel driver source.\n\n\tsh> cd mhvtl-1.3/kernel/\n\tsh> make\n\tsh> sudo make install\n\n\nUser space daemons:\n===================\nPre-req for a running mhvtl\n- sg3_utils (http://sg.danny.cz/sg/sg3_utils.html)\n\nPre-req to build/compile userspace:\n- zlib-devel\n- lzo-devel\n\n* To build an RPM\n  ===============\n\n\tsh> sudo cp mhvtl-YYYY-MM-DD.tar.gz /usr/src/packages/SOURCE/\n\tsh> cd /usr/src/packages/SOURCE\n\tsh> sudo rpmbuild -tb mhvtl-YYYY-MM-DD.tar.gz\n\t...  <wait for rpm build to complete>\n\tsh> sudo rpm -Uvh /usr/src/packages/RPMS/<cpu type>/mhvtl-1.3-z.<cpu type>.rpm\n\t...\n\n- Note: For RedHat, replace 'packages' with 'redhat'\n\n* To build from tar archive (Debian / Ubuntu):\n  ============================================\n apt-get install lsscsi\n apt-get install sg3-utils\n\nNote: we used to create a user and group called \"vtl\" to try to limit\nthe possible system hazards of having root access. But we now feel\nthat normal Linux permissions and security controls are sufficient.\n\nAlso note: The package sg3-utils has a different name based on the distribution\nused. Most distributions (Red Hat/Suse/Centos) use an underscore (sg3_utils).\nDebian based distributions (Debian/Ubuntu/Mint use a hyphen (sg3-utils).\n\nNow build user space daemons:\nFrom the parent directory where you extracted the source.\n\n\tsh> cd mhvtl-1.3\n\nBuild the binaries\n\n\tsh> make\n\nInstall the systemd scripts and binaries and tell systemd:\n\n\tsh> sudo make install\n\tsh> sudo systemctl daemon-reload\n\nEnable and start the mhvtl target service:\n\n\tsh> sudo systemctl enable mhvtl.target\n\tsh> sudo systemctl start mhvtl.target\n\nAnd make sure it worked:\n\n\tsh> sudo systemctl status mhvtl.target\n\nYou can test that your vtl* daemons are running with:\n\n\tsh> ps -ax | fgrep vtl\n\nTest:\nNote: Make sure the 'mtx' & 'lsscsi' utilities are installed\nThe virtual devices are attached to HBA #5 in this example.\ne.g.\n# lsscsi -g\n[0:0:0:0]    disk    ATA      WDC WD1200BEVS-0 02.0  /dev/sda  /dev/sg0\n[3:0:0:0]    cd/dvd  Optiarc  DVD RW AD-7910A  1.D1  /dev/sr0  /dev/sg1\n[5:0:0:0]    mediumx SPECTRA  PYTHON           5500  /dev/sch0  /dev/sg6\n[5:0:1:0]    tape    QUANTUM  SDLT600          5500  /dev/st0  /dev/sg2\n[5:0:2:0]    tape    QUANTUM  SDLT600          5500  /dev/st1  /dev/sg3\n[5:0:3:0]    tape    IBM      ULT3580-TD4      5500  /dev/st2  /dev/sg4\n[5:0:4:0]    tape    IBM      ULT3580-TD4      5500  /dev/st3  /dev/sg5\n\n\n# mtx -f /dev/sg6 status\n  Storage Changer /dev/sg6:4 Drives, 37 Slots ( 4 Import/Export )\nData Transfer Element 0:Empty\nData Transfer Element 1:Empty\nData Transfer Element 2:Empty\nData Transfer Element 3:Empty\n      Storage Element 1:Full :VolumeTag=SDLT01S3\n      Storage Element 2:Full :VolumeTag=SDLT02S3\n      Storage Element 3:Full :VolumeTag=SDLT03S3\n      Storage Element 4:Full :VolumeTag=SDLT04S3\n      Storage Element 5:Full :VolumeTag=SDLT05S3\n      Storage Element 6:Full :VolumeTag=SDLT06S3\n      Storage Element 7:Full :VolumeTag=SDLT07S3\n      Storage Element 8:Full :VolumeTag=SDLT08S3\n      Storage Element 9:Full :VolumeTag=SDLT09S3\n      Storage Element 10:Empty\n      Storage Element 11:Full :VolumeTag=ULT001L1\n      Storage Element 12:Full :VolumeTag=ULT002L2\n      Storage Element 13:Full :VolumeTag=ULT003L3\n      Storage Element 14:Full :VolumeTag=ULT004L4\n      Storage Element 15:Full :VolumeTag=ULT005L1\n      Storage Element 16:Full :VolumeTag=ULT006L2\n      Storage Element 17:Full :VolumeTag=ULT007L3\n      Storage Element 18:Full :VolumeTag=ULT008L4\n      Storage Element 19:Full :VolumeTag=ULT009L1\n      Storage Element 20:Empty\n      Storage Element 21:Full :VolumeTag=8MM001X4\n      Storage Element 22:Full :VolumeTag=8MM002X4\n      Storage Element 23:Full :VolumeTag=8MM003X4\n      Storage Element 24:Full :VolumeTag=8MM004X4\n      Storage Element 25:Empty\n      Storage Element 26:Empty\n      Storage Element 27:Empty\n      Storage Element 28:Empty\n      Storage Element 29:Empty\n      Storage Element 30:Empty\n      Storage Element 31:Full :VolumeTag=CLN001L1\n      Storage Element 32:Full :VolumeTag=CLN002L1\n      Storage Element 33:Full :VolumeTag=CLN003L1\n      Storage Element 34 IMPORT/EXPORT:Empty\n      Storage Element 35 IMPORT/EXPORT:Empty\n      Storage Element 36 IMPORT/EXPORT:Empty\n      Storage Element 37 IMPORT/EXPORT:Empty\n\n\nEnjoy.\n\nPlease feel free in letting me know if this works for you.\n\nBug fixes and suggestions always welcome.\n\nmarkh794@gmail.com\n"
  },
  {
    "path": "Makefile",
    "content": "#\n# This makefile needs to be invoked as follows:\n#\n#make <options>\n#\n# Here, options include:\n#\n# \tall \tto build all utilities\n# \tclean\tto clean up all intermediate files\n# \tkernel\tto build kernel module\n#\n\ninclude config.mk\n\nPARENTDIR = mhvtl-$(VER)\nCHECK_CC = cgcc\nCHECK_CC_FLAGS = '$(CHECK_CC) -Wbitwise -Wno-return-void -no-compile $(ARCH)'\n\nTAR_FILE := mhvtl-$(shell date +%F)-$(VERSION).$(EXTRAVERSION).tgz\n\nMAKE_VTL_MEDIA = usr/bin/make_vtl_media\n\nexport PREFIX DESTDIR TOPDIR\n\nCFLAGS=-Wall -g -O2 -D_LARGEFILE64_SOURCE $(RPM_OPT_FLAGS)\nCLFLAGS=-shared\n\nall:\tusr etc scripts\n\nscripts:\tpatch\n\t$(MAKE) -C scripts\n\netc:\tpatch\n\t$(MAKE) -C etc\n\nusr:\tpatch\n\t$(MAKE) -C usr\n\nkernel: patch\n\t$(MAKE) -C kernel\n\n.PHONY:check\ncheck:\tARCH=$(shell sh scripts/checkarch.sh)\ncheck:\n\tCC=$(CHECK_CC_FLAGS) $(MAKE) all\n\n\npatch:\n\n\ninstall: all\n\t[ -d $(DESTDIR)$(MHVTL_HOME_PATH) ] || mkdir -p $(DESTDIR)$(MHVTL_HOME_PATH)\n\t$(MAKE) -C usr install\n\t$(MAKE) -C scripts install\n\t$(MAKE) -i -C etc install\n\t$(MAKE) -C man install\n\t$(MAKE) -C kernel install\nifeq ($(ROOTUID),YES)\n\tsystemctl daemon-reload\nendif\n\ntape: # now ensure VTL media is setup\n\tenv LD_LIBRARY_PATH=$(DESTDIR)$(LIBDIR) \\\n\t\t$(MAKE_VTL_MEDIA) \\\n\t\t\t--config-dir=$(DESTDIR)$(MHVTL_CONFIG_PATH) \\\n\t\t\t--home-dir=$(DESTDIR)$(MHVTL_HOME_PATH) \\\n\t\t\t--mktape-path=usr/bin\n\n.PHONY:uninstall\nuninstall:\n\t$(MAKE) -C usr uninstall\n\t$(MAKE) -C scripts uninstall\n\t$(MAKE) -i -C etc uninstall\n\t$(MAKE) -C man uninstall\n\t$(MAKE) -C kernel uninstall\nifeq ($(ROOTUID),YES)\n\tsystemctl daemon-reload\nendif\n\ntar: distclean\n\ttest -d ../$(PARENTDIR) || ln -s $(TOPDIR) ../$(PARENTDIR)\n\t(cd kernel; tar --transform='s|.*/||' \\\n\t\t-cfz ../mhvtl_kernel.tgz * ../include/common/*)\n\t(cd ..;  tar cvzf $(TAR_FILE) --exclude='.git*' \\\n\t\t $(PARENTDIR)/man \\\n\t\t $(PARENTDIR)/doc \\\n\t\t $(PARENTDIR)/kernel \\\n\t\t $(PARENTDIR)/usr \\\n\t\t $(PARENTDIR)/etc/ \\\n\t\t $(PARENTDIR)/scripts/ \\\n\t\t $(PARENTDIR)/ccan/ \\\n\t\t $(PARENTDIR)/tcopy/ \\\n\t\t $(PARENTDIR)/include \\\n\t\t $(PARENTDIR)/Makefile \\\n\t\t $(PARENTDIR)/config.mk \\\n\t\t $(PARENTDIR)/README \\\n\t\t $(PARENTDIR)/INSTALL \\\n\t\t $(PARENTDIR)/ChangeLog \\\n\t\t $(PARENTDIR)/mhvtl_kernel.tgz \\\n\t\t $(PARENTDIR)/mhvtl-utils.spec)\n\t$(RM) ../$(PARENTDIR)\n\n.PHONY:tags\ntags:\n\t$(MAKE) -C usr tags\n\t$(MAKE) -C kernel tags\n\n# ========== Cleaning ==========\n\n.PHONY:clean\nclean:\n\t$(MAKE) -C usr clean\n\t$(MAKE) -C etc clean\n\t$(MAKE) -C scripts clean\n\t$(MAKE) -C man clean\n\t$(MAKE) -C kernel clean\n\t$(RM) mhvtl_kernel.tgz\n\n.PHONY: distclean\ndistclean:\n\t$(MAKE) -C usr distclean\n\t$(MAKE) -C etc distclean\n\t$(MAKE) -C scripts distclean\n\t$(MAKE) -C kernel distclean\n\t$(MAKE) -C man distclean\n\t$(RM) mhvtl_kernel.tgz\n\t$(RM) ../$(TAR_FILE)\n"
  },
  {
    "path": "README",
    "content": "\nmhvtl: A Virtual Tape & Library system.\n\nThis package is composed of a kernel module (mhvtl) which is a pseudo HBA\n\nThe vtl is basically a stripped down scsi_debug kernel module + a char dev\n'back end' to pass the SCSI commands thru to user space daemons. It is the\nuser space daemons responsibility to respond and process the SCSI commands.\n\nSee the INSTALL file for compile and install instructions.\n\nThis has been my first attempt at kernel level programming. Suggestions and\ncomments always welcome. It has also been many years since I have done any c\nprogramming. Please be gentle..\n\nMark Harvey\nmarkh794@gmail.com\n"
  },
  {
    "path": "ccan/ccan/crc32c/_info",
    "content": "#include \"config.h\"\n#include <string.h>\n#include <stdio.h>\n\n/**\n * crc32c - routine for Castagnoli CRC (crc32c) of bytes\n *\n * Cyclic Redundancy Check routine, optimized for x86-64.  Reasonably fast\n * checksum routines, but not suitable for cryptographic use.\n *\n * They are useful for simple error detection, eg. a 32-bit CRC will\n * detect a single error burst of up to 32 bits.\n *\n * Example:\n *\t#include <ccan/crc32c/crc32c.h>\n *\t#include <stdio.h>\n *\t#include <stdlib.h>\n *\n *\t// Given \"123456789\" outputs 0xe3069283\n *\tint main(int argc, char *argv[])\n *\t{\n *\t\tif (argc != 2) {\n *\t\t\tfprintf(stderr, \"Usage: %s <string>\\n\"\n *\t\t\t\t\"Prints 32 bit CRC of the string\\n\", argv[0]);\n *\t\t\texit(1);\n *\t\t}\n *\t\tprintf(\"0x%08x\\n\", crc32c(0, argv[1], strlen(argv[1])));\n *\t\texit(0);\n *\t}\n *\n * License: MIT\n * Author: Mark Adler\n * Maintainer: Rusty Russell <rusty@rustcorp.com.au>\n */\nint main(int argc, char *argv[])\n{\n\tif (argc != 2)\n\t\treturn 1;\n\n\tif (strcmp(argv[1], \"depends\") == 0) {\n\t\tprintf(\"ccan/compiler\\n\");\n\t\treturn 0;\n\t}\n\n\treturn 1;\n}\n"
  },
  {
    "path": "ccan/ccan/crc32c/benchmark/Makefile",
    "content": "CCANDIR=../../..\nCFLAGS=-Wall -Werror -O3 -I$(CCANDIR) -flto\n#CFLAGS=-Wall -Werror -g3 -I$(CCANDIR)\nLDFLAGS := -flto -O3\n\nall: bench\n\nCCAN_OBJS:=ccan-tal.o ccan-tal-grab_file.o ccan-noerr.o ccan-take.o ccan-time.o\n\nbench: bench.o $(CCAN_OBJS)\n\nclean:\n\trm -f bench *.o\n\nccan-time.o: $(CCANDIR)/ccan/time/time.c\n\t$(CC) $(CFLAGS) -c -o $@ $<\nccan-tal.o: $(CCANDIR)/ccan/tal/tal.c\n\t$(CC) $(CFLAGS) -c -o $@ $<\nccan-take.o: $(CCANDIR)/ccan/take/take.c\n\t$(CC) $(CFLAGS) -c -o $@ $<\nccan-noerr.o: $(CCANDIR)/ccan/noerr/noerr.c\n\t$(CC) $(CFLAGS) -c -o $@ $<\nccan-tal-grab_file.o: $(CCANDIR)/ccan/tal/grab_file/grab_file.c\n\t$(CC) $(CFLAGS) -c -o $@ $<\n"
  },
  {
    "path": "ccan/ccan/crc32c/benchmark/bench.c",
    "content": "#include <ccan/tal/grab_file/grab_file.h>\n#include <ccan/tal/tal.h>\n#include <ccan/time/time.h>\n#include <ccan/crc32c/crc32c.c>\n#include <assert.h>\n#include <ccan/err/err.h>\n\n#define RUNS 65536\n\nint main(int argc, char *argv[])\n{\n\tvoid *p;\n\tstruct timeabs start, end;\n\tsize_t len, runs;\n\tuint64_t sums = 0;\n\tbool sw = false, hw = false;\n\n\tif (argv[1]) {\n\t\tif (streq(argv[1], \"--software\")) {\n\t\t\tsw = true;\n\t\t\targv++;\n\t\t\targc--;\n\n\t\t} else if (streq(argv[1], \"--hardware\")) {\n\t\t\thw = true;\n\t\t\targv++;\n\t\t\targc--;\n\t\t}\n\t}\n\n\tif (argc < 2 || (runs = atol(argv[1])) == 0)\n\t\terrx(1, \"Usage: bench <num-runs> [<file>]\");\n\n\tp = grab_file(NULL, argv[2]);\n\tif (!p)\n\t\terr(1, \"Reading %s\", argv[2] ? argv[2] : \"<stdin>\");\n\tlen = tal_count(p) - 1;\n\tstart = time_now();\n\tif (sw) {\n\t\tfor (size_t i = 0; i < runs; i++)\n\t\t\tsums += crc32c_sw(0, p, len);\n\t} else if (hw) {\n\t\tfor (size_t i = 0; i < runs; i++)\n\t\t\tsums += crc32c_hw(0, p, len);\n\t} else {\n\t\tfor (size_t i = 0; i < runs; i++)\n\t\t\tsums += crc32c(0, p, len);\n\t}\n\tend = time_now();\n\n\tassert(sums % runs == 0);\n\tprintf(\"%u usec for %zu bytes, sum=%08x\\n\",\n\t       (int)time_to_usec(time_divide(time_between(end, start), runs)),\n\t       len,\n\t       (unsigned int)(sums / runs));\n\treturn 0;\n}\n"
  },
  {
    "path": "ccan/ccan/crc32c/crc32c.c",
    "content": "/* MIT (BSD) license - see LICENSE file for details */\n/* crc32c.c -- compute CRC-32C using the Intel crc32 instruction\n * Copyright (C) 2013, 2015 Mark Adler\n * Version 1.3  31 Dec 2015  Mark Adler\n */\n\n/*\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the author be held liable for any damages\n  arising from the use of this software.\n\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n\n  1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n\n  Mark Adler\n  madler@alumni.caltech.edu\n */\n\n/* Use hardware CRC instruction on Intel SSE 4.2 processors.  This computes a\n   CRC-32C, *not* the CRC-32 used by Ethernet and zip, gzip, etc.  A software\n   version is provided as a fall-back, as well as for speed comparisons. */\n\n/* Version history:\n   1.0  10 Feb 2013  First version\n   1.1   1 Aug 2013  Correct comments on why three crc instructions in parallel\n   1.2   1 Nov 2015  Add const qualifier to avoid compiler warning\n                     Load entire input into memory (test code)\n                     Argument gives number of times to repeat (test code)\n                     Argument < 0 forces software implementation (test code)\n   1.3  31 Dec 2015  Check for Intel architecture using compiler macro\n                     Support big-endian processors in software calculation\n                     Add header for external use\n */\n\n#include \"crc32c.h\"\n#include <ccan/compiler/compiler.h>\n#include <stdbool.h>\n\nstatic uint32_t crc32c_sw(uint32_t crc, void const *buf, size_t len);\n\n/* CRC-32C (iSCSI) polynomial in reversed bit order. */\n#define POLY 0x82f63b78\n\n#ifdef __x86_64__\n\n/* Hardware CRC-32C for Intel and compatible processors. */\n\n/* Multiply a matrix times a vector over the Galois field of two elements,\n   GF(2).  Each element is a bit in an unsigned integer.  mat must have at\n   least as many entries as the power of two for most significant one bit in\n   vec. */\nstatic inline uint32_t gf2_matrix_times(uint32_t *mat, uint32_t vec) {\n    uint32_t sum = 0;\n    while (vec) {\n        if (vec & 1)\n            sum ^= *mat;\n        vec >>= 1;\n        mat++;\n    }\n    return sum;\n}\n\n/* Multiply a matrix by itself over GF(2).  Both mat and square must have 32\n   rows. */\nstatic inline void gf2_matrix_square(uint32_t *square, uint32_t *mat) {\n    for (unsigned n = 0; n < 32; n++)\n        square[n] = gf2_matrix_times(mat, mat[n]);\n}\n\n/* Construct an operator to apply len zeros to a crc.  len must be a power of\n   two.  If len is not a power of two, then the result is the same as for the\n   largest power of two less than len.  The result for len == 0 is the same as\n   for len == 1.  A version of this routine could be easily written for any\n   len, but that is not needed for this application. */\nstatic void crc32c_zeros_op(uint32_t *even, size_t len) {\n    uint32_t odd[32];       /* odd-power-of-two zeros operator */\n\n    /* put operator for one zero bit in odd */\n    odd[0] = POLY;              /* CRC-32C polynomial */\n    uint32_t row = 1;\n    for (unsigned n = 1; n < 32; n++) {\n        odd[n] = row;\n        row <<= 1;\n    }\n\n    /* put operator for two zero bits in even */\n    gf2_matrix_square(even, odd);\n\n    /* put operator for four zero bits in odd */\n    gf2_matrix_square(odd, even);\n\n    /* first square will put the operator for one zero byte (eight zero bits),\n       in even -- next square puts operator for two zero bytes in odd, and so\n       on, until len has been rotated down to zero */\n    do {\n        gf2_matrix_square(even, odd);\n        len >>= 1;\n        if (len == 0)\n            return;\n        gf2_matrix_square(odd, even);\n        len >>= 1;\n    } while (len);\n\n    /* answer ended up in odd -- copy to even */\n    for (unsigned n = 0; n < 32; n++)\n        even[n] = odd[n];\n}\n\n/* Take a length and build four lookup tables for applying the zeros operator\n   for that length, byte-by-byte on the operand. */\nstatic void crc32c_zeros(uint32_t zeros[][256], size_t len) {\n    uint32_t op[32];\n\n    crc32c_zeros_op(op, len);\n    for (unsigned n = 0; n < 256; n++) {\n        zeros[0][n] = gf2_matrix_times(op, n);\n        zeros[1][n] = gf2_matrix_times(op, n << 8);\n        zeros[2][n] = gf2_matrix_times(op, n << 16);\n        zeros[3][n] = gf2_matrix_times(op, n << 24);\n    }\n}\n\n/* Apply the zeros operator table to crc. */\nstatic inline uint32_t crc32c_shift(uint32_t zeros[][256], uint32_t crc) {\n    return zeros[0][crc & 0xff] ^ zeros[1][(crc >> 8) & 0xff] ^\n           zeros[2][(crc >> 16) & 0xff] ^ zeros[3][crc >> 24];\n}\n\n/* Block sizes for three-way parallel crc computation.  LONG and SHORT must\n   both be powers of two.  The associated string constants must be set\n   accordingly, for use in constructing the assembler instructions. */\n#define LONG 8192\n#define LONGx1 \"8192\"\n#define LONGx2 \"16384\"\n#define SHORT 256\n#define SHORTx1 \"256\"\n#define SHORTx2 \"512\"\n\n/* Tables for hardware crc that shift a crc by LONG and SHORT zeros. */\nstatic bool crc32c_once_hw;\nstatic uint32_t crc32c_long[4][256];\nstatic uint32_t crc32c_short[4][256];\n\n/* Initialize tables for shifting crcs. */\nstatic void crc32c_init_hw(void) {\n    crc32c_once_hw = true;\n    crc32c_zeros(crc32c_long, LONG);\n    crc32c_zeros(crc32c_short, SHORT);\n}\n\n/* Compute CRC-32C using the Intel hardware instruction. */\nstatic uint32_t crc32c_hw(uint32_t crc, void const *buf, size_t len) {\n    /* populate shift tables the first time through */\n    if (!crc32c_once_hw)\n\tcrc32c_init_hw();\n\n    /* pre-process the crc */\n    crc = ~crc;\n    uint64_t crc0 = crc;            /* 64-bits for crc32q instruction */\n\n    /* compute the crc for up to seven leading bytes to bring the data pointer\n       to an eight-byte boundary */\n    unsigned char const *next = buf;\n    while (len && ((uintptr_t)next & 7) != 0) {\n        __asm__(\"crc32b\\t\" \"(%1), %0\"\n                : \"=r\"(crc0)\n                : \"r\"(next), \"0\"(crc0));\n        next++;\n        len--;\n    }\n\n    /* compute the crc on sets of LONG*3 bytes, executing three independent crc\n       instructions, each on LONG bytes -- this is optimized for the Nehalem,\n       Westmere, Sandy Bridge, and Ivy Bridge architectures, which have a\n       throughput of one crc per cycle, but a latency of three cycles */\n    while (len >= LONG*3) {\n        uint64_t crc1 = 0;\n        uint64_t crc2 = 0;\n        unsigned char const * const end = next + LONG;\n        do {\n            __asm__(\"crc32q\\t\" \"(%3), %0\\n\\t\"\n                    \"crc32q\\t\" LONGx1 \"(%3), %1\\n\\t\"\n                    \"crc32q\\t\" LONGx2 \"(%3), %2\"\n                    : \"=r\"(crc0), \"=r\"(crc1), \"=r\"(crc2)\n                    : \"r\"(next), \"0\"(crc0), \"1\"(crc1), \"2\"(crc2));\n            next += 8;\n        } while (next < end);\n        crc0 = crc32c_shift(crc32c_long, crc0) ^ crc1;\n        crc0 = crc32c_shift(crc32c_long, crc0) ^ crc2;\n        next += LONG*2;\n        len -= LONG*3;\n    }\n\n    /* do the same thing, but now on SHORT*3 blocks for the remaining data less\n       than a LONG*3 block */\n    while (len >= SHORT*3) {\n        uint64_t crc1 = 0;\n        uint64_t crc2 = 0;\n        unsigned char const * const end = next + SHORT;\n        do {\n            __asm__(\"crc32q\\t\" \"(%3), %0\\n\\t\"\n                    \"crc32q\\t\" SHORTx1 \"(%3), %1\\n\\t\"\n                    \"crc32q\\t\" SHORTx2 \"(%3), %2\"\n                    : \"=r\"(crc0), \"=r\"(crc1), \"=r\"(crc2)\n                    : \"r\"(next), \"0\"(crc0), \"1\"(crc1), \"2\"(crc2));\n            next += 8;\n        } while (next < end);\n        crc0 = crc32c_shift(crc32c_short, crc0) ^ crc1;\n        crc0 = crc32c_shift(crc32c_short, crc0) ^ crc2;\n        next += SHORT*2;\n        len -= SHORT*3;\n    }\n\n    /* compute the crc on the remaining eight-byte units less than a SHORT*3\n       block */\n    {\n        unsigned char const * const end = next + (len - (len & 7));\n        while (next < end) {\n            __asm__(\"crc32q\\t\" \"(%1), %0\"\n                    : \"=r\"(crc0)\n                    : \"r\"(next), \"0\"(crc0));\n            next += 8;\n        }\n        len &= 7;\n    }\n\n    /* compute the crc for up to seven trailing bytes */\n    while (len) {\n        __asm__(\"crc32b\\t\" \"(%1), %0\"\n                : \"=r\"(crc0)\n                : \"r\"(next), \"0\"(crc0));\n        next++;\n        len--;\n    }\n\n    /* return a post-processed crc */\n    return ~crc0;\n}\n\n/* Compute a CRC-32C.  If the crc32 instruction is available, use the hardware\n   version.  Otherwise, use the software version. */\nuint32_t crc32c(uint32_t crc, void const *buf, size_t len) {\n\n    return cpu_supports(\"sse4.2\") ? crc32c_hw(crc, buf, len) : crc32c_sw(crc, buf, len);\n}\n\n#else /* !__x86_64__ */\n\nuint32_t crc32c(uint32_t crc, void const *buf, size_t len) {\n    return crc32c_sw(crc, buf, len);\n}\n\n#endif\n\n/* Construct table for software CRC-32C little-endian calculation. */\nstatic bool crc32c_once_little;\nstatic uint32_t crc32c_table_little[8][256];\nstatic void crc32c_init_sw_little(void) {\n    for (unsigned n = 0; n < 256; n++) {\n        uint32_t crc = n;\n        crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n        crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n        crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n        crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n        crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n        crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n        crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n        crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n        crc32c_table_little[0][n] = crc;\n    }\n    for (unsigned n = 0; n < 256; n++) {\n        uint32_t crc = crc32c_table_little[0][n];\n        for (unsigned k = 1; k < 8; k++) {\n            crc = crc32c_table_little[0][crc & 0xff] ^ (crc >> 8);\n            crc32c_table_little[k][n] = crc;\n        }\n    }\n    crc32c_once_little = true;\n}\n\n/* Compute a CRC-32C in software assuming a little-endian architecture,\n   constructing the required table if that hasn't already been done. */\nstatic uint32_t crc32c_sw_little(uint32_t crc, void const *buf, size_t len) {\n    unsigned char const *next = buf;\n\n    if (!crc32c_once_little)\n\tcrc32c_init_sw_little();\n    crc = ~crc;\n    while (len && ((uintptr_t)next & 7) != 0) {\n        crc = crc32c_table_little[0][(crc ^ *next++) & 0xff] ^ (crc >> 8);\n        len--;\n    }\n    if (len >= 8) {\n        uint64_t crcw = crc;\n        do {\n            crcw ^= *(uint64_t const *)next;\n            crcw = crc32c_table_little[7][crcw & 0xff] ^\n                   crc32c_table_little[6][(crcw >> 8) & 0xff] ^\n                   crc32c_table_little[5][(crcw >> 16) & 0xff] ^\n                   crc32c_table_little[4][(crcw >> 24) & 0xff] ^\n                   crc32c_table_little[3][(crcw >> 32) & 0xff] ^\n                   crc32c_table_little[2][(crcw >> 40) & 0xff] ^\n                   crc32c_table_little[1][(crcw >> 48) & 0xff] ^\n                   crc32c_table_little[0][crcw >> 56];\n            next += 8;\n            len -= 8;\n        } while (len >= 8);\n        crc = crcw;\n    }\n    while (len) {\n        crc = crc32c_table_little[0][(crc ^ *next++) & 0xff] ^ (crc >> 8);\n        len--;\n    }\n    return ~crc;\n}\n\n/* Swap the bytes in a uint64_t.  (Only for big-endian.) */\n#if defined(__has_builtin) || (defined(__GNUC__) && \\\n    (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))\n#  define swap __builtin_bswap64\n#else\nstatic inline uint64_t swap(uint64_t x) {\n    x = ((x << 8) & 0xff00ff00ff00ff00) | ((x >> 8) & 0xff00ff00ff00ff);\n    x = ((x << 16) & 0xffff0000ffff0000) | ((x >> 16) & 0xffff0000ffff);\n    return (x << 32) | (x >> 32);\n}\n#endif\n\n/* Construct tables for software CRC-32C big-endian calculation. */\nstatic bool crc32c_once_big;\nstatic uint32_t crc32c_table_big_byte[256];\nstatic uint64_t crc32c_table_big[8][256];\nstatic void crc32c_init_sw_big(void) {\n    for (unsigned n = 0; n < 256; n++) {\n        uint32_t crc = n;\n        crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n        crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n        crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n        crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n        crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n        crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n        crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n        crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n        crc32c_table_big_byte[n] = crc;\n    }\n    for (unsigned n = 0; n < 256; n++) {\n        uint32_t crc = crc32c_table_big_byte[n];\n        crc32c_table_big[0][n] = swap(crc);\n        for (unsigned k = 1; k < 8; k++) {\n            crc = crc32c_table_big_byte[crc & 0xff] ^ (crc >> 8);\n            crc32c_table_big[k][n] = swap(crc);\n        }\n    }\n    crc32c_once_big = true;\n}\n\n/* Compute a CRC-32C in software assuming a big-endian architecture,\n   constructing the required tables if that hasn't already been done. */\nstatic uint32_t crc32c_sw_big(uint32_t crc, void const *buf, size_t len) {\n    unsigned char const *next = buf;\n\n    if (!crc32c_once_big)\n\tcrc32c_init_sw_big();\n    crc = ~crc;\n    while (len && ((uintptr_t)next & 7) != 0) {\n        crc = crc32c_table_big_byte[(crc ^ *next++) & 0xff] ^ (crc >> 8);\n        len--;\n    }\n    if (len >= 8) {\n        uint64_t crcw = swap(crc);\n        do {\n            crcw ^= *(uint64_t const *)next;\n            crcw = crc32c_table_big[0][crcw & 0xff] ^\n                   crc32c_table_big[1][(crcw >> 8) & 0xff] ^\n                   crc32c_table_big[2][(crcw >> 16) & 0xff] ^\n                   crc32c_table_big[3][(crcw >> 24) & 0xff] ^\n                   crc32c_table_big[4][(crcw >> 32) & 0xff] ^\n                   crc32c_table_big[5][(crcw >> 40) & 0xff] ^\n                   crc32c_table_big[6][(crcw >> 48) & 0xff] ^\n                   crc32c_table_big[7][(crcw >> 56)];\n            next += 8;\n            len -= 8;\n        } while (len >= 8);\n        crc = swap(crcw);\n    }\n    while (len) {\n        crc = crc32c_table_big_byte[(crc ^ *next++) & 0xff] ^ (crc >> 8);\n        len--;\n    }\n    return ~crc;\n}\n\n/* Table-driven software CRC-32C.  This is about 15 times slower than using the\n   hardware instructions.  Determine the endianess of the processor and proceed\n   accordingly.  Ideally the endianess will be determined at compile time, in\n   which case the unused functions and tables for the other endianess will be\n   removed by the optimizer.  If not, then the proper routines and tables will\n   be used, even if the endianess is changed mid-stream.  (Yes, there are\n   processors that permit that -- go figure.) */\nstatic uint32_t crc32c_sw(uint32_t crc, void const *buf, size_t len) {\n    static int const little = 1;\n    if (*(char const *)&little)\n        return crc32c_sw_little(crc, buf, len);\n    else\n        return crc32c_sw_big(crc, buf, len);\n}\n"
  },
  {
    "path": "ccan/ccan/crc32c/crc32c.h",
    "content": "/* Licensed under MIT - see LICENSE file for details */\n#ifndef CCAN_CRC32C_H\n#define CCAN_CRC32C_H\n#include <stdint.h>\n#include <stdlib.h>\n\n/**\n * crc32c - Castagnoli 32 bit crc of string of bytes\n * @start_crc: the initial crc (usually 0)\n * @buf: pointer to bytes\n * @size: length of buffer\n *\n * If you don't know what crc32 to use, use this one: it's the best.\n *\n * @Article{castagnoli-crc,\n * author =       { Guy Castagnoli and Stefan Braeuer and Martin Herrman},\n * title =        {{Optimization of Cyclic Redundancy-Check Codes with 24\n *                 and 32 Parity Bits}},\n * journal =      IEEE Transactions on Communication,\n * year =         {1993},\n * volume =       {41},\n * number =       {6},\n * pages =        {},\n * month =        {June},\n *}\n * 32 bit CRC checksum using polynomial\n * X^32+X^28+X^27+X^26+X^25+X^23+X^22+X^20+X^19+X^18+X^14+X^13+X^11+X^10+X^9+X^8+X^6+X^0.\n *\n * You can calculate the CRC of non-contiguous arrays by passing @start_crc\n * as 0 the first time, and the current crc result from then on.\n *\n * Example:\n *\t#include <sys/uio.h>\n *\t...\n *\t// Check that iovec has the crc we expect (Castagnoli version)\n *\tstatic bool check_crc(uint32_t expected, const struct iovec *iov, int l)\n *\t{\n *\t\tuint32_t crc = 0;\n *\t\twhile (l >= 0) {\n *\t\t\tcrc = crc32c(crc, iov->iov_base, iov->iov_len);\n *\t\t\tiov++;\n *\t\t}\n *\t\treturn crc == expected;\n *\t}\n */\nuint32_t crc32c(uint32_t start_crc, const void *buf, size_t size);\n\n#endif /* CCAN_CRC32C_H */\n"
  },
  {
    "path": "ccan/ccan/crc32c/test/api-crc32c.c",
    "content": "/* Test vectors from https://tools.ietf.org/html/rfc3720#appendix-B.4 */\n#include <ccan/crc32c/crc32c.h>\n#include <ccan/tap/tap.h>\n#include <string.h>\n\n#define BSWAP_32(val)\t\t\t\t\t\\\n\t((((uint32_t)(val) & 0x000000ff) << 24)\t\t\\\n\t | (((uint32_t)(val) & 0x0000ff00) << 8)\t\t\\\n\t | (((uint32_t)(val) & 0x00ff0000) >> 8)\t\t\\\n\t | (((uint32_t)(val) & 0xff000000) >> 24))\n\n#if HAVE_LITTLE_ENDIAN\n#define BE32_TO_CPU(le_val) BSWAP_32((uint32_t)le_val)\n#else\n#define BE32_TO_CPU(le_val) ((uint32_t)(le_val))\n#endif\n\nint main(void)\n{\n\tunsigned char m[48];\n\n\tplan_tests(5);\n\n\t/* 32 bytes of zeroes:\n\n     Byte:        0  1  2  3\n\n        0:       00 00 00 00\n      ...\n       28:       00 00 00 00\n\n      CRC:       aa 36 91 8a\n\t*/\n\n\tmemset(m, 0, 32);\n\tok1(crc32c(0, m, 32) == BE32_TO_CPU(0xaa36918a));\n\n\t/* 32 bytes of ones:\n\n     Byte:        0  1  2  3\n\n        0:       ff ff ff ff\n      ...\n       28:       ff ff ff ff\n\n      CRC:       43 ab a8 62\n\t*/\n\tmemset(m, 0xff, 32);\n\tok1(crc32c(0, m, 32) == BE32_TO_CPU(0x43aba862));\n\n\t/* 32 bytes of incrementing 00..1f:\n\n     Byte:        0  1  2  3\n\n        0:       00 01 02 03\n      ...\n       28:       1c 1d 1e 1f\n\n      CRC:       4e 79 dd 46\n\t*/\n\tfor (size_t i = 0; i < 32; i++)\n\t\tm[i] = i;\n\tok1(crc32c(0, m, 32) == BE32_TO_CPU(0x4e79dd46));\n\n\t/*  32 bytes of decrementing 1f..00:\n\n     Byte:        0  1  2  3\n\n        0:       1f 1e 1d 1c\n      ...\n       28:       03 02 01 00\n\n      CRC:       5c db 3f 11\n\t*/\n\tfor (size_t i = 0; i < 32; i++)\n\t\tm[i] = 31 - i;\n\tok1(crc32c(0, m, 32) == BE32_TO_CPU(0x5cdb3f11));\n\n\t/*  An iSCSI - SCSI Read (10) Command PDU\n    Byte:        0  1  2  3\n\n       0:       01 c0 00 00\n       4:       00 00 00 00\n       8:       00 00 00 00\n      12:       00 00 00 00\n      16:       14 00 00 00\n      20:       00 00 04 00\n      24:       00 00 00 14\n      28:       00 00 00 18\n      32:       28 00 00 00\n      36:       00 00 00 00\n      40:       02 00 00 00\n      44:       00 00 00 00\n\n     CRC:       56 3a 96 d9\n\t*/\n\tmemset(m, 0, sizeof(m));\n\tm[0] = 0x01;\n\tm[1] = 0xc0;\n\tm[16] = 0x14;\n\tm[22] = 0x04;\n\tm[27] = 0x14;\n\tm[31] = 0x18;\n\tm[32] = 0x28;\n\tm[40] = 0x02;\n\tok1(crc32c(0, m, sizeof(m)) == BE32_TO_CPU(0x563a96d9));\n\n\treturn exit_status();\n}\n"
  },
  {
    "path": "ccan/ccan/crc32c/test/run-crc32c.c",
    "content": "/* Test vectors from https://tools.ietf.org/html/rfc3720#appendix-B.4 */\n\n/* Get access to sw version explicitly */\n#include <ccan/crc32c/crc32c.c>\n#include <ccan/tap/tap.h>\n#include <string.h>\n\n#define BSWAP_32(val)\t\t\t\t\t\\\n\t((((uint32_t)(val) & 0x000000ff) << 24)\t\t\\\n\t | (((uint32_t)(val) & 0x0000ff00) << 8)\t\t\\\n\t | (((uint32_t)(val) & 0x00ff0000) >> 8)\t\t\\\n\t | (((uint32_t)(val) & 0xff000000) >> 24))\n\n#if HAVE_LITTLE_ENDIAN\n#define BE32_TO_CPU(le_val) BSWAP_32((uint32_t)le_val)\n#else\n#define BE32_TO_CPU(le_val) ((uint32_t)(le_val))\n#endif\n\nint main(void)\n{\n\tunsigned char m[48];\n\n\tplan_tests(5);\n\n\t/* 32 bytes of zeroes:\n\n     Byte:        0  1  2  3\n\n        0:       00 00 00 00\n      ...\n       28:       00 00 00 00\n\n      CRC:       aa 36 91 8a\n\t*/\n\n\tmemset(m, 0, 32);\n\tok1(crc32c_sw(0, m, 32) == BE32_TO_CPU(0xaa36918a));\n\n\t/* 32 bytes of ones:\n\n     Byte:        0  1  2  3\n\n        0:       ff ff ff ff\n      ...\n       28:       ff ff ff ff\n\n      CRC:       43 ab a8 62\n\t*/\n\tmemset(m, 0xff, 32);\n\tok1(crc32c_sw(0, m, 32) == BE32_TO_CPU(0x43aba862));\n\n\t/* 32 bytes of incrementing 00..1f:\n\n     Byte:        0  1  2  3\n\n        0:       00 01 02 03\n      ...\n       28:       1c 1d 1e 1f\n\n      CRC:       4e 79 dd 46\n\t*/\n\tfor (size_t i = 0; i < 32; i++)\n\t\tm[i] = i;\n\tok1(crc32c_sw(0, m, 32) == BE32_TO_CPU(0x4e79dd46));\n\n\t/*  32 bytes of decrementing 1f..00:\n\n     Byte:        0  1  2  3\n\n        0:       1f 1e 1d 1c\n      ...\n       28:       03 02 01 00\n\n      CRC:       5c db 3f 11\n\t*/\n\tfor (size_t i = 0; i < 32; i++)\n\t\tm[i] = 31 - i;\n\tok1(crc32c_sw(0, m, 32) == BE32_TO_CPU(0x5cdb3f11));\n\n\t/*  An iSCSI - SCSI Read (10) Command PDU\n    Byte:        0  1  2  3\n\n       0:       01 c0 00 00\n       4:       00 00 00 00\n       8:       00 00 00 00\n      12:       00 00 00 00\n      16:       14 00 00 00\n      20:       00 00 04 00\n      24:       00 00 00 14\n      28:       00 00 00 18\n      32:       28 00 00 00\n      36:       00 00 00 00\n      40:       02 00 00 00\n      44:       00 00 00 00\n\n     CRC:       56 3a 96 d9\n\t*/\n\tmemset(m, 0, sizeof(m));\n\tm[0] = 0x01;\n\tm[1] = 0xc0;\n\tm[16] = 0x14;\n\tm[22] = 0x04;\n\tm[27] = 0x14;\n\tm[31] = 0x18;\n\tm[32] = 0x28;\n\tm[40] = 0x02;\n\tok1(crc32c_sw(0, m, sizeof(m)) == BE32_TO_CPU(0x563a96d9));\n\n\treturn exit_status();\n}\n"
  },
  {
    "path": "config.mk",
    "content": "TOPDIR ?= $(CURDIR)\n\nVER ?= $(shell awk '/Version/ {print $$2}'  $(TOPDIR)/mhvtl-utils.spec)\nREL ?= $(shell awk -F'[ %]' '/Release/ {print $$2}' $(TOPDIR)/mhvtl-utils.spec)\nEXTRAVERSION ?= $(shell awk '/define minor/ {print $$3}' $(TOPDIR)/mhvtl-utils.spec)\n\nFIRMWAREDIR ?= $(shell awk '/^%.*_firmwarepath/ {print $$3}' $(TOPDIR)/mhvtl-utils.spec)\n\nGITHASH ?= $(if $(shell test -d $(TOPDIR)/.git && echo 1),commit:\\ $(shell git show -s --format=%h))\nGITDATE ?= $(if $(shell test -d $(TOPDIR)/.git && echo 1),$(shell git show -s --format=%aI))\n\nVERSION ?= $(VER)\n\nPREFIX ?= /usr\nMANDIR ?= /share/man\n\nMHVTL_HOME_PATH ?= /opt/mhvtl\nMHVTL_CONFIG_PATH ?= /etc/mhvtl\nSYSTEMD_GENERATOR_DIR ?= /lib/systemd/system-generators\nSYSTEMD_SERVICE_DIR ?= /lib/systemd/system\n\nifeq ($(shell whoami),root)\nROOTUID = YES\nendif\n\nifeq ($(shell grep lib64$ /etc/ld.so.conf /etc/ld.so.conf.d/* | wc -l),0)\nLIBDIR ?= $(PREFIX)/lib\nelse\nLIBDIR ?= $(PREFIX)/lib64\nendif\n\n-include $(TOPDIR)/local.mk\n\nHOME_PATH = $(subst /,\\/,$(MHVTL_HOME_PATH))\nCONFIG_PATH = $(subst /,\\/,$(MHVTL_CONFIG_PATH))\n"
  },
  {
    "path": "doc/4_library_example/device.conf",
    "content": "\nVERSION: 3\n\n# VPD page format:\n# <page #> <Length> <x> <x+1>... <x+n>\n# NAA format is an 8 hex byte value seperated by ':'\n# Note: NAA is part of inquiry VPD 0x83\n#\n# Each 'record' is sperated by one (or more) blank lines.\n# Each 'record' starts at column 1\n\nLibrary: 10 CHANNEL: 0 TARGET: 1 LUN: 0\n Vendor identification: SPECTRA\n Product identification: PYTHON\n Product revision level: 5500\n Unit serial number: XYZZY_10\n NAA: 10:22:33:44:ab:cd:ef:00\n\nDrive: 11 CHANNEL: 0 TARGET: 1 LUN: 1\n Library ID: 10 Slot: 1\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_11\n NAA: 10:22:33:44:ab:cd:ef:01\n VPD: b0 04 00 02 01 00\n\nDrive: 12 CHANNEL: 0 TARGET: 1 LUN: 2\n Library ID: 10 Slot: 2\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_12\n NAA: 10:22:33:44:ab:cd:ef:02\n VPD: b0 04 00 02 01 00\n\nDrive: 13 CHANNEL: 0 TARGET: 1 LUN: 3\n Library ID: 10 Slot: 3\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_13\n NAA: 10:22:33:44:ab:cd:ef:03\n VPD: b0 04 00 02 01 00\n\nDrive: 14 CHANNEL: 0 TARGET: 1 LUN: 4\n Library ID: 10 Slot: 4\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_14\n NAA: 10:22:33:44:ab:cd:ef:04\n VPD: b0 04 00 02 01 00\n\nDrive: 15 CHANNEL: 0 TARGET: 1 LUN: 5\n Library ID: 10 Slot: 5\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_15\n NAA: 10:22:33:44:ab:cd:ef:05\n VPD: b0 04 00 02 01 00\n\nDrive: 16 CHANNEL: 0 TARGET: 1 LUN: 6\n Library ID: 10 Slot: 6\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_16\n NAA: 10:22:33:44:ab:cd:ef:06\n VPD: b0 04 00 02 01 00\n\nDrive: 17 CHANNEL: 0 TARGET: 1 LUN: 7\n Library ID: 10 Slot: 7\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_17\n NAA: 10:22:33:44:ab:cd:ef:07\n VPD: b0 04 00 02 01 00\n\nDrive: 18 CHANNEL: 0 TARGET: 1 LUN: 8\n Library ID: 10 Slot: 8\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_18\n NAA: 10:22:33:44:ab:cd:ef:08\n VPD: b0 04 00 02 01 00\n\nDrive: 19 CHANNEL: 0 TARGET: 1 LUN: 9\n Library ID: 10 Slot: 9\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_19\n NAA: 10:22:33:44:ab:cd:ef:09\n VPD: b0 04 00 02 01 00\n\nLibrary: 20 CHANNEL: 0 TARGET: 1 LUN: 10\n Vendor identification: SPECTRA\n Product identification: PYTHON\n Product revision level: 5500\n Unit serial number: XYZZY_20\n NAA: 20:22:33:44:ab:cd:ef:00\n\nDrive: 21 CHANNEL: 0 TARGET: 1 LUN: 11\n Library ID: 20 Slot: 1\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_21\n NAA: 20:22:33:44:ab:cd:ef:01\n VPD: b0 04 00 02 01 00\n\nDrive: 22 CHANNEL: 0 TARGET: 1 LUN: 12\n Library ID: 20 Slot: 2\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_22\n NAA: 20:22:33:44:ab:cd:ef:02\n VPD: b0 04 00 02 01 00\n\nDrive: 23 CHANNEL: 0 TARGET: 1 LUN: 13\n Library ID: 20 Slot: 3\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_23\n NAA: 20:22:33:44:ab:cd:ef:03\n VPD: b0 04 00 02 01 00\n\nDrive: 24 CHANNEL: 0 TARGET: 1 LUN: 14\n Library ID: 20 Slot: 4\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_24\n NAA: 20:22:33:44:ab:cd:ef:04\n VPD: b0 04 00 02 01 00\n\nDrive: 25 CHANNEL: 0 TARGET: 1 LUN: 15\n Library ID: 20 Slot: 5\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_25\n NAA: 20:22:33:44:ab:cd:ef:05\n VPD: b0 04 00 02 01 00\n\nDrive: 26 CHANNEL: 0 TARGET: 1 LUN: 16\n Library ID: 20 Slot: 6\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_26\n NAA: 20:22:33:44:ab:cd:ef:06\n VPD: b0 04 00 02 01 00\n\nDrive: 27 CHANNEL: 0 TARGET: 1 LUN: 17\n Library ID: 20 Slot: 7\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_27\n NAA: 20:22:33:44:ab:cd:ef:07\n VPD: b0 04 00 02 01 00\n\nDrive: 28 CHANNEL: 0 TARGET: 1 LUN: 18\n Library ID: 20 Slot: 8\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_28\n NAA: 20:22:33:44:ab:cd:ef:08\n VPD: b0 04 00 02 01 00\n\nDrive: 29 CHANNEL: 0 TARGET: 1 LUN: 19\n Library ID: 20 Slot: 9\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_29\n NAA: 20:22:33:44:ab:cd:ef:09\n VPD: b0 04 00 02 01 00\n\nLibrary: 30 CHANNEL: 0 TARGET: 1 LUN: 20\n Vendor identification: SPECTRA\n Product identification: PYTHON\n Product revision level: 5500\n Unit serial number: XYZZY_30\n NAA: 30:22:33:44:ab:cd:ef:00\n\nDrive: 31 CHANNEL: 0 TARGET: 1 LUN: 21\n Library ID: 30 Slot: 1\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_31\n NAA: 30:22:33:44:ab:cd:ef:01\n VPD: b0 04 00 02 01 00\n\nDrive: 32 CHANNEL: 0 TARGET: 1 LUN: 22\n Library ID: 30 Slot: 2\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_32\n NAA: 30:22:33:44:ab:cd:ef:02\n VPD: b0 04 00 02 01 00\n\nDrive: 33 CHANNEL: 0 TARGET: 1 LUN: 23\n Library ID: 30 Slot: 3\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_33\n NAA: 30:22:33:44:ab:cd:ef:03\n VPD: b0 04 00 02 01 00\n\nDrive: 34 CHANNEL: 0 TARGET: 1 LUN: 24\n Library ID: 30 Slot: 4\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_34\n NAA: 30:22:33:44:ab:cd:ef:04\n VPD: b0 04 00 02 01 00\n\nDrive: 35 CHANNEL: 0 TARGET: 1 LUN: 25\n Library ID: 30 Slot: 5\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_35\n NAA: 30:22:33:44:ab:cd:ef:05\n VPD: b0 04 00 02 01 00\n\nDrive: 36 CHANNEL: 0 TARGET: 1 LUN: 26\n Library ID: 30 Slot: 6\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_36\n NAA: 30:22:33:44:ab:cd:ef:06\n VPD: b0 04 00 02 01 00\n\nDrive: 37 CHANNEL: 0 TARGET: 1 LUN: 27\n Library ID: 30 Slot: 7\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_37\n NAA: 30:22:33:44:ab:cd:ef:07\n VPD: b0 04 00 02 01 00\n\nDrive: 38 CHANNEL: 0 TARGET: 1 LUN: 28\n Library ID: 30 Slot: 8\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_38\n NAA: 30:22:33:44:ab:cd:ef:08\n VPD: b0 04 00 02 01 00\n\nDrive: 39 CHANNEL: 0 TARGET: 1 LUN: 29\n Library ID: 30 Slot: 9\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_39\n NAA: 30:22:33:44:ab:cd:ef:09\n VPD: b0 04 00 02 01 00\n\nLibrary: 40 CHANNEL: 0 TARGET: 1 LUN: 30\n Vendor identification: SPECTRA\n Product identification: PYTHON\n Product revision level: 5500\n Unit serial number: XYZZY_40\n NAA: 40:22:33:44:ab:cd:ef:00\n\nDrive: 41 CHANNEL: 0 TARGET: 1 LUN: 31\n Library ID: 40 Slot: 1\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_41\n NAA: 40:22:33:44:ab:cd:ef:01\n VPD: b0 04 00 02 01 00\n\nDrive: 42 CHANNEL: 0 TARGET: 2 LUN: 0\n Library ID: 40 Slot: 2\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_42\n NAA: 40:22:33:44:ab:cd:ef:02\n VPD: b0 04 00 02 01 00\n\nDrive: 43 CHANNEL: 0 TARGET: 2 LUN: 1\n Library ID: 40 Slot: 3\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_43\n NAA: 40:22:33:44:ab:cd:ef:03\n VPD: b0 04 00 02 01 00\n\nDrive: 44 CHANNEL: 0 TARGET: 2 LUN: 2\n Library ID: 40 Slot: 4\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_44\n NAA: 40:22:33:44:ab:cd:ef:04\n VPD: b0 04 00 02 01 00\n\nDrive: 45 CHANNEL: 0 TARGET: 2 LUN: 3\n Library ID: 40 Slot: 5\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_45\n NAA: 40:22:33:44:ab:cd:ef:05\n VPD: b0 04 00 02 01 00\n\nDrive: 46 CHANNEL: 0 TARGET: 2 LUN: 4\n Library ID: 40 Slot: 6\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_46\n NAA: 40:22:33:44:ab:cd:ef:06\n VPD: b0 04 00 02 01 00\n\nDrive: 47 CHANNEL: 0 TARGET: 2 LUN: 5\n Library ID: 40 Slot: 7\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_47\n NAA: 40:22:33:44:ab:cd:ef:07\n VPD: b0 04 00 02 01 00\n\nDrive: 48 CHANNEL: 0 TARGET: 2 LUN: 6\n Library ID: 40 Slot: 8\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_48\n NAA: 40:22:33:44:ab:cd:ef:08\n VPD: b0 04 00 02 01 00\n\nDrive: 49 CHANNEL: 0 TARGET: 2 LUN: 7\n Library ID: 40 Slot: 9\n Vendor identification: QUANTUM\n Product identification: SDLT600\n Product revision level: 5500\n Unit serial number: XYZZY_49\n NAA: 40:22:33:44:ab:cd:ef:09\n VPD: b0 04 00 02 01 00\n\n"
  },
  {
    "path": "doc/4_library_example/library_contents.10",
    "content": "VERSION: 2\n\nDrive 1:\nDrive 2:\nDrive 3:\nDrive 4:\nDrive 5:\nDrive 6:\nDrive 7:\nDrive 8:\nDrive 9:\n\nPicker 1:\n\nMAP 1:\nMAP 2:\nMAP 3:\nMAP 4:\n\n# Slot 1 - ?, no gaps\n# Slot N: [barcode]\n# [barcode]\n# a barcode is comprised of three fields: [Leading] [identifier] [Trailing]\n# Leading \"CLN\" -- cleaning tape\n# Leading \"W\" -- WORM tape\n# Leading \"NOBAR\" -- will appear to have no barcode\n# If the barcode is at least 8 character long, then the last two characters are\nTrailing\n# Trailing \"S3\" - SDLT600\n# Trailing \"X4\" - AIT-4\n# Trailing \"L1\" - LTO 1\n# Trailing \"TA\" - T10000+\n# Trailing \"JA\" - 3592+\n# Trailing \"JB\" - 3592E05+\n# Trailing \"JW\" - WORM 3592+\n# Trailing \"JX\" - WORM 3592E05+\n#\nSlot 01: L10001S3\nSlot 02: L10002S3\nSlot 03: L10003S3\nSlot 04: L10004S3\nSlot 05: L10005S3\nSlot 06: L10006S3\nSlot 07: L10007S3\nSlot 08: L10008S3\nSlot 09: L10009S3\nSlot 10: L10010S3\nSlot 11: L10011S3\nSlot 12: L10012S3\nSlot 13: L10013S3\nSlot 14: L10014S3\nSlot 15: L10015S3\nSlot 16: L10016S3\nSlot 17: L10017S3\nSlot 18: L10018S3\nSlot 19: L10019S3\nSlot 20: L10020S3\nSlot 21: L10021S3\nSlot 22: L10022S3\nSlot 23: L10023S3\nSlot 24: L10024S3\nSlot 25: L10025S3\nSlot 26: L10026S3\nSlot 27: L10027S3\nSlot 28: L10028S3\nSlot 29: L10029S3\nSlot 30: L10030S3\nSlot 31: L10031S3\nSlot 32: L10032S3\nSlot 33: L10033S3\nSlot 34: L10034S3\nSlot 35: L10035S3\nSlot 36: L10036S3\nSlot 37: L10037S3\nSlot 38: L10038S3\nSlot 39: L10039S3\nSlot 40: L10040S3\nSlot 41: L10041S3\nSlot 42: L10042S3\nSlot 43: L10043S3\nSlot 44: L10044S3\nSlot 45: L10045S3\nSlot 46: L10046S3\nSlot 47: L10047S3\nSlot 48: L10048S3\nSlot 49: L10049S3\nSlot 50: L10050S3\n"
  },
  {
    "path": "doc/4_library_example/library_contents.20",
    "content": "VERSION: 2\n\nDrive 1:\nDrive 2:\nDrive 3:\nDrive 4:\nDrive 5:\nDrive 6:\nDrive 7:\nDrive 8:\nDrive 9:\n\nPicker 1:\n\nMAP 1:\nMAP 2:\nMAP 3:\nMAP 4:\n\n# Slot 1 - ?, no gaps\n# Slot N: [barcode]\n# [barcode]\n# a barcode is comprised of three fields: [Leading] [identifier] [Trailing]\n# Leading \"CLN\" -- cleaning tape\n# Leading \"W\" -- WORM tape\n# Leading \"NOBAR\" -- will appear to have no barcode\n# If the barcode is at least 8 character long, then the last two characters are\nTrailing\n# Trailing \"S3\" - SDLT600\n# Trailing \"X4\" - AIT-4\n# Trailing \"L1\" - LTO 1\n# Trailing \"TA\" - T10000+\n# Trailing \"JA\" - 3592+\n# Trailing \"JB\" - 3592E05+\n# Trailing \"JW\" - WORM 3592+\n# Trailing \"JX\" - WORM 3592E05+\n#\nSlot 01: L20001S3\nSlot 02: L20002S3\nSlot 03: L20003S3\nSlot 04: L20004S3\nSlot 05: L20005S3\nSlot 06: L20006S3\nSlot 07: L20007S3\nSlot 08: L20008S3\nSlot 09: L20009S3\nSlot 10: L20010S3\nSlot 11: L20011S3\nSlot 12: L20012S3\nSlot 13: L20013S3\nSlot 14: L20014S3\nSlot 15: L20015S3\nSlot 16: L20016S3\nSlot 17: L20017S3\nSlot 18: L20018S3\nSlot 19: L20019S3\nSlot 20: L20020S3\nSlot 21: L20021S3\nSlot 22: L20022S3\nSlot 23: L20023S3\nSlot 24: L20024S3\nSlot 25: L20025S3\nSlot 26: L20026S3\nSlot 27: L20027S3\nSlot 28: L20028S3\nSlot 29: L20029S3\nSlot 30: L20030S3\nSlot 31: L20031S3\nSlot 32: L20032S3\nSlot 33: L20033S3\nSlot 34: L20034S3\nSlot 35: L20035S3\nSlot 36: L20036S3\nSlot 37: L20037S3\nSlot 38: L20038S3\nSlot 39: L20039S3\nSlot 40: L20040S3\nSlot 41: L20041S3\nSlot 42: L20042S3\nSlot 43: L20043S3\nSlot 44: L20044S3\nSlot 45: L20045S3\nSlot 46: L20046S3\nSlot 47: L20047S3\nSlot 48: L20048S3\nSlot 49: L20049S3\nSlot 50: L20050S3\n"
  },
  {
    "path": "doc/4_library_example/library_contents.30",
    "content": "VERSION: 2\n\nDrive 1:\nDrive 2:\nDrive 3:\nDrive 4:\nDrive 5:\nDrive 6:\nDrive 7:\nDrive 8:\nDrive 9:\n\nPicker 1:\n\nMAP 1:\nMAP 2:\nMAP 3:\nMAP 4:\n\n# Slot 1 - ?, no gaps\n# Slot N: [barcode]\n# [barcode]\n# a barcode is comprised of three fields: [Leading] [identifier] [Trailing]\n# Leading \"CLN\" -- cleaning tape\n# Leading \"W\" -- WORM tape\n# Leading \"NOBAR\" -- will appear to have no barcode\n# If the barcode is at least 8 character long, then the last two characters are\nTrailing\n# Trailing \"S3\" - SDLT600\n# Trailing \"X4\" - AIT-4\n# Trailing \"L1\" - LTO 1\n# Trailing \"TA\" - T10000+\n# Trailing \"JA\" - 3592+\n# Trailing \"JB\" - 3592E05+\n# Trailing \"JW\" - WORM 3592+\n# Trailing \"JX\" - WORM 3592E05+\n#\nSlot 01: L30001S3\nSlot 02: L30002S3\nSlot 03: L30003S3\nSlot 04: L30004S3\nSlot 05: L30005S3\nSlot 06: L30006S3\nSlot 07: L30007S3\nSlot 08: L30008S3\nSlot 09: L30009S3\nSlot 10: L30010S3\nSlot 11: L30011S3\nSlot 12: L30012S3\nSlot 13: L30013S3\nSlot 14: L30014S3\nSlot 15: L30015S3\nSlot 16: L30016S3\nSlot 17: L30017S3\nSlot 18: L30018S3\nSlot 19: L30019S3\nSlot 20: L30020S3\nSlot 21: L30021S3\nSlot 22: L30022S3\nSlot 23: L30023S3\nSlot 24: L30024S3\nSlot 25: L30025S3\nSlot 26: L30026S3\nSlot 27: L30027S3\nSlot 28: L30028S3\nSlot 29: L30029S3\nSlot 30: L30030S3\nSlot 31: L30031S3\nSlot 32: L30032S3\nSlot 33: L30033S3\nSlot 34: L30034S3\nSlot 35: L30035S3\nSlot 36: L30036S3\nSlot 37: L30037S3\nSlot 38: L30038S3\nSlot 39: L30039S3\nSlot 40: L30040S3\nSlot 41: L30041S3\nSlot 42: L30042S3\nSlot 43: L30043S3\nSlot 44: L30044S3\nSlot 45: L30045S3\nSlot 46: L30046S3\nSlot 47: L30047S3\nSlot 48: L30048S3\nSlot 49: L30049S3\nSlot 50: L30050S3\n"
  },
  {
    "path": "doc/4_library_example/library_contents.40",
    "content": "VERSION: 2\n\nDrive 1:\nDrive 2:\nDrive 3:\nDrive 4:\nDrive 5:\nDrive 6:\nDrive 7:\nDrive 8:\nDrive 9:\n\nPicker 1:\n\nMAP 1:\nMAP 2:\nMAP 3:\nMAP 4:\n\n# Slot 1 - ?, no gaps\n# Slot N: [barcode]\n# [barcode]\n# a barcode is comprised of three fields: [Leading] [identifier] [Trailing]\n# Leading \"CLN\" -- cleaning tape\n# Leading \"W\" -- WORM tape\n# Leading \"NOBAR\" -- will appear to have no barcode\n# If the barcode is at least 8 character long, then the last two characters are\nTrailing\n# Trailing \"S3\" - SDLT600\n# Trailing \"X4\" - AIT-4\n# Trailing \"L1\" - LTO 1\n# Trailing \"TA\" - T10000+\n# Trailing \"JA\" - 3592+\n# Trailing \"JB\" - 3592E05+\n# Trailing \"JW\" - WORM 3592+\n# Trailing \"JX\" - WORM 3592E05+\n#\nSlot 01: L40001S3\nSlot 02: L40002S3\nSlot 03: L40003S3\nSlot 04: L40004S3\nSlot 05: L40005S3\nSlot 06: L40006S3\nSlot 07: L40007S3\nSlot 08: L40008S3\nSlot 09: L40009S3\nSlot 10: L40010S3\nSlot 11: L40011S3\nSlot 12: L40012S3\nSlot 13: L40013S3\nSlot 14: L40014S3\nSlot 15: L40015S3\nSlot 16: L40016S3\nSlot 17: L40017S3\nSlot 18: L40018S3\nSlot 19: L40019S3\nSlot 20: L40020S3\nSlot 21: L40021S3\nSlot 22: L40022S3\nSlot 23: L40023S3\nSlot 24: L40024S3\nSlot 25: L40025S3\nSlot 26: L40026S3\nSlot 27: L40027S3\nSlot 28: L40028S3\nSlot 29: L40029S3\nSlot 30: L40030S3\nSlot 31: L40031S3\nSlot 32: L40032S3\nSlot 33: L40033S3\nSlot 34: L40034S3\nSlot 35: L40035S3\nSlot 36: L40036S3\nSlot 37: L40037S3\nSlot 38: L40038S3\nSlot 39: L40039S3\nSlot 40: L40040S3\nSlot 41: L40041S3\nSlot 42: L40042S3\nSlot 43: L40043S3\nSlot 44: L40044S3\nSlot 45: L40045S3\nSlot 46: L40046S3\nSlot 47: L40047S3\nSlot 48: L40048S3\nSlot 49: L40049S3\nSlot 50: L40050S3\n"
  },
  {
    "path": "doc/4_library_example/mhvtl.conf",
    "content": "\n# Home directory for config file(s)\nMHVTL_CONFIG_PATH=/etc/mhvtl\n\n# Default media capacity (5 G)\nCAPACITY=5000\n\n# Set default verbosity [0|1]\nVERBOSE=0\n\n# Set kernel module debugging [0|1]\nVTL_DEBUG=0\n"
  },
  {
    "path": "doc/index.html",
    "content": "<html>\n\n<h1 align=\"center\">Welcome to Mark Harvey's home page</h1>\n\n<hr width=\"80%\">\n\n<h2 align=\"center\">Current projects:</h2>\n\t<ul>\n\t<li><a href=\"#vtl\">Virtual Tape Library</a>\n\t\t<ul>\n\t\t<li><a href=\"#vtl-intro\">Introduction</a>\n\t\t<li><a href=\"#vtl-vtltape\">vtltape daemon</a>\n\t\t<li><a href=\"#vtl-vtllibrary\">vtllibrary daemon</a>\n\t\t<li><a href=\"#vtl-vtlcmd\">vtlcmd control utility</a>\n\t\t<li><a href=\"#vtl-examples-lsscsi\">Operational examples (lsscsi -g)</a>\n\t\t<li><a href=\"#vtl-examples-tpautoconf\">Operational examples (tpautoconf)</a>\n\t\t<li><a href=\"#vtl-examples-robtest\">Operational examples (robtest)</a>\n\t\t<li><a href=\"#vtl-examples-TapeAlert\">TapeAlert examples</a>\n\t\t<li><a href=\"#vtl-download\">Download</a>\n\t\t</ul>\n\t</ul>\n\n<hr width=\"80%\">\n\n<a NAME=\"vtl-intro\"></a>\n\t<h2 align=\"left\">Virtual Tape Library:</h2>\n\t<p>Virtual Tape Library consists of several components.</p>\n\n\t<ul>\n\t<li>LLD - A low level driver implemented as a kernel module - vx_tape</li>\n\t<li>Target devices - Daemons <b>vtltape(1)</b> and <b>vtllibrary(1)</b> which implement SCSI target device(s) in user-space</li>\n\t<li>Utility commands <b>mktape(1)</b>, <b>vtlcmd(1)</b></li>\n\t<li>And setup script <b>make_vtl_media(1)</b></li>\n\t</ul>\n\n\n<p>\nThe kernel module is based on the scsi_debug kernel module\n(<a href=http://www.torque.net/sg/sdebug26.html>http://www.torque.net/sg/sdebug26.html</a>).\nvx_tape is a pseudo HBA (LLD) reporting it has 1 x SMC target (StorageTek L700)\nand 8 x SSC targets (4 x IBM Ultrium-TD3 and 4 x Quantum SuperDLT600)\nattached.\n</p>\n\n<p>\nA char device back-end has been included with the vx_tape LLD\ndriver This allows data and SCSI commands to be passed from the LLD\nto user-mode daemons (SCSI targets) which constently poll the driver\nand process any outstanding SCSI commands.\n<p>\n\n<p>\n<a NAME=\"vtl-vtltape\"></a>\n<h3>vtltape</h3>\n<b>vtltape(1)</b> is the usermode SSC target daemon which writes/reads\n data to data files in the /opt/vtl directory\n(if  a virtual tape has been loaded). The virtual tape files include a\nMedium Auxiliary Memory (MAM) data structure to store  persistent  data\n(number of tape loads, total data written/read, media type etc).\n</p>\n\n<p>\n<a NAME=\"vtl-vtllibrary\"></a>\n<h3>vtllibrary</h3>\n<b>vtllibrary(1)</b> is the usermode SMC target daemon which reads its\nconfiguration from the file /etc/vtl/<b>library_contents(5)</b>\nat startup. The number of storage slots are built dynamically\nwhen the daemon starts. Hence changing the number of storage slots and\nmedia access slots are a matter of modifing the file contents and\nrestarting  the  vtllibrary(1)  daemon. All 'library' commands are\nperformed on data structures in memory ONLY.\n</p>\n\n<p>\n<a NAME=\"vtl-vtlcmd\"></a>\n<h3>vtlcmd</h3>\nA utility <b>vtlcmd(1)</b> is used to administrator the daemons <b>vtltape(1)</b>\nand <b>vtllibrary</b>.<br>\nMessage queue (key 0x4d61726b) is used to pass messages between\n<b>vtlcmd(1)</b>, <b>vtllibrary(1)</b> and <b>vtltape(1)</b>\n</p>\n\n<p>\nWhen a SCSI 'move medium' from a storage slot to a tape drive is requested,\nthe media location is updated in vtllibrary(1) data structures, and  the\nbarcode  of  the  media  id  is  passed  via  the  message queue to the\nvtltape(1) daemon in question. A file open of the barcode  is  attempted\nin  the /opt/vtl directory and if successful, the vtltape(1) daemon\nwill now return a ASC/ASCQ 0x0/0x0 to any Test Unit Ready requests.  An\nunload SCSI command to the tape drive will close the data file.\n</p>\n\n<p>\nMedia can be moved out of the VTL via the Media Access Port. Once media\nis logically moved into the MAP slots, the MAP entries can  be  cleared\nusing the vtlcmd:\n</p>\n\n<pre>\n# vtlcmd library empty map\n</pre>\n\n<a NAME=\"vtl-examples-lsscsi\"></a>\n<h4>Examples</h4>\n\nvx_tape is registered as HBA #3:\n<pre>\n# lsscsi -g\n[0:0:0:0]    disk    MAXTOR   ATLAS10K4_36SCA  DFM0  /dev/sda  /dev/sg0\n[0:0:6:0]    process PE/PV    1x3 SCSI BP      1.1   -         /dev/sg1\n[2:0:0:0]    disk    SEAGATE  ST336607FC       0003  /dev/sdb  /dev/sg2\n[2:0:1:0]    disk    SEAGATE  ST336607FC       0003  /dev/sdc  /dev/sg3\n[2:0:2:0]    mediumx ATL      1500             6.0   -         /dev/sg4\n[2:0:2:1]    tape    QUANTUM  SuperDLT1        2323  /dev/st0  /dev/sg5\n[2:0:2:2]    tape    QUANTUM  SuperDLT1        2323  /dev/st1  /dev/sg6\n[2:0:2:3]    process ATTO     310-LV           1.42  -         /dev/sg7\n[3:0:0:0]    mediumx STK      L700             vx_0  -         /dev/sg8\n[4:0:0:0]    tape    IBM      ULT3580-TD3      5400  /dev/st2  /dev/sg9\n[4:0:0:1]    tape    IBM      ULT3580-TD3      5400  /dev/st3  /dev/sg10\n[4:0:0:2]    tape    IBM      ULT3580-TD3      5400  /dev/st4  /dev/sg11\n[4:0:0:3]    tape    IBM      ULT3580-TD3      5400  /dev/st5  /dev/sg12\n[4:0:0:4]    tape    QUANTUM  SDLT600          5400  /dev/st6  /dev/sg13\n[4:0:0:5]    tape    QUANTUM  SDLT600          5400  /dev/st7  /dev/sg14\n[4:0:0:6]    tape    QUANTUM  SDLT600          5400  /dev/st8  /dev/sg15\n[4:0:0:7]    tape    QUANTUM  SDLT600          5400  /dev/st9  /dev/sg16\n</pre>\n\n<a NAME=\"vtl-examples-tpautoconf\"></a>\nNetBackup Utilities:\n<pre>\n# tpautoconf -r\nTPAC45 STK     L700            vx_0 8000 -1 -1 -1 -1 /dev/sg/h3c0t0l0 - -\n\n# tpautoconf -t\nTPAC45 IBM     ULT3580-TD3     5400 8001 -1 -1 -1 -1 /dev/st/nh3c0t0l1 - TapeAlert enabled\nTPAC45 IBM     ULT3580-TD3     5400 8002 -1 -1 -1 -1 /dev/st/nh3c0t0l2 - TapeAlert enabled\nTPAC45 IBM     ULT3580-TD3     5400 8003 -1 -1 -1 -1 /dev/st/nh3c0t0l3 - TapeAlert enabled\nTPAC45 IBM     ULT3580-TD3     5400 8004 -1 -1 -1 -1 /dev/st/nh3c0t0l4 - TapeAlert enabled\nTPAC45 QUANTUM SDLT600         5400 8005 -1 -1 -1 -1 /dev/st/nh3c0t0l5 - TapeAlert enabled\nTPAC45 QUANTUM SDLT600         5400 8006 -1 -1 -1 -1 /dev/st/nh3c0t0l6 - TapeAlert enabled\nTPAC45 QUANTUM SDLT600         5400 8007 -1 -1 -1 -1 /dev/st/nh3c0t0l7 - TapeAlert enabled\nTPAC45 QUANTUM SDLT600         5400 8008 -1 -1 -1 -1 /dev/st/nh3c0t0l8 - TapeAlert enabled\n\n</pre>\n\n<p>\n <a href=http://sites.google.com/site/linuxvtl2/scan.txt>volmgr/bin/scan output</a> </p>\n\n<a NAME=\"vtl-examples-robtest\"></a>\n<h4>Robot Inventory:</h4>\n\n<p> <a href=http://sites.google.com/site/linuxvtl2/mtx.txt>Using mtx</a> </p>\n<p> <a href=http://sites.google.com/site/linuxvtl2/robtest.txt>Using robtest</a> </p>\n\nA sample /etc/vtl/library_contents can be <a href=http://sites.google.com/site/linuxvtl2/library_contents.txt>viewed via this link.</a>\n\n\n<a NAME=\"vtl-examples-TapeAlert\"></a>\n<h3>TapeAlert</h3>\n<p>TapeAlert flags can be set using the <b>vtlcmd(1)</b></p>\n<p>e.g. vtlcmd [index|library] TapeAlert [flags]</p>\n<p>Where index is the message Q offset (or string 'library') associated with the drive.</p>\n<p>e.g. To set flag 14h (Clean now) the 20th bit (14h) needs to be set:<br>\nPull out the binary to decimal calculator<br>\n1000 0000 0000 0000 0000 (20 bits) =&gt hex =&gt 80000</p>\n<pre># vtlcmd 1 TapeAlert 80000</pre>\n<p>A listing of TapeAlert flags can be found at <a href=http://www.t10.org/ftp/t10/drafts/ssc3/ssc3r01e.pdf>t10 home page for SSC devices</a>\nAnnex A.</p>\n\n<table border=\"3\">\n<tr>\n<th>Code</th>\n<th>vtlcmd value</th>\n<th>Flag</th>\n<th>Type</th>\n<th>Flag Type</th>\n<th>Recommended application client message</th>\n<th>Probable cause</th>\n</tr>\n\n<tr>\n<td align=\"center\">01h</td>\n<td align=\"right\">1</td>\n<td>Read warning</td>\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>The tape drive is having problems reading data. No data has been lost, but there has been a reduction in the performance of the tape.</td>\n<td>The drive is having severe trouble reading.</td>\n</tr>\n\n<tr>\n<td align=\"center\">02h</td>\n<td align=\"right\">2</td>\n<td>Write warning</td>\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>The tape drive is having problems writing data. No\ndata has been lost, but there has been a reduction in\nthe capacity of the tape.</td>\n<td>The drive is having severe trouble writing.</td>\n</tr>\n\n<tr>\n<td align=\"center\">03h</td>\n<td align=\"right\">4</td>\n<td>Hard error</td>\n<td align=\"center\">M</td>\n<td align=\"center\">W</td>\n<td>The operation has stopped because an error has\noccurred while reading or writing data that the drive\ncannot correct.</td>\n<td>The drive had a hard\nread or write error.</td>\n</tr>\n\n<tr>\n<td align=\"center\">04h</td>\n<td align=\"right\">8</td>\n<td>Media</td>\n<td align=\"center\">M</td>\n<td align=\"center\">C</td>\n<td>Your data is at risk:\n<ol>\n<li>Copy any data you require from this tape.<br>\n<li>Do not use this tape again.<br>\n<li>Restart the operation with a different tape.</td>\n</ol>\n<td>Media can no longer be written/read, or performance is severely degraded.</td>\n</tr>\n\n<tr>\n<td align=\"center\">05h</td>\n<td align=\"right\">10</td>\n<td>Read failure</td>\n<td align=\"center\">M</td>\n<td align=\"center\">C</td>\n<td>The tape is damaged or the drive is faulty. Call the tape drive supplier help line.</td>\n\n<td>The drive can no longer read data from the tape.</td>\n</tr>\n\n<tr>\n<td align=\"center\">06h</td>\n<td align=\"right\">20</td>\n<td>Write failure</td>\n<td align=\"center\">M</td>\n<td align=\"center\">C</td>\n<td>The tape is from a faulty batch or the tape drive is\nfaulty:<br>\n<ol>\n<li>Use a good tape to test the drive.<br>\n<li>If the problem persists, call the tape drive supplier help line.</td>\n</ol>\n\n<td>The drive can no longer write data to the tape.</td>\n</tr>\n<tr>\n<td align=\"center\">07h</td>\n<td align=\"right\">40</td>\n<td>Media life</td>\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>The tape cartridge has reached the end of its calculated useful life:\n<ol>\n<li>Copy any data you need to another tape.<br>\n<li>Discard the old tape.</td>\n</ol>\n<td>The media has exceeded its specified life.</td>\n</tr>\n<tr>\n<td align=\"center\">08h</td>\n<td align=\"right\">80</td>\n<td>Not data grade</td>\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>The cartridge is not data-grade. Any data you write to the tape is at risk. Replace the cartridge with a data-grade tape.</td>\n<td>The drive has not been able to read the MRSa stripes.</td>\n</tr>\n\n<tr>\n<td align=\"center\">09h</td>\n<td align=\"right\">100</td>\n<td>Write protect</td>\n<td align=\"center\">O</td>\n<td align=\"center\">C</td>\n<td>You are trying to write to a write protected cartridge.  Remove the write protection or use another tape.</td>\n<td>Write command is attempted to a write protected tape.</td>\n</tr>\n\n<tr>\n<td align=\"center\">0Ah</td>\n<td align=\"right\">200</td>\n<td>No removal</td>\n<td align=\"center\">O</td>\n<td align=\"center\">I</td>\n<td>You cannot eject the cartridge because the tape drive is in use. Wait until the operation is complete before ejecting the cartridge.</td>\n<td>Manual or software unload attempted when prevent media removal is on.</td>\n</tr>\n\n<tr>\n<td align=\"center\">0Bh</td>\n<td align=\"right\">400</td>\n<td>Cleaning media</td>\n<td align=\"center\">O</td>\n<td align=\"center\">I</td>\n<td>The tape in the drive is a cleaning cartridge. Cleaning tape loaded into drive.</td>\n</tr>\n\n<tr>\n<td align=\"center\">0Ch</td>\n<td align=\"right\">800</td>\n<td>Unsupported format</td>\n<td align=\"center\">O</td>\n<td align=\"center\">I</td>\n<td>You have tried to load a cartridge of a type that is not\nsupported by this drive.</td>\n<td>Attempted load of unsupported tape format (e.g., DDS2 in DDS1 drive).</td>\n</tr>\n\n<tr>\n<td align=\"center\">0Dh</td>\n<td align=\"right\">1000</td>\n<td>Recoverable mechanical cartridge failure</td>\n<td align=\"center\">O</td>\n<td align=\"center\">C</td>\n<td>The operation has failed because the tape in the\ndrive has experienced a mechanical failure:<br>\n<ol>\n<li>Discard the old tape.<br>\n<li>Restart the operation with a different tape.</td>\n</ol>\n<td>Tape snapped/cut or other cartridge mechanical failure in the drive where medium can be de-mounted.</td>\n</tr>\n\n<tr>\n<td align=\"center\">0Eh</td>\n<td align=\"right\">2000</td>\n<td>Unrecoverable mechanical cartridge failure</td>\n<td align=\"center\">O</td>\n<td align=\"center\">C</td>\n<td>The operation has failed because the tape in the\ndrive has experienced a mechanical failure:<br>\n<ol>\n<li>Do not attempt to extract the tape cartridge.<br>\n<li>Call the tape drive supplier help line.</td>\n</ol>\n<td>Tape snapped/cut or other cartridge mechanical failure in the drive where medium cannot be de-mounted.</td>\n</tr>\n\n<tr>\n<td align=\"center\">0Fh</td>\n<td align=\"right\">4000</td>\n<td>Memory chip in cartridge failure</td>\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>The memory in the tape cartridge has failed, which reduces performance. Do not use the cartridge for further write operations.</td>\n<td>Memory chip failed in cartridge.</td>\n</tr>\n\n<td align=\"center\">10h</td>\n<td align=\"right\">8000</td>\n<td>Forced eject</td>\n<td align=\"center\">O</td>\n<td align=\"center\">C</td>\n<td>The operation has failed because the tape cartridge was manually de-mounted while the tape drive was actively writing or reading.</td>\n<td>Manual or forced eject while drive actively writing or reading.</td>\n</tr>\n\n<tr>\n<td align=\"center\">11h</td>\n<td align=\"right\">10000</td>\n<td>Read only format</td>\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>You have loaded a cartridge of a type that is read-only in this drive. The cartridge will appear as write protected.</td>\n<td>Media loaded that is read-only format.</td>\n</tr>\n\n<tr>\n<td align=\"center\">12h</td>\n<td align=\"right\">20000</td>\n<td>Tape directory corrupted on load</td>\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>The tape directory on the tape cartridge has been corrupted. File search performance will be degraded.  The tape directory can be rebuilt by reading all the data on the cartridge.</td>\n<td>Tape drive powered down with tape loaded, or permanent error prevented the tape directory being updated.</td>\n</tr>\n\n<tr>\n<td align=\"center\">13h</td>\n<td align=\"right\">40000</td>\n<td>Nearing media life</td>\n<td align=\"center\">O</td>\n<td align=\"center\">I</td>\n<td>The tape cartridge is nearing the end of its calculated life. It is recommended that you:<br>\n<ol>\n<li>Use another tape cartridge for your next backup.<br>\n<li>Store this tape cartridge in a safe place in case you need to restore data from it.</td>\n</ol>\n<td>Media may have exceeded its specified number of passes.</td>\n</tr>\n\n<tr>\n<td align=\"center\">14h</td>\n<td align=\"right\">80000</td>\n<td>Clean now</td>\n<td align=\"center\">O</td>\n<td align=\"center\">C</td>\n<td>The tape drive needs cleaning:<br>\n<ol>\n<li>If the operation has stopped, eject the tape and\nclean the drive.\n<li>If the operation has not stopped, wait for it to finish\nand then clean the drive.\n</ol>\nCheck the tape drive users manual for device specific\ncleaning instructions.</td>\n<td>The drive thinks it has a head clog or needs cleaning.</td>\n</tr>\n\n<tr>\n<td align=\"center\">15h</td>\n<td align=\"right\">100000</td>\n<td>Clean periodic</td>\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>The tape drive is due for routine cleaning:\n<ol>\n<li>Wait for the current operation to finish.\n<li>Then use a cleaning cartridge.\n</ol></td>\n<td>Check the tape drive users manual for device specific cleaning instructions.\nThe drive is ready for a periodic cleaning.</td>\n</tr>\n\n<tr>\n<td align=\"center\">16h</td>\n<td align=\"right\">200000</td>\n<td>Expired cleaning media</td>\n<td align=\"center\">O</td>\n<td align=\"center\">C</td>\n<td>The last cleaning cartridge used in the tape drive has worn out:<br>\n<ol>\n<li>Discard the worn out cleaning cartridge.<br>\n<li>Wait for the current operation to finish.<br>\n<li>Then use a new cleaning cartridge.\n</ol></td>\n<td>The cleaning tape has expired.</td>\n</tr>\n\n<tr>\n<td align=\"center\">17h</td>\n<td align=\"right\">400000</td>\n<td>Invalid cleaning tape</td>\n<td align=\"center\">O</td>\n<td align=\"center\">C</td>\n<td>The last cleaning cartridge used in the tape drive was\nan invalid type:<br>\n<ol>\n<li>Do not use this cleaning cartridge in this drive.<br>\n<li>Wait for the current operation to finish.<br>\n<li>Then use a valid cleaning cartridge.\n</ol></td>\n<td>Invalid cleaning tape type used.</td>\n</tr>\n\n<tr>\n<td align=\"center\">18h</td>\n<td align=\"right\">800000</td>\n<td>Retension requested</td>\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>The tape drive has requested a retension operation.</td>\n<td>The drive is having severe trouble reading or writing, that will be resolved by a retension cycle.</td>\n</tr>\n\n<tr>\n<td align=\"center\">19h</td>\n<td align=\"right\">1000000</td>\n<td>Dual-port interface error</td>\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>A redundant interface port on the tape drive has failed.</td>\n<td>Failure of one interface port in a dual-port configuration (i.e., Fibre Channel)</td>\n</tr>\n\n<tr>\n<td align=\"center\">1Ah</td>\n<td align=\"right\">2000000</td>\n<td>Cooling fan failure</td>\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>A tape drive cooling fan has failed.</td>\n<td>Fan failure inside tape drive mechanism or tape drive enclosure.</td>\n</tr>\n\n<tr>\n<td align=\"center\">1Bh</td>\n<td align=\"right\">4000000</td>\n<td>Power supply failure</td>\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>A redundant power supply has failed inside the tape drive enclosure. Check the enclosure users manual for instructions on replacing the failed power supply.</td>\n<td>Redundant PSU failure inside the tape drive enclosure or rack subsystem.</td>\n</tr>\n\n<tr>\n<td align=\"center\">1Ch</td>\n<td align=\"right\">8000000</td>\n<td>Power consumption</td>\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>The tape drive power consumption is outside the specified range.</td>\n<td>Power consumption of the tape drive is outside specified range.</td>\n</tr>\n\n<tr>\n<td align=\"center\">1Dh</td>\n<td align=\"right\">10000000</td>\n<td>Drive maintenance</td>\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>Preventive maintenance of the tape drive is required.  Check the tape drive users manual for device specific preventive maintenance tasks or call the tape drive supplier help line.</td>\n<td>The drive requires preventive maintenance (not cleaning).</td>\n</tr>\n\n<td align=\"center\">1Eh</td>\n<td align=\"right\">20000000</td>\n<td>Hardware A</td>\n<td align=\"center\">O</td>\n<td align=\"center\">C</td>\n<td>The tape drive has a hardware fault:\n<ol>\n<li>Eject the tape or magazine.\n<li>Reset the drive.\n<li>Restart the operation.\n</ol>\n</td>\n<td>The drive has a hardware fault that requires reset to recover.</td>\n</tr>\n\n<tr>\n<td align=\"center\">1Fh</td>\n<td align=\"right\">40000000</td>\n<td>Hardware B</td>\n<td align=\"center\">M</td>\n<td align=\"center\">C</td>\n<td>The tape drive has a hardware fault:\n<ol>\n<li>Turn the tape drive off and then on again.\n<li>Restart the operation.\n<li>If the problem persists, call the tape drive supplier help line.\n</ol></td>\n<td>The drive has a hardware fault that is not read/write related or requires a power cycle to recover.</td>\n</tr>\n\n<tr>\n<td align=\"center\">20h</td>\n<td align=\"right\">80000000</td>\n<td>Interface</td>\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>The tape drive has a problem with the application client interface:\n<ol>\n<li>Check the cables and cable connections.\n<li>Restart the operation.\n</ol>\n</td>\n<td>The drive has identified an interface fault.</td>\n</tr>\n\n<tr>\n<td align=\"center\">21h</td>\n<td align=\"right\">100000000</td>\n<td>Eject media</td>\n<td align=\"center\">O</td>\n<td align=\"center\">C</td>\n<td>The operation has failed:\n<ol>\n<li>Eject the tape or magazine.\n<li>Insert the tape or magazine again.\n<li>Restart the operation.\n</ol>\n</td>\n<td>Error recovery action.</td>\n</tr>\n\n<tr>\n<td align=\"center\">22h</td>\n<td align=\"right\">200000000</td>\n<td>Download fail</td>\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>The firmware download has failed because you have\ntried to use the incorrect firmware for this tape drive.\nObtain the correct firmware and try again.</td>\n<td>Firmware download failed.</td>\n</tr>\n\n<tr>\n<td align=\"center\">23h</td>\n<td align=\"right\">400000000</td>\n<td>Drive humidity</td>\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>Environmental conditions inside the tape drive are\noutside the specified humidity range.</td>\n<td>Drive humidity limits exceeded.</td>\n</tr>\n\n<tr>\n<td align=\"center\">24h</td>\n<td align=\"right\">800000000</td>\n<td>Drive temperature</td>\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>Environmental conditions inside the tape drive are\noutside the specified temperature range.</td>\n<td>Cooling problem.</td>\n</tr>\n\n<tr>\n<td align=\"center\">25h</td>\n<td align=\"right\">1000000000</td>\n<td>Drive voltage</td>\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>The voltage supply to the tape drive is outside the specified range.</td>\n<td>Drive voltage limits exceeded.</td>\n</tr>\n\n<tr>\n<td align=\"center\">26h</td>\n<td align=\"right\">2000000000</td>\n<td>Predictive failure</td>\n<td align=\"center\">O</td>\n<td align=\"center\">C</td>\n<td>A hardware failure of the tape drive is predicted. Call the tape drive supplier help line.</td>\n<td>Predictive failure of drive hardware.</td>\n</tr>\n\n<tr>\n<td align=\"center\">27h</td>\n<td align=\"right\">4000000000</td>\n<td>Diagnostics required</td>\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>The tape drive may have a hardware fault. Run\nextended diagnostics to verify and diagnose the\nproblem. Check the tape drive users manual for\ndevice specific instructions on running extended\ndiagnostic tests.</td>\n<td>The drive may have a hardware fault that may be identified by\nextended diagnostics (i.e., SEND DIAGNOSTIC command).</td>\n</tr>\n\n<tr>\n<td align=\"center\">28h - 2Eh</td>\n<td>Obsolete</td>\n</tr>\n\n<tr>\n<td align=\"center\">2Fh - 31h</td>\n<td>Rsvd</td>\n</tr>\n\n<tr>\n<td align=\"center\">32h</td>\n<td align=\"right\">4000000000000</td>\n<td>Lost statistics\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>Media statistics have been lost at some time in the past.</td>\n<td>Drive or library powered on with tape loaded.</td>\n</tr>\n\n<tr>\n<td align=\"center\">33h</td>\n<td align=\"right\">8000000000000</td>\n<td>Tape directory invalid at unload</td>\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>The tape directory on the tape cartridge just unloaded\nhas been corrupted. File search performance will be\ndegraded. The tape directory can be rebuilt by reading\nall the data. </td>\n<td>Error preventing the tape directory being updated on unload.</td>\n</tr>\n\n<tr>\n<td align=\"center\">34h</td>\n<td align=\"right\">10000000000000</td>\n<td>Tape system area write failure</td>\n<td align=\"center\">O</td>\n<td align=\"center\">C</td>\n<td>The tape just unloaded could not write its system\narea successfully:\n<ol>\n<li>Copy data to another tape cartridge.\n<li>Discard the old cartridge.\n</ol>\n</td>\n<td>Write errors while writing the system area on unload.</td>\n</tr>\n\n<tr>\n<td align=\"center\">35h</td>\n<td align=\"right\">20000000000000</td>\n<td>Tape system area read failure</td>\n<td align=\"center\">O</td>\n<td align=\"center\">C</td>\n<td>The tape system area could not be read successfully\nat load time:\n<ol>\n<li>Copy data to another tape cartridge.</td>\n</ol>\n<td>Read errors while reading the system area on load.</td>\n</tr>\n\n<tr>\n<td align=\"center\">36h</td>\n<td align=\"right\">40000000000000</td>\n<td>No start of data</td>\n<td align=\"center\">O</td>\n<td align=\"center\">C</td>\n<td>The start of data could not be found on the tape:\n1. Check that you are using the correct format tape.\n2. Discard the tape or return the tape to your supplier.\n</td>\n<td>Tape damaged, bulk erased, or incorrect format.</td>\n</tr>\n\n<tr>\n<td align=\"center\">37h</td>\n<td align=\"right\">80000000000000</td>\n<td>Loading failure</td>\n<td align=\"center\">O</td>\n<td align=\"center\">C</td>\n<td>The operation has failed because the media cannot be loaded and threaded.\n<ol>\n<li>Remove the cartridge, inspect it as specified in the\nproduct manual, and retry the operation.\n<li>If the problem persists, call the tape drive supplier help line.\n</ol>\n</td>\n<td>The drive is unable to load the media and thread the tape.</td>\n</tr>\n\n<tr>\n<td align=\"center\">38h</td>\n<td align=\"right\">100000000000000</td>\n<td>Unrecoverable unload failure</td>\n<td align=\"center\">O</td>\n<td align=\"center\">C</td>\n<td>The operation has failed because the medium cannot be unloaded:\n<ol>\n<li>Do not attempt to extract the tape cartridge.\n<li>Call the tape driver supplier help line.\n</ol>\n</td>\n<td>The drive is unable to unload the medium.</td>\n</tr>\n\n<tr>\n<td align=\"center\">39h</td>\n<td align=\"right\">200000000000000</td>\n<td>Automation interface failure</td>\n<td align=\"center\">O</td>\n<td align=\"center\">C</td>\n<td>The tape drive has a problem with the automation interface:\n<ol>\n<li>Check the power to the automation system.\n<li>Check the cables and cable connections.\n<li>Call the supplier help line if problem persists.\n</ol>\n</td>\n<td>The drive has identified an interface fault.</td>\n</tr>\n\n<tr>\n<td align=\"center\">3Ah</td>\n<td align=\"right\">400000000000000</td>\n<td>Firmware failure</td>\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>The tape drive has reset itself due to a detected firmware\nfault. If problem persists, call the supplier help line.</td>\n<td>Firmware bug.</td>\n</tr>\n\n<tr>\n<td align=\"center\">3Bh</td>\n<td align=\"right\">800000000000000</td>\n<td>WORM Medium - Integrity Check Failed</td>\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>The tape drive has detected an inconsistency during\nthe WORM medium integrity checks. Someone may\nhave tampered with the cartridge.  </td>\n<td>Someone has tampered with the WORM medium.</td>\n</tr>\n\n<tr>\n<td align=\"center\">3Ch</td>\n<td align=\"right\">1000000000000000</td>\n<td>WORM Medium - Overwrite Attempted</td>\n<td align=\"center\">O</td>\n<td align=\"center\">W</td>\n<td>An attempt had been made to overwrite user data on a WORM medium:\n<ol>\n<li>If a WORM medium was used inadvertently, replace\nit with a normal data medium.\n<li>If a WORM medium was used intentionally:<br>\na) Check that the software application is compatible\nwith the WORM medium format you are using.<br>\nb) Check that the medium is bar-coded correctly for WORM.\n<ol>\n</td>\n<td>The application software does not recognize the medium as WORM.</td>\n</tr>\n\n<tr>\n<td align=\"center\">3Dh</td>\n<td>Rsvd</td>\n</tr>\n<tr>\n<td align=\"center\">3Eh</td>\n<td>Rsvd</td>\n</tr>\n<tr>\n<td align=\"center\">3Fh</td>\n<td>Rsvd</td>\n</tr>\n<tr>\n<td align=\"center\">40h</td>\n<td>Rsvd</td>\n</tr>\n\n</table>\n\n<a NAME=\"vtl-download\"></a>\n<hr width=\"80%\">\n<h3>Download</h3>\n\n<p>\nJust the user-mode utilities packaged as an RPM:\n<a href=http://sites.google.com/site/linuxvtl2/mhvtl-0.15-0.i686.rpm>vtl-0.15-0.i686.rpm\n</a> (~50Kbytes)</p>\n<p>Source code for user-mode utilities + kernel module:\n<a href=http://sites.google.com/site/linuxvtl2/mhvtl-0.15-0.src.rpm>vtl-0.15-0.src.rpm\n</a> (~100Kbytes)\n</p>\n\n<hr width=\"80%\">\n\n<p align=\"center\">\nPlease email \n<a href=mailto:markh794@gmail.com>Mark Harvey</a>\nany questions and/or corrections.\n</p>\n<p align=\"center\">\n$Id: index.html,v 1.9.2.1 2008-03-06 07:28:54 markh Exp $\n</p>\n</html>\n"
  },
  {
    "path": "etc/.gitignore",
    "content": "mhvtl.conf\ndevice.conf\nlibrary_contents.10\nlibrary_contents.30\nvtllibrary@.service\nvtltape@.service\nmhvtl-load-modules.service\ngenerate_device_conf\ngenerate_library_contents\n"
  },
  {
    "path": "etc/Makefile",
    "content": "#\n# etc/Makefile\n#\n\nCURDIR = \"../\"\ninclude ../config.mk\n\nMHVTL_CONF_FILE = mhvtl.conf\nDEVICE_CONF_FILE = device.conf\nLIB_CONTENTS_FILES = library_contents.10 library_contents.30\nCONFIGS = $(MHVTL_CONF_FILE) $(DEVICE_CONF_FILE) $(LIB_CONTENTS_FILES)\n\nGENERATE_DEVICE_CONF = generate_device_conf\nGENERATE_LIB_CONTENTS = generate_library_contents\nGENERATORS = $(GENERATE_DEVICE_CONF) $(GENERATE_LIB_CONTENTS)\n\nSERVICES = $(patsubst %.in,%,$(wildcard *.service*))\nMHVTL_TARGET = mhvtl.target\n\n\nall: $(SERVICES) $(CONFIGS)\n\n%: %.in\n\tsed -e s'/@CONF_PATH@/$(CONFIG_PATH)/' \\\n\t    -e s'/@HOME_PATH@/$(HOME_PATH)/' $< > $@\n\n$(GENERATE_DEVICE_CONF): $(GENERATE_DEVICE_CONF).in\n\tsed -e s'/@CONF_PATH@/$(CONFIG_PATH)/' \\\n\t    -e s'/@HOME_PATH@/$(HOME_PATH)/' $< > $@\n\tchmod 755 $@\n\n$(GENERATE_LIB_CONTENTS): $(GENERATE_LIB_CONTENTS).in\n\tsed -e s'/@CONF_PATH@/$(CONFIG_PATH)/' \\\n\t    -e s'/@HOME_PATH@/$(HOME_PATH)/' $< > $@\n\tchmod 755 $@\n\n$(DEVICE_CONF_FILE): $(GENERATE_DEVICE_CONF)\n\tbash ./$(GENERATE_DEVICE_CONF) --force --home-dir=$(MHVTL_HOME_PATH) --override-home\n\n$(LIB_CONTENTS_FILES): $(GENERATE_LIB_CONTENTS) $(DEVICE_CONF_FILE)\n\tbash ./$(GENERATE_LIB_CONTENTS) --force --config=.\n\n.PHONY: distclean\ndistclean: clean\n\n.PHONY: clean\nclean:\n\t$(RM) $(GENERATED_FILES)\n\t$(RM) $(DEVICE_CONF_FILE) $(LIB_CONTENTS_FILES)\n\n$(DESTDIR)$(SYSTEMD_SERVICE_DIR):\n\tinstall -d -m 755 $@\n$(DESTDIR)$(MHVTL_CONFIG_PATH):\n\tinstall -d -m 755 $@\n\n# Installing services\n$(DESTDIR)$(SYSTEMD_SERVICE_DIR)/%.service: %.service | $(DESTDIR)$(SYSTEMD_SERVICE_DIR)\n\tinstall -m 644 $< $@\n\tsemanage fcontext -a -t systemd_unit_file_t \\'$@\\'\n$(DESTDIR)$(SYSTEMD_SERVICE_DIR)/%.target: %.target | $(DESTDIR)$(SYSTEMD_SERVICE_DIR)\n\tinstall -m 644 $< $@\n\tsemanage fcontext -a -t systemd_unit_file_t \\'$@\\'\n# Installing generator of config files\n$(DESTDIR)/usr/bin/generate_%: generate_%\n\tinstall -m 755 $< $@\n# save backup copies of config files\n$(DESTDIR)$(MHVTL_CONFIG_PATH)/%: % | $(DESTDIR)$(MHVTL_CONFIG_PATH)\n\tinstall -m 644 -b -S .orig $< $@\n\n.PHONY: install\ninstall: all \\\n\t\t $(addprefix $(DESTDIR)$(SYSTEMD_SERVICE_DIR)/,$(SERVICES) $(MHVTL_TARGET)) \\\n\t\t $(addprefix $(DESTDIR)$(MHVTL_CONFIG_PATH)/,$(CONFIGS)) \\\n\t\t $(addprefix $(DESTDIR)/usr/bin/,$(GENERATORS))\n\trestorecon -R -v  $(DESTDIR)$(SYSTEMD_SERVICE_DIR)\n"
  },
  {
    "path": "etc/generate_device_conf.in",
    "content": "#!/bin/bash\n#\n# generate_device_conf -- generate device.conf output to stdout\n#\n#\tThis script generates the device.conf file,\n#\tand is used at installation time. This is done so that\n#\tadministrators/users can modify or copy this script and\n#\tchange their tape device configuration.\n#\n\nDEVICE_CONF='device.conf'\nPROG_NAME=\"$0\"\nMHVTL_HOME_PATH=@HOME_PATH@\nDEST_DIR='.'\nFORCE=''\nOVERRIDE=''\n\nusage()\n{\n\techo \"Usage: $PROG_NAME: [OPTIONS] -- generate a $DEVICE_CONF file\"\n\techo \"where OPTIONS are from:\"\n\techo \"  [-h|--help]         -- print this message and exit\"\n\techo \"  [-H|--home-dir MHVTL_HOME_PATH]\"\n\techo \"                      -- home path [default $MHVTL_HOME_PATH]\"\n\techo \"  [-D|--dest-dir DIR] -- destination dir [default $DEST_DIR]\"\n\techo \"  [-f|--force]        -- overwrite files if present\"\n\techo \"  [-o|--override-home] -- override requirement that home dir exists\"\n\techo \"\"\n\techo \"To create a new $DEVICE_CONF file, edit this script and run it again\"\n}\n\n#\n# generate the static comments at the start of the file\n#\ngenerate_static_comments()\n{\n\tif (( $# != 0 )) ; then\n\t\techo \"internal error: expected 0 arguments, got $#\" 1>&2\n\t\texit 1\n\tfi\n\tcat << CONF_START\n\nVERSION: 5\n\n# VPD page format:\n# <page #> <Length> <x> <x+1>... <x+n>\n# NAA format is an 8 hex byte value seperated by ':'\n# Note: NAA is part of inquiry VPD 0x83\n#\n# Each 'record' is separated by one (or more) blank lines.\n# Each 'record' starts at column 1\n# Serial num max len is 10.\n# Compression: factor X enabled 0|1\n#     Where X is zlib compression factor\t1 = Fastest compression\n#\t\t\t\t\t\t9 = Best compression\n#     enabled 0 == off, 1 == on\n#\n# fifo: /var/tmp/mhvtl\n# If enabled, data must be read from fifo, otherwise daemon will block\n# trying to write.\n# e.g. cat /var/tmp/mhvtl (in another terminal)\n\nCONF_START\n}\n\n# add_library(DevID, Channel, Target, Lun, Vend, Prod, ProdRev, S/No)\nadd_library()\n{\n\tif (( $# != 8 )) ; then\n\t\techo \"internal error: expected 8 arguments, got $#\" 1>&2\n\t\texit 1\n\tfi\n\tID=$1\n\tCH=$2\n\tTARGET=$3\n\tLUN=$4\n\tVENDOR_ID=\"$5\"\n\tPROD_ID=\"$6\"\n\tUNIT_SN=\"$8\"\n\n\tprintf \"Library: %02d CHANNEL: %02d TARGET: %02d LUN: %02d\\n\" \\\n\t\t\t$ID $CH $TARGET $LUN\n\techo \" Vendor identification: $VENDOR_ID\"\n\techo \" Product identification: $PROD_ID\"\n\techo \" Unit serial number: $UNIT_SN\"\n\tprintf \" NAA: %02d:22:33:44:ab:%02d:%02d:%02d\\n\" \\\n\t\t\t$ID $CH $TARGET $LUN\n\techo \" Home directory: $MHVTL_HOME_PATH\"\n\techo \" PERSIST: False\"\n\techo \" Backoff: 400\"\n\techo \"# fifo: /var/tmp/mhvtl\"\n\techo \"\"\n}\n\n# add_drive(DevID, Channel, Target, Lun, Vend, Prod, ProdRev, S/No, LibID, Slot, Density)\nadd_drive()\n{\n\tif (( $# != 11 )) ; then\n\t\techo \"internal error: expected 11 arguments, got $#\" 1>&2\n\t\texit 1\n\tfi\n\tID=$1\n\tCH=$2\n\tTARGET=$3\n\tLUN=$4\n\tVENDORID=$5\n\tPRODUCTID=$6\n\tPRODUCTREV=$7\n\tUNITSERNO=$8\n\tLIB=$9\n\n\t# get arg 10 & 11\n\tshift 9\n\tSLOT=$1\n\tDENSITY=$2\n\n\tprintf \"Drive: %02d CHANNEL: %02d TARGET: %02d LUN: %02d\\n\" \\\n\t\t\t$ID $CH $TARGET $LUN\n\tprintf \" Library ID: %02d Slot: %02d\\n\" \\\n\t\t\t$LIB $SLOT\n\techo \" Vendor identification: $VENDORID\"\n\techo \" Product identification: $PRODUCTID\"\n\techo \" Product revision level: $PRODUCTREV\"\n\techo \" Unit serial number: $UNITSERNO\"\n\tprintf \" NAA: %02d:22:33:44:ab:%02d:%02d:%02d\\n\" \\\n\t\t\t$LIB $CH $TARGET $LUN\n\techo \" Compression: factor 1 enabled 1\"\n\techo \" Compression type: lzo\"\n\techo \" Backoff: 400\"\n\techo \"# fifo: /var/tmp/mhvtl\"\n\techo \"\"\n}\n\n# add_ibm_ultrium_drive(DevID, Channel, Target, Lun, S/No, LibID, Slot)\nadd_ibm_ultrium_drive()\n{\n\tif (( $# != 7 )) ; then\n\t\techo \"internal error: expected 0 arguments, got $#\" 1>&2\n\t\texit 1\n\tfi\n\tID=$1\n\tCH=$2\n\tTARGET=$3\n\tLUN=$4\n\tUNITSERNO=$5\n\tLIB=$6\n\tSLOT=$7\n\tVENDORID=\"IBM\"\n\tPRODUCTID=\"ULT3580-TD1\"\n\tPRODUCTREV=\"550V\"\n\tDENSITY=\"42\"\n\n\tadd_drive $ID $CH $TARGET $LUN $VENDORID $PRODUCTID $PRODUCTREV $UNITSERNO $LIB $SLOT $DENSITY\n}\n\n# add_ibm_ultrium_2_drive(DevID, Channel, Target, Lun, S/No, LibID, Slot)\nadd_ibm_ultrium_2_drive()\n{\n\tif (( $# != 7 )) ; then\n\t\techo \"internal error: expected 0 arguments, got $#\" 1>&2\n\t\texit 1\n\tfi\n\tID=$1\n\tCH=$2\n\tTARGET=$3\n\tLUN=$4\n\tUNITSERNO=$5\n\tLIB=$6\n\tSLOT=$7\n\tVENDORID=\"IBM\"\n\tPRODUCTID=\"ULT3580-TD2\"\n\tPRODUCTREV=\"550V\"\n\tDENSITY=\"44\"\n\n\tadd_drive $ID $CH $TARGET $LUN $VENDORID $PRODUCTID $PRODUCTREV $UNITSERNO $LIB $SLOT $DENSITY\n}\n\n# add_ibm_ultrium_3_drive(DevID, Channel, Target, Lun, S/No, LibID, Slot)\nadd_ibm_ultrium_3_drive()\n{\n\tif (( $# != 7 )) ; then\n\t\techo \"internal error: expected 0 arguments, got $#\" 1>&2\n\t\texit 1\n\tfi\n\tID=$1\n\tCH=$2\n\tTARGET=$3\n\tLUN=$4\n\tUNITSERNO=$5\n\tLIB=$6\n\tSLOT=$7\n\tVENDORID=\"IBM\"\n\tPRODUCTID=\"ULT3580-TD3\"\n\tPRODUCTREV=\"550V\"\n\tDENSITY=\"46\"\n\n\tadd_drive $ID $CH $TARGET $LUN $VENDORID $PRODUCTID $PRODUCTREV $UNITSERNO $LIB $SLOT $DENSITY\n}\n\n# add_ibm_ultrium_4_drive(DevID, Channel, Target, Lun, S/No, LibID, Slot)\nadd_ibm_ultrium_4_drive()\n{\n\tif (( $# != 7 )) ; then\n\t\techo \"internal error: expected 0 arguments, got $#\" 1>&2\n\t\texit 1\n\tfi\n\tID=$1\n\tCH=$2\n\tTARGET=$3\n\tLUN=$4\n\tUNITSERNO=$5\n\tLIB=$6\n\tSLOT=$7\n\tVENDORID=\"IBM\"\n\tPRODUCTID=\"ULT3580-TD4\"\n\tPRODUCTREV=\"550V\"\n\tDENSITY=\"48\"\n\n\tadd_drive $ID $CH $TARGET $LUN $VENDORID $PRODUCTID $PRODUCTREV $UNITSERNO $LIB $SLOT $DENSITY\n}\n\n# add_ibm_ultrium_5_drive(DevID, Channel, Target, Lun, S/No, LibID, Slot)\nadd_ibm_ultrium_5_drive()\n{\n\tif (( $# != 7 )) ; then\n\t\techo \"internal error: expected 0 arguments, got $#\" 1>&2\n\t\texit 1\n\tfi\n\tID=$1\n\tCH=$2\n\tTARGET=$3\n\tLUN=$4\n\tUNITSERNO=$5\n\tLIB=$6\n\tSLOT=$7\n\tVENDORID=\"IBM\"\n\tPRODUCTID=\"ULT3580-TD5\"\n\tPRODUCTREV=\"550V\"\n\tDENSITY=\"50\"\n\n\tadd_drive $ID $CH $TARGET $LUN $VENDORID $PRODUCTID $PRODUCTREV $UNITSERNO $LIB $SLOT $DENSITY\n}\n\n# add_ibm_ultrium_6_drive(DevID, Channel, Target, Lun, S/No, LibID, Slot)\nadd_ibm_ultrium_6_drive()\n{\n\tif (( $# != 7 )) ; then\n\t\techo \"internal error: expected 0 arguments, got $#\" 1>&2\n\t\texit 1\n\tfi\n\tID=$1\n\tCH=$2\n\tTARGET=$3\n\tLUN=$4\n\tUNITSERNO=$5\n\tLIB=$6\n\tSLOT=$7\n\tVENDORID=\"IBM\"\n\tPRODUCTID=\"ULT3580-TD6\"\n\t#### According to IBM LTO SCSI reference: REV is built of\n\t # \"ABCD\" - so 2160 decodes as Year 2022 (2), Jan (1), Day (6th), Version '0'\n\t # A = last digit char of year\n\t # B = Month, 1 - 9, A, B, C\n\t # C = Day, 1-9, A-V\n\t # D = Version\n\tPRODUCTREV=\"2160\"\n\tDENSITY=\"50\"\n\n\tadd_drive $ID $CH $TARGET $LUN $VENDORID $PRODUCTID $PRODUCTREV $UNITSERNO $LIB $SLOT $DENSITY\n}\n\n# add_ibm_ultrium_7_drive(DevID, Channel, Target, Lun, S/No, LibID, Slot)\nadd_ibm_ultrium_7_drive()\n{\n\tif (( $# != 7 )) ; then\n\t\techo \"internal error: expected 0 arguments, got $#\" 1>&2\n\t\texit 1\n\tfi\n\tID=$1\n\tCH=$2\n\tTARGET=$3\n\tLUN=$4\n\tUNITSERNO=$5\n\tLIB=$6\n\tSLOT=$7\n\tVENDORID=\"IBM\"\n\tPRODUCTID=\"ULT3580-TD7\"\n\t#### According to IBM LTO SCSI reference: REV is built of\n\t # \"ABCD\" - so 2160 decodes as Year 2022 (2), Jan (1), Day (6th), Version '0'\n\t # A = last digit char of year\n\t # B = Month, 1 - 9, A, B, C\n\t # C = Day, 1-9, A-V\n\t # D = Version\n\tPRODUCTREV=\"2160\"\n\tDENSITY=\"50\"\n\n\tadd_drive $ID $CH $TARGET $LUN $VENDORID $PRODUCTID $PRODUCTREV $UNITSERNO $LIB $SLOT $DENSITY\n}\n\n# add_ibm_ultrium_8_drive(DevID, Channel, Target, Lun, S/No, LibID, Slot)\nadd_ibm_ultrium_8_drive()\n{\n\tif (( $# != 7 )) ; then\n\t\techo \"internal error: expected 0 arguments, got $#\" 1>&2\n\t\texit 1\n\tfi\n\tID=$1\n\tCH=$2\n\tTARGET=$3\n\tLUN=$4\n\tUNITSERNO=$5\n\tLIB=$6\n\tSLOT=$7\n\tVENDORID=\"IBM\"\n\tPRODUCTID=\"ULT3580-TD8\"\n\t#### According to IBM LTO SCSI reference: REV is built of\n\t # \"ABCD\" - so 2160 decodes as Year 2022 (2), Jan (1), Day (6th), Version '0'\n\t # A = last digit char of year\n\t # B = Month, 1 - 9, A, B, C\n\t # C = Day, 1-9, A-V\n\t # D = Version\n\tPRODUCTREV=\"2160\"\n\tDENSITY=\"50\"\n\n\tadd_drive $ID $CH $TARGET $LUN $VENDORID $PRODUCTID $PRODUCTREV $UNITSERNO $LIB $SLOT $DENSITY\n}\n\n# add_stk_t10kb_drive(DevID, Channel, Target, Lun, S/No, LibID, Slot)\nadd_stk_t10kb_drive()\n{\n\tif (( $# != 7 )) ; then\n\t\techo \"internal error: expected 0 arguments, got $#\" 1>&2\n\t\texit 1\n\tfi\n\tID=$1\n\tCH=$2\n\tTARGET=$3\n\tLUN=$4\n\tUNITSERNO=$5\n\tLIB=$6\n\tSLOT=$7\n\tVENDORID=\"STK\"\n\tPRODUCTID=\"T10000B\"\n\tPRODUCTREV=\"550V\"\n\tDENSITY=\"50\"\n\n\tadd_drive $ID $CH $TARGET $LUN $VENDORID $PRODUCTID $PRODUCTREV $UNITSERNO $LIB $SLOT $DENSITY\n}\n\n# add_library_contents_10(void) -- add the robot \"10\" with 4 drives\nadd_library_contents_10()\n{\n\tif (( $# != 0 )) ; then\n\t\techo \"internal error: expected 0 arguments, got $#\" 1>&2\n\t\texit 1\n\tfi\n\n\t#         index channel target LUN Vendor ProdID ProdRev S/No\n\tadd_library 10 0 0 0 \"STK\" \"L700\"  \"550V\"  \"XYZZY_A\"\n\t#         index channel target LUN S/No Lib# Slot\n\tadd_ibm_ultrium_8_drive 11 0 1 0 \"XYZZY_A1\" 10 1\n\tadd_ibm_ultrium_8_drive 12 0 2 0 \"XYZZY_A2\" 10 2\n\tadd_ibm_ultrium_6_drive 13 0 3 0 \"XYZZY_A3\" 10 3\n\tadd_ibm_ultrium_6_drive 14 0 4 0 \"XYZZY_A4\" 10 4\n}\n\n# add_library_contents_30(void) -- add the robot \"30\" with 4 drives\nadd_library_contents_30()\n{\n\tif (( $# != 0 )) ; then\n\t\techo \"internal error: expected 0 arguments, got $#\" 1>&2\n\t\texit 1\n\tfi\n\n\t#         index channel target LUN Vendor ProdID ProdRev S/No\n\tadd_library 30 0 8 0 \"STK\" \"L80\"  \"550V\"  \"XYZZY_B\"\n\t#         index channel target LUN S/No Lib# Slot\n\tadd_stk_t10kb_drive 31 0 9 0 \"XYZZY_B1\" 30 1\n\tadd_stk_t10kb_drive 32 0 10 0 \"XYZZY_B2\" 30 2\n\tadd_stk_t10kb_drive 33 0 11 0 \"XYZZY_B3\" 30 3\n\tadd_stk_t10kb_drive 34 0 12 0 \"XYZZY_B4\" 30 4\n}\n\n#\n# start of script\n#\n\nTEMP=$(getopt -o 'hH:D:fo' --long 'help,home-dir:,dest-dir:,force,override-home' -n \"$PROG_NAME\" -- \"$@\")\nif [[ $? -ne 0 ]] ; then\n\tusage\n\texit 1\nfi\neval set - \"$TEMP\"\nunset TEMP\n\nwhile true; do\n\tcase \"$1\" in\n\t'-h'|'--help')\n\t\tusage\n\t\texit 0\n\t\t;;\n\t'-H'|'--home-dir')\n\t\tMHVTL_HOME_PATH=\"$2\"\n\t\tshift 2\n\t\tcontinue\n\t\t;;\n\t'-D'|'--dest-dir')\n\t\tDEST_DIR=\"$2\"\n\t\tshift 2\n\t\tcontinue\n\t\t;;\n\t'-f'|'--force')\n\t\tFORCE='1'\n\t\tshift\n\t\tcontinue\n\t\t;;\n\t'-o'|'--override-home')\n\t\tOVERRIDE='1'\n\t\tshift\n\t\tcontinue\n\t\t;;\n\t'--')\n\t\tshift\n\t\tbreak\n\t\t;;\n\t*)\n\t\techo \"internal error: unknown arg: $1\" 1>&2\n\t\texit 1\n\tesac\ndone\n\n# should be no more arguments\nif [[ $# -gt 0 ]] ; then\n\techo \"error: too many arguments\"\n\tusage\n\texit 1\nfi\n\n# verify a home path make sense\n# (for use in the device.conf we generate)\nif [[ ! -d \"$MHVTL_HOME_PATH\" ]] ; then\n\tif [[ -z \"$OVERRIDE\" ]] ; then\n\t\techo \"error: $MHVTL_HOME_PATH not a directory\" 1>&2\n\t\tusage\n\t\texit 1\n\tfi\nfi\n\n# ensure we do not step on earlier config file\nif [[ -r $DEST_DIR/$DEVICE_CONF ]] ; then\n\tif [[ -z \"$FORCE\" ]] ; then\n\t\techo \"error: already exists: $DEST_DIR/$DEVICE_CONF\" 1>&2\n\t\texit 1\n\tfi\nfi\n\necho '===>' \"Generating: $DEST_DIR/$DEVICE_CONF ...\"\n(\n\tgenerate_static_comments\n\tadd_library_contents_10\n\tadd_library_contents_30\n) > $DEST_DIR/$DEVICE_CONF\n"
  },
  {
    "path": "etc/generate_library_contents.in",
    "content": "#!/bin/bash\n#\n# generate_library_contents -- generate library_contents.* files\n#\n#\tThis script generates the library_contents.<NUMBER> (where\n#\tnumber defaults to 10 and 30) files in our configuration\n#\tdirectory. This is normally only done at installation time,\n#\tbut having this script makes it possible for administrators/\n#\tusers to customize the configuration if desired.\n#\n\nDEVICE_CONF='device.conf'\nPROG_NAME=\"$0\"\nFORCE=''\nMHVTL_CONFIG_PATH='@CONF_PATH@'\nDEST_DIR='.'\n\nusage()\n{\n\techo \"Usage: $PROG_NAME: [OPTIONS] -- generate\" 'library_contents.*' \"files from $DEVICE_CONF\"\n\techo \"where OPTIONS are from:\"\n\techo \"  [-h|--help]                   -- print this message and exit\"\n\techo \"  [-C|--config-dir CONFIG_DIR]  -- specificy config dir [default $MHVTL_CONFIG_PATH]\"\n\techo \"  [-D|--dest-dir DIRECTORY]     -- specificy destination dir [default $DEST_DIR]\"\n\techo \"  [-f|--force]                  -- overwrite files if present\"\n}\n\ncreate_library_file()\n{\n\tif (( $# != 1 )) ; then\n\t\techo \"create_library_file internal error: expected 1 argument, got $#\" 1>&2\n\t\texit 1\n\tfi\n\n\tLIBID=$1\n\n\techo \"VERSION: 2\"\n\techo \"\"\n\n\t# Count number of drives in this library\n\tDRV_COUNT=$(grep -c \"Library ID: $LIBID\" $MHVTL_CONFIG_PATH/$DEVICE_CONF)\n\n\t# Add a 'Drive X:' for each drive\n\tfor a in $(seq 1 $DRV_COUNT) ; do\n\t\tprintf \"Drive %d:\\n\" $a\n\tdone\n\n\t# create the static (non-changing, comment) part of the file\n\tcat <<CONF_SAMPLE\n\nPicker 1:\n\nMAP 1:\nMAP 2:\nMAP 3:\nMAP 4:\n\n# Slot 1 - ?, no gaps\n# Slot N: [barcode]\n# [barcode]\n# a barcode is comprised of three fields: [Leading] [identifier] [Trailing]\n# Leading \"CLN\" -- cleaning tape\n# Leading \"W\" -- WORM tape\n# Leading \"NOBAR\" -- will appear to have no barcode\n# If the barcode is at least 8 character long, then the last two characters are Trailing\n# Trailing \"S3\" - SDLT600\n# Trailing \"X4\" - AIT-4\n# Trailing \"L1\" - LTO 1, \"L2\" - LTO 2, \"L3\" - LTO 3, \"L4\" - LTO 4, \"L5\" - LTO 5\n# Trailing \"LT\" - LTO 3 WORM, \"LU\" -  LTO 4 WORM, \"LV\" - LTO 5 WORM\n# Trailing \"L6\" - LTO 6, \"LW\" - LTO 6 WORM\n# Trailing \"TA\" - T10000+\n# Trailing \"TZ\" - 9840A, \"TY\" - 9840B, \"TX\" - 9840C, \"TW\" - 9840D\n# Trailing \"TV\" - 9940A, \"TU\" - 9940B\n# Trailing \"JA\" - 3592+\n# Trailing \"JB\" - 3592E05+\n# Trailing \"JC\" - 3592E06+\n# Trailing \"JK\" - 3592E07+\n# Trailing \"JW\" - WORM 3592+\n# Trailing \"JX\" - WORM 3592E05+ & 3592E06\n# Trailing \"JY\" - WORM 3592E07+\n# Trailing \"D7\" - DLT7000 media (DLT IV)\n#\nCONF_SAMPLE\n\n\t# create the data in the file\n\tcase $LIBID in\n\t'10')\n\t\t# LTO-8 Media\n\t\tfor a in {1..20} ; do\n\t\t\tprintf \"Slot $a: E0%02d%02dL8\\n\" $LIBID $a\n\t\tdone\n\t\tprintf \"Slot 21: \\n\"\n\t\tprintf \"Slot 22: CLN%02d1L8\\n\" $LIBID\n\t\tprintf \"Slot 23: CLN%02d2L6\\n\" $LIBID\n\t\tfor a in {24..29} ; do\n\t\t\tprintf \"Slot $a:\\n\"\n\t\tdone\n\n\t\t# LTO-6 Media\n\t\tfor a in {30..39} ; do\n\t\t\tprintf \"Slot $a: F0%02d%02dL6\\n\" $LIBID $a\n\t\tdone\n\t\t;;\n\n\t'30')\n\t\tfor a in {1..39} ; do\n\t\t\tprintf \"Slot $a: G0%02d%02dTA\\n\" $LIBID $a\n\t\tdone\n\t\tprintf \"Slot 40: CLN%02d3TA\\n\" $LIBID\n\t\t;;\n\n\t*)\n\t\t# Not a library this script created, but create some slots anyway\n\t\tfor a in {1..39} ; do\n\t\t\tprintf \"Slot $a: M0%02d%02d\\n\" $LIBID $a\n\t\tdone\n\t\t;;\n\tesac\n}\n\n#\n# start of script\n#\n\nTEMP=$(getopt -o 'hC:D:f' --long 'help,config-dir:,dest-dir:,force' -n \"$PROG_NAME\" -- \"$@\")\nif [[ $? -ne 0 ]] ; then\n\tusage\n\texit 1\nfi\neval set - \"$TEMP\"\nunset TEMP\n\nwhile true; do\n\tcase \"$1\" in\n\t'-h'|'--help')\n\t\tusage\n\t\texit 0\n\t\t;;\n\t'-C'|'--config-dir')\n\t\tMHVTL_CONFIG_PATH=\"$2\"\n\t\tshift 2\n\t\tcontinue\n\t\t;;\n\t'-D'|'--dest-dir')\n\t\tDEST_DIR=\"$2\"\n\t\tshift 2\n\t\tcontinue\n\t\t;;\n\t'-f'|'--force')\n\t\tFORCE='1'\n\t\tshift\n\t\tcontinue\n\t\t;;\n\t'--')\n\t\tshift\n\t\tbreak\n\t\t;;\n\t*)\n\t\techo \"internal error: unknown arg: $1\" 1>&2\n\t\texit 1\n\tesac\ndone\n\n# should be no more arguments\nif [[ $# -gt 0 ]] ; then\n\techo \"error: too many arguments\" 1>&2\n\tusage\n\texit 1\nfi\n\nif [[ ! -d $MHVTL_CONFIG_PATH ]] ; then\n\techo \"error: mhvtl config path not present: $MHVTL_CONFIG_PATH\" 1>&2\n\tusage\n\texit 1\nfi\nif [[ ! -r $MHVTL_CONFIG_PATH/$DEVICE_CONF ]] ; then\n\techo \"error: need device config file: $MHVTL_CONFIG_PATH/$DEVICE_CONF\" 1>&2\n\tusage\n\texit 1\nfi\n\n# get a list of our libraries\nLIB_ID_LIST=$(awk '/^Library:/ {print $2}' $MHVTL_CONFIG_PATH/$DEVICE_CONF)\n\nfor id in $LIB_ID_LIST ; do\n\tID_FILE=\"$DEST_DIR/library_contents.$id\"\n\n\tif [[ -r $ID_FILE ]] ; then\n\t\tif [[ -z \"$FORCE\" ]] ; then\n\t\t\techo \"error: already exists: $ID_FILE\" 1>&2\n\t\t\texit 1\n\t\tfi\n\tfi\n\techo '===>' \"Generating: $ID_FILE ...\"\n\tcreate_library_file $id > $ID_FILE\ndone\n\nexit 0\n"
  },
  {
    "path": "etc/library_contents.sample",
    "content": "# Define how many tape drives you want in the vtl..\n\nDrive 1:\nDrive 2:\nDrive 3:\nDrive 4:\nDrive 5:\nDrive 6:\nDrive 7:\nDrive 8:\n\n# Place holder for the robotic arm. Not really used.\nPicker 1:\n\n# Media Access Port\n# (mailslots, Cartridge Access Port, <insert your favourate name here>)\n# Again, define how many MAPs this vtl will contain.\nMAP 1:\nMAP 2:\nMAP 3:\nMAP 4:\n\n# And the 'big' on, define your media and in which slot contains media.\n# When the rc script is started, all media listed here will be created\n# using the default media capacity.\nSlot 1:\tULT001L1\nSlot 2: ULT002L1\nSlot 3: ULT003L1\nSlot 4: ULT004L1\nSlot 5: ULT005L1\nSlot 6: ULT006L1\nSlot 7: ULT007L1\nSlot 8: ULT008L1\nSlot 9: ULT009L1\nSlot 10: ULT010L1\nSlot 11: SDLT01L1\nSlot 12: SDLT02L1\nSlot 13: SDLT03L1\nSlot 14: SDLT04L1\nSlot 15: SDLT05L1\nSlot 16: SDLT06L1\nSlot 17: SDLT07L1\nSlot 18: SDLT08L1\nSlot 19: SDLT09L1\nSlot 20: SDLT10L1\nSlot 21:\nSlot 22:\nSlot 23:\nSlot 24:\nSlot 25:\nSlot 26:\nSlot 27:\nSlot 28:\nSlot 29:\nSlot 30:\nSlot 31: CLN001L1\nSlot 32: CLN002L1\n"
  },
  {
    "path": "etc/mhvtl-load-modules.service.in",
    "content": "[Unit]\nDescription=Load mhvtl modules\nDocumentation=man:man:vtltape(1) man:man:vtllibrary(1)\nBefore=mhvtl.target\nPartOf=mhvtl.target\nConflicts=shutdown.target\nBefore=shutdown.target\n\n[Service]\nType=oneshot\nRemainAfterExit=yes\nEnvironment=VTL_DEBUG=\"0\"\nEnvironmentFile=-@CONF_PATH@/mhvtl.conf\nExecStart=/sbin/modprobe mhvtl opts=${VTL_DEBUG}\nExecStart=/sbin/modprobe sg\n\n[Install]\nWantedBy=mhvtl.target\n"
  },
  {
    "path": "etc/mhvtl.conf.in",
    "content": "#\n# mhvtl.conf\n#\n\n# Home directory for tape emulation files\nMHVTL_HOME_PATH=@HOME_PATH@\n\n# Default media capacity (500 M)\nCAPACITY=500\n\n# Set default verbosity [0|1|2|3]\nVERBOSE=1\n\n# Set kernel module debugging [0|1]\nVTL_DEBUG=0\n\n# vtltape and vtllibrary debugging [Blank or -d]\n#DAEMON_DEBUG=-d\n"
  },
  {
    "path": "etc/mhvtl.target",
    "content": "[Unit]\nDescription=mhvtl service allowing to start/stop all vtltape@.service and vtllibrary@.service instances at once\nDocumentation=man:man:vtltape(1) man:man:vtllibrary(1)\n\n[Install]\nWantedBy=multi-user.target\n"
  },
  {
    "path": "etc/vtllibrary@.service.in",
    "content": "[Unit]\nDocumentation=man:vtllibrary(1) man:vtlcmd(1)\nDescription=Robot Library Daemon for Virtual Tape & Robot Library\nBefore=mhvtl.target\nRequires=mhvtl-load-modules.service\nAfter=mhvtl-load-modules.service\nPartOf=mhvtl.target\n\n[Service]\nType=simple\nEnvironment=VERBOSE=0\nEnvironment=DAEMON_DEBUG=\nEnvironmentFile=-@CONF_PATH@/mhvtl.conf\nExecStart=/usr/bin/vtllibrary -F -q%i -v${VERBOSE} ${DAEMON_DEBUG}\nExecStop=/usr/bin/vtlcmd %i exit\nKillMode=none\nExecReload=/usr/bin/kill -HUP $MAINPID\n\n[Install]\nWantedBy=mhvtl.target\n"
  },
  {
    "path": "etc/vtltape@.service.in",
    "content": "[Unit]\nDocumentation=man:vtltape(1) man:vtlcmd(1)\nDescription=Tape Daemon for Virtual Tape & Robot Library\nBefore=mhvtl.target\nRequires=mhvtl-load-modules.service\nAfter=mhvtl-load-modules.service\nPartOf=mhvtl.target\n\n[Service]\nType=simple\nEnvironment=VERBOSE=0\nEnvironment=DAEMON_DEBUG=\nEnvironmentFile=-@CONF_PATH@/mhvtl.conf\nExecStart=/usr/bin/vtltape -F -q%i -v${VERBOSE} ${DAEMON_DEBUG}\nExecStop=/usr/bin/vtlcmd %i exit\nKillMode=none\n\n[Install]\nWantedBy=mhvtl.target\n"
  },
  {
    "path": "include/common/logging.h",
    "content": "/*\n * logging macros\n *\n * Copyright (C) 2005-2025 Mark Harvey markh794@gmail.com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n */\n\n#ifndef _LOGGING_H_\n#define _LOGGING_H_\n\n#include <syslog.h>\n#include <stdint.h>\n\n#define MHVTL_OPT_NOISE 0x11\n\n#ifdef MHVTL_DEBUG\nextern char\t   mhvtl_driver_name[];\nextern uint8_t debug;\nextern uint8_t verbose;\n\n#define MHVTL_DBG_NO_FUNC(lvl, format, arg...)            \\\n\tdo {                                                  \\\n\t\tif (debug)                                        \\\n\t\t\tprintf(\"%s: \" format \"\\n\",                    \\\n\t\t\t\t   mhvtl_driver_name, ##arg);             \\\n\t\telse if ((verbose) >= (lvl))                      \\\n\t\t\tsyslog(LOG_DAEMON | LOG_INFO, format, ##arg); \\\n\t} while (0)\n\n#define MHVTL_ERR(format, arg...)                                         \\\n\tdo {                                                                  \\\n\t\tif (debug) {                                                      \\\n\t\t\tprintf(\"%s: ERROR: %s(): \" format \"\\n\",                       \\\n\t\t\t\t   mhvtl_driver_name, __func__, ##arg);                   \\\n\t\t\tfflush(NULL);                                                 \\\n\t\t} else {                                                          \\\n\t\t\tsyslog(LOG_DAEMON | LOG_ERR, \"ERROR: %s(): line: %d,\" format, \\\n\t\t\t\t   __func__, __LINE__, ##arg);                            \\\n\t\t}                                                                 \\\n\t} while (0)\n\n#define MHVTL_LOG(format, arg...)                         \\\n\tdo {                                                  \\\n\t\tif (debug) {                                      \\\n\t\t\tprintf(\"%s: %s(): \" format \"\\n\",              \\\n\t\t\t\t   mhvtl_driver_name, __func__, ##arg);   \\\n\t\t\tfflush(NULL);                                 \\\n\t\t} else {                                          \\\n\t\t\tsyslog(LOG_DAEMON | LOG_ERR, \"%s(): \" format, \\\n\t\t\t\t   __func__, ##arg);                      \\\n\t\t}                                                 \\\n\t} while (0)\n\n#define MHVTL_DBG(lvl, format, arg...)                     \\\n\tdo {                                                   \\\n\t\tif (debug)                                         \\\n\t\t\tprintf(\"%s: %s(): \" format \"\\n\",               \\\n\t\t\t\t   mhvtl_driver_name, __func__, ##arg);    \\\n\t\telse if ((verbose) >= (lvl))                       \\\n\t\t\tsyslog(LOG_DAEMON | LOG_INFO, \"%s(): \" format, \\\n\t\t\t\t   __func__, ##arg);                       \\\n\t} while (0)\n\n#define MHVTL_DBG_PRT_CDB(lvl, cmd)      \\\n\tdo {                                 \\\n\t\tif (debug) {                     \\\n\t\t\tmhvtl_prt_cdb((lvl), (cmd)); \\\n\t\t} else if ((verbose) >= (lvl)) { \\\n\t\t\tmhvtl_prt_cdb((lvl), (cmd)); \\\n\t\t}                                \\\n\t} while (0)\n\n#else\n\n#define MHVTL_DBG(lvl, s...)\n#define MHVTL_DBG_NO_FUNC(lvl, s...)\n#define MHVTL_DBG_PRT_CDB(lvl, cmd)\n\n#define MHVTL_ERR(format, arg...)                            \\\n\tdo {                                                     \\\n\t\tsyslog(LOG_DAEMON | LOG_ERR, \"ERROR: %s(): \" format, \\\n\t\t\t   __func__, ##arg);                             \\\n\t} while (0)\n\n#define MHVTL_LOG(format, arg...)                     \\\n\tdo {                                              \\\n\t\tsyslog(LOG_DAEMON | LOG_ERR, \"%s(): \" format, \\\n\t\t\t   __func__, ##arg);                      \\\n\t} while (0)\n\n#endif /* MHVTL_DEBUG */\n#endif /*  _LOGGING_H_ */\n"
  },
  {
    "path": "include/common/mhvtl_scsi.h",
    "content": "/*\n * The userspace tape/library header file for the vtl virtual\n * tape kernel module.\n *\n * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n */\n\n#ifndef _SCSI_SCSI_H\n#define _SCSI_SCSI_H\n\n/*\n * Device types\n */\n#define TYPE_DISK\t\t\t0x00\n#define TYPE_TAPE\t\t\t0x01\n#define TYPE_PROCESSOR\t\t0x03\n#define TYPE_WORM\t\t\t0x04\n#define TYPE_ROM\t\t\t0x05\n#define TYPE_SCANNER\t\t0x06\n#define TYPE_MOD\t\t\t0x07\n#define TYPE_MEDIUM_CHANGER 0x08\n#define TYPE_ENCLOSURE\t\t0x0d\n#define TYPE_NO_LUN\t\t\t0x7f\n\n/*\n * SCSI Architectual model (SAM) Status codes.\n */\n#define SAM_STAT_GOOD\t\t\t\t\t\t0x00\n#define SAM_STAT_CHECK_CONDITION\t\t\t0x02\n#define SAM_STAT_CONDITION_MET\t\t\t\t0x04\n#define SAM_STAT_BUSY\t\t\t\t\t\t0x08\n#define SAM_STAT_INTERMEDIATE\t\t\t\t0x10\n#define SAM_STAT_INTERMEDIATE_CONDITION_MET 0x14\n#define SAM_STAT_RESERVATION_CONFLICT\t\t0x18\n#define SAM_STAT_COMMAND_TERMINATED\t\t\t0x22\n#define SAM_STAT_QUEUE_FULL\t\t\t\t\t0x28\n\n/*\n * SENSE keys\n */\n#define NO_SENSE\t\t0x00\n#define RECOVERED_ERROR 0x01\n#define NOT_READY\t\t0x02\n#define MEDIUM_ERROR\t0x03\n#define HARDWARE_ERROR\t0x04\n#define ILLEGAL_REQUEST 0x05\n#define UNIT_ATTENTION\t0x06\n#define DATA_PROTECT\t0x07\n#define BLANK_CHECK\t\t0x08\n#define VOLUME_OVERFLOW 0x0d\n\n/*\n * OP Codes\n */\n\n#define ALLOW_MEDIUM_REMOVAL\t\t\t\t 0x1e\n#define ALLOW_OVERWRITE\t\t\t\t\t\t 0x82\n#define ACCESS_CONTROL_IN\t\t\t\t\t 0x86\n#define ACCESS_CONTROL_OUT\t\t\t\t\t 0x87\n#define EXTENDED_COPY\t\t\t\t\t\t 0x83\n#define A3_SA\t\t\t\t\t\t\t\t 0xa3\n#define A4_SA\t\t\t\t\t\t\t\t 0xa4\n#define ERASE_6\t\t\t\t\t\t\t\t 0x19\n#define ERASE_16\t\t\t\t\t\t\t 0x93\n#define FORMAT_UNIT\t\t\t\t\t\t\t 0x04\n#define EXCHANGE_MEDIUM\t\t\t\t\t\t 0xa6\n#define INITIALIZE_ELEMENT_STATUS\t\t\t 0x07\n#define INITIALIZE_ELEMENT_STATUS_WITH_RANGE 0xE7\n#define INQUIRY\t\t\t\t\t\t\t\t 0x12\n#define LOAD_DISPLAY\t\t\t\t\t\t 0x06 /* STK T10000 specific */\n#define LOCATE_10\t\t\t\t\t\t\t 0x2b\n#define LOCATE_16\t\t\t\t\t\t\t 0x92\n#define MODE_SENSE\t\t\t\t\t\t\t 0x1a\n#define MODE_SENSE_10\t\t\t\t\t\t 0x5a\n#define MODE_SELECT\t\t\t\t\t\t\t 0x15\n#define MODE_SELECT_10\t\t\t\t\t\t 0x55\n#define MOVE_MEDIUM\t\t\t\t\t\t\t 0xa5\n#define LOG_SELECT\t\t\t\t\t\t\t 0x4c\n#define LOG_SENSE\t\t\t\t\t\t\t 0x4d\n#define PERSISTENT_RESERVE_IN\t\t\t\t 0x5e\n#define PERSISTENT_RESERVE_OUT\t\t\t\t 0x5f\n#define READ_6\t\t\t\t\t\t\t\t 0x08\n#define READ_10\t\t\t\t\t\t\t\t 0x28\n#define READ_12\t\t\t\t\t\t\t\t 0xa8\n#define READ_16\t\t\t\t\t\t\t\t 0x88\n#define READ_ATTRIBUTE\t\t\t\t\t\t 0x8c\n#define READ_BLOCK_LIMITS\t\t\t\t\t 0x05\n#define READ_BUFFER\t\t\t\t\t\t\t 0x3c\n#define READ_ELEMENT_STATUS\t\t\t\t\t 0xb8\n#define READ_MEDIA_SERIAL_NUMBER\t\t\t 0xab\n#define READ_POSITION\t\t\t\t\t\t 0x34\n#define READ_REVERSE_6\t\t\t\t\t\t 0x0f\n#define READ_REVERSE_16\t\t\t\t\t\t 0x81\n#define RECEIVE_DIAGNOSTIC\t\t\t\t\t 0x1c\n#define RECOVER_BUFFERED_DATA\t\t\t\t 0x14\n#define RELEASE\t\t\t\t\t\t\t\t 0x17\n#define RELEASE_10\t\t\t\t\t\t\t 0x57\n#define REPORT_DENSITY\t\t\t\t\t\t 0x44\n#define REPORT_ELEMENT_INFORMATION\t\t\t 0x9e\n#define REPORT_LUNS\t\t\t\t\t\t\t 0xa0\n#define REQUEST_SENSE\t\t\t\t\t\t 0x03\n#define RESERVE\t\t\t\t\t\t\t\t 0x16\n#define RESERVE_10\t\t\t\t\t\t\t 0x56\n#define REZERO_UNIT\t\t\t\t\t\t\t 0x01\n#define SECURITY_PROTOCOL_IN\t\t\t\t 0xa2\n#define SECURITY_PROTOCOL_OUT\t\t\t\t 0xb5\n#define SEND_DIAGNOSTIC\t\t\t\t\t\t 0x1d\n#define SET_CAPACITY\t\t\t\t\t\t 0x0b\n#define SPACE\t\t\t\t\t\t\t\t 0x11\n#define SPACE_16\t\t\t\t\t\t\t 0x91\n#define START_STOP\t\t\t\t\t\t\t 0x1b\n#define TEST_UNIT_READY\t\t\t\t\t\t 0x00\n#define VERIFY_6\t\t\t\t\t\t\t 0x13\n#define VERIFY_16\t\t\t\t\t\t\t 0x8f\n#define WRITE_6\t\t\t\t\t\t\t\t 0x0a\n#define WRITE_10\t\t\t\t\t\t\t 0x2a\n#define WRITE_12\t\t\t\t\t\t\t 0xaa\n#define WRITE_16\t\t\t\t\t\t\t 0x8a\n#define WRITE_ATTRIBUTE\t\t\t\t\t\t 0x8d\n#define WRITE_BUFFER\t\t\t\t\t\t 0x3b\n#define WRITE_FILEMARKS\t\t\t\t\t\t 0x10\n#define WRITE_FILEMARKS_16\t\t\t\t\t 0x80\n\n/* Service codes */\n#define FORCED_EJECT\t\t\t 0x1f\n#define MANAGEMENT_PROTOCOL_IN\t 0x10\n#define MANAGEMENT_PROTOCOL_OUT\t 0x10\n#define CHANGE_ALIASES\t\t\t 0x0b\n#define REPORT_ALIASES\t\t\t 0x0b\n#define REPORT_SUPPORTED_OPCODES 0x0c\n#define REPORT_TIMESTAMP\t\t 0x0f\n#define SET_TIMESTAMP\t\t\t 0x0f\n\n/* No Sense Errors */\n#define NO_ADDITIONAL_SENSE\t\t\t 0x0000\n#define E_MARK\t\t\t\t\t\t 0x0001\n#define E_EOM\t\t\t\t\t\t 0x0002\n#define E_BOM\t\t\t\t\t\t 0x0004\n#define E_END_OF_DATA\t\t\t\t 0x0005\n#define E_PROGRAMMABLE_EARLY_WARNING 0x0007\n#define E_OP_IN_PROGRESS\t\t\t 0x0016\n#define E_DRIVE_REQUIRES_CLEANING\t 0x8282\n\n/* Recovered Errors */\n#define E_WRITE_ERROR\t\t\t 0x0c00\n#define E_READ_ERROR\t\t\t 0x1100\n#define E_RECOVERED_WITH_RETRYS\t 0x1701\n#define E_MEDIA_LOAD_EJECT_ERROR 0x5300\n#define E_FAILURE_PREDICTION\t 0x5d00\n\n/* Not ready */\n#define E_CAUSE_NOT_REPORTABLE\t  0x0400\n#define E_BECOMING_READY\t\t  0x0401\n#define E_INITIALIZING_REQUIRED\t  0x0402\n#define E_OFFLINE\t\t\t\t  0x0412\n#define E_EARLY_WARNING_EOM\t\t  0x2c98\n#define E_CLEANING_CART_INSTALLED 0x3003\n#define E_CLEANING_FAILURE\t\t  0x3007\n#define E_MEDIUM_NOT_PRESENT\t  0x3a00\n#define E_MAP_OPEN\t\t\t\t  0x3a02\n#define E_LOGICAL_UNIT_NOT_CONFIG 0x3e00\n\n/* Medium Errors */\n#define E_WRITE_ERROR\t\t\t\t0x0c00\n#define E_UNRECOVERED_READ\t\t\t0x1100\n#define E_RECORDED_ENTITY_NOT_FOUND 0x1400\n#define E_UNKNOWN_FORMAT\t\t\t0x3001\n#define E_IMCOMPATIBLE_FORMAT\t\t0x3002\n#define E_MEDIUM_FMT_CORRUPT\t\t0x3100\n#define E_SEQUENTIAL_POSITION_ERR\t0x3b00\n#define E_WRITE_APPEND_ERR\t\t\t0x5000\n#define E_CARTRIDGE_FAULT\t\t\t0x5200\n\n/* Hardware Failure */\n#define E_COMPRESSION_CHECK\t\t\t 0x0c04\n#define E_LOGICAL_BLOCK_GUARD_FAILED 0x1001\n#define E_DECOMPRESSION_CRC\t\t\t 0x110d\n#define E_MANUAL_INTERVENTION_REQ\t 0x0403\n#define E_HARDWARE_FAILURE\t\t\t 0x4000\n#define E_INTERNAL_TARGET_FAILURE\t 0x4400\n#define E_ERASE_FAILURE\t\t\t\t 0x5100\n\n/* Illegal Request */\n#define E_PARAMETER_LIST_LENGTH_ERR\t\t  0x1a00\n#define E_INVALID_OP_CODE\t\t\t\t  0x2000\n#define E_ILLEGAL_COMMAND_WHEN_NOT_APPEND 0x200C\n#define E_INVALID_ELEMENT_ADDR\t\t\t  0x2101\n#define E_INVALID_FIELD_IN_CDB\t\t\t  0x2400\n#define E_LUN_NOT_SUPPORTED\t\t\t\t  0x2500\n#define E_INVALID_FIELD_IN_PARMS\t\t  0x2600\n#define E_MEDIUM_INCOMPATIBLE\t\t\t  0x3000\n#define E_SAVING_PARMS_UNSUP\t\t\t  0x3900\n#define E_SEQUENTIAL_POSITIONING_ERROR\t  0x3b00\n#define E_MEDIUM_DEST_FULL\t\t\t\t  0x3b0d\n#define E_MEDIUM_SRC_EMPTY\t\t\t\t  0x3b0e\n#define E_POSITION_PAST_BOM\t\t\t\t  0x3b0c\n#define E_MEDIUM_REMOVAL_PREVENTED\t\t  0x5302\n#define E_BAD_MICROCODE_DETECTED\t\t  0x8283\n\n/* Unit Attention */\n#define E_NOT_READY_TO_TRANSITION  0x2800\n#define E_IMPORT_ELEMENT_ACCESSED  0x2801\n#define E_POWERON_RESET\t\t\t   0x2900\n#define E_I_T_NEXUS_LOSS\t\t   0x2907\n#define E_MODE_PARAMETERS_CHANGED  0x2a01\n#define E_MICROCODE_DOWNLOADED\t   0x3f01\n#define E_FAILURE_PREDICTION_FALSE 0x5dff\n#define E_MODE_PARAMETERS_CHANGED  0x2a01\n#define E_TIMESTAMP_CHANGED\t\t   0x2a10\n#define E_INQUIRY_DATA_HAS_CHANGED 0x3f03\n\n/* Data Protect */\n#define E_WRITE_PROTECT\t\t\t   0x2700\n#define E_MEDIUM_OVERWRITE_ATTEMPT 0x300c\n#define E_UNABLE_TO_DECRYPT\t\t   0x7401\n#define E_UNENCRYPTED_DATA\t\t   0x7402\n#define E_INCORRECT_KEY\t\t\t   0x7403\n\n/* Suppress Incorrect Length Indicator */\n#define SILI 0x2\n/* Fixed block format */\n#define FIXED_BLOCK 0x1\n\n/* Sense Data format bits & pieces */\n/* Incorrect Length Indicator */\n#define SD_CURRENT_INFORMATION_FIXED 0x70\n#define SD_VALID\t\t\t\t\t 0x80\n#define SD_FILEMARK\t\t\t\t\t 0x80\n#define SD_EOM\t\t\t\t\t\t 0x40\n#define SD_ILI\t\t\t\t\t\t 0x20\n\n/* Sense - field pointer sense key specific data - SPC4 - 4.5.2.4 */\n#define SKSV 0x80\n#define CD\t 0x40\n#define BPV\t 0x08\n\n/* MODE PAGE */\n#define MODE_RW_ERROR_RECOVER\t\t  0x01\n#define MODE_DISCONNECT_RECONNECT\t  0x02\n#define MODE_CONTROL\t\t\t\t  0x0a\n#define MODE_DATA_COMPRESSION\t\t  0x0f\n#define MODE_DEVICE_CONFIGURATION\t  0x10\n#define MODE_MEDIUM_PARTITION\t\t  0x11\n#define MODE_POWER_CONDITION\t\t  0x1a\n#define MODE_INFORMATION_EXCEPTION\t  0x1c\n#define MODE_MEDIUM_CONFIGURATION\t  0x1d\n#define MODE_ELEMENT_ADDRESS\t\t  0x1d\n#define MODE_TRANSPORT_GEOMETRY\t\t  0x1e\n#define MODE_DEVICE_CAPABILITIES\t  0x1f\n#define MODE_VENDOR_SPECIFIC_24H\t  0x24\n#define MODE_VENDOR_SPECIFIC_25H\t  0x25\n#define MODE_BEHAVIOR_CONFIGURATION\t  0x2f\n#define MODE_ENCRYPTION_MODE\t\t  0x30\n#define MODE_AIT_DEVICE_CONFIGURATION 0x31\n\n#define TA_NONE\t\t\t\t\t\t 0x00\n#define TA_READ\t\t\t\t\t\t 0x01\n#define TA_WRITE\t\t\t\t\t 0x02\n#define TA_HARD\t\t\t\t\t\t 0x04\n#define TA_MEDIA\t\t\t\t\t 0x08\n#define TA_READ_FAILURE\t\t\t\t 0x10\n#define TA_WRITE_FAILURE\t\t\t 0X20\n#define TA_MEDIA_EOL\t\t\t\t 0x40\n#define TA_NOT_DATA_GRADE\t\t\t 0X80\n#define TA_WRITE_PROTECT\t\t\t 0X100\n#define TA_DRIVE_IN_USE\t\t\t\t 0x200\n#define TA_CLEANING_MEDIA\t\t\t 0x400\n#define TA_MEDIA_NOT_SUPPORTED\t\t 0x800\n#define TA_RECOV_CART_FAILURE\t\t 0x1000\n#define TA_UNRECOV_CART_FAILURE\t\t 0x2000\n#define TA_MEM_CHIP_FAILURE\t\t\t 0x4000\n#define TA_TAPE_UNMOUNTED\t\t\t 0x8000\n#define TA_MEDIA_RO\t\t\t\t\t 0x10000\n#define TA_MEDIA_DIR_CORRUPT\t\t 0x20000\n#define TA_MEDIA_NEAR_EOL\t\t\t 0x40000\n#define TA_DRIVE_NEEDS_CLEANING\t\t 0x80000\n#define TA_CLEAN_PERIODIC\t\t\t 0x100000\n#define TA_EXPIRED_CLEANING_CART\t 0x200000\n#define TA_INVALID_CLEANING_CART\t 0x400000\n#define TA_RETENTION_REQUESTED\t\t 0x800000\n#define TA_INTERFACE_PORT_ERROR\t\t 0x1000000\n#define TA_COOLING_FAN_FAILURE\t\t 0x2000000\n#define TA_PSU_FAILURE\t\t\t\t 0x4000000\n#define TA_PSU_POWER_CONSUMPTION\t 0x8000000\n#define TA_PREVENTIVE_MAINTENANCE\t 0x10000000\n#define TA_HARDWARE_A_FAULT\t\t\t 0x20000000\n#define TA_HARDWARE_B_FAULT\t\t\t 0x40000000\n#define TA_INTERFACE_FAULT\t\t\t 0x80000000\n#define TA_MOUNT_FAILURE\t\t\t 0x100000000ull\n#define TA_INCORRECT_FIRMWARE\t\t 0x200000000ull\n#define TA_HUMIDITY_CONDITIONS\t\t 0x400000000ull\n#define TA_TEMPERATURE_CONDITIONS\t 0x800000000ull\n#define TA_DRIVE_VOLTAGE\t\t\t 0x1000000000ull\n#define TA_PREDICTIVE_FAILURE\t\t 0x2000000000ull\n#define TA_DIAGNOSTICS_REQUIRED\t\t 0x4000000000ull\n#define TA_LOST_STATISTICS\t\t\t 0x2000000000000ull\n#define TA_TAPE_DIR_INVALID\t\t\t 0x4000000000000ull\n#define TA_SYSTEM_AREA_WRITE_FAILURE 0x8000000000000ull\n#define TA_SYSTEM_AREA_READ_FAILURE\t 0x10000000000000ull\n#define TA_NO_START_OF_DATA\t\t\t 0x20000000000000ull\n#define TA_LOAD_FAILURE\t\t\t\t 0x40000000000000ull\n#define TA_UNRECOV_UNLOAD_FAILURE\t 0x80000000000000ull\n#define TA_AUTOMATION_FAILURE\t\t 0x100000000000000ull\n#define TA_FIRMWARE_FAILURE\t\t\t 0x200000000000000ull\n#define TA_WORM_INTEGRITY_FAILED\t 0x400000000000000ull\n#define TA_WORM_OVERWRITE_ATTEMPTED\t 0x800000000000000ull\n\n#endif /* _SCSI_SCSI_H */"
  },
  {
    "path": "include/common/vtl_common.h",
    "content": "/* Common stuff for kernel and usr programs */\n#ifndef VTL_COMMON_H\n#define VTL_COMMON_H\n\n#define SENSE_BUF_SIZE 96\n/* Max cdb size */\n#define MAX_COMMAND_SIZE 16\n\n#define VTL_IDLE\t  0x00\n#define VTL_QUEUE_CMD 0xfe\n\n/* ioctl defines */\n#define VX_TAPE_ONLINE\t\t\t0x80\n#define VTL_POLL_AND_GET_HEADER 0x200\n#define VTL_GET_DATA\t\t\t0x201\n#define VTL_PUT_DATA\t\t\t0x203\n#define VTL_REMOVE_LU\t\t\t0x205\n\n#define VENDOR_ID_LEN\t8\n#define PRODUCT_ID_LEN\t16\n#define PRODUCT_REV_LEN 4\n\nstruct mhvtl_header {\n\tunsigned long long serialNo;\n\tunsigned char\t   cdb[MAX_COMMAND_SIZE];\n\tunsigned char\t  *buf;\n};\n\nstruct mhvtl_ds {\n\tvoid\t\t\t  *data;\n\tunsigned int\t   sz;\n\tunsigned long long serialNo;\n\tvoid\t\t\t  *sense_buf;\n\tunsigned char\t   sam_stat;\n};\n\nstruct mhvtl_ctl {\n\tunsigned int channel;\n\tunsigned int id;\n\tunsigned int lun;\n};\n\n#if !defined(FALSE)\n#define FALSE 0\n#endif\n\n#if !defined(TRUE)\n#define TRUE 1\n#endif\n\n#endif /* VTL_COMMON_H */\n"
  },
  {
    "path": "include/common/vtl_u.h",
    "content": "/*\n * vtl_u.h\n */\n#define NETLINK_VTL 22\n\nstruct mhvtl_event {\n\tu32\t\t\ttid;\n\taligned_u64 sid;\n\taligned_u64 serial_no;\n\tu32\t\t\tcid;\n\tu32\t\t\tstate;\n}\n"
  },
  {
    "path": "include/common/vtltape_pem.h",
    "content": "static char *certificate =\n\t\"-----BEGIN CERTIFICATE-----\\n\"\n\t\"MIID9zCCA2CgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBtDELMAkGA1UEBhMCTlox\\n\"\n\t\"EzARBgNVBAcTCldlbGxpbmd0b24xPDA6BgNVBAoTM1JlYWxseSBJcnJlc3BvbnNp\\n\"\n\t\"YmxlIEF1dGhvcmlzYXRpb24gQXV0aG9yaXR5IChSSUFBKTEWMBQGA1UECxMNQ2Vy\\n\"\n\t\"dC1zdGFtcGluZzEZMBcGA1UEAxMQSmFja292IGFsLVRyYWRlczEfMB0GCSqGSIb3\\n\"\n\t\"DQEJARYQbm9uZUBmYWtlLmRvbWFpbjAeFw0wMjAxMTYwNTA5NTlaFw0xMjAxMTQw\\n\"\n\t\"NTA5NTlaMIG0MQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2VsbGluZ3RvbjE8MDoG\\n\"\n\t\"A1UEChMzUmVhbGx5IElycmVzcG9uc2libGUgQXV0aG9yaXNhdGlvbiBBdXRob3Jp\\n\"\n\t\"dHkgKFJJQUEpMRYwFAYDVQQLEw1DZXJ0LXN0YW1waW5nMRkwFwYDVQQDExBKYWNr\\n\"\n\t\"b3YgYWwtVHJhZGVzMR8wHQYJKoZIhvcNAQkBFhBub25lQGZha2UuZG9tYWluMIGf\\n\"\n\t\"MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7QdDfFIrJn3X24hKmpkyk3TG0Ivxd\\n\"\n\t\"K2wWmDPXq1wjr8lUTwrA6hM5Ba9N36jLieWpXhviLOWu9DBza5GmtgCuXloATKTC\\n\"\n\t\"94xOdKHlciTVujG3wDlLDB5e710Kar84nnj6VueL1RyZ0bmP5PANa4mbGW9Tqc7J\\n\"\n\t\"CkBTTW2y9d0SgQIDAQABo4IBFTCCAREwHQYDVR0OBBYEFEn7RXISxMzhRaHTCJ6V\\n\"\n\t\"xCxtVT8XMIHhBgNVHSMEgdkwgdaAFEn7RXISxMzhRaHTCJ6VxCxtVT8XoYG6pIG3\\n\"\n\t\"MIG0MQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2VsbGluZ3RvbjE8MDoGA1UEChMz\\n\"\n\t\"UmVhbGx5IElycmVzcG9uc2libGUgQXV0aG9yaXNhdGlvbiBBdXRob3JpdHkgKFJJ\\n\"\n\t\"QUEpMRYwFAYDVQQLEw1DZXJ0LXN0YW1waW5nMRkwFwYDVQQDExBKYWNrb3YgYWwt\\n\"\n\t\"VHJhZGVzMR8wHQYJKoZIhvcNAQkBFhBub25lQGZha2UuZG9tYWluggEAMAwGA1Ud\\n\"\n\t\"EwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAYQo95V/NY+eKxYxkhibZiUQygph+\\n\"\n\t\"gTfgbDG20MsnH6+8//w5ArHauFCgDrf0P2VyACgq+N4pBTWFGaAaLwbjKy9HCe2E\\n\"\n\t\"j9C91tO1CqDS4MJkDB5AP13FTkK6fP1ZCiTQranOAp3DlGWTTWsFVyW5kVfQ9diS\\n\"\n\t\"ZOyJZ9Fit5XM2X0=\\n\"\n\t\"-----END CERTIFICATE-----\\n\";\n"
  },
  {
    "path": "include/mhvtl_log.h",
    "content": "/*\n * This handles any SCSI OP 'log sense / log select'\n *\n * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n * See comments in vtltape.c for a more complete version release...\n *\n */\n\n#ifndef MHVTL_LOG_H\n#define MHVTL_LOG_H\n\n#include <stdint.h>\n#include \"mhvtl_list.h\"\n\nstruct lu_phy_attr;\ntypedef void (*init_pg_fn)(void *log_ptr);\n\n/*\n * Process the LOG_SENSE page definitions\n */\n#define SUPPORTED_LOG_PAGES\t\t\t0x00\n#define BUFFER_UNDER_OVER_RUN\t\t0x01\n#define WRITE_ERROR_COUNTER\t\t\t0x02\n#define READ_ERROR_COUNTER\t\t\t0x03\n#define READ_REVERSE_ERROR_COUNTER\t0x04\n#define VERIFY_ERROR_COUNTER\t\t0x05\n#define NON_MEDIUM_ERROR_COUNTER\t0x06\n#define LAST_n_ERROR\t\t\t\t0x07\n#define FORMAT_STATUS\t\t\t\t0x08\n#define LAST_n_DEFERRED_ERROR\t\t0x0b\n#define SEQUENTIAL_ACCESS_DEVICE\t0x0c\n#define TEMPERATURE_PAGE\t\t\t0x0d\n#define START_STOP_CYCLE_COUNTER\t0x0e\n#define APPLICATION_CLIENT\t\t\t0x0f\n#define SELFTEST_RESULTS\t\t\t0x10\n#define DEVICE_STATUS\t\t\t\t0x11\n#define VOLUME_STATISTICS\t\t\t0x17\n#define TAPE_ALERT\t\t\t\t\t0x2e\n#define INFORMATIONAL_EXCEPTIONS\t0x2f\n#define TAPE_USAGE\t\t\t\t\t0x30\n#define TAPE_CAPACITY\t\t\t\t0x31\n#define DATA_COMPRESSION\t\t\t0x32\n#define PERFORMANCE_CHARACTERISTICS 0x37\n\n#define NO_SUBPAGE 0x00\n\nstruct log_pg_list {\n\tstruct list_head siblings;\n\tchar\t\t\t*description;\n\tint\t\t\t\t log_page_num;\n\tint\t\t\t\t log_subpage_num;\n\tint\t\t\t\t size;\n\tvoid\t\t\t*p;\n};\n\n/* Log Page header */\nstruct log_pg_header {\n\tuint8_t\t pcode;\n\tuint8_t\t res;\n\tuint16_t len;\n} __attribute__((packed));\n\n/* Page Code header struct. */\nstruct pc_header {\n\tuint8_t head0;\n\tuint8_t head1;\n\tuint8_t flags;\n\tuint8_t len;\n} __attribute__((packed));\n\n/* Vendor Specific : 0x32 (Taken from IBM Ultrium doco) */\nstruct DataCompression_pg {\n\tstruct log_pg_header pcode_head;\n\n\tstruct pc_header h_ReadCompressionRatio;\n\tuint16_t\t\t ReadCompressionRatio;\n\tstruct pc_header h_WriteCompressionRatio;\n\tuint16_t\t\t WriteCompressionRatio;\n\tstruct pc_header h_MBytesToServer;\n\tuint32_t\t\t MBytesToServer;\n\tstruct pc_header h_BytesToServer;\n\tuint32_t\t\t BytesToServer;\n\tstruct pc_header h_MBytesReadFromTape;\n\tuint32_t\t\t MBytesReadFromTape;\n\tstruct pc_header h_BytesReadFromTape;\n\tuint32_t\t\t BytesReadFromTape;\n\n\tstruct pc_header h_MBytesFromServer;\n\tuint32_t\t\t MBytesFromServer;\n\tstruct pc_header h_BytesFromServer;\n\tuint32_t\t\t BytesFromServer;\n\tstruct pc_header h_MBytesWrittenToTape;\n\tuint32_t\t\t MBytesWrittenToTape;\n\tstruct pc_header h_BytesWrittenToTape;\n\tuint32_t\t\t BytesWrittenToTape;\n} __attribute__((packed));\n\n/* Buffer Under/Over Run log page - 0x01 : SPC-3 (7.2.3) */\nstruct BufferUnderOverRun_pg {\n\tstruct log_pg_header pcode_head;\n} __attribute__((packed));\n\nstruct TapeUsage_pg {\n\tstruct log_pg_header pcode_head;\n\tstruct pc_header\t flagNo01;\n\tuint32_t\t\t\t volumeMounts;\n\tstruct pc_header\t flagNo02;\n\tuint64_t\t\t\t volumeDatasetsWritten;\n\tstruct pc_header\t flagNo03;\n\tuint32_t\t\t\t volWriteRetries;\n\tstruct pc_header\t flagNo04;\n\tuint16_t\t\t\t volWritePerms;\n\tstruct pc_header\t flagNo05;\n\tuint16_t\t\t\t volSuspendedWrites;\n\tstruct pc_header\t flagNo06;\n\tuint16_t\t\t\t volFatalSuspendedWrites;\n\tstruct pc_header\t flagNo07;\n\tuint64_t\t\t\t volDatasetsRead;\n\tstruct pc_header\t flagNo08;\n\tuint32_t\t\t\t volReadRetries;\n\tstruct pc_header\t flagNo09;\n\tuint16_t\t\t\t volReadPerms;\n\tstruct pc_header\t flagNo10;\n\tuint16_t\t\t\t volSuspendedReads;\n\tstruct pc_header\t flagNo11;\n\tuint16_t\t\t\t volFatalSuspendedReads;\n} __attribute__((packed));\n\n/* Self-Test Results - 0x10\n *\n */\n\nstruct selfTest_data { /* data in log parameters of selftest results */\n\tuint8_t\t self_test_code_results;\n\tuint8_t\t self_test_number;\n\tuint16_t accumulated_power_on_hours;\n\tuint64_t address_of_first_failure;\n\tuint8_t\t sense_key;\n\tuint8_t\t asc;\n\tuint8_t\t ascq;\n\tuint8_t\t vendor_specific;\n} __attribute__((packed));\n\nstruct SelfTestResults_pg {\n\n\tstruct log_pg_header pcode_head;\n\n\tstruct pc_header\t h_result01;\n\tstruct selfTest_data data01;\n\n\tstruct pc_header\t h_result02;\n\tstruct selfTest_data data02;\n\n\tstruct pc_header\t h_result03;\n\tstruct selfTest_data data03;\n\n\tstruct pc_header\t h_result04;\n\tstruct selfTest_data data04;\n\n\tstruct pc_header\t h_result05;\n\tstruct selfTest_data data05;\n\n\tstruct pc_header\t h_result06;\n\tstruct selfTest_data data06;\n\n\tstruct pc_header\t h_result07;\n\tstruct selfTest_data data07;\n\n\tstruct pc_header\t h_result08;\n\tstruct selfTest_data data08;\n\n\tstruct pc_header\t h_result09;\n\tstruct selfTest_data data09;\n\n\tstruct pc_header\t h_result0a;\n\tstruct selfTest_data data0a;\n\n\tstruct pc_header\t h_result0b;\n\tstruct selfTest_data data0b;\n\n\tstruct pc_header\t h_result0c;\n\tstruct selfTest_data data0c;\n\n\tstruct pc_header\t h_result0d;\n\tstruct selfTest_data data0d;\n\n\tstruct pc_header\t h_result0e;\n\tstruct selfTest_data data0e;\n\n\tstruct pc_header\t h_result0f;\n\tstruct selfTest_data data0f;\n\n\tstruct pc_header\t h_result10;\n\tstruct selfTest_data data10;\n\n\tstruct pc_header\t h_result11;\n\tstruct selfTest_data data11;\n\n\tstruct pc_header\t h_result12;\n\tstruct selfTest_data data12;\n\n\tstruct pc_header\t h_result13;\n\tstruct selfTest_data data13;\n\n\tstruct pc_header\t h_result14;\n\tstruct selfTest_data data14;\n\n} __attribute__((packed));\n\nstruct DeviceStatus_pg {\n\tstruct log_pg_header pcode_head;\n\n\tstruct pc_header h_vhf;\n\tstruct __attribute__((packed)) {\n\t\tstruct __attribute__((packed)) {\n\t\t\tuint8_t DINIT : 1; /* Device Initialized - 0 not initialised*/\n\t\t\tuint8_t CRQRD : 1; /* Cleaning required - before media is mounted (required) */\n\t\t\tuint8_t CRQST : 1; /* Cleaning required - non urgent (request) */\n\t\t\tuint8_t WRTP : 1;  /* Physical Write Protect */\n\t\t\tuint8_t CMPR : 1;  /* Compression enabled */\n\t\t\tuint8_t MACC : 1;  /* MAM accessible */\n\t\t\tuint8_t HIU : 1;   /* Host Initiated Unload */\n\t\t\tuint8_t PAMR : 1;  /* Prevent/Allow Media Removal */\n\t\t} b4;\n\n\t\tstruct __attribute__((packed)) {\n\t\t\tuint8_t MOUNTED : 1; /* Medium mounted */\n\t\t\tuint8_t MTHRD : 1;\t /* Medium Threaded */\n\t\t\tuint8_t MSTD : 1;\t /* Medium Seated */\n\t\t\tuint8_t RSVD_2 : 1;\n\t\t\tuint8_t MPRSNT : 1; /* Medium Present */\n\t\t\tuint8_t RAA : 1;\t/* Robotic access allowed */\n\t\t\tuint8_t RSVD_1 : 1;\n\t\t\tuint8_t INXTN : 1; /* In Transition - other bits in byte 5 not stable */\n\t\t} b5;\n\n\t\tuint8_t b6; /* DT Device Activity */\n\n\t\tstruct __attribute__((packed)) {\n\t\t\tuint8_t TAFC : 1;\t/* TapeAlert state flag changed */\n\t\t\tuint8_t INITFC : 1; /* Interface changed */\n\t\t\tuint8_t RRQST : 1;\t/* Recovery requested */\n\t\t\tuint8_t ESR : 1;\t/* Encryption Service Requested */\n\t\t\tuint8_t EPP : 1;\t/* Encryption Parameters Present */\n\t\t\tuint8_t TDDEC : 1;\t/* Tape Diagnostic data entry created */\n\t\t\tuint8_t RSVD : 1;\n\t\t\tuint8_t VS : 1; /* Always 0 */\n\t\t} b7;\n\n\t} vhf; /* Very High Frequency data */\n} __attribute__((packed));\n\nstruct TapeCapacity_pg {\n\tstruct log_pg_header pcode_head;\n\tstruct pc_header\t flagNo01;\n\tuint32_t\t\t\t partition0remaining;\n\tstruct pc_header\t flagNo02;\n\tuint32_t\t\t\t partition1remaining;\n\tstruct pc_header\t flagNo03;\n\tuint32_t\t\t\t partition0maximum;\n\tstruct pc_header\t flagNo04;\n\tuint32_t\t\t\t partition1maximum;\n} __attribute__((packed));\n\n/* Volume Statistics - 0x17\n * SSC-4\n */\nstruct partition_record_header {\n\tuint8_t\t len;\n\tuint8_t\t reserved;\n\tuint16_t partition_no;\n\n} __attribute__((packed));\n\nstruct partition_record_size4 {\n\tstruct partition_record_header header;\n\tuint32_t\t\t\t\t\t   data;\n} __attribute__((packed));\n\nstruct partition_record_size6 {\n\tstruct partition_record_header header;\n\tuint8_t\t\t\t\t\t\t   data[6];\n} __attribute__((packed));\n\nstruct VolumeStatistics_pg {\n\tstruct log_pg_header pcode_head;\n\n\tstruct pc_header h_PageValid;\n\tuint8_t\t\t\t PageValid;\n\n\tstruct pc_header h_VolumeMounts;\n\tuint32_t\t\t VolumeMounts;\n\n\tstruct pc_header h_VolumeDatasetsWritten;\n\tuint64_t\t\t VolumeDatasetsWritten;\n\n\tstruct pc_header h_RecoveredWriteDataErrors;\n\tuint32_t\t\t RecoveredWriteDataErrors;\n\n\tstruct pc_header h_UnrecoveredWriteDataErrors;\n\tuint16_t\t\t UnrecoveredWriteDataErrors;\n\n\tstruct pc_header h_WriteServoErrors;\n\tuint16_t\t\t WriteServoErrors;\n\n\tstruct pc_header h_UnrecoveredWriteServoErrors;\n\tuint16_t\t\t UnrecoveredWriteServoErrors;\n\n\tstruct pc_header h_VolumeDatasetsRead;\n\tuint64_t\t\t VolumeDatasetsRead;\n\n\tstruct pc_header h_RecoveredReadErrors;\n\tuint32_t\t\t RecoveredReadErrors;\n\n\tstruct pc_header h_UnrecoveredReadErrors;\n\tuint16_t\t\t UnrecoveredReadErrors;\n\n\tstruct pc_header h_LastMountUnrecoveredWriteErrors;\n\tuint16_t\t\t LastMountUnrecoveredWriteErrors;\n\n\tstruct pc_header h_LastMountUnrecoveredReadErrors;\n\tuint16_t\t\t LastMountUnrecoveredReadErrors;\n\n\tstruct pc_header h_LastMountMBWritten;\n\tuint32_t\t\t LastMountMBWritten;\n\n\tstruct pc_header h_LastMountMBRead;\n\tuint32_t\t\t LastMountMBRead;\n\n\tstruct pc_header h_LifetimeMBWritten;\n\tuint64_t\t\t LifetimeMBWritten;\n\n\tstruct pc_header h_LifetimeMBRead;\n\tuint64_t\t\t LifetimeMBRead;\n\n\tstruct pc_header h_LastLoadWriteCompressionRatio;\n\tuint16_t\t\t LastLoadWriteCompressionRatio;\n\n\tstruct pc_header h_LastLoadReadCompressionRatio;\n\tuint16_t\t\t LastLoadReadCompressionRatio;\n\n\tstruct pc_header h_MediumMountTime;\n\tuint8_t\t\t\t MediumMountTime[6];\n\n\tstruct pc_header h_MediumReadyTime;\n\tuint8_t\t\t\t MediumReadyTime[6];\n\n\tstruct pc_header h_TotalNativeCapacity;\n\tuint32_t\t\t TotalNativeCapacity;\n\n\tstruct pc_header h_TotalUsedNativeCapacity;\n\tuint32_t\t\t TotalUsedNativeCapacity;\n\n\tstruct pc_header h_AppDesignCapacity;\n\tuint32_t\t\t AppDesignCapacity;\n\n\tstruct pc_header h_VolumeLifetimeRemaining;\n\tuint8_t\t\t\t VolumeLifetimeRemaining;\n\n\tstruct pc_header h_VolumeSerialNumber;\n\tuint8_t\t\t\t VolumeSerialNumber[32];\n\n\tstruct pc_header h_TapeLotIdentifier;\n\tuint8_t\t\t\t TapeLotIdentifier[8];\n\n\tstruct pc_header h_VolumeBarcode;\n\tuint8_t\t\t\t VolumeBarcode[32];\n\n\tstruct pc_header h_VolumeManufacturer;\n\tuint8_t\t\t\t VolumeManufacturer[8];\n\n\tstruct pc_header h_VolumeLicenseCode;\n\tuint8_t\t\t\t VolumeLicenseCode[4];\n\n\tstruct pc_header h_VolumePersonality;\n\tuint8_t\t\t\t VolumePersonality[9];\n\n\tstruct pc_header h_WriteProtect;\n\tuint8_t\t\t\t WriteProtect;\n\n\tstruct pc_header h_WORM;\n\tuint8_t\t\t\t WORM;\n\n\tstruct pc_header h_TempExceeded;\n\tuint8_t\t\t\t TempExceeded;\n\n\tstruct pc_header h_BOMPasses;\n\tuint32_t\t\t BOMPasses;\n\n\tstruct pc_header h_MOTPasses;\n\tuint32_t\t\t MOTPasses;\n\n\t/* size depends on actual nb of partitions\n\t=> we put max size by default and adapt dynamically later */\n\tstruct pc_header\t\t\t  h_FirstEncryptedLogicalObj;\n\tstruct partition_record_size6 FirstEncryptedLogicalObj[MAX_PARTITIONS];\n\n\tstruct pc_header\t\t\t  h_FirstUnencryptedLogicalObj;\n\tstruct partition_record_size6 FirstUnencryptedLogicalObj[MAX_PARTITIONS];\n\n\tstruct pc_header\t\t\t  h_ApproxNativeCapacityPartition;\n\tstruct partition_record_size4 ApproxNativeCapacityPartition[MAX_PARTITIONS];\n\n\tstruct pc_header\t\t\t  h_ApproxUsedNativeCapacityPartition;\n\tstruct partition_record_size4 ApproxUsedNativeCapacityPartition[MAX_PARTITIONS];\n\n\tstruct pc_header\t\t\t  h_RemainingCapacityToEWPartition;\n\tstruct partition_record_size4 RemainingCapacityToEWPartition[MAX_PARTITIONS];\n\n} __attribute__((packed));\n\nstruct TapeAlert_flag {\n\tstruct pc_header flag;\n\tuint8_t\t\t\t value;\n} __attribute__((packed));\n\n/* Tape Alert Log Page - 0x2E\n * SSC-3 (8.2.3)\n */\nstruct TapeAlert_pg {\n\tstruct log_pg_header pcode_head;\n\n\tstruct TapeAlert_flag TapeAlert[64];\n} __attribute__((packed));\n\n/* Temperature Log Page - 0x0d\n * SPC-3 (7.2.13)\n */\nstruct Temperature_pg {\n\tstruct log_pg_header pcode_head;\n\tstruct pc_header\t header;\n\tuint16_t\t\t\t temperature;\n} __attribute__((packed));\n\n/* Write/Read/Read Reverse\n * Error Counter log page - 0x02, 0x03, 0x04\n * SPC-3 (7.2.4)\n */\nstruct ErrorCounter_pg {\n\tstruct log_pg_header pcode_head;\n\n\tstruct pc_header h_err_correctedWODelay;\n\tuint32_t\t\t err_correctedWODelay;\n\tstruct pc_header h_err_correctedWDelay;\n\tuint32_t\t\t err_correctedWDelay;\n\tstruct pc_header h_totalReTry;\n\tuint32_t\t\t totalReTry;\n\tstruct pc_header h_totalErrorsCorrected;\n\tuint32_t\t\t totalErrorsCorrected;\n\tstruct pc_header h_correctAlgorithm;\n\tuint32_t\t\t correctAlgorithm;\n\tstruct pc_header h_bytesProcessed;\n\tuint64_t\t\t bytesProcessed;\n\tstruct pc_header h_uncorrectedErrors;\n\tuint32_t\t\t uncorrectedErrors;\n\tstruct pc_header h_readErrorsSinceLast;\n\tuint32_t\t\t readErrorsSinceLast;\n\tstruct pc_header h_totalRawReadError;\n\tuint32_t\t\t totalRawReadError;\n\tstruct pc_header h_totalDropoutError;\n\tuint32_t\t\t totalDropoutError;\n\tstruct pc_header h_totalServoTracking;\n\tuint32_t\t\t totalServoTracking;\n} __attribute__((packed));\n\n/* Sequential-Access\n * Device log page - 0x0C\n * SSC-3 (Ch 8.2.2)\n */\nstruct SequentialAccessDevice_pg {\n\tstruct log_pg_header pcode_head;\n\n\tstruct pc_header h_writeDataB4;\n\tuint64_t\t\t writeDataB4Compression; /* Write. Bytes from initiator */\n\tstruct pc_header h_writeData_Af;\n\tuint64_t\t\t writeDataAfCompression; /* Write. Bytes written to media */\n\n\tstruct pc_header h_readData_b4;\n\tuint64_t\t\t readDataB4Compression; /* Read. Bytes read from media */\n\tstruct pc_header h_readData_Af;\n\tuint64_t\t\t readDataAfCompression; /* Read. Bytes to initiator */\n\n\tstruct pc_header h_bop_eod;\n\tuint32_t\t\t capacity_bop_eod; /* Native capacity BOT to EOD */\n\n\tstruct pc_header h_bop_ew;\n\tuint32_t\t\t capacity_bop_ew; /* Native capacity BOP to EW */\n\n\tstruct pc_header h_ew_leop;\n\tuint32_t\t\t capacity_ew_leop; /* Native capacity EW and\n\t\t\t\t\t\t\t\t\t\t* Logical End Of Partition */\n\n\tstruct pc_header h_bop_curr;\n\tuint32_t\t\t capacity_bop_curr; /* Native capacity BOP to curr pos */\n\n\tstruct pc_header h_buffer;\n\tuint32_t\t\t capacity_buffer; /* Native capacity in buffer */\n\n\tstruct pc_header h_cleaning;\n\tuint64_t\t\t TapeAlert;\n\n\tstruct pc_header h_mbytes_processed;\n\tuint32_t\t\t mbytes_processed; /* MB since cleaning */\n\n\tstruct pc_header h_load_cycle;\n\tuint32_t\t\t load_cycle; /* Total number of load cycles over drive lifetime*/\n\n\tstruct pc_header h_clean;\n\tuint32_t\t\t clean_cycle; /* Total number of cleans over drive lifetime */\n\n} __attribute__((packed));\n\n/* Performance Characteristics Log Page - 0x37\n * Sample\n */\nstruct PerformanceCharacteristics_pg {\n\tstruct log_pg_header pcode_head;\n\n\tstruct pc_header h_DriveEfficiency;\n\tuint8_t\t\t\t DriveEfficiency;\n\n} __attribute__((packed));\n\nvoid set_current_state(int s);\nint\t get_tape_load_status();\nvoid set_tape_load_status(int s);\n\nvoid set_lp_11_macc(int flag);\nvoid set_lp11_medium_present(int flag); /* Update LogPage 11 'Medium Present' bit */\nvoid set_lp11_compression(int flag);\t/* Update LogPage 11 compression bit */\nvoid set_lp_11_wp(int flag);\nvoid setTapeAlert(struct TapeAlert_pg *, uint64_t); /* in vtllib.c, never used */\nvoid initTapeAlert(struct TapeAlert_pg *);\nvoid dealloc_all_log_pages(struct lu_phy_attr *lu);\n\nvoid update_VolumeStatistics(struct VolumeStatistics_pg *pg, struct priv_lu_ssc *lu_priv);\nint\t update_TapeAlert(uint64_t flags);\nint\t set_TapeAlert(uint64_t flags);\nvoid update_TapeUsage(struct TapeUsage_pg *b);\nvoid update_TapeCapacity(struct TapeCapacity_pg *pg);\nvoid update_SequentialAccessDevice(struct SequentialAccessDevice_pg *sa);\n\nstruct log_pg_list *lookup_log_pg(struct list_head *l, uint8_t page, uint8_t subpage);\nint\t\t\t\t\talloc_log_page(struct lu_phy_attr *lu,\n\t\t\t\t\t\t\t\t   uint8_t page, uint8_t subpage,\n\t\t\t\t\t\t\t\t   init_pg_fn init_log_pg,\n\t\t\t\t\t\t\t\t   size_t\t  pg_size);\n\nint add_log_write_err_counter(struct lu_phy_attr *lu);\nint add_log_read_err_counter(struct lu_phy_attr *lu);\nint add_log_sequential_access(struct lu_phy_attr *lu);\nint add_log_temperature_page(struct lu_phy_attr *lu);\nint add_log_selftest_results(struct lu_phy_attr *lu);\nint add_log_volume_statistics(struct lu_phy_attr *lu);\nint add_log_tape_alert(struct lu_phy_attr *lu);\nint add_log_tape_usage(struct lu_phy_attr *lu);\nint add_log_tape_capacity(struct lu_phy_attr *lu);\nint add_log_data_compression(struct lu_phy_attr *lu);\nint add_log_device_status(struct lu_phy_attr *lu);\nint add_log_performance_characteristics(struct lu_phy_attr *lu);\n\nextern const char *log_page_desc[0x38];\n\n#endif /* MHVTL_LOG_H */"
  },
  {
    "path": "include/mode.h",
    "content": "/*\n * This handles any SCSI OP 'mode sense / mode select'\n *\n * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n * See comments in vtltape.c for a more complete version release...\n *\n */\n\n#ifndef MODE_H\n#define MODE_H\n\n#include <stdint.h>\n\nstruct lu_phy_attr;\n\nint add_mode_page_rw_err_recovery(struct lu_phy_attr *lu);\nint add_mode_disconnect_reconnect(struct lu_phy_attr *lu);\nint add_mode_control(struct lu_phy_attr *lu);\nint add_mode_control_extension(struct lu_phy_attr *lu);\nint add_mode_control_data_protection(struct lu_phy_attr *lu);\nint add_mode_data_compression(struct lu_phy_attr *lu);\nint add_mode_device_configuration(struct lu_phy_attr *lu);\nint add_mode_device_configuration_extension(struct lu_phy_attr *lu);\nint add_mode_medium_partition(struct lu_phy_attr *lu);\nint add_mode_power_condition(struct lu_phy_attr *lu);\nint add_mode_information_exception(struct lu_phy_attr *lu);\nint add_mode_medium_configuration(struct lu_phy_attr *lu);\nint add_mode_ait_device_configuration(struct lu_phy_attr *lu);\nint add_mode_ult_encr_mode_pages(struct lu_phy_attr *lu);\nint add_mode_vendor_25h_mode_pages(struct lu_phy_attr *lu);\nint add_mode_encryption_mode_attribute(struct lu_phy_attr *lu);\nint add_mode_behavior_configuration(struct lu_phy_attr *lu);\n\nint\t\tadd_mode_device_capabilities(struct lu_phy_attr *lu);\nint\t\tadd_mode_transport_geometry(struct lu_phy_attr *lu);\nint\t\tadd_mode_element_address_assignment(struct lu_phy_attr *lu);\nint\t\tupdate_prog_early_warning(struct lu_phy_attr *lu);\nint\t\tupdate_logical_block_protection(struct lu_phy_attr *lu, uint8_t *buf);\nuint8_t set_lbp(struct scsi_cmd *cmd, uint8_t *buf, int len);\nvoid\tdealloc_all_mode_pages(struct lu_phy_attr *lu);\nint\t\tadd_smc_mode_page_drive_configuration(struct lu_phy_attr *lu);\n\nvoid\tset_mode_compression(struct scsi_cmd *cmd, uint8_t *p);\nvoid\tset_device_configuration(struct scsi_cmd *cmd, uint8_t *p);\nuint8_t set_device_configuration_extension(struct scsi_cmd *cmd, uint8_t *p);\nvoid\tset_medium_partition(struct scsi_cmd *cmd, uint8_t *p);\n\n#endif /* MODE_H */"
  },
  {
    "path": "include/smc.h",
    "content": "#ifndef SMC_H\n#define SMC_H\n\n#include <stdint.h>\n\nstruct scsi_cmd;\nstruct s_info;\n\n/* Element type codes */\n#define ANY\t\t\t\t 0\n#define MEDIUM_TRANSPORT 1\n#define STORAGE_ELEMENT\t 2\n#define MAP_ELEMENT\t\t 3\n#define DATA_TRANSFER\t 4\n\n#define CAP_CLOSED 1\n#define CAP_OPEN   0\n#define OPERATOR   1\n#define ROBOT_ARM  0\n\nstruct smc_personality_template {\n\tchar\t*name;\n\tuint32_t library_has_map : 1;\n\tuint32_t library_has_barcode_reader : 1;\n\tuint32_t library_has_playground : 1;\n\tuint32_t dvcid_serial_only : 1;\n\tuint32_t no_dvcid_flag : 1;\n\n\tuint32_t start_drive;\n\tuint32_t start_picker;\n\tuint32_t start_map;\n\tuint32_t start_storage;\n\tuint32_t dvcid_len;\n\n\tstruct lu_phy_attr *lu;\n};\n\nuint8_t smc_allow_removal(struct scsi_cmd *cmd);\nuint8_t smc_initialize_element_status(struct scsi_cmd *cmd);\nuint8_t smc_initialize_element_status_with_range(struct scsi_cmd *cmd);\nuint8_t smc_log_sense(struct scsi_cmd *cmd);\nuint8_t smc_move_medium(struct scsi_cmd *cmd);\nuint8_t smc_read_element_status(struct scsi_cmd *cmd);\nuint8_t smc_rezero(struct scsi_cmd *cmd);\nuint8_t smc_open_close_import_export_element(struct scsi_cmd *cmd);\n\nint\t get_cart_type(char *barcode);\nvoid update_home_dir(long my_id); /* for the 'get_cart_type()' function only */\n\nint\t slotOccupied(struct s_info *s);\nvoid setImpExpStatus(struct s_info *s, int flg);\nvoid setSlotEmpty(struct s_info *s);\nvoid unload_drive_on_shutdown(struct s_info *src, struct s_info *dest);\n\nvoid init_slot_info(struct lu_phy_attr *lu);\nvoid init_stkl20(struct lu_phy_attr *lu);\nvoid init_stklxx(struct lu_phy_attr *lu);\nvoid init_stkslxx(struct lu_phy_attr *lu);\nvoid init_default_smc(struct lu_phy_attr *lu);\nvoid init_scalar_smc(struct lu_phy_attr *lu);\nvoid init_spectra_logic_smc(struct lu_phy_attr *lu);\nvoid init_spectra_215_smc(struct lu_phy_attr *lu);\nvoid init_spectra_gator_smc(struct lu_phy_attr *lu);\nvoid init_ibmts3100(struct lu_phy_attr *lu);\nvoid init_ibm3584(struct lu_phy_attr *lu);\nvoid init_hp_eml_smc(struct lu_phy_attr *lu);\nvoid init_hp_msl_smc(struct lu_phy_attr *lu);\nvoid init_overland_smc(struct lu_phy_attr *lu);\nvoid smc_personality_module_register(struct smc_personality_template *pm);\nvoid setAccessStatus(struct s_info *s, int flg);\n\n#endif /* SMC_H */"
  },
  {
    "path": "include/spc.h",
    "content": "\n#ifndef SPC_H\n#define SPC_H\n\n#include <stdint.h>\n\nstruct scsi_cmd;\n\n/* Variables for simple, single initiator, SCSI Reservation system */\n\nextern uint64_t SPR_Reservation_Key;\nextern uint32_t SPR_Reservation_Generation;\nextern uint8_t\tSPR_Reservation_Type;\n\nuint8_t resp_spc_pro(uint8_t *cdb, struct mhvtl_ds *dbuf_p);\nuint8_t resp_spc_pri(uint8_t *cdb, struct mhvtl_ds *dbuf_p);\n\nuint8_t spc_illegal_op(struct scsi_cmd *cmd);\nuint8_t spc_inquiry(struct scsi_cmd *cmd);\nuint8_t spc_log_select(struct scsi_cmd *cmd);\nuint8_t spc_log_sense(struct scsi_cmd *cmd);\nuint8_t spc_mode_select(struct scsi_cmd *cmd);\nuint8_t spc_mode_sense(struct scsi_cmd *cmd);\nuint8_t spc_recv_diagnostics(struct scsi_cmd *cmd);\nuint8_t spc_release(struct scsi_cmd *cmd);\nuint8_t spc_request_sense(struct scsi_cmd *cmd);\nuint8_t spc_reserve(struct scsi_cmd *cmd);\nuint8_t spc_send_diagnostics(struct scsi_cmd *cmd);\nuint8_t spc_tur(struct scsi_cmd *cmd);\nuint8_t spc_read_buffer(struct scsi_cmd *cmd);\n\n#endif /* SPC_H */\n"
  },
  {
    "path": "include/ssc.h",
    "content": "#ifndef SSC_H\n#define SSC_H\n\n#include <signal.h>\n#include <stdint.h>\n#include <sys/types.h>\n#include \"mhvtl_list.h\"\n#include \"q.h\"\n\nstruct mhvtl_ds;\nstruct scsi_cmd;\n\n#define ENCR_C 1 /* Device supports Encryption */\n#define ENCR_E 4 /* Encryption is enabled */\n\n#define ENCR_IN_SUPPORT_PAGES\t  0\n#define ENCR_OUT_SUPPORT_PAGES\t  1\n#define ENCR_CAPABILITIES\t\t  0x10\n#define ENCR_KEY_FORMATS\t\t  0x11\n#define ENCR_KEY_MGT_CAPABILITIES 0x12\n#define ENCR_DATA_ENCR_STATUS\t  0x20\n#define ENCR_NEXT_BLK_ENCR_STATUS 0x21\n\n#define ENCR_SET_DATA_ENCRYPTION 0x10\n\n#define EARLY_WARNING_SZ\t  (1024 * 1024 * 2) /* 2M EW size */\n#define PROG_EARLY_WARNING_SZ (1024 * 1024 * 3) /* 3M Prog EW size */\n\n#define MAX_DELAY_LOAD\t   20\n#define MAX_DELAY_UNLOAD   20\n#define MAX_DELAY_THREAD   20\n#define MAX_DELAY_POSITION 20\n#define MAX_DELAY_REWIND   30\n\n#define LBP_RSCRC  1\n#define LBP_CRC32C 2\n\nstruct name_to_media_info {\n\tchar *name;\n\tint\t  media_type;\n\tint\t  mode_media_type;\n\tint\t  media_density;\n};\n\nstruct ssc_personality_template {\n\tchar *name;\n\tint\t  drive_type;\n\n\tuint32_t drive_supports_append_only_mode : 1;\n\tuint32_t drive_supports_early_warning : 1;\n\tuint32_t drive_supports_prog_early_warning : 1;\n\tuint32_t drive_supports_WORM : 1; /* Write Once Read Many */\n\tuint32_t drive_supports_SPR : 1;  /* SCSI Persistent Reservation */\n\tuint32_t drive_supports_SP : 1;\t  /* Security Protocol */\n\tuint32_t drive_supports_LBP : 2;  /* 0 - No, 1- Reed-Solomon only, 2 - RSCRC and CRC32C */\n\tuint32_t drive_ANSI_VERSION : 5;\n\n\tstruct density_info\t\t  *native_drive_density;\n\tstruct name_to_media_info *media_handling;\n\n\tstruct lu_phy_attr *lu;\n\n\t/* Read check if this block contains valid encryption keys */\n\tuint8_t (*valid_encryption_blk)(struct scsi_cmd *cmd);\n\n\t/* Write check if the media supports encryption */\n\tuint8_t (*valid_encryption_media)(struct scsi_cmd *cmd);\n\n\t/* SPIN page 20 -> Encryption Capabilities */\n\tint (*encryption_capabilities)(struct scsi_cmd *cmd);\n\n\t/* SPOUT -> Validation KAD info is correct */\n\tint (*kad_validation)(int encrypt_mode, int akad, int ukad);\n\n\t/* Update mode page for encryption capabilities */\n\tuint8_t (*update_encryption_mode)(struct list_head *m, void *p, int mode);\n\n\t/* Media access, check if any write restrictions */\n\tuint8_t (*check_restrictions)(struct scsi_cmd *cmd);\n\t/* enable/disable compression */\n\tuint8_t (*clear_compression)(struct list_head *l);\n\tuint8_t (*set_compression)(struct list_head *l, int level);\n\t/* enable/disable WORM */\n\tuint8_t (*clear_WORM)(struct list_head *l);\n\tuint8_t (*set_WORM)(struct list_head *l);\n\n\t/* Cleaning media mount calls into here */\n\tuint8_t (*cleaning_media)(void *priv);\n\n\t/* Called on load/unload - where var load = 0 on unload, 1 on load */\n\tuint8_t (*media_load)(struct lu_phy_attr *lu, int load);\n};\n\nenum delay_list {\n\tDELAY_UNDEFINED, /* Must be first */\n\tDELAY_LOAD,\n\tDELAY_THREAD,\n\tDELAY_POSITION,\n\tDELAY_REWIND,\n\tDELAY_UNLOAD,\n\tDELAY_LAST_ITEM /* Flag end of list */\n};\n\n/* Load capabilities - density_status bits */\n#define LOAD_INVALID  1\n#define LOAD_RW\t\t  2\n#define LOAD_RO\t\t  4\n#define LOAD_WORM\t  8\n#define LOAD_ENCRYPT  0x10\n#define LOAD_FAIL\t  0x20\n#define LOAD_CLEANING 0x40\n#define LOAD_NOACCESS 0x80 /* Loads but can not read/write */\n\n#define CLEAN_MOUNT_STAGE1 1\n#define CLEAN_MOUNT_STAGE2 2\n#define CLEAN_MOUNT_STAGE3 3\n\nstruct media_details {\n\tstruct list_head siblings;\n\tunsigned int\t media_type;\t  /* Media Type */\n\tunsigned int\t load_capability; /* RO, RW, invalid or fail mount */\n};\n\nstruct priv_lu_ssc {\n\n\tint bufsize;\n\tint load_status; /* Tape load state: Unloaded, loading, loaded */\n\n\tuint32_t inLibrary : 1;\t\t\t  /* This tape drive is 'assigned' as part of a library */\n\tuint32_t I_am_SPC_2_Reserved : 1; /* Variables for simple, single initiator, SCSI Reservation system */\n\tuint32_t append_only_mode : 1;\n\tuint32_t MediaWriteProtect : 1;\n\tuint32_t LBP_method : 2; /* Logical Block Protection method 0: off, 1: Reed-Solomon CRC, 2: CRC32C */\n\tuint32_t LBP_W : 1;\t\t /* Logical Block Protection during writes */\n\tuint32_t LBP_R : 1;\t\t /* Logical Block Protection during reads */\n\n\tchar *barcode; /* Barcode of tape in the drive - NULL if nothing is in mouth of drive */\n\n\tuint8_t sam_status;\n\n\tuint8_t allow_overwrite;\n\n\t/* Default value read from config file */\n\tuint8_t configCompressionFactor;\n\tuint8_t configCompressionEnabled;\n\n\tuint8_t compressionType; /* lzo or zlib compression */\n\n\tloff_t capacity_unit;\n\tloff_t early_warning_sz;\n\tloff_t prog_early_warning_sz;\n\n\tloff_t early_warning_position;\n\tloff_t prog_early_warning_position;\n\n\t/* Pointer into Device config mode page */\n\tuint8_t *compressionFactor;\n\n\tint\t\t   *OK_2_write;\n\tstruct MAM *mamp;\n\n\tuint64_t allow_overwrite_block; /* Used by 'allow overwrite' op code */\n\tuint64_t max_capacity;\t\t\t/* save MAM.max_capacity here for quick access */\n\tuint64_t bytesRead_M;\t\t\t/* Bytes read from media */\n\tuint64_t bytesRead_I;\t\t\t/* Bytes read and sent to initiator */\n\tuint64_t bytesWritten_M;\t\t/* Bytes written to media (compressed) */\n\tuint64_t bytesWritten_I;\t\t/* Bytes recevied from initiator */\n\n\t/* Allow to insert delays into op codes */\n\tint delay_load;\n\tint delay_unload;\n\tint delay_thread;\n\tint delay_position;\n\tint delay_rewind;\n\n\tstruct blk_header *c_pos;\n\n\tuint32_t\t\t   KEY_INSTANCE_COUNTER;\n\tuint32_t\t\t   DECRYPT_MODE;\n\tuint32_t\t\t   ENCRYPT_MODE;\n\tstruct encryption *app_encr_info;\n\n\tstruct list_head supported_media_list;\n\n\tunsigned char mediaSerialNo[34];\n\n\t/* cleaning_media_state -  Only used for cleaning media status..\n\t\tUsing signal / alarm which will increment this value thru:\n\t\t\t0/NULL (unmonted)\n\t\t\t1 (mounted) -> sense: \"Cleaning cartridge installed\"\n\t\t\t2 (mounted) -> sense: \"Logical unit not ready\"\n\t\t\t3 (mounted) -> sense: \"Cause not reportable\"\n\t */\n\tvolatile sig_atomic_t *cleaning_media_state;\n\n\tchar\t\t  *state_msg; /* Custom State message */\n\tstruct q_entry r_entry;\t  /* IPC message queue */\n\n\tstruct ssc_personality_template *pm; /* Personality Module */\n};\n\n/* cdb[1] bits for verify_6 op code */\nstruct verify_6_bits {\n\tuint8_t FIXED : 1;\t/* FIXED block */\n\tuint8_t BYTCMP : 1; /* Byte Compare */\n\tuint8_t IMMED : 1;\t/* Immediate */\n\tuint8_t VBF : 1;\t/* Verify by Filemarks */\n\tuint8_t VLBPM : 1;\t/* Verify Logical Block Protection Method */\n\tuint8_t VTE : 1;\t/* Verify To End-of-data */\n};\n\n#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\n\nstruct read_position_information_short {\n\tuint8_t BPEW : 1;  /* Beyond Early Warning - 0: The LOCU is set to 1, the PEWS field in MP 0x10:01 is set to 0, 1: logical object location is in a PEWZ or on EOP side of EW */\n\tuint8_t PERR : 1;  /* Position Error - 0: An overflow has not occurred, 1: An overflow has occurred - should use the LONG FORM (06h) instead */\n\tuint8_t LOLU : 1;  /* Logical object location is unknown - 0: Block position is exact, 1: Block position is estimate */\n\tuint8_t resvd : 1; /* Reserved */\n\tuint8_t BYCU : 1;  /* Byte Count Unknown - 0: Byte count is exact, 1: Byte count is an estimate */\n\tuint8_t LOCU : 1;  /* Logical Object Count Unknown - 0: Block count is exact, 1: Block count is an estimate */\n\tuint8_t EOP : 1;   /* End of Partition 0: Not between early warning and end of partition, 1: Positioned between early warning and end of partition */\n\tuint8_t BOP : 1;   /* Beginning of Partition 0: current logical position is not at beginning, 1: At beginning of partition */\n} __attribute__((packed));\n\nstruct read_position_information_long {\n\tuint8_t BPEW : 1;\t/* Beyond Early Warning - 0: The LOCU is set to 1, the PEWS field in MP 0x10:01 is set to 0, 1: logical object location is in a PEWZ or on EOP side of EW */\n\tuint8_t rsvd_1 : 1; /* Reserved 1 bit */\n\tuint8_t LONU : 1;\t/* Logical Object Number Unknown - 0: Logical Object Number and Partition number contains exact info, 1: LON is estimate */\n\tuint8_t MPU : 1;\t/* Mark Position Unknown - 0: Filemark count is exact, 1: Filemark count is an estimate */\n\tuint8_t rsvd_0 : 2; /* Reserved 2 bits */\n\tuint8_t EOP : 1;\t/* End of Partition 0: Not between early warning and end of partition, 1: Positioned between early warning and end of partition */\n\tuint8_t BOP : 1;\t/* Beginning of Partition 0: current logical position is not at beginning, 1: At beginning of partition */\n} __attribute__((packed));\n\nstruct read_position_information_extended {\n\tuint8_t BPEW : 1;  /* Beyond Early Warning - 0: The LOCU is set to 1, the PEWS field in MP 0x10:01 is set to 0, 1: logical object location is in a PEWZ or on EOP side of EW */\n\tuint8_t PERR : 1;  /* Position Error - 0: An overflow has not occurred, 1: An overflow has occurred - should use the LONG FORM (06h) instead */\n\tuint8_t LOLU : 1;  /* Logical object location is unknown - 0: Block position is exact, 1: Block position is estimate */\n\tuint8_t resvd : 1; /* Reserved */\n\tuint8_t BYCU : 1;  /* Byte Count Unknown - 0: Byte count is exact, 1: Byte count is an estimate */\n\tuint8_t LOCU : 1;  /* Logical Object Count Unknown - 0: Block count is exact, 1: Block count is an estimate */\n\tuint8_t EOP : 1;   /* End of Partition 0: Not between early warning and end of partition, 1: Positioned between early warning and end of partition */\n\tuint8_t BOP : 1;   /* Beginning of Partition 0: current logical position is not at beginning, 1: At beginning of partition */\n} __attribute__((packed));\n\n#else\n\nstruct read_position_information_short {\n\tuint8_t BOP : 1;   /* Beginning of Partition 0: current logical position is not at beginning, 1: At beginning of partition */\n\tuint8_t EOP : 1;   /* End of Partition 0: Not between early warning and end of partition, 1: Positioned between early warning and end of partition */\n\tuint8_t LOCU : 1;  /* Logical Object Count Unknown - 0: Block count is exact, 1: Block count is an estimate */\n\tuint8_t BYCU : 1;  /* Byte Count Unknown - 0: Byte count is exact, 1: Byte count is an estimate */\n\tuint8_t resvd : 1; /* Reserved */\n\tuint8_t LOLU : 1;  /* Logical object location is unknown - 0: Block position is exact, 1: Block position is estimate */\n\tuint8_t PERR : 1;  /* Position Error - 0: An overflow has not occurred, 1: An overflow has occurred - should use the LONG FORM (06h) instead */\n\tuint8_t BPEW : 1;  /* Beyond Early Warning - 0: The LOCU is set to 1, the PEWS field in MP 0x10:01 is set to 0, 1: logical object location is in a PEWZ or on EOP side of EW */\n} __attribute__((packed));\n\nstruct read_position_information_long {\n\tuint8_t BOP : 1;\t/* Beginning of Partition 0: current logical position is not at beginning, 1: At beginning of partition */\n\tuint8_t EOP : 1;\t/* End of Partition 0: Not between early warning and end of partition, 1: Positioned between early warning and end of partition */\n\tuint8_t rsvd_0 : 2; /* Reserved 2 bits */\n\tuint8_t MPU : 1;\t/* Mark Position Unknown - 0: Filemark count is exact, 1: Filemark count is an estimate */\n\tuint8_t LONU : 1;\t/* Logical Object Number Unknown - 0: Logical Object Number and Partition number contains exact info, 1: LON is estimate */\n\tuint8_t rsvd_1 : 1; /* Reserved 1 bit */\n\tuint8_t BPEW : 1;\t/* Beyond Early Warning - 0: The LOCU is set to 1, the PEWS field in MP 0x10:01 is set to 0, 1: logical object location is in a PEWZ or on EOP side of EW */\n} __attribute__((packed));\n\nstruct read_position_information_extended {\n\tuint8_t BOP : 1;   /* Beginning of Partition 0: current logical position is not at beginning, 1: At beginning of partition */\n\tuint8_t EOP : 1;   /* End of Partition 0: Not between early warning and end of partition, 1: Positioned between early warning and end of partition */\n\tuint8_t LOCU : 1;  /* Logical Object Count Unknown - 0: Block count is exact, 1: Block count is an estimate */\n\tuint8_t BYCU : 1;  /* Byte Count Unknown - 0: Byte count is exact, 1: Byte count is an estimate */\n\tuint8_t resvd : 1; /* Reserved */\n\tuint8_t LOLU : 1;  /* Logical object location is unknown - 0: Block position is exact, 1: Block position is estimate */\n\tuint8_t PERR : 1;  /* Position Error - 0: An overflow has not occurred, 1: An overflow has occurred - should use the LONG FORM (06h) instead */\n\tuint8_t BPEW : 1;  /* Beyond Early Warning - 0: The LOCU is set to 1, the PEWS field in MP 0x10:01 is set to 0, 1: logical object location is in a PEWZ or on EOP side of EW */\n} __attribute__((packed));\n\n#endif /* Byte order */\n\nvoid ssc_personality_module_register(struct ssc_personality_template *pm);\n\nint readBlock(uint8_t *buf, uint32_t request_sz, int sili, int lbp, uint8_t *sam_stat);\nint writeBlock(struct scsi_cmd *cmd, uint32_t request_sz);\n\nuint8_t ssc_a3_service_action(struct scsi_cmd *cmd);\nuint8_t ssc_a4_service_action(struct scsi_cmd *cmd);\nuint8_t ssc_allow_overwrite(struct scsi_cmd *cmd);\nuint8_t ssc_allow_prevent_removal(struct scsi_cmd *cmd);\nuint8_t ssc_erase(struct scsi_cmd *cmd);\nuint8_t ssc_format_medium(struct scsi_cmd *cmd);\nuint8_t ssc_load_display(struct scsi_cmd *cmd);\nuint8_t ssc_log_select(struct scsi_cmd *cmd);\nuint8_t ssc_log_sense(struct scsi_cmd *cmd);\nuint8_t ssc_mode_select(struct scsi_cmd *cmd);\nuint8_t ssc_pr_in(struct scsi_cmd *cmd);\nuint8_t ssc_pr_out(struct scsi_cmd *cmd);\nuint8_t ssc_read_6(struct scsi_cmd *cmd);\nuint8_t ssc_read_attributes(struct scsi_cmd *cmd);\nuint8_t ssc_read_block_limits(struct scsi_cmd *cmd);\nuint8_t ssc_read_display(struct scsi_cmd *cmd);\nuint8_t ssc_read_media_sn(struct scsi_cmd *cmd);\nuint8_t ssc_read_position(struct scsi_cmd *cmd);\nuint8_t ssc_release(struct scsi_cmd *cmd);\nuint8_t ssc_report_density_support(struct scsi_cmd *cmd);\nuint8_t ssc_reserve(struct scsi_cmd *cmd);\nuint8_t ssc_rewind(struct scsi_cmd *cmd);\nuint8_t ssc_locate(struct scsi_cmd *cmd);\nuint8_t ssc_send_diagnostics(struct scsi_cmd *cmd);\nuint8_t ssc_recv_diagnostics(struct scsi_cmd *cmd);\nuint8_t ssc_space_6(struct scsi_cmd *cmd);\nuint8_t ssc_space_16(struct scsi_cmd *cmd);\nuint8_t ssc_spin(struct scsi_cmd *cmd);\nuint8_t ssc_spout(struct scsi_cmd *cmd);\nuint8_t ssc_load_unload(struct scsi_cmd *cmd);\nuint8_t ssc_tur(struct scsi_cmd *cmd);\nuint8_t ssc_verify_6(struct scsi_cmd *cmd);\nuint8_t ssc_write_6(struct scsi_cmd *cmd);\nuint8_t ssc_write_attributes(struct scsi_cmd *cmd);\nuint8_t ssc_write_filemarks(struct scsi_cmd *cmd);\nuint8_t ssc_set_capacity(struct scsi_cmd *cmd);\n\n/* Initialisation of personality modules */\nvoid init_ait1_ssc(struct lu_phy_attr *lu);\nvoid init_ait2_ssc(struct lu_phy_attr *lu);\nvoid init_ait3_ssc(struct lu_phy_attr *lu);\nvoid init_ait4_ssc(struct lu_phy_attr *lu);\nvoid init_default_ssc(struct lu_phy_attr *lu);\nvoid init_t10kA_ssc(struct lu_phy_attr *lu);\nvoid init_t10kB_ssc(struct lu_phy_attr *lu);\nvoid init_t10kC_ssc(struct lu_phy_attr *lu);\nvoid init_9840A_ssc(struct lu_phy_attr *lu);\nvoid init_9840B_ssc(struct lu_phy_attr *lu);\nvoid init_9840C_ssc(struct lu_phy_attr *lu);\nvoid init_9840D_ssc(struct lu_phy_attr *lu);\nvoid init_9940A_ssc(struct lu_phy_attr *lu);\nvoid init_9940B_ssc(struct lu_phy_attr *lu);\nvoid init_ult3580_td1(struct lu_phy_attr *lu);\nvoid init_ult3580_td2(struct lu_phy_attr *lu);\nvoid init_ult3580_td3(struct lu_phy_attr *lu);\nvoid init_ult3580_td4(struct lu_phy_attr *lu);\nvoid init_ult3580_td5(struct lu_phy_attr *lu);\nvoid init_ult3580_td6(struct lu_phy_attr *lu);\nvoid init_ult3580_td7(struct lu_phy_attr *lu);\nvoid init_ult3580_td8(struct lu_phy_attr *lu);\nvoid init_ult3580_td9(struct lu_phy_attr *lu);\nvoid init_hp_ult_1(struct lu_phy_attr *lu);\nvoid init_hp_ult_2(struct lu_phy_attr *lu);\nvoid init_hp_ult_3(struct lu_phy_attr *lu);\nvoid init_hp_ult_4(struct lu_phy_attr *lu);\nvoid init_hp_ult_5(struct lu_phy_attr *lu);\nvoid init_hp_ult_6(struct lu_phy_attr *lu);\nvoid init_hp_ult_7(struct lu_phy_attr *lu);\nvoid init_hp_ult_8(struct lu_phy_attr *lu);\nvoid init_3592_j1a(struct lu_phy_attr *lu);\nvoid init_3592_E05(struct lu_phy_attr *lu);\nvoid init_3592_E06(struct lu_phy_attr *lu);\nvoid init_3592_E07(struct lu_phy_attr *lu);\nvoid init_dlt7000_ssc(struct lu_phy_attr *lu);\nvoid init_dlt8000_ssc(struct lu_phy_attr *lu);\nvoid init_sdlt320_ssc(struct lu_phy_attr *lu);\nvoid init_sdlt600_ssc(struct lu_phy_attr *lu);\n\nvoid register_ops(struct lu_phy_attr *lu, int op, void *f, void *g, void *h);\n\nuint8_t valid_encryption_blk(struct scsi_cmd *cmd);\nuint8_t check_restrictions(struct scsi_cmd *cmd);\nvoid\tinit_default_ssc_mode_pages(struct list_head *l);\nuint8_t resp_spin(struct scsi_cmd *cmd);\nuint8_t resp_spout(struct scsi_cmd *cmd);\nint\t\tresp_write_attribute(struct scsi_cmd *cmd);\nint\t\tresp_read_attribute(struct scsi_cmd *cmd);\nint\t\tresp_report_density(struct priv_lu_ssc *lu_ssc, uint8_t media,\n\t\t\t\t\t\t\tstruct mhvtl_ds *dbuf_p);\nvoid\tresp_space(int64_t count, int code, uint8_t *sam_stat);\nint\t\tloadTape(char *barcode, uint8_t *sam_stat);\nvoid\tunloadTape(int update_library, uint8_t *sam_stat);\nvoid\tdelay_opcode(int what, int value);\nvoid\tset_timestamp(uint8_t source, uint64_t ts);\n\nvoid memset_ssc_buf(struct scsi_cmd *cmd, uint64_t alloc_len);\n\n#endif /* SSC_H */"
  },
  {
    "path": "include/utils/be_byteshift.h",
    "content": "#ifndef _LINUX_UNALIGNED_BE_BYTESHIFT_H\n#define _LINUX_UNALIGNED_BE_BYTESHIFT_H\n\n#include <stdint.h>\n\nstatic inline uint16_t __get_unaligned_be16(const uint8_t *p) {\n\treturn p[0] << 8 | p[1];\n}\n\nstatic inline uint32_t __get_unaligned_be32(const uint8_t *p) {\n\treturn p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];\n}\n\nstatic inline uint64_t __get_unaligned_be64(const uint8_t *p) {\n\treturn (uint64_t)__get_unaligned_be32(p) << 32 |\n\t\t   __get_unaligned_be32(p + 4);\n}\n\nstatic inline void __put_unaligned_be16(uint16_t val, uint8_t *p) {\n\t*p++ = val >> 8;\n\t*p++ = val;\n}\n\nstatic inline void __put_unaligned_be32(uint32_t val, uint8_t *p) {\n\t__put_unaligned_be16(val >> 16, p);\n\t__put_unaligned_be16(val, p + 2);\n}\n\nstatic inline void __put_unaligned_be64(uint64_t val, uint8_t *p) {\n\t__put_unaligned_be32(val >> 32, p);\n\t__put_unaligned_be32(val, p + 4);\n}\n\nstatic inline uint16_t get_unaligned_be16(const void *p) {\n\treturn __get_unaligned_be16((const uint8_t *)p);\n}\n\nstatic inline uint32_t get_unaligned_be24(const uint8_t *p) {\n\treturn p[0] << 16 | p[1] << 8 | p[2];\n}\n\nstatic inline uint32_t get_unaligned_be32(const void *p) {\n\treturn __get_unaligned_be32((const uint8_t *)p);\n}\n\nstatic inline uint64_t get_unaligned_be48(const void *p) {\n\treturn (uint64_t)__get_unaligned_be32(p) << 32 |\n\t\t   __get_unaligned_be16(p + 4);\n}\n\nstatic inline uint64_t get_unaligned_be64(const void *p) {\n\treturn __get_unaligned_be64((const uint8_t *)p);\n}\n\nstatic inline void put_unaligned_be16(uint16_t val, void *p) {\n\t__put_unaligned_be16(val, (uint8_t *)p);\n}\n\nstatic inline void put_unaligned_be24(uint32_t val, void *p) {\n\t((uint8_t *)p)[0] = (val >> 16) & 0xff;\n\t((uint8_t *)p)[1] = (val >> 8) & 0xff;\n\t((uint8_t *)p)[2] = val & 0xff;\n}\n\nstatic inline void put_unaligned_be32(uint32_t val, void *p) {\n\t__put_unaligned_be32(val, (uint8_t *)p);\n}\n\nstatic inline void put_unaligned_be48(uint64_t val, void *p) {\n\t__put_unaligned_be32(val >> 32, (uint8_t *)p);\n\t__put_unaligned_be16(val, p + 4);\n}\n\nstatic inline void put_unaligned_be64(uint64_t val, void *p) {\n\t__put_unaligned_be64(val, (uint8_t *)p);\n}\n\n#endif /* _LINUX_UNALIGNED_BE_BYTESHIFT_H */\n"
  },
  {
    "path": "include/utils/lzoconf.h",
    "content": "/* lzoconf.h -- configuration of the LZO data compression library\n\n   This file is part of the LZO real-time data compression library.\n\n   Copyright (C) 1996-2015 Markus Franz Xaver Johannes Oberhumer\n   All Rights Reserved.\n\n   The LZO library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU General Public License as\n   published by the Free Software Foundation; either version 2 of\n   the License, or (at your option) any later version.\n\n   The LZO library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n\n   You should have received a copy of the GNU General Public License\n   along with the LZO library; see the file COPYING.\n   If not, write to the Free Software Foundation, Inc.,\n   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n\n   Markus F.X.J. Oberhumer\n   <markus@oberhumer.com>\n   http://www.oberhumer.com/opensource/lzo/\n */\n\n#ifndef __LZOCONF_H_INCLUDED\n#define __LZOCONF_H_INCLUDED 1\n\n#define LZO_VERSION\t\t   0x2090\n#define LZO_VERSION_STRING \"2.09\"\n#define LZO_VERSION_DATE   \"Feb 04 2015\"\n\n/* internal Autoconf configuration file - only used when building LZO */\n#if defined(LZO_HAVE_CONFIG_H)\n#include <config.h>\n#endif\n#include <limits.h>\n#include <stddef.h>\n\n/***********************************************************************\n// LZO requires a conforming <limits.h>\n************************************************************************/\n\n#if !defined(CHAR_BIT) || (CHAR_BIT != 8)\n#error \"invalid CHAR_BIT\"\n#endif\n#if !defined(UCHAR_MAX) || !defined(USHRT_MAX) || !defined(UINT_MAX) || !defined(ULONG_MAX)\n#error \"check your compiler installation\"\n#endif\n#if (USHRT_MAX < 1) || (UINT_MAX < 1) || (ULONG_MAX < 1)\n#error \"your limits.h macros are broken\"\n#endif\n\n/* get OS and architecture defines */\n#ifndef __LZODEFS_H_INCLUDED\n#include \"lzodefs.h\"\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/***********************************************************************\n// some core defines\n************************************************************************/\n\n/* memory checkers */\n#if !defined(__LZO_CHECKER)\n#if defined(__BOUNDS_CHECKING_ON)\n#define __LZO_CHECKER 1\n#elif defined(__CHECKER__)\n#define __LZO_CHECKER 1\n#elif defined(__INSURE__)\n#define __LZO_CHECKER 1\n#elif defined(__PURIFY__)\n#define __LZO_CHECKER 1\n#endif\n#endif\n\n/***********************************************************************\n// integral and pointer types\n************************************************************************/\n\n/* lzo_uint must match size_t */\n#if !defined(LZO_UINT_MAX)\n#if (LZO_ABI_LLP64)\n#if (LZO_OS_WIN64)\ntypedef unsigned __int64 lzo_uint;\ntypedef __int64\t\t\t lzo_int;\n#define LZO_TYPEOF_LZO_INT LZO_TYPEOF___INT64\n#else\ntypedef lzo_ullong_t lzo_uint;\ntypedef lzo_llong_t\t lzo_int;\n#define LZO_TYPEOF_LZO_INT LZO_TYPEOF_LONG_LONG\n#endif\n#define LZO_SIZEOF_LZO_INT 8\n#define LZO_UINT_MAX\t   0xffffffffffffffffull\n#define LZO_INT_MAX\t\t   9223372036854775807LL\n#define LZO_INT_MIN\t\t   (-1LL - LZO_INT_MAX)\n#elif (LZO_ABI_IP32L64) /* MIPS R5900 */\ntypedef unsigned int lzo_uint;\ntypedef int\t\t\t lzo_int;\n#define LZO_SIZEOF_LZO_INT LZO_SIZEOF_INT\n#define LZO_TYPEOF_LZO_INT LZO_TYPEOF_INT\n#define LZO_UINT_MAX\t   UINT_MAX\n#define LZO_INT_MAX\t\t   INT_MAX\n#define LZO_INT_MIN\t\t   INT_MIN\n#elif (ULONG_MAX >= LZO_0xffffffffL)\ntypedef unsigned long lzo_uint;\ntypedef long\t\t  lzo_int;\n#define LZO_SIZEOF_LZO_INT LZO_SIZEOF_LONG\n#define LZO_TYPEOF_LZO_INT LZO_TYPEOF_LONG\n#define LZO_UINT_MAX\t   ULONG_MAX\n#define LZO_INT_MAX\t\t   LONG_MAX\n#define LZO_INT_MIN\t\t   LONG_MIN\n#else\n#error \"lzo_uint\"\n#endif\n#endif\n\n/* The larger type of lzo_uint and lzo_uint32_t. */\n#if (LZO_SIZEOF_LZO_INT >= 4)\n#define lzo_xint lzo_uint\n#else\n#define lzo_xint lzo_uint32_t\n#endif\n\ntypedef int lzo_bool;\n\n/* sanity checks */\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int) == LZO_SIZEOF_LZO_INT)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == LZO_SIZEOF_LZO_INT)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_xint) >= sizeof(lzo_uint))\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_xint) >= sizeof(lzo_uint32_t))\n\n#ifndef __LZO_MMODEL\n#define __LZO_MMODEL /*empty*/\n#endif\n\n/* no typedef here because of const-pointer issues */\n#define lzo_bytep\tunsigned char __LZO_MMODEL *\n#define lzo_charp\tchar __LZO_MMODEL *\n#define lzo_voidp\tvoid __LZO_MMODEL *\n#define lzo_shortp\tshort __LZO_MMODEL *\n#define lzo_ushortp unsigned short __LZO_MMODEL *\n#define lzo_intp\tlzo_int __LZO_MMODEL *\n#define lzo_uintp\tlzo_uint __LZO_MMODEL *\n#define lzo_xintp\tlzo_xint __LZO_MMODEL *\n#define lzo_voidpp\tlzo_voidp __LZO_MMODEL *\n#define lzo_bytepp\tlzo_bytep __LZO_MMODEL *\n\n#define lzo_int8_tp\t  lzo_int8_t __LZO_MMODEL *\n#define lzo_uint8_tp  lzo_uint8_t __LZO_MMODEL *\n#define lzo_int16_tp  lzo_int16_t __LZO_MMODEL *\n#define lzo_uint16_tp lzo_uint16_t __LZO_MMODEL *\n#define lzo_int32_tp  lzo_int32_t __LZO_MMODEL *\n#define lzo_uint32_tp lzo_uint32_t __LZO_MMODEL *\n#if defined(lzo_int64_t)\n#define lzo_int64_tp  lzo_int64_t __LZO_MMODEL *\n#define lzo_uint64_tp lzo_uint64_t __LZO_MMODEL *\n#endif\n\n/* Older LZO versions used to support ancient systems and memory models\n * such as 16-bit MSDOS with __huge pointers or Cray PVP, but these\n * obsolete configurations are not supported any longer.\n */\n#if defined(__LZO_MMODEL_HUGE)\n#error \"__LZO_MMODEL_HUGE memory model is unsupported\"\n#endif\n#if (LZO_MM_PVP)\n#error \"LZO_MM_PVP memory model is unsupported\"\n#endif\n#if (LZO_SIZEOF_INT < 4)\n#error \"LZO_SIZEOF_INT < 4 is unsupported\"\n#endif\n#if (__LZO_UINTPTR_T_IS_POINTER)\n#error \"__LZO_UINTPTR_T_IS_POINTER is unsupported\"\n#endif\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(int) >= 4)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) >= 4)\n/* Strange configurations where sizeof(lzo_uint) != sizeof(size_t) should\n * work but have not received much testing lately, so be strict here.\n */\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == sizeof(size_t))\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == sizeof(ptrdiff_t))\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == sizeof(lzo_uintptr_t))\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(void *) == sizeof(lzo_uintptr_t))\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(char *) == sizeof(lzo_uintptr_t))\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long *) == sizeof(lzo_uintptr_t))\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(void *) == sizeof(lzo_voidp))\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(char *) == sizeof(lzo_bytep))\n\n/***********************************************************************\n// function types\n************************************************************************/\n\n/* name mangling */\n#if !defined(__LZO_EXTERN_C)\n#ifdef __cplusplus\n#define __LZO_EXTERN_C extern \"C\"\n#else\n#define __LZO_EXTERN_C extern\n#endif\n#endif\n\n/* calling convention */\n#if !defined(__LZO_CDECL)\n#define __LZO_CDECL __lzo_cdecl\n#endif\n\n/* DLL export information */\n#if !defined(__LZO_EXPORT1)\n#define __LZO_EXPORT1 /*empty*/\n#endif\n#if !defined(__LZO_EXPORT2)\n#define __LZO_EXPORT2 /*empty*/\n#endif\n\n/* __cdecl calling convention for public C and assembly functions */\n#if !defined(LZO_PUBLIC)\n#define LZO_PUBLIC(r) __LZO_EXPORT1 r __LZO_EXPORT2 __LZO_CDECL\n#endif\n#if !defined(LZO_EXTERN)\n#define LZO_EXTERN(r) __LZO_EXTERN_C LZO_PUBLIC(r)\n#endif\n#if !defined(LZO_PRIVATE)\n#define LZO_PRIVATE(r) static r __LZO_CDECL\n#endif\n\n/* function types */\ntypedef int(__LZO_CDECL *lzo_compress_t)(const lzo_bytep src, lzo_uint src_len,\n\t\t\t\t\t\t\t\t\t\t lzo_bytep dst, lzo_uintp dst_len,\n\t\t\t\t\t\t\t\t\t\t lzo_voidp wrkmem);\n\ntypedef int(__LZO_CDECL *lzo_decompress_t)(const lzo_bytep src, lzo_uint src_len,\n\t\t\t\t\t\t\t\t\t\t   lzo_bytep dst, lzo_uintp dst_len,\n\t\t\t\t\t\t\t\t\t\t   lzo_voidp wrkmem);\n\ntypedef int(__LZO_CDECL *lzo_optimize_t)(lzo_bytep src, lzo_uint src_len,\n\t\t\t\t\t\t\t\t\t\t lzo_bytep dst, lzo_uintp dst_len,\n\t\t\t\t\t\t\t\t\t\t lzo_voidp wrkmem);\n\ntypedef int(__LZO_CDECL *lzo_compress_dict_t)(const lzo_bytep src, lzo_uint src_len,\n\t\t\t\t\t\t\t\t\t\t\t  lzo_bytep dst, lzo_uintp dst_len,\n\t\t\t\t\t\t\t\t\t\t\t  lzo_voidp\t\t  wrkmem,\n\t\t\t\t\t\t\t\t\t\t\t  const lzo_bytep dict, lzo_uint dict_len);\n\ntypedef int(__LZO_CDECL *lzo_decompress_dict_t)(const lzo_bytep src, lzo_uint src_len,\n\t\t\t\t\t\t\t\t\t\t\t\tlzo_bytep dst, lzo_uintp dst_len,\n\t\t\t\t\t\t\t\t\t\t\t\tlzo_voidp\t\twrkmem,\n\t\t\t\t\t\t\t\t\t\t\t\tconst lzo_bytep dict, lzo_uint dict_len);\n\n/* Callback interface. Currently only the progress indicator (\"nprogress\")\n * is used, but this may change in a future release. */\n\nstruct lzo_callback_t;\ntypedef struct lzo_callback_t lzo_callback_t;\n#define lzo_callback_p lzo_callback_t __LZO_MMODEL *\n\n/* malloc & free function types */\ntypedef lzo_voidp(__LZO_CDECL *lzo_alloc_func_t)(lzo_callback_p self, lzo_uint items, lzo_uint size);\ntypedef void(__LZO_CDECL *lzo_free_func_t)(lzo_callback_p self, lzo_voidp ptr);\n\n/* a progress indicator callback function */\ntypedef void(__LZO_CDECL *lzo_progress_func_t)(lzo_callback_p, lzo_uint, lzo_uint, int);\n\nstruct lzo_callback_t {\n\t/* custom allocators (set to 0 to disable) */\n\tlzo_alloc_func_t nalloc; /* [not used right now] */\n\tlzo_free_func_t\t nfree;\t /* [not used right now] */\n\n\t/* a progress indicator callback function (set to 0 to disable) */\n\tlzo_progress_func_t nprogress;\n\n\t/* INFO: the first parameter \"self\" of the nalloc/nfree/nprogress\n\t * callbacks points back to this struct, so you are free to store\n\t * some extra info in the following variables. */\n\tlzo_voidp user1;\n\tlzo_xint  user2;\n\tlzo_xint  user3;\n};\n\n/***********************************************************************\n// error codes and prototypes\n************************************************************************/\n\n/* Error codes for the compression/decompression functions. Negative\n * values are errors, positive values will be used for special but\n * normal events.\n */\n#define LZO_E_OK\t\t\t\t  0\n#define LZO_E_ERROR\t\t\t\t  (-1)\n#define LZO_E_OUT_OF_MEMORY\t\t  (-2) /* [lzo_alloc_func_t failure] */\n#define LZO_E_NOT_COMPRESSIBLE\t  (-3) /* [not used right now] */\n#define LZO_E_INPUT_OVERRUN\t\t  (-4)\n#define LZO_E_OUTPUT_OVERRUN\t  (-5)\n#define LZO_E_LOOKBEHIND_OVERRUN  (-6)\n#define LZO_E_EOF_NOT_FOUND\t\t  (-7)\n#define LZO_E_INPUT_NOT_CONSUMED  (-8)\n#define LZO_E_NOT_YET_IMPLEMENTED (-9) /* [not used right now] */\n#define LZO_E_INVALID_ARGUMENT\t  (-10)\n#define LZO_E_INVALID_ALIGNMENT\t  (-11) /* pointer argument is not properly aligned */\n#define LZO_E_OUTPUT_NOT_CONSUMED (-12)\n#define LZO_E_INTERNAL_ERROR\t  (-99)\n\n#ifndef lzo_sizeof_dict_t\n#define lzo_sizeof_dict_t ((unsigned)sizeof(lzo_bytep))\n#endif\n\n/* lzo_init() should be the first function you call.\n * Check the return code !\n *\n * lzo_init() is a macro to allow checking that the library and the\n * compiler's view of various types are consistent.\n */\n#define lzo_init() __lzo_init_v2(LZO_VERSION, (int)sizeof(short), (int)sizeof(int),                   \\\n\t\t\t\t\t\t\t\t (int)sizeof(long), (int)sizeof(lzo_uint32_t), (int)sizeof(lzo_uint), \\\n\t\t\t\t\t\t\t\t (int)lzo_sizeof_dict_t, (int)sizeof(char *), (int)sizeof(lzo_voidp), \\\n\t\t\t\t\t\t\t\t (int)sizeof(lzo_callback_t))\nLZO_EXTERN(int)\n__lzo_init_v2(unsigned, int, int, int, int, int, int, int, int, int);\n\n/* version functions (useful for shared libraries) */\nLZO_EXTERN(unsigned)\nlzo_version(void);\nLZO_EXTERN(const char *)\nlzo_version_string(void);\nLZO_EXTERN(const char *)\nlzo_version_date(void);\nLZO_EXTERN(const lzo_charp)\n_lzo_version_string(void);\nLZO_EXTERN(const lzo_charp)\n_lzo_version_date(void);\n\n/* string functions */\nLZO_EXTERN(int)\nlzo_memcmp(const lzo_voidp a, const lzo_voidp b, lzo_uint len);\nLZO_EXTERN(lzo_voidp)\nlzo_memcpy(lzo_voidp dst, const lzo_voidp src, lzo_uint len);\nLZO_EXTERN(lzo_voidp)\nlzo_memmove(lzo_voidp dst, const lzo_voidp src, lzo_uint len);\nLZO_EXTERN(lzo_voidp)\nlzo_memset(lzo_voidp buf, int c, lzo_uint len);\n\n/* checksum functions */\nLZO_EXTERN(lzo_uint32_t)\nlzo_adler32(lzo_uint32_t c, const lzo_bytep buf, lzo_uint len);\nLZO_EXTERN(lzo_uint32_t)\nlzo_crc32(lzo_uint32_t c, const lzo_bytep buf, lzo_uint len);\nLZO_EXTERN(const lzo_uint32_tp)\nlzo_get_crc32_table(void);\n\n/* misc. */\nLZO_EXTERN(int)\n_lzo_config_check(void);\ntypedef union {\n\tlzo_voidp\t   a00;\n\tlzo_bytep\t   a01;\n\tlzo_uint\t   a02;\n\tlzo_xint\t   a03;\n\tlzo_uintptr_t  a04;\n\tvoid\t\t  *a05;\n\tunsigned char *a06;\n\tunsigned long  a07;\n\tsize_t\t\t   a08;\n\tptrdiff_t\t   a09;\n#if defined(lzo_int64_t)\n\tlzo_uint64_t a10;\n#endif\n} lzo_align_t;\n\n/* align a char pointer on a boundary that is a multiple of 'size' */\nLZO_EXTERN(unsigned)\n__lzo_align_gap(const lzo_voidp p, lzo_uint size);\n#define LZO_PTR_ALIGN_UP(p, size) \\\n\t((p) + (lzo_uint)__lzo_align_gap((const lzo_voidp)(p), (lzo_uint)(size)))\n\n/***********************************************************************\n// deprecated macros - only for backward compatibility\n************************************************************************/\n\n/* deprecated - use 'lzo_bytep' instead of 'lzo_byte *' */\n#define lzo_byte unsigned char\n/* deprecated type names */\n#define lzo_int32\t   lzo_int32_t\n#define lzo_uint32\t   lzo_uint32_t\n#define lzo_int32p\t   lzo_int32_t __LZO_MMODEL *\n#define lzo_uint32p\t   lzo_uint32_t __LZO_MMODEL *\n#define LZO_INT32_MAX  LZO_INT32_C(2147483647)\n#define LZO_UINT32_MAX LZO_UINT32_C(4294967295)\n#if defined(lzo_int64_t)\n#define lzo_int64\t   lzo_int64_t\n#define lzo_uint64\t   lzo_uint64_t\n#define lzo_int64p\t   lzo_int64_t __LZO_MMODEL *\n#define lzo_uint64p\t   lzo_uint64_t __LZO_MMODEL *\n#define LZO_INT64_MAX  LZO_INT64_C(9223372036854775807)\n#define LZO_UINT64_MAX LZO_UINT64_C(18446744073709551615)\n#endif\n/* deprecated types */\ntypedef union {\n\tlzo_bytep a;\n\tlzo_uint  b;\n} __lzo_pu_u;\ntypedef union {\n\tlzo_bytep\t a;\n\tlzo_uint32_t b;\n} __lzo_pu32_u;\n/* deprecated defines */\n#if !defined(LZO_SIZEOF_LZO_UINT)\n#define LZO_SIZEOF_LZO_UINT LZO_SIZEOF_LZO_INT\n#endif\n\n#if defined(LZO_CFG_COMPAT)\n\n#define __LZOCONF_H 1\n\n#if defined(LZO_ARCH_I086)\n#define __LZO_i386 1\n#elif defined(LZO_ARCH_I386)\n#define __LZO_i386 1\n#endif\n\n#if defined(LZO_OS_DOS16)\n#define __LZO_DOS\t1\n#define __LZO_DOS16 1\n#elif defined(LZO_OS_DOS32)\n#define __LZO_DOS 1\n#elif defined(LZO_OS_WIN16)\n#define __LZO_WIN\t1\n#define __LZO_WIN16 1\n#elif defined(LZO_OS_WIN32)\n#define __LZO_WIN 1\n#endif\n\n#define __LZO_CMODEL\t /*empty*/\n#define __LZO_DMODEL\t /*empty*/\n#define __LZO_ENTRY\t\t __LZO_CDECL\n#define LZO_EXTERN_CDECL LZO_EXTERN\n#define LZO_ALIGN\t\t LZO_PTR_ALIGN_UP\n\n#define lzo_compress_asm_t\t lzo_compress_t\n#define lzo_decompress_asm_t lzo_decompress_t\n\n#endif /* LZO_CFG_COMPAT */\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /* already included */\n\n/* vim:set ts=4 sw=4 et: */\n"
  },
  {
    "path": "include/utils/lzodefs.h",
    "content": "/* lzodefs.h -- architecture, OS and compiler specific defines\n\n   This file is part of the LZO real-time data compression library.\n\n   Copyright (C) 1996-2015 Markus Franz Xaver Johannes Oberhumer\n   All Rights Reserved.\n\n   The LZO library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU General Public License as\n   published by the Free Software Foundation; either version 2 of\n   the License, or (at your option) any later version.\n\n   The LZO library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n\n   You should have received a copy of the GNU General Public License\n   along with the LZO library; see the file COPYING.\n   If not, write to the Free Software Foundation, Inc.,\n   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n\n   Markus F.X.J. Oberhumer\n   <markus@oberhumer.com>\n   http://www.oberhumer.com/opensource/lzo/\n */\n\n\n#ifndef __LZODEFS_H_INCLUDED\n#define __LZODEFS_H_INCLUDED 1\n\n#if defined(__CYGWIN32__) && !defined(__CYGWIN__)\n#  define __CYGWIN__ __CYGWIN32__\n#endif\n#if 1 && defined(__INTERIX) && defined(__GNUC__) && !defined(_ALL_SOURCE)\n#  define _ALL_SOURCE 1\n#endif\n#if defined(__mips__) && defined(__R5900__)\n#  if !defined(__LONG_MAX__)\n#    define __LONG_MAX__ 9223372036854775807L\n#  endif\n#endif\n#if !defined(LZO_CFG_NO_DISABLE_WUNDEF)\n#if defined(__ARMCC_VERSION)\n#  pragma diag_suppress 193\n#elif defined(__clang__) && defined(__clang_minor__)\n#  pragma clang diagnostic ignored \"-Wundef\"\n#elif defined(__INTEL_COMPILER)\n#  pragma warning(disable: 193)\n#elif defined(__KEIL__) && defined(__C166__)\n#  pragma warning disable = 322\n#elif defined(__GNUC__) && defined(__GNUC_MINOR__) && !defined(__PATHSCALE__)\n#  if ((__GNUC__-0) >= 5 || ((__GNUC__-0) == 4 && (__GNUC_MINOR__-0) >= 2))\n#    pragma GCC diagnostic ignored \"-Wundef\"\n#  endif\n#elif defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__MWERKS__)\n#  if ((_MSC_VER-0) >= 1300)\n#    pragma warning(disable: 4668)\n#  endif\n#endif\n#endif\n#if 0 && defined(__POCC__) && defined(_WIN32)\n#  if (__POCC__ >= 400)\n#    pragma warn(disable: 2216)\n#  endif\n#endif\n#if 0 && defined(__WATCOMC__)\n#  if (__WATCOMC__ >= 1050) && (__WATCOMC__ < 1060)\n#    pragma warning 203 9\n#  endif\n#endif\n#if defined(__BORLANDC__) && defined(__MSDOS__) && !defined(__FLAT__)\n#  pragma option -h\n#endif\n#if !(LZO_CFG_NO_DISABLE_WCRTNONSTDC)\n#ifndef _CRT_NONSTDC_NO_DEPRECATE\n#define _CRT_NONSTDC_NO_DEPRECATE 1\n#endif\n#ifndef _CRT_NONSTDC_NO_WARNINGS\n#define _CRT_NONSTDC_NO_WARNINGS 1\n#endif\n#ifndef _CRT_SECURE_NO_DEPRECATE\n#define _CRT_SECURE_NO_DEPRECATE 1\n#endif\n#ifndef _CRT_SECURE_NO_WARNINGS\n#define _CRT_SECURE_NO_WARNINGS 1\n#endif\n#endif\n#if 0\n#define LZO_0xffffUL            0xfffful\n#define LZO_0xffffffffUL        0xfffffffful\n#else\n#define LZO_0xffffUL            65535ul\n#define LZO_0xffffffffUL        4294967295ul\n#endif\n#define LZO_0xffffL             LZO_0xffffUL\n#define LZO_0xffffffffL         LZO_0xffffffffUL\n#if (LZO_0xffffL == LZO_0xffffffffL)\n#  error \"your preprocessor is broken 1\"\n#endif\n#if (16ul * 16384ul != 262144ul)\n#  error \"your preprocessor is broken 2\"\n#endif\n#if 0\n#if (32767 >= 4294967295ul)\n#  error \"your preprocessor is broken 3\"\n#endif\n#if (65535u >= 4294967295ul)\n#  error \"your preprocessor is broken 4\"\n#endif\n#endif\n#if defined(__COUNTER__)\n#  ifndef LZO_CFG_USE_COUNTER\n#  define LZO_CFG_USE_COUNTER 1\n#  endif\n#else\n#  undef LZO_CFG_USE_COUNTER\n#endif\n#if (UINT_MAX == LZO_0xffffL)\n#if defined(__ZTC__) && defined(__I86__) && !defined(__OS2__)\n#  if !defined(MSDOS)\n#    define MSDOS 1\n#  endif\n#  if !defined(_MSDOS)\n#    define _MSDOS 1\n#  endif\n#elif 0 && defined(__VERSION) && defined(MB_LEN_MAX)\n#  if (__VERSION == 520) && (MB_LEN_MAX == 1)\n#    if !defined(__AZTEC_C__)\n#      define __AZTEC_C__ __VERSION\n#    endif\n#    if !defined(__DOS__)\n#      define __DOS__ 1\n#    endif\n#  endif\n#endif\n#endif\n#if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL)\n#  define ptrdiff_t long\n#  define _PTRDIFF_T_DEFINED 1\n#endif\n#if (UINT_MAX == LZO_0xffffL)\n#  undef __LZO_RENAME_A\n#  undef __LZO_RENAME_B\n#  if defined(__AZTEC_C__) && defined(__DOS__)\n#    define __LZO_RENAME_A 1\n#  elif defined(_MSC_VER) && defined(MSDOS)\n#    if (_MSC_VER < 600)\n#      define __LZO_RENAME_A 1\n#    elif (_MSC_VER < 700)\n#      define __LZO_RENAME_B 1\n#    endif\n#  elif defined(__TSC__) && defined(__OS2__)\n#    define __LZO_RENAME_A 1\n#  elif defined(__MSDOS__) && defined(__TURBOC__) && (__TURBOC__ < 0x0410)\n#    define __LZO_RENAME_A 1\n#  elif defined(__PACIFIC__) && defined(DOS)\n#    if !defined(__far)\n#      define __far far\n#    endif\n#    if !defined(__near)\n#      define __near near\n#    endif\n#  endif\n#  if defined(__LZO_RENAME_A)\n#    if !defined(__cdecl)\n#      define __cdecl cdecl\n#    endif\n#    if !defined(__far)\n#      define __far far\n#    endif\n#    if !defined(__huge)\n#      define __huge huge\n#    endif\n#    if !defined(__near)\n#      define __near near\n#    endif\n#    if !defined(__pascal)\n#      define __pascal pascal\n#    endif\n#    if !defined(__huge)\n#      define __huge huge\n#    endif\n#  elif defined(__LZO_RENAME_B)\n#    if !defined(__cdecl)\n#      define __cdecl _cdecl\n#    endif\n#    if !defined(__far)\n#      define __far _far\n#    endif\n#    if !defined(__huge)\n#      define __huge _huge\n#    endif\n#    if !defined(__near)\n#      define __near _near\n#    endif\n#    if !defined(__pascal)\n#      define __pascal _pascal\n#    endif\n#  elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__)\n#    if !defined(__cdecl)\n#      define __cdecl cdecl\n#    endif\n#    if !defined(__pascal)\n#      define __pascal pascal\n#    endif\n#  endif\n#  undef __LZO_RENAME_A\n#  undef __LZO_RENAME_B\n#endif\n#if (UINT_MAX == LZO_0xffffL)\n#if defined(__AZTEC_C__) && defined(__DOS__)\n#  define LZO_BROKEN_CDECL_ALT_SYNTAX 1\n#elif defined(_MSC_VER) && defined(MSDOS)\n#  if (_MSC_VER < 600)\n#    define LZO_BROKEN_INTEGRAL_CONSTANTS 1\n#  endif\n#  if (_MSC_VER < 700)\n#    define LZO_BROKEN_INTEGRAL_PROMOTION 1\n#    define LZO_BROKEN_SIZEOF 1\n#  endif\n#elif defined(__PACIFIC__) && defined(DOS)\n#  define LZO_BROKEN_INTEGRAL_CONSTANTS 1\n#elif defined(__TURBOC__) && defined(__MSDOS__)\n#  if (__TURBOC__ < 0x0150)\n#    define LZO_BROKEN_CDECL_ALT_SYNTAX 1\n#    define LZO_BROKEN_INTEGRAL_CONSTANTS 1\n#    define LZO_BROKEN_INTEGRAL_PROMOTION 1\n#  endif\n#  if (__TURBOC__ < 0x0200)\n#    define LZO_BROKEN_SIZEOF 1\n#  endif\n#  if (__TURBOC__ < 0x0400) && defined(__cplusplus)\n#    define LZO_BROKEN_CDECL_ALT_SYNTAX 1\n#  endif\n#elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__)\n#  define LZO_BROKEN_CDECL_ALT_SYNTAX 1\n#  define LZO_BROKEN_SIZEOF 1\n#endif\n#endif\n#if defined(__WATCOMC__) && (__WATCOMC__ < 900)\n#  define LZO_BROKEN_INTEGRAL_CONSTANTS 1\n#endif\n#if defined(_CRAY) && defined(_CRAY1)\n#  define LZO_BROKEN_SIGNED_RIGHT_SHIFT 1\n#endif\n#define LZO_PP_STRINGIZE(x)             #x\n#define LZO_PP_MACRO_EXPAND(x)          LZO_PP_STRINGIZE(x)\n#define LZO_PP_CONCAT0()                /*empty*/\n#define LZO_PP_CONCAT1(a)               a\n#define LZO_PP_CONCAT2(a,b)             a ## b\n#define LZO_PP_CONCAT3(a,b,c)           a ## b ## c\n#define LZO_PP_CONCAT4(a,b,c,d)         a ## b ## c ## d\n#define LZO_PP_CONCAT5(a,b,c,d,e)       a ## b ## c ## d ## e\n#define LZO_PP_CONCAT6(a,b,c,d,e,f)     a ## b ## c ## d ## e ## f\n#define LZO_PP_CONCAT7(a,b,c,d,e,f,g)   a ## b ## c ## d ## e ## f ## g\n#define LZO_PP_ECONCAT0()               LZO_PP_CONCAT0()\n#define LZO_PP_ECONCAT1(a)              LZO_PP_CONCAT1(a)\n#define LZO_PP_ECONCAT2(a,b)            LZO_PP_CONCAT2(a,b)\n#define LZO_PP_ECONCAT3(a,b,c)          LZO_PP_CONCAT3(a,b,c)\n#define LZO_PP_ECONCAT4(a,b,c,d)        LZO_PP_CONCAT4(a,b,c,d)\n#define LZO_PP_ECONCAT5(a,b,c,d,e)      LZO_PP_CONCAT5(a,b,c,d,e)\n#define LZO_PP_ECONCAT6(a,b,c,d,e,f)    LZO_PP_CONCAT6(a,b,c,d,e,f)\n#define LZO_PP_ECONCAT7(a,b,c,d,e,f,g)  LZO_PP_CONCAT7(a,b,c,d,e,f,g)\n#define LZO_PP_EMPTY                    /*empty*/\n#define LZO_PP_EMPTY0()                 /*empty*/\n#define LZO_PP_EMPTY1(a)                /*empty*/\n#define LZO_PP_EMPTY2(a,b)              /*empty*/\n#define LZO_PP_EMPTY3(a,b,c)            /*empty*/\n#define LZO_PP_EMPTY4(a,b,c,d)          /*empty*/\n#define LZO_PP_EMPTY5(a,b,c,d,e)        /*empty*/\n#define LZO_PP_EMPTY6(a,b,c,d,e,f)      /*empty*/\n#define LZO_PP_EMPTY7(a,b,c,d,e,f,g)    /*empty*/\n#if 1\n#define LZO_CPP_STRINGIZE(x)            #x\n#define LZO_CPP_MACRO_EXPAND(x)         LZO_CPP_STRINGIZE(x)\n#define LZO_CPP_CONCAT2(a,b)            a ## b\n#define LZO_CPP_CONCAT3(a,b,c)          a ## b ## c\n#define LZO_CPP_CONCAT4(a,b,c,d)        a ## b ## c ## d\n#define LZO_CPP_CONCAT5(a,b,c,d,e)      a ## b ## c ## d ## e\n#define LZO_CPP_CONCAT6(a,b,c,d,e,f)    a ## b ## c ## d ## e ## f\n#define LZO_CPP_CONCAT7(a,b,c,d,e,f,g)  a ## b ## c ## d ## e ## f ## g\n#define LZO_CPP_ECONCAT2(a,b)           LZO_CPP_CONCAT2(a,b)\n#define LZO_CPP_ECONCAT3(a,b,c)         LZO_CPP_CONCAT3(a,b,c)\n#define LZO_CPP_ECONCAT4(a,b,c,d)       LZO_CPP_CONCAT4(a,b,c,d)\n#define LZO_CPP_ECONCAT5(a,b,c,d,e)     LZO_CPP_CONCAT5(a,b,c,d,e)\n#define LZO_CPP_ECONCAT6(a,b,c,d,e,f)   LZO_CPP_CONCAT6(a,b,c,d,e,f)\n#define LZO_CPP_ECONCAT7(a,b,c,d,e,f,g) LZO_CPP_CONCAT7(a,b,c,d,e,f,g)\n#endif\n#define __LZO_MASK_GEN(o,b)     (((((o) << ((b)-!!(b))) - (o)) << 1) + (o)*!!(b))\n#if 1 && defined(__cplusplus)\n#  if !defined(__STDC_CONSTANT_MACROS)\n#    define __STDC_CONSTANT_MACROS 1\n#  endif\n#  if !defined(__STDC_LIMIT_MACROS)\n#    define __STDC_LIMIT_MACROS 1\n#  endif\n#endif\n#if defined(__cplusplus)\n#  define LZO_EXTERN_C          extern \"C\"\n#  define LZO_EXTERN_C_BEGIN    extern \"C\" {\n#  define LZO_EXTERN_C_END      }\n#else\n#  define LZO_EXTERN_C          extern\n#  define LZO_EXTERN_C_BEGIN    /*empty*/\n#  define LZO_EXTERN_C_END      /*empty*/\n#endif\n#if !defined(__LZO_OS_OVERRIDE)\n#if (LZO_OS_FREESTANDING)\n#  define LZO_INFO_OS           \"freestanding\"\n#elif (LZO_OS_EMBEDDED)\n#  define LZO_INFO_OS           \"embedded\"\n#elif 1 && defined(__IAR_SYSTEMS_ICC__)\n#  define LZO_OS_EMBEDDED       1\n#  define LZO_INFO_OS           \"embedded\"\n#elif defined(__CYGWIN__) && defined(__GNUC__)\n#  define LZO_OS_CYGWIN         1\n#  define LZO_INFO_OS           \"cygwin\"\n#elif defined(__EMX__) && defined(__GNUC__)\n#  define LZO_OS_EMX            1\n#  define LZO_INFO_OS           \"emx\"\n#elif defined(__BEOS__)\n#  define LZO_OS_BEOS           1\n#  define LZO_INFO_OS           \"beos\"\n#elif defined(__Lynx__)\n#  define LZO_OS_LYNXOS         1\n#  define LZO_INFO_OS           \"lynxos\"\n#elif defined(__OS400__)\n#  define LZO_OS_OS400          1\n#  define LZO_INFO_OS           \"os400\"\n#elif defined(__QNX__)\n#  define LZO_OS_QNX            1\n#  define LZO_INFO_OS           \"qnx\"\n#elif defined(__BORLANDC__) && defined(__DPMI32__) && (__BORLANDC__ >= 0x0460)\n#  define LZO_OS_DOS32          1\n#  define LZO_INFO_OS           \"dos32\"\n#elif defined(__BORLANDC__) && defined(__DPMI16__)\n#  define LZO_OS_DOS16          1\n#  define LZO_INFO_OS           \"dos16\"\n#elif defined(__ZTC__) && defined(DOS386)\n#  define LZO_OS_DOS32          1\n#  define LZO_INFO_OS           \"dos32\"\n#elif defined(__OS2__) || defined(__OS2V2__)\n#  if (UINT_MAX == LZO_0xffffL)\n#    define LZO_OS_OS216        1\n#    define LZO_INFO_OS         \"os216\"\n#  elif (UINT_MAX == LZO_0xffffffffL)\n#    define LZO_OS_OS2          1\n#    define LZO_INFO_OS         \"os2\"\n#  else\n#    error \"check your limits.h header\"\n#  endif\n#elif defined(__WIN64__) || defined(_WIN64) || defined(WIN64)\n#  define LZO_OS_WIN64          1\n#  define LZO_INFO_OS           \"win64\"\n#elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WINDOWS_386__)\n#  define LZO_OS_WIN32          1\n#  define LZO_INFO_OS           \"win32\"\n#elif defined(__MWERKS__) && defined(__INTEL__)\n#  define LZO_OS_WIN32          1\n#  define LZO_INFO_OS           \"win32\"\n#elif defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows)\n#  if (UINT_MAX == LZO_0xffffL)\n#    define LZO_OS_WIN16        1\n#    define LZO_INFO_OS         \"win16\"\n#  elif (UINT_MAX == LZO_0xffffffffL)\n#    define LZO_OS_WIN32        1\n#    define LZO_INFO_OS         \"win32\"\n#  else\n#    error \"check your limits.h header\"\n#  endif\n#elif defined(__DOS__) || defined(__MSDOS__) || defined(_MSDOS) || defined(MSDOS) || (defined(__PACIFIC__) && defined(DOS))\n#  if (UINT_MAX == LZO_0xffffL)\n#    define LZO_OS_DOS16        1\n#    define LZO_INFO_OS         \"dos16\"\n#  elif (UINT_MAX == LZO_0xffffffffL)\n#    define LZO_OS_DOS32        1\n#    define LZO_INFO_OS         \"dos32\"\n#  else\n#    error \"check your limits.h header\"\n#  endif\n#elif defined(__WATCOMC__)\n#  if defined(__NT__) && (UINT_MAX == LZO_0xffffL)\n#    define LZO_OS_DOS16        1\n#    define LZO_INFO_OS         \"dos16\"\n#  elif defined(__NT__) && (__WATCOMC__ < 1100)\n#    define LZO_OS_WIN32        1\n#    define LZO_INFO_OS         \"win32\"\n#  elif defined(__linux__) || defined(__LINUX__)\n#    define LZO_OS_POSIX        1\n#    define LZO_INFO_OS         \"posix\"\n#  else\n#    error \"please specify a target using the -bt compiler option\"\n#  endif\n#elif defined(__palmos__)\n#  define LZO_OS_PALMOS         1\n#  define LZO_INFO_OS           \"palmos\"\n#elif defined(__TOS__) || defined(__atarist__)\n#  define LZO_OS_TOS            1\n#  define LZO_INFO_OS           \"tos\"\n#elif defined(macintosh) && !defined(__arm__) && !defined(__i386__) && !defined(__ppc__) && !defined(__x64_64__)\n#  define LZO_OS_MACCLASSIC     1\n#  define LZO_INFO_OS           \"macclassic\"\n#elif defined(__VMS)\n#  define LZO_OS_VMS            1\n#  define LZO_INFO_OS           \"vms\"\n#elif (defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)\n#  define LZO_OS_CONSOLE        1\n#  define LZO_OS_CONSOLE_PS2    1\n#  define LZO_INFO_OS           \"console\"\n#  define LZO_INFO_OS_CONSOLE   \"ps2\"\n#elif defined(__mips__) && defined(__psp__)\n#  define LZO_OS_CONSOLE        1\n#  define LZO_OS_CONSOLE_PSP    1\n#  define LZO_INFO_OS           \"console\"\n#  define LZO_INFO_OS_CONSOLE   \"psp\"\n#else\n#  define LZO_OS_POSIX          1\n#  define LZO_INFO_OS           \"posix\"\n#endif\n#if (LZO_OS_POSIX)\n#  if defined(_AIX) || defined(__AIX__) || defined(__aix__)\n#    define LZO_OS_POSIX_AIX        1\n#    define LZO_INFO_OS_POSIX       \"aix\"\n#  elif defined(__FreeBSD__)\n#    define LZO_OS_POSIX_FREEBSD    1\n#    define LZO_INFO_OS_POSIX       \"freebsd\"\n#  elif defined(__hpux__) || defined(__hpux)\n#    define LZO_OS_POSIX_HPUX       1\n#    define LZO_INFO_OS_POSIX       \"hpux\"\n#  elif defined(__INTERIX)\n#    define LZO_OS_POSIX_INTERIX    1\n#    define LZO_INFO_OS_POSIX       \"interix\"\n#  elif defined(__IRIX__) || defined(__irix__)\n#    define LZO_OS_POSIX_IRIX       1\n#    define LZO_INFO_OS_POSIX       \"irix\"\n#  elif defined(__linux__) || defined(__linux) || defined(__LINUX__)\n#    define LZO_OS_POSIX_LINUX      1\n#    define LZO_INFO_OS_POSIX       \"linux\"\n#  elif defined(__APPLE__) && defined(__MACH__)\n#    if ((__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__-0) >= 20000)\n#      define LZO_OS_POSIX_DARWIN     1040\n#      define LZO_INFO_OS_POSIX       \"darwin_iphone\"\n#    elif ((__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__-0) >= 1040)\n#      define LZO_OS_POSIX_DARWIN     __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__\n#      define LZO_INFO_OS_POSIX       \"darwin\"\n#    else\n#      define LZO_OS_POSIX_DARWIN     1\n#      define LZO_INFO_OS_POSIX       \"darwin\"\n#    endif\n#    define LZO_OS_POSIX_MACOSX     LZO_OS_POSIX_DARWIN\n#  elif defined(__minix__) || defined(__minix)\n#    define LZO_OS_POSIX_MINIX      1\n#    define LZO_INFO_OS_POSIX       \"minix\"\n#  elif defined(__NetBSD__)\n#    define LZO_OS_POSIX_NETBSD     1\n#    define LZO_INFO_OS_POSIX       \"netbsd\"\n#  elif defined(__OpenBSD__)\n#    define LZO_OS_POSIX_OPENBSD    1\n#    define LZO_INFO_OS_POSIX       \"openbsd\"\n#  elif defined(__osf__)\n#    define LZO_OS_POSIX_OSF        1\n#    define LZO_INFO_OS_POSIX       \"osf\"\n#  elif defined(__solaris__) || defined(__sun)\n#    if defined(__SVR4) || defined(__svr4__)\n#      define LZO_OS_POSIX_SOLARIS  1\n#      define LZO_INFO_OS_POSIX     \"solaris\"\n#    else\n#      define LZO_OS_POSIX_SUNOS    1\n#      define LZO_INFO_OS_POSIX     \"sunos\"\n#    endif\n#  elif defined(__ultrix__) || defined(__ultrix)\n#    define LZO_OS_POSIX_ULTRIX     1\n#    define LZO_INFO_OS_POSIX       \"ultrix\"\n#  elif defined(_UNICOS)\n#    define LZO_OS_POSIX_UNICOS     1\n#    define LZO_INFO_OS_POSIX       \"unicos\"\n#  else\n#    define LZO_OS_POSIX_UNKNOWN    1\n#    define LZO_INFO_OS_POSIX       \"unknown\"\n#  endif\n#endif\n#endif\n#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)\n#  if (UINT_MAX != LZO_0xffffL)\n#    error \"unexpected configuration - check your compiler defines\"\n#  endif\n#  if (ULONG_MAX != LZO_0xffffffffL)\n#    error \"unexpected configuration - check your compiler defines\"\n#  endif\n#endif\n#if (LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_WIN32 || LZO_OS_WIN64)\n#  if (UINT_MAX != LZO_0xffffffffL)\n#    error \"unexpected configuration - check your compiler defines\"\n#  endif\n#  if (ULONG_MAX != LZO_0xffffffffL)\n#    error \"unexpected configuration - check your compiler defines\"\n#  endif\n#endif\n#if defined(CIL) && defined(_GNUCC) && defined(__GNUC__)\n#  define LZO_CC_CILLY          1\n#  define LZO_INFO_CC           \"Cilly\"\n#  if defined(__CILLY__)\n#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__CILLY__)\n#  else\n#    define LZO_INFO_CCVER      \"unknown\"\n#  endif\n#elif 0 && defined(SDCC) && defined(__VERSION__) && !defined(__GNUC__)\n#  define LZO_CC_SDCC           1\n#  define LZO_INFO_CC           \"sdcc\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(SDCC)\n#elif defined(__PATHSCALE__) && defined(__PATHCC_PATCHLEVEL__)\n#  define LZO_CC_PATHSCALE      (__PATHCC__ * 0x10000L + (__PATHCC_MINOR__-0) * 0x100 + (__PATHCC_PATCHLEVEL__-0))\n#  define LZO_INFO_CC           \"Pathscale C\"\n#  define LZO_INFO_CCVER        __PATHSCALE__\n#  if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)\n#    define LZO_CC_PATHSCALE_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))\n#  endif\n#elif defined(__INTEL_COMPILER) && ((__INTEL_COMPILER-0) > 0)\n#  define LZO_CC_INTELC         __INTEL_COMPILER\n#  define LZO_INFO_CC           \"Intel C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__INTEL_COMPILER)\n#  if defined(_MSC_VER) && ((_MSC_VER-0) > 0)\n#    define LZO_CC_INTELC_MSC   _MSC_VER\n#  elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)\n#    define LZO_CC_INTELC_GNUC   (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))\n#  endif\n#elif defined(__POCC__) && defined(_WIN32)\n#  define LZO_CC_PELLESC        1\n#  define LZO_INFO_CC           \"Pelles C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__POCC__)\n#elif defined(__ARMCC_VERSION) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)\n#  if defined(__GNUC_PATCHLEVEL__)\n#    define LZO_CC_ARMCC_GNUC   (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))\n#  else\n#    define LZO_CC_ARMCC_GNUC   (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100)\n#  endif\n#  define LZO_CC_ARMCC          __ARMCC_VERSION\n#  define LZO_INFO_CC           \"ARM C Compiler\"\n#  define LZO_INFO_CCVER        __VERSION__\n#elif defined(__clang__) && defined(__llvm__) && defined(__VERSION__)\n#  if defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__)\n#    define LZO_CC_CLANG        (__clang_major__ * 0x10000L + (__clang_minor__-0) * 0x100 + (__clang_patchlevel__-0))\n#  else\n#    define LZO_CC_CLANG        0x010000L\n#  endif\n#  if defined(_MSC_VER) && ((_MSC_VER-0) > 0)\n#    define LZO_CC_CLANG_MSC    _MSC_VER\n#  elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)\n#    define LZO_CC_CLANG_GNUC   (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))\n#  endif\n#  define LZO_INFO_CC           \"clang\"\n#  define LZO_INFO_CCVER        __VERSION__\n#elif defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)\n#  if defined(__GNUC_PATCHLEVEL__)\n#    define LZO_CC_LLVM_GNUC    (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))\n#  else\n#    define LZO_CC_LLVM_GNUC    (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100)\n#  endif\n#  define LZO_CC_LLVM           LZO_CC_LLVM_GNUC\n#  define LZO_INFO_CC           \"llvm-gcc\"\n#  define LZO_INFO_CCVER        __VERSION__\n#elif defined(__ACK__) && defined(_ACK)\n#  define LZO_CC_ACK            1\n#  define LZO_INFO_CC           \"Amsterdam Compiler Kit C\"\n#  define LZO_INFO_CCVER        \"unknown\"\n#elif defined(__ARMCC_VERSION) && !defined(__GNUC__)\n#  define LZO_CC_ARMCC          __ARMCC_VERSION\n#  define LZO_CC_ARMCC_ARMCC    __ARMCC_VERSION\n#  define LZO_INFO_CC           \"ARM C Compiler\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__ARMCC_VERSION)\n#elif defined(__AZTEC_C__)\n#  define LZO_CC_AZTECC         1\n#  define LZO_INFO_CC           \"Aztec C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__AZTEC_C__)\n#elif defined(__CODEGEARC__)\n#  define LZO_CC_CODEGEARC      1\n#  define LZO_INFO_CC           \"CodeGear C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__CODEGEARC__)\n#elif defined(__BORLANDC__)\n#  define LZO_CC_BORLANDC       1\n#  define LZO_INFO_CC           \"Borland C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__BORLANDC__)\n#elif defined(_CRAYC) && defined(_RELEASE)\n#  define LZO_CC_CRAYC          1\n#  define LZO_INFO_CC           \"Cray C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(_RELEASE)\n#elif defined(__DMC__) && defined(__SC__)\n#  define LZO_CC_DMC            1\n#  define LZO_INFO_CC           \"Digital Mars C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__DMC__)\n#elif defined(__DECC)\n#  define LZO_CC_DECC           1\n#  define LZO_INFO_CC           \"DEC C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__DECC)\n#elif (defined(__ghs) || defined(__ghs__)) && defined(__GHS_VERSION_NUMBER) && ((__GHS_VERSION_NUMBER-0) > 0)\n#  define LZO_CC_GHS            1\n#  define LZO_INFO_CC           \"Green Hills C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__GHS_VERSION_NUMBER)\n#  if defined(_MSC_VER) && ((_MSC_VER-0) > 0)\n#    define LZO_CC_GHS_MSC      _MSC_VER\n#  elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)\n#    define LZO_CC_GHS_GNUC     (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))\n#  endif\n#elif defined(__HIGHC__)\n#  define LZO_CC_HIGHC          1\n#  define LZO_INFO_CC           \"MetaWare High C\"\n#  define LZO_INFO_CCVER        \"unknown\"\n#elif defined(__HP_aCC) && ((__HP_aCC-0) > 0)\n#  define LZO_CC_HPACC          __HP_aCC\n#  define LZO_INFO_CC           \"HP aCC\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__HP_aCC)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#  define LZO_CC_IARC           1\n#  define LZO_INFO_CC           \"IAR C\"\n#  if defined(__VER__)\n#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__VER__)\n#  else\n#    define LZO_INFO_CCVER      \"unknown\"\n#  endif\n#elif defined(__IBMC__) && ((__IBMC__-0) > 0)\n#  define LZO_CC_IBMC           __IBMC__\n#  define LZO_INFO_CC           \"IBM C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__IBMC__)\n#elif defined(__IBMCPP__) && ((__IBMCPP__-0) > 0)\n#  define LZO_CC_IBMC           __IBMCPP__\n#  define LZO_INFO_CC           \"IBM C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__IBMCPP__)\n#elif defined(__KEIL__) && defined(__C166__)\n#  define LZO_CC_KEILC          1\n#  define LZO_INFO_CC           \"Keil C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__C166__)\n#elif defined(__LCC__) && defined(_WIN32) && defined(__LCCOPTIMLEVEL)\n#  define LZO_CC_LCCWIN32       1\n#  define LZO_INFO_CC           \"lcc-win32\"\n#  define LZO_INFO_CCVER        \"unknown\"\n#elif defined(__LCC__)\n#  define LZO_CC_LCC            1\n#  define LZO_INFO_CC           \"lcc\"\n#  if defined(__LCC_VERSION__)\n#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__LCC_VERSION__)\n#  else\n#    define LZO_INFO_CCVER      \"unknown\"\n#  endif\n#elif defined(__MWERKS__) && ((__MWERKS__-0) > 0)\n#  define LZO_CC_MWERKS         __MWERKS__\n#  define LZO_INFO_CC           \"Metrowerks C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__MWERKS__)\n#elif (defined(__NDPC__) || defined(__NDPX__)) && defined(__i386)\n#  define LZO_CC_NDPC           1\n#  define LZO_INFO_CC           \"Microway NDP C\"\n#  define LZO_INFO_CCVER        \"unknown\"\n#elif defined(__PACIFIC__)\n#  define LZO_CC_PACIFICC       1\n#  define LZO_INFO_CC           \"Pacific C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__PACIFIC__)\n#elif defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__)\n#  if defined(__PGIC_PATCHLEVEL__)\n#    define LZO_CC_PGI          (__PGIC__ * 0x10000L + (__PGIC_MINOR__-0) * 0x100 + (__PGIC_PATCHLEVEL__-0))\n#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__PGIC__) \".\" LZO_PP_MACRO_EXPAND(__PGIC_MINOR__) \".\" LZO_PP_MACRO_EXPAND(__PGIC_PATCHLEVEL__)\n#  else\n#    define LZO_CC_PGI          (__PGIC__ * 0x10000L + (__PGIC_MINOR__-0) * 0x100)\n#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__PGIC__) \".\" LZO_PP_MACRO_EXPAND(__PGIC_MINOR__) \".0\"\n#  endif\n#  define LZO_INFO_CC           \"Portland Group PGI C\"\n#elif defined(__PGI) && (defined(__linux__) || defined(__WIN32__))\n#  define LZO_CC_PGI            1\n#  define LZO_INFO_CC           \"Portland Group PGI C\"\n#  define LZO_INFO_CCVER        \"unknown\"\n#elif defined(__PUREC__) && defined(__TOS__)\n#  define LZO_CC_PUREC          1\n#  define LZO_INFO_CC           \"Pure C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__PUREC__)\n#elif defined(__SC__) && defined(__ZTC__)\n#  define LZO_CC_SYMANTECC      1\n#  define LZO_INFO_CC           \"Symantec C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__SC__)\n#elif defined(__SUNPRO_C)\n#  define LZO_INFO_CC           \"SunPro C\"\n#  if ((__SUNPRO_C-0) > 0)\n#    define LZO_CC_SUNPROC      __SUNPRO_C\n#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__SUNPRO_C)\n#  else\n#    define LZO_CC_SUNPROC      1\n#    define LZO_INFO_CCVER      \"unknown\"\n#  endif\n#elif defined(__SUNPRO_CC)\n#  define LZO_INFO_CC           \"SunPro C\"\n#  if ((__SUNPRO_CC-0) > 0)\n#    define LZO_CC_SUNPROC      __SUNPRO_CC\n#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__SUNPRO_CC)\n#  else\n#    define LZO_CC_SUNPROC      1\n#    define LZO_INFO_CCVER      \"unknown\"\n#  endif\n#elif defined(__TINYC__)\n#  define LZO_CC_TINYC          1\n#  define LZO_INFO_CC           \"Tiny C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__TINYC__)\n#elif defined(__TSC__)\n#  define LZO_CC_TOPSPEEDC      1\n#  define LZO_INFO_CC           \"TopSpeed C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__TSC__)\n#elif defined(__WATCOMC__)\n#  define LZO_CC_WATCOMC        1\n#  define LZO_INFO_CC           \"Watcom C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__WATCOMC__)\n#elif defined(__TURBOC__)\n#  define LZO_CC_TURBOC         1\n#  define LZO_INFO_CC           \"Turbo C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__TURBOC__)\n#elif defined(__ZTC__)\n#  define LZO_CC_ZORTECHC       1\n#  define LZO_INFO_CC           \"Zortech C\"\n#  if ((__ZTC__-0) == 0x310)\n#    define LZO_INFO_CCVER      \"0x310\"\n#  else\n#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__ZTC__)\n#  endif\n#elif defined(__GNUC__) && defined(__VERSION__)\n#  if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)\n#    define LZO_CC_GNUC         (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))\n#  elif defined(__GNUC_MINOR__)\n#    define LZO_CC_GNUC         (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100)\n#  else\n#    define LZO_CC_GNUC         (__GNUC__ * 0x10000L)\n#  endif\n#  define LZO_INFO_CC           \"gcc\"\n#  define LZO_INFO_CCVER        __VERSION__\n#elif defined(_MSC_VER) && ((_MSC_VER-0) > 0)\n#  define LZO_CC_MSC            _MSC_VER\n#  define LZO_INFO_CC           \"Microsoft C\"\n#  if defined(_MSC_FULL_VER)\n#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(_MSC_VER) \".\" LZO_PP_MACRO_EXPAND(_MSC_FULL_VER)\n#  else\n#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(_MSC_VER)\n#  endif\n#else\n#  define LZO_CC_UNKNOWN        1\n#  define LZO_INFO_CC           \"unknown\"\n#  define LZO_INFO_CCVER        \"unknown\"\n#endif\n#if (LZO_CC_GNUC) && defined(__OPEN64__)\n#  if defined(__OPENCC__) && defined(__OPENCC_MINOR__) && defined(__OPENCC_PATCHLEVEL__)\n#    define LZO_CC_OPEN64       (__OPENCC__ * 0x10000L + (__OPENCC_MINOR__-0) * 0x100 + (__OPENCC_PATCHLEVEL__-0))\n#    define LZO_CC_OPEN64_GNUC  LZO_CC_GNUC\n#  endif\n#endif\n#if (LZO_CC_GNUC) && defined(__PCC__)\n#  if defined(__PCC__) && defined(__PCC_MINOR__) && defined(__PCC_MINORMINOR__)\n#    define LZO_CC_PCC          (__PCC__ * 0x10000L + (__PCC_MINOR__-0) * 0x100 + (__PCC_MINORMINOR__-0))\n#    define LZO_CC_PCC_GNUC     LZO_CC_GNUC\n#  endif\n#endif\n#if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER)\n#  error \"LZO_CC_MSC: _MSC_FULL_VER is not defined\"\n#endif\n#if !defined(__LZO_ARCH_OVERRIDE) && !(LZO_ARCH_GENERIC) && defined(_CRAY)\n#  if (UINT_MAX > LZO_0xffffffffL) && defined(_CRAY)\n#    if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E)\n#      define LZO_ARCH_CRAY_MPP     1\n#    elif defined(_CRAY1)\n#      define LZO_ARCH_CRAY_PVP     1\n#    endif\n#  endif\n#endif\n#if !defined(__LZO_ARCH_OVERRIDE)\n#if (LZO_ARCH_GENERIC)\n#  define LZO_INFO_ARCH             \"generic\"\n#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)\n#  define LZO_ARCH_I086             1\n#  define LZO_INFO_ARCH             \"i086\"\n#elif defined(__aarch64__)\n#  define LZO_ARCH_ARM64            1\n#  define LZO_INFO_ARCH             \"arm64\"\n#elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA)\n#  define LZO_ARCH_ALPHA            1\n#  define LZO_INFO_ARCH             \"alpha\"\n#elif (LZO_ARCH_CRAY_MPP) && (defined(_CRAYT3D) || defined(_CRAYT3E))\n#  define LZO_ARCH_ALPHA            1\n#  define LZO_INFO_ARCH             \"alpha\"\n#elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64)\n#  define LZO_ARCH_AMD64            1\n#  define LZO_INFO_ARCH             \"amd64\"\n#elif defined(__arm__) || defined(_M_ARM)\n#  define LZO_ARCH_ARM              1\n#  define LZO_INFO_ARCH             \"arm\"\n#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__)\n#  define LZO_ARCH_ARM              1\n#  define LZO_INFO_ARCH             \"arm\"\n#elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__)\n#  define LZO_ARCH_AVR              1\n#  define LZO_INFO_ARCH             \"avr\"\n#elif defined(__avr32__) || defined(__AVR32__)\n#  define LZO_ARCH_AVR32            1\n#  define LZO_INFO_ARCH             \"avr32\"\n#elif defined(__bfin__)\n#  define LZO_ARCH_BLACKFIN         1\n#  define LZO_INFO_ARCH             \"blackfin\"\n#elif (UINT_MAX == LZO_0xffffL) && defined(__C166__)\n#  define LZO_ARCH_C166             1\n#  define LZO_INFO_ARCH             \"c166\"\n#elif defined(__cris__)\n#  define LZO_ARCH_CRIS             1\n#  define LZO_INFO_ARCH             \"cris\"\n#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCEZ80__)\n#  define LZO_ARCH_EZ80             1\n#  define LZO_INFO_ARCH             \"ez80\"\n#elif defined(__H8300__) || defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)\n#  define LZO_ARCH_H8300            1\n#  define LZO_INFO_ARCH             \"h8300\"\n#elif defined(__hppa__) || defined(__hppa)\n#  define LZO_ARCH_HPPA             1\n#  define LZO_INFO_ARCH             \"hppa\"\n#elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386)\n#  define LZO_ARCH_I386             1\n#  define LZO_ARCH_IA32             1\n#  define LZO_INFO_ARCH             \"i386\"\n#elif (LZO_CC_ZORTECHC && defined(__I86__))\n#  define LZO_ARCH_I386             1\n#  define LZO_ARCH_IA32             1\n#  define LZO_INFO_ARCH             \"i386\"\n#elif (LZO_OS_DOS32 && LZO_CC_HIGHC) && defined(_I386)\n#  define LZO_ARCH_I386             1\n#  define LZO_ARCH_IA32             1\n#  define LZO_INFO_ARCH             \"i386\"\n#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64)\n#  define LZO_ARCH_IA64             1\n#  define LZO_INFO_ARCH             \"ia64\"\n#elif (UINT_MAX == LZO_0xffffL) && defined(__m32c__)\n#  define LZO_ARCH_M16C             1\n#  define LZO_INFO_ARCH             \"m16c\"\n#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCM16C__)\n#  define LZO_ARCH_M16C             1\n#  define LZO_INFO_ARCH             \"m16c\"\n#elif defined(__m32r__)\n#  define LZO_ARCH_M32R             1\n#  define LZO_INFO_ARCH             \"m32r\"\n#elif (LZO_OS_TOS) || defined(__m68k__) || defined(__m68000__) || defined(__mc68000__) || defined(__mc68020__) || defined(_M_M68K)\n#  define LZO_ARCH_M68K             1\n#  define LZO_INFO_ARCH             \"m68k\"\n#elif (UINT_MAX == LZO_0xffffL) && defined(__C251__)\n#  define LZO_ARCH_MCS251           1\n#  define LZO_INFO_ARCH             \"mcs251\"\n#elif (UINT_MAX == LZO_0xffffL) && defined(__C51__)\n#  define LZO_ARCH_MCS51            1\n#  define LZO_INFO_ARCH             \"mcs51\"\n#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC8051__)\n#  define LZO_ARCH_MCS51            1\n#  define LZO_INFO_ARCH             \"mcs51\"\n#elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000)\n#  define LZO_ARCH_MIPS             1\n#  define LZO_INFO_ARCH             \"mips\"\n#elif (UINT_MAX == LZO_0xffffL) && defined(__MSP430__)\n#  define LZO_ARCH_MSP430           1\n#  define LZO_INFO_ARCH             \"msp430\"\n#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC430__)\n#  define LZO_ARCH_MSP430           1\n#  define LZO_INFO_ARCH             \"msp430\"\n#elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR)\n#  define LZO_ARCH_POWERPC          1\n#  define LZO_INFO_ARCH             \"powerpc\"\n#elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x)\n#  define LZO_ARCH_S390             1\n#  define LZO_INFO_ARCH             \"s390\"\n#elif defined(__sh__) || defined(_M_SH)\n#  define LZO_ARCH_SH               1\n#  define LZO_INFO_ARCH             \"sh\"\n#elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8)\n#  define LZO_ARCH_SPARC            1\n#  define LZO_INFO_ARCH             \"sparc\"\n#elif defined(__SPU__)\n#  define LZO_ARCH_SPU              1\n#  define LZO_INFO_ARCH             \"spu\"\n#elif (UINT_MAX == LZO_0xffffL) && defined(__z80)\n#  define LZO_ARCH_Z80              1\n#  define LZO_INFO_ARCH             \"z80\"\n#elif (LZO_ARCH_CRAY_PVP)\n#  if defined(_CRAYSV1)\n#    define LZO_ARCH_CRAY_SV1       1\n#    define LZO_INFO_ARCH           \"cray_sv1\"\n#  elif (_ADDR64)\n#    define LZO_ARCH_CRAY_T90       1\n#    define LZO_INFO_ARCH           \"cray_t90\"\n#  elif (_ADDR32)\n#    define LZO_ARCH_CRAY_YMP       1\n#    define LZO_INFO_ARCH           \"cray_ymp\"\n#  else\n#    define LZO_ARCH_CRAY_XMP       1\n#    define LZO_INFO_ARCH           \"cray_xmp\"\n#  endif\n#else\n#  define LZO_ARCH_UNKNOWN          1\n#  define LZO_INFO_ARCH             \"unknown\"\n#endif\n#endif\n#if !defined(LZO_ARCH_ARM_THUMB2)\n#if (LZO_ARCH_ARM)\n#  if defined(__ARM_ARCH_ISA_THUMB)\n#   if ((__ARM_ARCH_ISA_THUMB)+0 >= 2)\n#    define LZO_ARCH_ARM_THUMB2     1\n#   endif\n#  elif 1 && defined(__thumb2__)\n#    define LZO_ARCH_ARM_THUMB2     1\n#  elif 1 && defined(__TARGET_ARCH_THUMB) && ((__TARGET_ARCH_THUMB)+0 >= 4)\n#    define LZO_ARCH_ARM_THUMB2     1\n#  endif\n#endif\n#endif\n#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_DOS32 || LZO_OS_OS2)\n#  error \"FIXME - missing define for CPU architecture\"\n#endif\n#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN32)\n#  error \"FIXME - missing LZO_OS_WIN32 define for CPU architecture\"\n#endif\n#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN64)\n#  error \"FIXME - missing LZO_OS_WIN64 define for CPU architecture\"\n#endif\n#if (LZO_OS_OS216 || LZO_OS_WIN16)\n#  define LZO_ARCH_I086PM           1\n#elif 1 && (LZO_OS_DOS16 && defined(BLX286))\n#  define LZO_ARCH_I086PM           1\n#elif 1 && (LZO_OS_DOS16 && defined(DOSX286))\n#  define LZO_ARCH_I086PM           1\n#elif 1 && (LZO_OS_DOS16 && LZO_CC_BORLANDC && defined(__DPMI16__))\n#  define LZO_ARCH_I086PM           1\n#endif\n#if (LZO_ARCH_AMD64 && !LZO_ARCH_X64)\n#  define LZO_ARCH_X64              1\n#elif (!LZO_ARCH_AMD64 && LZO_ARCH_X64) && defined(__LZO_ARCH_OVERRIDE)\n#  define LZO_ARCH_AMD64            1\n#endif\n#if (LZO_ARCH_ARM64 && !LZO_ARCH_AARCH64)\n#  define LZO_ARCH_AARCH64          1\n#elif (!LZO_ARCH_ARM64 && LZO_ARCH_AARCH64) && defined(__LZO_ARCH_OVERRIDE)\n#  define LZO_ARCH_ARM64            1\n#endif\n#if (LZO_ARCH_I386 && !LZO_ARCH_X86)\n#  define LZO_ARCH_X86              1\n#elif (!LZO_ARCH_I386 && LZO_ARCH_X86) && defined(__LZO_ARCH_OVERRIDE)\n#  define LZO_ARCH_I386            1\n#endif\n#if (LZO_ARCH_AMD64 && !LZO_ARCH_X64) || (!LZO_ARCH_AMD64 && LZO_ARCH_X64)\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if (LZO_ARCH_ARM64 && !LZO_ARCH_AARCH64) || (!LZO_ARCH_ARM64 && LZO_ARCH_AARCH64)\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if (LZO_ARCH_I386 && !LZO_ARCH_X86) || (!LZO_ARCH_I386 && LZO_ARCH_X86)\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if (LZO_ARCH_ARM_THUMB1 && !LZO_ARCH_ARM)\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if (LZO_ARCH_ARM_THUMB2 && !LZO_ARCH_ARM)\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if (LZO_ARCH_ARM_THUMB1 && LZO_ARCH_ARM_THUMB2)\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if (LZO_ARCH_I086PM && !LZO_ARCH_I086)\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if (LZO_ARCH_I086)\n#  if (UINT_MAX != LZO_0xffffL)\n#    error \"unexpected configuration - check your compiler defines\"\n#  endif\n#  if (ULONG_MAX != LZO_0xffffffffL)\n#    error \"unexpected configuration - check your compiler defines\"\n#  endif\n#endif\n#if (LZO_ARCH_I386)\n#  if (UINT_MAX != LZO_0xffffL) && defined(__i386_int16__)\n#    error \"unexpected configuration - check your compiler defines\"\n#  endif\n#  if (UINT_MAX != LZO_0xffffffffL) && !defined(__i386_int16__)\n#    error \"unexpected configuration - check your compiler defines\"\n#  endif\n#  if (ULONG_MAX != LZO_0xffffffffL)\n#    error \"unexpected configuration - check your compiler defines\"\n#  endif\n#endif\n#if (LZO_ARCH_AMD64 || LZO_ARCH_I386)\n#  if !defined(LZO_TARGET_FEATURE_SSE2)\n#    if defined(__SSE2__)\n#      define LZO_TARGET_FEATURE_SSE2       1\n#    elif defined(_MSC_VER) && (defined(_M_IX86_FP) && ((_M_IX86_FP)+0 >= 2))\n#      define LZO_TARGET_FEATURE_SSE2       1\n#    elif (LZO_CC_INTELC_MSC || LZO_CC_MSC) && defined(_M_AMD64)\n#      define LZO_TARGET_FEATURE_SSE2       1\n#    endif\n#  endif\n#  if !defined(LZO_TARGET_FEATURE_SSSE3)\n#  if (LZO_TARGET_FEATURE_SSE2)\n#    if defined(__SSSE3__)\n#      define LZO_TARGET_FEATURE_SSSE3      1\n#    elif defined(_MSC_VER) && defined(__AVX__)\n#      define LZO_TARGET_FEATURE_SSSE3      1\n#    endif\n#  endif\n#  endif\n#  if !defined(LZO_TARGET_FEATURE_SSE4_2)\n#  if (LZO_TARGET_FEATURE_SSSE3)\n#    if defined(__SSE4_2__)\n#      define LZO_TARGET_FEATURE_SSE4_2     1\n#    endif\n#  endif\n#  endif\n#  if !defined(LZO_TARGET_FEATURE_AVX)\n#  if (LZO_TARGET_FEATURE_SSSE3)\n#    if defined(__AVX__)\n#      define LZO_TARGET_FEATURE_AVX        1\n#    endif\n#  endif\n#  endif\n#  if !defined(LZO_TARGET_FEATURE_AVX2)\n#  if (LZO_TARGET_FEATURE_AVX)\n#    if defined(__AVX2__)\n#      define LZO_TARGET_FEATURE_AVX2       1\n#    endif\n#  endif\n#  endif\n#endif\n#if (LZO_TARGET_FEATURE_SSSE3 && !(LZO_TARGET_FEATURE_SSE2))\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if (LZO_TARGET_FEATURE_SSE4_2 && !(LZO_TARGET_FEATURE_SSSE3))\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if (LZO_TARGET_FEATURE_AVX && !(LZO_TARGET_FEATURE_SSSE3))\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if (LZO_TARGET_FEATURE_AVX2 && !(LZO_TARGET_FEATURE_AVX))\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if (LZO_ARCH_ARM)\n#  if !defined(LZO_TARGET_FEATURE_NEON)\n#    if defined(__ARM_NEON) && ((__ARM_NEON)+0)\n#      define LZO_TARGET_FEATURE_NEON       1\n#    elif 1 && defined(__ARM_NEON__) && ((__ARM_NEON__)+0)\n#      define LZO_TARGET_FEATURE_NEON       1\n#    elif 1 && defined(__TARGET_FEATURE_NEON) && ((__TARGET_FEATURE_NEON)+0)\n#      define LZO_TARGET_FEATURE_NEON       1\n#    endif\n#  endif\n#elif (LZO_ARCH_ARM64)\n#  if !defined(LZO_TARGET_FEATURE_NEON)\n#    if 1\n#      define LZO_TARGET_FEATURE_NEON       1\n#    endif\n#  endif\n#endif\n#if 0\n#elif !defined(__LZO_MM_OVERRIDE)\n#if (LZO_ARCH_I086)\n#if (UINT_MAX != LZO_0xffffL)\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if defined(__TINY__) || defined(M_I86TM) || defined(_M_I86TM)\n#  define LZO_MM_TINY           1\n#elif defined(__HUGE__) || defined(_HUGE_) || defined(M_I86HM) || defined(_M_I86HM)\n#  define LZO_MM_HUGE           1\n#elif defined(__SMALL__) || defined(M_I86SM) || defined(_M_I86SM) || defined(SMALL_MODEL)\n#  define LZO_MM_SMALL          1\n#elif defined(__MEDIUM__) || defined(M_I86MM) || defined(_M_I86MM)\n#  define LZO_MM_MEDIUM         1\n#elif defined(__COMPACT__) || defined(M_I86CM) || defined(_M_I86CM)\n#  define LZO_MM_COMPACT        1\n#elif defined(__LARGE__) || defined(M_I86LM) || defined(_M_I86LM) || defined(LARGE_MODEL)\n#  define LZO_MM_LARGE          1\n#elif (LZO_CC_AZTECC)\n#  if defined(_LARGE_CODE) && defined(_LARGE_DATA)\n#    define LZO_MM_LARGE        1\n#  elif defined(_LARGE_CODE)\n#    define LZO_MM_MEDIUM       1\n#  elif defined(_LARGE_DATA)\n#    define LZO_MM_COMPACT      1\n#  else\n#    define LZO_MM_SMALL        1\n#  endif\n#elif (LZO_CC_ZORTECHC && defined(__VCM__))\n#  define LZO_MM_LARGE          1\n#else\n#  error \"unknown LZO_ARCH_I086 memory model\"\n#endif\n#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)\n#define LZO_HAVE_MM_HUGE_PTR        1\n#define LZO_HAVE_MM_HUGE_ARRAY      1\n#if (LZO_MM_TINY)\n#  undef LZO_HAVE_MM_HUGE_ARRAY\n#endif\n#if (LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_ZORTECHC)\n#  undef LZO_HAVE_MM_HUGE_PTR\n#  undef LZO_HAVE_MM_HUGE_ARRAY\n#elif (LZO_CC_DMC || LZO_CC_SYMANTECC)\n#  undef LZO_HAVE_MM_HUGE_ARRAY\n#elif (LZO_CC_MSC && defined(_QC))\n#  undef LZO_HAVE_MM_HUGE_ARRAY\n#  if (_MSC_VER < 600)\n#    undef LZO_HAVE_MM_HUGE_PTR\n#  endif\n#elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295))\n#  undef LZO_HAVE_MM_HUGE_ARRAY\n#endif\n#if (LZO_ARCH_I086PM) && !(LZO_HAVE_MM_HUGE_PTR)\n#  if (LZO_OS_DOS16)\n#    error \"unexpected configuration - check your compiler defines\"\n#  elif (LZO_CC_ZORTECHC)\n#  else\n#    error \"unexpected configuration - check your compiler defines\"\n#  endif\n#endif\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n#if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0200))\n   extern void __near __cdecl _AHSHIFT(void);\n#  define LZO_MM_AHSHIFT      ((unsigned) _AHSHIFT)\n#elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)\n   extern void __near __cdecl _AHSHIFT(void);\n#  define LZO_MM_AHSHIFT      ((unsigned) _AHSHIFT)\n#elif (LZO_CC_MSC || LZO_CC_TOPSPEEDC)\n   extern void __near __cdecl _AHSHIFT(void);\n#  define LZO_MM_AHSHIFT      ((unsigned) _AHSHIFT)\n#elif (LZO_CC_TURBOC && (__TURBOC__ >= 0x0295))\n   extern void __near __cdecl _AHSHIFT(void);\n#  define LZO_MM_AHSHIFT      ((unsigned) _AHSHIFT)\n#elif ((LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_TURBOC) && LZO_OS_DOS16)\n#  define LZO_MM_AHSHIFT      12\n#elif (LZO_CC_WATCOMC)\n   extern unsigned char _HShift;\n#  define LZO_MM_AHSHIFT      ((unsigned) _HShift)\n#else\n#  error \"FIXME - implement LZO_MM_AHSHIFT\"\n#endif\n#ifdef __cplusplus\n}\n#endif\n#endif\n#elif (LZO_ARCH_C166)\n#if !defined(__MODEL__)\n#  error \"FIXME - LZO_ARCH_C166 __MODEL__\"\n#elif ((__MODEL__) == 0)\n#  define LZO_MM_SMALL          1\n#elif ((__MODEL__) == 1)\n#  define LZO_MM_SMALL          1\n#elif ((__MODEL__) == 2)\n#  define LZO_MM_LARGE          1\n#elif ((__MODEL__) == 3)\n#  define LZO_MM_TINY           1\n#elif ((__MODEL__) == 4)\n#  define LZO_MM_XTINY          1\n#elif ((__MODEL__) == 5)\n#  define LZO_MM_XSMALL         1\n#else\n#  error \"FIXME - LZO_ARCH_C166 __MODEL__\"\n#endif\n#elif (LZO_ARCH_MCS251)\n#if !defined(__MODEL__)\n#  error \"FIXME - LZO_ARCH_MCS251 __MODEL__\"\n#elif ((__MODEL__) == 0)\n#  define LZO_MM_SMALL          1\n#elif ((__MODEL__) == 2)\n#  define LZO_MM_LARGE          1\n#elif ((__MODEL__) == 3)\n#  define LZO_MM_TINY           1\n#elif ((__MODEL__) == 4)\n#  define LZO_MM_XTINY          1\n#elif ((__MODEL__) == 5)\n#  define LZO_MM_XSMALL         1\n#else\n#  error \"FIXME - LZO_ARCH_MCS251 __MODEL__\"\n#endif\n#elif (LZO_ARCH_MCS51)\n#if !defined(__MODEL__)\n#  error \"FIXME - LZO_ARCH_MCS51 __MODEL__\"\n#elif ((__MODEL__) == 1)\n#  define LZO_MM_SMALL          1\n#elif ((__MODEL__) == 2)\n#  define LZO_MM_LARGE          1\n#elif ((__MODEL__) == 3)\n#  define LZO_MM_TINY           1\n#elif ((__MODEL__) == 4)\n#  define LZO_MM_XTINY          1\n#elif ((__MODEL__) == 5)\n#  define LZO_MM_XSMALL         1\n#else\n#  error \"FIXME - LZO_ARCH_MCS51 __MODEL__\"\n#endif\n#elif (LZO_ARCH_CRAY_PVP)\n#  define LZO_MM_PVP            1\n#else\n#  define LZO_MM_FLAT           1\n#endif\n#if (LZO_MM_COMPACT)\n#  define LZO_INFO_MM           \"compact\"\n#elif (LZO_MM_FLAT)\n#  define LZO_INFO_MM           \"flat\"\n#elif (LZO_MM_HUGE)\n#  define LZO_INFO_MM           \"huge\"\n#elif (LZO_MM_LARGE)\n#  define LZO_INFO_MM           \"large\"\n#elif (LZO_MM_MEDIUM)\n#  define LZO_INFO_MM           \"medium\"\n#elif (LZO_MM_PVP)\n#  define LZO_INFO_MM           \"pvp\"\n#elif (LZO_MM_SMALL)\n#  define LZO_INFO_MM           \"small\"\n#elif (LZO_MM_TINY)\n#  define LZO_INFO_MM           \"tiny\"\n#else\n#  error \"unknown memory model\"\n#endif\n#endif\n#if !defined(__lzo_gnuc_extension__)\n#if (LZO_CC_GNUC >= 0x020800ul)\n#  define __lzo_gnuc_extension__    __extension__\n#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#  define __lzo_gnuc_extension__    __extension__\n#elif (LZO_CC_IBMC >= 600)\n#  define __lzo_gnuc_extension__    __extension__\n#else\n#endif\n#endif\n#if !defined(__lzo_gnuc_extension__)\n#  define __lzo_gnuc_extension__    /*empty*/\n#endif\n#if !defined(lzo_has_builtin)\n#if (LZO_CC_CLANG) && defined(__has_builtin)\n#  define lzo_has_builtin           __has_builtin\n#endif\n#endif\n#if !defined(lzo_has_builtin)\n#  define lzo_has_builtin(x)        0\n#endif\n#if !defined(lzo_has_attribute)\n#if (LZO_CC_CLANG) && defined(__has_attribute)\n#  define lzo_has_attribute         __has_attribute\n#endif\n#endif\n#if !defined(lzo_has_attribute)\n#  define lzo_has_attribute(x)      0\n#endif\n#if !defined(lzo_has_declspec_attribute)\n#if (LZO_CC_CLANG) && defined(__has_declspec_attribute)\n#  define lzo_has_declspec_attribute        __has_declspec_attribute\n#endif\n#endif\n#if !defined(lzo_has_declspec_attribute)\n#  define lzo_has_declspec_attribute(x)     0\n#endif\n#if !defined(lzo_has_feature)\n#if (LZO_CC_CLANG) && defined(__has_feature)\n#  define lzo_has_feature         __has_feature\n#endif\n#endif\n#if !defined(lzo_has_feature)\n#  define lzo_has_feature(x)        0\n#endif\n#if !defined(lzo_has_extension)\n#if (LZO_CC_CLANG) && defined(__has_extension)\n#  define lzo_has_extension         __has_extension\n#elif (LZO_CC_CLANG) && defined(__has_feature)\n#  define lzo_has_extension         __has_feature\n#endif\n#endif\n#if !defined(lzo_has_extension)\n#  define lzo_has_extension         0\n#endif\n#if !defined(LZO_CFG_USE_NEW_STYLE_CASTS) && defined(__cplusplus) && 0\n#  if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020800ul))\n#    define LZO_CFG_USE_NEW_STYLE_CASTS 0\n#  elif (LZO_CC_INTELC && (__INTEL_COMPILER < 1200))\n#    define LZO_CFG_USE_NEW_STYLE_CASTS 0\n#  else\n#    define LZO_CFG_USE_NEW_STYLE_CASTS 1\n#  endif\n#endif\n#if !defined(LZO_CFG_USE_NEW_STYLE_CASTS)\n#  define LZO_CFG_USE_NEW_STYLE_CASTS 0\n#endif\n#if !defined(__cplusplus)\n#  if defined(LZO_CFG_USE_NEW_STYLE_CASTS)\n#    undef LZO_CFG_USE_NEW_STYLE_CASTS\n#  endif\n#  define LZO_CFG_USE_NEW_STYLE_CASTS 0\n#endif\n#if !defined(LZO_REINTERPRET_CAST)\n#  if (LZO_CFG_USE_NEW_STYLE_CASTS)\n#    define LZO_REINTERPRET_CAST(t,e)       (reinterpret_cast<t> (e))\n#  endif\n#endif\n#if !defined(LZO_REINTERPRET_CAST)\n#  define LZO_REINTERPRET_CAST(t,e)         ((t) (e))\n#endif\n#if !defined(LZO_STATIC_CAST)\n#  if (LZO_CFG_USE_NEW_STYLE_CASTS)\n#    define LZO_STATIC_CAST(t,e)            (static_cast<t> (e))\n#  endif\n#endif\n#if !defined(LZO_STATIC_CAST)\n#  define LZO_STATIC_CAST(t,e)              ((t) (e))\n#endif\n#if !defined(LZO_STATIC_CAST2)\n#  define LZO_STATIC_CAST2(t1,t2,e)         LZO_STATIC_CAST(t1, LZO_STATIC_CAST(t2, e))\n#endif\n#if !defined(LZO_UNCONST_CAST)\n#  if (LZO_CFG_USE_NEW_STYLE_CASTS)\n#    define LZO_UNCONST_CAST(t,e)           (const_cast<t> (e))\n#  elif (LZO_HAVE_MM_HUGE_PTR)\n#    define LZO_UNCONST_CAST(t,e)           ((t) (e))\n#  elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#    define LZO_UNCONST_CAST(t,e)           ((t) ((void *) ((lzo_uintptr_t) ((const void *) (e)))))\n#  endif\n#endif\n#if !defined(LZO_UNCONST_CAST)\n#  define LZO_UNCONST_CAST(t,e)             ((t) ((void *) ((const void *) (e))))\n#endif\n#if !defined(LZO_UNCONST_VOLATILE_CAST)\n#  if (LZO_CFG_USE_NEW_STYLE_CASTS)\n#    define LZO_UNCONST_VOLATILE_CAST(t,e)  (const_cast<t> (e))\n#  elif (LZO_HAVE_MM_HUGE_PTR)\n#    define LZO_UNCONST_VOLATILE_CAST(t,e)  ((t) (e))\n#  elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#    define LZO_UNCONST_VOLATILE_CAST(t,e)  ((t) ((volatile void *) ((lzo_uintptr_t) ((volatile const void *) (e)))))\n#  endif\n#endif\n#if !defined(LZO_UNCONST_VOLATILE_CAST)\n#  define LZO_UNCONST_VOLATILE_CAST(t,e)    ((t) ((volatile void *) ((volatile const void *) (e))))\n#endif\n#if !defined(LZO_UNVOLATILE_CAST)\n#  if (LZO_CFG_USE_NEW_STYLE_CASTS)\n#    define LZO_UNVOLATILE_CAST(t,e)        (const_cast<t> (e))\n#  elif (LZO_HAVE_MM_HUGE_PTR)\n#    define LZO_UNVOLATILE_CAST(t,e)        ((t) (e))\n#  elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#    define LZO_UNVOLATILE_CAST(t,e)        ((t) ((void *) ((lzo_uintptr_t) ((volatile void *) (e)))))\n#  endif\n#endif\n#if !defined(LZO_UNVOLATILE_CAST)\n#  define LZO_UNVOLATILE_CAST(t,e)          ((t) ((void *) ((volatile void *) (e))))\n#endif\n#if !defined(LZO_UNVOLATILE_CONST_CAST)\n#  if (LZO_CFG_USE_NEW_STYLE_CASTS)\n#    define LZO_UNVOLATILE_CONST_CAST(t,e)  (const_cast<t> (e))\n#  elif (LZO_HAVE_MM_HUGE_PTR)\n#    define LZO_UNVOLATILE_CONST_CAST(t,e)  ((t) (e))\n#  elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#    define LZO_UNVOLATILE_CONST_CAST(t,e)  ((t) ((const void *) ((lzo_uintptr_t) ((volatile const void *) (e)))))\n#  endif\n#endif\n#if !defined(LZO_UNVOLATILE_CONST_CAST)\n#  define LZO_UNVOLATILE_CONST_CAST(t,e)    ((t) ((const void *) ((volatile const void *) (e))))\n#endif\n#if !defined(LZO_PCAST)\n#  if (LZO_HAVE_MM_HUGE_PTR)\n#    define LZO_PCAST(t,e)                  ((t) (e))\n#  endif\n#endif\n#if !defined(LZO_PCAST)\n#  define LZO_PCAST(t,e)                    LZO_STATIC_CAST(t, LZO_STATIC_CAST(void *, e))\n#endif\n#if !defined(LZO_CCAST)\n#  if (LZO_HAVE_MM_HUGE_PTR)\n#    define LZO_CCAST(t,e)                  ((t) (e))\n#  endif\n#endif\n#if !defined(LZO_CCAST)\n#  define LZO_CCAST(t,e)                    LZO_STATIC_CAST(t, LZO_STATIC_CAST(const void *, e))\n#endif\n#if !defined(LZO_ICONV)\n#  define LZO_ICONV(t,e)                    LZO_STATIC_CAST(t, e)\n#endif\n#if !defined(LZO_ICAST)\n#  define LZO_ICAST(t,e)                    LZO_STATIC_CAST(t, e)\n#endif\n#if !defined(LZO_ITRUNC)\n#  define LZO_ITRUNC(t,e)                   LZO_STATIC_CAST(t, e)\n#endif\n#if !defined(__lzo_cte)\n#  if (LZO_CC_MSC || LZO_CC_WATCOMC)\n#    define __lzo_cte(e)            ((void)0,(e))\n#  elif 1\n#    define __lzo_cte(e)            ((void)0,(e))\n#  endif\n#endif\n#if !defined(__lzo_cte)\n#  define __lzo_cte(e)              (e)\n#endif\n#if !defined(LZO_BLOCK_BEGIN)\n#  define LZO_BLOCK_BEGIN           do {\n#  define LZO_BLOCK_END             } while __lzo_cte(0)\n#endif\n#if !defined(LZO_UNUSED)\n#  if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600))\n#    define LZO_UNUSED(var)         ((void) &var)\n#  elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC)\n#    define LZO_UNUSED(var)         if (&var) ; else\n#  elif (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x030200ul))\n#    define LZO_UNUSED(var)         ((void) &var)\n#  elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#    define LZO_UNUSED(var)         ((void) var)\n#  elif (LZO_CC_MSC && (_MSC_VER < 900))\n#    define LZO_UNUSED(var)         if (&var) ; else\n#  elif (LZO_CC_KEILC)\n#    define LZO_UNUSED(var)         {extern int lzo_unused__[1-2*!(sizeof(var)>0)]; (void)lzo_unused__;}\n#  elif (LZO_CC_PACIFICC)\n#    define LZO_UNUSED(var)         ((void) sizeof(var))\n#  elif (LZO_CC_WATCOMC) && defined(__cplusplus)\n#    define LZO_UNUSED(var)         ((void) var)\n#  else\n#    define LZO_UNUSED(var)         ((void) &var)\n#  endif\n#endif\n#if !defined(LZO_UNUSED_FUNC)\n#  if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600))\n#    define LZO_UNUSED_FUNC(func)   ((void) func)\n#  elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC)\n#    define LZO_UNUSED_FUNC(func)   if (func) ; else\n#  elif (LZO_CC_CLANG || LZO_CC_LLVM)\n#    define LZO_UNUSED_FUNC(func)   ((void) &func)\n#  elif (LZO_CC_MSC && (_MSC_VER < 900))\n#    define LZO_UNUSED_FUNC(func)   if (func) ; else\n#  elif (LZO_CC_MSC)\n#    define LZO_UNUSED_FUNC(func)   ((void) &func)\n#  elif (LZO_CC_KEILC || LZO_CC_PELLESC)\n#    define LZO_UNUSED_FUNC(func)   {extern int lzo_unused__[1-2*!(sizeof((int)func)>0)]; (void)lzo_unused__;}\n#  else\n#    define LZO_UNUSED_FUNC(func)   ((void) func)\n#  endif\n#endif\n#if !defined(LZO_UNUSED_LABEL)\n#  if (LZO_CC_CLANG >= 0x020800ul)\n#    define LZO_UNUSED_LABEL(l)     (__lzo_gnuc_extension__ ((void) ((const void *) &&l)))\n#  elif (LZO_CC_ARMCC || LZO_CC_CLANG || LZO_CC_INTELC || LZO_CC_WATCOMC)\n#    define LZO_UNUSED_LABEL(l)     if __lzo_cte(0) goto l\n#  else\n#    define LZO_UNUSED_LABEL(l)     switch (0) case 1:goto l\n#  endif\n#endif\n#if !defined(LZO_DEFINE_UNINITIALIZED_VAR)\n#  if 0\n#    define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init)  type var\n#  elif 0 && (LZO_CC_GNUC)\n#    define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init)  type var = var\n#  else\n#    define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init)  type var = init\n#  endif\n#endif\n#if !defined(__lzo_inline)\n#if (LZO_CC_TURBOC && (__TURBOC__ <= 0x0295))\n#elif defined(__cplusplus)\n#  define __lzo_inline          inline\n#elif defined(__STDC_VERSION__) && (__STDC_VERSION__-0 >= 199901L)\n#  define __lzo_inline          inline\n#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550))\n#  define __lzo_inline          __inline\n#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)\n#  define __lzo_inline          __inline__\n#elif (LZO_CC_DMC)\n#  define __lzo_inline          __inline\n#elif (LZO_CC_GHS)\n#  define __lzo_inline          __inline__\n#elif (LZO_CC_IBMC >= 600)\n#  define __lzo_inline          __inline__\n#elif (LZO_CC_INTELC)\n#  define __lzo_inline          __inline\n#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x2405))\n#  define __lzo_inline          __inline\n#elif (LZO_CC_MSC && (_MSC_VER >= 900))\n#  define __lzo_inline          __inline\n#elif (LZO_CC_SUNPROC >= 0x5100)\n#  define __lzo_inline          __inline__\n#endif\n#endif\n#if defined(__lzo_inline)\n#  ifndef __lzo_HAVE_inline\n#  define __lzo_HAVE_inline 1\n#  endif\n#else\n#  define __lzo_inline          /*empty*/\n#endif\n#if !defined(__lzo_forceinline)\n#if (LZO_CC_GNUC >= 0x030200ul)\n#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))\n#elif (LZO_CC_IBMC >= 700)\n#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))\n#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 450))\n#  define __lzo_forceinline     __forceinline\n#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 800))\n#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))\n#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))\n#elif (LZO_CC_MSC && (_MSC_VER >= 1200))\n#  define __lzo_forceinline     __forceinline\n#elif (LZO_CC_PGI >= 0x0d0a00ul)\n#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))\n#elif (LZO_CC_SUNPROC >= 0x5100)\n#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))\n#endif\n#endif\n#if defined(__lzo_forceinline)\n#  ifndef __lzo_HAVE_forceinline\n#  define __lzo_HAVE_forceinline 1\n#  endif\n#else\n#  define __lzo_forceinline     __lzo_inline\n#endif\n#if !defined(__lzo_noinline)\n#if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul)\n#  define __lzo_noinline        __attribute__((__noinline__,__used__))\n#elif (LZO_CC_GNUC >= 0x030200ul)\n#  define __lzo_noinline        __attribute__((__noinline__))\n#elif (LZO_CC_IBMC >= 700)\n#  define __lzo_noinline        __attribute__((__noinline__))\n#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 600))\n#  define __lzo_noinline        __declspec(noinline)\n#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 800))\n#  define __lzo_noinline        __attribute__((__noinline__))\n#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#  define __lzo_noinline        __attribute__((__noinline__))\n#elif (LZO_CC_MSC && (_MSC_VER >= 1300))\n#  define __lzo_noinline        __declspec(noinline)\n#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x3200) && (LZO_OS_WIN32 || LZO_OS_WIN64))\n#  if defined(__cplusplus)\n#  else\n#    define __lzo_noinline      __declspec(noinline)\n#  endif\n#elif (LZO_CC_PGI >= 0x0d0a00ul)\n#  define __lzo_noinline        __attribute__((__noinline__))\n#elif (LZO_CC_SUNPROC >= 0x5100)\n#  define __lzo_noinline        __attribute__((__noinline__))\n#endif\n#endif\n#if defined(__lzo_noinline)\n#  ifndef __lzo_HAVE_noinline\n#  define __lzo_HAVE_noinline 1\n#  endif\n#else\n#  define __lzo_noinline        /*empty*/\n#endif\n#if (__lzo_HAVE_forceinline || __lzo_HAVE_noinline) && !(__lzo_HAVE_inline)\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if !defined(__lzo_static_inline)\n#if (LZO_CC_IBMC)\n#  define __lzo_static_inline       __lzo_gnuc_extension__ static __lzo_inline\n#endif\n#endif\n#if !defined(__lzo_static_inline)\n#  define __lzo_static_inline       static __lzo_inline\n#endif\n#if !defined(__lzo_static_forceinline)\n#if (LZO_CC_IBMC)\n#  define __lzo_static_forceinline  __lzo_gnuc_extension__ static __lzo_forceinline\n#endif\n#endif\n#if !defined(__lzo_static_forceinline)\n#  define __lzo_static_forceinline  static __lzo_forceinline\n#endif\n#if !defined(__lzo_static_noinline)\n#if (LZO_CC_IBMC)\n#  define __lzo_static_noinline     __lzo_gnuc_extension__ static __lzo_noinline\n#endif\n#endif\n#if !defined(__lzo_static_noinline)\n#  define __lzo_static_noinline     static __lzo_noinline\n#endif\n#if !defined(__lzo_c99_extern_inline)\n#if defined(__GNUC_GNU_INLINE__)\n#  define __lzo_c99_extern_inline   __lzo_inline\n#elif defined(__GNUC_STDC_INLINE__)\n#  define __lzo_c99_extern_inline   extern __lzo_inline\n#elif defined(__STDC_VERSION__) && (__STDC_VERSION__-0 >= 199901L)\n#  define __lzo_c99_extern_inline   extern __lzo_inline\n#endif\n#if !defined(__lzo_c99_extern_inline) && (__lzo_HAVE_inline)\n#  define __lzo_c99_extern_inline   __lzo_inline\n#endif\n#endif\n#if defined(__lzo_c99_extern_inline)\n#  ifndef __lzo_HAVE_c99_extern_inline\n#  define __lzo_HAVE_c99_extern_inline 1\n#  endif\n#else\n#  define __lzo_c99_extern_inline   /*empty*/\n#endif\n#if !defined(__lzo_may_alias)\n#if (LZO_CC_GNUC >= 0x030400ul)\n#  define __lzo_may_alias       __attribute__((__may_alias__))\n#elif (LZO_CC_CLANG >= 0x020900ul)\n#  define __lzo_may_alias       __attribute__((__may_alias__))\n#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 1210)) && 0\n#  define __lzo_may_alias       __attribute__((__may_alias__))\n#elif (LZO_CC_PGI >= 0x0d0a00ul) && 0\n#  define __lzo_may_alias       __attribute__((__may_alias__))\n#endif\n#endif\n#if defined(__lzo_may_alias)\n#  ifndef __lzo_HAVE_may_alias\n#  define __lzo_HAVE_may_alias 1\n#  endif\n#else\n#  define __lzo_may_alias       /*empty*/\n#endif\n#if !defined(__lzo_noreturn)\n#if (LZO_CC_GNUC >= 0x020700ul)\n#  define __lzo_noreturn        __attribute__((__noreturn__))\n#elif (LZO_CC_IBMC >= 700)\n#  define __lzo_noreturn        __attribute__((__noreturn__))\n#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 450))\n#  define __lzo_noreturn        __declspec(noreturn)\n#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 600))\n#  define __lzo_noreturn        __attribute__((__noreturn__))\n#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#  define __lzo_noreturn        __attribute__((__noreturn__))\n#elif (LZO_CC_MSC && (_MSC_VER >= 1200))\n#  define __lzo_noreturn        __declspec(noreturn)\n#elif (LZO_CC_PGI >= 0x0d0a00ul)\n#  define __lzo_noreturn        __attribute__((__noreturn__))\n#endif\n#endif\n#if defined(__lzo_noreturn)\n#  ifndef __lzo_HAVE_noreturn\n#  define __lzo_HAVE_noreturn 1\n#  endif\n#else\n#  define __lzo_noreturn        /*empty*/\n#endif\n#if !defined(__lzo_nothrow)\n#if (LZO_CC_GNUC >= 0x030300ul)\n#  define __lzo_nothrow         __attribute__((__nothrow__))\n#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 450)) && defined(__cplusplus)\n#  define __lzo_nothrow         __declspec(nothrow)\n#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 900))\n#  define __lzo_nothrow         __attribute__((__nothrow__))\n#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#  define __lzo_nothrow         __attribute__((__nothrow__))\n#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus)\n#  define __lzo_nothrow         __declspec(nothrow)\n#endif\n#endif\n#if defined(__lzo_nothrow)\n#  ifndef __lzo_HAVE_nothrow\n#  define __lzo_HAVE_nothrow 1\n#  endif\n#else\n#  define __lzo_nothrow         /*empty*/\n#endif\n#if !defined(__lzo_restrict)\n#if (LZO_CC_GNUC >= 0x030400ul)\n#  define __lzo_restrict        __restrict__\n#elif (LZO_CC_IBMC >= 800) && !defined(__cplusplus)\n#  define __lzo_restrict        __restrict__\n#elif (LZO_CC_IBMC >= 1210)\n#  define __lzo_restrict        __restrict__\n#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 600))\n#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 600))\n#  define __lzo_restrict        __restrict__\n#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM)\n#  define __lzo_restrict        __restrict__\n#elif (LZO_CC_MSC && (_MSC_VER >= 1400))\n#  define __lzo_restrict        __restrict\n#elif (LZO_CC_PGI >= 0x0d0a00ul)\n#  define __lzo_restrict        __restrict__\n#endif\n#endif\n#if defined(__lzo_restrict)\n#  ifndef __lzo_HAVE_restrict\n#  define __lzo_HAVE_restrict 1\n#  endif\n#else\n#  define __lzo_restrict        /*empty*/\n#endif\n#if !defined(__lzo_alignof)\n#if (LZO_CC_ARMCC || LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)\n#  define __lzo_alignof(e)      __alignof__(e)\n#elif (LZO_CC_GHS) && !defined(__cplusplus)\n#  define __lzo_alignof(e)      __alignof__(e)\n#elif (LZO_CC_IBMC >= 600)\n#  define __lzo_alignof(e)      (__lzo_gnuc_extension__ __alignof__(e))\n#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700))\n#  define __lzo_alignof(e)      __alignof__(e)\n#elif (LZO_CC_MSC && (_MSC_VER >= 1300))\n#  define __lzo_alignof(e)      __alignof(e)\n#elif (LZO_CC_SUNPROC >= 0x5100)\n#  define __lzo_alignof(e)      __alignof__(e)\n#endif\n#endif\n#if defined(__lzo_alignof)\n#  ifndef __lzo_HAVE_alignof\n#  define __lzo_HAVE_alignof 1\n#  endif\n#endif\n#if !defined(__lzo_struct_packed)\n#if   (LZO_CC_CLANG && (LZO_CC_CLANG < 0x020800ul)) && defined(__cplusplus)\n#elif (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020700ul))\n#elif (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020800ul)) && defined(__cplusplus)\n#elif (LZO_CC_PCC && (LZO_CC_PCC < 0x010100ul))\n#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC < 0x5110)) && !defined(__cplusplus)\n#elif (LZO_CC_GNUC >= 0x030400ul) && !(LZO_CC_PCC_GNUC) && (LZO_ARCH_AMD64 || LZO_ARCH_I386)\n#  define __lzo_struct_packed(s)        struct s {\n#  define __lzo_struct_packed_end()     } __attribute__((__gcc_struct__,__packed__));\n#  define __lzo_struct_packed_ma_end()  } __lzo_may_alias __attribute__((__gcc_struct__,__packed__));\n#elif (LZO_CC_ARMCC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || (LZO_CC_PGI >= 0x0d0a00ul) || (LZO_CC_SUNPROC >= 0x5100))\n#  define __lzo_struct_packed(s)        struct s {\n#  define __lzo_struct_packed_end()     } __attribute__((__packed__));\n#  define __lzo_struct_packed_ma_end()  } __lzo_may_alias __attribute__((__packed__));\n#elif (LZO_CC_IBMC >= 700)\n#  define __lzo_struct_packed(s)        __lzo_gnuc_extension__ struct s {\n#  define __lzo_struct_packed_end()     } __attribute__((__packed__));\n#  define __lzo_struct_packed_ma_end()  } __lzo_may_alias __attribute__((__packed__));\n#elif (LZO_CC_INTELC_MSC) || (LZO_CC_MSC && (_MSC_VER >= 1300))\n#  define __lzo_struct_packed(s)        __pragma(pack(push,1)) struct s {\n#  define __lzo_struct_packed_end()     } __pragma(pack(pop));\n#elif (LZO_CC_WATCOMC && (__WATCOMC__ >= 900))\n#  define __lzo_struct_packed(s)        _Packed struct s {\n#  define __lzo_struct_packed_end()     };\n#endif\n#endif\n#if defined(__lzo_struct_packed) && !defined(__lzo_struct_packed_ma)\n#  define __lzo_struct_packed_ma(s)     __lzo_struct_packed(s)\n#endif\n#if defined(__lzo_struct_packed_end) && !defined(__lzo_struct_packed_ma_end)\n#  define __lzo_struct_packed_ma_end()  __lzo_struct_packed_end()\n#endif\n#if !defined(__lzo_byte_struct)\n#if defined(__lzo_struct_packed)\n#  define __lzo_byte_struct(s,n)        __lzo_struct_packed(s) unsigned char a[n]; __lzo_struct_packed_end()\n#  define __lzo_byte_struct_ma(s,n)     __lzo_struct_packed_ma(s) unsigned char a[n]; __lzo_struct_packed_ma_end()\n#elif (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_PGI || (LZO_CC_SUNPROC >= 0x5100))\n#  define __lzo_byte_struct(s,n)        struct s { unsigned char a[n]; } __attribute__((__packed__));\n#  define __lzo_byte_struct_ma(s,n)     struct s { unsigned char a[n]; } __lzo_may_alias __attribute__((__packed__));\n#endif\n#endif\n#if defined(__lzo_byte_struct) &&  !defined(__lzo_byte_struct_ma)\n#  define __lzo_byte_struct_ma(s,n)     __lzo_byte_struct(s,n)\n#endif\n#if !defined(__lzo_struct_align16) && (__lzo_HAVE_alignof)\n#if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x030000ul))\n#elif (LZO_CC_CLANG && (LZO_CC_CLANG < 0x020800ul)) && defined(__cplusplus)\n#elif (LZO_CC_CILLY || LZO_CC_PCC)\n#elif (LZO_CC_INTELC_MSC) || (LZO_CC_MSC && (_MSC_VER >= 1300))\n#  define __lzo_struct_align16(s)       struct __declspec(align(16)) s {\n#  define __lzo_struct_align16_end()    };\n#  define __lzo_struct_align32(s)       struct __declspec(align(32)) s {\n#  define __lzo_struct_align32_end()    };\n#  define __lzo_struct_align64(s)       struct __declspec(align(64)) s {\n#  define __lzo_struct_align64_end()    };\n#elif (LZO_CC_ARMCC || LZO_CC_CLANG || LZO_CC_GNUC || (LZO_CC_IBMC >= 700) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#  define __lzo_struct_align16(s)       struct s {\n#  define __lzo_struct_align16_end()    } __attribute__((__aligned__(16)));\n#  define __lzo_struct_align32(s)       struct s {\n#  define __lzo_struct_align32_end()    } __attribute__((__aligned__(32)));\n#  define __lzo_struct_align64(s)       struct s {\n#  define __lzo_struct_align64_end()    } __attribute__((__aligned__(64)));\n#endif\n#endif\n#if !defined(__lzo_union_um)\n#if   (LZO_CC_CLANG && (LZO_CC_CLANG < 0x020800ul)) && defined(__cplusplus)\n#elif (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020700ul))\n#elif (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020800ul)) && defined(__cplusplus)\n#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER < 810))\n#elif (LZO_CC_PCC && (LZO_CC_PCC < 0x010100ul))\n#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC < 0x5110)) && !defined(__cplusplus)\n#elif (LZO_CC_ARMCC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || (LZO_CC_PGI >= 0x0d0a00ul) || (LZO_CC_SUNPROC >= 0x5100))\n#  define __lzo_union_am(s)             union s {\n#  define __lzo_union_am_end()          } __lzo_may_alias;\n#  define __lzo_union_um(s)             union s {\n#  define __lzo_union_um_end()          } __lzo_may_alias __attribute__((__packed__));\n#elif (LZO_CC_IBMC >= 700)\n#  define __lzo_union_am(s)             __lzo_gnuc_extension__ union s {\n#  define __lzo_union_am_end()          } __lzo_may_alias;\n#  define __lzo_union_um(s)             __lzo_gnuc_extension__ union s {\n#  define __lzo_union_um_end()          } __lzo_may_alias __attribute__((__packed__));\n#elif (LZO_CC_INTELC_MSC) || (LZO_CC_MSC && (_MSC_VER >= 1300))\n#  define __lzo_union_um(s)             __pragma(pack(push,1)) union s {\n#  define __lzo_union_um_end()          } __pragma(pack(pop));\n#elif (LZO_CC_WATCOMC && (__WATCOMC__ >= 900))\n#  define __lzo_union_um(s)             _Packed union s {\n#  define __lzo_union_um_end()          };\n#endif\n#endif\n#if !defined(__lzo_union_am)\n#  define __lzo_union_am(s)             union s {\n#  define __lzo_union_am_end()          };\n#endif\n#if !defined(__lzo_constructor)\n#if (LZO_CC_GNUC >= 0x030400ul)\n#  define __lzo_constructor     __attribute__((__constructor__,__used__))\n#elif (LZO_CC_GNUC >= 0x020700ul)\n#  define __lzo_constructor     __attribute__((__constructor__))\n#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 800))\n#  define __lzo_constructor     __attribute__((__constructor__,__used__))\n#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#  define __lzo_constructor     __attribute__((__constructor__))\n#endif\n#endif\n#if defined(__lzo_constructor)\n#  ifndef __lzo_HAVE_constructor\n#  define __lzo_HAVE_constructor 1\n#  endif\n#endif\n#if !defined(__lzo_destructor)\n#if (LZO_CC_GNUC >= 0x030400ul)\n#  define __lzo_destructor      __attribute__((__destructor__,__used__))\n#elif (LZO_CC_GNUC >= 0x020700ul)\n#  define __lzo_destructor      __attribute__((__destructor__))\n#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 800))\n#  define __lzo_destructor      __attribute__((__destructor__,__used__))\n#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#  define __lzo_destructor      __attribute__((__destructor__))\n#endif\n#endif\n#if defined(__lzo_destructor)\n#  ifndef __lzo_HAVE_destructor\n#  define __lzo_HAVE_destructor 1\n#  endif\n#endif\n#if (__lzo_HAVE_destructor) && !(__lzo_HAVE_constructor)\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if !defined(__lzo_likely) && !defined(__lzo_unlikely)\n#if (LZO_CC_GNUC >= 0x030200ul)\n#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))\n#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))\n#elif (LZO_CC_IBMC >= 1010)\n#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))\n#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))\n#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800))\n#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))\n#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))\n#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))\n#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))\n#endif\n#endif\n#if defined(__lzo_likely)\n#  ifndef __lzo_HAVE_likely\n#  define __lzo_HAVE_likely 1\n#  endif\n#else\n#  define __lzo_likely(e)           (e)\n#endif\n#if defined(__lzo_very_likely)\n#  ifndef __lzo_HAVE_very_likely\n#  define __lzo_HAVE_very_likely 1\n#  endif\n#else\n#  define __lzo_very_likely(e)      __lzo_likely(e)\n#endif\n#if defined(__lzo_unlikely)\n#  ifndef __lzo_HAVE_unlikely\n#  define __lzo_HAVE_unlikely 1\n#  endif\n#else\n#  define __lzo_unlikely(e)         (e)\n#endif\n#if defined(__lzo_very_unlikely)\n#  ifndef __lzo_HAVE_very_unlikely\n#  define __lzo_HAVE_very_unlikely 1\n#  endif\n#else\n#  define __lzo_very_unlikely(e)    __lzo_unlikely(e)\n#endif\n#if !defined(__lzo_loop_forever)\n#  if (LZO_CC_IBMC)\n#    define __lzo_loop_forever()    LZO_BLOCK_BEGIN for (;;) { ; } LZO_BLOCK_END\n#  else\n#    define __lzo_loop_forever()    do { ; } while __lzo_cte(1)\n#  endif\n#endif\n#if !defined(__lzo_unreachable)\n#if (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x020800ul)) && lzo_has_builtin(__builtin_unreachable)\n#  define __lzo_unreachable()       __builtin_unreachable();\n#elif (LZO_CC_GNUC >= 0x040500ul)\n#  define __lzo_unreachable()       __builtin_unreachable();\n#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 1300)) && 1\n#  define __lzo_unreachable()       __builtin_unreachable();\n#endif\n#endif\n#if defined(__lzo_unreachable)\n#  ifndef __lzo_HAVE_unreachable\n#  define __lzo_HAVE_unreachable 1\n#  endif\n#else\n#  if 0\n#  define __lzo_unreachable()       ((void)0);\n#  else\n#  define __lzo_unreachable()       __lzo_loop_forever();\n#  endif\n#endif\n#if !defined(lzo_unused_funcs_impl)\n#  if 1 && (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)\n#    define lzo_unused_funcs_impl(r,f)  static r __attribute__((__unused__)) f\n#  elif 1 && (LZO_CC_BORLANDC || LZO_CC_GNUC)\n#    define lzo_unused_funcs_impl(r,f)  static r f\n#  else\n#    define lzo_unused_funcs_impl(r,f)  __lzo_static_forceinline r f\n#  endif\n#endif\n#ifndef __LZO_CTA_NAME\n#if (LZO_CFG_USE_COUNTER)\n#  define __LZO_CTA_NAME(a)         LZO_PP_ECONCAT2(a,__COUNTER__)\n#else\n#  define __LZO_CTA_NAME(a)         LZO_PP_ECONCAT2(a,__LINE__)\n#endif\n#endif\n#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER)\n#  if (LZO_CC_AZTECC || LZO_CC_ZORTECHC)\n#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  LZO_EXTERN_C_BEGIN extern int __LZO_CTA_NAME(lzo_cta__)[1-!(e)]; LZO_EXTERN_C_END\n#  elif (LZO_CC_DMC || LZO_CC_SYMANTECC)\n#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  LZO_EXTERN_C_BEGIN extern int __LZO_CTA_NAME(lzo_cta__)[1u-2*!(e)]; LZO_EXTERN_C_END\n#  elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295))\n#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  LZO_EXTERN_C_BEGIN extern int __LZO_CTA_NAME(lzo_cta__)[1-!(e)]; LZO_EXTERN_C_END\n#  elif (LZO_CC_CLANG && (LZO_CC_CLANG < 0x020900ul)) && defined(__cplusplus)\n#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  LZO_EXTERN_C_BEGIN int __LZO_CTA_NAME(lzo_cta_f__)(int [1-2*!(e)]); LZO_EXTERN_C_END\n#  elif (LZO_CC_GNUC) && defined(__CHECKER__) && defined(__SPARSE_CHECKER__)\n#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  LZO_EXTERN_C_BEGIN enum {__LZO_CTA_NAME(lzo_cta_e__)=1/!!(e)} __attribute__((__unused__)); LZO_EXTERN_C_END\n#  else\n#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  LZO_EXTERN_C_BEGIN extern int __LZO_CTA_NAME(lzo_cta__)[1-2*!(e)]; LZO_EXTERN_C_END\n#  endif\n#endif\n#if !defined(LZO_COMPILE_TIME_ASSERT)\n#  if (LZO_CC_AZTECC)\n#    define LZO_COMPILE_TIME_ASSERT(e)  {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-!(e)];}\n#  elif (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x030000ul))\n#    define LZO_COMPILE_TIME_ASSERT(e)  {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-2*!(e)] __attribute__((__unused__));}\n#  elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)\n#    define LZO_COMPILE_TIME_ASSERT(e)  switch(0) case 1:case !(e):break;\n#  elif (LZO_CC_GNUC) && defined(__CHECKER__) && defined(__SPARSE_CHECKER__)\n#    define LZO_COMPILE_TIME_ASSERT(e)  {(void) (0/!!(e));}\n#  elif (LZO_CC_GNUC >= 0x040700ul) && (LZO_CFG_USE_COUNTER) && defined(__cplusplus)\n#    define LZO_COMPILE_TIME_ASSERT(e)  {enum {__LZO_CTA_NAME(lzo_cta_e__)=1/!!(e)} __attribute__((__unused__));}\n#  elif (LZO_CC_GNUC >= 0x040700ul)\n#    define LZO_COMPILE_TIME_ASSERT(e)  {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-2*!(e)] __attribute__((__unused__));}\n#  elif (LZO_CC_MSC && (_MSC_VER < 900))\n#    define LZO_COMPILE_TIME_ASSERT(e)  switch(0) case 1:case !(e):break;\n#  elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295))\n#    define LZO_COMPILE_TIME_ASSERT(e)  switch(0) case 1:case !(e):break;\n#  else\n#    define LZO_COMPILE_TIME_ASSERT(e)  {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-2*!(e)];}\n#  endif\n#endif\nLZO_COMPILE_TIME_ASSERT_HEADER(1 == 1)\n#if defined(__cplusplus)\nextern \"C\" { LZO_COMPILE_TIME_ASSERT_HEADER(2 == 2) }\n#endif\nLZO_COMPILE_TIME_ASSERT_HEADER(3 == 3)\n#if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64)\n#  if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC)\n#  elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)\n#    define __lzo_cdecl                 __cdecl\n#    define __lzo_cdecl_atexit          /*empty*/\n#    define __lzo_cdecl_main            __cdecl\n#    if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC))\n#      define __lzo_cdecl_qsort         __pascal\n#    elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC))\n#      define __lzo_cdecl_qsort         _stdcall\n#    else\n#      define __lzo_cdecl_qsort         __cdecl\n#    endif\n#  elif (LZO_CC_WATCOMC)\n#    define __lzo_cdecl                 __cdecl\n#  else\n#    define __lzo_cdecl                 __cdecl\n#    define __lzo_cdecl_atexit          __cdecl\n#    define __lzo_cdecl_main            __cdecl\n#    define __lzo_cdecl_qsort           __cdecl\n#  endif\n#  if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC || LZO_CC_WATCOMC)\n#  elif (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC))\n#    define __lzo_cdecl_sighandler      __pascal\n#  elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC))\n#    define __lzo_cdecl_sighandler      _stdcall\n#  elif (LZO_CC_MSC && (_MSC_VER >= 1400)) && defined(_M_CEE_PURE)\n#    define __lzo_cdecl_sighandler      __clrcall\n#  elif (LZO_CC_MSC && (_MSC_VER >= 600 && _MSC_VER < 700))\n#    if defined(_DLL)\n#      define __lzo_cdecl_sighandler    _far _cdecl _loadds\n#    elif defined(_MT)\n#      define __lzo_cdecl_sighandler    _far _cdecl\n#    else\n#      define __lzo_cdecl_sighandler    _cdecl\n#    endif\n#  else\n#    define __lzo_cdecl_sighandler      __cdecl\n#  endif\n#elif (LZO_ARCH_I386) && (LZO_CC_WATCOMC)\n#  define __lzo_cdecl                   __cdecl\n#elif (LZO_ARCH_M68K && LZO_OS_TOS && (LZO_CC_PUREC || LZO_CC_TURBOC))\n#  define __lzo_cdecl                   cdecl\n#endif\n#if !defined(__lzo_cdecl)\n#  define __lzo_cdecl                   /*empty*/\n#endif\n#if !defined(__lzo_cdecl_atexit)\n#  define __lzo_cdecl_atexit            /*empty*/\n#endif\n#if !defined(__lzo_cdecl_main)\n#  define __lzo_cdecl_main              /*empty*/\n#endif\n#if !defined(__lzo_cdecl_qsort)\n#  define __lzo_cdecl_qsort             /*empty*/\n#endif\n#if !defined(__lzo_cdecl_sighandler)\n#  define __lzo_cdecl_sighandler        /*empty*/\n#endif\n#if !defined(__lzo_cdecl_va)\n#  define __lzo_cdecl_va                __lzo_cdecl\n#endif\n#if !(LZO_CFG_NO_WINDOWS_H)\n#if !defined(LZO_HAVE_WINDOWS_H)\n#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64)\n#  if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000))\n#  elif ((LZO_OS_WIN32 && defined(__PW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x030000ul)))\n#  elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul)))\n#  else\n#    define LZO_HAVE_WINDOWS_H 1\n#  endif\n#endif\n#endif\n#endif\n#ifndef LZO_SIZEOF_SHORT\n#if defined(SIZEOF_SHORT)\n#  define LZO_SIZEOF_SHORT          (SIZEOF_SHORT)\n#elif defined(__SIZEOF_SHORT__)\n#  define LZO_SIZEOF_SHORT          (__SIZEOF_SHORT__)\n#endif\n#endif\n#ifndef LZO_SIZEOF_INT\n#if defined(SIZEOF_INT)\n#  define LZO_SIZEOF_INT            (SIZEOF_INT)\n#elif defined(__SIZEOF_INT__)\n#  define LZO_SIZEOF_INT            (__SIZEOF_INT__)\n#endif\n#endif\n#ifndef LZO_SIZEOF_LONG\n#if defined(SIZEOF_LONG)\n#  define LZO_SIZEOF_LONG           (SIZEOF_LONG)\n#elif defined(__SIZEOF_LONG__)\n#  define LZO_SIZEOF_LONG           (__SIZEOF_LONG__)\n#endif\n#endif\n#ifndef LZO_SIZEOF_LONG_LONG\n#if defined(SIZEOF_LONG_LONG)\n#  define LZO_SIZEOF_LONG_LONG      (SIZEOF_LONG_LONG)\n#elif defined(__SIZEOF_LONG_LONG__)\n#  define LZO_SIZEOF_LONG_LONG      (__SIZEOF_LONG_LONG__)\n#endif\n#endif\n#ifndef LZO_SIZEOF___INT16\n#if defined(SIZEOF___INT16)\n#  define LZO_SIZEOF___INT16        (SIZEOF___INT16)\n#endif\n#endif\n#ifndef LZO_SIZEOF___INT32\n#if defined(SIZEOF___INT32)\n#  define LZO_SIZEOF___INT32        (SIZEOF___INT32)\n#endif\n#endif\n#ifndef LZO_SIZEOF___INT64\n#if defined(SIZEOF___INT64)\n#  define LZO_SIZEOF___INT64        (SIZEOF___INT64)\n#endif\n#endif\n#ifndef LZO_SIZEOF_VOID_P\n#if defined(SIZEOF_VOID_P)\n#  define LZO_SIZEOF_VOID_P         (SIZEOF_VOID_P)\n#elif defined(__SIZEOF_POINTER__)\n#  define LZO_SIZEOF_VOID_P         (__SIZEOF_POINTER__)\n#endif\n#endif\n#ifndef LZO_SIZEOF_SIZE_T\n#if defined(SIZEOF_SIZE_T)\n#  define LZO_SIZEOF_SIZE_T         (SIZEOF_SIZE_T)\n#elif defined(__SIZEOF_SIZE_T__)\n#  define LZO_SIZEOF_SIZE_T         (__SIZEOF_SIZE_T__)\n#endif\n#endif\n#ifndef LZO_SIZEOF_PTRDIFF_T\n#if defined(SIZEOF_PTRDIFF_T)\n#  define LZO_SIZEOF_PTRDIFF_T      (SIZEOF_PTRDIFF_T)\n#elif defined(__SIZEOF_PTRDIFF_T__)\n#  define LZO_SIZEOF_PTRDIFF_T      (__SIZEOF_PTRDIFF_T__)\n#endif\n#endif\n#define __LZO_LSR(x,b)    (((x)+0ul) >> (b))\n#if !defined(LZO_SIZEOF_SHORT)\n#  if (LZO_ARCH_CRAY_PVP)\n#    define LZO_SIZEOF_SHORT        8\n#  elif (USHRT_MAX == LZO_0xffffL)\n#    define LZO_SIZEOF_SHORT        2\n#  elif (__LZO_LSR(USHRT_MAX,7) == 1)\n#    define LZO_SIZEOF_SHORT        1\n#  elif (__LZO_LSR(USHRT_MAX,15) == 1)\n#    define LZO_SIZEOF_SHORT        2\n#  elif (__LZO_LSR(USHRT_MAX,31) == 1)\n#    define LZO_SIZEOF_SHORT        4\n#  elif (__LZO_LSR(USHRT_MAX,63) == 1)\n#    define LZO_SIZEOF_SHORT        8\n#  elif (__LZO_LSR(USHRT_MAX,127) == 1)\n#    define LZO_SIZEOF_SHORT        16\n#  else\n#    error \"LZO_SIZEOF_SHORT\"\n#  endif\n#endif\nLZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_SHORT == sizeof(short))\n#if !defined(LZO_SIZEOF_INT)\n#  if (LZO_ARCH_CRAY_PVP)\n#    define LZO_SIZEOF_INT          8\n#  elif (UINT_MAX == LZO_0xffffL)\n#    define LZO_SIZEOF_INT          2\n#  elif (UINT_MAX == LZO_0xffffffffL)\n#    define LZO_SIZEOF_INT          4\n#  elif (__LZO_LSR(UINT_MAX,7) == 1)\n#    define LZO_SIZEOF_INT          1\n#  elif (__LZO_LSR(UINT_MAX,15) == 1)\n#    define LZO_SIZEOF_INT          2\n#  elif (__LZO_LSR(UINT_MAX,31) == 1)\n#    define LZO_SIZEOF_INT          4\n#  elif (__LZO_LSR(UINT_MAX,63) == 1)\n#    define LZO_SIZEOF_INT          8\n#  elif (__LZO_LSR(UINT_MAX,127) == 1)\n#    define LZO_SIZEOF_INT          16\n#  else\n#    error \"LZO_SIZEOF_INT\"\n#  endif\n#endif\nLZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_INT == sizeof(int))\n#if !defined(LZO_SIZEOF_LONG)\n#  if (ULONG_MAX == LZO_0xffffffffL)\n#    define LZO_SIZEOF_LONG         4\n#  elif (__LZO_LSR(ULONG_MAX,7) == 1)\n#    define LZO_SIZEOF_LONG         1\n#  elif (__LZO_LSR(ULONG_MAX,15) == 1)\n#    define LZO_SIZEOF_LONG         2\n#  elif (__LZO_LSR(ULONG_MAX,31) == 1)\n#    define LZO_SIZEOF_LONG         4\n#  elif (__LZO_LSR(ULONG_MAX,39) == 1)\n#    define LZO_SIZEOF_LONG         5\n#  elif (__LZO_LSR(ULONG_MAX,63) == 1)\n#    define LZO_SIZEOF_LONG         8\n#  elif (__LZO_LSR(ULONG_MAX,127) == 1)\n#    define LZO_SIZEOF_LONG         16\n#  else\n#    error \"LZO_SIZEOF_LONG\"\n#  endif\n#endif\nLZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_LONG == sizeof(long))\n#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64)\n#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8)\n#  if defined(__LONG_MAX__) && defined(__LONG_LONG_MAX__)\n#    if (LZO_CC_GNUC >= 0x030300ul)\n#      if ((__LONG_MAX__-0) == (__LONG_LONG_MAX__-0))\n#        define LZO_SIZEOF_LONG_LONG      LZO_SIZEOF_LONG\n#      elif (__LZO_LSR(__LONG_LONG_MAX__,30) == 1)\n#        define LZO_SIZEOF_LONG_LONG      4\n#      endif\n#    endif\n#  endif\n#endif\n#endif\n#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64)\n#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8)\n#if (LZO_ARCH_I086 && LZO_CC_DMC)\n#elif (LZO_CC_CILLY) && defined(__GNUC__)\n#  define LZO_SIZEOF_LONG_LONG      8\n#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#  define LZO_SIZEOF_LONG_LONG      8\n#elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400))\n#  define LZO_SIZEOF_LONG_LONG      8\n#elif (LZO_OS_WIN64 || defined(_WIN64))\n#  define LZO_SIZEOF___INT64        8\n#elif (LZO_ARCH_I386 && (LZO_CC_DMC))\n#  define LZO_SIZEOF_LONG_LONG      8\n#elif (LZO_ARCH_I386 && (LZO_CC_SYMANTECC && (__SC__ >= 0x700)))\n#  define LZO_SIZEOF_LONG_LONG      8\n#elif (LZO_ARCH_I386 && (LZO_CC_INTELC && defined(__linux__)))\n#  define LZO_SIZEOF_LONG_LONG      8\n#elif (LZO_ARCH_I386 && (LZO_CC_MWERKS || LZO_CC_PELLESC || LZO_CC_PGI || LZO_CC_SUNPROC))\n#  define LZO_SIZEOF_LONG_LONG      8\n#elif (LZO_ARCH_I386 && (LZO_CC_INTELC || LZO_CC_MSC))\n#  define LZO_SIZEOF___INT64        8\n#elif ((LZO_OS_WIN32 || defined(_WIN32)) && (LZO_CC_MSC))\n#  define LZO_SIZEOF___INT64        8\n#elif (LZO_ARCH_I386 && (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0520)))\n#  define LZO_SIZEOF___INT64        8\n#elif (LZO_ARCH_I386 && (LZO_CC_WATCOMC && (__WATCOMC__ >= 1100)))\n#  define LZO_SIZEOF___INT64        8\n#elif (LZO_CC_GHS && defined(__LLONG_BIT) && ((__LLONG_BIT-0) == 64))\n#  define LZO_SIZEOF_LONG_LONG      8\n#elif (LZO_CC_WATCOMC && defined(_INTEGRAL_MAX_BITS) && ((_INTEGRAL_MAX_BITS-0) == 64))\n#  define LZO_SIZEOF___INT64        8\n#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__)\n#  define LZO_SIZEOF_LONG_LONG      8\n#elif (defined(__vms) || defined(__VMS)) && ((__INITIAL_POINTER_SIZE-0) == 64)\n#  define LZO_SIZEOF_LONG_LONG      8\n#elif (LZO_CC_SDCC) && (LZO_SIZEOF_INT == 2)\n#elif 1 && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)\n#  define LZO_SIZEOF_LONG_LONG      8\n#endif\n#endif\n#endif\n#if defined(__cplusplus) && (LZO_CC_GNUC)\n#  if (LZO_CC_GNUC < 0x020800ul)\n#    undef LZO_SIZEOF_LONG_LONG\n#  endif\n#endif\n#if (LZO_CFG_NO_LONG_LONG)\n#  undef LZO_SIZEOF_LONG_LONG\n#elif defined(__NO_LONG_LONG)\n#  undef LZO_SIZEOF_LONG_LONG\n#elif defined(_NO_LONGLONG)\n#  undef LZO_SIZEOF_LONG_LONG\n#endif\n#if !defined(LZO_WORDSIZE)\n#if (LZO_ARCH_ALPHA)\n#  define LZO_WORDSIZE              8\n#elif (LZO_ARCH_AMD64)\n#  define LZO_WORDSIZE              8\n#elif (LZO_ARCH_AVR)\n#  define LZO_WORDSIZE              1\n#elif (LZO_ARCH_H8300)\n#  if defined(__NORMAL_MODE__)\n#    define LZO_WORDSIZE            4\n#  elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)\n#    define LZO_WORDSIZE            4\n#  else\n#    define LZO_WORDSIZE            2\n#  endif\n#elif (LZO_ARCH_I086)\n#  define LZO_WORDSIZE              2\n#elif (LZO_ARCH_IA64)\n#  define LZO_WORDSIZE              8\n#elif (LZO_ARCH_M16C)\n#  define LZO_WORDSIZE              2\n#elif (LZO_ARCH_SPU)\n#  define LZO_WORDSIZE              4\n#elif (LZO_ARCH_Z80)\n#  define LZO_WORDSIZE              1\n#elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__))\n#  define LZO_WORDSIZE              8\n#elif (LZO_OS_OS400 || defined(__OS400__))\n#  define LZO_WORDSIZE              8\n#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64)\n#  define LZO_WORDSIZE              8\n#endif\n#endif\n#if !defined(LZO_SIZEOF_VOID_P)\n#if defined(__ILP32__) || defined(__ILP32) || defined(_ILP32)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(int)  == 4)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 4)\n#  define LZO_SIZEOF_VOID_P         4\n#elif defined(__ILP64__) || defined(__ILP64) || defined(_ILP64)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(int)  == 8)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 8)\n#  define LZO_SIZEOF_VOID_P         8\n#elif defined(__LLP64__) || defined(__LLP64) || defined(_LLP64) || defined(_WIN64)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 4)\n#  define LZO_SIZEOF_VOID_P         8\n#elif defined(__LP64__) || defined(__LP64) || defined(_LP64)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 8)\n#  define LZO_SIZEOF_VOID_P         8\n#elif (LZO_ARCH_AVR)\n#  define LZO_SIZEOF_VOID_P         2\n#elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430)\n#  define LZO_SIZEOF_VOID_P         2\n#elif (LZO_ARCH_H8300)\n#  if defined(__NORMAL_MODE__)\n#    define LZO_SIZEOF_VOID_P       2\n#  elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)\n#    define LZO_SIZEOF_VOID_P       4\n#  else\n#    define LZO_SIZEOF_VOID_P       2\n#  endif\n#  if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4)\n#    define LZO_SIZEOF_SIZE_T       LZO_SIZEOF_INT\n#    define LZO_SIZEOF_PTRDIFF_T    LZO_SIZEOF_INT\n#  endif\n#elif (LZO_ARCH_I086)\n#  if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM)\n#    define LZO_SIZEOF_VOID_P       2\n#  elif (LZO_MM_COMPACT || LZO_MM_LARGE || LZO_MM_HUGE)\n#    define LZO_SIZEOF_VOID_P       4\n#  else\n#    error \"invalid LZO_ARCH_I086 memory model\"\n#  endif\n#elif (LZO_ARCH_M16C)\n#  if defined(__m32c_cpu__) || defined(__m32cm_cpu__)\n#    define LZO_SIZEOF_VOID_P       4\n#  else\n#    define LZO_SIZEOF_VOID_P       2\n#  endif\n#elif (LZO_ARCH_SPU)\n#  define LZO_SIZEOF_VOID_P         4\n#elif (LZO_ARCH_Z80)\n#  define LZO_SIZEOF_VOID_P         2\n#elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__))\n#  define LZO_SIZEOF_VOID_P         4\n#elif (LZO_OS_OS400 || defined(__OS400__))\n#  if defined(__LLP64_IFC__)\n#    define LZO_SIZEOF_VOID_P       8\n#    define LZO_SIZEOF_SIZE_T       LZO_SIZEOF_LONG\n#    define LZO_SIZEOF_PTRDIFF_T    LZO_SIZEOF_LONG\n#  else\n#    define LZO_SIZEOF_VOID_P       16\n#    define LZO_SIZEOF_SIZE_T       LZO_SIZEOF_LONG\n#    define LZO_SIZEOF_PTRDIFF_T    LZO_SIZEOF_LONG\n#  endif\n#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64)\n#  define LZO_SIZEOF_VOID_P         8\n#  define LZO_SIZEOF_SIZE_T         LZO_SIZEOF_LONG\n#  define LZO_SIZEOF_PTRDIFF_T      LZO_SIZEOF_LONG\n#endif\n#endif\n#if !defined(LZO_SIZEOF_VOID_P)\n#  define LZO_SIZEOF_VOID_P         LZO_SIZEOF_LONG\n#endif\nLZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_VOID_P == sizeof(void *))\n#if !defined(LZO_SIZEOF_SIZE_T)\n#if (LZO_ARCH_I086 || LZO_ARCH_M16C)\n#  define LZO_SIZEOF_SIZE_T         2\n#endif\n#endif\n#if !defined(LZO_SIZEOF_SIZE_T)\n#  define LZO_SIZEOF_SIZE_T         LZO_SIZEOF_VOID_P\n#endif\n#if defined(offsetof)\nLZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_SIZE_T == sizeof(size_t))\n#endif\n#if !defined(LZO_SIZEOF_PTRDIFF_T)\n#if (LZO_ARCH_I086)\n#  if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM || LZO_MM_HUGE)\n#    define LZO_SIZEOF_PTRDIFF_T    LZO_SIZEOF_VOID_P\n#  elif (LZO_MM_COMPACT || LZO_MM_LARGE)\n#    if (LZO_CC_BORLANDC || LZO_CC_TURBOC)\n#      define LZO_SIZEOF_PTRDIFF_T  4\n#    else\n#      define LZO_SIZEOF_PTRDIFF_T  2\n#    endif\n#  else\n#    error \"invalid LZO_ARCH_I086 memory model\"\n#  endif\n#endif\n#endif\n#if !defined(LZO_SIZEOF_PTRDIFF_T)\n#  define LZO_SIZEOF_PTRDIFF_T      LZO_SIZEOF_SIZE_T\n#endif\n#if defined(offsetof)\nLZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))\n#endif\n#if !defined(LZO_WORDSIZE)\n#  define LZO_WORDSIZE              LZO_SIZEOF_VOID_P\n#endif\n#if (LZO_ABI_NEUTRAL_ENDIAN)\n#  undef LZO_ABI_BIG_ENDIAN\n#  undef LZO_ABI_LITTLE_ENDIAN\n#elif !(LZO_ABI_BIG_ENDIAN) && !(LZO_ABI_LITTLE_ENDIAN)\n#if (LZO_ARCH_ALPHA) && (LZO_ARCH_CRAY_MPP)\n#  define LZO_ABI_BIG_ENDIAN        1\n#elif (LZO_ARCH_IA64) && (LZO_OS_POSIX_LINUX || LZO_OS_WIN64)\n#  define LZO_ABI_LITTLE_ENDIAN     1\n#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430)\n#  define LZO_ABI_LITTLE_ENDIAN     1\n#elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390 || LZO_ARCH_SPU)\n#  define LZO_ABI_BIG_ENDIAN        1\n#elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__)\n#  if (__LITTLE_ENDIAN__ == 1)\n#    define LZO_ABI_LITTLE_ENDIAN   1\n#  else\n#    define LZO_ABI_BIG_ENDIAN      1\n#  endif\n#elif 1 && defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)\n#  define LZO_ABI_BIG_ENDIAN        1\n#elif 1 && defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)\n#  define LZO_ABI_LITTLE_ENDIAN     1\n#elif 1 && (LZO_ARCH_ARM) && defined(__ARM_BIG_ENDIAN) && ((__ARM_BIG_ENDIAN)+0)\n#  define LZO_ABI_BIG_ENDIAN        1\n#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEB__) && !defined(__ARMEL__)\n#  define LZO_ABI_BIG_ENDIAN        1\n#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__)\n#  define LZO_ABI_LITTLE_ENDIAN     1\n#elif 1 && (LZO_ARCH_ARM && LZO_CC_ARMCC_ARMCC)\n#  if defined(__BIG_ENDIAN) && defined(__LITTLE_ENDIAN)\n#    error \"unexpected configuration - check your compiler defines\"\n#  elif defined(__BIG_ENDIAN)\n#    define LZO_ABI_BIG_ENDIAN      1\n#  else\n#    define LZO_ABI_LITTLE_ENDIAN   1\n#  endif\n#  define LZO_ABI_LITTLE_ENDIAN     1\n#elif 1 && (LZO_ARCH_ARM64) && defined(__ARM_BIG_ENDIAN) && ((__ARM_BIG_ENDIAN)+0)\n#  define LZO_ABI_BIG_ENDIAN        1\n#elif 1 && (LZO_ARCH_ARM64) && defined(__AARCH64EB__) && !defined(__AARCH64EL__)\n#  define LZO_ABI_BIG_ENDIAN        1\n#elif 1 && (LZO_ARCH_ARM64) && defined(__AARCH64EL__) && !defined(__AARCH64EB__)\n#  define LZO_ABI_LITTLE_ENDIAN     1\n#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__)\n#  define LZO_ABI_BIG_ENDIAN        1\n#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__)\n#  define LZO_ABI_LITTLE_ENDIAN     1\n#endif\n#endif\n#if (LZO_ABI_BIG_ENDIAN) && (LZO_ABI_LITTLE_ENDIAN)\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if (LZO_ABI_BIG_ENDIAN)\n#  define LZO_INFO_ABI_ENDIAN       \"be\"\n#elif (LZO_ABI_LITTLE_ENDIAN)\n#  define LZO_INFO_ABI_ENDIAN       \"le\"\n#elif (LZO_ABI_NEUTRAL_ENDIAN)\n#  define LZO_INFO_ABI_ENDIAN       \"neutral\"\n#endif\n#if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2)\n#  define LZO_ABI_I8LP16         1\n#  define LZO_INFO_ABI_PM       \"i8lp16\"\n#elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2)\n#  define LZO_ABI_ILP16         1\n#  define LZO_INFO_ABI_PM       \"ilp16\"\n#elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4)\n#  define LZO_ABI_LP32          1\n#  define LZO_INFO_ABI_PM       \"lp32\"\n#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4)\n#  define LZO_ABI_ILP32         1\n#  define LZO_INFO_ABI_PM       \"ilp32\"\n#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 8 && LZO_SIZEOF_SIZE_T == 8)\n#  define LZO_ABI_LLP64         1\n#  define LZO_INFO_ABI_PM       \"llp64\"\n#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8)\n#  define LZO_ABI_LP64          1\n#  define LZO_INFO_ABI_PM       \"lp64\"\n#elif (LZO_SIZEOF_INT == 8 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8)\n#  define LZO_ABI_ILP64         1\n#  define LZO_INFO_ABI_PM       \"ilp64\"\n#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 4)\n#  define LZO_ABI_IP32L64       1\n#  define LZO_INFO_ABI_PM       \"ip32l64\"\n#endif\n#if 0\n#elif !defined(__LZO_LIBC_OVERRIDE)\n#if (LZO_LIBC_NAKED)\n#  define LZO_INFO_LIBC         \"naked\"\n#elif (LZO_LIBC_FREESTANDING)\n#  define LZO_INFO_LIBC         \"freestanding\"\n#elif (LZO_LIBC_MOSTLY_FREESTANDING)\n#  define LZO_INFO_LIBC         \"mfreestanding\"\n#elif (LZO_LIBC_ISOC90)\n#  define LZO_INFO_LIBC         \"isoc90\"\n#elif (LZO_LIBC_ISOC99)\n#  define LZO_INFO_LIBC         \"isoc99\"\n#elif (LZO_CC_ARMCC_ARMCC) && defined(__ARMCLIB_VERSION)\n#  define LZO_LIBC_ISOC90       1\n#  define LZO_INFO_LIBC         \"isoc90\"\n#elif defined(__dietlibc__)\n#  define LZO_LIBC_DIETLIBC     1\n#  define LZO_INFO_LIBC         \"dietlibc\"\n#elif defined(_NEWLIB_VERSION)\n#  define LZO_LIBC_NEWLIB       1\n#  define LZO_INFO_LIBC         \"newlib\"\n#elif defined(__UCLIBC__) && defined(__UCLIBC_MAJOR__) && defined(__UCLIBC_MINOR__)\n#  if defined(__UCLIBC_SUBLEVEL__)\n#    define LZO_LIBC_UCLIBC     (__UCLIBC_MAJOR__ * 0x10000L + (__UCLIBC_MINOR__-0) * 0x100 + (__UCLIBC_SUBLEVEL__-0))\n#  else\n#    define LZO_LIBC_UCLIBC     0x00090bL\n#  endif\n#  define LZO_INFO_LIBC         \"uc\" \"libc\"\n#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__)\n#  define LZO_LIBC_GLIBC        (__GLIBC__ * 0x10000L + (__GLIBC_MINOR__-0) * 0x100)\n#  define LZO_INFO_LIBC         \"glibc\"\n#elif (LZO_CC_MWERKS) && defined(__MSL__)\n#  define LZO_LIBC_MSL          __MSL__\n#  define LZO_INFO_LIBC         \"msl\"\n#elif 1 && defined(__IAR_SYSTEMS_ICC__)\n#  define LZO_LIBC_ISOC90       1\n#  define LZO_INFO_LIBC         \"isoc90\"\n#else\n#  define LZO_LIBC_DEFAULT      1\n#  define LZO_INFO_LIBC         \"default\"\n#endif\n#endif\n#if (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))\n#  define LZO_ASM_SYNTAX_MSC 1\n#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))\n#elif (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC == 0x011f00ul))\n#elif (LZO_ARCH_I386 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))\n#  define LZO_ASM_SYNTAX_GNUC 1\n#elif (LZO_ARCH_AMD64 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))\n#  define LZO_ASM_SYNTAX_GNUC 1\n#elif (LZO_CC_GNUC)\n#  define LZO_ASM_SYNTAX_GNUC 1\n#endif\n#if (LZO_ASM_SYNTAX_GNUC)\n#if (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC < 0x020000ul))\n#  define __LZO_ASM_CLOBBER                     \"ax\"\n#  define __LZO_ASM_CLOBBER_LIST_CC             /*empty*/\n#  define __LZO_ASM_CLOBBER_LIST_CC_MEMORY      /*empty*/\n#  define __LZO_ASM_CLOBBER_LIST_EMPTY          /*empty*/\n#elif (LZO_CC_INTELC && (__INTEL_COMPILER < 1000))\n#  define __LZO_ASM_CLOBBER                     \"memory\"\n#  define __LZO_ASM_CLOBBER_LIST_CC             /*empty*/\n#  define __LZO_ASM_CLOBBER_LIST_CC_MEMORY      : \"memory\"\n#  define __LZO_ASM_CLOBBER_LIST_EMPTY          /*empty*/\n#else\n#  define __LZO_ASM_CLOBBER                     \"cc\", \"memory\"\n#  define __LZO_ASM_CLOBBER_LIST_CC             : \"cc\"\n#  define __LZO_ASM_CLOBBER_LIST_CC_MEMORY      : \"cc\", \"memory\"\n#  define __LZO_ASM_CLOBBER_LIST_EMPTY          /*empty*/\n#endif\n#endif\n#if (LZO_ARCH_ALPHA)\n#  define LZO_OPT_AVOID_UINT_INDEX          1\n#elif (LZO_ARCH_AMD64)\n#  define LZO_OPT_AVOID_INT_INDEX           1\n#  define LZO_OPT_AVOID_UINT_INDEX          1\n#  ifndef LZO_OPT_UNALIGNED16\n#  define LZO_OPT_UNALIGNED16               1\n#  endif\n#  ifndef LZO_OPT_UNALIGNED32\n#  define LZO_OPT_UNALIGNED32               1\n#  endif\n#  ifndef LZO_OPT_UNALIGNED64\n#  define LZO_OPT_UNALIGNED64               1\n#  endif\n#elif (LZO_ARCH_ARM)\n#  if defined(__ARM_FEATURE_UNALIGNED)\n#   if ((__ARM_FEATURE_UNALIGNED)+0)\n#    ifndef LZO_OPT_UNALIGNED16\n#    define LZO_OPT_UNALIGNED16             1\n#    endif\n#    ifndef LZO_OPT_UNALIGNED32\n#    define LZO_OPT_UNALIGNED32             1\n#    endif\n#   endif\n#  elif 1 && (LZO_ARCH_ARM_THUMB2)\n#    ifndef LZO_OPT_UNALIGNED16\n#    define LZO_OPT_UNALIGNED16             1\n#    endif\n#    ifndef LZO_OPT_UNALIGNED32\n#    define LZO_OPT_UNALIGNED32             1\n#    endif\n#  elif 1 && defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM)+0 >= 7)\n#    ifndef LZO_OPT_UNALIGNED16\n#    define LZO_OPT_UNALIGNED16             1\n#    endif\n#    ifndef LZO_OPT_UNALIGNED32\n#    define LZO_OPT_UNALIGNED32             1\n#    endif\n#  elif 1 && defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM)+0 >= 6) && (defined(__TARGET_PROFILE_A) || defined(__TARGET_PROFILE_R))\n#    ifndef LZO_OPT_UNALIGNED16\n#    define LZO_OPT_UNALIGNED16             1\n#    endif\n#    ifndef LZO_OPT_UNALIGNED32\n#    define LZO_OPT_UNALIGNED32             1\n#    endif\n#  endif\n#elif (LZO_ARCH_ARM64)\n#  ifndef LZO_OPT_UNALIGNED16\n#  define LZO_OPT_UNALIGNED16               1\n#  endif\n#  ifndef LZO_OPT_UNALIGNED32\n#  define LZO_OPT_UNALIGNED32               1\n#  endif\n#  ifndef LZO_OPT_UNALIGNED64\n#  define LZO_OPT_UNALIGNED64               1\n#  endif\n#elif (LZO_ARCH_CRIS)\n#  ifndef LZO_OPT_UNALIGNED16\n#  define LZO_OPT_UNALIGNED16               1\n#  endif\n#  ifndef LZO_OPT_UNALIGNED32\n#  define LZO_OPT_UNALIGNED32               1\n#  endif\n#elif (LZO_ARCH_I386)\n#  ifndef LZO_OPT_UNALIGNED16\n#  define LZO_OPT_UNALIGNED16               1\n#  endif\n#  ifndef LZO_OPT_UNALIGNED32\n#  define LZO_OPT_UNALIGNED32               1\n#  endif\n#elif (LZO_ARCH_IA64)\n#  define LZO_OPT_AVOID_INT_INDEX           1\n#  define LZO_OPT_AVOID_UINT_INDEX          1\n#  define LZO_OPT_PREFER_POSTINC            1\n#elif (LZO_ARCH_M68K)\n#  define LZO_OPT_PREFER_POSTINC            1\n#  define LZO_OPT_PREFER_PREDEC             1\n#  if defined(__mc68020__) && !defined(__mcoldfire__)\n#    ifndef LZO_OPT_UNALIGNED16\n#    define LZO_OPT_UNALIGNED16             1\n#    endif\n#    ifndef LZO_OPT_UNALIGNED32\n#    define LZO_OPT_UNALIGNED32             1\n#    endif\n#  endif\n#elif (LZO_ARCH_MIPS)\n#  define LZO_OPT_AVOID_UINT_INDEX          1\n#elif (LZO_ARCH_POWERPC)\n#  define LZO_OPT_PREFER_PREINC             1\n#  define LZO_OPT_PREFER_PREDEC             1\n#  if (LZO_ABI_BIG_ENDIAN)\n#    ifndef LZO_OPT_UNALIGNED16\n#    define LZO_OPT_UNALIGNED16             1\n#    endif\n#    ifndef LZO_OPT_UNALIGNED32\n#    define LZO_OPT_UNALIGNED32             1\n#    endif\n#    if (LZO_WORDSIZE == 8)\n#      ifndef LZO_OPT_UNALIGNED64\n#      define LZO_OPT_UNALIGNED64           1\n#      endif\n#    endif\n#  endif\n#elif (LZO_ARCH_S390)\n#  ifndef LZO_OPT_UNALIGNED16\n#  define LZO_OPT_UNALIGNED16               1\n#  endif\n#  ifndef LZO_OPT_UNALIGNED32\n#  define LZO_OPT_UNALIGNED32               1\n#  endif\n#  if (LZO_WORDSIZE == 8)\n#    ifndef LZO_OPT_UNALIGNED64\n#    define LZO_OPT_UNALIGNED64             1\n#    endif\n#  endif\n#elif (LZO_ARCH_SH)\n#  define LZO_OPT_PREFER_POSTINC            1\n#  define LZO_OPT_PREFER_PREDEC             1\n#endif\n#ifndef LZO_CFG_NO_INLINE_ASM\n#if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC)\n#  define LZO_CFG_NO_INLINE_ASM 1\n#elif (LZO_CC_LLVM)\n#  define LZO_CFG_NO_INLINE_ASM 1\n#endif\n#endif\n#if (LZO_CFG_NO_INLINE_ASM)\n#  undef LZO_ASM_SYNTAX_MSC\n#  undef LZO_ASM_SYNTAX_GNUC\n#  undef __LZO_ASM_CLOBBER\n#  undef __LZO_ASM_CLOBBER_LIST_CC\n#  undef __LZO_ASM_CLOBBER_LIST_CC_MEMORY\n#  undef __LZO_ASM_CLOBBER_LIST_EMPTY\n#endif\n#ifndef LZO_CFG_NO_UNALIGNED\n#if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC)\n#  define LZO_CFG_NO_UNALIGNED 1\n#endif\n#endif\n#if (LZO_CFG_NO_UNALIGNED)\n#  undef LZO_OPT_UNALIGNED16\n#  undef LZO_OPT_UNALIGNED32\n#  undef LZO_OPT_UNALIGNED64\n#endif\n#if defined(__LZO_INFOSTR_MM)\n#elif (LZO_MM_FLAT) && (defined(__LZO_INFOSTR_PM) || defined(LZO_INFO_ABI_PM))\n#  define __LZO_INFOSTR_MM          \"\"\n#elif defined(LZO_INFO_MM)\n#  define __LZO_INFOSTR_MM          \".\" LZO_INFO_MM\n#else\n#  define __LZO_INFOSTR_MM          \"\"\n#endif\n#if defined(__LZO_INFOSTR_PM)\n#elif defined(LZO_INFO_ABI_PM)\n#  define __LZO_INFOSTR_PM          \".\" LZO_INFO_ABI_PM\n#else\n#  define __LZO_INFOSTR_PM          \"\"\n#endif\n#if defined(__LZO_INFOSTR_ENDIAN)\n#elif defined(LZO_INFO_ABI_ENDIAN)\n#  define __LZO_INFOSTR_ENDIAN      \".\" LZO_INFO_ABI_ENDIAN\n#else\n#  define __LZO_INFOSTR_ENDIAN      \"\"\n#endif\n#if defined(__LZO_INFOSTR_OSNAME)\n#elif defined(LZO_INFO_OS_CONSOLE)\n#  define __LZO_INFOSTR_OSNAME      LZO_INFO_OS \".\" LZO_INFO_OS_CONSOLE\n#elif defined(LZO_INFO_OS_POSIX)\n#  define __LZO_INFOSTR_OSNAME      LZO_INFO_OS \".\" LZO_INFO_OS_POSIX\n#else\n#  define __LZO_INFOSTR_OSNAME      LZO_INFO_OS\n#endif\n#if defined(__LZO_INFOSTR_LIBC)\n#elif defined(LZO_INFO_LIBC)\n#  define __LZO_INFOSTR_LIBC        \".\" LZO_INFO_LIBC\n#else\n#  define __LZO_INFOSTR_LIBC        \"\"\n#endif\n#if defined(__LZO_INFOSTR_CCVER)\n#elif defined(LZO_INFO_CCVER)\n#  define __LZO_INFOSTR_CCVER       \" \" LZO_INFO_CCVER\n#else\n#  define __LZO_INFOSTR_CCVER       \"\"\n#endif\n#define LZO_INFO_STRING \\\n    LZO_INFO_ARCH __LZO_INFOSTR_MM __LZO_INFOSTR_PM __LZO_INFOSTR_ENDIAN \\\n    \" \" __LZO_INFOSTR_OSNAME __LZO_INFOSTR_LIBC \" \" LZO_INFO_CC __LZO_INFOSTR_CCVER\n#if !(LZO_CFG_SKIP_LZO_TYPES)\n#if (!(LZO_SIZEOF_SHORT+0 > 0 && LZO_SIZEOF_INT+0 > 0 && LZO_SIZEOF_LONG+0 > 0))\n#  error \"missing defines for sizes\"\n#endif\n#if (!(LZO_SIZEOF_PTRDIFF_T+0 > 0 && LZO_SIZEOF_SIZE_T+0 > 0 && LZO_SIZEOF_VOID_P+0 > 0))\n#  error \"missing defines for sizes\"\n#endif\n#define LZO_TYPEOF_CHAR             1u\n#define LZO_TYPEOF_SHORT            2u\n#define LZO_TYPEOF_INT              3u\n#define LZO_TYPEOF_LONG             4u\n#define LZO_TYPEOF_LONG_LONG        5u\n#define LZO_TYPEOF___INT8           17u\n#define LZO_TYPEOF___INT16          18u\n#define LZO_TYPEOF___INT32          19u\n#define LZO_TYPEOF___INT64          20u\n#define LZO_TYPEOF___INT128         21u\n#define LZO_TYPEOF___INT256         22u\n#define LZO_TYPEOF___MODE_QI        33u\n#define LZO_TYPEOF___MODE_HI        34u\n#define LZO_TYPEOF___MODE_SI        35u\n#define LZO_TYPEOF___MODE_DI        36u\n#define LZO_TYPEOF___MODE_TI        37u\n#define LZO_TYPEOF_CHAR_P           129u\n#if !defined(lzo_llong_t)\n#if (LZO_SIZEOF_LONG_LONG+0 > 0)\n__lzo_gnuc_extension__ typedef long long lzo_llong_t__;\n__lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;\n#  define lzo_llong_t               lzo_llong_t__\n#  define lzo_ullong_t              lzo_ullong_t__\n#endif\n#endif\n#if !defined(lzo_int16e_t)\n#if (LZO_SIZEOF_LONG == 2)\n#  define lzo_int16e_t              long\n#  define lzo_uint16e_t             unsigned long\n#  define LZO_TYPEOF_LZO_INT16E_T   LZO_TYPEOF_LONG\n#elif (LZO_SIZEOF_INT == 2)\n#  define lzo_int16e_t              int\n#  define lzo_uint16e_t             unsigned int\n#  define LZO_TYPEOF_LZO_INT16E_T   LZO_TYPEOF_INT\n#elif (LZO_SIZEOF_SHORT == 2)\n#  define lzo_int16e_t              short int\n#  define lzo_uint16e_t             unsigned short int\n#  define LZO_TYPEOF_LZO_INT16E_T   LZO_TYPEOF_SHORT\n#elif 1 && !(LZO_CFG_TYPE_NO_MODE_HI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM)\n   typedef int lzo_int16e_hi_t__ __attribute__((__mode__(__HI__)));\n   typedef unsigned int lzo_uint16e_hi_t__ __attribute__((__mode__(__HI__)));\n#  define lzo_int16e_t              lzo_int16e_hi_t__\n#  define lzo_uint16e_t             lzo_uint16e_hi_t__\n#  define LZO_TYPEOF_LZO_INT16E_T   LZO_TYPEOF___MODE_HI\n#elif (LZO_SIZEOF___INT16 == 2)\n#  define lzo_int16e_t              __int16\n#  define lzo_uint16e_t             unsigned __int16\n#  define LZO_TYPEOF_LZO_INT16E_T   LZO_TYPEOF___INT16\n#else\n#endif\n#endif\n#if defined(lzo_int16e_t)\n#  define LZO_SIZEOF_LZO_INT16E_T   2\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16e_t) == 2)\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16e_t) == LZO_SIZEOF_LZO_INT16E_T)\n#endif\n#if !defined(lzo_int32e_t)\n#if (LZO_SIZEOF_LONG == 4)\n#  define lzo_int32e_t              long int\n#  define lzo_uint32e_t             unsigned long int\n#  define LZO_TYPEOF_LZO_INT32E_T   LZO_TYPEOF_LONG\n#elif (LZO_SIZEOF_INT == 4)\n#  define lzo_int32e_t              int\n#  define lzo_uint32e_t             unsigned int\n#  define LZO_TYPEOF_LZO_INT32E_T   LZO_TYPEOF_INT\n#elif (LZO_SIZEOF_SHORT == 4)\n#  define lzo_int32e_t              short int\n#  define lzo_uint32e_t             unsigned short int\n#  define LZO_TYPEOF_LZO_INT32E_T   LZO_TYPEOF_SHORT\n#elif (LZO_SIZEOF_LONG_LONG == 4)\n#  define lzo_int32e_t              lzo_llong_t\n#  define lzo_uint32e_t             lzo_ullong_t\n#  define LZO_TYPEOF_LZO_INT32E_T   LZO_TYPEOF_LONG_LONG\n#elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM) && (__INT_MAX__+0 > 2147483647L)\n   typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__)));\n   typedef unsigned int lzo_uint32e_si_t__ __attribute__((__mode__(__SI__)));\n#  define lzo_int32e_t              lzo_int32e_si_t__\n#  define lzo_uint32e_t             lzo_uint32e_si_t__\n#  define LZO_TYPEOF_LZO_INT32E_T   LZO_TYPEOF___MODE_SI\n#elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_GNUC >= 0x025f00ul) && defined(__AVR__) && (__LONG_MAX__+0 == 32767L)\n   typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__)));\n   typedef unsigned int lzo_uint32e_si_t__ __attribute__((__mode__(__SI__)));\n#  define lzo_int32e_t              lzo_int32e_si_t__\n#  define lzo_uint32e_t             lzo_uint32e_si_t__\n#  define LZO_INT32_C(c)            (c##LL)\n#  define LZO_UINT32_C(c)           (c##ULL)\n#  define LZO_TYPEOF_LZO_INT32E_T   LZO_TYPEOF___MODE_SI\n#elif (LZO_SIZEOF___INT32 == 4)\n#  define lzo_int32e_t              __int32\n#  define lzo_uint32e_t             unsigned __int32\n#  define LZO_TYPEOF_LZO_INT32E_T   LZO_TYPEOF___INT32\n#else\n#endif\n#endif\n#if defined(lzo_int32e_t)\n#  define LZO_SIZEOF_LZO_INT32E_T   4\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32e_t) == 4)\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32e_t) == LZO_SIZEOF_LZO_INT32E_T)\n#endif\n#if !defined(lzo_int64e_t)\n#if (LZO_SIZEOF___INT64 == 8)\n#  if (LZO_CC_BORLANDC) && !(LZO_CFG_TYPE_PREFER___INT64)\n#    define LZO_CFG_TYPE_PREFER___INT64 1\n#  endif\n#endif\n#if (LZO_SIZEOF_INT == 8) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)\n#  define lzo_int64e_t              int\n#  define lzo_uint64e_t             unsigned int\n#  define LZO_TYPEOF_LZO_INT64E_T   LZO_TYPEOF_INT\n#elif (LZO_SIZEOF_LONG == 8)\n#  define lzo_int64e_t              long int\n#  define lzo_uint64e_t             unsigned long int\n#  define LZO_TYPEOF_LZO_INT64E_T   LZO_TYPEOF_LONG\n#elif (LZO_SIZEOF_LONG_LONG == 8) && !(LZO_CFG_TYPE_PREFER___INT64)\n#  define lzo_int64e_t              lzo_llong_t\n#  define lzo_uint64e_t             lzo_ullong_t\n#  define LZO_TYPEOF_LZO_INT64E_T   LZO_TYPEOF_LONG_LONG\n#  if (LZO_CC_BORLANDC)\n#    define LZO_INT64_C(c)          ((c) + 0ll)\n#    define LZO_UINT64_C(c)         ((c) + 0ull)\n#  elif 0\n#    define LZO_INT64_C(c)          (__lzo_gnuc_extension__ (c##LL))\n#    define LZO_UINT64_C(c)         (__lzo_gnuc_extension__ (c##ULL))\n#  else\n#    define LZO_INT64_C(c)          (c##LL)\n#    define LZO_UINT64_C(c)         (c##ULL)\n#  endif\n#elif (LZO_SIZEOF___INT64 == 8)\n#  define lzo_int64e_t              __int64\n#  define lzo_uint64e_t             unsigned __int64\n#  define LZO_TYPEOF_LZO_INT64E_T   LZO_TYPEOF___INT64\n#  if (LZO_CC_BORLANDC)\n#    define LZO_INT64_C(c)          ((c) + 0i64)\n#    define LZO_UINT64_C(c)         ((c) + 0ui64)\n#  else\n#    define LZO_INT64_C(c)          (c##i64)\n#    define LZO_UINT64_C(c)         (c##ui64)\n#  endif\n#else\n#endif\n#endif\n#if defined(lzo_int64e_t)\n#  define LZO_SIZEOF_LZO_INT64E_T   8\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64e_t) == 8)\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64e_t) == LZO_SIZEOF_LZO_INT64E_T)\n#endif\n#if !defined(lzo_int32l_t)\n#if defined(lzo_int32e_t)\n#  define lzo_int32l_t              lzo_int32e_t\n#  define lzo_uint32l_t             lzo_uint32e_t\n#  define LZO_SIZEOF_LZO_INT32L_T   LZO_SIZEOF_LZO_INT32E_T\n#  define LZO_TYPEOF_LZO_INT32L_T   LZO_TYPEOF_LZO_INT32E_T\n#elif (LZO_SIZEOF_INT >= 4) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)\n#  define lzo_int32l_t              int\n#  define lzo_uint32l_t             unsigned int\n#  define LZO_SIZEOF_LZO_INT32L_T   LZO_SIZEOF_INT\n#  define LZO_TYPEOF_LZO_INT32L_T   LZO_SIZEOF_INT\n#elif (LZO_SIZEOF_LONG >= 4)\n#  define lzo_int32l_t              long int\n#  define lzo_uint32l_t             unsigned long int\n#  define LZO_SIZEOF_LZO_INT32L_T   LZO_SIZEOF_LONG\n#  define LZO_TYPEOF_LZO_INT32L_T   LZO_SIZEOF_LONG\n#else\n#  error \"lzo_int32l_t\"\n#endif\n#endif\n#if 1\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32l_t) >= 4)\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32l_t) == LZO_SIZEOF_LZO_INT32L_T)\n#endif\n#if !defined(lzo_int64l_t)\n#if defined(lzo_int64e_t)\n#  define lzo_int64l_t              lzo_int64e_t\n#  define lzo_uint64l_t             lzo_uint64e_t\n#  define LZO_SIZEOF_LZO_INT64L_T   LZO_SIZEOF_LZO_INT64E_T\n#  define LZO_TYPEOF_LZO_INT64L_T   LZO_TYPEOF_LZO_INT64E_T\n#else\n#endif\n#endif\n#if defined(lzo_int64l_t)\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64l_t) >= 8)\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64l_t) == LZO_SIZEOF_LZO_INT64L_T)\n#endif\n#if !defined(lzo_int32f_t)\n#if (LZO_SIZEOF_SIZE_T >= 8)\n#  define lzo_int32f_t              lzo_int64l_t\n#  define lzo_uint32f_t             lzo_uint64l_t\n#  define LZO_SIZEOF_LZO_INT32F_T   LZO_SIZEOF_LZO_INT64L_T\n#  define LZO_TYPEOF_LZO_INT32F_T   LZO_TYPEOF_LZO_INT64L_T\n#else\n#  define lzo_int32f_t              lzo_int32l_t\n#  define lzo_uint32f_t             lzo_uint32l_t\n#  define LZO_SIZEOF_LZO_INT32F_T   LZO_SIZEOF_LZO_INT32L_T\n#  define LZO_TYPEOF_LZO_INT32F_T   LZO_TYPEOF_LZO_INT32L_T\n#endif\n#endif\n#if 1\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32f_t) >= 4)\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32f_t) == LZO_SIZEOF_LZO_INT32F_T)\n#endif\n#if !defined(lzo_int64f_t)\n#if defined(lzo_int64l_t)\n#  define lzo_int64f_t              lzo_int64l_t\n#  define lzo_uint64f_t             lzo_uint64l_t\n#  define LZO_SIZEOF_LZO_INT64F_T   LZO_SIZEOF_LZO_INT64L_T\n#  define LZO_TYPEOF_LZO_INT64F_T   LZO_TYPEOF_LZO_INT64L_T\n#else\n#endif\n#endif\n#if defined(lzo_int64f_t)\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64f_t) >= 8)\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64f_t) == LZO_SIZEOF_LZO_INT64F_T)\n#endif\n#if !defined(lzo_intptr_t)\n#if 1 && (LZO_OS_OS400 && (LZO_SIZEOF_VOID_P == 16))\n#  define __LZO_INTPTR_T_IS_POINTER 1\n   typedef char *                   lzo_intptr_t;\n   typedef char *                   lzo_uintptr_t;\n#  define lzo_intptr_t              lzo_intptr_t\n#  define lzo_uintptr_t             lzo_uintptr_t\n#  define LZO_SIZEOF_LZO_INTPTR_T   LZO_SIZEOF_VOID_P\n#  define LZO_TYPEOF_LZO_INTPTR_T   LZO_TYPEOF_CHAR_P\n#elif (LZO_CC_MSC && (_MSC_VER >= 1300) && (LZO_SIZEOF_VOID_P == 4) && (LZO_SIZEOF_INT == 4))\n   typedef __w64 int                lzo_intptr_t;\n   typedef __w64 unsigned int       lzo_uintptr_t;\n#  define lzo_intptr_t              lzo_intptr_t\n#  define lzo_uintptr_t             lzo_uintptr_t\n#  define LZO_SIZEOF_LZO_INTPTR_T   LZO_SIZEOF_INT\n#  define LZO_TYPEOF_LZO_INTPTR_T   LZO_TYPEOF_INT\n#elif (LZO_SIZEOF_SHORT == LZO_SIZEOF_VOID_P) && (LZO_SIZEOF_INT > LZO_SIZEOF_VOID_P)\n#  define lzo_intptr_t              short\n#  define lzo_uintptr_t             unsigned short\n#  define LZO_SIZEOF_LZO_INTPTR_T   LZO_SIZEOF_SHORT\n#  define LZO_TYPEOF_LZO_INTPTR_T   LZO_TYPEOF_SHORT\n#elif (LZO_SIZEOF_INT >= LZO_SIZEOF_VOID_P) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)\n#  define lzo_intptr_t              int\n#  define lzo_uintptr_t             unsigned int\n#  define LZO_SIZEOF_LZO_INTPTR_T   LZO_SIZEOF_INT\n#  define LZO_TYPEOF_LZO_INTPTR_T   LZO_TYPEOF_INT\n#elif (LZO_SIZEOF_LONG >= LZO_SIZEOF_VOID_P)\n#  define lzo_intptr_t              long\n#  define lzo_uintptr_t             unsigned long\n#  define LZO_SIZEOF_LZO_INTPTR_T   LZO_SIZEOF_LONG\n#  define LZO_TYPEOF_LZO_INTPTR_T   LZO_TYPEOF_LONG\n#elif (LZO_SIZEOF_LZO_INT64L_T >= LZO_SIZEOF_VOID_P)\n#  define lzo_intptr_t              lzo_int64l_t\n#  define lzo_uintptr_t             lzo_uint64l_t\n#  define LZO_SIZEOF_LZO_INTPTR_T   LZO_SIZEOF_LZO_INT64L_T\n#  define LZO_TYPEOF_LZO_INTPTR_T   LZO_TYPEOF_LZO_INT64L_T\n#else\n#  error \"lzo_intptr_t\"\n#endif\n#endif\n#if 1\n    LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_intptr_t) >= sizeof(void *))\n    LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_intptr_t) == sizeof(lzo_uintptr_t))\n#endif\n#if !defined(lzo_word_t)\n#if defined(LZO_WORDSIZE) && (LZO_WORDSIZE+0 > 0)\n#if (LZO_WORDSIZE == LZO_SIZEOF_LZO_INTPTR_T) && !(__LZO_INTPTR_T_IS_POINTER)\n#  define lzo_word_t                lzo_uintptr_t\n#  define lzo_sword_t               lzo_intptr_t\n#  define LZO_SIZEOF_LZO_WORD_T     LZO_SIZEOF_LZO_INTPTR_T\n#  define LZO_TYPEOF_LZO_WORD_T     LZO_TYPEOF_LZO_INTPTR_T\n#elif (LZO_WORDSIZE == LZO_SIZEOF_LONG)\n#  define lzo_word_t                unsigned long\n#  define lzo_sword_t               long\n#  define LZO_SIZEOF_LZO_WORD_T     LZO_SIZEOF_LONG\n#  define LZO_TYPEOF_LZO_WORD_T     LZO_TYPEOF_LONG\n#elif (LZO_WORDSIZE == LZO_SIZEOF_INT)\n#  define lzo_word_t                unsigned int\n#  define lzo_sword_t               int\n#  define LZO_SIZEOF_LZO_WORD_T     LZO_SIZEOF_INT\n#  define LZO_TYPEOF_LZO_WORD_T     LZO_TYPEOF_INT\n#elif (LZO_WORDSIZE == LZO_SIZEOF_SHORT)\n#  define lzo_word_t                unsigned short\n#  define lzo_sword_t               short\n#  define LZO_SIZEOF_LZO_WORD_T     LZO_SIZEOF_SHORT\n#  define LZO_TYPEOF_LZO_WORD_T     LZO_TYPEOF_SHORT\n#elif (LZO_WORDSIZE == 1)\n#  define lzo_word_t                unsigned char\n#  define lzo_sword_t               signed char\n#  define LZO_SIZEOF_LZO_WORD_T     1\n#  define LZO_TYPEOF_LZO_WORD_T     LZO_TYPEOF_CHAR\n#elif (LZO_WORDSIZE == LZO_SIZEOF_LZO_INT64L_T)\n#  define lzo_word_t                lzo_uint64l_t\n#  define lzo_sword_t               lzo_int64l_t\n#  define LZO_SIZEOF_LZO_WORD_T     LZO_SIZEOF_LZO_INT64L_T\n#  define LZO_TYPEOF_LZO_WORD_T     LZO_SIZEOF_LZO_INT64L_T\n#elif (LZO_ARCH_SPU) && (LZO_CC_GNUC)\n#if 0\n   typedef unsigned lzo_word_t  __attribute__((__mode__(__V16QI__)));\n   typedef int      lzo_sword_t __attribute__((__mode__(__V16QI__)));\n#  define lzo_word_t                lzo_word_t\n#  define lzo_sword_t               lzo_sword_t\n#  define LZO_SIZEOF_LZO_WORD_T     16\n#  define LZO_TYPEOF_LZO_WORD_T     LZO_TYPEOF___MODE_V16QI\n#endif\n#else\n#  error \"lzo_word_t\"\n#endif\n#endif\n#endif\n#if 1 && defined(lzo_word_t)\n    LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_word_t)  == LZO_WORDSIZE)\n    LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_sword_t) == LZO_WORDSIZE)\n#endif\n#if 1\n#define lzo_int8_t                  signed char\n#define lzo_uint8_t                 unsigned char\n#define LZO_SIZEOF_LZO_INT8_T       1\n#define LZO_TYPEOF_LZO_INT8_T       LZO_TYPEOF_CHAR\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == 1)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == sizeof(lzo_uint8_t))\n#endif\n#if defined(lzo_int16e_t)\n#define lzo_int16_t                 lzo_int16e_t\n#define lzo_uint16_t                lzo_uint16e_t\n#define LZO_SIZEOF_LZO_INT16_T      LZO_SIZEOF_LZO_INT16E_T\n#define LZO_TYPEOF_LZO_INT16_T      LZO_TYPEOF_LZO_INT16E_T\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == 2)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == sizeof(lzo_uint16_t))\n#endif\n#if defined(lzo_int32e_t)\n#define lzo_int32_t                 lzo_int32e_t\n#define lzo_uint32_t                lzo_uint32e_t\n#define LZO_SIZEOF_LZO_INT32_T      LZO_SIZEOF_LZO_INT32E_T\n#define LZO_TYPEOF_LZO_INT32_T      LZO_TYPEOF_LZO_INT32E_T\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == 4)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == sizeof(lzo_uint32_t))\n#endif\n#if defined(lzo_int64e_t)\n#define lzo_int64_t                 lzo_int64e_t\n#define lzo_uint64_t                lzo_uint64e_t\n#define LZO_SIZEOF_LZO_INT64_T      LZO_SIZEOF_LZO_INT64E_T\n#define LZO_TYPEOF_LZO_INT64_T      LZO_TYPEOF_LZO_INT64E_T\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == 8)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == sizeof(lzo_uint64_t))\n#endif\n#if 1\n#define lzo_int_least32_t           lzo_int32l_t\n#define lzo_uint_least32_t          lzo_uint32l_t\n#define LZO_SIZEOF_LZO_INT_LEAST32_T LZO_SIZEOF_LZO_INT32L_T\n#define LZO_TYPEOF_LZO_INT_LEAST32_T LZO_TYPEOF_LZO_INT32L_T\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least32_t) >= 4)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least32_t) == sizeof(lzo_uint_least32_t))\n#endif\n#if defined(lzo_int64l_t)\n#define lzo_int_least64_t           lzo_int64l_t\n#define lzo_uint_least64_t          lzo_uint64l_t\n#define LZO_SIZEOF_LZO_INT_LEAST64_T LZO_SIZEOF_LZO_INT64L_T\n#define LZO_TYPEOF_LZO_INT_LEAST64_T LZO_TYPEOF_LZO_INT64L_T\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least64_t) >= 8)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least64_t) == sizeof(lzo_uint_least64_t))\n#endif\n#if 1\n#define lzo_int_fast32_t           lzo_int32f_t\n#define lzo_uint_fast32_t          lzo_uint32f_t\n#define LZO_SIZEOF_LZO_INT_FAST32_T LZO_SIZEOF_LZO_INT32F_T\n#define LZO_TYPEOF_LZO_INT_FAST32_T LZO_TYPEOF_LZO_INT32F_T\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast32_t) >= 4)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast32_t) == sizeof(lzo_uint_fast32_t))\n#endif\n#if defined(lzo_int64f_t)\n#define lzo_int_fast64_t           lzo_int64f_t\n#define lzo_uint_fast64_t          lzo_uint64f_t\n#define LZO_SIZEOF_LZO_INT_FAST64_T LZO_SIZEOF_LZO_INT64F_T\n#define LZO_TYPEOF_LZO_INT_FAST64_T LZO_TYPEOF_LZO_INT64F_T\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) >= 8)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) == sizeof(lzo_uint_fast64_t))\n#endif\n#if !defined(LZO_INT16_C)\n#  if (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_INT >= 2)\n#    define LZO_INT16_C(c)          ((c) + 0)\n#    define LZO_UINT16_C(c)         ((c) + 0U)\n#  elif (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_LONG >= 2)\n#    define LZO_INT16_C(c)          ((c) + 0L)\n#    define LZO_UINT16_C(c)         ((c) + 0UL)\n#  elif (LZO_SIZEOF_INT >= 2)\n#    define LZO_INT16_C(c)          (c)\n#    define LZO_UINT16_C(c)         (c##U)\n#  elif (LZO_SIZEOF_LONG >= 2)\n#    define LZO_INT16_C(c)          (c##L)\n#    define LZO_UINT16_C(c)         (c##UL)\n#  else\n#    error \"LZO_INT16_C\"\n#  endif\n#endif\n#if !defined(LZO_INT32_C)\n#  if (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_INT >= 4)\n#    define LZO_INT32_C(c)          ((c) + 0)\n#    define LZO_UINT32_C(c)         ((c) + 0U)\n#  elif (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_LONG >= 4)\n#    define LZO_INT32_C(c)          ((c) + 0L)\n#    define LZO_UINT32_C(c)         ((c) + 0UL)\n#  elif (LZO_SIZEOF_INT >= 4)\n#    define LZO_INT32_C(c)          (c)\n#    define LZO_UINT32_C(c)         (c##U)\n#  elif (LZO_SIZEOF_LONG >= 4)\n#    define LZO_INT32_C(c)          (c##L)\n#    define LZO_UINT32_C(c)         (c##UL)\n#  elif (LZO_SIZEOF_LONG_LONG >= 4)\n#    define LZO_INT32_C(c)          (c##LL)\n#    define LZO_UINT32_C(c)         (c##ULL)\n#  else\n#    error \"LZO_INT32_C\"\n#  endif\n#endif\n#if !defined(LZO_INT64_C) && defined(lzo_int64l_t)\n#  if (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_INT >= 8)\n#    define LZO_INT64_C(c)          ((c) + 0)\n#    define LZO_UINT64_C(c)         ((c) + 0U)\n#  elif (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_LONG >= 8)\n#    define LZO_INT64_C(c)          ((c) + 0L)\n#    define LZO_UINT64_C(c)         ((c) + 0UL)\n#  elif (LZO_SIZEOF_INT >= 8)\n#    define LZO_INT64_C(c)          (c)\n#    define LZO_UINT64_C(c)         (c##U)\n#  elif (LZO_SIZEOF_LONG >= 8)\n#    define LZO_INT64_C(c)          (c##L)\n#    define LZO_UINT64_C(c)         (c##UL)\n#  else\n#    error \"LZO_INT64_C\"\n#  endif\n#endif\n#endif\n\n#endif /* already included */\n\n/* vim:set ts=4 sw=4 et: */\n"
  },
  {
    "path": "include/utils/mhvtl_list.h",
    "content": "#ifndef __LIST_H__\n#define __LIST_H__\n\n#include <stddef.h>\n/* taken from linux kernel */\n\n#undef offsetof\n#ifdef __compiler_offsetof\n#define offsetof(TYPE, MEMBER) __compiler_offsetof(TYPE, MEMBER)\n#else\n#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)\n#endif\n\n#define container_of(ptr, type, member) ({\t\t\t\\\n\tconst typeof( ((type *)0)->member ) *__mptr = (ptr);\t\\\n\t(type *)( (char *)__mptr - offsetof(type, member) ); })\n\nstruct list_head {\n\tstruct list_head *next, *prev;\n};\n\n#define LIST_HEAD_INIT(name) {&(name), &(name)}\n\n#define LIST_HEAD(name) \\\n\tstruct list_head name = LIST_HEAD_INIT(name)\n\nstatic inline void INIT_LIST_HEAD(struct list_head *list) {\n\tlist->next = list;\n\tlist->prev = list;\n}\n\n#define list_first_entry(ptr, type, member) \\\n\tlist_entry((ptr)->next, type, member)\n\nstatic inline int list_empty(const struct list_head *head) {\n\treturn head->next == head;\n}\n\n#define list_entry(ptr, type, member) \\\n\tcontainer_of(ptr, type, member)\n\n#define list_for_each(pos, head) \\\n\tfor (pos = (head)->next; pos != (head); pos = pos->next)\n\n#define list_for_each_entry(pos, head, member)                 \\\n\tfor (pos = list_entry((head)->next, typeof(*pos), member); \\\n\t\t &pos->member != (head);                               \\\n\t\t pos = list_entry(pos->member.next, typeof(*pos), member))\n\n#define list_for_each_entry_safe(pos, n, head, member)             \\\n\tfor (pos = list_entry((head)->next, typeof(*pos), member),     \\\n\t\tn\t = list_entry(pos->member.next, typeof(*pos), member); \\\n\t\t &pos->member != (head);                                   \\\n\t\t pos = n, n = list_entry(n->member.next, typeof(*n), member))\n\nstatic inline void __list_add(struct list_head *newhead,\n\t\t\t\t\t\t\t  struct list_head *prev,\n\t\t\t\t\t\t\t  struct list_head *next) {\n\tnext->prev\t  = newhead;\n\tnewhead->next = next;\n\tnewhead->prev = prev;\n\tprev->next\t  = newhead;\n}\n\nstatic inline void list_add(struct list_head *newhead, struct list_head *head) {\n\t__list_add(newhead, head, head->next);\n}\n\nstatic inline void list_add_tail(struct list_head *newhead, struct list_head *head) {\n\t__list_add(newhead, head->prev, head);\n}\n\nstatic inline void __list_del(struct list_head *prev, struct list_head *next) {\n\tnext->prev = prev;\n\tprev->next = next;\n}\n\nstatic inline void list_del(struct list_head *entry) {\n\t__list_del(entry->prev, entry->next);\n\tentry->next = entry->prev = NULL;\n}\n\nstatic inline void list_del_init(struct list_head *entry) {\n\t__list_del(entry->prev, entry->next);\n\tINIT_LIST_HEAD(entry);\n}\n\nstatic inline void __list_splice(const struct list_head *list,\n\t\t\t\t\t\t\t\t struct list_head\t\t*prev,\n\t\t\t\t\t\t\t\t struct list_head\t\t*next) {\n\tstruct list_head *first = list->next;\n\tstruct list_head *last\t= list->prev;\n\n\tfirst->prev = prev;\n\tprev->next\t= first;\n\n\tlast->next = next;\n\tnext->prev = last;\n}\n\nstatic inline void list_splice_init(struct list_head *list,\n\t\t\t\t\t\t\t\t\tstruct list_head *head) {\n\tif (!list_empty(list)) {\n\t\t__list_splice(list, head, head->next);\n\t\tINIT_LIST_HEAD(list);\n\t}\n}\n\n#endif\n"
  },
  {
    "path": "include/utils/mhvtl_update.h",
    "content": "/*\n * Structures and Functions to update the tape format and mam format to new versions\n *\n * Copyright (C) 2005-2025 Mark Harvey markh794@gmail.com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n */\n\n#ifndef MHVTL_UPDATE_H\n#define MHVTL_UPDATE_H\n\nint try_extract_mam(char *currentPCL);\nint try_update_mam(char *currentPCL);\nint try_update_tape(char *currentPCL);\n\n#endif /* MHVTL_UPDATE_H */"
  },
  {
    "path": "include/utils/minilzo.h",
    "content": "/* minilzo.h -- mini subset of the LZO real-time data compression library\n\n   This file is part of the LZO real-time data compression library.\n\n   Copyright (C) 1996-2015 Markus Franz Xaver Johannes Oberhumer\n   All Rights Reserved.\n\n   The LZO library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU General Public License as\n   published by the Free Software Foundation; either version 2 of\n   the License, or (at your option) any later version.\n\n   The LZO library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n\n   You should have received a copy of the GNU General Public License\n   along with the LZO library; see the file COPYING.\n   If not, write to the Free Software Foundation, Inc.,\n   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n\n   Markus F.X.J. Oberhumer\n   <markus@oberhumer.com>\n   http://www.oberhumer.com/opensource/lzo/\n */\n\n/*\n * NOTE:\n *   the full LZO package can be found at\n *   http://www.oberhumer.com/opensource/lzo/\n */\n\n\n#ifndef __MINILZO_H_INCLUDED\n#define __MINILZO_H_INCLUDED 1\n\n#define MINILZO_VERSION         0x2090\n\n#if defined(__LZOCONF_H_INCLUDED)\n#  error \"you cannot use both LZO and miniLZO\"\n#endif\n\n/* internal Autoconf configuration file - only used when building miniLZO */\n#ifdef MINILZO_HAVE_CONFIG_H\n#  include <config.h>\n#endif\n#include <limits.h>\n#include <stddef.h>\n\n#ifndef __LZODEFS_H_INCLUDED\n#include \"lzodefs.h\"\n#endif\n#undef LZO_HAVE_CONFIG_H\n#include \"lzoconf.h\"\n\n#if !defined(LZO_VERSION) || (LZO_VERSION != MINILZO_VERSION)\n#  error \"version mismatch in header files\"\n#endif\n\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n/***********************************************************************\n//\n************************************************************************/\n\n/* Memory required for the wrkmem parameter.\n * When the required size is 0, you can also pass a NULL pointer.\n */\n\n#define LZO1X_MEM_COMPRESS      LZO1X_1_MEM_COMPRESS\n#define LZO1X_1_MEM_COMPRESS    ((lzo_uint32_t) (16384L * lzo_sizeof_dict_t))\n#define LZO1X_MEM_DECOMPRESS    (0)\n\n\n/* compression */\nLZO_EXTERN(int)\nlzo1x_1_compress        ( const lzo_bytep src, lzo_uint  src_len,\n                                lzo_bytep dst, lzo_uintp dst_len,\n                                lzo_voidp wrkmem );\n\n/* decompression */\nLZO_EXTERN(int)\nlzo1x_decompress        ( const lzo_bytep src, lzo_uint  src_len,\n                                lzo_bytep dst, lzo_uintp dst_len,\n                                lzo_voidp wrkmem /* NOT USED */ );\n\n/* safe decompression with overrun testing */\nLZO_EXTERN(int)\nlzo1x_decompress_safe   ( const lzo_bytep src, lzo_uint  src_len,\n                                lzo_bytep dst, lzo_uintp dst_len,\n                                lzo_voidp wrkmem /* NOT USED */ );\n\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /* already included */\n\n\n/* vim:set ts=4 sw=4 et: */\n"
  },
  {
    "path": "include/utils/q.h",
    "content": "/*\n * q.h -- Message queue for vtltape/vtllibrary\n *\n * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n * Message key - My 2 seconds of fame :-)\n */\n\n#ifndef _Q_H_\n#define _Q_H_\n\n#define MAXTEXTLEN 1024\n\nstruct q_msg {\n\tlong snd_id;\n\tchar text[MAXTEXTLEN + 1];\n};\n\n#define QKEY\t (key_t)0x4d61726b\t  /* Identifying key for queue */\n#define QPERM\t 0660\t\t\t\t  /* Permissions for queue */\n#define MAXOBN\t sizeof(struct q_msg) /* Maximum length of message for Q. */\n#define MAXPRIOR 1024\t\t\t\t  /* max priority level */\n#define VTLCMD_Q 32768\t\t\t\t  /* Priority for vtlcmd */\n\nstruct q_entry {\n\tlong\t\t rcv_id;\n\tstruct q_msg msg;\n};\n\nint enter(char *, long rcv_id);\nint send_msg(char *cmd, long rcv_id);\nint serve(void);\nint init_queue(void);\n\nextern long my_id;\n\n/* Message strings passed between vtllibrary & vtltape */\n#define msg_not_occupied \"Not occupied\"\n#define msg_occupied\t \"occupied\"\n#define msg_unload_ok\t \"Unloaded OK\"\n#define msg_load_failed\t \"Load failed\"\n#define msg_load_ok\t\t \"Loaded OK\"\n#define msg_mount_state\t \"mount_state\"\n#define msg_eject\t\t \"eject\"\n#define msg_set_empty\t \"set_empty\"\n\n#endif /* _Q_H_ */\n"
  },
  {
    "path": "include/utils/security_protocol.h",
    "content": "\n#ifndef _SECURITY_PROTOCOL_H_\n#define _SECURITY_PROTOCOL_H_\n/*\n * Security Protocol IN/OUT\n *\n * Based on spc4r14 / ssc3r04a\n *\n */\n\n#include <stdint.h>\n\n/*\n * Security Algorithm Code\n */\n#define HMAC_KDF_SHA1\t 0x0020002\n#define HMAC_KDF_SHA256\t 0x0020005\n#define HMAC_KDF_SHA384\t 0x0020006\n#define HMAC_KDF_SHA512\t 0x0020007\n#define KDF_AES_128_XCBC 0x0020004\n\n/*\n * Security Association\n *\tspc4r14 5.13.2\n */\nstruct sa {\n\tuint32_t ac_sai;\n\tuint32_t ds_sai;\n\tuint32_t timeout;\n\n\tuint64_t ac_sqn;\n\tuint64_t ds_sqn;\n\n\tuint8_t ac_nonce[64];\n\tuint8_t ds_nonce[64];\n\n\tuint8_t key_seed[64];\n\n\tuint32_t kdf_id;\n\n\tuint8_t keymat[1024];\n\n\tuint16_t usage_type;\n\tuint8_t\t usage_data[1024];\n\tuint8_t\t mgmt_data[1024];\n};\n\n#endif /*  _SECURITY_PROTOCOL_H_ */\n"
  },
  {
    "path": "include/utils/subprocess.h",
    "content": "\nint run_command(char *command, int timeout);\n"
  },
  {
    "path": "include/vtlcart.h",
    "content": "/*\n * Describes the header layout of each tape 'block'\n *\n * $Id: vtlcart.h,v 1.1.2.1 2006-08-06 07:58:44 markh Exp $\n *\n * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n */\n\n#ifndef _VTLCART_H_\n#define _VTLCART_H_\n\n#include <stdint.h>\n\nstruct MAM;\n\n/* Block type definitions */\n#define B_DATA\t   11\n#define B_FILEMARK 3\n#define B_EOD\t   5 /* End of data */\n#define B_NOOP\t   8 /* No Operation - fake it */\n\n#define BLKHDR_FLG_ZLIB_COMPRESSED 0x01\n#define BLKHDR_FLG_ENCRYPTED\t   0x02\n#define BLKHDR_FLG_LZO_COMPRESSED  0x04\n#define BLKHDR_FLG_CRC\t\t\t   0x08\n\n#define TAPE_FMT_VERSION 6\n\n#define ENCR_KEY_MAX_LEN 32\nstruct encryption {\n\tuint32_t key_length;\n\tuint32_t ukad_length;\n\tuint32_t akad_length;\n\tuint32_t pad;\n\tuint8_t\t key[ENCR_KEY_MAX_LEN];\n\tuint8_t\t ukad[ENCR_KEY_MAX_LEN];\n\tuint8_t\t akad[ENCR_KEY_MAX_LEN];\n};\n\n/*\n * Header before each block of data in 'file'\n *\n *\tblock_type\t-> See above 'Block type definitions'\n *\tblk_size\t-> Uncompressed size of data block\n *\t\t   (Specifies capacity of tape (used in BOT header) in Mbytes.\n *\tdisk_blk_size\t-> Amount of space block takes up in 'file'\n *\tuncomp_crc\t-> CRC of the uncompressed data\n * encryption.key_length   -> what length was the key used to 'encrypt' this block\n * encryption.ukad_length  -> what length was the ukad used to 'encrypt' this block\n * encryption.akad_length  -> what length was the akad used to 'encrypt' this block\n * encryption.key  -> what key was used to 'encrypt' this block\n * encryption.ukad -> what ukad was used to 'encrypt' this block\n * encryption.kkad -> what akad was used to 'encrypt' this block\n */\n\nstruct blk_header {\n\tuint32_t\t\t  blk_type;\n\tuint32_t\t\t  blk_flags;\n\tuint32_t\t\t  blk_number;\n\tuint32_t\t\t  blk_size;\n\tuint32_t\t\t  disk_blk_size;\n\tuint32_t\t\t  uncomp_crc;\n\tstruct encryption blk_encryption_info;\n\n\tuint32_t partition_id;\n\tuint32_t reserved; // for 64 bit alignment\n\n\t/*\n\t * Add other things right here...\n\t * Be careful to keep data 64bit aligned\n\t */\n};\n\n/* Default tape size specified in Mbytes */\n#define DEFAULT_TAPE_SZ 8000\n\n/*\n * Medium Density Code\n *\n * This value is returned in the first byte [0] of the Mode Sense 'Block Descriptor'\n */\n\n/* A good list can be found her:\nhttps://github.com/iustin/mt-st/blob/fbfd923faad0d6f613415f4de747833fb6b4a465/mt.c#L136\n*/\n#define medium_density_code_unknown 0x20\n\n#define medium_density_code_lto1\t0x40\n#define medium_density_code_lto2\t0x42\n#define medium_density_code_lto3\t0x44\n#define medium_density_code_lto4\t0x46\n#define medium_density_code_lto5\t0x58\n#define medium_density_code_lto6\t0x5a\n#define medium_density_code_lto7\t0x5c\n#define medium_density_code_lto7\t0x5c\n#define medium_density_code_lto8_m8 0x5d\n#define medium_density_code_lto8\t0x5e\n#define medium_density_code_lto9\t0x60\n\n#define medium_density_code_j1a\t\t 0x51\n#define medium_density_code_e05\t\t 0x52\n#define medium_density_code_e06\t\t 0x53\n#define medium_density_code_e07\t\t 0x54\n#define medium_density_code_j1a_ENCR 0x71\n#define medium_density_code_e05_ENCR 0x72\n#define medium_density_code_e06_ENCR 0x73\n#define medium_density_code_e07_ENCR 0x74\n\n#define medium_density_code_ait1 0x30\n#define medium_density_code_ait2 0x31\n#define medium_density_code_ait3 0x32\n#define medium_density_code_ait4 0x33\n\n#define medium_density_code_10kA 0x4a\n#define medium_density_code_10kB 0x4b\n#define medium_density_code_10kC 0x4c\n\n#define medium_density_code_9840A 0x42\n#define medium_density_code_9840B 0x42\n#define medium_density_code_9840C 0x45\n#define medium_density_code_9840D 0x46\n\n#define medium_density_code_9940A 0x43\n#define medium_density_code_9940B 0x44\n\n#define medium_density_code_dlt2\t 0x16 /* X3.193-1990 */\n#define medium_density_code_dlt3_2G\t 0x17 /* 2.6G */\n#define medium_density_code_dlt3_6G\t 0x18 /* 6G */\n#define medium_density_code_dlt3_10G 0x19 /* 10G */\n#define medium_density_code_dlt3\t 0x19 /* default to 10G density */\n#define medium_density_code_dlt4_20G 0x1a\n#define medium_density_code_dlt4_35G 0x1b\n#define medium_density_code_dlt4\t 0x1b /* Default to 35G density */\n\n#define medium_density_code_sdlt 0x90\n\n#define medium_density_code_220 0x48\n#define medium_density_code_320 0x49\n#define medium_density_code_600 0x4a\n#define medium_density_code_s4\t0x4b\n\n#define medium_density_code_QIC 0x11\n\n#define medium_density_code_DDS1 0x13\n#define medium_density_code_DDS2 0x24\n#define medium_density_code_DDS3 0x25\n#define medium_density_code_DDS4 0x26\n#define medium_density_code_DDS5 0x47\n\n/* Used by MODE SENSE 'media type' in Mode Parameter Header */\n#define media_type_unknown\t   0x00\n#define media_type_dlt_clean   0x81\n#define media_type_dlt1\t\t   0x82\n#define media_type_dlt3\t\t   0x83\n#define media_type_dlt3xt\t   0x84\n#define media_type_dlt4\t\t   0x85\n#define media_type_lto1_data   0x18\n#define media_type_lto2_data   0x28\n#define media_type_lto3_data   0x38\n#define media_type_lto3_worm   0x3C\n#define media_type_lto4_data   0x48\n#define media_type_lto4_worm   0x4C\n#define media_type_lto5_data   0x58\n#define media_type_lto5_worm   0x5c\n#define media_type_lto6_data   0x68\n#define media_type_lto6_worm   0x6c\n#define media_type_lto7_data   0x78\n#define media_type_lto7_worm   0x7c\n#define media_type_lto8_data   0x88\n#define media_type_lto8_worm   0x8c\n#define media_type_lto9_data   0x98\n#define media_type_lto9_worm   0x9c\n#define media_type_hp_lto_data 0x00\n#define media_type_hp_lto_worm 0x01\n#define media_type_hp_lto_cd   0x80\n\n#define LZO\t 1 /* Using lzo compression libraries */\n#define ZLIB 2 /* Using zlib compression libraries */\n\n/* The remainder of this file defines the interface between the tape drive\n   software and the implementation of a tape cartridge as one or more disk\n   files.\n*/\n\nint\t create_tape(const char *pcl, uint8_t *sam_stat);\nint\t load_partition(const char *pcl, uint8_t *sam_stat, uint8_t error_check, uint8_t partition_number);\nint\t load_tape(const char *pcl, uint8_t *sam_stat);\nvoid unload_tape(uint8_t *sam_stat);\n\nint rewind_tape(uint8_t *sam_stat);\nint position_to_eod(uint8_t *sam_stat);\nint position_to_block(uint32_t blk_no, uint8_t *sam_stat);\nint position_blocks_forw(uint64_t count, uint8_t *sam_stat);\nint position_blocks_back(uint64_t count, uint8_t *sam_stat);\nint position_filemarks_forw(uint64_t count, uint8_t *sam_stat);\nint position_filemarks_back(uint64_t count, uint8_t *sam_stat);\nint change_partition(uint8_t partition_number);\n\nuint32_t read_tape_block(uint8_t *buf, uint32_t size, uint8_t *sam_stat);\n\nint write_filemarks(uint32_t count, uint8_t *sam_stat);\nint write_tape_block(const uint8_t *buf, uint32_t uncomp_size,\n\t\t\t\t\t uint32_t comp_size, const struct encryption *cp,\n\t\t\t\t\t uint8_t comp_type, uint8_t null_type, uint32_t crc, uint8_t *sam_stat);\nint format_partition(uint8_t *sam_stat);\nint format_tape(uint8_t *sam_stat);\n\nint\t\t write_mam(int mam_fd, int mhvtl_fd);\nint\t\t read_mam(int mam_fd, int mhvtl_fd, struct MAM *mamp);\nint\t\t rewriteMAM(uint8_t *sam_stat);\nuint64_t current_tape_offset(void);\nuint64_t current_tape_block(void);\nuint64_t last_block(uint8_t partition_number);\nuint64_t block_from_filemark(uint8_t partition_number, uint32_t filemark);\nuint64_t count_filemarks(int64_t count);\n\nvoid print_raw_header(void);\nvoid print_filemark_count(void);\nvoid print_metadata(void);\nvoid cart_deinit(void);\n\n#endif /* _VTLCART_H_ */\n"
  },
  {
    "path": "include/vtllib.h",
    "content": "/*\n * The shared library libvtlscsi.so function defs\n *\n * Copyright (C) 2005-2025 Mark Harvey markh794@gmail.com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n */\n#ifndef _VTLLIB_H_\n#define _VTLLIB_H_\n\n#ifndef Solaris\n#include <endian.h>\n#include <byteswap.h>\n#endif\n\n#include <stdio.h>\n#include <inttypes.h>\n#include <sys/types.h>\n#include <unistd.h>\n\n#include \"vtl_common.h\"\n#include \"mhvtl_list.h\"\n#include \"vtlcart.h\"\n\n#ifndef MHVTL_CONFIG_PATH\n#define MHVTL_CONFIG_PATH \"/etc/mhvtl\"\n#endif\n\n#ifndef MHVTL_HOME_PATH\n/* Where all the tape data files belong */\n#define MHVTL_HOME_PATH \"/opt/vtl\"\n#endif\n\n/*\nhttp://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/\n */\n#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2 * !!(condition)]))\n\n#define min(x, y) ({\t\t\\\n\ttypeof(x) _x = (x);\t\\\n\ttypeof(y) _y = (y);\t\\\n\t(void) (&_x == &_y);\t\\\n\t_x < _y ? _x : _y; })\n\n#define max(x, y) ({\t\t\\\n\ttypeof(x) _x = (x);\t\\\n\ttypeof(y) _y = (y);\t\\\n\t(void) (&_x == &_y);\t\\\n\t_x > _y ? _x : _y; })\n\n#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))\n\n#define likely(x)\t__builtin_expect((x), 1)\n#define unlikely(x) __builtin_expect((x), 0)\n\n#define STATUS_OK 0\n\n#define STATUS_QUEUE_CMD 0xfe\n\n#define SCSI_SN_LEN 16\n\n#define MAX_BARCODE_LEN\t 16\n#define LEFT_JUST_16_STR \"%-16.16s\"\n\n#define MAX_INQ_ARR_SZ 64\n#define MALLOC_SZ\t   512\n\n#define TAPE_UNLOADED 0\n#define TAPE_LOADED\t  1\n#define TAPE_LOADING  2\n\n#define MIN_SLEEP_TIME\t\t5\n#define DEFLT_BACKOFF_VALUE 400\n\n#define HOME_DIR_PATH_SZ 1024\n#define CONF_DIR_PATH_SZ 1024\n#define CONF_FILE_SZ\t 1024 + 256\n\n#define MAX_PARTITIONS 4\n\ntypedef enum {\n\tDEVICE_CONF,\n\tLIBCONTENTS,\n\tLIBCONTENTS_PERSIST,\n} conf_file;\n\n/*\n * Medium Type Definitions\n */\n#define MEDIA_TYPE_DATA\t\t  0\n#define MEDIA_TYPE_WORM\t\t  1\n#define MEDIA_TYPE_NULL\t\t  2\n#define MEDIA_TYPE_DIAGNOSTIC 3\n#define MEDIA_TYPE_FIRMWARE\t  4\n#define MEDIA_TYPE_CLEAN\t  6\n\n#define MHVTL_NO_COMPRESSION 0\n\n/* status definitions (byte[2] in the element descriptor) */\n#define STATUS_Full\t\t 0x01\n#define STATUS_ImpExp\t 0x02\n#define STATUS_Except\t 0x04\n#define STATUS_Access\t 0x08\n#define STATUS_ExEnab\t 0x10\n#define STATUS_InEnab\t 0x20\n#define STATUS_Reserved6 0x40\n#define STATUS_Reserved7 0x80\n/* internal_status definitions: */\n#define INSTATUS_NO_BARCODE 0x01\n\n#define VOLTAG_LEN 36 /* size of voltag area in RES descriptor */\n\n#define VPD_83_SZ 50\n#define VPD_86_SZ 0x3c\n#define VPD_B0_SZ 4\n#define VPD_B1_SZ SCSI_SN_LEN\n#define VPD_B2_SZ 8\n#define VPD_B5_SZ 8\n#define VPD_C0_SZ 0x28\n\nstruct smc_type_slot {\n\tchar\t type;\n\tuint32_t start;\n\tuint32_t number;\n};\n\nstruct mode {\n\tstruct list_head siblings;\n\tuint8_t\t\t\t pcode;\t\t\t\t /* Page code */\n\tuint8_t\t\t\t subpcode;\t\t\t /* Sub page code */\n\tint32_t\t\t\t pcodeSize;\t\t\t /* Size of page code data. */\n\tuint8_t\t\t\t*pcodePointerBitMap; /* bitmap for changeable data */\n\tuint8_t\t\t\t*pcodePointer;\t\t /* Pointer to page code data */\n\tchar\t\t\t*description;\t\t /* ASCII text 'description' */\n};\n\n/* v2 of the tape media\n * Between BOT & blk #1, is the MAM (Medium Auxiliary Memory)\n */\n#define MAM_VERSION 4\n\nenum MAM_attribute_idx {\n\t/* 0x0000 – 0x03ff : Device */\n\tMAM_REMAINING_CAPACITY,\n\tMAM_MAX_CAPACITY,\n\tMAM_TAPE_ALERT,\n\tMAM_LOAD_COUNT,\n\tMAM_MAM_SPACE_REMAINING,\n\tMAM_ASSIGNING_ORG_1,\n\tMAM_FORMATTED_DENSITY_CODE,\n\tMAM_INITIALIZATION_COUNT,\n\n\t/* 0x008 Not supported */\n\n\tMAM_VOLUME_CHANGE_REFERENCE,\n\tMAM_DEV_MAKE_SERIAL_LAST_LOAD,\n\tMAM_DEV_MAKE_SERIAL_LAST_LOAD1,\n\tMAM_DEV_MAKE_SERIAL_LAST_LOAD2,\n\tMAM_DEV_MAKE_SERIAL_LAST_LOAD3,\n\tMAM_WRITTEN_IN_MEDIUM_LIFE,\n\tMAM_READ_IN_MEDIUM_LIFE,\n\tMAM_WRITTEN_IN_LAST_LOAD,\n\tMAM_READ_IN_LAST_LOAD,\n\n\t/* 0x0400 – 0x07ff : Medium */\n\tMAM_MEDIUM_MANUFACTURER,\n\tMAM_MEDIUM_SERIAL_NUMBER,\n\tMAM_MEDIUM_LENGTH,\n\tMAM_MEDIUM_WIDTH,\n\tMAM_ASSIGNING_ORG_2,\n\tMAM_MEDIUM_DENSITY_CODE,\n\tMAM_MEDIUM_MANUFACTURE_DATE,\n\tMAM_MAM_CAPACITY,\n\tMAM_MEDIUM_TYPE,\n\tMAM_MEDIUM_TYPE_INFORMATION,\n\n\t/* 0x0800 – 0x0bff : Host */\n\tMAM_APPLICATION_VENDOR,\n\tMAM_APPLICATION_NAME,\n\tMAM_APPLICATION_VERSION,\n\tMAM_USER_MEDIUM_TEXT_LABEL,\n\tMAM_DATE_TIME_LAST_WRITTEN,\n\tMAM_LOCALIZATION_IDENTIFIER,\n\tMAM_BARCODE,\n\tMAM_OWNING_HOST_TEXTUAL_NAME,\n\tMAM_MEDIA_POOL,\n\tMAM_APPLICATION_FORMAT_VERSION,\n\tMAM_VOLUME_COHERENCY_INFORMATION,\n\n\t/* 0x0c00 - 0x0fff - Device - Vendor Specific */\n\t/* 0x1000 - 0x13ff - Medium - Vendor Specific */\n\t/* 0x1400 - 0x17ff -  Host  - Vendor Specific */\n\tMAM_VOLUME_LOCK,\n\n\tMAM_ATTRIBUTE_END,\n};\n\nenum MHVTL_attribute_idx {\n\tMAM_MHVTL_RECORD_DIRTY,\n\tMAM_MHVTL_FLAGS,\n\tMAM_MHVTL_MAX_PARTITIONS,\n\tMAM_MHVTL_NUM_PARTITIONS,\n\tMAM_MHVTL_MEDIA_TYPE,\n\n\t/* media_info */\n\tMAM_MHVTL_MEDIAINFO_BITS_PER_MM,\n\tMAM_MHVTL_MEDIAINFO_TRACKS,\n\tMAM_MHVTL_MEDIAINFO_DENSITY_NAME,\n\tMAM_MHVTL_MEDIAINFO_DESCRIPTION,\n\n\tMAM_MHVTL_ATTRIBUTE_END,\n};\n\nstruct MAM_attr {\n\tuint16_t attribute_id;\n\tuint16_t length;\n\tuint8_t\t read_only; /* 0: Not RO 1: RO */\n\tuint8_t\t format;\t/* 0: binary 1: ASCII 2: TEXT */\n\tvoid\t*value;\n};\n\nstruct MHVTL_attr {\n\tuint16_t attribute_id;\n\tuint16_t length;\n\tvoid\t*value;\n};\n\nstruct MAM {\n\tstruct MAM_attr\t  attributes[MAM_ATTRIBUTE_END + 1];\n\tstruct MHVTL_attr mhvtl_attr[MAM_MHVTL_ATTRIBUTE_END + 1];\n\tuint32_t\t\t  tape_fmt_version;\n\tuint32_t\t\t  mam_fmt_version;\n\n\t/* Device (0x0000 - 0x03ff) */\n\tuint64_t remaining_capacity;\n\tuint64_t max_capacity;\n\tuint64_t TapeAlert;\n\tuint64_t LoadCount;\n\tuint64_t MAMSpaceRemaining;\n\tuint8_t\t AssigningOrganization_1[8];\n\tuint8_t\t FormattedDensityCode;\n\tuint8_t\t InitializationCount[2];\n\n\tuint32_t VolumeChangeReference;\n\tuint8_t\t DevMakeSerialLastLoad[40];\n\tuint8_t\t DevMakeSerialLastLoad1[40];\n\tuint8_t\t DevMakeSerialLastLoad2[40];\n\tuint8_t\t DevMakeSerialLastLoad3[40];\n\tuint64_t WrittenInMediumLife;\n\tuint64_t ReadInMediumLife;\n\tuint64_t WrittenInLastLoad;\n\tuint64_t ReadInLastLoad;\n\n\t/* Medium (0x0400 - 0x07ff) */\n\tuint8_t\t MediumManufacturer[8];\n\tuint8_t\t MediumSerialNumber[32];\n\tuint32_t MediumLength;\n\tuint32_t MediumWidth;\n\tuint8_t\t AssigningOrganization_2[8];\n\tuint8_t\t MediumDensityCode;\n\tuint8_t\t MediumManufactureDate[12];\n\tuint64_t MAMCapacity;\n\tuint8_t\t MediumType;\t\t\t/* 0 -> Data, 1 -> WORM, 6 -> Clean */\n\tuint16_t MediumTypeInformation; /* If Clean, max mount */\n\n\t/* Host (0x0800 - 0x0bff) */\n\tuint8_t ApplicationVendor[8];\n\tuint8_t ApplicationName[32];\n\tuint8_t ApplicationVersion[8];\n\tuint8_t UserMediumTextLabel[160];\n\tuint8_t DateTimeLastWritten[12];\n\tuint8_t LocalizationIdentifier;\n\tuint8_t Barcode[32];\n\tuint8_t OwningHostTextualName[80];\n\tuint8_t MediaPool[160];\n\tuint8_t ApplicationFormatVersion[16];\n\tuint8_t VolumeCoherencyInformation[46];\n\n\t/* 0x0c00 - 0x0fff - Device - Vendor Specific */\n\t/* 0x1000 - 0x13ff - Medium - Vendor Specific */\n\t/* 0x1400 - 0x17ff -  Host  - Vendor Specific */\n\tuint8_t VolumeLock;\n\n\t/* mhvtl attributes */\n\tuint8_t\t record_dirty; /* 0 = Record clean, non-zero umount failed. */\n\tuint16_t Flags;\n\tuint8_t\t MediaType; /* LTO1, LTO2, AIT etc (Media_Type_list) */\n\tuint8_t\t max_partitions;\n\tuint8_t\t num_partitions;\n\n\tstruct uniq_media_info {\n\t\tuint32_t bits_per_mm;\n\t\tuint16_t tracks;\n\t\tchar\t density_name[8];\n\t\tchar\t description[32];\n\t} media_info;\n};\n\n#define MAM_FLAGS_ENCRYPTION_FORMAT\t  0x0001\n#define MAM_FLAGS_MEDIA_WRITE_PROTECT 0x0002\n\n#define PCODE_SHIFT\t\t7\n#define PCODE_OFFSET(x) (x & ((1 << PCODE_SHIFT) - 1))\n\nstruct lu_phy_attr;\n\n/* Vital Product Data (VPD) */\nstruct vpd {\n\tuint16_t sz;\n\tuint8_t *data;\n};\n\nenum drive_type_list {\n\tdrive_undefined,\n\tdrive_LTO1,\n\tdrive_LTO2,\n\tdrive_LTO3,\n\tdrive_LTO4,\n\tdrive_LTO5,\n\tdrive_LTO6,\n\tdrive_LTO7,\n\tdrive_LTO8,\n\tdrive_3592_J1A,\n\tdrive_3592_E05,\n\tdrive_3592_E06,\n\tdrive_3592_E07,\n\tdrive_DDS1,\n\tdrive_DDS2,\n\tdrive_DDS3,\n\tdrive_DDS4,\n\tdrive_DDS5,\n\tdrive_AIT1,\n\tdrive_AIT2,\n\tdrive_AIT3,\n\tdrive_AIT4,\n\tdrive_10K_A,\n\tdrive_10K_B,\n\tdrive_10K_C,\n\tdrive_DLT7K,\n\tdrive_DLT8K,\n\tdrive_SDLT,\n\tdrive_SDLT220,\n\tdrive_SDLT320,\n\tdrive_SDLT600,\n\tdrive_SDLT_S4,\n\tdrive_9840_A,\n\tdrive_9840_B,\n\tdrive_9840_C,\n\tdrive_9840_D,\n\tdrive_9940_A,\n\tdrive_9940_B,\n\tdrive_UNKNOWN /* Always last */\n};\n\n/* Uniquely define each media type known */\nenum Media_Type_list {\n\tMedia_undefined,\n\tMedia_LTO1,\n\tMedia_LTO1_CLEAN,\n\tMedia_LTO2,\n\tMedia_LTO2_CLEAN,\n\tMedia_LTO3,\n\tMedia_LTO3_CLEAN,\n\tMedia_LTO3_WORM,\n\tMedia_LTO4,\n\tMedia_LTO4_CLEAN,\n\tMedia_LTO4_WORM,\n\tMedia_LTO5,\n\tMedia_LTO5_CLEAN,\n\tMedia_LTO5_WORM,\n\tMedia_LTO6,\n\tMedia_LTO6_CLEAN,\n\tMedia_LTO6_WORM,\n\tMedia_LTO7,\n\tMedia_LTO7_CLEAN,\n\tMedia_LTO7_WORM,\n\tMedia_LTO8,\n\tMedia_LTO8_CLEAN,\n\tMedia_LTO8_WORM,\n\tMedia_LTO9,\n\tMedia_LTO9_CLEAN,\n\tMedia_LTO9_WORM,\n\tMedia_3592_JA,\n\tMedia_3592_JA_CLEAN,\n\tMedia_3592_JW,\n\tMedia_3592_JB,\n\tMedia_3592_JB_CLEAN,\n\tMedia_3592_JX,\n\tMedia_3592_JX_CLEAN,\n\tMedia_3592_JK,\t\t /* E07 */\n\tMedia_3592_JK_CLEAN, /* E07 */\n\tMedia_AIT1,\n\tMedia_AIT1_CLEAN,\n\tMedia_AIT2,\n\tMedia_AIT2_CLEAN,\n\tMedia_AIT3,\n\tMedia_AIT3_CLEAN,\n\tMedia_AIT4,\n\tMedia_AIT4_CLEAN,\n\tMedia_AIT4_WORM,\n\tMedia_T10KA,\n\tMedia_T10KA_CLEAN,\n\tMedia_T10KA_WORM,\n\tMedia_T10KB,\n\tMedia_T10KB_CLEAN,\n\tMedia_T10KB_WORM,\n\tMedia_T10KC,\n\tMedia_T10KC_CLEAN,\n\tMedia_T10KC_WORM,\n\tMedia_DLT2,\n\tMedia_DLT2_CLEAN,\n\tMedia_DLT3,\n\tMedia_DLT3_CLEAN,\n\tMedia_DLT4,\n\tMedia_DLT4_CLEAN,\n\tMedia_SDLT,\n\tMedia_SDLT_CLEAN,\n\tMedia_SDLT220,\n\tMedia_SDLT220_CLEAN,\n\tMedia_SDLT320,\n\tMedia_SDLT320_CLEAN,\n\tMedia_SDLT600,\n\tMedia_SDLT600_CLEAN,\n\tMedia_SDLT600_WORM,\n\tMedia_SDLT_S4,\n\tMedia_SDLT_S4_CLEAN,\n\tMedia_SDLT_S4_WORM,\n\tMedia_DDS1,\n\tMedia_DDS1_CLEAN,\n\tMedia_DDS2,\n\tMedia_DDS2_CLEAN,\n\tMedia_DDS3,\n\tMedia_DDS3_CLEAN,\n\tMedia_DDS4,\n\tMedia_DDS4_CLEAN,\n\tMedia_DDS5,\n\tMedia_DDS5_CLEAN,\n\tMedia_9840A,\n\tMedia_9840A_CLEAN,\n\tMedia_9840B,\n\tMedia_9840B_CLEAN,\n\tMedia_9840C,\n\tMedia_9840C_CLEAN,\n\tMedia_9840D,\n\tMedia_9840D_CLEAN,\n\tMedia_9940A,\n\tMedia_9940A_CLEAN,\n\tMedia_9940B,\n\tMedia_9940B_CLEAN,\n\tMedia_UNKNOWN /* always last */\n};\n\nstruct scsi_cmd {\n\tuint8_t\t\t\t   *scb; /* SCSI Command Block */\n\tint\t\t\t\t\tscb_len;\n\tint\t\t\t\t\tcdev;\t\t  /* filepointer to char dev */\n\tuseconds_t\t\t\tpollInterval; /* Poor mans Performance counter */\n\tstruct mhvtl_ds\t   *dbuf_p;\n\tstruct lu_phy_attr *lu;\n};\n\n#define SCSI_OP(opcode, fn) \\\n\t[opcode] = {            \\\n\t\t.cmd_perform = fn,  \\\n\t}\n\n#define SCSI_OP_RANGE(lo_op, hi_op, fn) \\\n\t[lo_op... hi_op] = {                \\\n\t\t.cmd_perform = fn,              \\\n\t}\n\nstruct device_type_operations {\n\tuint8_t (*cmd_perform)(struct scsi_cmd *cmd);\n\tint (*pre_cmd_perform)(struct scsi_cmd *cmd, void *p);\n\tint (*post_cmd_perform)(struct scsi_cmd *cmd, void *p);\n};\n\nstruct device_type_template {\n\tstruct device_type_operations ops[256];\n};\n\n#define MAX_INQUIRY_SZ 256\n\n/* Logical Unit information */\nstruct lu_phy_attr {\n\tchar ptype;\n\tchar mode_media_type;\n\tchar online;\n\tchar inquiry[MAX_INQUIRY_SZ];\n\tchar vendor_id[VENDOR_ID_LEN + 1];\n\tchar product_id[PRODUCT_ID_LEN + 1];\n\tchar lu_serial_no[SCSI_SN_LEN];\n\n\tstruct list_head den_list;\n\n\tstruct list_head mode_pg;\n\n\tstruct list_head log_pg;\n\n\tstruct device_type_template *scsi_ops;\n\n\tuint8_t\t   *naa;\n\tstruct vpd *lu_vpd[1 << (PCODE_SHIFT + 1)];\n\n\tFILE *fifo_fd;\n\tchar *fifoname;\n\tint\t  fifo_flag;\n\tint\t  persist; /* Save changes across restarts */\n\n\tuint8_t *sense_p; /* Pointer to sense buffer */\n\n\tvoid *lu_private; /* Private data struct per lu */\n};\n\n/* Drive Info */\nstruct d_info {\n\tstruct list_head siblings;\n\tchar\t\t\t inq_vendor_id[10];\n\tchar\t\t\t inq_product_id[18];\n\tchar\t\t\t inq_product_rev[6];\n\tchar\t\t\t inq_product_sno[12];\n\tlong\t\t\t drv_id; /* drive's send_msg queue ID */\n\tchar\t\t\t online; /* Physical status of drive */\n\tint\t\t\t\t SCSI_BUS;\n\tint\t\t\t\t SCSI_ID;\n\tint\t\t\t\t SCSI_LUN;\n\tchar\t\t\t load_status; /* Tape is 'loaded' by drive */\n\tstruct s_info\t*slot;\n};\n\nstruct m_info { /* Media Info */\n\tstruct list_head siblings;\n\tuint32_t\t\t last_location;\n\tchar\t\t\t barcode[MAX_BARCODE_LEN + 1];\n\tuint8_t\t\t\t media_domain;\n\tuint8_t\t\t\t media_type;\n\tuint8_t\t\t\t cart_type;\n\tuint8_t\t\t\t internal_status; /* internal states */\n};\n\nstruct s_info { /* Slot Info */\n\tstruct list_head siblings;\n\tuint32_t\t\t slot_location;\n\tuint32_t\t\t last_location;\n\tstruct d_info\t*drive;\n\tstruct m_info\t*media;\n\t/* Additional Sense Code & Additional Sense Code Qualifier */\n\tuint16_t asc_ascq;\n\tuint8_t\t status; /* Used for MAP status. */\n\t/* 1 Media Transport, 2 Storage, 3 MAP, 4 Data transfer */\n\tuint8_t element_type;\n\tuint8_t media_domain; /* L700 */\n\tuint8_t media_type;\t  /* L700 */\n};\n\n#define DEF_SMC_PRIV_STATE_MSG_LENGTH 64\n\nstruct smc_priv {\n\tuint32_t\t\t bufsize;\n\tstruct list_head drive_list;\n\tstruct list_head slot_list;\n\tstruct list_head media_list;\n\tint\t\t\t\t commandtimeout; /* Timeout for 'movecommand' */\n\tint\t\t\t\t num_drives;\n\tint\t\t\t\t num_picker;\n\tint\t\t\t\t num_map;\n\tint\t\t\t\t num_storage;\n\tchar\t\t\t cap_closed;\n\tchar\t\t\t*state_msg;\t  /* Custom State message */\n\tchar\t\t\t*movecommand; /* 3rd party command to call */\n\n\tstruct smc_personality_template *pm;\n};\n\nstruct density_info {\n\tuint32_t bits_per_mm;\n\tuint16_t media_width;\n\tuint16_t tracks;\n\tuint32_t capacity;\n\tuint16_t density;\n\tchar\t assigning_org[9];\n\tchar\t density_name[9];\n\tchar\t description[20];\n};\n\nstruct supported_density_list {\n\tstruct list_head\t siblings;\n\tstruct density_info *density_info;\n\tint\t\t\t\t\t rw;\n};\n\nextern uint8_t sense[SENSE_BUF_SIZE];\n\n/* Sense Specific Data - SPC4.5.5.2.4\n * For those sense keys where the invalid byte/field is known\n */\nstruct s_sd {\n\tuint8_t\t byte0;\n\tuint16_t field_pointer;\n};\n\n/* Used by Mode Sense - if set, return block descriptor */\nextern uint8_t modeBlockDescriptor[8];\n\nenum MHVTL_STATE {\n\tMHVTL_STATE_INIT,\n\tMHVTL_STATE_IDLE,\n\t/* Drive operation states */\n\tMHVTL_STATE_UNLOADED,\n\tMHVTL_STATE_LOADING,\n\tMHVTL_STATE_LOADING_CLEAN,\n\tMHVTL_STATE_LOADING_WORM,\n\tMHVTL_STATE_LOADED,\n\tMHVTL_STATE_LOADED_IDLE,\n\tMHVTL_STATE_LOAD_FAILED,\n\tMHVTL_STATE_REWIND,\n\tMHVTL_STATE_POSITIONING,\n\tMHVTL_STATE_LOCATE,\n\tMHVTL_STATE_READING,\n\tMHVTL_STATE_WRITING,\n\tMHVTL_STATE_UNLOADING,\n\tMHVTL_STATE_ERASE,\n\tMHVTL_STATE_VERIFY,\n\n\t/* Library operation states */\n\tMHVTL_STATE_MOVING_DRIVE_2_SLOT,\n\tMHVTL_STATE_MOVING_SLOT_2_DRIVE,\n\tMHVTL_STATE_MOVING_DRIVE_2_MAP,\n\tMHVTL_STATE_MOVING_MAP_2_DRIVE,\n\tMHVTL_STATE_MOVING_SLOT_2_MAP,\n\tMHVTL_STATE_MOVING_MAP_2_SLOT,\n\tMHVTL_STATE_MOVING_DRIVE_2_DRIVE,\n\tMHVTL_STATE_MOVING_SLOT_2_SLOT,\n\tMHVTL_STATE_OPENING_MAP,\n\tMHVTL_STATE_CLOSING_MAP,\n\tMHVTL_STATE_INVENTORY,\n\tMHVTL_STATE_INITIALISE_ELEMENTS,\n\tMHVTL_STATE_ONLINE,\n\tMHVTL_STATE_OFFLINE,\n\tMHVTL_STATE_UNKNOWN,\n};\n\nint\t get_config(char *buf, conf_file conf, long my_id);\nvoid init_mam(struct MAM* mamp);\n\nint\t check_reset(uint8_t *);\nint\t check_inquiry_data_has_changed(uint8_t *);\nvoid reset_device(void);\nvoid set_inquiry_data_changed(void);\n\nvoid sam_unit_attention(uint16_t ascq, uint8_t *sam_stat);\nvoid sam_not_ready(uint16_t ascq, uint8_t *sam_stat);\nvoid sam_illegal_request(uint16_t ascq, struct s_sd *sd, uint8_t *sam_stat);\nvoid sam_medium_error(uint16_t ascq, uint8_t *sam_stat);\nvoid sam_blank_check(uint16_t ascq, uint8_t *sam_stat);\nvoid sam_data_protect(uint16_t ascq, uint8_t *sam_stat);\nvoid sam_hardware_error(uint16_t ascq, uint8_t *sam_stat);\nvoid sam_no_sense(uint8_t key, uint16_t ascq, uint8_t *sam_stat);\n\nvoid\t\t resp_log_select(uint8_t *, uint8_t *);\nint\t\t\t resp_read_position_long(loff_t, uint8_t *, uint8_t *);\nint\t\t\t resp_read_position(loff_t, uint8_t *, uint8_t *);\nuint32_t\t resp_read_media_serial(uint8_t *, uint8_t *, uint8_t *);\nint\t\t\t resp_mode_sense(uint8_t *, uint8_t *, struct mode *, uint8_t, uint8_t *);\nstruct mode *lookup_mode_pg(struct list_head *l, uint8_t pcode, uint8_t subpcode);\nint\t\t\t resp_read_block_limits(struct mhvtl_ds *dbuf_p, int sz);\n\nvoid  hex_dump(uint8_t *, int);\nvoid *zalloc(int sz);\nint\t  chrdev_open(const char *name, unsigned minor);\nint\t  chrdev_create(unsigned minor);\nvoid  chrdev_delete(unsigned minor);\nint\t  oom_adjust(void);\nint\t  open_fifo(FILE **fifo_fd, char *fifoname);\nvoid  status_change(FILE *fifo_fd, int current_status, int my_id, char **msg);\n\nchar *readline(char *s, int len, FILE *f);\nvoid  blank_fill(uint8_t *dest, char *src, int len);\n\nvoid log_opcode(char *opcode, struct scsi_cmd *cmd);\n\nstruct vpd *alloc_vpd(uint16_t sz);\nvoid\t\tdealloc_vpd(struct vpd *pg);\nvoid\t\tcleanup_density_support(struct list_head *l);\n\npid_t add_lu(unsigned minor, struct mhvtl_ctl *ctl);\n\nvoid completeSCSICommand(int, struct mhvtl_ds *ds);\nint\t retrieve_CDB_data(int cdev, struct mhvtl_ds *dbuf_p);\nint\t check_for_running_daemons(unsigned minor);\nint\t free_lock(unsigned minor);\n\nvoid\t   mhvtl_prt_cdb(int l, struct scsi_cmd *cmd);\nvoid\t   checkstrlen(char *s, unsigned int len, int linecount);\nextern int device_type_register(struct lu_phy_attr\t\t\t*lu,\n\t\t\t\t\t\t\t\tstruct device_type_template *t);\n\nvoid process_fifoname(struct lu_phy_attr *lu, char *s, int flag);\n\nuint8_t clear_WORM(struct list_head *l);\nuint8_t set_WORM(struct list_head *l);\nuint8_t clear_compression_mode_pg(struct list_head *l);\nuint8_t set_compression_mode_pg(struct list_head *l, int lvl);\n\nvoid  rmnl(char *s, unsigned char c, int len);\nvoid  truncate_spaces(char *s, int maxlen);\nchar *get_version(void);\n\nvoid update_vpd_80(struct lu_phy_attr *lu, void *p);\nvoid update_vpd_83(struct lu_phy_attr *lu, void *p);\nvoid update_vpd_86(struct lu_phy_attr *lu, void *p);\nvoid update_vpd_b0(struct lu_phy_attr *lu, void *p);\nvoid update_vpd_b1(struct lu_phy_attr *lu, void *p);\nvoid update_vpd_b2(struct lu_phy_attr *lu, void *p);\nvoid update_vpd_c0(struct lu_phy_attr *lu, void *p);\nvoid update_vpd_c1(struct lu_phy_attr *lu, void *p);\n\nint\t get_fifo_count(void);\nint\t dec_fifo_count(void);\nint\t inc_fifo_count(void);\nvoid cleanup_msg(void);\n\nint add_density_support(struct list_head *l, struct density_info *di, int rw);\nint add_drive_media_list(struct lu_phy_attr *lu, int status, char *s);\n\nvoid\t\t find_media_home_directory(char *config_directory, long lib_id);\nunsigned int set_media_params(struct MAM *mamp, char *density);\n\nchar *slot_type_str(int type);\nvoid  init_smc_log_pages(struct lu_phy_attr *lu);\nvoid  init_smc_mode_pages(struct lu_phy_attr *lu);\nvoid  bubbleSort(int *array, int size);\nvoid  sort_library_slot_type(struct lu_phy_attr *lu, struct smc_type_slot *type);\n\nvoid ymd(int *year, int *month, int *day, int *hh, int *min, int *sec);\nvoid opcode_6_params(struct scsi_cmd *cmd, int *num, int *sz);\n\n/* ======== Global variables ========*/\n/* In vtllib.c */\nextern struct MAM\t\t  mam;\nextern struct priv_lu_ssc lu_ssc;\nextern struct lu_phy_attr lunit;\nextern struct encryption  app_encryption_state; /* Stores the encryption info the application sent us */\nextern int\t\t\t\t  current_state;\t\t/* Last status sent to fifo */\nextern int\t\t\t\t  lbp_rscrc_be;\t\t\t/* Logical Block Protection: RS-CRC big-endian */\nextern int\t\t\t\t  OK_to_write;\nextern uint8_t\t\t\t  sense[SENSE_BUF_SIZE];\nextern uint8_t\t\t\t  modeBlockDescriptor[8]; /* Used by Mode Sense - if set, return block descriptor */\nextern char\t\t\t\t  home_directory[HOME_DIR_PATH_SZ + 1];\n\nextern uint8_t verbose;\nextern uint8_t debug;\nextern long\t   my_id;\n\n/* In vtlcart.c */\nextern struct blk_header *c_pos; /* current position, declared and initialised in vtlcart.c */\n\n#endif /*  _VTLLIB_H_ */\n"
  },
  {
    "path": "kernel/.gitignore",
    "content": "TAGS\n*.cmd\n*.mod"
  },
  {
    "path": "kernel/Makefile",
    "content": "#\n# $Id: Makefile,v 1.2.2.3 2006-08-30 06:35:14 markh Exp $\n#\n\n# CC=/usr/bin/gcc\n#\nEXTRA_CFLAGS += -I$(SRC)/../include\nEXTRA_CFLAGS += -DMHVTL_DEBUG\n\nccflags-y += -I$(M)/../include/common -DMHVTL_DEBUG\nobj-m\t:= mhvtl.o\nvtl-objs := mhvtl.o\n\nV\t?= $(shell uname -r)\n\nifeq ($(KDIR),)\nifneq ($(wildcard /lib/modules/$(V)/build),)\nKDIR := /lib/modules/$(V)/build\nelse\nifneq ($(wildcard /usr/src/linux-headers-$(V)),)\nKDIR := /usr/src/linux-headers-$(V)\nendif\nendif\nendif\n\nexport KDIR\n\nTOPDIR ?= $(CURDIR)/..\nFIRMWAREDIR ?= $(shell awk '/^%.*_firmwarepath/ {print $$3}' $(TOPDIR)/mhvtl-utils.spec)\n\nPWD\t:= $(shell pwd)\n\nall: mhvtl.ko ../mhvtl_kernel.tgz\n\nmhvtl.ko:\tconfig.h\n\t$(MAKE) -C $(KDIR) M=$(PWD) modules\n\nconfig.h: config.sh\n\t./config.sh\n\ninstall: all\n\t[ -d $(DESTDIR)$(FIRMWAREDIR)/mhvtl ] || mkdir -p $(DESTDIR)$(FIRMWAREDIR)/mhvtl\n\tinstall -m 755 ../mhvtl_kernel.tgz $(DESTDIR)$(FIRMWAREDIR)/mhvtl/\n\tinstall -o root -g root -m 644 mhvtl.ko /lib/modules/$(V)/kernel/drivers/scsi/\n\tdepmod -a\n\nuninstall: distclean\n\trm -f /lib/modules/$(V)/kernel/drivers/scsi/mhvtl.ko $(DESTDIR)$(FIRMWAREDIR)/mhvtl/mhvtl_kernel.tgz\n\tdepmod -a\n\n../mhvtl_kernel.tgz:  $(wildcard ./*.c) $(wildcard ./*.h) $(wildcard ../include/common/*.h) \\\n\t\t\t\t\t  config.sh Makefile\n\ttar --sort=name --mtime=@1 --format=gnu --transform='s|.*/||' -czf $@ $^\n\ninstall-bkup:\n\tcp mhvtl.ko ~/mhvtl-$(V)_`uname -m`.ko\n\ntags:\n\tctags -R *\n\n# ========== Cleaning ==========\n\n.PHONY: clean\nclean:\n\t$(RM) mhvtl.ko\n\t$(RM) *.o\n\t$(RM) TAGS\n\t$(RM) config.h\n\n.PHONY: distclean\ndistclean: clean\n\t$(RM) .*.o.d \\\n\t    mhvtl.mod.c \\\n\t    Modules.symvers \\\n\t    Module.symvers \\\n\t    .mhvtl.ko.cmd \\\n\t    .mhvtl.o.cmd \\\n\t    .mhvtl.mod.o.cmd \\\n\t    .event.o.cmd \\\n\t    .event.o.d \\\n\t    .Module.symvers.cmd \\\n\t    .mhvtl.mod.cmd \\\n\t    .modules.order.cmd \\\n\t    mhvtl.mod \\\n\t    Module.markers \\\n\t    modules.order \\\n\t    mhvtl.ko.unsigned \\\n\t    .mhvtl.ko.unsigned.cmd \\\n\t    config.h\n\t$(RM) -r .tmp_versions"
  },
  {
    "path": "kernel/backport.h",
    "content": "/*\n * Include wrappers for older kernels as interfaces change\n */\n\n#include \"config.h\"\n\n#ifndef SG_SEGMENT_SZ\n#define SG_SEGMENT_SZ 65536\n#endif\n\n#ifndef slab_flags_t\ntypedef unsigned __bitwise slab_flags_t;\n#endif\n\n/*\n * Copied kmem_cache_create_usercopy() from scst project\n */\n#if !defined(HAVE_KMEM_CACHE_CREATE_USERCOPY)\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23)\nstatic inline struct kmem_cache *kmem_cache_create_usercopy(const char\t*name,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tunsigned int size, unsigned int align,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tslab_flags_t flags,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tunsigned int useroffset, unsigned int usersize,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tvoid (*ctor)(void *)) {\n\treturn kmem_cache_create(name, size, align, flags, ctor, NULL);\n}\n#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0)\nstatic inline struct kmem_cache *kmem_cache_create_usercopy(const char\t*name,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tunsigned int size, unsigned int align,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tslab_flags_t flags,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tunsigned int useroffset, unsigned int usersize,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tvoid (*ctor)(void *)) {\n\treturn kmem_cache_create(name, size, align, flags, ctor);\n}\n#endif\n#endif\n\n#if !defined(HAVE_FILE_INODE)\n/*\n * See also patch \"new helper: file_inode(file)\" (commit ID\n * 496ad9aa8ef448058e36ca7a787c61f2e63f0f54).\n */\nstatic inline struct inode *file_inode(struct file *f) {\n\treturn f->f_path.dentry->d_inode;\n}\n#endif\n\n#if !defined(HAVE_SYSFS_EMIT)\n/* https://patches.linaro.org/project/stable/patch/20210305120853.392925382@linuxfoundation.org/ */\n/**\n *\tsysfs_emit - scnprintf equivalent, aware of PAGE_SIZE buffer.\n *\t@buf:\tstart of PAGE_SIZE buffer.\n *\t@fmt:\tformat\n *\t@...:\toptional arguments to @format\n *\n *\n * Returns number of characters written to @buf.\n */\nstatic int sysfs_emit(char *buf, const char *fmt, ...) {\n\tva_list args;\n\tint\t\tlen;\n\n\tif (WARN(!buf || offset_in_page(buf),\n\t\t\t \"invalid sysfs_emit: buf:%p\\n\", buf))\n\t\treturn 0;\n\n\tva_start(args, fmt);\n\tlen = vscnprintf(buf, PAGE_SIZE, fmt, args);\n\tva_end(args);\n\n\treturn len;\n}\n#endif\n\n#if !defined(USE_TIMER_DELETE_NOT_DEL_TIMER)\n#define timer_delete_sync del_timer_sync\n#endif\n\n/*\n * 6.16 kernel change, from \"from_timer()\" to \"timer_container_of()\" in timer.h.\n */\n#if !defined(FROM_TIMER_NOW_TIMER_CONTAINER_OF)\n#define timer_container_of from_timer\n#endif\n"
  },
  {
    "path": "kernel/config.sh",
    "content": "#!/usr/bin/env bash\n# vim: tabstop=4 shiftwidth=4 expandtab colorcolumn=80 foldmethod=marker :\n\n# uncomment the next line to enable script debugging\n# set -x\n\n# make sure we have the kernel directory defined\nif [ -z \"${KDIR}\" ] ; then\n    echo \"error: you must supply environment variable KDIR\" 1>&2\n    echo \"       or you do not have the kernel-devel installed\" 1>&2\n    exit 1\nfi\n\n#\n# \"syms\" is an associative array, where the \"key\"\n# is a symbol that we try to find (using grep) in\n# the \"value\", i.e. we try to find the string\n# \"sysfs_emit\" in the include file sysfs.h. Based\n# on that, we create a cpp #define or #undef.\n#\ndeclare -A syms\nsyms[kmem_cache_create_usercopy]='slab.h'\nsyms[file_inode]='fs.h'\nsyms[sysfs_emit]='sysfs.h'\n\noutput='config.h'\nkparent=\"${KDIR%/*}\"\n\n#\n# use the \"fs.h\" to determine where the kernel headers are located\n#\nif [ -e \"${KDIR}/include/linux/fs.h\" ]\nthen\n    hdrs=\"${KDIR}/include\"\nelif [ -e \"${kparent}/source/include/linux/fs.h\" ]\nthen\n    hdrs=\"${kparent}/source/include\"\nelse\n    echo \"Cannot infer kernel headers location\" 1>&2\n    exit 1\nfi\n\nrm -f \"${output}\"\n\ncat <<EOF >\"${output}\"\n/* Autogenerated by kernel/config.sh - do not edit\n */\n\n#ifndef _MHVTL_KERNEL_CONFIG_H\n#define _MHVTL_KERNEL_CONFIG_H\n\n\nEOF\n\n#\n# start checking for compatability issues\n#\n\n#\n# first, check the symbols in our associative array\n#\nfor sym in ${!syms[@]}\ndo\n    grep -q \"${sym}\" \"${hdrs}/linux/${syms[$sym]}\"\n    if [ $? -eq 0 ]\n    then\n        printf '#define HAVE_%s\\n' \\\n            \"$( echo \"${sym}\" | tr [:lower:] [:upper:] )\" >> \"${output}\"\n    else\n        printf '#undef HAVE_%s\\n' \\\n            \"$( echo \"${sym}\" | tr [:lower:] [:upper:] )\" >> \"${output}\"\n    fi\ndone\n\n#\n# do we have a \"genhd.h\" present?\n#\nif [ -e \"${hdrs}/linux/genhd.h\" ]; then\n    echo \"#define HAVE_GENHD\"\nelse\n    echo \"#undef HAVE_GENHD\"\nfi >> \"${output}\"\n\n#\n# see if \"struct file_operations\" has member \"unlocked_ioctl\"\n# (otherwise, just \"ioctl\")\n#\nsyms[file_operations]='fs.h'\nif grep -q unlocked_ioctl \"${hdrs}/linux/fs.h\"; then\n    echo \"#ifndef HAVE_UNLOCKED_IOCTL\"\n    echo \"#define HAVE_UNLOCKED_IOCTL\"\n    echo \"#endif\"\nelse\n    echo \"#undef HAVE_UNLOCKED_IOCTL\"\nfi >> \"${output}\"\n\n#\n# check for the scsi queue command taking one or two args\n#\nstr=$( grep 'rc = func_name##_lck' ${hdrs}/scsi/scsi_host.h )\nif [[ \"$str\" == *,* ]] ; then\n    echo \"#undef QUEUECOMMAND_LCK_ONE_ARG\"\nelse\n    echo \"#ifndef QUEUECOMMAND_LCK_ONE_ARG\"\n    echo \"#define QUEUECOMMAND_LCK_ONE_ARG\"\n    echo \"#endif\"\nfi >> \"${output}\"\n\n#\n# check for DEFINE_SEMAPHORE() taking an argument or not\n#\nif grep -q 'DEFINE_SEMAPHORE(_name, _n)' \"${hdrs}/linux/semaphore.h\"; then\n    echo \"#ifndef DEFINE_SEMAPHORE_HAS_NUMERIC_ARG\"\n    echo \"#define DEFINE_SEMAPHORE_HAS_NUMERIC_ARG\"\n    echo \"#endif\"\nelse\n    echo \"#undef DEFINE_SEMAPHORE_HAS_NUMERIC_ARG\"\nfi >> \"${output}\"\n\n#\n# check if scsi_host_template argument to scsi_host_alloc\n# is const\n#\nif grep -F -q 'extern struct Scsi_Host *scsi_host_alloc(const' \\\n        \"${hdrs}/scsi/scsi_host.h\"; then\n    # the first argument to scsi_host_alloc needs to be a \"const\"\n    echo \"#ifndef DEFINE_CONST_STRUCT_SCSI_HOST_TEMPLATE\"\n    echo \"#define DEFINE_CONST_STRUCT_SCSI_HOST_TEMPLATE\"\n    echo \"#endif\"\nelse\n    echo \"#undef DEFINE_CONST_STRUCT_SCSI_HOST_TEMPLATE\"\nfi >> \"${output}\"\n\n#\n# We need to find the definition for \"struct bus_type\", so that we\n# can if the \"match\" member of this struct, which points to a function,\n# has a 2nd argument that is const or not.\n#\n\n# The pattern to find (if \"const\" is needed)\npat='int (*match)(struct device *dev, const struct device_driver *drv);'\n\n# First, find the file\nbus_type_def_file=$(grep -Rl 'struct bus_type {' ${hdrs})\n: {bus_type_def_file:=\"not-found\"}\n\n# Now check for the 2nd argument needs a \"const\"\nif [ -r \"$bus_type_def_file\" ] &&\n    grep -F -q \"$pat\" \"$bus_type_def_file\"; then\n    # the second argument needs a \"const\" definition\n    echo \"#ifndef DEFINE_CONST_STRUCT_DEVICE_DRIVER\"\n    echo \"#define DEFINE_CONST_STRUCT_DEVICE_DRIVER\"\n    echo \"#endif\"\nelse\n    echo \"#undef DEFINE_CONST_STRUCT_DEVICE_DRIVER\"\nfi >> \"${output}\"\n\n#\n# check if slave_configure has been renamed to sdev_configure\n#\npat='int (* sdev_configure)(struct scsi_device *, struct queue_limits *lim);'\nif grep -F -q \"$pat\" \"${hdrs}/scsi/scsi_host.h\"; then\n    echo \"#ifndef DEFINE_QUEUE_LIMITS_SCSI_DEV_CONFIGURE\"\n    echo \"#define DEFINE_QUEUE_LIMITS_SCSI_DEV_CONFIGURE\"\n    echo \"#endif\"\nelse\n    echo \"#undef DEFINE_QUEUE_LIMITS_SCSI_DEV_CONFIGURE\"\nfi >> \"${output}\"\n\n#\n# check if del_timer_sync() has been renamed to timer_delete()\n#\nif grep -F -q 'int timer_delete_sync(' \"${hdrs}/linux/timer.h\"; then\n    echo \"#ifndef USE_TIMER_DELETE_NOT_DEL_TIMER\"\n    echo \"#define USE_TIMER_DELETE_NOT_DEL_TIMER\"\n    echo \"#endif\"\nelse\n    echo \"#undef USE_TIMER_DELETE_NOT_DEL_TIMER\"\nfi >> \"${output}\"\n\n#\n# has \"from_timer()\" been renamed to \"timer_container_of()\"?\n#\nif grep -F -q 'timer_container_of(' \"${hdrs}/linux/timer.h\"; then\n    echo \"#ifndef FROM_TIMER_NOW_TIMER_CONTAINER_OF\"\n    echo \"#define FROM_TIMER_NOW_TIMER_CONTAINER_OF\"\n    echo \"#endif\"\nelse\n    echo \"#undef FROM_TIMER_NOW_TIMER_CONTAINER_OF\"\nfi >> \"${output}\"\n\nprintf '\\n\\n#endif /* _MHVTL_KERNEL_CONFIG_H */\\n' >> \"${output}\"\n"
  },
  {
    "path": "kernel/fetch.c",
    "content": "\n/*\n * Copy data from SCSI command buffer to device buffer\n *  (SCSI command buffer -> user space)\n *\n * Returns number of bytes fetched into 'arr'/FIFO or -1 if error.\n */\nstatic int mhvtl_fetch_to_dev_buffer(struct scsi_cmnd *scp, char __user *arr,\n\t\t\t\t\t\t\t\t\t int max_arr_len) {\n\tint\t\t\t\t\tk, req_len, act_len, len, active;\n\tint\t\t\t\t\tretval;\n\tvoid\t\t\t   *kaddr;\n\tvoid\t\t\t   *kaddr_off;\n\tstruct scatterlist *sg;\n\n\tif (0 == scp->request_bufflen)\n\t\treturn 0;\n\tif (NULL == scp->request_buffer)\n\t\treturn -1;\n\tif (NULL == arr) {\n\t\tpr_crit(\"%s, userspace pointer is NULL\\n\", __func__);\n\t\tWARN_ON(1);\n\t}\n\n\tif (!((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||\n\t\t  (scp->sc_data_direction == DMA_TO_DEVICE)))\n\t\treturn -1;\n\tif (0 == scp->use_sg) {\n\t\treq_len = scp->request_bufflen;\n\t\tact_len = (req_len < max_arr_len) ? req_len : max_arr_len;\n\t\tif (copy_to_user(arr, scp->request_buffer, act_len))\n\t\t\treturn -1;\n\t\treturn act_len;\n\t}\n\tsg = (struct scatterlist *)scp->request_buffer;\n\tfor (k = 0, req_len = 0, active = 0; k < scp->use_sg; ++k, ++sg) {\n\t\tkaddr = (unsigned char *)kmap(sg->page);\n\t\tif (NULL == kaddr)\n\t\t\treturn -1;\n\t\tkaddr_off = (unsigned char *)kaddr + sg->offset;\n\t\tlen\t\t  = sg->length;\n\t\tif ((req_len + len) > max_arr_len) {\n\t\t\tlen\t   = max_arr_len - req_len;\n\t\t\tactive = 1;\n\t\t}\n\t\tretval = copy_to_user(arr + req_len, kaddr_off, len);\n\t\tkunmap(sg->page);\n\t\tif (retval) {\n\t\t\tpr_err(\"mhvtl: %s[%d] failed to copy_to_user()\\n\",\n\t\t\t\t   __func__, __LINE__);\n\t\t\treturn -1;\n\t\t}\n\t\tif (active)\n\t\t\treturn req_len + len;\n\t\treq_len += sg->length;\n\t}\n\treturn req_len;\n}\n\n/*\n * fill_from_user_buffer : Retrieves data from user-space into SCSI\n * buffer(s)\n\n Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid .\n */\nstatic int mhvtl_fill_from_user_buffer(struct scsi_cmnd *scp, char __user *arr,\n\t\t\t\t\t\t\t\t\t   int arr_len) {\n\tint\t\t\t\t\tk, req_len, act_len, len, active;\n\tint\t\t\t\t\tretval;\n\tvoid\t\t\t   *kaddr;\n\tvoid\t\t\t   *kaddr_off;\n\tstruct scatterlist *sg;\n\n\tif (0 == scp->request_bufflen)\n\t\treturn 0;\n\tif (NULL == scp->request_buffer)\n\t\treturn DID_ERROR << 16;\n\tif (!((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||\n\t\t  (scp->sc_data_direction == DMA_FROM_DEVICE)))\n\t\treturn DID_ERROR << 16;\n\tif (0 == scp->use_sg) {\n\t\treq_len = scp->request_bufflen;\n\t\tact_len = (req_len < arr_len) ? req_len : arr_len;\n\t\tif (copy_from_user(scp->request_buffer, arr, act_len))\n\t\t\tpr_err(\"%s[%d]: failed to copy_from_user()\\n\",\n\t\t\t\t   __func__, __LINE__);\n\n\t\tscp->resid = req_len - act_len;\n\t\treturn 0;\n\t}\n\tactive = 1;\n\tsg\t   = (struct scatterlist *)scp->request_buffer;\n\tfor (k = 0, req_len = 0, act_len = 0; k < scp->use_sg; ++k, ++sg) {\n\t\tif (active) {\n\t\t\tkaddr = (unsigned char *)kmap(sg->page);\n\t\t\tif (NULL == kaddr)\n\t\t\t\treturn DID_ERROR << 16;\n\t\t\tkaddr_off = (unsigned char *)kaddr + sg->offset;\n\t\t\tlen\t\t  = sg->length;\n\t\t\tif ((req_len + len) > arr_len) {\n\t\t\t\tactive = 0;\n\t\t\t\tlen\t   = arr_len - req_len;\n\t\t\t}\n\t\t\tretval = copy_from_user(kaddr_off, arr + req_len, len);\n\t\t\tkunmap(sg->page);\n\t\t\tif (retval) {\n\t\t\t\tpr_err(\"mhvtl: %s[%d] failed to copy_from_user()\\n\",\n\t\t\t\t\t   __func__, __LINE__);\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tact_len += len;\n\t\t}\n\t\treq_len += sg->length;\n\t}\n\tscp->resid = req_len - act_len;\n\n\treturn 0;\n}\n\n/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */\nstatic int mhvtl_fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,\n\t\t\t\t\t\t\t\t\t  int arr_len) {\n\tint\t\t\t\t\tk, req_len, act_len, len, active;\n\tvoid\t\t\t   *kaddr;\n\tvoid\t\t\t   *kaddr_off;\n\tstruct scatterlist *sg;\n\n\tif (0 == scp->request_bufflen)\n\t\treturn 0;\n\tif (NULL == scp->request_buffer)\n\t\treturn DID_ERROR << 16;\n\tif (!((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||\n\t\t  (scp->sc_data_direction == DMA_FROM_DEVICE)))\n\t\treturn DID_ERROR << 16;\n\tif (0 == scp->use_sg) {\n\t\treq_len = scp->request_bufflen;\n\t\tact_len = (req_len < arr_len) ? req_len : arr_len;\n\t\tmemcpy(scp->request_buffer, arr, act_len);\n\t\tscp->resid = req_len - act_len;\n\t\treturn 0;\n\t}\n\tactive = 1;\n\tsg\t   = (struct scatterlist *)scp->request_buffer;\n\tfor (k = 0, req_len = 0, act_len = 0; k < scp->use_sg; ++k, ++sg) {\n\t\tif (active) {\n\t\t\tkaddr = (unsigned char *)\n\t\t\t\tkmap_atomic(sg->page, KM_USER0);\n\t\t\tif (NULL == kaddr)\n\t\t\t\treturn DID_ERROR << 16;\n\t\t\tkaddr_off = (unsigned char *)kaddr + sg->offset;\n\t\t\tlen\t\t  = sg->length;\n\t\t\tif ((req_len + len) > arr_len) {\n\t\t\t\tactive = 0;\n\t\t\t\tlen\t   = arr_len - req_len;\n\t\t\t}\n\t\t\tmemcpy(kaddr_off, arr + req_len, len);\n\t\t\tkunmap_atomic(kaddr, KM_USER0);\n\t\t\tact_len += len;\n\t\t}\n\t\treq_len += sg->length;\n\t}\n\tscp->resid = req_len - act_len;\n\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/fetch24.c",
    "content": "\n/*\n * Copy data from SCSI command buffer to device buffer\n *  (SCSI command buffer -> user space)\n *\n * Returns number of bytes fetched into 'arr'/FIFO or -1 if error.\n */\nstatic int mhvtl_fetch_to_dev_buffer(struct scsi_cmnd *scp, char __user *arr,\n\t\t\t\t\t\t\t\t\t int max_arr_len) {\n\tint\t\t\t\t\tk, req_len, act_len, len, active;\n\tint\t\t\t\t\tretval;\n\tvoid\t\t\t   *kaddr;\n\tvoid\t\t\t   *kaddr_off;\n\tstruct scatterlist *sg;\n\n\tif (0 == scp->request_bufflen)\n\t\treturn 0;\n\tif (NULL == scp->request_buffer)\n\t\treturn -1;\n\tif (NULL == arr) {\n\t\tpr_err(\"%s, userspace pointer is NULL\\n\", __func__);\n\t\tWARN_ON(1);\n\t}\n\n\tif (!((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||\n\t\t  (scp->sc_data_direction == DMA_TO_DEVICE)))\n\t\treturn -1;\n\tif (0 == scp->use_sg) {\n\t\treq_len = scp->request_bufflen;\n\t\tact_len = (req_len < max_arr_len) ? req_len : max_arr_len;\n\t\tif (copy_to_user(arr, scp->request_buffer, act_len))\n\t\t\treturn -1;\n\t\treturn act_len;\n\t}\n\tactive\t= 1;\n\treq_len = 0;\n\tact_len = 0;\n\tscsi_for_each_sg(scp, sg, scp->use_sg, k) {\n\t\tif (active) {\n\t\t\tkaddr = (unsigned char *)kmap(sg_page(sg));\n\t\t\tif (NULL == kaddr)\n\t\t\t\treturn DID_ERROR << 16;\n\t\t\tkaddr_off = (unsigned char *)kaddr + sg->offset;\n\t\t\tlen\t\t  = sg->length;\n\t\t\tif ((req_len + len) > max_arr_len) {\n\t\t\t\tactive = 0;\n\t\t\t\tlen\t   = max_arr_len - req_len;\n\t\t\t}\n\t\t\tretval = copy_to_user(arr + act_len, kaddr_off, len);\n\t\t\tkunmap(sg_page(sg));\n\t\t\tif (retval) {\n\t\t\t\tpr_err(\"mhvtl: %s[%d] failed to \"\n\t\t\t\t\t   \"copy_to_user()\\n\",\n\t\t\t\t\t   __func__, __LINE__);\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tact_len += len;\n\t\t}\n\t\treq_len += sg->length;\n\t}\n\tif (scp->resid)\n\t\tscp->resid -= act_len;\n\telse\n\t\tscp->resid = req_len - act_len;\n\treturn 0;\n}\n\n/*\n * fill_from_user_buffer : Retrieves data from user-space into SCSI\n * buffer(s)\n\n Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid .\n */\nstatic int mhvtl_fill_from_user_buffer(struct scsi_cmnd *scp, char __user *arr,\n\t\t\t\t\t\t\t\t\t   int arr_len) {\n\tint\t\t\t\t\tk, req_len, act_len, len, active;\n\tint\t\t\t\t\tretval;\n\tvoid\t\t\t   *kaddr;\n\tvoid\t\t\t   *kaddr_off;\n\tstruct scatterlist *sg;\n\n\tif (0 == scp->request_bufflen)\n\t\treturn 0;\n\tif (NULL == scp->request_buffer)\n\t\treturn DID_ERROR << 16;\n\tif (!((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||\n\t\t  (scp->sc_data_direction == DMA_FROM_DEVICE)))\n\t\treturn DID_ERROR << 16;\n\tif (0 == scp->use_sg) {\n\t\treq_len = scp->request_bufflen;\n\t\tact_len = (req_len < arr_len) ? req_len : arr_len;\n\t\tif (copy_from_user(scp->request_buffer, arr, act_len))\n\t\t\tpr_err(\"%s[%d]: failed to copy_from_user()\\n\",\n\t\t\t\t   __func__, __LINE__);\n\n\t\tscp->resid = req_len - act_len;\n\t\treturn 0;\n\t}\n\tactive\t= 1;\n\treq_len = 0;\n\tact_len = 0;\n\tscsi_for_each_sg(scp, sg, scp->use_sg, k) {\n\t\tif (active) {\n\t\t\tkaddr = (unsigned char *)kmap(sg_page(sg));\n\t\t\tif (NULL == kaddr)\n\t\t\t\treturn DID_ERROR << 16;\n\t\t\tkaddr_off = (unsigned char *)kaddr + sg->offset;\n\t\t\tlen\t\t  = sg->length;\n\t\t\tif ((req_len + len) > arr_len) {\n\t\t\t\tactive = 0;\n\t\t\t\tlen\t   = arr_len - req_len;\n\t\t\t}\n\t\t\tretval = copy_from_user(kaddr_off, arr + req_len, len);\n\t\t\tkunmap(sg_page(sg));\n\t\t\tif (retval) {\n\t\t\t\tpr_err(\"mhvtl: %s[%d] failed to copy_from_user()\\n\",\n\t\t\t\t\t   __func__, __LINE__);\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tact_len += len;\n\t\t}\n\t\treq_len += sg->length;\n\t}\n\tif (scp->resid)\n\t\tscp->resid -= act_len;\n\telse\n\t\tscp->resid = req_len - act_len;\n\n\treturn 0;\n}\n\n/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */\nstatic int mhvtl_fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,\n\t\t\t\t\t\t\t\t\t  int arr_len) {\n\tint\t\t\t\t\tk, req_len, act_len, len, active;\n\tvoid\t\t\t   *kaddr;\n\tvoid\t\t\t   *kaddr_off;\n\tstruct scatterlist *sg;\n\n\tif (0 == scp->request_bufflen)\n\t\treturn 0;\n\tif (NULL == scp->request_buffer)\n\t\treturn DID_ERROR << 16;\n\tif (!((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||\n\t\t  (scp->sc_data_direction == DMA_FROM_DEVICE)))\n\t\treturn DID_ERROR << 16;\n\tif (0 == scp->use_sg) {\n\t\treq_len = scp->request_bufflen;\n\t\tact_len = (req_len < arr_len) ? req_len : arr_len;\n\t\tmemcpy(scp->request_buffer, arr, act_len);\n\t\tscp->resid = req_len - act_len;\n\t\treturn 0;\n\t}\n\tactive\t= 1;\n\treq_len = act_len = 0;\n\tscsi_for_each_sg(scp, sg, scp->use_sg, k) {\n\t\tif (active) {\n\t\t\tkaddr = (unsigned char *)\n\t\t\t\tkmap_atomic(sg_page(sg), KM_USER0);\n\t\t\tif (NULL == kaddr)\n\t\t\t\treturn DID_ERROR << 16;\n\t\t\tkaddr_off = (unsigned char *)kaddr + sg->offset;\n\t\t\tlen\t\t  = sg->length;\n\t\t\tif ((req_len + len) > arr_len) {\n\t\t\t\tactive = 0;\n\t\t\t\tlen\t   = arr_len - req_len;\n\t\t\t}\n\t\t\tmemcpy(kaddr_off, arr + req_len, len);\n\t\t\tkunmap_atomic(kaddr, KM_USER0);\n\t\t\tact_len += len;\n\t\t}\n\t\treq_len += sg->length;\n\t}\n\tif (scp->resid)\n\t\tscp->resid -= act_len;\n\telse\n\t\tscp->resid = req_len - act_len;\n\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/fetch26.c",
    "content": "\n/*\n * Routines based on linux/lib/scatterlist.c\n */\n\n/**\n * sg_copy_buffer - Copy data between a linear buffer and an SG list\n * @sgl:\t\t The SG list\n * @nents:\t\t Number of SG entries\n * @buf:\t\t Where to copy from\n * @buflen:\t\t The number of bytes to copy\n * @to_buffer:\t\t transfer direction (non zero == from an sg list to a\n *\t\t\t buffer, 0 == from a buffer to an sg list\n *\n * Returns the number of copied bytes.\n *\n **/\nstatic size_t mhvtl_sg_copy_user(struct scatterlist *sgl, unsigned int nents,\n\t\t\t\t\t\t\t\t __user void *buf, size_t buflen, int to_buffer) {\n\tstruct scatterlist *sg;\n\tsize_t\t\t\t\tbuf_off = 0;\n\tint\t\t\t\t\ti;\n\tint\t\t\t\t\tret;\n\n\tfor_each_sg(sgl, sg, nents, i) {\n\t\tstruct page *page;\n\t\tint\t\t\t n\t\t = 0;\n\t\tunsigned int sg_off\t = sg->offset;\n\t\tunsigned int sg_copy = sg->length;\n\n\t\tif (sg_copy > buflen)\n\t\t\tsg_copy = buflen;\n\t\tbuflen -= sg_copy;\n\n\t\twhile (sg_copy > 0) {\n\t\t\tunsigned int page_copy;\n\t\t\tvoid\t\t*p;\n\n\t\t\tpage_copy = PAGE_SIZE - sg_off;\n\t\t\tif (page_copy > sg_copy)\n\t\t\t\tpage_copy = sg_copy;\n\n\t\t\tpage = nth_page(sg_page(sg), n);\n\t\t\tp\t = kmap_atomic(page, KM_BIO_SRC_IRQ);\n\n\t\t\tif (to_buffer)\n\t\t\t\tret = copy_to_user(buf + buf_off, p + sg_off, page_copy);\n\t\t\telse {\n\t\t\t\tret = copy_from_user(p + sg_off, buf + buf_off, page_copy);\n\t\t\t\tflush_kernel_dcache_page(page);\n\t\t\t}\n\n\t\t\tkunmap_atomic(p, KM_BIO_SRC_IRQ);\n\n\t\t\tbuf_off += page_copy;\n\t\t\tsg_off += page_copy;\n\t\t\tif (sg_off == PAGE_SIZE) {\n\t\t\t\tsg_off = 0;\n\t\t\t\tn++;\n\t\t\t}\n\t\t\tsg_copy -= page_copy;\n\t\t}\n\n\t\tif (!buflen)\n\t\t\tbreak;\n\t}\n\n\treturn buf_off;\n}\n\nsize_t mhvtl_copy_from_user(struct scatterlist *sgl, unsigned int nents,\n\t\t\t\t\t\t\tchar __user *buf, size_t buflen) {\n\treturn mhvtl_sg_copy_user(sgl, nents, buf, buflen, 0);\n}\n\nsize_t mhvtl_copy_to_user(struct scatterlist *sgl, unsigned int nents,\n\t\t\t\t\t\t  char __user *buf, size_t buflen) {\n\treturn mhvtl_sg_copy_user(sgl, nents, buf, buflen, 1);\n}\n\n/*\n * Copy data from SCSI command buffer to device buffer\n *  (SCSI command buffer -> user space)\n *\n * Returns number of bytes fetched into 'arr' or -1 if error.\n */\nstatic int mhvtl_fetch_to_dev_buffer(struct scsi_cmnd *scp, char __user *arr, int len) {\n\tstruct scsi_data_buffer *sdb = scsi_out(scp);\n\n\tif (!scsi_bufflen(scp))\n\t\treturn 0;\n\tif (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))\n\t\treturn -1;\n\n\treturn mhvtl_copy_to_user(sdb->table.sgl, sdb->table.nents, arr, len);\n}\n\n/*\n * fill_from_user_buffer : Retrieves data from user-space into SCSI\n * buffer(s)\n\n Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid .\n */\nstatic int mhvtl_fill_from_user_buffer(struct scsi_cmnd *scp, char __user *arr,\n\t\t\t\t\t\t\t\t\t   int arr_len) {\n\tint\t\t\t\t\t\t act_len;\n\tstruct scsi_data_buffer *sdb = scsi_in(scp);\n\n\tif (!sdb->length)\n\t\treturn 0;\n\tif (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))\n\t\treturn DID_ERROR << 16;\n\n\tact_len = mhvtl_copy_from_user(sdb->table.sgl, sdb->table.nents,\n\t\t\t\t\t\t\t\t   arr, arr_len);\n\tif (sdb->resid)\n\t\tsdb->resid -= act_len;\n\telse\n\t\tsdb->resid = scsi_bufflen(scp) - act_len;\n\n\treturn 0;\n}\n\n/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */\nstatic int mhvtl_fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,\n\t\t\t\t\t\t\t\t\t  int arr_len) {\n\tint\t\t\t\t\t\t act_len;\n\tstruct scsi_data_buffer *sdb = scsi_in(scp);\n\n\tif (!sdb->length)\n\t\treturn 0;\n\tif (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))\n\t\treturn DID_ERROR << 16;\n\n\tact_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,\n\t\t\t\t\t\t\t\t  arr, arr_len);\n\tif (sdb->resid)\n\t\tsdb->resid -= act_len;\n\telse\n\t\tsdb->resid = scsi_bufflen(scp) - act_len;\n\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/fetch27.c",
    "content": "\n/**\n * mhvtl_sg_copy_user - Copy data between user-space linear buffer and an SG list\n * @sgl:\tThe SG list\n * @nents:\tNumber of SG entries\n * @buf:\tWhere to copy from\n * @buflen:\tThe number of bytes to copy\n * @to_buffer:\tTransfer direction (non zero == from an sg list to a buffer,\n *\t\t0 == from a buffer to an sg list\n *\n * Returns number of copied bytes\n *\n * Taken in whole from scatterlist.c\n */\n\nstatic size_t mhvtl_sg_copy_user(struct scatterlist *sgl, unsigned int nents,\n\t\t\t\t\t\t\t\t __user void *buf, size_t buflen, int to_buffer) {\n\tunsigned int\t\t   offset = 0;\n\tstruct sg_mapping_iter miter;\n\t/* Do not use SG_MITER_ATOMIC flag on the sg_miter_start() call */\n\tunsigned int sg_flags = 0;\n\tunsigned int rem;\n\tvoid\t\t*kmem_user;\n\n#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 30)\n\tif (to_buffer)\n\t\tsg_flags |= SG_MITER_FROM_SG;\n\telse\n\t\tsg_flags |= SG_MITER_TO_SG;\n#endif\n\n\tkmem_user = kmem_cache_alloc(sgp, 0);\n\tif (!kmem_user)\n\t\treturn offset;\n\n\tsg_miter_start(&miter, sgl, nents, sg_flags);\n\n\twhile (sg_miter_next(&miter) && offset < buflen) {\n\t\tunsigned int len;\n\n\t\tlen = min(miter.length, buflen - offset);\n\t\tif (len > SG_SEGMENT_SZ) {\n\t\t\tpr_warn(\"scatter-gather segment size larger than SG_SEGMENT_SZ (%d > %d)\",\n\t\t\t\t\tlen, SG_SEGMENT_SZ);\n\t\t\tgoto abort_early;\n\t\t}\n\n\t\tif (to_buffer) {\n\t\t\tmemcpy(kmem_user, miter.addr, len);\n\t\t\trem = copy_to_user(buf + offset, kmem_user, len);\n\t\t} else {\n\t\t\trem = copy_from_user(kmem_user, buf + offset, len);\n\t\t\tmemcpy(miter.addr, kmem_user, len);\n\t\t\tflush_kernel_dcache_page(miter.page);\n\t\t}\n\t\tif (rem)\n\t\t\tpr_debug(\"mhvtl: %s(): \"\n\t\t\t\t\t \"copy_%s_user() failed, rem %ld, buf 0x%llx, \"\n\t\t\t\t\t \"miter.addr 0x%llx, len %d\\n\",\n\t\t\t\t\t __func__, (to_buffer) ? \"to\" : \"from\",\n\t\t\t\t\t (long)rem,\n\t\t\t\t\t (unsigned long long)(buf + offset),\n\t\t\t\t\t (unsigned long long)miter.addr, len);\n\n\t\toffset += len;\n\t}\n\nabort_early:\n\tsg_miter_stop(&miter);\n\tkmem_cache_free(sgp, kmem_user);\n\n\treturn offset;\n}\n\nstatic size_t mhvtl_copy_from_user(struct scatterlist *sgl, unsigned int nents,\n\t\t\t\t\t\t\t\t   char __user *buf, size_t buflen) {\n\treturn mhvtl_sg_copy_user(sgl, nents, buf, buflen, 0);\n}\n\nstatic size_t mhvtl_copy_to_user(struct scatterlist *sgl, unsigned int nents,\n\t\t\t\t\t\t\t\t char __user *buf, size_t buflen) {\n\treturn mhvtl_sg_copy_user(sgl, nents, buf, buflen, 1);\n}\n\n/*\n * Copy data from SCSI command buffer to device buffer\n *  (SCSI command buffer -> user space)\n *\n * Returns number of bytes fetched into 'arr' or -1 if error.\n */\nstatic int mhvtl_fetch_to_dev_buffer(struct scsi_cmnd *scp, char __user *arr, int len) {\n\tstruct scsi_data_buffer *sdb = scsi_out(scp);\n\n\tif (!scsi_bufflen(scp))\n\t\treturn 0;\n\tif (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))\n\t\treturn -1;\n\n\treturn mhvtl_copy_to_user(sdb->table.sgl, sdb->table.nents, arr, len);\n}\n\n/*\n * fill_from_user_buffer : Retrieves data from user-space into SCSI\n * buffer(s)\n\n Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid .\n */\nstatic int mhvtl_fill_from_user_buffer(struct scsi_cmnd *scp, char __user *arr,\n\t\t\t\t\t\t\t\t\t   int arr_len) {\n\tint\t\t\t\t\t\t act_len;\n\tstruct scsi_data_buffer *sdb = scsi_in(scp);\n\n\tif (!sdb->length)\n\t\treturn 0;\n\tif (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))\n\t\treturn DID_ERROR << 16;\n\n\tact_len = mhvtl_copy_from_user(sdb->table.sgl, sdb->table.nents,\n\t\t\t\t\t\t\t\t   arr, arr_len);\n\tif (sdb->resid)\n\t\tsdb->resid -= act_len;\n\telse\n\t\tsdb->resid = scsi_bufflen(scp) - act_len;\n\n\treturn 0;\n}\n\n/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */\nstatic int mhvtl_fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,\n\t\t\t\t\t\t\t\t\t  int arr_len) {\n\tint\t\t\t\t\t\t act_len;\n\tstruct scsi_data_buffer *sdb = scsi_in(scp);\n\n\tif (!sdb->length)\n\t\treturn 0;\n\tif (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))\n\t\treturn DID_ERROR << 16;\n\n\tact_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,\n\t\t\t\t\t\t\t\t  arr, arr_len);\n\tif (sdb->resid)\n\t\tsdb->resid -= act_len;\n\telse\n\t\tsdb->resid = scsi_bufflen(scp) - act_len;\n\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/fetch50.c",
    "content": "\n\n/**\n * mhvtl_sg_copy_user - Copy data between user-space linear buffer and an SG list\n * @sgl:\tThe SG list\n * @nents:\tNumber of SG entries\n * @buf:\tWhere to copy from\n * @buflen:\tThe number of bytes to copy\n * @to_buffer:\tTransfer direction (non zero == from an sg list to a buffer,\n *\t\t0 == from a buffer to an sg list\n *\n * Returns number of copied bytes\n *\n * Taken in whole from scatterlist.c\n */\n\nstatic size_t mhvtl_sg_copy_user(struct scatterlist *sgl, unsigned int nents,\n\t\t\t\t\t\t\t\t __user void *buf, size_t buflen, int to_buffer) {\n\tunsigned int\t\t   offset = 0;\n\tstruct sg_mapping_iter miter;\n\t/* Do not use SG_MITER_ATOMIC flag on the sg_miter_start() call */\n\tunsigned int sg_flags = 0;\n\tunsigned int rem;\n\tvoid\t\t*kmem_user;\n\n#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 30)\n\tif (to_buffer)\n\t\tsg_flags |= SG_MITER_FROM_SG;\n\telse\n\t\tsg_flags |= SG_MITER_TO_SG;\n#endif\n\n\tkmem_user = kmem_cache_alloc(sgp, 0);\n\tif (!kmem_user)\n\t\treturn offset;\n\n\tsg_miter_start(&miter, sgl, nents, sg_flags);\n\n\twhile (sg_miter_next(&miter) && offset < buflen) {\n\t\tunsigned int len;\n\n\t\tlen = min(miter.length, buflen - offset);\n\t\tif (unlikely(len > SG_SEGMENT_SZ)) {\n\t\t\tpr_warn(\"scatter-gather segment size larger than SG_SEGMENT_SZ (%d > %d)\",\n\t\t\t\t\tlen, SG_SEGMENT_SZ);\n\t\t\tgoto abort_early;\n\t\t}\n\n\t\t/* Since user copy 'white list' - need to copy into 'kmem_buffer' first */\n\t\tif (to_buffer) {\n\t\t\tmemcpy(kmem_user, miter.addr, len);\n\t\t\trem = copy_to_user(buf + offset, kmem_user, len);\n\t\t} else {\n\t\t\trem = copy_from_user(kmem_user, buf + offset, len);\n\t\t\tmemcpy(miter.addr, kmem_user, len);\n\t\t\tflush_dcache_page(miter.page);\n\t\t}\n\t\tif (rem)\n\t\t\tpr_warn(\"mhvtl: %s(): \"\n\t\t\t\t\t\"copy_%s_user() failed, rem %ld, buf 0x%pS, \"\n\t\t\t\t\t\"miter.addr 0x%pS, len %d\\n\",\n\t\t\t\t\t__func__, (to_buffer) ? \"to\" : \"from\",\n\t\t\t\t\t(long)rem,\n\t\t\t\t\t(buf + offset),\n\t\t\t\t\tmiter.addr,\n\t\t\t\t\tlen);\n\n\t\toffset += len;\n\t}\n\nabort_early:\n\tsg_miter_stop(&miter);\n\tkmem_cache_free(sgp, kmem_user);\n\n\treturn offset;\n}\n\nstatic size_t mhvtl_copy_from_user(struct scatterlist *sgl, unsigned int nents,\n\t\t\t\t\t\t\t\t   char __user *buf, size_t buflen) {\n\treturn mhvtl_sg_copy_user(sgl, nents, buf, buflen, 0);\n}\n\nstatic size_t mhvtl_copy_to_user(struct scatterlist *sgl, unsigned int nents,\n\t\t\t\t\t\t\t\t char __user *buf, size_t buflen) {\n\treturn mhvtl_sg_copy_user(sgl, nents, buf, buflen, 1);\n}\n\n/*\n * Copy data from SCSI command buffer to device buffer\n *  (SCSI command buffer -> user space)\n *\n * Returns number of bytes fetched into 'arr' or -1 if error.\n */\nstatic int mhvtl_fetch_to_dev_buffer(struct scsi_cmnd *scp, char __user *arr, int len) {\n\tif (!scsi_bufflen(scp))\n\t\treturn 0;\n\tif (scp->sc_data_direction != DMA_TO_DEVICE)\n\t\treturn -1;\n\n\treturn mhvtl_copy_to_user(scsi_sglist(scp), scsi_sg_count(scp), arr, len);\n}\n\n/*\n * fill_from_user_buffer : Retrieves data from user-space into SCSI\n * buffer(s)\n\n Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid .\n */\nstatic int mhvtl_fill_from_user_buffer(struct scsi_cmnd *scp, char __user *arr,\n\t\t\t\t\t\t\t\t\t   int arr_len) {\n\tint\t\t\t\t\t\t act_len;\n\tstruct scsi_data_buffer *sdb = &scp->sdb;\n\n\tif (!sdb->length)\n\t\treturn 0;\n\tif (scp->sc_data_direction != DMA_FROM_DEVICE)\n\t\treturn DID_ERROR << 16;\n\n\tact_len = mhvtl_copy_from_user(sdb->table.sgl, sdb->table.nents,\n\t\t\t\t\t\t\t\t   arr, arr_len);\n\tscsi_set_resid(scp, scsi_bufflen(scp) - act_len);\n\n\treturn 0;\n}\n\n/* Build SCSI \"data-in\" buffer. Returns 0 if ok else (DID_ERROR << 16). */\nstatic int mhvtl_fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,\n\t\t\t\t\t\t\t\t\t  int arr_len) {\n\tint\t\t\t\t\t\t act_len;\n\tstruct scsi_data_buffer *sdb = &scp->sdb;\n\n\tif (!sdb->length)\n\t\treturn 0;\n\tif (scp->sc_data_direction != DMA_FROM_DEVICE)\n\t\treturn DID_ERROR << 16;\n\n\tact_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,\n\t\t\t\t\t\t\t\t  arr, arr_len);\n\tscsi_set_resid(scp, scsi_bufflen(scp) - act_len);\n\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/mhvtl.c",
    "content": "/*\n *  linux/kernel/vtl.c\n * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n *  Copyright (C) 1992  Eric Youngdale\n *  Simulate a host adapter with 2 disks attached.  Do a lot of checking\n *  to make sure that we are not getting blocks mixed up, and PANIC if\n *  anything out of the ordinary is seen.\n * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n *\n *  For documentation see http://sg.danny.cz/sg/sdebug26.html\n *\n *   D. Gilbert (dpg) work for Magneto-Optical device test [20010421]\n *   dpg: work for devfs large number of disks [20010809]\n *        forked for lk 2.5 series [20011216, 20020101]\n *        use vmalloc() more inquiry+mode_sense [20020302]\n *   Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031]\n *   Mike Anderson <andmike@us.ibm.com> sysfs work [20021118]\n *   dpg: change style of boot options to \"vtl.num_tgts=2\" and\n *        module options to \"modprobe vtl num_tgts=2\" [20021221]\n *\n *\tMark Harvey 2005 - 2025\n *\n *\tmarkh794@gmail.com\n *\n *\tPinched wholesale from scsi_debug.[ch]\n *\n *\tHacked to represent SCSI tape drives & Library.\n *\n *\tRegistered char driver to handle data to user space daemon.\n *\tIdea is for user space daemons (vtltape & vtllibrary) to emulate\n *\tand process the SCSI SSC/SMC device command set.\n *\n *\tI've used it for testing NetBackup - but there is no reason any\n *\tother backup utility could not use it as well.\n *\n * Modification History:\n *    2010-04-18 hstadler - some source code revision in mhvtl_init,\n *\t\t\t    mhvtl_exit, some return code checking\n *\n *\n */\n\n#define pr_fmt(fmt) \"%s: %s(): \" fmt, KBUILD_MODNAME, __func__\n\n#include <linux/module.h>\n\n#include <linux/kernel.h>\n#include <linux/sched.h>\n#include <linux/errno.h>\n#include <linux/timer.h>\n#include <linux/types.h>\n#include <linux/string.h>\n#include <linux/fs.h>\n#include <linux/init.h>\n#include <linux/moduleparam.h>\n#include <linux/slab.h>\n#include <asm/uaccess.h>\n\n#include <linux/blkdev.h>\n#include <linux/cdev.h>\n\n#include <scsi/scsi_host.h>\n#include <scsi/scsi_tcq.h>\n#include <scsi/scsicam.h>\n\n#include <linux/stat.h>\n\n#ifndef LINUX_VERSION_CODE\n#include <linux/version.h>\n#endif\n\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)\n#include <linux/smp_lock.h>\n#endif\n\n#ifndef _SCSI_H\n#define _SCSI_H\n\n#include <scsi/scsi_cmnd.h>\n#include <scsi/scsi_device.h>\n#include <scsi/scsi_eh.h>\n#include <scsi/scsi_tcq.h>\n#include <scsi/scsi.h>\n\nstruct Scsi_Host;\nstruct scsi_cmnd;\nstruct scsi_device;\nstruct scsi_target;\nstruct scatterlist;\n\n#endif /* _SCSI_H */\n\n#include \"vtl_common.h\"\n#include \"backport.h\"\n\n#if defined(HAVE_GENHD)\n#include <linux/genhd.h>\n#endif\n\n#include <scsi/scsi_driver.h>\n#include <scsi/scsi_ioctl.h>\n\n/* version of scsi_debug I started from\n #define VTL_VERSION \"1.75\"\n*/\n#ifndef MHVTL_VERSION\n#define MHVTL_VERSION \"0.18.40\"\n#endif\nstatic const char *mhvtl_version_date  = \"20260506-0\";\nstatic const char  mhvtl_driver_name[] = \"mhvtl\";\n\n/* Additional Sense Code (ASC) used */\n#define INVALID_FIELD_IN_CDB 0x24\n\n#define VTL_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */\n\n#ifndef SCSI_MAX_SG_CHAIN_SEGMENTS\n#define SCSI_MAX_SG_CHAIN_SEGMENTS SG_ALL\n#endif\n\n#define TIMEOUT_FOR_USER_DAEMON 50000\n\n/* Default values for driver parameters */\n#define DEF_NUM_HOST 1\n#define DEF_NUM_TGTS 0\n#define DEF_MAX_LUNS 32\n#define DEF_OPTS\t 1 /* Default to verbose logging */\n\n/* bit mask values for mhvtl_opts */\n#define VTL_OPT_NOISE 3\n\n#ifndef MHVTL_DEBUG\n\n#define MHVTL_DBG_PRT_CDB(lvl, s...)\n\n#else\n\n#define MHVTL_DBG_PRT_CDB(lvl, sn, s, len)                                                                  \\\n\t{                                                                                                       \\\n\t\tif ((mhvtl_opts & VTL_OPT_NOISE) >= (lvl)) {                                                        \\\n\t\t\tpr_info(\"(%llu) %d bytes\", (long long unsigned)sn, len);                                        \\\n\t\t\tswitch (len) {                                                                                  \\\n\t\t\tcase 6:                                                                                         \\\n\t\t\t\tpr_cont(\" %02x %02x %02x %02x %02x %02x\",                                                   \\\n\t\t\t\t\t\ts[0], s[1], s[2], s[3],                                                             \\\n\t\t\t\t\t\ts[4], s[5]);                                                                        \\\n\t\t\t\tbreak;                                                                                      \\\n\t\t\tcase 8:                                                                                         \\\n\t\t\t\tpr_cont(\" %02x %02x %02x %02x %02x %02x %02x %02x\",                                         \\\n\t\t\t\t\t\ts[0], s[1], s[2], s[3],                                                             \\\n\t\t\t\t\t\ts[4], s[5], s[6], s[7]);                                                            \\\n\t\t\t\tbreak;                                                                                      \\\n\t\t\tcase 10:                                                                                        \\\n\t\t\t\tpr_cont(\" %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\",                               \\\n\t\t\t\t\t\ts[0], s[1], s[2], s[3],                                                             \\\n\t\t\t\t\t\ts[4], s[5], s[6], s[7],                                                             \\\n\t\t\t\t\t\ts[8], s[9]);                                                                        \\\n\t\t\t\tbreak;                                                                                      \\\n\t\t\tcase 12:                                                                                        \\\n\t\t\t\tpr_cont(\" %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\",                     \\\n\t\t\t\t\t\ts[0], s[1], s[2], s[3],                                                             \\\n\t\t\t\t\t\ts[4], s[5], s[6], s[7],                                                             \\\n\t\t\t\t\t\ts[8], s[9], s[10], s[11]);                                                          \\\n\t\t\t\tbreak;                                                                                      \\\n\t\t\tcase 16:                                                                                        \\\n\t\t\tdefault:                                                                                        \\\n\t\t\t\tpr_cont(\" %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\", \\\n\t\t\t\t\t\ts[0], s[1], s[2], s[3],                                                             \\\n\t\t\t\t\t\ts[4], s[5], s[6], s[7],                                                             \\\n\t\t\t\t\t\ts[8], s[9], s[10], s[11],                                                           \\\n\t\t\t\t\t\ts[12], s[13], s[14], s[15]);                                                        \\\n\t\t\t\tbreak;                                                                                      \\\n\t\t\t}                                                                                               \\\n\t\t}                                                                                                   \\\n\t}\n\n#endif /* MHVTL_DEBUG */\n\n/* If REPORT LUNS has luns >= 256 it can choose \"flat space\" (value 1)\n * or \"peripheral device\" addressing (value 0) */\n#define SAM2_LUN_ADDRESS_METHOD 0\n\n/* Major number assigned to vtl driver => 0 means to ask for one */\nstatic int mhvtl_major = 0;\n\n#define DEF_MAX_MINOR_NO 1024 /* Max number of minor nos. this driver will handle */\n\n#define VTL_CANQUEUE\t1 /* needs to be >= 1 */\n#define VTL_MAX_CMD_LEN 16\n\nstatic struct kmem_cache *dsp;\nstatic struct kmem_cache *sgp;\n\nstatic int mhvtl_add_host = DEF_NUM_HOST;\nstatic int mhvtl_max_luns = DEF_MAX_LUNS;\nstatic int mhvtl_num_tgts = DEF_NUM_TGTS; /* targets per host */\nstatic int mhvtl_opts\t  = DEF_OPTS;\n\nstatic int mhvtl_cmnd_count = 0;\n\nstatic unsigned long long serial_number;\n\nstruct mhvtl_lu_info {\n\tstruct list_head\t   lu_sibling;\n\tunsigned char\t\t   sense_buff[SENSE_BUF_SIZE]; /* weak nexus */\n\tunsigned int\t\t   channel;\n\tunsigned int\t\t   target;\n\tunsigned int\t\t   lun;\n\tunsigned int\t\t   minor;\n\tstruct mhvtl_hba_info *mhvtl_hba;\n\tstruct scsi_device\t  *sdev;\n\tspinlock_t\t\t\t   sdev_lock;\n\n\tchar reset;\n\n\tstruct list_head cmd_list; /* list of outstanding cmds for this lu */\n\tspinlock_t\t\t cmd_list_lock;\n};\n\nstatic struct mhvtl_lu_info *devp[DEF_MAX_MINOR_NO];\n\nstruct mhvtl_hba_info {\n\tstruct list_head  hba_sibling; /* List of adapters */\n\tstruct list_head  lu_list;\t   /* List of lu */\n\tstruct Scsi_Host *shost;\n\tstruct device\t  dev;\n};\n\n#define to_mhvtl_hba(d) \\\n\tcontainer_of(d, struct mhvtl_hba_info, dev)\n\nstatic LIST_HEAD(mhvtl_hba_list); /* dll of adapters */\n#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)\nstatic spinlock_t mhvtl_hba_list_lock = __SPIN_LOCK_UNLOCKED(mhvtl_hba_list_lock);\n#else\nstatic spinlock_t mhvtl_hba_list_lock = SPIN_LOCK_UNLOCKED;\n#endif\n\ntypedef void (*done_funct_t)(struct scsi_cmnd *);\n\n/* mhvtl_queued_cmd-> state */\nenum cmd_state {\n\tCMD_STATE_FREE = 0,\n\tCMD_STATE_QUEUED,\n\tCMD_STATE_IN_USE,\n};\n\nstruct mhvtl_queued_cmd {\n\tint\t\t\t\t\tstate;\n\tstruct timer_list\tcmnd_timer;\n\tdone_funct_t\t\tdone_funct;\n\tstruct scsi_cmnd   *a_cmnd;\n\tint\t\t\t\t\tscsi_result;\n\tstruct mhvtl_header op_header;\n\n\tstruct list_head   queued_sibling;\n\tunsigned long long serial_number;\n};\n\nstatic int num_aborts\t   = 0;\nstatic int num_dev_resets  = 0;\nstatic int num_bus_resets  = 0;\nstatic int num_host_resets = 0;\n\nstatic int\t\t\t   mhvtl_driver_probe(struct device *);\nstatic int\t\t\t   mhvtl_driver_remove(struct device *);\nstatic struct bus_type mhvtl_pseudo_lld_bus;\n\nstatic struct device_driver mhvtl_driverfs_driver = {\n\t.name\t= mhvtl_driver_name,\n\t.bus\t= &mhvtl_pseudo_lld_bus,\n\t.probe\t= mhvtl_driver_probe,\n\t.remove = mhvtl_driver_remove,\n};\n\n/* function declarations */\nstatic int mhvtl_resp_report_luns(struct scsi_cmnd *SCpnt, struct mhvtl_lu_info *lu);\nstatic int mhvtl_fill_from_user_buffer(struct scsi_cmnd *scp, char __user *arr,\n\t\t\t\t\t\t\t\t\t   int arr_len);\nstatic int mhvtl_fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,\n\t\t\t\t\t\t\t\t\t  int arr_len);\n#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)\nstatic void mhvtl_timer_intr_handler(struct timer_list *indx);\n#else\nstatic void mhvtl_timer_intr_handler(unsigned long indx);\n#endif\nstatic struct mhvtl_lu_info *devInfoReg(struct scsi_device *sdp);\nstatic void\t\t\t\t\t mk_sense_buffer(struct mhvtl_lu_info *lu, int key, int asc, int asq);\nstatic void\t\t\t\t\t mhvtl_stop_all_queued(void);\nstatic int\t\t\t\t\t do_create_driverfs_files(void);\nstatic void\t\t\t\t\t do_remove_driverfs_files(void);\n\nstatic int\tmhvtl_add_adapter(void);\nstatic void mhvtl_remove_adapter(void);\n\nstatic int mhvtl_sdev_alloc(struct scsi_device *);\n#ifdef DEFINE_QUEUE_LIMITS_SCSI_DEV_CONFIGURE\nstatic int mhvtl_sdev_configure(struct scsi_device *, struct queue_limits *lim);\n#else\nstatic int mhvtl_sdev_configure(struct scsi_device *);\n#endif\nstatic void mhvtl_sdev_destroy(struct scsi_device *);\n#if LINUX_VERSION_CODE != KERNEL_VERSION(2, 6, 9)\n#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 19, 0) || LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33))\nstatic int mhvtl_change_queue_depth(struct scsi_device *sdev, int qdepth);\n#else\nstatic int mhvtl_change_queue_depth(struct scsi_device *sdev, int qdepth,\n\t\t\t\t\t\t\t\t\tint reason);\n#endif\n#endif\n#ifdef QUEUECOMMAND_LCK_ONE_ARG\nstatic int mhvtl_queuecommand_lck(struct scsi_cmnd *);\n#else\nstatic int mhvtl_queuecommand_lck(struct scsi_cmnd *, done_funct_t done);\n#endif\n\n#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)\nstatic int mhvtl_b_ioctl(struct scsi_device *, unsigned int, void __user *);\n#else\nstatic int mhvtl_b_ioctl(struct scsi_device *, int, void __user *);\n#endif\nstatic long\t\t   mhvtl_c_ioctl(struct file *, unsigned int, unsigned long);\nstatic int\t\t   mhvtl_c_ioctl_bkl(struct inode *, struct file *, unsigned int, unsigned long);\nstatic int\t\t   mhvtl_abort(struct scsi_cmnd *);\nstatic int\t\t   mhvtl_bus_reset(struct scsi_cmnd *);\nstatic int\t\t   mhvtl_device_reset(struct scsi_cmnd *);\nstatic int\t\t   mhvtl_host_reset(struct scsi_cmnd *);\nstatic const char *mhvtl_info(struct Scsi_Host *);\nstatic int\t\t   mhvtl_open(struct inode *, struct file *);\nstatic int\t\t   mhvtl_release(struct inode *, struct file *);\n\n#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)\nstatic DEF_SCSI_QCMD(mhvtl_queuecommand)\n#endif\n\n\tstatic struct device mhvtl_pseudo_primary;\n\n#ifdef DEFINE_CONST_STRUCT_SCSI_HOST_TEMPLATE\nstatic const struct scsi_host_template mhvtl_driver_template = {\n#else\nstatic struct scsi_host_template mhvtl_driver_template = {\n#endif\n\t.name = \"VTL\",\n\t.info = mhvtl_info,\n#ifdef DEFINE_QUEUE_LIMITS_SCSI_DEV_CONFIGURE\n\t.sdev_init\t\t= mhvtl_sdev_alloc,\n\t.sdev_configure = mhvtl_sdev_configure,\n\t.sdev_destroy\t= mhvtl_sdev_destroy,\n#else\n\t.slave_alloc\t = mhvtl_sdev_alloc,\n\t.slave_configure = mhvtl_sdev_configure,\n\t.slave_destroy\t = mhvtl_sdev_destroy,\n#endif\n\t.ioctl = mhvtl_b_ioctl,\n#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)\n\t.queuecommand = mhvtl_queuecommand,\n#else\n\t.queuecommand = mhvtl_queuecommand_lck,\n#endif\n#if LINUX_VERSION_CODE != KERNEL_VERSION(2, 6, 9)\n\t.change_queue_depth = mhvtl_change_queue_depth,\n#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)\n\t.ordered_tag = 1,\n#endif\n#endif\n\t.eh_abort_handler\t\t = mhvtl_abort,\n\t.eh_bus_reset_handler\t = mhvtl_bus_reset,\n\t.eh_device_reset_handler = mhvtl_device_reset,\n\t.eh_host_reset_handler\t = mhvtl_host_reset,\n\t.can_queue\t\t\t\t = VTL_CANQUEUE,\n\t.this_id\t\t\t\t = -1,\n\t.proc_name\t\t\t\t = mhvtl_driver_name,\n\t.sg_tablesize\t\t\t = SCSI_MAX_SG_CHAIN_SEGMENTS,\n\t.cmd_per_lun\t\t\t = 1,\n\t.max_sectors\t\t\t = 4096,\n#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)\n\t.use_clustering = ENABLE_CLUSTERING,\n#else\n\t.dma_boundary = PAGE_SIZE - 1,\n#endif\n\t.module = THIS_MODULE,\n};\n\nstatic const struct file_operations mhvtl_fops = {\n\t.owner = THIS_MODULE,\n#if defined(HAVE_UNLOCKED_IOCTL)\n\t.unlocked_ioctl = mhvtl_c_ioctl,\n#else\n\t.ioctl = mhvtl_c_ioctl_bkl,\n#endif\n\t.open\t = mhvtl_open,\n\t.release = mhvtl_release,\n};\n\n#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 17, 0)\n#include \"fetch50.c\"\n#elif LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 26)\n#include \"fetch27.c\"\n#elif LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 26)\n#include \"fetch26.c\"\n#elif LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 23)\n#include \"fetch24.c\"\n#else\n#include \"fetch.c\"\n#endif\n\n/**********************************************************************\n *                misc functions to handle queuing SCSI commands\n **********************************************************************/\n\n/*\n * mhvtl_schedule_resp() - handle SCSI commands that are processed from the\n *                   queuecommand() interface. i.e. No callback to done()\n *                   outside the queuecommand() function.\n *\n *                   Any SCSI command handled directly by the kernel driver\n *                   will use this.\n */\nstatic int mhvtl_schedule_resp(struct scsi_cmnd\t\t*SCpnt,\n\t\t\t\t\t\t\t   struct mhvtl_lu_info *lu,\n\t\t\t\t\t\t\t   done_funct_t done, int scsi_result) {\n\tif ((VTL_OPT_NOISE & mhvtl_opts) && SCpnt) {\n\t\tif (scsi_result) {\n\t\t\tstruct scsi_device *sdp = SCpnt->device;\n\n\t\t\tpr_info(\" <%u %u %u %llu> non-zero result=0x%x\\n\",\n\t\t\t\t\tsdp->host->host_no,\n\t\t\t\t\tsdp->channel, sdp->id,\n\t\t\t\t\t(unsigned long long)sdp->lun, scsi_result);\n\t\t}\n\t}\n\tif (SCpnt && lu) {\n\t\t/* simulate autosense by this driver */\n\t\tif (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))\n\t\t\tmemcpy(SCpnt->sense_buffer, lu->sense_buff,\n\t\t\t\t   (SCSI_SENSE_BUFFERSIZE > SENSE_BUF_SIZE) ? SENSE_BUF_SIZE : SCSI_SENSE_BUFFERSIZE);\n\t}\n\tif (SCpnt)\n\t\tSCpnt->result = scsi_result;\n\tif (done)\n\t\tdone(SCpnt);\n\treturn 0;\n}\n\n/**********************************************************************\n *                SCSI data handling routines\n **********************************************************************/\nstatic int mhvtl_resp_write_to_user(struct scsi_cmnd *SCpnt,\n\t\t\t\t\t\t\t\t\tvoid __user *up, int count) {\n\tint fetched;\n\n\tfetched = mhvtl_fetch_to_dev_buffer(SCpnt, up, count);\n\n\tif (fetched < count) {\n\t\tpr_err(\" cdb indicated=%d, IO sent=%d bytes\\n\",\n\t\t\t   count, fetched);\n\t\treturn -EIO;\n\t}\n\n\treturn 0;\n}\n\nstatic void mhvtl_debug_queued_list(struct mhvtl_lu_info *lu) {\n\tunsigned long\t\t\t iflags = 0;\n\tstruct mhvtl_queued_cmd *sqcp, *n;\n\tint\t\t\t\t\t\t k = 0;\n\n\tspin_lock_irqsave(&lu->cmd_list_lock, iflags);\n\tlist_for_each_entry_safe(sqcp, n, &lu->cmd_list, queued_sibling) {\n\t\tif (sqcp->state) {\n\t\t\tif (sqcp->a_cmnd) {\n\t\t\t\tpr_info(\"%d entry in use \"\n\t\t\t\t\t\t\"SCpnt: %p, SCSI result: %d, done: %p, \"\n\t\t\t\t\t\t\"Serial No: %lld\\n\",\n\t\t\t\t\t\tk, sqcp->a_cmnd, sqcp->scsi_result,\n\t\t\t\t\t\tsqcp->done_funct,\n\t\t\t\t\t\tsqcp->serial_number);\n\t\t\t} else {\n\t\t\t\tpr_info(\"%d entry in use \"\n\t\t\t\t\t\t\"SCpnt: %p, SCSI result: %d, done: %p\\n\",\n\t\t\t\t\t\tk, sqcp->a_cmnd, sqcp->scsi_result,\n\t\t\t\t\t\tsqcp->done_funct);\n\t\t\t}\n\t\t} else\n\t\t\tpr_info(\"entry free %d\\n\", k);\n\t\tk++;\n\t}\n\tspin_unlock_irqrestore(&lu->cmd_list_lock, iflags);\n\tpr_info(\"found %d entr%s\\n\", k, (k == 1) ? \"y\" : \"ies\");\n}\n\nstatic struct mhvtl_hba_info *mhvtl_get_hba_entry(void) {\n\tstruct mhvtl_hba_info *mhvtl_hba;\n\n\tspin_lock(&mhvtl_hba_list_lock);\n\tif (list_empty(&mhvtl_hba_list))\n\t\tmhvtl_hba = NULL;\n\telse\n\t\tmhvtl_hba = list_entry(mhvtl_hba_list.prev,\n\t\t\t\t\t\t\t   struct mhvtl_hba_info, hba_sibling);\n\tspin_unlock(&mhvtl_hba_list_lock);\n\treturn mhvtl_hba;\n}\n\nstatic void mhvtl_dump_queued_list(void) {\n\tstruct mhvtl_lu_info *lu, *__lu;\n\n\tstruct mhvtl_hba_info *mhvtl_hba;\n\n\tmhvtl_hba = mhvtl_get_hba_entry();\n\tif (!mhvtl_hba)\n\t\treturn;\n\n\t/* Now that the work list is split per lu, we have to check each\n\t * lu to see if we can find the serial number in question\n\t */\n\tlist_for_each_entry_safe(lu, __lu, &mhvtl_hba->lu_list, lu_sibling) {\n\t\tpr_debug(\"Channel %d, ID %d, LUN %d\\n\", lu->channel, lu->target, lu->lun);\n\t\tmhvtl_debug_queued_list(lu);\n\t}\n}\n\n/*********************************************************\n * Generic interface to queue SCSI cmd to userspace daemon\n *********************************************************/\n/*\n * mhvtl_q_cmd returns success if we successfully added the SCSI\n * cmd to the queued_list\n *\n * - Set state to indicate that the SCSI cmnd is ready for processing.\n */\nstatic int mhvtl_q_cmd(struct scsi_cmnd\t\t*scp,\n\t\t\t\t\t   done_funct_t\t\t\t done,\n\t\t\t\t\t   struct mhvtl_lu_info *lu) {\n\tunsigned long\t\t\t iflags = 0;\n\tstruct mhvtl_header\t\t*vheadp;\n\tstruct mhvtl_queued_cmd *sqcp;\n\n\tsqcp = kmalloc(sizeof(*sqcp), GFP_ATOMIC);\n\tif (!sqcp) {\n\t\tpr_err(\"kmalloc failed %ld bytes\\n\", sizeof(*sqcp));\n\t\treturn 1;\n\t}\n\n#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)\n\ttimer_setup(&sqcp->cmnd_timer, mhvtl_timer_intr_handler, 0);\n#else\n\tinit_timer(&sqcp->cmnd_timer);\n\tsqcp->cmnd_timer.function = mhvtl_timer_intr_handler;\n#endif\n\tsqcp->a_cmnd\t\t\t = scp;\n\tsqcp->scsi_result\t\t = 0;\n\tsqcp->done_funct\t\t = done;\n\tsqcp->cmnd_timer.expires = jiffies + TIMEOUT_FOR_USER_DAEMON;\n\tadd_timer(&sqcp->cmnd_timer);\n\n\tvheadp\t\t\t\t= &sqcp->op_header;\n\tvheadp->serialNo\t= serial_number;\n\tsqcp->serial_number = serial_number;\n\t/* Make sure serial_number can't wrap to '0' */\n\tif (unlikely(serial_number < 2))\n\t\tserial_number = 2;\n\tserial_number++;\n\tmemcpy(vheadp->cdb, scp->cmnd, scp->cmd_len);\n\n\t/* Set flag.\n\t * Next ioctl() poll by user-daemon will check this state.\n\t */\n\tsqcp->state = CMD_STATE_QUEUED;\n\n\tspin_lock_irqsave(&lu->cmd_list_lock, iflags);\n\tlist_add_tail(&sqcp->queued_sibling, &lu->cmd_list);\n\tspin_unlock_irqrestore(&lu->cmd_list_lock, iflags);\n\n\tif ((mhvtl_opts & VTL_OPT_NOISE) >= 2)\n\t\tmhvtl_dump_queued_list();\n\n\treturn 0;\n}\n\n/**********************************************************************\n *                Main interface from SCSI mid level\n **********************************************************************/\nstatic int _mhvtl_queuecommand_lck(struct scsi_cmnd *SCpnt, done_funct_t done) {\n\tunsigned char\t\t *cmd\t = (unsigned char *)SCpnt->cmnd;\n\tint\t\t\t\t\t  errsts = 0;\n\tstruct mhvtl_lu_info *lu\t = NULL;\n\n\tif (done == NULL)\n\t\treturn 0; /* assume mid level reprocessing command */\n\n\tif (cmd) {\n\t\tMHVTL_DBG_PRT_CDB(1, serial_number, cmd, SCpnt->cmd_len);\n\t}\n\n\tif (SCpnt->device->id == mhvtl_driver_template.this_id) {\n\t\tpr_err(\"initiator's id used as target!\\n\");\n\t\treturn mhvtl_schedule_resp(SCpnt, NULL, done, DID_NO_CONNECT << 16);\n\t}\n\n\tif (SCpnt->device->lun >= mhvtl_max_luns) {\n\t\tpr_err(\"Max luns exceeded\\n\");\n\t\treturn mhvtl_schedule_resp(SCpnt, NULL, done, DID_NO_CONNECT << 16);\n\t}\n\n\tlu = devInfoReg(SCpnt->device);\n\tif (NULL == lu) {\n\t\tpr_err(\"Could not find lu\\n\");\n\t\treturn mhvtl_schedule_resp(SCpnt, NULL, done, DID_NO_CONNECT << 16);\n\t}\n\n\tswitch (*cmd) {\n\tcase REPORT_LUNS: /* mandatory, ignore unit attention */\n\t\terrsts = mhvtl_resp_report_luns(SCpnt, lu);\n\t\tbreak;\n\n\t/* All commands down the list are handled by a user-space daemon */\n\tdefault: /* Pass on to user space daemon to process */\n\t\terrsts = mhvtl_q_cmd(SCpnt, done, lu);\n\t\tif (!errsts)\n\t\t\treturn 0;\n\t\tbreak;\n\t}\n\treturn mhvtl_schedule_resp(SCpnt, lu, done, errsts);\n}\n\n#ifdef QUEUECOMMAND_LCK_ONE_ARG\nstatic int mhvtl_queuecommand_lck(struct scsi_cmnd *SCpnt) {\n\tvoid (*done)(struct scsi_cmnd *) = scsi_done;\n\n\treturn _mhvtl_queuecommand_lck(SCpnt, done);\n}\n#else\nstatic int mhvtl_queuecommand_lck(struct scsi_cmnd *SCpnt, done_funct_t done) {\n\treturn _mhvtl_queuecommand_lck(SCpnt, done);\n}\n#endif\n\n/* FIXME: I don't know what version this inline routine was introduced */\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9)\n\n/* RedHat 4 appears to define 'scsi_get_tag_type' but doesn't understand\n * change_queue_depth\n * Disabling for kernel 2.6.9 (RedHat AS 4)\n */\n\n#define MSG_SIMPLE_TAG\t0x20\n#define MSG_ORDERED_TAG 0x22\n\n/**\n * scsi_get_tag_type - get the type of tag the device supports\n * @sdev:\tthe scsi device\n *\n * Notes:\n *\tIf the drive only supports simple tags, returns MSG_SIMPLE_TAG\n *\tif it supports all tag types, returns MSG_ORDERED_TAG.\n */\nstatic inline int scsi_get_tag_type(struct scsi_device *sdev) {\n\tif (!sdev->tagged_supported)\n\t\treturn 0;\n\tif (sdev->ordered_tags)\n\t\treturn MSG_ORDERED_TAG;\n\tif (sdev->simple_tags)\n\t\treturn MSG_SIMPLE_TAG;\n\treturn 0;\n}\n\n#endif\n\n/* RedHat 4 appears to define 'scsi_get_tag_type' but doesn't understand\n * change_queue_depth\n * Disabling for kernel 2.6.9 (RedHat AS 4)\n */\n#if LINUX_VERSION_CODE != KERNEL_VERSION(2, 6, 9)\n#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 19, 0) || LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33))\nstatic int mhvtl_change_queue_depth(struct scsi_device *sdev, int qdepth)\n#else\nstatic int mhvtl_change_queue_depth(struct scsi_device *sdev, int qdepth,\n\t\t\t\t\t\t\t\t\tint reason)\n#endif\n{\n\tpr_info(\"queue depth now %d\\n\", qdepth);\n\n\tif (qdepth < 1)\n\t\tqdepth = 1;\n\telse if (qdepth > sdev->host->cmd_per_lun)\n\t\tqdepth = sdev->host->cmd_per_lun;\n\n#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)\n\tscsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);\n#else\n\tscsi_change_queue_depth(sdev, qdepth);\n#endif\n\treturn sdev->queue_depth;\n}\n#endif\n\nstatic struct mhvtl_queued_cmd *lookup_sqcp(struct mhvtl_lu_info *lu,\n\t\t\t\t\t\t\t\t\t\t\tunsigned long\t\t  serialNo) {\n\tunsigned long\t\t\t iflags;\n\tstruct mhvtl_queued_cmd *sqcp;\n\n\tspin_lock_irqsave(&lu->cmd_list_lock, iflags);\n\tlist_for_each_entry(sqcp, &lu->cmd_list, queued_sibling) {\n\t\tif (sqcp->state && (sqcp->serial_number == serialNo)) {\n\t\t\tspin_unlock_irqrestore(&lu->cmd_list_lock, iflags);\n\t\t\treturn sqcp;\n\t\t}\n\t}\n\tspin_unlock_irqrestore(&lu->cmd_list_lock, iflags);\n\treturn NULL;\n}\n\n/*\n * Block device ioctl\n */\n#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)\nstatic int mhvtl_b_ioctl(struct scsi_device *sdp, unsigned int cmd, void __user *arg)\n#else\nstatic int mhvtl_b_ioctl(struct scsi_device *sdp, int cmd, void __user *arg)\n#endif\n{\n\tpr_debug(\"cmd=0x%x\\n\", cmd);\n\n\treturn -ENOTTY;\n}\n\n#define MHVTL_RLUN_ARR_SZ 128\n\nstatic int mhvtl_resp_report_luns(struct scsi_cmnd *scp, struct mhvtl_lu_info *lu) {\n\tunsigned int\t alloc_len;\n\tint\t\t\t\t lun_cnt, i, upper;\n\tunsigned char\t*cmd\t\t   = (unsigned char *)scp->cmnd;\n\tint\t\t\t\t select_report = (int)cmd[2];\n\tstruct scsi_lun *one_lun;\n\tunsigned char\t arr[MHVTL_RLUN_ARR_SZ];\n\n\talloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);\n\tif ((alloc_len < 16) || (select_report > 2)) {\n\t\tmk_sense_buffer(lu, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\t/* can produce response with up to 16k luns (lun 0 to lun 16383) */\n\tmemset(arr, 0, MHVTL_RLUN_ARR_SZ);\n\tlun_cnt = mhvtl_max_luns;\n\tarr[2]\t= ((sizeof(struct scsi_lun) * lun_cnt) >> 8) & 0xff;\n\tarr[3]\t= (sizeof(struct scsi_lun) * lun_cnt) & 0xff;\n\tlun_cnt = min((int)((MHVTL_RLUN_ARR_SZ - 8) /\n\t\t\t\t\t\tsizeof(struct scsi_lun)),\n\t\t\t\t  lun_cnt);\n\tone_lun = (struct scsi_lun *)&arr[8];\n\tfor (i = 0; i < lun_cnt; i++) {\n\t\tupper = (i >> 8) & 0x3f;\n\t\tif (upper)\n\t\t\tone_lun[i].scsi_lun[0] =\n\t\t\t\t(upper | (SAM2_LUN_ADDRESS_METHOD << 6));\n\t\tone_lun[i].scsi_lun[1] = i & 0xff;\n\t}\n\treturn mhvtl_fill_from_dev_buffer(scp, arr, min((int)alloc_len, MHVTL_RLUN_ARR_SZ));\n}\n\nstatic void __mhvtl_remove_sqcp(struct mhvtl_queued_cmd *sqcp) {\n\tlist_del(&sqcp->queued_sibling);\n\tkfree(sqcp);\n}\n\nstatic void mhvtl_remove_sqcp(struct mhvtl_lu_info *lu, struct mhvtl_queued_cmd *sqcp) {\n\tunsigned long iflags;\n\tspin_lock_irqsave(&lu->cmd_list_lock, iflags);\n\t__mhvtl_remove_sqcp(sqcp);\n\tspin_unlock_irqrestore(&lu->cmd_list_lock, iflags);\n}\n\n/* When timer goes off this function is called. */\n#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)\nstatic void mhvtl_timer_intr_handler(struct timer_list *t) {\n\tstruct mhvtl_queued_cmd *sqcp = timer_container_of(sqcp, t, cmnd_timer);\n\tunsigned long long\t\t indx = sqcp->serial_number;\n#else\nstatic void mhvtl_timer_intr_handler(unsigned long indx) {\n\tstruct mhvtl_queued_cmd *sqcp = NULL;\n#endif\n\tstruct mhvtl_lu_info *lu;\n\n\tstruct mhvtl_hba_info *mhvtl_hba;\n\n\tmhvtl_hba = mhvtl_get_hba_entry();\n\tif (!mhvtl_hba)\n\t\treturn;\n\n\t/* Now that the work list is split per lu, we have to check each\n\t * lu to see if we can find the serial number in question\n\t */\n\tlist_for_each_entry(lu, &mhvtl_hba->lu_list, lu_sibling) {\n\t\tsqcp = lookup_sqcp(lu, indx);\n\t\tif (sqcp)\n\t\t\tbreak;\n\t}\n\n\tif (!sqcp) {\n\t\tpr_err(\"Unexpected interrupt, indx %ld\\n\", (unsigned long)indx);\n\t\treturn;\n\t}\n\n\tsqcp->state = CMD_STATE_FREE;\n\tif (sqcp->done_funct) {\n\t\tsqcp->a_cmnd->result = sqcp->scsi_result;\n\t\tsqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */\n\t}\n\tsqcp->done_funct = NULL;\n\tmhvtl_remove_sqcp(lu, sqcp);\n}\n\nstatic int mhvtl_sdev_alloc(struct scsi_device *sdp) {\n\tstruct mhvtl_hba_info *mhvtl_hba;\n\tstruct mhvtl_lu_info  *lu = (struct mhvtl_lu_info *)sdp->hostdata;\n\n\tpr_debug(\"<%u %u %u %llu>\\n\",\n\t\t\t sdp->host->host_no, sdp->channel, sdp->id,\n\t\t\t (unsigned long long)sdp->lun);\n\n\tif (lu)\n\t\treturn 0;\n\n\tmhvtl_hba = *(struct mhvtl_hba_info **)sdp->host->hostdata;\n\tif (!mhvtl_hba) {\n\t\tpr_err(\"Host info NULL\\n\");\n\t\treturn -1;\n\t}\n\n\tlist_for_each_entry(lu, &mhvtl_hba->lu_list, lu_sibling) {\n\t\tif ((lu->channel == sdp->channel) &&\n\t\t\t(lu->target == sdp->id) &&\n\t\t\t(lu->lun == sdp->lun)) {\n\t\t\tpr_debug(\"line %d found matching lu\\n\", __LINE__);\n\t\t\treturn 0;\n\t\t}\n\t}\n\treturn -1;\n}\n\n#ifdef DEFINE_QUEUE_LIMITS_SCSI_DEV_CONFIGURE\nstatic int mhvtl_sdev_configure(struct scsi_device *sdp, struct queue_limits *lim)\n#else\nstatic int mhvtl_sdev_configure(struct scsi_device *sdp)\n#endif\n{\n\tstruct mhvtl_lu_info *lu;\n\n\tpr_debug(\"<%u %u %u %llu>\\n\",\n\t\t\t sdp->host->host_no, sdp->channel, sdp->id,\n\t\t\t (unsigned long long)sdp->lun);\n\tif (sdp->host->max_cmd_len != VTL_MAX_CMD_LEN)\n\t\tsdp->host->max_cmd_len = VTL_MAX_CMD_LEN;\n\tlu\t\t\t  = devInfoReg(sdp);\n\tsdp->hostdata = lu;\n\tif (sdp->host->cmd_per_lun)\n#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)\n\t\tscsi_adjust_queue_depth(sdp, VTL_TAGGED_QUEUING,\n\t\t\t\t\t\t\t\tsdp->host->cmd_per_lun);\n#else\n\t\tscsi_change_queue_depth(sdp, sdp->host->cmd_per_lun);\n#endif\n\treturn 0;\n}\n\nstatic void mhvtl_sdev_destroy(struct scsi_device *sdp) {\n\tstruct mhvtl_lu_info *lu = (struct mhvtl_lu_info *)sdp->hostdata;\n\n\tpr_notice(\"<%u %u %u %llu>\\n\",\n\t\t\t  sdp->host->host_no, sdp->channel, sdp->id,\n\t\t\t  (unsigned long long)sdp->lun);\n\tif (lu) {\n\t\tpr_debug(\"Removing lu structure, minor %d\\n\", lu->minor);\n\t\t/* make this slot avaliable for re-use */\n\t\tdevp[lu->minor] = NULL;\n\t\tkfree(sdp->hostdata);\n\t\tsdp->hostdata = NULL;\n\t}\n}\n\nstatic struct mhvtl_lu_info *devInfoReg(struct scsi_device *sdp) {\n\tstruct mhvtl_hba_info *mhvtl_hba;\n\tstruct mhvtl_lu_info  *lu = (struct mhvtl_lu_info *)sdp->hostdata;\n\n\tif (lu)\n\t\treturn lu;\n\n\tmhvtl_hba = *(struct mhvtl_hba_info **)sdp->host->hostdata;\n\tif (!mhvtl_hba) {\n\t\tpr_err(\"Host info NULL\\n\");\n\t\treturn NULL;\n\t}\n\n\tlist_for_each_entry(lu, &mhvtl_hba->lu_list, lu_sibling) {\n\t\tif ((lu->channel == sdp->channel) &&\n\t\t\t(lu->target == sdp->id) &&\n\t\t\t(lu->lun == sdp->lun))\n\t\t\treturn lu;\n\t}\n\n\treturn NULL;\n}\n\nstatic void mk_sense_buffer(struct mhvtl_lu_info *lu, int key, int asc, int asq) {\n\tunsigned char *sbuff;\n\n\tsbuff = lu->sense_buff;\n\tmemset(sbuff, 0, SENSE_BUF_SIZE);\n\tsbuff[0]  = 0x70; /* fixed, current */\n\tsbuff[2]  = key;\n\tsbuff[7]  = 0xa; /* implies 18 byte sense buffer */\n\tsbuff[12] = asc;\n\tsbuff[13] = asq;\n\tpr_notice(\" [key,asc,ascq]: [0x%x,0x%x,0x%x]\\n\", key, asc, asq);\n}\n\nstatic int mhvtl_device_reset(struct scsi_cmnd *SCpnt) {\n\tstruct mhvtl_lu_info *lu;\n\n\tpr_notice(\"Device reset called\\n\");\n\t++num_dev_resets;\n\tif (SCpnt) {\n\t\tlu = devInfoReg(SCpnt->device);\n\t\tif (lu)\n\t\t\tlu->reset = 1;\n\t}\n\treturn SUCCESS;\n}\n\nstatic int mhvtl_bus_reset(struct scsi_cmnd *SCpnt) {\n\tstruct mhvtl_hba_info *mhvtl_hba;\n\tstruct mhvtl_lu_info  *lu;\n\tstruct scsi_device\t  *sdp;\n\tstruct Scsi_Host\t  *hp;\n\n\tpr_notice(\"Bus reset called\\n\");\n\t++num_bus_resets;\n\tif (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {\n\t\tmhvtl_hba = *(struct mhvtl_hba_info **)hp->hostdata;\n\t\tif (mhvtl_hba) {\n\t\t\tlist_for_each_entry(lu, &mhvtl_hba->lu_list,\n\t\t\t\t\t\t\t\tlu_sibling)\n\t\t\t\tlu->reset = 1;\n\t\t}\n\t}\n\treturn SUCCESS;\n}\n\nstatic int mhvtl_host_reset(struct scsi_cmnd *SCpnt) {\n\tstruct mhvtl_hba_info *mhvtl_hba;\n\tstruct mhvtl_lu_info  *lu;\n\n\tpr_notice(\"Host reset called\\n\");\n\t++num_host_resets;\n\tspin_lock(&mhvtl_hba_list_lock);\n\tlist_for_each_entry(mhvtl_hba, &mhvtl_hba_list, hba_sibling) {\n\t\tlist_for_each_entry(lu, &mhvtl_hba->lu_list, lu_sibling)\n\t\t\tlu->reset = 1;\n\t}\n\tspin_unlock(&mhvtl_hba_list_lock);\n\tmhvtl_stop_all_queued();\n\treturn SUCCESS;\n}\n\n/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */\nstatic int mhvtl_stop_queued_cmnd(struct scsi_cmnd *SCpnt) {\n\tint\t\t\t\t\t\t found = 0;\n\tunsigned long\t\t\t iflags;\n\tstruct mhvtl_queued_cmd *sqcp, *n;\n\tstruct mhvtl_lu_info\t*lu;\n\n\tlu = devInfoReg(SCpnt->device);\n\n\tspin_lock_irqsave(&lu->cmd_list_lock, iflags);\n\tlist_for_each_entry_safe(sqcp, n, &lu->cmd_list, queued_sibling) {\n\t\tif (sqcp->state && (SCpnt == sqcp->a_cmnd)) {\n\t\t\ttimer_delete_sync(&sqcp->cmnd_timer);\n\t\t\tsqcp->state\t = CMD_STATE_FREE;\n\t\t\tsqcp->a_cmnd = NULL;\n\t\t\tfound\t\t = 1;\n\t\t\t__mhvtl_remove_sqcp(sqcp);\n\t\t\tbreak;\n\t\t}\n\t}\n\tspin_unlock_irqrestore(&lu->cmd_list_lock, iflags);\n\treturn found;\n}\n\n/* Deletes (stops) timers of all queued commands */\nstatic void mhvtl_stop_all_queued(void) {\n\tunsigned long\t\t\t iflags;\n\tstruct mhvtl_queued_cmd *sqcp, *n;\n\tstruct mhvtl_hba_info\t*mhvtl_hba;\n\tstruct mhvtl_lu_info\t*lu;\n\n\tmhvtl_hba = mhvtl_get_hba_entry();\n\tif (!mhvtl_hba)\n\t\treturn;\n\n\tlist_for_each_entry(lu, &mhvtl_hba->lu_list, lu_sibling) {\n\t\tspin_lock_irqsave(&lu->cmd_list_lock, iflags);\n\t\tlist_for_each_entry_safe(sqcp, n, &lu->cmd_list,\n\t\t\t\t\t\t\t\t queued_sibling) {\n\t\t\tif (sqcp->state && sqcp->a_cmnd) {\n\t\t\t\ttimer_delete_sync(&sqcp->cmnd_timer);\n\t\t\t\tsqcp->state\t = CMD_STATE_FREE;\n\t\t\t\tsqcp->a_cmnd = NULL;\n\t\t\t\t__mhvtl_remove_sqcp(sqcp);\n\t\t\t}\n\t\t}\n\t\tspin_unlock_irqrestore(&lu->cmd_list_lock, iflags);\n\t}\n}\n\nstatic int mhvtl_abort(struct scsi_cmnd *SCpnt) {\n\tpr_notice(\"Abort called\\n\");\n\t++num_aborts;\n\tmhvtl_stop_queued_cmnd(SCpnt);\n\treturn SUCCESS;\n}\n\n/* SLES 9 */\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 6)\nstruct scsi_device *__scsi_add_device(struct Scsi_Host *hpnt, uint channel, uint id, uint lun, char *p) {\n\treturn scsi_add_device(hpnt, channel, id, lun);\n}\n#endif\n\n/*\n * According to scsi_mid_low_api.txt\n *\n * A call from LLD scsi_add_device() will result in SCSI mid layer\n *   -> sdev_alloc()\n *   -> sdev_configure()\n */\nstatic int mhvtl_add_device(unsigned int minor, struct mhvtl_ctl *ctl) {\n\tstruct Scsi_Host\t  *hpnt;\n\tstruct mhvtl_hba_info *mhvtl_hba;\n\tstruct mhvtl_lu_info  *lu;\n\tstruct scsi_device\t  *tmp_sdev;\n\tint\t\t\t\t\t   error = 0;\n\n\tif (devp[minor]) {\n\t\tpr_notice(\"device struct already in place\\n\");\n\t\treturn error;\n\t}\n\n\tmhvtl_hba = mhvtl_get_hba_entry();\n\tif (!mhvtl_hba) {\n\t\tpr_err(\"mhvtl_ost info struct is NULL\\n\");\n\t\treturn -ENOTTY;\n\t}\n\tpr_debug(\"mhvtl_hba_info struct is %p\\n\", mhvtl_hba);\n\n\thpnt = mhvtl_hba->shost;\n\tif (!hpnt) {\n\t\tpr_notice(\"scsi host structure is NULL\\n\");\n\t\treturn -ENOTTY;\n\t}\n\tpr_debug(\"scsi_host struct is %p\\n\", hpnt);\n\n\tlu = kmalloc(sizeof(*lu), GFP_KERNEL);\n\tif (!lu) {\n\t\tpr_err(\"line %d - out of memory attempting to kmalloc %ld bytes\\n\", __LINE__, sizeof(*lu));\n\t\treturn -ENOMEM;\n\t}\n\tmemset(lu, 0, sizeof(*lu));\n\n\tlu->minor\t  = minor;\n\tlu->channel\t  = ctl->channel;\n\tlu->target\t  = ctl->id;\n\tlu->lun\t\t  = ctl->lun;\n\tlu->mhvtl_hba = mhvtl_hba;\n\tlu->reset\t  = 0;\n#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)\n\tspin_lock_init(&lu->cmd_list_lock);\n\tspin_lock_init(&lu->sdev_lock);\n#else\n\tlu->cmd_list_lock = SPIN_LOCK_UNLOCKED;\n\tlu->sdev_lock\t  = SPIN_LOCK_UNLOCKED;\n#endif\n\n\t/* List of queued SCSI op codes associated with this device */\n\tINIT_LIST_HEAD(&lu->cmd_list);\n\n\tlu->sense_buff[0] = 0x70;\n\tlu->sense_buff[7] = 0xa;\n\tdevp[minor]\t\t  = lu;\n\n\tspin_lock(&mhvtl_hba_list_lock);\n\tlist_add_tail(&lu->lu_sibling, &mhvtl_hba->lu_list);\n\tspin_unlock(&mhvtl_hba_list_lock);\n\n\tpr_debug(\"Added lu: %p to devp[%d]\\n\", lu, minor);\n\n\ttmp_sdev = __scsi_add_device(hpnt, ctl->channel, ctl->id, ctl->lun, NULL);\n\tif (IS_ERR(tmp_sdev)) {\n\t\ttmp_sdev = NULL;\n\t\terror\t = -ENODEV;\n\t}\n\tspin_lock(&lu->sdev_lock);\n\tlu->sdev = tmp_sdev;\n\tspin_unlock(&lu->sdev_lock);\n\treturn error;\n}\n\n/* Set 'perm' (4th argument) to 0 to disable module_param's definition\n * of sysfs parameters (which module_param doesn't yet support).\n * Sysfs parameters defined explicitly below.\n */\nmodule_param_named(opts, mhvtl_opts, int, 0); /* perm=0644 */\n\nMODULE_AUTHOR(\"Eric Youngdale + Douglas Gilbert + Mark Harvey\");\nMODULE_DESCRIPTION(\"SCSI vtl adapter driver\");\nMODULE_LICENSE(\"GPL\");\nMODULE_VERSION(MHVTL_VERSION);\n\nMODULE_PARM_DESC(opts, \"1->noise, 2->medium_error, 4->...\");\n\nstatic char mhvtl_parm_info[256];\n\nstatic const char *mhvtl_info(struct Scsi_Host *shp) {\n\tsprintf(mhvtl_parm_info, \"%s: version %s [%s], \"\n\t\t\t\t\t\t\t \"opts=0x%x\",\n\t\t\tmhvtl_driver_name, MHVTL_VERSION,\n\t\t\tmhvtl_version_date, mhvtl_opts);\n\treturn mhvtl_parm_info;\n}\n\nstatic ssize_t opts_show(struct device_driver *ddp, char *buf) {\n\treturn sysfs_emit(buf, \"0x%x\\n\", mhvtl_opts);\n}\n\nstatic ssize_t opts_store(struct device_driver *ddp,\n\t\t\t\t\t\t  const char *buf, size_t count) {\n\tint\t opts;\n\tchar work[20];\n\n\tif (1 == sscanf(buf, \"%10s\", work)) {\n#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)\n\t\tif (0 == strncasecmp(work, \"0x\", 2)) {\n#else\n\t\tif (0 == strnicmp(work, \"0x\", 2)) {\n#endif\n\t\t\tif (1 == sscanf(&work[2], \"%x\", &opts))\n\t\t\t\tgoto opts_done;\n\t\t} else {\n\t\t\tif (1 == sscanf(work, \"%d\", &opts))\n\t\t\t\tgoto opts_done;\n\t\t}\n\t}\n\treturn -EINVAL;\nopts_done:\n\tmhvtl_opts\t\t = opts;\n\tmhvtl_cmnd_count = 0;\n\treturn count;\n}\n\nstatic ssize_t major_show(struct device_driver *ddp, char *buf) {\n\treturn sysfs_emit(buf, \"%d\\n\", mhvtl_major);\n}\n\nstatic ssize_t add_lu_store(struct device_driver *ddp,\n\t\t\t\t\t\t\tconst char *buf, size_t count) {\n\tint\t\t\t\t retval;\n\tunsigned int\t minor;\n\tstruct mhvtl_ctl ctl;\n\tchar\t\t\t str[512];\n\n\tif (strncmp(buf, \"add\", 3)) {\n\t\tpr_err(\"Invalid command: %s\\n\", buf);\n\t\treturn count;\n\t}\n\n\tretval = sscanf(buf, \"%s %u %d %d %d\",\n\t\t\t\t\tstr, &minor, &ctl.channel, &ctl.id, &ctl.lun);\n\n\tpr_debug(\"Calling 'mhvtl_add_device(minor: %u,\"\n\t\t\t \" Channel: %d, ID: %d, LUN: %d)\\n\",\n\t\t\t minor, ctl.channel, ctl.id, ctl.lun);\n\n\tretval = mhvtl_add_device(minor, &ctl);\n\n\treturn count;\n}\n\n#ifdef DRIVER_ATTR\nstatic DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, opts_show, opts_store);\nstatic DRIVER_ATTR(major, S_IRUGO, major_show, NULL);\nstatic DRIVER_ATTR(add_lu, S_IWUSR | S_IWGRP, NULL, add_lu_store);\n#else\nstatic DRIVER_ATTR_RW(opts);\nstatic DRIVER_ATTR_RO(major);\nstatic DRIVER_ATTR_WO(add_lu);\n#endif\n\nstatic int do_create_driverfs_files(void) {\n\tint ret;\n\tret = driver_create_file(&mhvtl_driverfs_driver, &driver_attr_add_lu);\n\tret |= driver_create_file(&mhvtl_driverfs_driver, &driver_attr_opts);\n\tret |= driver_create_file(&mhvtl_driverfs_driver, &driver_attr_major);\n\treturn ret;\n}\n\nstatic void do_remove_driverfs_files(void) {\n\tdriver_remove_file(&mhvtl_driverfs_driver, &driver_attr_major);\n\tdriver_remove_file(&mhvtl_driverfs_driver, &driver_attr_opts);\n\tdriver_remove_file(&mhvtl_driverfs_driver, &driver_attr_add_lu);\n}\n\nstatic int __init mhvtl_init(void) {\n\tint ret;\n\n\tmemset(&devp, 0, sizeof(devp));\n\n\tserial_number = 2; /* Start at something other than 0 */\n\n\tmhvtl_major = register_chrdev(mhvtl_major, \"mhvtl\", &mhvtl_fops);\n\tif (mhvtl_major < 0) {\n\t\tpr_crit(\"Can't get major number\\n\");\n\t\tgoto register_chrdev_error;\n\t}\n\n\tret = device_register(&mhvtl_pseudo_primary);\n\tif (ret < 0) {\n\t\tpr_crit(\"Device_register error: %d\\n\", ret);\n\t\tgoto device_register_error;\n\t}\n\n\tret = bus_register(&mhvtl_pseudo_lld_bus);\n\tif (ret < 0) {\n\t\tpr_crit(\"Bus_register error: %d\\n\", ret);\n\t\tgoto bus_register_error;\n\t}\n\n\tret = driver_register(&mhvtl_driverfs_driver);\n\tif (ret < 0) {\n\t\tpr_crit(\"Driver_register error: %d\\n\", ret);\n\t\tgoto driver_register_error;\n\t}\n\n\tret = do_create_driverfs_files();\n\tif (ret < 0) {\n\t\tpr_crit(\"Driver_create_file error: %d\\n\", ret);\n\t\tgoto do_create_driverfs_error;\n\t}\n\n\tmhvtl_add_host = 0;\n\n\tif (mhvtl_add_adapter()) {\n\t\tpr_crit(\"mhvtl_add_adapter failed\\n\");\n\t\tgoto mhvtl_add_adapter_error;\n\t}\n\n\tpr_debug(\"Built %d host%s\\n\",\n\t\t\t mhvtl_add_host, (mhvtl_add_host == 1) ? \"\" : \"s\");\n\n\tdsp = (struct kmem_cache *)kmem_cache_create_usercopy(\"mhvtl_ds_cache\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t  sizeof(struct mhvtl_ds), 0, SLAB_HWCACHE_ALIGN,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t  0, sizeof(struct mhvtl_ds), NULL);\n\tif (!dsp) {\n\t\tpr_err(\"Unable to create ds cache\");\n\t\tgoto mhvtl_kmem_cache_error;\n\t}\n\n\tsgp = (struct kmem_cache *)kmem_cache_create_usercopy(\"mhvtl_sg_cache\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t  SG_SEGMENT_SZ, 0, SLAB_HWCACHE_ALIGN,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t  0, SG_SEGMENT_SZ, NULL);\n\tif (!sgp) {\n\t\tpr_err(\"Unable to create sg cache (size %d)\", (int)SG_SEGMENT_SZ);\n\t\tgoto mhvtl_kmem_cache_error;\n\t} else {\n\t\tpr_info(\"kmem_cache_user_copy: page size: %d\", (int)SG_SEGMENT_SZ);\n\t}\n\tpr_debug(\"Starting serial_number: %lld\", serial_number);\n\n\treturn 0;\n\nmhvtl_kmem_cache_error:\n\tmhvtl_remove_adapter();\n\nmhvtl_add_adapter_error:\n\tdo_remove_driverfs_files();\n\ndo_create_driverfs_error:\n\tdriver_unregister(&mhvtl_driverfs_driver);\n\ndriver_register_error:\n\tbus_unregister(&mhvtl_pseudo_lld_bus);\n\nbus_register_error:\n\tdevice_unregister(&mhvtl_pseudo_primary);\n\ndevice_register_error:\n\tunregister_chrdev(mhvtl_major, \"mhvtl\");\n\nregister_chrdev_error:\n\n\treturn -EFAULT;\n}\n\nstatic void __exit mhvtl_exit(void) {\n\tint k;\n\n\tmhvtl_stop_all_queued();\n\n\tfor (k = mhvtl_add_host; k; k--)\n\t\tmhvtl_remove_adapter();\n\n\tif (mhvtl_add_host != 0)\n\t\tpr_err(\"mhvtl_remove_adapter error at line %d\\n\", __LINE__);\n\n\tdo_remove_driverfs_files();\n\tdriver_unregister(&mhvtl_driverfs_driver);\n\tbus_unregister(&mhvtl_pseudo_lld_bus);\n\tdevice_unregister(&mhvtl_pseudo_primary);\n\tunregister_chrdev(mhvtl_major, \"mhvtl\");\n\tkmem_cache_destroy(dsp);\n\tkmem_cache_destroy(sgp);\n}\n\ndevice_initcall(mhvtl_init);\nmodule_exit(mhvtl_exit);\n\nstatic void mhvtl_pseudo_release(struct device *dev) {\n\tpr_notice(\"Called\\n\");\n}\n\nstatic struct device mhvtl_pseudo_primary = {\n#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 30)\n\t.init_name = \"mhvtl_pseudo\",\n#else\n\t.bus_id = \"mhvtl_pseudo\",\n#endif\n\t.release = mhvtl_pseudo_release,\n};\n\nstatic int mhvtl_lld_bus_match(struct device *dev,\n#ifdef DEFINE_CONST_STRUCT_DEVICE_DRIVER\n\t\t\t\t\t\t\t   const\n#endif\n\t\t\t\t\t\t\t   struct device_driver *dev_driver) {\n\treturn 1;\n}\n\nstatic struct bus_type mhvtl_pseudo_lld_bus = {\n\t.name  = \"mhvtl\",\n\t.match = mhvtl_lld_bus_match,\n};\n\nstatic void mhvtl_release_adapter(struct device *dev) {\n\tstruct mhvtl_hba_info *mhvtl_hba;\n\n\tmhvtl_hba = to_mhvtl_hba(dev);\n\tkfree(mhvtl_hba);\n}\n\n/* Simplified from original.\n *\n * Changed so it only adds one hba instance and no logical units\n */\nstatic int mhvtl_add_adapter(void) {\n\tint\t\t\t\t\t   error = 0;\n\tstruct mhvtl_hba_info *mhvtl_hba;\n\n\tmhvtl_hba = kmalloc(sizeof(*mhvtl_hba), GFP_KERNEL);\n\n\tif (!mhvtl_hba) {\n\t\tpr_err(\"Unable to kmalloc %ld bytes of memory at line %d\\n\", sizeof(*mhvtl_hba), __LINE__);\n\t\treturn -ENOMEM;\n\t}\n\n\tmemset(mhvtl_hba, 0, sizeof(*mhvtl_hba));\n\tINIT_LIST_HEAD(&mhvtl_hba->lu_list);\n\n\tspin_lock(&mhvtl_hba_list_lock);\n\tlist_add_tail(&mhvtl_hba->hba_sibling, &mhvtl_hba_list);\n\tspin_unlock(&mhvtl_hba_list_lock);\n\n\tmhvtl_hba->dev.bus\t   = &mhvtl_pseudo_lld_bus;\n\tmhvtl_hba->dev.parent  = &mhvtl_pseudo_primary;\n\tmhvtl_hba->dev.release = &mhvtl_release_adapter;\n#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 30)\n\tdev_set_name(&mhvtl_hba->dev, \"adapter%d\", mhvtl_add_host);\n#else\n\tsprintf(mhvtl_hba->dev.bus_id, \"adapter%d\", mhvtl_add_host);\n#endif\n\n\terror = device_register(&mhvtl_hba->dev);\n\tif (error) {\n\t\tkfree(mhvtl_hba);\n\t\treturn error;\n\t}\n\n\tmhvtl_add_host++;\n\n\treturn error;\n}\n\nstatic void mhvtl_remove_adapter(void) {\n\tstruct mhvtl_hba_info *mhvtl_hba = NULL;\n\n\tspin_lock(&mhvtl_hba_list_lock);\n\tif (!list_empty(&mhvtl_hba_list)) {\n\t\tmhvtl_hba = list_entry(mhvtl_hba_list.prev,\n\t\t\t\t\t\t\t   struct mhvtl_hba_info, hba_sibling);\n\t\tlist_del(&mhvtl_hba->hba_sibling);\n\t}\n\tspin_unlock(&mhvtl_hba_list_lock);\n\n\tif (!mhvtl_hba)\n\t\treturn;\n\n\tdevice_unregister(&mhvtl_hba->dev);\n\t--mhvtl_add_host;\n}\n\nstatic int mhvtl_driver_probe(struct device *dev) {\n\tint\t\t\t\t\t   error = 0;\n\tstruct mhvtl_hba_info *mhvtl_hba;\n\tstruct Scsi_Host\t  *hpnt;\n\n\tmhvtl_hba = to_mhvtl_hba(dev);\n\n\thpnt = scsi_host_alloc(&mhvtl_driver_template, sizeof(*mhvtl_hba));\n\tif (NULL == hpnt) {\n\t\tpr_err(\"scsi_register failed\\n\");\n\t\terror = -ENODEV;\n\t\treturn error;\n\t}\n\n\tmhvtl_hba->shost\t\t\t\t\t\t\t= hpnt;\n\t*((struct mhvtl_hba_info **)hpnt->hostdata) = mhvtl_hba;\n\tif ((hpnt->this_id >= 0) && (mhvtl_num_tgts > hpnt->this_id))\n\t\thpnt->max_id = mhvtl_num_tgts + 1;\n\telse\n\t\thpnt->max_id = mhvtl_num_tgts;\n\thpnt->max_lun = mhvtl_max_luns;\n\n\terror = scsi_add_host(hpnt, &mhvtl_hba->dev);\n\tif (error) {\n\t\tpr_err(\"scsi_add_host failed\\n\");\n\t\terror = -ENODEV;\n\t\tscsi_host_put(hpnt);\n\t} else\n\t\tscsi_scan_host(hpnt);\n\n\treturn error;\n}\n\nstatic int mhvtl_driver_remove(struct device *dev) {\n\tstruct list_head\t  *lh, *lh_sf;\n\tstruct mhvtl_hba_info *mhvtl_hba;\n\tstruct mhvtl_lu_info  *lu;\n\n\tmhvtl_hba = to_mhvtl_hba(dev);\n\n\tif (!mhvtl_hba) {\n\t\tpr_err(\"Unable to locate host info\\n\");\n\t\treturn -ENODEV;\n\t}\n\n\tscsi_remove_host(mhvtl_hba->shost);\n\n\tlist_for_each_safe(lh, lh_sf, &mhvtl_hba->lu_list) {\n\t\tlu = list_entry(lh, struct mhvtl_lu_info,\n\t\t\t\t\t\tlu_sibling);\n\t\tlist_del(&lu->lu_sibling);\n\t\tkfree(lu);\n\t}\n\n\tscsi_host_put(mhvtl_hba->shost);\n\tmhvtl_hba->shost = NULL;\n\treturn 0;\n}\n\n/*\n *******************************************************************\n * Char device driver routines\n *******************************************************************\n */\nstatic int mhvtl_get_user_data(unsigned int minor, char __user *arg) {\n\tstruct mhvtl_queued_cmd *sqcp = NULL;\n\tstruct mhvtl_ds\t\t\t*ds;\n\tint\t\t\t\t\t\t ret = 0;\n\tunsigned char __user\t*up;\n\tsize_t\t\t\t\t\t sz;\n\n\tds = kmem_cache_alloc(dsp, 0);\n\tif (!ds)\n\t\treturn -EFAULT;\n\n\tif (copy_from_user((u8 *)ds, (u8 *)arg, sizeof(struct mhvtl_ds))) {\n\t\tret = -EFAULT;\n\t\tgoto ret_err;\n\t}\n\n\tpr_debug(\" data Cmd S/No  : %lld\\n\", (unsigned long long)ds->serialNo);\n\tpr_debug(\" data pointer   : %p\\n\", ds->data);\n\tpr_debug(\" data sz        : %d\\n\", ds->sz);\n\tpr_debug(\" SAM status     : %d (0x%02x)\\n\",\n\t\t\t ds->sam_stat, ds->sam_stat);\n\tup\t = ds->data;\n\tsz\t = ds->sz;\n\tsqcp = lookup_sqcp(devp[minor], ds->serialNo);\n\tif (!sqcp) {\n\t\tret = -ENOTTY;\n\t\tgoto ret_err;\n\t}\n\n\tret = mhvtl_resp_write_to_user(sqcp->a_cmnd, up, sz);\n\nret_err:\n\tkmem_cache_free(dsp, ds);\n\treturn ret;\n}\n\nstatic int mhvtl_put_user_data(unsigned int minor, char __user *arg) {\n\tstruct mhvtl_queued_cmd *sqcp = NULL;\n\tstruct mhvtl_ds\t\t\t*ds;\n\tint\t\t\t\t\t\t ret = 0;\n\tuint8_t\t\t\t\t\t*s;\n\n\tds = kmem_cache_alloc(dsp, 0);\n\tif (!ds) {\n\t\tpr_err(\"Failed to allocate kmem_cache\\n\");\n\t\tret = -EFAULT;\n\t\tgoto give_up;\n\t}\n\n\tif (copy_from_user((u8 *)ds, (u8 *)arg, sizeof(struct mhvtl_ds))) {\n\t\tpr_err(\"Failed to copy from user %ld bytes\", (unsigned long)sizeof(struct mhvtl_ds));\n\t\tret = -EFAULT;\n\t\tgoto give_up;\n\t}\n\tpr_debug(\" data Cmd S/No  : %lld\\n\", (unsigned long long)ds->serialNo);\n\tpr_debug(\" data pointer   : %p\\n\", ds->data);\n\tpr_debug(\" data sz        : %d\\n\", ds->sz);\n\tpr_debug(\" SAM status     : %d (0x%02x)\\n\",\n\t\t\t ds->sam_stat, ds->sam_stat);\n\tsqcp = lookup_sqcp(devp[minor], ds->serialNo);\n\tif (!sqcp) {\n\t\tpr_err(\"Callback function not found for SCSI cmd s/no. %lld, minor: %d\\n\",\n\t\t\t   (unsigned long long)ds->serialNo,\n\t\t\t   minor);\n\t\tret = 1; /* report busy to mid level */\n\t\tgoto give_up;\n\t}\n\tret = mhvtl_fill_from_user_buffer(sqcp->a_cmnd, ds->data, ds->sz);\n\tif (ds->sam_stat) { /* Auto-sense */\n\t\tsqcp->a_cmnd->result = ds->sam_stat;\n\t\tif (copy_from_user(sqcp->a_cmnd->sense_buffer,\n\t\t\t\t\t\t   ds->sense_buf, SENSE_BUF_SIZE))\n\t\t\tpr_err(\"Failed to retrieve autosense data\\n\");\n\t\tsqcp->a_cmnd->sense_buffer[0] |= 0x70; /* force valid sense */\n\t\ts = sqcp->a_cmnd->sense_buffer;\n\t\tpr_debug(\"Auto-Sense returned [key/ASC/ASCQ] \"\n\t\t\t\t \"[%02x %02x %02x]\\n\",\n\t\t\t\t s[2],\n\t\t\t\t s[12],\n\t\t\t\t s[13]);\n\t} else {\n\t\tsqcp->a_cmnd->result = DID_OK << 16;\n\t}\n\ttimer_delete_sync(&sqcp->cmnd_timer);\n\tif (sqcp->done_funct)\n\t\tsqcp->done_funct(sqcp->a_cmnd);\n\telse\n\t\tpr_err(\"FATAL, line %d: SCSI done_funct callback => NULL\\n\", __LINE__);\n\tmhvtl_remove_sqcp(devp[minor], sqcp);\n\n\tret = 0;\n\ngive_up:\n\tkmem_cache_free(dsp, ds);\n\treturn ret;\n}\n\nstatic int send_mhvtl_header(unsigned int minor, char __user *arg) {\n\tstruct mhvtl_header\t\t*vheadp;\n\tstruct mhvtl_queued_cmd *sqcp, *n;\n\tint\t\t\t\t\t\t ret = 0;\n\n\tlist_for_each_entry_safe(sqcp, n, &devp[minor]->cmd_list, queued_sibling) {\n\t\tif (sqcp->state == CMD_STATE_QUEUED) {\n\t\t\tvheadp = &sqcp->op_header;\n\t\t\tif (copy_to_user((u8 *)arg, (u8 *)vheadp,\n\t\t\t\t\t\t\t sizeof(struct mhvtl_header))) {\n\t\t\t\tret = -EFAULT;\n\t\t\t\tgoto give_up;\n\t\t\t}\n\t\t\t/* Found an outstanding cmd to send */\n\t\t\tsqcp->state = CMD_STATE_IN_USE;\n\t\t\tret\t\t\t= VTL_QUEUE_CMD;\n\t\t\t/* Can only send one header at a time */\n\t\t\tgoto give_up;\n\t\t}\n\t}\n\ngive_up:\n\treturn ret;\n}\n\n#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)\n#if defined(DEFINE_SEMAPHORE_HAS_NUMERIC_ARG)\nstatic DEFINE_SEMAPHORE(tmp_mutex, 1);\n#else\nstatic DEFINE_SEMAPHORE(tmp_mutex);\n#endif /* DEFINE_SEMAPHORE_HAS_NUMERIC_ARG */\n#else\nstatic DECLARE_MUTEX(tmp_mutex);\n#endif\n\nstatic int mhvtl_remove_lu(unsigned int minor, char __user *arg) {\n\tstruct mhvtl_ctl\t   ctl;\n\tstruct mhvtl_hba_info *mhvtl_hba;\n\tstruct mhvtl_lu_info  *lu, *n;\n\tstruct scsi_device\t  *baksdev;\n\tint\t\t\t\t\t   ret = -ENODEV;\n\n\tbaksdev = NULL;\n\n\tdown(&tmp_mutex);\n\n\tif (copy_from_user((u8 *)&ctl, (u8 *)arg, sizeof(ctl))) {\n\t\tret = -EFAULT;\n\t\tgoto give_up;\n\t}\n\n\tmhvtl_hba = mhvtl_get_hba_entry();\n\tif (!mhvtl_hba) {\n\t\tret = 0;\n\t\tgoto give_up;\n\t}\n\n\tpr_debug(\"ioctl to remove device <c t l> <%02d %02d %02d>, hba: %p\\n\",\n\t\t\t ctl.channel, ctl.id, ctl.lun, mhvtl_hba);\n\n\tspin_lock(&mhvtl_hba_list_lock);\n\tlist_for_each_entry_safe(lu, n, &mhvtl_hba->lu_list, lu_sibling) {\n\t\tif ((lu->channel == ctl.channel) && (lu->target == ctl.id) &&\n\t\t\t(lu->lun == ctl.lun)) {\n\t\t\tpr_debug(\"line %d found matching lu\\n\", __LINE__);\n\t\t\tlist_del(&lu->lu_sibling);\n\t\t\tdevp[minor] = NULL;\n\n\t\t\tspin_lock(&lu->sdev_lock);\n\t\t\tif (lu->sdev) {\n\t\t\t\tbaksdev = lu->sdev;\n\t\t\t\tspin_unlock(&lu->sdev_lock);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tspin_unlock(&lu->sdev_lock);\n\t\t}\n\t}\n\tspin_unlock(&mhvtl_hba_list_lock);\n\n\tif (baksdev) {\n\t\tscsi_remove_device(baksdev);\n\t\tscsi_device_put(baksdev);\n\t}\n\n\tret = 0;\n\ngive_up:\n\tup(&tmp_mutex);\n\treturn ret;\n}\n\n#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)\nstatic DEFINE_MUTEX(ioctl_mutex);\n#endif\n\nstatic long mhvtl_c_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {\n\tlong ret;\n\n\tstruct inode *inode = file_inode(file);\n\tif (!inode) {\n\t\tpr_err(\"Unable to obtain inode - inode is null\\n\");\n\t\treturn -ENODEV;\n\t}\n\n#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)\n\tmutex_lock(&ioctl_mutex);\n#else\n\tlock_kernel();\n#endif\n\tret = mhvtl_c_ioctl_bkl(inode, file, cmd, arg);\n#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)\n\tmutex_unlock(&ioctl_mutex);\n#else\n\tunlock_kernel();\n#endif\n\n\treturn ret;\n}\n\n/*\n * char device ioctl entry point\n */\nstatic int mhvtl_c_ioctl_bkl(struct inode *inode, struct file *file,\n\t\t\t\t\t\t\t unsigned int cmd, unsigned long arg) {\n\tunsigned int minor = iminor(inode);\n\tint\t\t\t ret;\n\n\tif (minor >= DEF_MAX_MINOR_NO) { /* Check limit minor no. */\n\t\treturn -ENODEV;\n\t}\n\n\tret = 0;\n\n\tswitch (cmd) {\n\n\tcase VTL_POLL_AND_GET_HEADER:\n\t\tif (!devp[minor]) {\n\t\t\tput_user(0, (unsigned int *)arg);\n\t\t\tret = 0;\n\t\t\tbreak;\n\t\t}\n\t\tret = send_mhvtl_header(minor, (char __user *)arg);\n\t\tbreak;\n\n\tcase VTL_GET_DATA:\n\t\tpr_debug(\"ioctl(VTL_GET_DATA)\\n\");\n\t\tret = mhvtl_get_user_data(minor, (char __user *)arg);\n\t\tbreak;\n\n\tcase VTL_PUT_DATA:\n\t\tpr_debug(\"ioctl(VTL_PUT_DATA)\\n\");\n\t\tret = mhvtl_put_user_data(minor, (char __user *)arg);\n\t\tbreak;\n\n\tcase VTL_REMOVE_LU:\n\t\tpr_debug(\"ioctl(VTL_REMOVE_LU)\\n\");\n\t\tret = mhvtl_remove_lu(minor, (char __user *)arg);\n\t\tbreak;\n\n\tdefault:\n\t\tret = -ENOTTY;\n\t\tbreak;\n\t}\n\treturn ret;\n}\n\nstatic int mhvtl_release(struct inode *inode, struct file *filp) {\n\tunsigned int minor = iminor(inode);\n\n\tpr_debug(\"lu for minor %u Release\\n\", minor);\n\treturn 0;\n}\n\nstatic int mhvtl_open(struct inode *inode, struct file *filp) {\n\tunsigned int minor = iminor(inode);\n\n\tpr_debug(\"mhvtl%u: opened\\n\", minor);\n\treturn 0;\n}\n"
  },
  {
    "path": "man/Makefile",
    "content": "#\n# This makefile needs to be invoked as follows:\n#\n#make <options>\n#\n# Here, options include:\n#\n# \tall \tto build all utilities\n# \tclean\tto clean up all intermediate files\n#\n#\n# Makefile magic\n# $@ is a variable that expands to the name of the file being built\n# $< is a variable that expands to the naem of the source file\n# @ at the beginning of the first line tell make not to echo the commands as it run it.\n#\n\nCURDIR = \"../\"\n\ninclude ../config.mk\n\nMONTH = $(shell date -r ../ChangeLog +%B)\nYEAR = $(shell date -r ../ChangeLog +%Y)\n\nMAN_PATH = $(DESTDIR)$(PREFIX)$(MANDIR)\nMAN1_PAGES = $(patsubst %.1.in,%.1,$(wildcard *.1.in))\nMAN5_PAGES = $(patsubst %.5.in,%.5,$(wildcard *.5.in))\n\nall: $(MAN1_PAGES) $(MAN5_PAGES)\n\n# Create man pages in local folder\n%: %.in\n\tsed -e s'/@VERSION@/$(VERSION)/' \\\n\t\t-e s'/@MONTH@/$(MONTH)/' \\\n\t\t-e s'/@YEAR@/$(YEAR)/' \\\n\t\t-e s'/@CONFIG_PATH@/$(CONFIG_PATH)/' \\\n\t\t-e s'/@HOME_PATH@/$(HOME_PATH)/' $< > $@\n\n# Directories\n$(MAN_PATH)/man1:\n\tinstall -d -m 755 $@\n$(MAN_PATH)/man5:\n\tinstall -d -m 755 $@\n\n# installation\n$(MAN_PATH)/man1/%.1: %.1 | $(MAN_PATH)/man1\n\tinstall $< $@\n$(MAN_PATH)/man5/%.5: %.5 | $(MAN_PATH)/man5\n\tinstall $< $@\n\n.PHONY:install\ninstall: $(addprefix $(MAN_PATH)/man1/,$(MAN1_PAGES)) \\\n\t\t $(addprefix $(MAN_PATH)/man5/,$(MAN5_PAGES))\n\n.PHONY: uninstall\nuninstall:\n\trm -f $(addprefix $(MAN_PATH)/man1/,$(MAN1_PAGES)) \\\n\t\t  $(addprefix $(MAN_PATH)/man5/,$(MAN5_PAGES))\n\n# ========== Cleaning ==========\n\n.PHONY:clean\nclean:\n\trm -f *.1 *.5\n\n.PHONY:distclean\ndistclean:\n\trm -f *.1 *.5"
  },
  {
    "path": "man/device.conf.5.in",
    "content": ".TH device.conf \"5\" \"@MONTH@ @YEAR@\" \"mhvtl @VERSION@\" \"User Commands\"\n.SH NAME\ndevice.conf \\- Configuration file for\n.BR vtllibrary(1)\nand\n.BR vtltape(1)\n.SH DESCRIPTION\n.\\\" Add any additional description here\n.PP\nEach configured device contains a unique entry in device.conf\n\nEach section starts at column 1 and is terminated by a blank line.\n.IP e.g.\nLibrary: 10 CHANNEL: 00 TARGET: 00 LUN: 00\n Vendor identification: SPECTRA\n Product identification: PYTHON\n Product revision level: 550V\n Unit serial number: XYZZY_A\n NAA: 10:22:33:44:ab:00:00:00\n Home directory: @HOME_PATH@/Spectra\n fifo: /var/tmp/mhvtl\n PERSIST: True\n.PP\nWhere descriptor\n.B Library:\nor\n.B Drive:\nstarts each section The descriptor is followed by a unique ID (a decimal number)\n\nOn the same line following the descriptor is the SCSI corrordinates for the\ndevice described.\n\n.B Vendor identification,\n.B Product identification,\n.B Product revision level\nand\n.B Unit serial number\nare common fields across all device types.\n\n.B NAA\nfield is used by some backup software (e.g. Legato) as means to uniquely identify devices. It is used by INQUIRY VPD page 0x83. Most software uses the\n.B Unit serial number\nas the unique identifier.\n\n.B Compression:\nfactor\n.B X\nenabled\n.B Y\n\nWhere\n.PP\n.B X\nis 1 through 9.\n.IP\n1 is fastest compression, 9 is best compression.\n.PP\n.B Y\n.IP\n1: compression is enabled, 0: compression is disabled.\n\n.PP\n.B Compression type:\nzlib or lzo\n\n.PP\n.B Backoff:\nValue between 10 and 10000. Default is 1000.\nThis value is added to existing 'usleep' time in between ioctl polls. If there is work to do, the usleep time is reset to 10.\n\n.PP\n.B Home directory:\n/some/where/with/space\n.PP\nSpecify a parent directory for the virtual media associated with this library.\nOnly in valid ^Library: entries (not for ^Tape: entries)\n\n.PP\n.B fifo:\n/some/where/for/named/pipe\n.PP\nIf fifo: is defined, (near) real time state information will be available\nfor external applications by reading from this named pipe.\n.PP\nNote: the '-f fifo' switch on daemon startup has higher precedence\n\n.PP\n.B PERSIST:\nTrue | False\nIf PERSIST is set to 'Yes' or 'True' - enable saving state on shutdown.\nA file 'library_contents.XX.persist' will be created on shutdown to save\npersistent state. On startup - Default to read the\nlibrary_contents.XX.persist if the file exists. Fall back to\nlibrary_contents.XX if no .persist file exists.\n\n.SH AUTHOR\nWritten by Mark Harvey\n.SH BUGS\n.RS\nThis man page.\n.RE\n.RS\nNo version information.\n.RE\n.RS\nConfig file not xml.\n.RE\n.RS\n.BR vtllibrary(1)\nand\n.BR vtltape(1)\nneeds to be restarted to read any changes made.\n.RE\n.SH \"REPORTING BUGS\"\nReport bugs to <markh794@gmail.com>\n.SH COPYRIGHT\nCopyright \\(co 2005 Free Software Foundation, Inc.\n.br\nThis is free software; see the source for copying conditions.  There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n.SH \"SEE ALSO\"\n.BR library_contents(5)\n.BR make_vtl_media(1),\n.BR mktape(1),\n.BR vtlcmd(1),\n.BR vtllibrary(1),\n.BR vtltape(1)\n"
  },
  {
    "path": "man/dump_tape.1.in",
    "content": ".TH dump_tape \"1\" \"@MONTH@ @YEAR@\" \"mhvtl @VERSION@\" \"User Commands\"\n.SH NAME\ndump_tape \\- Utility to dump tape contents for virtual media in VTL.\n.SH SYNOPSIS\n.B dump_tape\n.B [ \\-h ]\n.br\n.B dump_tape\n.B [ \\fIOPTIONS\\fR]\n.SH DESCRIPTION\n.\\\" Add any additional description here\n.PP\nDump the contents of the specified PCL. If a library is specified, look\nthere, else look through all of the libraries.\n.SH OPTIONS\n.TP\n.B \\-h\ndisplay usage information and exit\n.TP\n.B \\-v\nbe verbose\n.TP\n.B \\-d\nprint debugging information\n.TP\n.BR \\-l lib_no\n\\fB\\-l n\\fR\nWhere lib_no is the library index number (default library index numbers 10 & 30).\n.TP\n\\fB\\-m PCL\\fR\nwhere PCL is the Physical Cartridge Label (barcode). This is required.\n.TP\n.B \\-D\ndump data\n.SH AUTHOR\nWritten by Mark Harvey\n.SH BUGS\nNeeds to be made user friendly.\n.SH \"REPORTING BUGS\"\nReport bugs to <markh794@gmail.com>\n.SH COPYRIGHT\nCopyright \\(co 2005 Free Software Foundation, Inc.\n.br\nThis is free software; see the source for copying conditions.  There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n.SH \"SEE ALSO\"\n.BR make_vtl_media(1),\n.BR library_contents(5),\n.BR vtlcmd(1),\n.BR vtllibrary(1),\n.BR vtltape(1),\n.BR edit_tape(1),\n.BR preload_tape(1)\n"
  },
  {
    "path": "man/edit_tape.1.in",
    "content": ".TH edit_tape \"1\" \"@MONTH@ @YEAR@\" \"mhvtl @VERSION@\" \"User Commands\"\n.SH NAME\nedit_tape \\- Utility to update meta data virtual media for the VTL.\n.SH SYNOPSIS\n.B edit_tape\n.B [ \\-h ]\n.B [ \\fIoptions \\fR]\n.B ...\n.SH DESCRIPTION\n.\\\" Add any additional description here\n.PP\nCreate and initialise new media for the Virtual Tape Library. Media is created in the\n/opt/vtl/ directory. This path is hard coded.\n.SH OPTIONS\n.TP\n\\fB\\-h\\fR\ndisplay this help and exit\n.TP\n\\fB\\-m PCL\\fR\nwhere PCL is the Physical Cartridge Label (barcode).\n.TP\n\\fB\\-w on|off\\fR\nTurn on|off media write-protect flag\n.TP\n\\fB\\-s size\\fR\nwhere size is the capacity of the virtual media - Size is defined in 'megabytes'.\n.TP\n\\fB\\-t type\\fR\nThe media 'type' which can be: \"data\" , \"WORM\" (Write Once Read Many) or\n\"clean\" (cleaning cartridge)\n.TP\n\\fB\\-d density\\fR\nMedia density. Can be one of LTO1, LTO2, LTO3, LTO4, LTO5, LTO6, LTO7, LTO8, LTO9, SDLT1, SDLT2, SDLT3, SDLT4, AIT1, AIT2, AIT3,\nAIT4, T10KA, T10KB, T10KC, 9840A, 9840B, 9840C, 9840D, 9940A, 9940B, J1A, E05 and E06\n\nThe 'J1A, E05 and E06' media densities refer to the IBM 03592 media types.\n\n.SH AUTHOR\nWritten by Mark Harvey\n.SH BUGS\nNeeds to be made user friendly.\n.SH \"REPORTING BUGS\"\nReport bugs to <markh794@gmail.com>\n.SH COPYRIGHT\nCopyright \\(co 2005 Free Software Foundation, Inc.\n.br\nThis is free software; see the source for copying conditions.  There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n.SH \"SEE ALSO\"\n.BR make_vtl_media(1),\n.BR library_contents(5),\n.BR vtlcmd(1),\n.BR vtllibrary(1),\n.BR vtltape(1)\n.BR mktape(1)\n"
  },
  {
    "path": "man/generate_device_conf.1.in",
    "content": ".TH generate_device_conf \"1\" \"@MONTH@ @YEAR@\" \"mhvtl @VERSION@\" \"User Commands\"\n.SH NAME\ngenerate_device_conf \\- Utility to generate the device.conf file\n.SH SYNOPSIS\n.B generate_device_conf -h|--help -- print help message and exit\n.br\n.BI generate_device_conf OPTIONS\n.SH DESCRIPTION\n.PP\nThis script creates the device.conf file, from scratch. Edit this\nscript and run it to generate a non-default configuration.\n.PP\nThis script is normally run at software installation time, but can be\nedited then run again to regenerate the\n.B device.conf\nfile again.\n.PP\n.I OPTIONS\nare from:\n.TP\n\\fB\\-H\\fR, \\fB\\-\\-home-dir\\fR \\fIHOME_DIR\\fR\nSet the\n.I mhvtl\nhome directory [default\n.BR @HOME_PATH@ .\n.TP\n\\fB\\-D\\fR, \\fB\\-\\-dest-dir\\fR \\fIDIR\\fR\nSet the destination directory [default\n.BR . ]\n.TP\n\\fB\\-f\\fR, \\fB\\-\\-force\\fR\nOverwrite existing\n.B device.conf\nif needed.\n.TP\n\\fB\\-o\\fR, \\fB\\-\\-override-home\\fR\nAllow script to continue even if home directory is not present.\n.SH AUTHOR\nWritten by Mark Harvey.\n.SH BUGS\nNeeds to be made user friendly and more verbose.\nAnd it would be nice to be able to change the device configuration\nfile without editing this script.\n.SH \"REPORTING BUGS\"\nReport bugs to <markh794@gmail.com>\n.SH COPYRIGHT\nCopyright \\(co 2018 Free Software Foundation, Inc.\n.br\nThis is free software; see the source for copying conditions.  There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n.SH \"SEE ALSO\"\n.BR device.conf(5) ,\n.BR make_vtl_media(1) ,\n.BR library_contents(5) ,\n.BR vtlcmd(1) ,\n.BR vtllibrary(1) ,\n.BR vtltape(1) ,\n.BR edit_tape(1) ,\n.BR generate_library_contents(1)\n"
  },
  {
    "path": "man/generate_library_contents.1.in",
    "content": ".TH generate_library_contents \"1\" \"@MONTH@ @YEAR@\" \"mhvtl @VERSION@\" \"User Commands\"\n.SH NAME\ngenerate_library_contents \\- Utility to generate the lib_contents.* files from device.conf\n.SH SYNOPSIS\n\\fBgenerate_library_contents -h|--help\\fR -- print help usage and exit, or\n.br\n.B generate_library_contents\n.I [OPTIONS]\n.SH DESCRIPTION\nWhere\n.I OPTIONS\nare from:\n.TP\n\\fB\\-C\\fR, \\fB\\-\\-config-dir\\fR=\\fIDIR\\fR\nSet config directory [defaults to\n.BR @CONF_PATH@ ]\n.TP\n\\fB\\-D\\fR, \\fB\\-\\-dest-dir\\fR=\\fIDIR\\fR\nSet the destination directory [defaults to\n.BR . ]\n.TP\n\\fB\\-f\\fR, \\fB\\-\\-force\\fR\nWrite over existing library_contents.* files, if needed.\n.PP\nThis script creates the library_contents.* files from the\n.B device.conf\nfile.\nIt is normally run at system installation time, but can be called to regenerate\nthese files if\n.B device.conf\nhas changed.\n.PP\n.SH AUTHOR\nWritten by Mark Harvey.\nUpdated by Lee Duncan.\n.SH BUGS\nNeeds to be made user friendly and more verbose.\nAnd perhaps this should be integrated with\n.BR generate_device_conf(1) .\n.SH \"REPORTING BUGS\"\nReport bugs to <markh794@gmail.com>\n.SH COPYRIGHT\nCopyright \\(co 2018 Free Software Foundation, Inc.\n.br\nThis is free software; see the source for copying conditions.  There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n.SH \"SEE ALSO\"\n.BR device.conf(5) ,\n.BR make_vtl_media(1) ,\n.BR library_contents(5) ,\n.BR vtlcmd(1) ,\n.BR vtllibrary(1) ,\n.BR vtltape(1) ,\n.BR edit_tape(1) ,\n.BR generate_device_conf(1)\n"
  },
  {
    "path": "man/library_contents.5.in",
    "content": ".TH library_contents \"5\" \"@MONTH@ @YEAR@\" \"mhvtl @VERSION@\" \"User Commands\"\n.SH NAME\nlibrary_contents \\- Configuration file for\n.BR vtllibrary(1)\n.SH DESCRIPTION\n.\\\" Add any additional description here\n.PP\nConfiguration file for vtllibrary daemon (part of Virtual Tape Library)\nOne line per entry.\nContains the following sections, Only the 'Slot' section should be populated\nwith additional information (barcodes).\nThe other sections are used as place holders. e.g. If the number of MAP\nslots are to be changed within the VTL, change the number of entries in\nthis configuration file.\n.IP \"Drive #: \"\nNote: Set the serial number of the drive in device.conf\n.IP \"Picker #:\"\n.IP \"MAP #:\"\n.IP \"Slot #: [Barcode]\"\nWhere [Barcode] can be any ASCII string from 1 to 12 chars in length. If there is no Barcode\ndefined for the Slot number, the slot is taken to be empty.\n.SH AUTHOR\nWritten by Mark Harvey\n.SH BUGS\n.RS\nThis man page.\n.RE\n.RS\nNo version information.\n.RE\n.RS\nConfig file not xml.\n.RE\n.RS\n.BR vtllibrary(1)\nneeds to be restarted to read any changes made.\n.RE\n.SH \"REPORTING BUGS\"\nReport bugs to <markh794@gmail.com>\n.SH COPYRIGHT\nCopyright \\(co 2005 Free Software Foundation, Inc.\n.br\nThis is free software; see the source for copying conditions.  There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n.SH \"SEE ALSO\"\n.BR make_vtl_media(1),\n.BR mktape(1),\n.BR vtlcmd(1),\n.BR vtllibrary(1),\n.BR vtltape(1)\n.BR device.conf(5)\n"
  },
  {
    "path": "man/make_vtl_media.1.in",
    "content": ".TH make_vtl_media \"1\" \"@MONTH@ @YEAR@\" \"mhvtl @VERSION@\" \"User Commands\"\n.SH NAME\nmake_vtl_media \\- create the library database from lib_contents.* file(s)\n.SH SYNOPSIS\n\\fBmake_vtl_media \\-h|\\-\\-help\\fR -- print help message and exit, or\n.br\n.B make_vtl_media\n.I [OPTIONS]\n.SH DESCRIPTION\n.PP\nWhere\n.I OPTIONS\nare from:\n.TP\n\\fB\\-H\\fR, \\fB\\-\\-home-dir\\fR=\\fIDIR\\fR\nSet the\n.I mhvtl\nhome directory [default\n.BR @HOME_PATH@ ]\n.TP\n\\fB\\-C\\fR, \\fB\\-\\-config-dir\\fR=\\fIDIR\\fR\nSet the config directory [default\n.BR @CONFIG_PATH@ ]\n.TP\n\\fB\\-f\\fR, \\fB\\-\\-force\\fR\nOverwrite existing database files, if needed.\n.TP\n\\fB\\-c\\fR, \\fB\\-\\-create-dir\\fR\nCreate the home directory, if needed.\n.PP\nThis program is invoked initialy when the software is installed, but\ncan also be ran later to recreate the tape libraray database. It does so by reading\nthe\n.I device.conf\nand\n.I library_contents.*\nfiles in our configuration directory, and finding the\n.B Slot\nentries in those files, extracting the\n.I barcode\nfound for each slot.\n.PP\n.IP \"If \\fIbarcode\\fR starts with W\"\nCreate as Write Once Read Many (WORM) media type.\n.IP \"If \\fIbarcode\\fR starts with CLN\"\nCreate media type as cleaning cartridge.\n.IP \"Otherwise\"\nCreate the media as a data cartridge.\n.IP\nAttempts to use the chars 7 and 8 to work out the media type (LTO1/2/3/4/5/6/7,\nT10K, AIT etc) See\n.B mktape(1)\nfor more details on media density.\n.IP\nFeel free to replace this script with one that better suits your needs.\n.PP\nIf the configuration is regenerated then the\n.B mhvtl.target\nservice should be restarted.\n.SH AUTHOR\nWritten by Mark Harvey\n.SH BUGS\nNot documented.\n.SH \"REPORTING BUGS\"\nReport bugs to <markh794@gmail.com>\n.SH COPYRIGHT\nCopyright \\(co 2019 Free Software Foundation, Inc.\n.P\nThis is free software; see the source for copying conditions.  There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n.SH \"SEE ALSO\"\n.BR library_contents(5) ,\n.BR mktape(1) ,\n.BR vtlcmd(1) ,\n.BR vtllibrary(1) ,\n.BR vtltape(1) ,\n.BR generate_device_conf(1) ,\n.BR generate_library_contents(1)\n"
  },
  {
    "path": "man/mhvtl.conf.5.in",
    "content": ".TH mhvtl.conf \"5\" \"@MONTH@ @YEAR@\" \"mhvtl @VERSION@\" \"User Commands\"\n.SH NAME\nmhvtl.conf \\- Configuration file for\n.B vtllibrary(1)\nand\n.B vtltape(1)\n.SH DESCRIPTION\n.\\\" Add any additional description here\n.PP\nConfiguration file to define startup behaviour of the virtual tape library.\n.TP\nMHVTL_HOME_PATH=@HOME_PATH@\nThe location where\n.I mhvtl\nstores its tape\n.IR database .\n.TP\nCAPACITY=500\nDefines default capacity any new media will be created (in Megabytes).\n.B make_vtl_media(1)\nuses this value and passes to\n.IR mktape .\n.TP\nVERBOSE=1\nSet verbosity to level [0|1|2|3] for daemon logging level at startup.\nRefer to\n.B vtlcmd(1)\nto adjust logging level at runtime.\n.TP\nVTL_DEBUG=0\nSet to [0|1]. to disable/enable kernel module logging. Can be enabled/disabled\nat runtime via:\n.IP\n\"echo 0 > /sys/bus/pseduo/drivers/mhvtl/opts\" to disable, or\n.IP\n\"echo 1 > /sys/bus/pseudo/drivers/mhvtl/opts\" to enable logging.\n.TP\nDAEMON_DEBUG=''\nSet to\n.I ''\nto disable daemon debugging, or\n.I '-d'\nto enable it.\n.SH AUTHOR\nWritten by Mark Harvey\n.SH BUGS\nThis man page.\n.PP\nConfig file not xml.\n.PP\n.B vtllibrary(1)\nneeds to be restarted to read any changes made. (By design).\n.SH \"REPORTING BUGS\"\nReport bugs to <markh794@gmail.com>\n.SH COPYRIGHT\nCopyright \\(co 2019 Free Software Foundation, Inc.\n.br\nThis is free software; see the source for copying conditions.  There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n.SH \"SEE ALSO\"\n.BR mktape(1) ,\n.BR vtlcmd(1) ,\n.BR vtllibrary(1) ,\n.BR vtltape(1)\n"
  },
  {
    "path": "man/mhvtl_kernel_mod_build.1.in",
    "content": ".TH mhvtl_kernel_mod_build \"1\" \"@MONTH@ @YEAR@\" \"mhvtl @VERSION@\" \"User Commands\"\n.SH NAME\nmhvtl_kernel_mod_build \\- Simple wrapper script to extract mhvtl.ko source and compile\n.SH SYNOPSIS\n\\fBmhvtl_kernel_mod_build\n.br\n.SH DESCRIPTION\n.br\nThis bash script simply extracts /usr/lib/firmware/mhvtl/mhvtl_kernel.tgz and compiles (make && sudo make install)\n.br\nThe mhvtl.ko source is extracted into a unique tmp directory using 'mktemp()'\n.SH AUTHOR\nWritten by Mark Harvey\n.SH BUGS\nAssumes the kernel-devel and gcc plus supporting packages are already installed.\n.SH \"REPORTING BUGS\"\nReport bugs to <markh794@gmail.com> or log an issue at https://github.com/markh794/mhvtl.git\n.br\nBetter yet, I'm happy to accept patches which fix bugs :)\n.SH COPYRIGHT\nCopyright \\(co 2019 Free Software Foundation, Inc.\n.P\nThis is free software; see the source for copying conditions.  There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n.SH \"SEE ALSO\"\n.BR library_contents(5) ,\n.BR mktape(1) ,\n.BR vtlcmd(1) ,\n.BR vtllibrary(1) ,\n.BR vtltape(1) ,\n.BR generate_device_conf(1) ,\n.BR generate_library_contents(1)\n"
  },
  {
    "path": "man/mktape.1.in",
    "content": ".TH mktape \"1\" \"@MONTH@ @YEAR@\" \"mhvtl @VERSION@\" \"User Commands\"\n.SH NAME\nmktape \\- Utility to create new/blank virtual media for the VTL.\n.SH SYNOPSIS\n.B mktape \\-h\n.br\n.B mktape REQUIRED_PARAMS\n.BI [ OPTIONS ]\n.B ...\n.SH DESCRIPTION\n.PP\nCreate and initialise new media for the Virtual Tape Library. Media is\ncreated in the\n.B @HOME_PATH@\ndirectory by default. This can be over-ridden\nusing the 'Home directory:' setting in\n.BR device.conf .\n.SH OPTIONS\nOptions are from:\n.TP\n.B \\-h\ndisplay this help and exit\n.TP\n.B \\-V\nPrint version information and exit\n.TP\n.B \\-v\nBe verbose\n.TP\n.B \\-D\nEnter debugging mode (much each output)\n.TP\n\\fB\\-C\\fR \\fIconfig-dir\\fR\nUse\n.I config-dir\ninstead of the default of\n.BR @CONFIG_PATH@ .\n.PP\nRequired options are:\n.TP\n\\fB\\-l\\fR \\fIn\\fR\nWhere\n.I n\nis the library index number (default library index numbers 10 & 30).\nThe 'Home directory:' entry for the library specified is used as parent\ndirectory for media created.\nIf the library index number does not exist, then a subdir under\n@HOME_PATH@/<n>\nis created and virtual media created in this directory.\nFor example \"mktape -l 20 -m ABC123 -s 1024 -t data -d LTO3\" will create a virtual\nmedia\n.I ABC123\nin @HOME_PATH@/20/\nif no library index 20 defined in\n.BR device.conf .\n.TP\n\\fB\\-m\\fR \\fIPCL\\fR\nwhere\n.I PCL\nis the Physical Cartridge Label (barcode).\n.TP\n\\fB\\-s\\fR \\fIsize\\fR\nwhere\n.I size\nis the capacity of the virtual media - Size is defined in 'megabytes'.\n.TP\n\\fB\\-t\\fR \\fItype\\fR\nThe media\n.I type\nwhich can be:\n.BR data ,\n.B WORM\n(Write Once Read Many),\n.B clean\n(cleaning cartridge) or\n.B NULL\nfor media which does not save data.\n.PP\nThe\n.B NULL\nis a special media type used primarily to test performance with disk\nwrites kept to a minimum. Note: Metadata (512bytes per data block) is still\nwritten.\n.TP\n\\fB\\-d\\fR \\fIdensity\\fR\nMedia\n.IR density .\nCan be one of\n.BR LTO1 ,\n.BR LTO2 ,\n.BR LTO3 ,\n.BR LTO4 ,\n.BR LTO5 ,\n.BR LTO6 ,\n.BR LTO7 ,\n.BR LTO8 ,\n.BR LTO9 ,\n.BR SDLT1 ,\n.BR SDLT2 ,\n.BR SDLT3 ,\n.BR SDLT4 ,\n.BR AIT1 ,\n.BR AIT2 ,\n.BR AIT3 ,\n.BR AIT4 ,\n.BR T10KA ,\n.BR T10KB ,\n.BR T10KC ,\n.BR 9840A ,\n.BR 9840B ,\n.BR 9840C ,\n.BR 9840D ,\n.BR 9940A ,\n.BR 9940B ,\n.BR J1A ,\n.BR E05\nand\n.BR E06 .\n.PP\nThe\n.BR J1A ,\n.B E05\nand\n.B E06\nmedia densities refer to the IBM 03592 media types.\n.SH AUTHOR\nWritten by Mark Harvey\n.SH BUGS\nNeeds to be made user friendly.\n.SH \"REPORTING BUGS\"\nReport bugs to <markh794@gmail.com>\n.SH COPYRIGHT\nCopyright \\(co 2018 Free Software Foundation, Inc.\n.br\nThis is free software; see the source for copying conditions.  There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n.SH \"SEE ALSO\"\n.BR make_vtl_media(1) ,\n.BR library_contents(5) ,\n.BR vtlcmd(1) ,\n.BR vtllibrary(1) ,\n.BR vtltape(1) ,\n.BR edit_tape(1) ,\n.BR generate_device_conf(1) ,\n.BR generate_library_contents(1)\n"
  },
  {
    "path": "man/preload_tape.1.in",
    "content": ".TH preload_tape \"1\" \"@MONTH@ @YEAR@\" \"mhvtl @VERSION@\" \"User Commands\"\n.SH NAME\npreload_tape \\- Utility to write a file directly to virtual media.\n.SH SYNOPSIS\n.B preload_tape\n.B [ \\-h ]\n.br\n.B preload_tape\n.B [ \\fIOPTIONS\\fR]\n.SH DESCRIPTION\n.\\\" Add any additional description here\n.PP\nDump the contents of the specified PCL. If a library is specified, look\nthere, else look through all of the libraries.\n.SH OPTIONS\n.TP\n.B \\-h\ndisplay usage information and exit\n.TP\n.B \\-v\nbe verbose\n.TP\n.B \\-d\nprint debugging information\n.TP\n.BR \\-l lib_no\n\\fB\\-l n\\fR\nWhere lib_no is the library index number (default library index numbers 10 & 30).\n.TP\n\\fB\\-m PCL\\fR\nwhere PCL is the Physical Cartridge Label (barcode). This is required.\n.TP\n\\fB\\-F <filename>\\fR\nwhere <filename> is the source of the data to write 'in' virtual media format.\n.TP\n\\fB\\-b block_size\\fR\nwhere block_size is the size of the 'tape block' - e.g. -b 65535 will write in 64k blocks\n.TP\n\\fB\\-c LZO|ZLIB|NONE\\fR\nCompress data before writing in virtual media format.\n.TP\n.B\n.SH AUTHOR\nWritten by Mark Harvey\n.SH BUGS\nNeeds to be made user friendly.\n.SH \"REPORTING BUGS\"\nReport bugs to <markh794@gmail.com>\n.SH COPYRIGHT\nCopyright \\(co 2005 Free Software Foundation, Inc.\n.br\nThis is free software; see the source for copying conditions.  There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n.SH \"SEE ALSO\"\n.BR make_vtl_media(1),\n.BR library_contents(5),\n.BR vtlcmd(1),\n.BR dump_tape(1),\n.BR vtllibrary(1),\n.BR vtltape(1),\n.BR edit_tape(1)\n"
  },
  {
    "path": "man/tapeexerciser.1.in",
    "content": ".TH tapeexerciser \"1\" \"@MONTH@ @YEAR@\" \"mhvtl @VERSION@\" \"User Commands\"\n.SH NAME\ntapeexerciser \\- Utility to exercise virtual media for the VTL.\n.SH SYNOPSIS\n.B tapeexerciser\n.BR \\-f tape_device\n.SH DESCRIPTION\n.\\\" Add any additional description here\n.PP\nExercise the specified tape drive path and exercise the tape found\nthere.\n.PP\n.B NOTE: \nThis will overwrite the contents of the tape media on the specified drive.\n.SH AUTHOR\nWritten by Mark Harvey\n.SH BUGS\nNeeds to be made user friendly.\n.SH \"REPORTING BUGS\"\nReport bugs to <markh794@gmail.com>\n.SH COPYRIGHT\nCopyright \\(co 2005 Free Software Foundation, Inc.\n.br\nThis is free software; see the source for copying conditions.  There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n.SH \"SEE ALSO\"\n.BR make_vtl_media(1),\n.BR library_contents(5),\n.BR vtlcmd(1),\n.BR vtllibrary(1),\n.BR vtltape(1)\n.BR edit_tape(1)\n"
  },
  {
    "path": "man/update_device.conf.1.in",
    "content": ".TH update_device.conf \"1\" \"@MONTH@ @YEAR@\" \"mhvtl @VERSION@\" \"User Commands\"\n.SH NAME\nupdate_device.conf \\- Utility to update device.conf to version 4\n.SH SYNOPSIS\n.B update_device.conf\n.SH DESCRIPTION\n.\\\" Add any additional description here\n.PP\nThis script updates the device.conf file to version 4, and sets\nthe library index to one more than the number of drives found.\n.SH AUTHOR\nWritten by Mark Harvey\n.SH BUGS\nNeeds to be made user friendly and more verbose.\n.SH \"REPORTING BUGS\"\nReport bugs to <markh794@gmail.com>\n.SH COPYRIGHT\nCopyright \\(co 2005 Free Software Foundation, Inc.\n.br\nThis is free software; see the source for copying conditions.  There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n.SH \"SEE ALSO\"\n.BR device.conf(5)\n.BR make_vtl_media(1),\n.BR library_contents(5),\n.BR vtlcmd(1),\n.BR vtllibrary(1),\n.BR vtltape(1)\n.BR edit_tape(1)\n"
  },
  {
    "path": "man/vtlcmd.1.in",
    "content": ".TH vtlcmd \"1\" \"@MONTH@ @YEAR@\" \"mhvtl @VERSION@\" \"User Commands\"\n.SH NAME\nvtlcmd \\- user space utility to send commands to\n.BR vtltape(1),\n.BR vtllibrary(1),\ndaemons.\n.SH SYNOPSIS\n.B vtlcmd 'Q number'\n.B [ \\-h ]\n.B [ \\fIcommand \\fR]\n.B ...\n.SH DESCRIPTION\n.\\\" Add any additional description here\n.PP\nWhere 'Q number' is the message queue number for the drive (see\n.BR vtltape(1)\n)\n\n.TP\n\\fB\\-h\\fR\ndisplay this help and exit\n.SH COMMAND\n.IP verbose\nToggle verbose flag. This will cycle verbose flag thru verbose settings 3 2 1 off\n.IP \"load <ID>\"\nLoad media ID (barcode) - Used for stand-alone tape drive daemon.\n.IP \"unload <ID>\"\nUnload media ID (barcode)\n.IP \"compression <ZLIB|LZO>\"\nChanges compression libraries used to compress each block of data. Valid for\n.B tape\nonly.\n.IP \"delay load x\"\nSets a delay for loading media to\n.B x\nseconds. Valid values 0 - 20. ssc target returns <02/04/01> 'NOT READY/BECOMMING READY' status in response to any 'Test Unit Ready' requested until timer expires.\nValid for\n.B tape\nonly.\n.IP \"delay unload x\"\nSets a delay for unloading media to\n.B x\nseconds. Valid values 0 - 20. Valid for\n.B tape\nonly.\n.IP \"delay rewind x\"\nSets a delay for rewinding media to\n.B x\nseconds. Valid values 0 - 30. Valid for\n.B tape\nonly.\n.IP \"delay position x\"\nSets a delay for positioning media to\n.B x\nseconds. Valid values 0 - 20. Valid for\n.B tape\nonly.\n.IP \"delay thread x\"\nSets a delay for \\'threading\\' media to\n.B x\nseconds. Valid values 0 - 20. Valid for\n.B tape\nonly.\n\n.IP \"TapeAlert <alert flag>\"\nSend a 64bit hex number, each bit corresponds to one TapeAlert flag as defined by t10.org. Where bit 0 is TapeAlert flag 1, and bit 63 is TapeAlert flag 64.\n.IP exit\nSend a terminate message to daemon.\n.IP online\nValid for\n.B library\nonly.\nPlace library in 'online' mode.\n.IP offline\nValid for\n.B library\nonly.\nTake library 'offline'.\n.IP \"add slot\"\nValid for\n.B library\nonly.\nThis will dynamically add an additional storage slot to the library. This is not persistent.\n.IP \"list map\"\nValid for\n.B library\nonly.\nReturns a list of media IDs in Media Access Port (MAP).\n.IP \"open map\"\nValid for\n.B library\nonly.\nLogically 'opens' the Media Access Port (MAP).\n.IP \"close map\"\nValid for\n.B library\nonly.\nLogically 'closes' the Media Access Port (MAP). MAP needs to be 'closed'\nbefore the Medium Transport Element can move media to/from MAP.\n.IP \"empty map\"\nValid for\n.B library\nonly.\nClears media from Media Access Port (MAP). Only valid when MAP is\nin 'open' state\n.IP \"load map <media>\"\nValid for\n.B library\nonly.\nPlaces <media> logically into the Media Access Port (MAP). Note: <media> needs\nto exist first, otherwise the command fails with suggestion to create media\nfirst. see\n.BR mktape(1)\nfor creating media.\n.SH AUTHOR\nWritten by Mark Harvey\n.SH BUGS\nNeeds to be made user friendly.\n.SH \"REPORTING BUGS\"\nReport bugs to <markh794@gmail.com>\n.SH COPYRIGHT\nCopyright \\(co 2005 Free Software Foundation, Inc.\n.br\nThis is free software; see the source for copying conditions.  There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n.SH \"SEE ALSO\"\n.BR library_contents(5),\n.BR mktape(1),\n.BR vtllibrary(1),\n.BR vtltape(1)\n"
  },
  {
    "path": "man/vtllibrary.1.in",
    "content": ".TH vtllibrary \"1\" \"@MONTH@ @YEAR@\" \"mhvtl @VERSION@\" \"User Commands\"\n.SH NAME\nvtllibrary \\- user space daemon to handle SCSI SMC commands for Virtual Tape Library.\n.SH SYNOPSIS\n\\fBvtllibrary \\-h\\fR -- print a help message and exit, or\n.br\n.B vtllibrary\n.I [OPTIONS]\n\\fB\\-q\\fR \\fIQUEUE_ID\\fR -- Emulate a tape library for queue \\fIQUEUE_ID\\fR.\n.SH DESCRIPTION\n.\\\" Add any additional description here\nThis command emulates a tape library device, using queue\n.IR QUEUE_ID ,\nwhich represent the message queue number used for this daemon.\nThis number is derived from the\n.I device.conf\nwhere it must be unique. Media files can be created using\n.I OPTIONS\nare from:\n.TP\n.B \\-d\nEnable debug logging (to stdout). Do not background the process,\nand set verbosity to level 9.\n.TP\n.BI \\-v[ N ]\nEnable verbose logging (to syslog) at level \\fIN\\fR (default 1).\n.TP\n.B -F\nRun in the foreground, not as a daemon.\n.TP\n.BI \\-f FIFO\nNear real time device state information will be available for external utilities by reading from this fifo. This switch has a higher precedence than the 'fifo:' entry in\n.BR device.conf .\n.PP\nThe\n.B vtllibrary\ndaemon simulates a tape library device, and is started by\n.BR systemd(1) ,\nas needed, one invocation per Tape Library being simulated. The\n.B vtllibrary\ndaemon registers each\n.B vtltape(1)\nvia message queue. The\n.B vtllibrary\nreads @CONFIG_PATH@/library_contents.*\nand dynamically builds an internal structure of Storage slots and Media Access slots.\nAll media movement is performed on internal structures only. The configuration file\nis never changed, i.e. a re-start of the daemon will result in the loss of any\nprevious media movements.\n.P\nWhen media is moved to/from a \"Data transfer element\" (tape drive), a (un)load message is sent\nvia the drive 'slot number' message Q number to load/unload the barcode.\n.SH FILES\n@CONFIG_PATH@/device.conf -- to find which \\fIlibrary_contents.*\\fR files to examine\n.br\n@CONFIG_PATH@/library_contents.*\n.SH AUTHOR\nWritten by Mark Harvey\n.SH BUGS\nDoes not implement the complete SCSI SMC-2/SMC-3 command set.\n.SH \"REPORTING BUGS\"\nReport bugs to <markh794@gmail.com>\n.SH COPYRIGHT\nCopyright \\(co 2019 Free Software Foundation, Inc.\n.br\nThis is free software; see the source for copying conditions. There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n.SH \"SEE ALSO\"\n.BR library_contents(5) ,\n.BR mktape(1) ,\n.BR make_vtl_media(1) ,\n.BR vtlcmd(1) ,\n.BR vtltape(1)\n"
  },
  {
    "path": "man/vtltape.1.in",
    "content": ".TH vtltape \"1\" \"@MONTH@ @YEAR@\" \"mhvtl @VERSION@\" \"User Commands\"\n.SH NAME\nvtltape \\- user space daemon to handle SCSI SSC commands for Virtual Tape Library.\n.SH SYNOPSIS\n\\fBvtltape -h\\fR -- print a help message and exit, or\n.br\n.B vtltape\n.I [OPTIONS]\n\\fB-q\\fR \\fIQUEUE_ID\\fR -- Emulate a tape drive for queue \\fIQUEUE_ID\\fR.\n.SH DESCRIPTION\n.\\\" Add any additional description here\nThis command emulates a tape device, using queue\n.IR QUEUE_ID ,\nwhich represent the message queue number used for this daemon.\nThis number is derived from the\n.I device.conf\nwhere it must be unique. Media files can be created using\n.BR mktape(1) .\n.P\n.I OPTIONS\nare from:\n.TP\n.B \\-d\nEnable debug logging (to stdout). Do not background the process,\nand set verbosity to level 9.\n.TP\n.BI \\-v[ N ]\nEnable verbose logging (to syslog) at level \\fIN\\fR (default 1).\n.TP\n.BI \\-f FIFO\nNear real time device state information will be available for external utilities by reading from this fifo.\nThis switch has a higher precedence than the 'fifo:' entry in\n.BR\ndevice.conf .\n.SH AUTHOR\nWritten by Mark Harvey\n.SH BUGS\nDoes not implement the complete SCSI SSC-3 command set.\n.SH \"REPORTING BUGS\"\nReport bugs to <markh794@gmail.com>\n.SH COPYRIGHT\nCopyright \\(co 2019 Free Software Foundation, Inc.\n.br\nThis is free software; see the source for copying conditions. There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n.SH \"SEE ALSO\"\n.BR library_contents(5) ,\n.BR make_vtl_media(1) ,\n.BR mktape(1) ,\n.BR vtlcmd(1) ,\n.BR vtllibrary(1)\n"
  },
  {
    "path": "mhvtl-utils.spec",
    "content": "# Disable the building of the debug package(s).\n%define debug_package %{nil}\n\n# config.sh parses '_firmwarepath' to define FIRMWAREDIR in parent Makefile\n%global _firmwarepath\t/usr/lib/firmware\n\n# Compat path macros\n# pilfered from https://src.fedoraproject.org/rpms/snapd/blob/master/f/snapd.spec\n%{!?_systemdgeneratordir: %global _systemdgeneratordir %{_prefix}/lib/systemd/system-generators}\n\n%define _unpackaged_files_terminate_build 0\n\n%define mhvtl_home_dir /opt/mhvtl\n\nSummary: Virtual tape library. kernel pseudo HBA driver + userspace daemons\n%define real_name mhvtl\nName: mhvtl-utils\n%define real_version 2026-03-10\n%define minor 0\nVersion: 1.8\nRelease: %{minor}%{?dist}\nLicense: GPL\nGroup: System/Kernel\nURL: http://sites.google.com/site/linuxvtl2/\n\nSource: mhvtl-%{real_version}.tgz\nBuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-build-%(%{__id_u} -n)\n\nRecommends: lsscsi mtx mt-st\n\nRequires:sg3_utils\nRequires: policycoreutils\nRequires: tar >= 1.28\n\nBuildRequires: systemd\nBuildRequires: systemd-rpm-macros\nBuildRequires: zlib-devel\n%{?systemd_requires}\n%{?systemd_ordering}\n\nObsoletes: mhvtl <= %{version}-%{release}\nProvides: mhvtl = %{version}-%{release}\n\n%description\nA Virtual tape library and tape drives:\n\nUsed to emulate hardware robot & tape drives:\n\nVTL consists of a pseudo HBA kernel driver and user-space daemons which\nfunction as the SCSI target.\n\nCommunication between the kernel module and the daemons is achieved\nvia /dev/mhvtl? device nodes.\n\nThe kernel module is based on the scsi_debug driver.\nThe SSC/SMC target daemons have been written from scratch.\n\n%prep\n%setup -n %{real_name}-%{version}\n\n%post\n/sbin/semanage fcontext -a -t systemd_unit_file_t %{_unitdir}/mhvtl-load-modules.service\n/sbin/semanage fcontext -a -t systemd_unit_file_t %{_unitdir}/vtllibrary@.service\n/sbin/semanage fcontext -a -t systemd_unit_file_t %{_unitdir}/vtltape@.service\n/sbin/semanage fcontext -a -t systemd_unit_file_t %{_unitdir}/mhvtl.target\n/sbin/restorecon -R -v %{_unitdir}\n/bin/systemctl daemon-reload\n%{service_add_post mhvtl.target mhvtl-load-modules.service vtllibrary@.service vtltape@.service}\n/bin/systemctl start mhvtl.target\n/bin/systemctl enable  mhvtl.target\nmake_vtl_media --config-dir=%{_sysconfdir}/mhvtl --home-dir=/opt/mhvtl --mktape-path=%{_bindir}\n\n%postun\n/sbin/ldconfig\n/bin/systemctl daemon-reload\n\n#%{service_del_postun mhvtl.target mhvtl-load-modules.service vtllibrary@.service vtltape@.service}\n\n%pre\n#%{service_add_pre mhvtl.target mhvtl-load-modules.service vtllibrary@.service vtltape@.service}\n\n%preun\n/bin/systemctl stop  mhvtl.target\n/bin/systemctl disable  mhvtl.target\n#%{service_del_preun mhvtl.target mhvtl-load-modules.service vtllibrary@.service vtltape@.service}\n\n%build\nmake MHVTL_HOME_PATH=%{mhvtl_home_dir} VERSION=%{version} EXTRAVERSION=%{minor} \\\n\tSYSTEMD_GENERATOR_DIR=%{_systemdgeneratordir} \\\n\tSYSTEMD_SERVICE_DIR=%{_unitdir}\n\n%install\n%make_install \\\n\tMHVTL_HOME_PATH=%{mhvtl_home_dir} VERSION=%{version} EXTRAVERSION=%{minor} LIBDIR=%{_libdir} \\\n\tSYSTEMD_GENERATOR_DIR=%{_systemdgeneratordir} \\\n\tSYSTEMD_SERVICE_DIR=%{_unitdir}\ninstall -d -m 755 %{buildroot}%{_sbindir}\nln -s %{_sbindir}/service %{buildroot}/%{_sbindir}/rc%{name}\ninstall -d -m 755 %{buildroot}/var/lib/%{name}\n\n%clean\n%{__rm} -rf %{buildroot}\n\n%files\n%defattr(-, root, root, 0755)\n%doc INSTALL README etc/library_contents.sample\n%doc %{_mandir}/man1/mktape.1*\n%doc %{_mandir}/man1/edit_tape.1*\n%doc %{_mandir}/man1/vtlcmd.1*\n%doc %{_mandir}/man1/vtllibrary.1*\n%doc %{_mandir}/man1/vtltape.1*\n%doc %{_mandir}/man1/preload_tape.1*\n%doc %{_mandir}/man1/dump_tape.1*\n%doc %{_mandir}/man1/make_vtl_media.1*\n%doc %{_mandir}/man1/mhvtl_kernel_mod_build.1*\n%doc %{_mandir}/man1/tapeexerciser.1*\n%doc %{_mandir}/man1/update_device.conf.1*\n%doc %{_mandir}/man1/generate_device_conf.1*\n%doc %{_mandir}/man1/generate_library_contents.1*\n%doc %{_mandir}/man5/device.conf.5*\n%doc %{_mandir}/man5/mhvtl.conf.5*\n%doc %{_mandir}/man5/library_contents.5*\n%{_bindir}/vtlcmd\n%{_bindir}/mktape\n%{_bindir}/edit_tape\n%{_bindir}/dump_tape\n%{_bindir}/preload_tape\n%{_bindir}/tapeexerciser\n%{_bindir}/make_vtl_media\n%{_bindir}/mhvtl_kernel_mod_build\n%{_bindir}/update_device.conf\n%{_bindir}/generate_device_conf\n%{_bindir}/generate_library_contents\n%{_libdir}/libvtlscsi.so\n%{_libdir}/libvtlcart.so\n%{_firmwarepath}/mhvtl/mhvtl_kernel.tgz\n%dir %{_sysconfdir}/mhvtl\n%config(noreplace) %{_sysconfdir}/mhvtl/mhvtl.conf\n%config(noreplace) %{_sysconfdir}/mhvtl/device.conf\n%config(noreplace) %{_sysconfdir}/mhvtl/library_contents.10\n%config(noreplace) %{_sysconfdir}/mhvtl/library_contents.30\n%{_systemdgeneratordir}/mhvtl-device-conf-generator\n%{_unitdir}/mhvtl-load-modules.service\n%{_unitdir}/vtllibrary@.service\n%{_unitdir}/vtltape@.service\n%{_unitdir}/mhvtl.target\n%dir %{mhvtl_home_dir}\n%ghost %{mhvtl_home_dir}/*\n\n%defattr(755, root, root, 0755)\n%{_bindir}/vtltape\n%{_bindir}/vtllibrary\n\n%defattr(-, root, root, 755)\n%dir /opt/mhvtl/\n\n%changelog\n* Fri Mar 10 2023 Mark Harvey <markh794@gmail.com> - 1.7-1\n- Updated to release 1.7-1 (2023-03-10).\n\n* Thu Mar 10 2022 Mark Harvey <markh794@gmail.com> - 1.7-0\n- Updated to release 1.7-0 (2022-03-10).\n\n* Thu Oct 07 2021 Mark Harvey <markh794@gmail.com> - 1.6-4\n- Updated to release 1.6-4 (2021-10-07).\n\n* Tue Mar 03 2020 Mark Harvey <markh794@gmail.com> - 1.6-3\n- Updated to release 1.6-3 (2020-03-10).\n\n* Sun Oct 06 2019 Mark Harvey <markh794@gmail.com> - 1.6-2\n- Updated to release 1.6-2 (2019-10-06).\n\n* Thu Mar 10 2016 Mark Harvey <markh794@gmail.com> - 1.5-4\n- Updated to release 1.5-4 (2016-03-10).\n\n* Tue Apr 14 2015 Mark Harvey <markh794@gmail.com> - 1.5-3\n- Updated to release 1.5-3 (2015-04-14).\n\n* Sun Sep 7 2014 Mark Harvey <markh794@gmail.com> - 1.5-2\n- Updated to release 1.5-2 (2014-09-04).\n\n* Sun Apr 13 2014 Mark Harvey <markh794@gmail.com> - 1.5-0\n- Updated to release 1.5-0 (2014-04-13).\n\n* Sun Oct 20 2013 Mark Harvey <markh794@gmail.com> - 1.4-10\n- Updated to release 1.4-10 (2013-10-20).\n\n* Thu Aug 29 2013 Mark Harvey <markh794@gmail.com> - 1.4-9\n- Updated to release 1.4-9 (2013-08-29).\n\n* Sat Jun 29 2013 Mark Harvey <markh794@gmail.com> - 1.4-8\n- Updated to release 1.4-8 (2013-06-29).\n\n* Fri Mar 22 2013 Mark Harvey <markh794@gmail.com> - 1.4-7\n- Updated to release 1.4-7 (2013-03-22).\n\n* Thu Jan 31 2013 Mark Harvey <markh794@gmail.com> - 1.4-6\n- Updated to release 1.4-6 (2013-01-31).\n\n* Sat Jan 12 2013 Mark Harvey <markh794@gmail.com> - 1.4-5\n- Updated to release 1.4-5 (2013-01-12).\n\n* Mon Aug 13 2012 Mark Harvey <markh794@gmail.com> - 1.4-4\n- Updated to release 1.4-4 (2012-09-13).\n\n* Wed Aug  8 2012 Mark Harvey <markh794@gmail.com> - 1.4-1\n- Updated to release 1.4-1 (2012-08-08).\n\n* Wed Aug  1 2012 Mark Harvey <markh794@gmail.com> - 1.4-0\n- Updated to release 1.4 (2012-08-01).\n- install using Makefile\n\n* Thu Jun 21 2012 Dag Wieers <dag@wieers.com> - 1.3-1\n- Updated to release 1.3 (2012-06-15).\n\n* Thu Aug 05 2010 Dag Wieers <dag@wieers.com> - 0.18-11\n- Initial build of the kmod package.\n"
  },
  {
    "path": "scripts/70-persistent-generic.rules",
    "content": "\n# Media changer\nACTION==\"add|change\", KERNEL==\"sg[0-9]*\", SUBSYSTEM==\"scsi_generic\", PROGRAM==\"/lib/udev/scsi_id --page=0x83 --whitelisted -u --device=$tempnode\", RESULT==\"?IBM_03584L32_XYZZY_A00*\", NAME=\"sg9\"\n\n# Persistent name starting from 'sg6'\nACTION==\"add|change\", KERNEL==\"sg[0-9]*\", SUBSYSTEM==\"scsi_generic\", PROGRAM==\"/lib/udev/scsi_id --page=0x83 --whitelisted --device=$tempnode\", RESULT==\"350223344ff000100\", NAME=\"sg6\"\nACTION==\"add|change\", KERNEL==\"sg[0-9]*\", SUBSYSTEM==\"scsi_generic\", PROGRAM==\"/lib/udev/scsi_id --page=0x83 --whitelisted --device=$tempnode\", RESULT==\"350223344ff000200\", NAME=\"sg7\"\nACTION==\"add|change\", KERNEL==\"sg[0-9]*\", SUBSYSTEM==\"scsi_generic\", PROGRAM==\"/lib/udev/scsi_id --page=0x83 --whitelisted --device=$tempnode\", RESULT==\"350223344ff000300\", NAME=\"sg8\"\n"
  },
  {
    "path": "scripts/70-persistent-tape.rules",
    "content": "ACTION==\"add|change\", KERNEL==\"st[0-9]*\", SUBSYSTEM==\"scsi_tape\", ENV{ID_SERIAL}==\"350223344ff000100\", NAME=\"st0\"\nACTION==\"add|change\", KERNEL==\"nst[0-9]*\", SUBSYSTEM==\"scsi_tape\", ENV{ID_SERIAL}==\"350223344ff000100\", NAME=\"nst0\"\n#\nACTION==\"add|change\", KERNEL==\"st[0-9]*\", SUBSYSTEM==\"scsi_tape\", ENV{ID_SERIAL}==\"350223344ff000200\", NAME=\"st1\"\nACTION==\"add|change\", KERNEL==\"nst[0-9]*\", SUBSYSTEM==\"scsi_tape\", ENV{ID_SERIAL}==\"350223344ff000200\", NAME=\"nst1\"\n#\nACTION==\"add|change\", KERNEL==\"st[0-9]*\", SUBSYSTEM==\"scsi_tape\", ENV{ID_SERIAL}==\"350223344ff000300\", NAME=\"st2\"\nACTION==\"add|change\", KERNEL==\"nst[0-9]*\", SUBSYSTEM==\"scsi_tape\", ENV{ID_SERIAL}==\"350223344ff000300\", NAME=\"nst2\"\n"
  },
  {
    "path": "scripts/Makefile",
    "content": "\nCURDIR = \"../\"\ninclude ../config.mk\n\nRCFILE = update_device.conf\n\n$(RCFILE): $(RCFILE).in\n\tsed -e s'/@CONF_PATH@/$(CONFIG_PATH)/' $< > $@\n\n.PHONY: rcfile\nrcfile: $(RCFILE)\n\n\n.PHONY: install\ninstall:\n\tinstall -m 700 $(RCFILE) $(DESTDIR)$(PREFIX)/bin/\n\n.PHONY: uninstall\nuninstall:\n\t$(RM)  $(DESTDIR)$(PREFIX)/bin/$(RCFILE)\n\n# ========== Cleaning ==========\n\n.PHONY: clean\nclean:\n\trm -f $(RCFILE)\n\n.PHONY: distclean\ndistclean:\n\trm -f $(RCFILE)\n"
  },
  {
    "path": "scripts/NetBackup/drive_stats.pl",
    "content": "#!/usr/bin/perl -w\n#\n# To be called from NetBackup volmgr/bin/drive_unmount_notify\n# Parses output of \"scsi_command -log_dump\"\n#\n# To collect hard & soft errors from drive(s) along with informaiton\n# about bytes sent/received by initiator & bytes written/read to/from media\n#\n# Released under GPL2 license\n\n##############################################################################\n## Modules\n###############################################################################\n\nuse strict;\nuse POSIX qw(locale_h);\n\n#############################################################################\n## Variables\n#############################################################################\nmy $locale = setlocale(LC_CTYPE);\nmy $line;\nmy $tape_usage = 0;\nmy $read_errors = 0;\nmy $write_errors = 0;\nmy $last_drive = 0;\nmy $last_drive_value = 0;\n\nmy $write_bytes_initiator;\nmy $write_bytes_media;\nmy $read_bytes_initiator;\nmy $read_bytes_media;\n\nmy $total_corrective_read_errors;\nmy $total_read_retries;\n\nmy $total_corrective_write_errors;\nmy $total_write_retries;\n\nprint \"\\n  ===============\\n\";\nwhile($line = <>) {\n\t$line =~ s/^M//g;       # Strip any cr/lf to lf\n\tchomp($line);\n# Print header information\n\tif ($line =~ /^Inquiry/) {\n\t\tprint $line . \"\\n\";\n\t}\n\tif ($line =~ /path/) {\n\t\tprint $line . \"\\n\";\n\t}\n\tif ($line =~ /Serial_Number/) {\n\t\tprint $line . \"\\n\\n\";\n\t}\n\n# Search for Write Error log page (0x02)\n\tif ($line =~ /^\\*\\*\\*Write\\s+Error\\s+Log\\s+Page/) {\n\t\t$tape_usage = 0;\n\t\t$write_errors = 1;\n\t\t$read_errors = 0;\n\t}\n# Search for Read Error log page (0x03)\n\tif ($line =~ /^\\*\\*\\*Read\\s+Error\\s+Log\\s+Page/) {\n\t\t$tape_usage = 0;\n\t\t$write_errors = 0;\n\t\t$read_errors = 1;\n\t}\n# Search for Tape Usage log page (0x0C)\n\tif ($line =~ /^\\*\\*\\*Log\\s+page\\s+\\((.*)\\)/) {\n\t\tif ($1 =~ /0x0c/) { # Found Tape Usage log page\n\t\t\t$tape_usage = 1;\n\t\t\t$write_errors = 0;\n\t\t\t$read_errors = 0;\n\t\t} else { # Not a log page we're interested in - reset all\n\t\t\t$tape_usage = 0;\n\t\t\t$write_errors = 0;\n\t\t\t$read_errors = 0;\n\t\t}\n\t}\n\t# last loop matched key.. This time around is the value\n\tif ($last_drive) {\n\t\t$last_drive_value = 1;\n\t}\n\tif ($line =~ /attribute\\s0x020[abcd]/) { # Key match\n\t\t$last_drive = 1;\n\t\t$last_drive_value = 0;\n\t}\n\n\tif ($tape_usage) {\n\t\tif ($line =~ /parameter\\s+code:\\s+0x0000,\\s+value:\\s+(.*)/) {\n\t\t\t$write_bytes_initiator = hex(\"$1\");\n\t\t\tprint \"Bytes written by initiator    : $write_bytes_initiator\\n\";\n\t\t}\n\t\tif ($line =~ /parameter\\s+code:\\s+0x0001,\\s+value:\\s+(.*)/) {\n\t\t\t$write_bytes_media = hex(\"$1\");\n\t\t\tprint \"Bytes written to media        : $write_bytes_media\\n\";\n\t\t}\n\t\tif ($line =~ /parameter\\s+code:\\s+0x0002,\\s+value:\\s+(.*)/) {\n\t\t\t$read_bytes_media = hex(\"$1\");\n\t\t\tprint \"Bytes read from media         : $read_bytes_media\\n\";\n\t\t}\n\t\tif ($line =~ /parameter\\s+code:\\s+0x0003,\\s+value:\\s+(.*)/) {\n\t\t\t$read_bytes_initiator = hex(\"$1\");\n\t\t\tprint \"Bytes read by initiator       : $read_bytes_initiator\\n\";\n\t\t}\n\t}\n\tif ($read_errors) {\n\t\tif ($line =~ /parameter\\s+code:\\s+0x0003,\\s+value:\\s+(.*)/) {\n\t\t\t$total_corrective_read_errors = hex(\"$1\");\n\t\t\tprint \"Total Corrective read errors  : $total_corrective_read_errors\\n\";\n\t\t}\n\t\tif ($line =~ /parameter\\s+code:\\s+0x0004,\\s+value:\\s+(.*)/) {\n\t\t\t$total_read_retries = hex(\"$1\");\n\t\t\tprint \"Total read retries            : $total_read_retries\\n\";\n\t\t}\n\t}\n\tif ($write_errors) {\n\t\tif ($line =~ /parameter\\s+code:\\s+0x0003,\\s+value:\\s+(.*)/) {\n\t\t\t$total_corrective_write_errors = hex(\"$1\");\n\t\t\tprint \"Total Corrective write errors : $total_corrective_write_errors\\n\";\n\t\t}\n\t\tif ($line =~ /parameter\\s+code:\\s+0x0004,\\s+value:\\s+(.*)/) {\n\t\t\t$total_write_retries = hex(\"$1\");\n\t\t\tprint \"Total write retries           : $total_write_retries\\n\";\n\t\t}\n\t}\n\tif ($last_drive_value) {\n\t\tprint \"Media previously mounted in  : $line\\n\";\n\t\t$last_drive_value = 0;\n\t\t$last_drive = 0;\n\t}\n}\n\n"
  },
  {
    "path": "scripts/NetBackup/vlt_endeject_notify.pl",
    "content": "#!/usr/bin/perl\n# vlt_endeject_notify\n#\n# This script is called after the vault job completes the eject processing for\n# the media to be vaulted.\n#\n# This script will empty the MAP after a vault eject and insert any tapes\n# \"returning\" from the vault into\n#\n# Netbackup provides 4 parameters to the script when executed from\n# a vault profile:\n#  1 = $robot_number     - robot number\n#  2 = $vault_name       - logical vault name\n#  3 = $vault_profile    - profile name\n#  4 = $vault_session_id - vault session id\n\n# This script:\n#       must be executable by the root user\n#       must exit with 0 upon successful completion\n#       must exit with a non zero error code upon failure\n#\n# CAUTION:  writing anything to stdout or stderr will cause problems in the\n#           calling program.\n#\n# This script closes STDOUT and STDERR and opens them as a pipe to the\n# mail command.\n# Any errors encountered will be in the output that is emailed.\nuse strict;\nuse warnings;\n\nmy ($robot_number, $vault_name, $vault_profile, $vault_session_id) = @ARGV;\n\nmy $mail_to = join \",\", qw(\n  admin1@example.com\n  admin2@example.com\n);\n\nmy $vtlcmd_binary      = \"/usr/bin/vtlcmd\";\nmy $vmquery_binary     = \"/usr/openv/volmgr/bin/vmquery\";\nmy $vmupdate_binary    = \"/usr/openv/volmgr/bin/vmupdate\";\nmy $robot_type         = \"tld\"; # Netbackup robot type\nmy $mhvtl_robot_number = 50;\nmy $mail_subject       = \"Vault Eject for $vault_name\";\nmy $mail_binary        = find_mail_binary();\nmy $scratch_pool       = \"Scratch\";\n\n# Open STDOUT and STDERR as pipes to the mail command only if not running in an\n# interactive terminal\nif (not -t STDIN and not -t STDOUT) {\n  close(STDOUT);\n  close(STDERR);\n  open(STDOUT, \"|-\", qq{$mail_binary -s \"$mail_subject\" \"$mail_to\"} );\n  open(STDERR, \">&\", \"STDOUT\");\n}\n\nlist_map();\nopen_map();\nempty_map();\ninsert_tapes();\nclose_map();\ninventory_robot();\n\nsub empty_map {\n  print \"Emptying MAP: \";\n  system(\"$vtlcmd_binary $mhvtl_robot_number empty map\");\n  if ($?) {\n    die \"Error emptying MAP: $!\";\n  }\n}\n\nsub list_map {\n  print \"Current MAP \";\n  system(\"$vtlcmd_binary $mhvtl_robot_number list map\");\n  if ($?) {\n    die \"Error listing contents of MAP: $@\";\n  }\n}\n\nsub open_map {\n  print \"Opening MAP: \";\n  system(\"$vtlcmd_binary $mhvtl_robot_number open map\");\n  if ($?) {\n    die \"Error opening MAP: $!\";\n  }\n}\n\nsub close_map {\n  print \"Closing MAP: \";\n  system(\"$vtlcmd_binary $mhvtl_robot_number close map\");\n  if ($?) {\n    die \"Error closing MAP: $!\";\n  }\n}\n\nsub inventory_robot {\n  print \"Inventorying robot:\\n\";\n  system(\"$vmupdate_binary -rt $robot_type -rn $robot_number -full -empty_map -use_barcode_rules\");\n  if ($?) {\n    die \"Error inventorying robot: $!\";\n  }\n}\n\nsub insert_tapes {\n  # Get all tapes that are \"outside\" the library and have been returned to the\n  # scratch volume pool\n  my @returned_tapes = \n    map {\n      (split /\\s+/, $_)[3]\n    }\n    grep {\n     # This regex filters all lines that don't have the 12th field (Volume Pool)\n     # as the Scratch Volume Pool\n      /^(?:[^\\s]+\\s+){11}$scratch_pool/\n    } `$vmquery_binary -rt NONE -W`;\n\n  if ($?) {\n    die \"Error running vmquery: $!\";\n  }\n\n  foreach my $tape_to_insert (@returned_tapes) {\n    print \"Loading Tape $tape_to_insert into MAP: \";\n    system(\"$vtlcmd_binary $mhvtl_robot_number load map $tape_to_insert\");\n    if ($?) {\n      die \"Error inserting tape into MAP: $!\";\n    }\n  }\n}\n\n# Taken from the sample netbackup vlt_endeject_notify script\nsub find_mail_binary {\n  foreach my $mail_command ( qw( mailx Mail mail ) ) {\n    foreach my $mail_dir ( qw( /usr/bin /usr/ucb /usr/sbin /bin /sbin ) ) {\n      return \"$mail_dir/$mail_command\" if -e \"$mail_dir/$mail_command\";\n    }\n  }\n\n  die \"No mail binary found!\";\n}\n"
  },
  {
    "path": "scripts/build-persistent-tape-rules.sh",
    "content": "#!/bin/bash\n\n# To 'view' what are valid fields we can use - Pick a tape drive you are interested in. using /dev/st0 here.\n\n#  # udevadm info --name=/dev/st0 --query=all\n#  P: /devices/pseudo_9/adapter0/host4/target4:0:1/4:0:1:0/scsi_tape/st0\n#  N: st0\n#  S: tape/by-id/scsi-350223344ab000100\n#  E: DEVLINKS=/dev/tape/by-id/scsi-350223344ab000100\n#  E: DEVNAME=/dev/st0\n#  E: DEVPATH=/devices/pseudo_9/adapter0/host4/target4:0:1/4:0:1:0/scsi_tape/st0\n#  E: ID_BUS=scsi\n#  E: ID_MODEL=ULT3580-TD5\n#  E: ID_MODEL_ENC=ULT3580-TD5\\x20\\x20\\x20\\x20\\x20\n#  E: ID_REVISION=0105\n#  E: ID_SCSI=1\n#  E: ID_SCSI_SERIAL=XYZZY_A1\n#  E: ID_SERIAL=350223344ab000100\n#  E: ID_SERIAL_SHORT=50223344ab000100\n#  E: ID_TYPE=tape\n#  E: ID_VENDOR=IBM\n#  E: ID_VENDOR_ENC=IBM\\x20\\x20\\x20\\x20\\x20\n#  E: ID_WWN=0x50223344ab000100\n#  E: ID_WWN_WITH_EXTENSION=0x50223344ab000100\n#  E: MAJOR=9\n#  E: MINOR=0\n#  E: SUBSYSTEM=scsi_tape\n#  E: USEC_INITIALIZED=421748\n#  E: nodmraid=1\n#\n# Anything beginning with 'E' are environmental and can be used by/for 'ENV{}'\n\nfor SN in `grep ^Drive -A6 /etc/mhvtl/device.conf | awk '/NAA:/ {print $2}' | sed -e \"s/://g\" -e \"s/^[13]0/50/g\"`\ndo\n\techo \"ACTION==\\\"add|change\\\", KERNEL==\\\"nst*\\\", ENV{SUBSYSTEM}==\\\"scsi_tape\\\", ENV{ID_SERIAL_SHORT}==\\\"$SN\\\", SYMLINK+=\\\"tape/by-path/%E{ID_VENDOR}-%E{ID_MODEL}-%E{ID_SCSI_SERIAL}-nst\\\", MODE=\\\"0666\\\"\"\ndone\n"
  },
  {
    "path": "scripts/centos_configure.sh",
    "content": "#!/bin/sh\n\n###  Install script for auto install mhvtl on CentOS Linux 6.2 i386/x86_64\n###  Version: 1.0.0\n###  made by patrick ru\n###  mail: patrick.ru@hotmail.com\n###  Date: 2012.Mar.18\n\n# prepair : pre-install centos linux 6.2 with minimal installation.\n\n# update the system\nyum update -y\n\n# close the selinux and the firewall\nchkconfig iptables off\nservice iptables stop\nsed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config\n/usr/sbin/setenforce 0\n\n# install Git\nyum install -y git\n\n# install supported Rpms\nyum install -y mc ntp gcc gcc-c++ make kernel-devel zlib-devel sg3_utils lsscsi mt-st mtx lzo lzo-devel perl-Config-General\n\n# Create required directories\nmkdir -p /opt/mhvtl\nmkdir -p /etc/mhvtl\n\n# install mhvtl\nmkdir -p /usr/src/mhvtl\ncd /usr/src/mhvtl\ngit init\ngit pull http://github.com/markh794/mhvtl.git\nmake distclean\ncd kernel/\nmake && make install\ncd ..\nmake && make install\nsystemctl enable mhvtl\nsystemctl start mhvtl\n\n# install tgt\nmkdir /etc/tgt\nmkdir /usr/src/tgt\ncd /usr/src/tgt\ngit init\ngit pull http://github.com/fujita/tgt.git\nmake && make install\n/usr/sbin/tgtd -d 1\n\n# install mhvtl-gui\nyum install -y httpd php sudo sysstat\ncp /etc/sudoers /etc/sudoers.old\nsed -i '/Defaults    requiretty/s/^/#/' /etc/sudoers\necho \"apache ALL=(ALL) NOPASSWD: ALL\" >> /etc/sudoers\nchkconfig httpd on\nmkdir /var/www/html/mhvtl\ncd /var/www/html/mhvtl\ngit init\ngit pull http://github.com/niadev67/mhvtl-gui.git\nchown -R apache:apache ./\nservice httpd start\ntouch /var/www/html/mhvtl/ENABLE_TGTD_SCSI_TARGET\nsh scripts/auto.iscsi.config.stgt.sh\n\necho installation has finished! please use mhvtl-gui to install and config tgtd after config the mhvtl for running!\n"
  },
  {
    "path": "scripts/checkarch.sh",
    "content": "#!/bin/sh\narch=`gcc -dumpmachine`\n\ncase $arch in\n`echo $arch | grep x86_64`)\n\techo -m64\n\t;;\n`echo $arch | grep \"i[3-6]86\"`)\n\techo -m32\n\t;;\n*)\n\techo '\n\tFailed to parse your architecture.\n\tPlease run\n\n\t$ make check32\n\n\tor\n\n\t$ make check64\n\n\tmanually.\n\t'\n\texit 1\n;;\nesac\n"
  },
  {
    "path": "scripts/checkpatch.pl",
    "content": "#!/usr/bin/perl -w\n# (c) 2001, Dave Jones. (the file handling bit)\n# (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit)\n# (c) 2007,2008, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite)\n# (c) 2008-2010 Andy Whitcroft <apw@canonical.com>\n# Licensed under the terms of the GNU GPL License version 2\n\nuse strict;\n\nmy $P = $0;\n$P =~ s@.*/@@g;\n\nmy $V = '0.31';\n\nuse Getopt::Long qw(:config no_auto_abbrev);\n\nmy $quiet = 0;\nmy $tree = 0;\nmy $chk_signoff = 1;\nmy $chk_patch = 1;\nmy $tst_only;\nmy $emacs = 0;\nmy $terse = 0;\nmy $file = 0;\nmy $check = 0;\nmy $summary = 1;\nmy $mailback = 0;\nmy $summary_file = 0;\nmy $root;\nmy %debug;\nmy $help = 0;\n\nsub help {\n\tmy ($exitcode) = @_;\n\n\tprint << \"EOM\";\nUsage: $P [OPTION]... [FILE]...\nVersion: $V\n\nOptions:\n  -q, --quiet                quiet\n  --no-tree                  run without a kernel tree\n  --no-signoff               do not check for 'Signed-off-by' line\n  --patch                    treat FILE as patchfile (default)\n  --emacs                    emacs compile window format\n  --terse                    one line per report\n  -f, --file                 treat FILE as regular source file\n  --subjective, --strict     enable more subjective tests\n  --root=PATH                PATH to the kernel tree root\n  --no-summary               suppress the per-file summary\n  --mailback                 only produce a report in case of warnings/errors\n  --summary-file             include the filename in summary\n  --debug KEY=[0|1]          turn on/off debugging of KEY, where KEY is one of\n                             'values', 'possible', 'type', and 'attr' (default\n                             is all off)\n  --test-only=WORD           report only warnings/errors containing WORD\n                             literally\n  -h, --help, --version      display this help and exit\n\nWhen FILE is - read standard input.\nEOM\n\n\texit($exitcode);\n}\n\nGetOptions(\n\t'q|quiet+'\t=> \\$quiet,\n\t'tree!'\t\t=> \\$tree,\n\t'signoff!'\t=> \\$chk_signoff,\n\t'patch!'\t=> \\$chk_patch,\n\t'emacs!'\t=> \\$emacs,\n\t'terse!'\t=> \\$terse,\n\t'f|file!'\t=> \\$file,\n\t'subjective!'\t=> \\$check,\n\t'strict!'\t=> \\$check,\n\t'root=s'\t=> \\$root,\n\t'summary!'\t=> \\$summary,\n\t'mailback!'\t=> \\$mailback,\n\t'summary-file!'\t=> \\$summary_file,\n\n\t'debug=s'\t=> \\%debug,\n\t'test-only=s'\t=> \\$tst_only,\n\t'h|help'\t=> \\$help,\n\t'version'\t=> \\$help\n) or help(1);\n\nhelp(0) if ($help);\n\nmy $exit = 0;\n\nif ($#ARGV < 0) {\n\tprint \"$P: no input files\\n\";\n\texit(1);\n}\n\nmy $dbg_values = 0;\nmy $dbg_possible = 0;\nmy $dbg_type = 0;\nmy $dbg_attr = 0;\nfor my $key (keys %debug) {\n\t## no critic\n\teval \"\\${dbg_$key} = '$debug{$key}';\";\n\tdie \"$@\" if ($@);\n}\n\nmy $rpt_cleaners = 0;\n\nif ($terse) {\n\t$emacs = 1;\n\t$quiet++;\n}\n\nif ($tree) {\n\tif (defined $root) {\n\t\tif (!top_of_kernel_tree($root)) {\n\t\t\tdie \"$P: $root: --root does not point at a valid tree\\n\";\n\t\t}\n\t} else {\n\t\tif (top_of_kernel_tree('.')) {\n\t\t\t$root = '.';\n\t\t} elsif ($0 =~ m@(.*)/scripts/[^/]*$@ &&\n\t\t\t\t\t\ttop_of_kernel_tree($1)) {\n\t\t\t$root = $1;\n\t\t}\n\t}\n\n\tif (!defined $root) {\n\t\tprint \"Must be run from the top-level dir. of a kernel tree\\n\";\n\t\texit(2);\n\t}\n}\n\nmy $emitted_corrupt = 0;\n\nour $Ident\t= qr{\n\t\t\t[A-Za-z_][A-Za-z\\d_]*\n\t\t\t(?:\\s*\\#\\#\\s*[A-Za-z_][A-Za-z\\d_]*)*\n\t\t}x;\nour $Storage\t= qr{extern|static|asmlinkage};\nour $Sparse\t= qr{\n\t\t\t__user|\n\t\t\t__kernel|\n\t\t\t__force|\n\t\t\t__iomem|\n\t\t\t__must_check|\n\t\t\t__init_refok|\n\t\t\t__kprobes|\n\t\t\t__ref\n\t\t}x;\n\n# Notes to $Attribute:\n# We need \\b after 'init' otherwise 'initconst' will cause a false positive in a check\nour $Attribute\t= qr{\n\t\t\tconst|\n\t\t\t__percpu|\n\t\t\t__nocast|\n\t\t\t__safe|\n\t\t\t__bitwise__|\n\t\t\t__packed__|\n\t\t\t__packed2__|\n\t\t\t__naked|\n\t\t\t__maybe_unused|\n\t\t\t__always_unused|\n\t\t\t__noreturn|\n\t\t\t__used|\n\t\t\t__cold|\n\t\t\t__noclone|\n\t\t\t__deprecated|\n\t\t\t__read_mostly|\n\t\t\t__kprobes|\n\t\t\t__(?:mem|cpu|dev|)(?:initdata|initconst|init\\b)|\n\t\t\t____cacheline_aligned|\n\t\t\t____cacheline_aligned_in_smp|\n\t\t\t____cacheline_internodealigned_in_smp|\n\t\t\t__weak\n\t\t  }x;\nour $Modifier;\nour $Inline\t= qr{inline|__always_inline|noinline};\nour $Member\t= qr{->$Ident|\\.$Ident|\\[[^]]*\\]};\nour $Lval\t= qr{$Ident(?:$Member)*};\n\nour $Constant\t= qr{(?:[0-9]+|0x[0-9a-fA-F]+)[UL]*};\nour $Assignment\t= qr{(?:\\*\\=|/=|%=|\\+=|-=|<<=|>>=|&=|\\^=|\\|=|=)};\nour $Compare    = qr{<=|>=|==|!=|<|>};\nour $Operators\t= qr{\n\t\t\t<=|>=|==|!=|\n\t\t\t=>|->|<<|>>|<|>|!|~|\n\t\t\t&&|\\|\\||,|\\^|\\+\\+|--|&|\\||\\+|-|\\*|\\/|%\n\t\t  }x;\n\nour $NonptrType;\nour $Type;\nour $Declare;\n\nour $UTF8\t= qr {\n\t[\\x09\\x0A\\x0D\\x20-\\x7E]              # ASCII\n\t| [\\xC2-\\xDF][\\x80-\\xBF]             # non-overlong 2-byte\n\t|  \\xE0[\\xA0-\\xBF][\\x80-\\xBF]        # excluding overlongs\n\t| [\\xE1-\\xEC\\xEE\\xEF][\\x80-\\xBF]{2}  # straight 3-byte\n\t|  \\xED[\\x80-\\x9F][\\x80-\\xBF]        # excluding surrogates\n\t|  \\xF0[\\x90-\\xBF][\\x80-\\xBF]{2}     # planes 1-3\n\t| [\\xF1-\\xF3][\\x80-\\xBF]{3}          # planes 4-15\n\t|  \\xF4[\\x80-\\x8F][\\x80-\\xBF]{2}     # plane 16\n}x;\n\nour $typeTypedefs = qr{(?x:\n\t(?:__)?(?:u|s|be|le)(?:8|16|32|64)|\n\tatomic_t\n)};\n\nour $logFunctions = qr{(?x:\n\tprintk|\n\t[a-z]+_(emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)|\n\tWARN|\n\tpanic|\n\tMODULE_[A-Z_]+\n)};\n\nour @typeList = (\n\tqr{void},\n\tqr{(?:unsigned\\s+)?char},\n\tqr{(?:unsigned\\s+)?short},\n\tqr{(?:unsigned\\s+)?int},\n\tqr{(?:unsigned\\s+)?long},\n\tqr{(?:unsigned\\s+)?long\\s+int},\n\tqr{(?:unsigned\\s+)?long\\s+long},\n\tqr{(?:unsigned\\s+)?long\\s+long\\s+int},\n\tqr{unsigned},\n\tqr{float},\n\tqr{double},\n\tqr{bool},\n\tqr{struct\\s+$Ident},\n\tqr{union\\s+$Ident},\n\tqr{enum\\s+$Ident},\n\tqr{${Ident}_t},\n\tqr{${Ident}_handler},\n\tqr{${Ident}_handler_fn},\n);\nour @modifierList = (\n\tqr{fastcall},\n);\n\nour $allowed_asm_includes = qr{(?x:\n\tirq|\n\tmemory\n)};\n# memory.h: ARM has a custom one\n\nsub build_types {\n\tmy $mods = \"(?x:  \\n\" . join(\"|\\n  \", @modifierList) . \"\\n)\";\n\tmy $all = \"(?x:  \\n\" . join(\"|\\n  \", @typeList) . \"\\n)\";\n\t$Modifier\t= qr{(?:$Attribute|$Sparse|$mods)};\n\t$NonptrType\t= qr{\n\t\t\t(?:$Modifier\\s+|const\\s+)*\n\t\t\t(?:\n\t\t\t\t(?:typeof|__typeof__)\\s*\\(\\s*\\**\\s*$Ident\\s*\\)|\n\t\t\t\t(?:$typeTypedefs\\b)|\n\t\t\t\t(?:${all}\\b)\n\t\t\t)\n\t\t\t(?:\\s+$Modifier|\\s+const)*\n\t\t  }x;\n\t$Type\t= qr{\n\t\t\t$NonptrType\n\t\t\t(?:[\\s\\*]+\\s*const|[\\s\\*]+|(?:\\s*\\[\\s*\\])+)?\n\t\t\t(?:\\s+$Inline|\\s+$Modifier)*\n\t\t  }x;\n\t$Declare\t= qr{(?:$Storage\\s+)?$Type};\n}\nbuild_types();\n\n$chk_signoff = 0 if ($file);\n\nmy @dep_includes = ();\nmy @dep_functions = ();\nmy $removal = \"Documentation/feature-removal-schedule.txt\";\nif ($tree && -f \"$root/$removal\") {\n\topen(my $REMOVE, '<', \"$root/$removal\") ||\n\t\t\t\tdie \"$P: $removal: open failed - $!\\n\";\n\twhile (<$REMOVE>) {\n\t\tif (/^Check:\\s+(.*\\S)/) {\n\t\t\tfor my $entry (split(/[, ]+/, $1)) {\n\t\t\t\tif ($entry =~ m@include/(.*)@) {\n\t\t\t\t\tpush(@dep_includes, $1);\n\n\t\t\t\t} elsif ($entry !~ m@/@) {\n\t\t\t\t\tpush(@dep_functions, $entry);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tclose($REMOVE);\n}\n\nmy @rawlines = ();\nmy @lines = ();\nmy $vname;\nfor my $filename (@ARGV) {\n\tmy $FILE;\n\tif ($file) {\n\t\topen($FILE, '-|', \"diff -u /dev/null $filename\") ||\n\t\t\tdie \"$P: $filename: diff failed - $!\\n\";\n\t} elsif ($filename eq '-') {\n\t\topen($FILE, '<&STDIN');\n\t} else {\n\t\topen($FILE, '<', \"$filename\") ||\n\t\t\tdie \"$P: $filename: open failed - $!\\n\";\n\t}\n\tif ($filename eq '-') {\n\t\t$vname = 'Your patch';\n\t} else {\n\t\t$vname = $filename;\n\t}\n\twhile (<$FILE>) {\n\t\tchomp;\n\t\tpush(@rawlines, $_);\n\t}\n\tclose($FILE);\n\tif (!process($filename)) {\n\t\t$exit = 1;\n\t}\n\t@rawlines = ();\n\t@lines = ();\n}\n\nexit($exit);\n\nsub top_of_kernel_tree {\n\tmy ($root) = @_;\n\n\tmy @tree_check = (\n\t\t\"COPYING\", \"CREDITS\", \"Kbuild\", \"MAINTAINERS\", \"Makefile\",\n\t\t\"README\", \"Documentation\", \"arch\", \"include\", \"drivers\",\n\t\t\"fs\", \"init\", \"ipc\", \"kernel\", \"lib\", \"scripts\",\n\t);\n\n\tforeach my $check (@tree_check) {\n\t\tif (! -e $root . '/' . $check) {\n\t\t\treturn 0;\n\t\t}\n\t}\n\treturn 1;\n}\n\nsub expand_tabs {\n\tmy ($str) = @_;\n\n\tmy $res = '';\n\tmy $n = 0;\n\tfor my $c (split(//, $str)) {\n\t\tif ($c eq \"\\t\") {\n\t\t\t$res .= ' ';\n\t\t\t$n++;\n\t\t\tfor (; ($n % 8) != 0; $n++) {\n\t\t\t\t$res .= ' ';\n\t\t\t}\n\t\t\tnext;\n\t\t}\n\t\t$res .= $c;\n\t\t$n++;\n\t}\n\n\treturn $res;\n}\nsub copy_spacing {\n\t(my $res = shift) =~ tr/\\t/ /c;\n\treturn $res;\n}\n\nsub line_stats {\n\tmy ($line) = @_;\n\n\t# Drop the diff line leader and expand tabs\n\t$line =~ s/^.//;\n\t$line = expand_tabs($line);\n\n\t# Pick the indent from the front of the line.\n\tmy ($white) = ($line =~ /^(\\s*)/);\n\n\treturn (length($line), length($white));\n}\n\nmy $sanitise_quote = '';\n\nsub sanitise_line_reset {\n\tmy ($in_comment) = @_;\n\n\tif ($in_comment) {\n\t\t$sanitise_quote = '*/';\n\t} else {\n\t\t$sanitise_quote = '';\n\t}\n}\nsub sanitise_line {\n\tmy ($line) = @_;\n\n\tmy $res = '';\n\tmy $l = '';\n\n\tmy $qlen = 0;\n\tmy $off = 0;\n\tmy $c;\n\n\t# Always copy over the diff marker.\n\t$res = substr($line, 0, 1);\n\n\tfor ($off = 1; $off < length($line); $off++) {\n\t\t$c = substr($line, $off, 1);\n\n\t\t# Comments we are wacking completly including the begin\n\t\t# and end, all to $;.\n\t\tif ($sanitise_quote eq '' && substr($line, $off, 2) eq '/*') {\n\t\t\t$sanitise_quote = '*/';\n\n\t\t\tsubstr($res, $off, 2, \"$;$;\");\n\t\t\t$off++;\n\t\t\tnext;\n\t\t}\n\t\tif ($sanitise_quote eq '*/' && substr($line, $off, 2) eq '*/') {\n\t\t\t$sanitise_quote = '';\n\t\t\tsubstr($res, $off, 2, \"$;$;\");\n\t\t\t$off++;\n\t\t\tnext;\n\t\t}\n\t\tif ($sanitise_quote eq '' && substr($line, $off, 2) eq '//') {\n\t\t\t$sanitise_quote = '//';\n\n\t\t\tsubstr($res, $off, 2, $sanitise_quote);\n\t\t\t$off++;\n\t\t\tnext;\n\t\t}\n\n\t\t# A \\ in a string means ignore the next character.\n\t\tif (($sanitise_quote eq \"'\" || $sanitise_quote eq '\"') &&\n\t\t    $c eq \"\\\\\") {\n\t\t\tsubstr($res, $off, 2, 'XX');\n\t\t\t$off++;\n\t\t\tnext;\n\t\t}\n\t\t# Regular quotes.\n\t\tif ($c eq \"'\" || $c eq '\"') {\n\t\t\tif ($sanitise_quote eq '') {\n\t\t\t\t$sanitise_quote = $c;\n\n\t\t\t\tsubstr($res, $off, 1, $c);\n\t\t\t\tnext;\n\t\t\t} elsif ($sanitise_quote eq $c) {\n\t\t\t\t$sanitise_quote = '';\n\t\t\t}\n\t\t}\n\n\t\t#print \"c<$c> SQ<$sanitise_quote>\\n\";\n\t\tif ($off != 0 && $sanitise_quote eq '*/' && $c ne \"\\t\") {\n\t\t\tsubstr($res, $off, 1, $;);\n\t\t} elsif ($off != 0 && $sanitise_quote eq '//' && $c ne \"\\t\") {\n\t\t\tsubstr($res, $off, 1, $;);\n\t\t} elsif ($off != 0 && $sanitise_quote && $c ne \"\\t\") {\n\t\t\tsubstr($res, $off, 1, 'X');\n\t\t} else {\n\t\t\tsubstr($res, $off, 1, $c);\n\t\t}\n\t}\n\n\tif ($sanitise_quote eq '//') {\n\t\t$sanitise_quote = '';\n\t}\n\n\t# The pathname on a #include may be surrounded by '<' and '>'.\n\tif ($res =~ /^.\\s*\\#\\s*include\\s+\\<(.*)\\>/) {\n\t\tmy $clean = 'X' x length($1);\n\t\t$res =~ s@\\<.*\\>@<$clean>@;\n\n\t# The whole of a #error is a string.\n\t} elsif ($res =~ /^.\\s*\\#\\s*(?:error|warning)\\s+(.*)\\b/) {\n\t\tmy $clean = 'X' x length($1);\n\t\t$res =~ s@(\\#\\s*(?:error|warning)\\s+).*@$1$clean@;\n\t}\n\n\treturn $res;\n}\n\nsub ctx_statement_block {\n\tmy ($linenr, $remain, $off) = @_;\n\tmy $line = $linenr - 1;\n\tmy $blk = '';\n\tmy $soff = $off;\n\tmy $coff = $off - 1;\n\tmy $coff_set = 0;\n\n\tmy $loff = 0;\n\n\tmy $type = '';\n\tmy $level = 0;\n\tmy @stack = ();\n\tmy $p;\n\tmy $c;\n\tmy $len = 0;\n\n\tmy $remainder;\n\twhile (1) {\n\t\t@stack = (['', 0]) if ($#stack == -1);\n\n\t\t#warn \"CSB: blk<$blk> remain<$remain>\\n\";\n\t\t# If we are about to drop off the end, pull in more\n\t\t# context.\n\t\tif ($off >= $len) {\n\t\t\tfor (; $remain > 0; $line++) {\n\t\t\t\tlast if (!defined $lines[$line]);\n\t\t\t\tnext if ($lines[$line] =~ /^-/);\n\t\t\t\t$remain--;\n\t\t\t\t$loff = $len;\n\t\t\t\t$blk .= $lines[$line] . \"\\n\";\n\t\t\t\t$len = length($blk);\n\t\t\t\t$line++;\n\t\t\t\tlast;\n\t\t\t}\n\t\t\t# Bail if there is no further context.\n\t\t\t#warn \"CSB: blk<$blk> off<$off> len<$len>\\n\";\n\t\t\tif ($off >= $len) {\n\t\t\t\tlast;\n\t\t\t}\n\t\t}\n\t\t$p = $c;\n\t\t$c = substr($blk, $off, 1);\n\t\t$remainder = substr($blk, $off);\n\n\t\t#warn \"CSB: c<$c> type<$type> level<$level> remainder<$remainder> coff_set<$coff_set>\\n\";\n\n\t\t# Handle nested #if/#else.\n\t\tif ($remainder =~ /^#\\s*(?:ifndef|ifdef|if)\\s/) {\n\t\t\tpush(@stack, [ $type, $level ]);\n\t\t} elsif ($remainder =~ /^#\\s*(?:else|elif)\\b/) {\n\t\t\t($type, $level) = @{$stack[$#stack - 1]};\n\t\t} elsif ($remainder =~ /^#\\s*endif\\b/) {\n\t\t\t($type, $level) = @{pop(@stack)};\n\t\t}\n\n\t\t# Statement ends at the ';' or a close '}' at the\n\t\t# outermost level.\n\t\tif ($level == 0 && $c eq ';') {\n\t\t\tlast;\n\t\t}\n\n\t\t# An else is really a conditional as long as its not else if\n\t\tif ($level == 0 && $coff_set == 0 &&\n\t\t\t\t(!defined($p) || $p =~ /(?:\\s|\\}|\\+)/) &&\n\t\t\t\t$remainder =~ /^(else)(?:\\s|{)/ &&\n\t\t\t\t$remainder !~ /^else\\s+if\\b/) {\n\t\t\t$coff = $off + length($1) - 1;\n\t\t\t$coff_set = 1;\n\t\t\t#warn \"CSB: mark coff<$coff> soff<$soff> 1<$1>\\n\";\n\t\t\t#warn \"[\" . substr($blk, $soff, $coff - $soff + 1) . \"]\\n\";\n\t\t}\n\n\t\tif (($type eq '' || $type eq '(') && $c eq '(') {\n\t\t\t$level++;\n\t\t\t$type = '(';\n\t\t}\n\t\tif ($type eq '(' && $c eq ')') {\n\t\t\t$level--;\n\t\t\t$type = ($level != 0)? '(' : '';\n\n\t\t\tif ($level == 0 && $coff < $soff) {\n\t\t\t\t$coff = $off;\n\t\t\t\t$coff_set = 1;\n\t\t\t\t#warn \"CSB: mark coff<$coff>\\n\";\n\t\t\t}\n\t\t}\n\t\tif (($type eq '' || $type eq '{') && $c eq '{') {\n\t\t\t$level++;\n\t\t\t$type = '{';\n\t\t}\n\t\tif ($type eq '{' && $c eq '}') {\n\t\t\t$level--;\n\t\t\t$type = ($level != 0)? '{' : '';\n\n\t\t\tif ($level == 0) {\n\t\t\t\tif (substr($blk, $off + 1, 1) eq ';') {\n\t\t\t\t\t$off++;\n\t\t\t\t}\n\t\t\t\tlast;\n\t\t\t}\n\t\t}\n\t\t$off++;\n\t}\n\t# We are truly at the end, so shuffle to the next line.\n\tif ($off == $len) {\n\t\t$loff = $len + 1;\n\t\t$line++;\n\t\t$remain--;\n\t}\n\n\tmy $statement = substr($blk, $soff, $off - $soff + 1);\n\tmy $condition = substr($blk, $soff, $coff - $soff + 1);\n\n\t#warn \"STATEMENT<$statement>\\n\";\n\t#warn \"CONDITION<$condition>\\n\";\n\n\t#print \"coff<$coff> soff<$off> loff<$loff>\\n\";\n\n\treturn ($statement, $condition,\n\t\t\t$line, $remain + 1, $off - $loff + 1, $level);\n}\n\nsub statement_lines {\n\tmy ($stmt) = @_;\n\n\t# Strip the diff line prefixes and rip blank lines at start and end.\n\t$stmt =~ s/(^|\\n)./$1/g;\n\t$stmt =~ s/^\\s*//;\n\t$stmt =~ s/\\s*$//;\n\n\tmy @stmt_lines = ($stmt =~ /\\n/g);\n\n\treturn $#stmt_lines + 2;\n}\n\nsub statement_rawlines {\n\tmy ($stmt) = @_;\n\n\tmy @stmt_lines = ($stmt =~ /\\n/g);\n\n\treturn $#stmt_lines + 2;\n}\n\nsub statement_block_size {\n\tmy ($stmt) = @_;\n\n\t$stmt =~ s/(^|\\n)./$1/g;\n\t$stmt =~ s/^\\s*{//;\n\t$stmt =~ s/}\\s*$//;\n\t$stmt =~ s/^\\s*//;\n\t$stmt =~ s/\\s*$//;\n\n\tmy @stmt_lines = ($stmt =~ /\\n/g);\n\tmy @stmt_statements = ($stmt =~ /;/g);\n\n\tmy $stmt_lines = $#stmt_lines + 2;\n\tmy $stmt_statements = $#stmt_statements + 1;\n\n\tif ($stmt_lines > $stmt_statements) {\n\t\treturn $stmt_lines;\n\t} else {\n\t\treturn $stmt_statements;\n\t}\n}\n\nsub ctx_statement_full {\n\tmy ($linenr, $remain, $off) = @_;\n\tmy ($statement, $condition, $level);\n\n\tmy (@chunks);\n\n\t# Grab the first conditional/block pair.\n\t($statement, $condition, $linenr, $remain, $off, $level) =\n\t\t\t\tctx_statement_block($linenr, $remain, $off);\n\t#print \"F: c<$condition> s<$statement> remain<$remain>\\n\";\n\tpush(@chunks, [ $condition, $statement ]);\n\tif (!($remain > 0 && $condition =~ /^\\s*(?:\\n[+-])?\\s*(?:if|else|do)\\b/s)) {\n\t\treturn ($level, $linenr, @chunks);\n\t}\n\n\t# Pull in the following conditional/block pairs and see if they\n\t# could continue the statement.\n\tfor (;;) {\n\t\t($statement, $condition, $linenr, $remain, $off, $level) =\n\t\t\t\tctx_statement_block($linenr, $remain, $off);\n\t\t#print \"C: c<$condition> s<$statement> remain<$remain>\\n\";\n\t\tlast if (!($remain > 0 && $condition =~ /^(?:\\s*\\n[+-])*\\s*(?:else|do)\\b/s));\n\t\t#print \"C: push\\n\";\n\t\tpush(@chunks, [ $condition, $statement ]);\n\t}\n\n\treturn ($level, $linenr, @chunks);\n}\n\nsub ctx_block_get {\n\tmy ($linenr, $remain, $outer, $open, $close, $off) = @_;\n\tmy $line;\n\tmy $start = $linenr - 1;\n\tmy $blk = '';\n\tmy @o;\n\tmy @c;\n\tmy @res = ();\n\n\tmy $level = 0;\n\tmy @stack = ($level);\n\tfor ($line = $start; $remain > 0; $line++) {\n\t\tnext if ($rawlines[$line] =~ /^-/);\n\t\t$remain--;\n\n\t\t$blk .= $rawlines[$line];\n\n\t\t# Handle nested #if/#else.\n\t\tif ($lines[$line] =~ /^.\\s*#\\s*(?:ifndef|ifdef|if)\\s/) {\n\t\t\tpush(@stack, $level);\n\t\t} elsif ($lines[$line] =~ /^.\\s*#\\s*(?:else|elif)\\b/) {\n\t\t\t$level = $stack[$#stack - 1];\n\t\t} elsif ($lines[$line] =~ /^.\\s*#\\s*endif\\b/) {\n\t\t\t$level = pop(@stack);\n\t\t}\n\n\t\tforeach my $c (split(//, $lines[$line])) {\n\t\t\t##print \"C<$c>L<$level><$open$close>O<$off>\\n\";\n\t\t\tif ($off > 0) {\n\t\t\t\t$off--;\n\t\t\t\tnext;\n\t\t\t}\n\n\t\t\tif ($c eq $close && $level > 0) {\n\t\t\t\t$level--;\n\t\t\t\tlast if ($level == 0);\n\t\t\t} elsif ($c eq $open) {\n\t\t\t\t$level++;\n\t\t\t}\n\t\t}\n\n\t\tif (!$outer || $level <= 1) {\n\t\t\tpush(@res, $rawlines[$line]);\n\t\t}\n\n\t\tlast if ($level == 0);\n\t}\n\n\treturn ($level, @res);\n}\nsub ctx_block_outer {\n\tmy ($linenr, $remain) = @_;\n\n\tmy ($level, @r) = ctx_block_get($linenr, $remain, 1, '{', '}', 0);\n\treturn @r;\n}\nsub ctx_block {\n\tmy ($linenr, $remain) = @_;\n\n\tmy ($level, @r) = ctx_block_get($linenr, $remain, 0, '{', '}', 0);\n\treturn @r;\n}\nsub ctx_statement {\n\tmy ($linenr, $remain, $off) = @_;\n\n\tmy ($level, @r) = ctx_block_get($linenr, $remain, 0, '(', ')', $off);\n\treturn @r;\n}\nsub ctx_block_level {\n\tmy ($linenr, $remain) = @_;\n\n\treturn ctx_block_get($linenr, $remain, 0, '{', '}', 0);\n}\nsub ctx_statement_level {\n\tmy ($linenr, $remain, $off) = @_;\n\n\treturn ctx_block_get($linenr, $remain, 0, '(', ')', $off);\n}\n\nsub ctx_locate_comment {\n\tmy ($first_line, $end_line) = @_;\n\n\t# Catch a comment on the end of the line itself.\n\tmy ($current_comment) = ($rawlines[$end_line - 1] =~ m@.*(/\\*.*\\*/)\\s*(?:\\\\\\s*)?$@);\n\treturn $current_comment if (defined $current_comment);\n\n\t# Look through the context and try and figure out if there is a\n\t# comment.\n\tmy $in_comment = 0;\n\t$current_comment = '';\n\tfor (my $linenr = $first_line; $linenr < $end_line; $linenr++) {\n\t\tmy $line = $rawlines[$linenr - 1];\n\t\t#warn \"           $line\\n\";\n\t\tif ($linenr == $first_line and $line =~ m@^.\\s*\\*@) {\n\t\t\t$in_comment = 1;\n\t\t}\n\t\tif ($line =~ m@/\\*@) {\n\t\t\t$in_comment = 1;\n\t\t}\n\t\tif (!$in_comment && $current_comment ne '') {\n\t\t\t$current_comment = '';\n\t\t}\n\t\t$current_comment .= $line . \"\\n\" if ($in_comment);\n\t\tif ($line =~ m@\\*/@) {\n\t\t\t$in_comment = 0;\n\t\t}\n\t}\n\n\tchomp($current_comment);\n\treturn($current_comment);\n}\nsub ctx_has_comment {\n\tmy ($first_line, $end_line) = @_;\n\tmy $cmt = ctx_locate_comment($first_line, $end_line);\n\n\t##print \"LINE: $rawlines[$end_line - 1 ]\\n\";\n\t##print \"CMMT: $cmt\\n\";\n\n\treturn ($cmt ne '');\n}\n\nsub raw_line {\n\tmy ($linenr, $cnt) = @_;\n\n\tmy $offset = $linenr - 1;\n\t$cnt++;\n\n\tmy $line;\n\twhile ($cnt) {\n\t\t$line = $rawlines[$offset++];\n\t\tnext if (defined($line) && $line =~ /^-/);\n\t\t$cnt--;\n\t}\n\n\treturn $line;\n}\n\nsub cat_vet {\n\tmy ($vet) = @_;\n\tmy ($res, $coded);\n\n\t$res = '';\n\twhile ($vet =~ /([^[:cntrl:]]*)([[:cntrl:]]|$)/g) {\n\t\t$res .= $1;\n\t\tif ($2 ne '') {\n\t\t\t$coded = sprintf(\"^%c\", unpack('C', $2) + 64);\n\t\t\t$res .= $coded;\n\t\t}\n\t}\n\t$res =~ s/$/\\$/;\n\n\treturn $res;\n}\n\nmy $av_preprocessor = 0;\nmy $av_pending;\nmy @av_paren_type;\nmy $av_pend_colon;\n\nsub annotate_reset {\n\t$av_preprocessor = 0;\n\t$av_pending = '_';\n\t@av_paren_type = ('E');\n\t$av_pend_colon = 'O';\n}\n\nsub annotate_values {\n\tmy ($stream, $type) = @_;\n\n\tmy $res;\n\tmy $var = '_' x length($stream);\n\tmy $cur = $stream;\n\n\tprint \"$stream\\n\" if ($dbg_values > 1);\n\n\twhile (length($cur)) {\n\t\t@av_paren_type = ('E') if ($#av_paren_type < 0);\n\t\tprint \" <\" . join('', @av_paren_type) .\n\t\t\t\t\"> <$type> <$av_pending>\" if ($dbg_values > 1);\n\t\tif ($cur =~ /^(\\s+)/o) {\n\t\t\tprint \"WS($1)\\n\" if ($dbg_values > 1);\n\t\t\tif ($1 =~ /\\n/ && $av_preprocessor) {\n\t\t\t\t$type = pop(@av_paren_type);\n\t\t\t\t$av_preprocessor = 0;\n\t\t\t}\n\n\t\t} elsif ($cur =~ /^(\\(\\s*$Type\\s*)\\)/ && $av_pending eq '_') {\n\t\t\tprint \"CAST($1)\\n\" if ($dbg_values > 1);\n\t\t\tpush(@av_paren_type, $type);\n\t\t\t$type = 'C';\n\n\t\t} elsif ($cur =~ /^($Type)\\s*(?:$Ident|,|\\)|\\(|\\s*$)/) {\n\t\t\tprint \"DECLARE($1)\\n\" if ($dbg_values > 1);\n\t\t\t$type = 'T';\n\n\t\t} elsif ($cur =~ /^($Modifier)\\s*/) {\n\t\t\tprint \"MODIFIER($1)\\n\" if ($dbg_values > 1);\n\t\t\t$type = 'T';\n\n\t\t} elsif ($cur =~ /^(\\#\\s*define\\s*$Ident)(\\(?)/o) {\n\t\t\tprint \"DEFINE($1,$2)\\n\" if ($dbg_values > 1);\n\t\t\t$av_preprocessor = 1;\n\t\t\tpush(@av_paren_type, $type);\n\t\t\tif ($2 ne '') {\n\t\t\t\t$av_pending = 'N';\n\t\t\t}\n\t\t\t$type = 'E';\n\n\t\t} elsif ($cur =~ /^(\\#\\s*(?:undef\\s*$Ident|include\\b))/o) {\n\t\t\tprint \"UNDEF($1)\\n\" if ($dbg_values > 1);\n\t\t\t$av_preprocessor = 1;\n\t\t\tpush(@av_paren_type, $type);\n\n\t\t} elsif ($cur =~ /^(\\#\\s*(?:ifdef|ifndef|if))/o) {\n\t\t\tprint \"PRE_START($1)\\n\" if ($dbg_values > 1);\n\t\t\t$av_preprocessor = 1;\n\n\t\t\tpush(@av_paren_type, $type);\n\t\t\tpush(@av_paren_type, $type);\n\t\t\t$type = 'E';\n\n\t\t} elsif ($cur =~ /^(\\#\\s*(?:else|elif))/o) {\n\t\t\tprint \"PRE_RESTART($1)\\n\" if ($dbg_values > 1);\n\t\t\t$av_preprocessor = 1;\n\n\t\t\tpush(@av_paren_type, $av_paren_type[$#av_paren_type]);\n\n\t\t\t$type = 'E';\n\n\t\t} elsif ($cur =~ /^(\\#\\s*(?:endif))/o) {\n\t\t\tprint \"PRE_END($1)\\n\" if ($dbg_values > 1);\n\n\t\t\t$av_preprocessor = 1;\n\n\t\t\t# Assume all arms of the conditional end as this\n\t\t\t# one does, and continue as if the #endif was not here.\n\t\t\tpop(@av_paren_type);\n\t\t\tpush(@av_paren_type, $type);\n\t\t\t$type = 'E';\n\n\t\t} elsif ($cur =~ /^(\\\\\\n)/o) {\n\t\t\tprint \"PRECONT($1)\\n\" if ($dbg_values > 1);\n\n\t\t} elsif ($cur =~ /^(__attribute__)\\s*\\(?/o) {\n\t\t\tprint \"ATTR($1)\\n\" if ($dbg_values > 1);\n\t\t\t$av_pending = $type;\n\t\t\t$type = 'N';\n\n\t\t} elsif ($cur =~ /^(sizeof)\\s*(\\()?/o) {\n\t\t\tprint \"SIZEOF($1)\\n\" if ($dbg_values > 1);\n\t\t\tif (defined $2) {\n\t\t\t\t$av_pending = 'V';\n\t\t\t}\n\t\t\t$type = 'N';\n\n\t\t} elsif ($cur =~ /^(if|while|for)\\b/o) {\n\t\t\tprint \"COND($1)\\n\" if ($dbg_values > 1);\n\t\t\t$av_pending = 'E';\n\t\t\t$type = 'N';\n\n\t\t} elsif ($cur =~/^(case)/o) {\n\t\t\tprint \"CASE($1)\\n\" if ($dbg_values > 1);\n\t\t\t$av_pend_colon = 'C';\n\t\t\t$type = 'N';\n\n\t\t} elsif ($cur =~/^(return|else|goto|typeof|__typeof__)\\b/o) {\n\t\t\tprint \"KEYWORD($1)\\n\" if ($dbg_values > 1);\n\t\t\t$type = 'N';\n\n\t\t} elsif ($cur =~ /^(\\()/o) {\n\t\t\tprint \"PAREN('$1')\\n\" if ($dbg_values > 1);\n\t\t\tpush(@av_paren_type, $av_pending);\n\t\t\t$av_pending = '_';\n\t\t\t$type = 'N';\n\n\t\t} elsif ($cur =~ /^(\\))/o) {\n\t\t\tmy $new_type = pop(@av_paren_type);\n\t\t\tif ($new_type ne '_') {\n\t\t\t\t$type = $new_type;\n\t\t\t\tprint \"PAREN('$1') -> $type\\n\"\n\t\t\t\t\t\t\tif ($dbg_values > 1);\n\t\t\t} else {\n\t\t\t\tprint \"PAREN('$1')\\n\" if ($dbg_values > 1);\n\t\t\t}\n\n\t\t} elsif ($cur =~ /^($Ident)\\s*\\(/o) {\n\t\t\tprint \"FUNC($1)\\n\" if ($dbg_values > 1);\n\t\t\t$type = 'V';\n\t\t\t$av_pending = 'V';\n\n\t\t} elsif ($cur =~ /^($Ident\\s*):(?:\\s*\\d+\\s*(,|=|;))?/) {\n\t\t\tif (defined $2 && $type eq 'C' || $type eq 'T') {\n\t\t\t\t$av_pend_colon = 'B';\n\t\t\t} elsif ($type eq 'E') {\n\t\t\t\t$av_pend_colon = 'L';\n\t\t\t}\n\t\t\tprint \"IDENT_COLON($1,$type>$av_pend_colon)\\n\" if ($dbg_values > 1);\n\t\t\t$type = 'V';\n\n\t\t} elsif ($cur =~ /^($Ident|$Constant)/o) {\n\t\t\tprint \"IDENT($1)\\n\" if ($dbg_values > 1);\n\t\t\t$type = 'V';\n\n\t\t} elsif ($cur =~ /^($Assignment)/o) {\n\t\t\tprint \"ASSIGN($1)\\n\" if ($dbg_values > 1);\n\t\t\t$type = 'N';\n\n\t\t} elsif ($cur =~/^(;|{|})/) {\n\t\t\tprint \"END($1)\\n\" if ($dbg_values > 1);\n\t\t\t$type = 'E';\n\t\t\t$av_pend_colon = 'O';\n\n\t\t} elsif ($cur =~/^(,)/) {\n\t\t\tprint \"COMMA($1)\\n\" if ($dbg_values > 1);\n\t\t\t$type = 'C';\n\n\t\t} elsif ($cur =~ /^(\\?)/o) {\n\t\t\tprint \"QUESTION($1)\\n\" if ($dbg_values > 1);\n\t\t\t$type = 'N';\n\n\t\t} elsif ($cur =~ /^(:)/o) {\n\t\t\tprint \"COLON($1,$av_pend_colon)\\n\" if ($dbg_values > 1);\n\n\t\t\tsubstr($var, length($res), 1, $av_pend_colon);\n\t\t\tif ($av_pend_colon eq 'C' || $av_pend_colon eq 'L') {\n\t\t\t\t$type = 'E';\n\t\t\t} else {\n\t\t\t\t$type = 'N';\n\t\t\t}\n\t\t\t$av_pend_colon = 'O';\n\n\t\t} elsif ($cur =~ /^(\\[)/o) {\n\t\t\tprint \"CLOSE($1)\\n\" if ($dbg_values > 1);\n\t\t\t$type = 'N';\n\n\t\t} elsif ($cur =~ /^(-(?![->])|\\+(?!\\+)|\\*|\\&\\&|\\&)/o) {\n\t\t\tmy $variant;\n\n\t\t\tprint \"OPV($1)\\n\" if ($dbg_values > 1);\n\t\t\tif ($type eq 'V') {\n\t\t\t\t$variant = 'B';\n\t\t\t} else {\n\t\t\t\t$variant = 'U';\n\t\t\t}\n\n\t\t\tsubstr($var, length($res), 1, $variant);\n\t\t\t$type = 'N';\n\n\t\t} elsif ($cur =~ /^($Operators)/o) {\n\t\t\tprint \"OP($1)\\n\" if ($dbg_values > 1);\n\t\t\tif ($1 ne '++' && $1 ne '--') {\n\t\t\t\t$type = 'N';\n\t\t\t}\n\n\t\t} elsif ($cur =~ /(^.)/o) {\n\t\t\tprint \"C($1)\\n\" if ($dbg_values > 1);\n\t\t}\n\t\tif (defined $1) {\n\t\t\t$cur = substr($cur, length($1));\n\t\t\t$res .= $type x length($1);\n\t\t}\n\t}\n\n\treturn ($res, $var);\n}\n\nsub possible {\n\tmy ($possible, $line) = @_;\n\tmy $notPermitted = qr{(?:\n\t\t^(?:\n\t\t\t$Modifier|\n\t\t\t$Storage|\n\t\t\t$Type|\n\t\t\tDEFINE_\\S+\n\t\t)$|\n\t\t^(?:\n\t\t\tgoto|\n\t\t\treturn|\n\t\t\tcase|\n\t\t\telse|\n\t\t\tasm|__asm__|\n\t\t\tdo\n\t\t)(?:\\s|$)|\n\t\t^(?:typedef|struct|enum)\\b\n\t    )}x;\n\twarn \"CHECK<$possible> ($line)\\n\" if ($dbg_possible > 2);\n\tif ($possible !~ $notPermitted) {\n\t\t# Check for modifiers.\n\t\t$possible =~ s/\\s*$Storage\\s*//g;\n\t\t$possible =~ s/\\s*$Sparse\\s*//g;\n\t\tif ($possible =~ /^\\s*$/) {\n\n\t\t} elsif ($possible =~ /\\s/) {\n\t\t\t$possible =~ s/\\s*$Type\\s*//g;\n\t\t\tfor my $modifier (split(' ', $possible)) {\n\t\t\t\tif ($modifier !~ $notPermitted) {\n\t\t\t\t\twarn \"MODIFIER: $modifier ($possible) ($line)\\n\" if ($dbg_possible);\n\t\t\t\t\tpush(@modifierList, $modifier);\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else {\n\t\t\twarn \"POSSIBLE: $possible ($line)\\n\" if ($dbg_possible);\n\t\t\tpush(@typeList, $possible);\n\t\t}\n\t\tbuild_types();\n\t} else {\n\t\twarn \"NOTPOSS: $possible ($line)\\n\" if ($dbg_possible > 1);\n\t}\n}\n\nmy $prefix = '';\n\nsub report {\n\tif (defined $tst_only && $_[0] !~ /\\Q$tst_only\\E/) {\n\t\treturn 0;\n\t}\n\tmy $line = $prefix . $_[0];\n\n\t$line = (split('\\n', $line))[0] . \"\\n\" if ($terse);\n\n\tpush(our @report, $line);\n\n\treturn 1;\n}\nsub report_dump {\n\tour @report;\n}\nsub ERROR {\n\tif (report(\"ERROR: $_[0]\\n\")) {\n\t\tour $clean = 0;\n\t\tour $cnt_error++;\n\t}\n}\nsub WARN {\n\tif (report(\"WARNING: $_[0]\\n\")) {\n\t\tour $clean = 0;\n\t\tour $cnt_warn++;\n\t}\n}\nsub CHK {\n\tif ($check && report(\"CHECK: $_[0]\\n\")) {\n\t\tour $clean = 0;\n\t\tour $cnt_chk++;\n\t}\n}\n\nsub check_absolute_file {\n\tmy ($absolute, $herecurr) = @_;\n\tmy $file = $absolute;\n\n\t##print \"absolute<$absolute>\\n\";\n\n\t# See if any suffix of this path is a path within the tree.\n\twhile ($file =~ s@^[^/]*/@@) {\n\t\tif (-f \"$root/$file\") {\n\t\t\t##print \"file<$file>\\n\";\n\t\t\tlast;\n\t\t}\n\t}\n\tif (! -f _)  {\n\t\treturn 0;\n\t}\n\n\t# It is, so see if the prefix is acceptable.\n\tmy $prefix = $absolute;\n\tsubstr($prefix, -length($file)) = '';\n\n\t##print \"prefix<$prefix>\\n\";\n\tif ($prefix ne \".../\") {\n\t\tWARN(\"use relative pathname instead of absolute in changelog text\\n\" . $herecurr);\n\t}\n}\n\nsub process {\n\tmy $filename = shift;\n\n\tmy $linenr=0;\n\tmy $prevline=\"\";\n\tmy $prevrawline=\"\";\n\tmy $stashline=\"\";\n\tmy $stashrawline=\"\";\n\n\tmy $length;\n\tmy $indent;\n\tmy $previndent=0;\n\tmy $stashindent=0;\n\n\tour $clean = 1;\n\tmy $signoff = 0;\n\tmy $is_patch = 0;\n\n\tour @report = ();\n\tour $cnt_lines = 0;\n\tour $cnt_error = 0;\n\tour $cnt_warn = 0;\n\tour $cnt_chk = 0;\n\n\t# Trace the real file/line as we go.\n\tmy $realfile = '';\n\tmy $realline = 0;\n\tmy $realcnt = 0;\n\tmy $here = '';\n\tmy $in_comment = 0;\n\tmy $comment_edge = 0;\n\tmy $first_line = 0;\n\tmy $p1_prefix = '';\n\n\tmy $prev_values = 'E';\n\n\t# suppression flags\n\tmy %suppress_ifbraces;\n\tmy %suppress_whiletrailers;\n\tmy %suppress_export;\n\n\t# Pre-scan the patch sanitizing the lines.\n\t# Pre-scan the patch looking for any __setup documentation.\n\t#\n\tmy @setup_docs = ();\n\tmy $setup_docs = 0;\n\n\tsanitise_line_reset();\n\tmy $line;\n\tforeach my $rawline (@rawlines) {\n\t\t$linenr++;\n\t\t$line = $rawline;\n\n\t\tif ($rawline=~/^\\+\\+\\+\\s+(\\S+)/) {\n\t\t\t$setup_docs = 0;\n\t\t\tif ($1 =~ m@Documentation/kernel-parameters.txt$@) {\n\t\t\t\t$setup_docs = 1;\n\t\t\t}\n\t\t\t#next;\n\t\t}\n\t\tif ($rawline=~/^\\@\\@ -\\d+(?:,\\d+)? \\+(\\d+)(,(\\d+))? \\@\\@/) {\n\t\t\t$realline=$1-1;\n\t\t\tif (defined $2) {\n\t\t\t\t$realcnt=$3+1;\n\t\t\t} else {\n\t\t\t\t$realcnt=1+1;\n\t\t\t}\n\t\t\t$in_comment = 0;\n\n\t\t\t# Guestimate if this is a continuing comment.  Run\n\t\t\t# the context looking for a comment \"edge\".  If this\n\t\t\t# edge is a close comment then we must be in a comment\n\t\t\t# at context start.\n\t\t\tmy $edge;\n\t\t\tmy $cnt = $realcnt;\n\t\t\tfor (my $ln = $linenr + 1; $cnt > 0; $ln++) {\n\t\t\t\tnext if (defined $rawlines[$ln - 1] &&\n\t\t\t\t\t $rawlines[$ln - 1] =~ /^-/);\n\t\t\t\t$cnt--;\n\t\t\t\t#print \"RAW<$rawlines[$ln - 1]>\\n\";\n\t\t\t\tlast if (!defined $rawlines[$ln - 1]);\n\t\t\t\tif ($rawlines[$ln - 1] =~ m@(/\\*|\\*/)@ &&\n\t\t\t\t    $rawlines[$ln - 1] !~ m@\"[^\"]*(?:/\\*|\\*/)[^\"]*\"@) {\n\t\t\t\t\t($edge) = $1;\n\t\t\t\t\tlast;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (defined $edge && $edge eq '*/') {\n\t\t\t\t$in_comment = 1;\n\t\t\t}\n\n\t\t\t# Guestimate if this is a continuing comment.  If this\n\t\t\t# is the start of a diff block and this line starts\n\t\t\t# ' *' then it is very likely a comment.\n\t\t\tif (!defined $edge &&\n\t\t\t    $rawlines[$linenr] =~ m@^.\\s*(?:\\*\\*+| \\*)(?:\\s|$)@)\n\t\t\t{\n\t\t\t\t$in_comment = 1;\n\t\t\t}\n\n\t\t\t##print \"COMMENT:$in_comment edge<$edge> $rawline\\n\";\n\t\t\tsanitise_line_reset($in_comment);\n\n\t\t} elsif ($realcnt && $rawline =~ /^(?:\\+| |$)/) {\n\t\t\t# Standardise the strings and chars within the input to\n\t\t\t# simplify matching -- only bother with positive lines.\n\t\t\t$line = sanitise_line($rawline);\n\t\t}\n\t\tpush(@lines, $line);\n\n\t\tif ($realcnt > 1) {\n\t\t\t$realcnt-- if ($line =~ /^(?:\\+| |$)/);\n\t\t} else {\n\t\t\t$realcnt = 0;\n\t\t}\n\n\t\t#print \"==>$rawline\\n\";\n\t\t#print \"-->$line\\n\";\n\n\t\tif ($setup_docs && $line =~ /^\\+/) {\n\t\t\tpush(@setup_docs, $line);\n\t\t}\n\t}\n\n\t$prefix = '';\n\n\t$realcnt = 0;\n\t$linenr = 0;\n\tforeach my $line (@lines) {\n\t\t$linenr++;\n\n\t\tmy $rawline = $rawlines[$linenr - 1];\n\n#extract the line range in the file after the patch is applied\n\t\tif ($line=~/^\\@\\@ -\\d+(?:,\\d+)? \\+(\\d+)(,(\\d+))? \\@\\@/) {\n\t\t\t$is_patch = 1;\n\t\t\t$first_line = $linenr + 1;\n\t\t\t$realline=$1-1;\n\t\t\tif (defined $2) {\n\t\t\t\t$realcnt=$3+1;\n\t\t\t} else {\n\t\t\t\t$realcnt=1+1;\n\t\t\t}\n\t\t\tannotate_reset();\n\t\t\t$prev_values = 'E';\n\n\t\t\t%suppress_ifbraces = ();\n\t\t\t%suppress_whiletrailers = ();\n\t\t\t%suppress_export = ();\n\t\t\tnext;\n\n# track the line number as we move through the hunk, note that\n# new versions of GNU diff omit the leading space on completely\n# blank context lines so we need to count that too.\n\t\t} elsif ($line =~ /^( |\\+|$)/) {\n\t\t\t$realline++;\n\t\t\t$realcnt-- if ($realcnt != 0);\n\n\t\t\t# Measure the line length and indent.\n\t\t\t($length, $indent) = line_stats($rawline);\n\n\t\t\t# Track the previous line.\n\t\t\t($prevline, $stashline) = ($stashline, $line);\n\t\t\t($previndent, $stashindent) = ($stashindent, $indent);\n\t\t\t($prevrawline, $stashrawline) = ($stashrawline, $rawline);\n\n\t\t\t#warn \"line<$line>\\n\";\n\n\t\t} elsif ($realcnt == 1) {\n\t\t\t$realcnt--;\n\t\t}\n\n\t\tmy $hunk_line = ($realcnt != 0);\n\n#make up the handle for any error we report on this line\n\t\t$prefix = \"$filename:$realline: \" if ($emacs && $file);\n\t\t$prefix = \"$filename:$linenr: \" if ($emacs && !$file);\n\n\t\t$here = \"#$linenr: \" if (!$file);\n\t\t$here = \"#$realline: \" if ($file);\n\n\t\t# extract the filename as it passes\n\t\tif ($line =~ /^diff --git.*?(\\S+)$/) {\n\t\t\t$realfile = $1;\n\t\t\t$realfile =~ s@^([^/]*)/@@;\n\n\t\t} elsif ($line =~ /^\\+\\+\\+\\s+(\\S+)/) {\n\t\t\t$realfile = $1;\n\t\t\t$realfile =~ s@^([^/]*)/@@;\n\n\t\t\t$p1_prefix = $1;\n\t\t\tif (!$file && $tree && $p1_prefix ne '' &&\n\t\t\t    -e \"$root/$p1_prefix\") {\n\t\t\t\tWARN(\"patch prefix '$p1_prefix' exists, appears to be a -p0 patch\\n\");\n\t\t\t}\n\n\t\t\tif ($realfile =~ m@^include/asm/@) {\n\t\t\t\tERROR(\"do not modify files in include/asm, change architecture specific files in include/asm-<architecture>\\n\" . \"$here$rawline\\n\");\n\t\t\t}\n\t\t\tnext;\n\t\t}\n\n\t\t$here .= \"FILE: $realfile:$realline:\" if ($realcnt != 0);\n\n\t\tmy $hereline = \"$here\\n$rawline\\n\";\n\t\tmy $herecurr = \"$here\\n$rawline\\n\";\n\t\tmy $hereprev = \"$here\\n$prevrawline\\n$rawline\\n\";\n\n\t\t$cnt_lines++ if ($realcnt != 0);\n\n# Check for incorrect file permissions\n\t\tif ($line =~ /^new (file )?mode.*[7531]\\d{0,2}$/) {\n\t\t\tmy $permhere = $here . \"FILE: $realfile\\n\";\n\t\t\tif ($realfile =~ /(Makefile|Kconfig|\\.c|\\.h|\\.S|\\.tmpl)$/) {\n\t\t\t\tERROR(\"do not set execute permissions for source files\\n\" . $permhere);\n\t\t\t}\n\t\t}\n\n#check the patch for a signoff:\n\t\tif ($line =~ /^\\s*signed-off-by:/i) {\n\t\t\t# This is a signoff, if ugly, so do not double report.\n\t\t\t$signoff++;\n\t\t\tif (!($line =~ /^\\s*Signed-off-by:/)) {\n\t\t\t\tWARN(\"Signed-off-by: is the preferred form\\n\" .\n\t\t\t\t\t$herecurr);\n\t\t\t}\n\t\t\tif ($line =~ /^\\s*signed-off-by:\\S/i) {\n\t\t\t\tWARN(\"space required after Signed-off-by:\\n\" .\n\t\t\t\t\t$herecurr);\n\t\t\t}\n\t\t}\n\n# Check for wrappage within a valid hunk of the file\n\t\tif ($realcnt != 0 && $line !~ m{^(?:\\+|-| |\\\\ No newline|$)}) {\n\t\t\tERROR(\"patch seems to be corrupt (line wrapped?)\\n\" .\n\t\t\t\t$herecurr) if (!$emitted_corrupt++);\n\t\t}\n\n# Check for absolute kernel paths.\n\t\tif ($tree) {\n\t\t\twhile ($line =~ m{(?:^|\\s)(/\\S*)}g) {\n\t\t\t\tmy $file = $1;\n\n\t\t\t\tif ($file =~ m{^(.*?)(?::\\d+)+:?$} &&\n\t\t\t\t    check_absolute_file($1, $herecurr)) {\n\t\t\t\t\t#\n\t\t\t\t} else {\n\t\t\t\t\tcheck_absolute_file($file, $herecurr);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n# UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php\n\t\tif (($realfile =~ /^$/ || $line =~ /^\\+/) &&\n\t\t    $rawline !~ m/^$UTF8*$/) {\n\t\t\tmy ($utf8_prefix) = ($rawline =~ /^($UTF8*)/);\n\n\t\t\tmy $blank = copy_spacing($rawline);\n\t\t\tmy $ptr = substr($blank, 0, length($utf8_prefix)) . \"^\";\n\t\t\tmy $hereptr = \"$hereline$ptr\\n\";\n\n\t\t\tERROR(\"Invalid UTF-8, patch and commit message should be encoded in UTF-8\\n\" . $hereptr);\n\t\t}\n\n# ignore non-hunk lines and lines being removed\n\t\tnext if (!$hunk_line || $line =~ /^-/);\n\n#trailing whitespace\n\t\tif ($line =~ /^\\+.*\\015/) {\n\t\t\tmy $herevet = \"$here\\n\" . cat_vet($rawline) . \"\\n\";\n\t\t\tERROR(\"DOS line endings\\n\" . $herevet);\n\n\t\t} elsif ($rawline =~ /^\\+.*\\S\\s+$/ || $rawline =~ /^\\+\\s+$/) {\n\t\t\tmy $herevet = \"$here\\n\" . cat_vet($rawline) . \"\\n\";\n\t\t\tERROR(\"trailing whitespace\\n\" . $herevet);\n\t\t\t$rpt_cleaners = 1;\n\t\t}\n\n# check for Kconfig help text having a real description\n# Only applies when adding the entry originally, after that we do not have\n# sufficient context to determine whether it is indeed long enough.\n\t\tif ($realfile =~ /Kconfig/ &&\n\t\t    $line =~ /\\+\\s*(?:---)?help(?:---)?$/) {\n\t\t\tmy $length = 0;\n\t\t\tmy $cnt = $realcnt;\n\t\t\tmy $ln = $linenr + 1;\n\t\t\tmy $f;\n\t\t\tmy $is_end = 0;\n\t\t\twhile ($cnt > 0 && defined $lines[$ln - 1]) {\n\t\t\t\t$f = $lines[$ln - 1];\n\t\t\t\t$cnt-- if ($lines[$ln - 1] !~ /^-/);\n\t\t\t\t$is_end = $lines[$ln - 1] =~ /^\\+/;\n\t\t\t\t$ln++;\n\n\t\t\t\tnext if ($f =~ /^-/);\n\t\t\t\t$f =~ s/^.//;\n\t\t\t\t$f =~ s/#.*//;\n\t\t\t\t$f =~ s/^\\s+//;\n\t\t\t\tnext if ($f =~ /^$/);\n\t\t\t\tif ($f =~ /^\\s*config\\s/) {\n\t\t\t\t\t$is_end = 1;\n\t\t\t\t\tlast;\n\t\t\t\t}\n\t\t\t\t$length++;\n\t\t\t}\n\t\t\tWARN(\"please write a paragraph that describes the config symbol fully\\n\" . $herecurr) if ($is_end && $length < 4);\n\t\t\t#print \"is_end<$is_end> length<$length>\\n\";\n\t\t}\n\n# check we are in a valid source file if not then ignore this hunk\n\t\tnext if ($realfile !~ /\\.(h|c|s|S|pl|sh)$/);\n\n#80 column limit\n\t\tif ($line =~ /^\\+/ && $prevrawline !~ /\\/\\*\\*/ &&\n\t\t    $rawline !~ /^.\\s*\\*\\s*\\@$Ident\\s/ &&\n\t\t    !($line =~ /^\\+\\s*$logFunctions\\s*\\(\\s*(?:(KERN_\\S+\\s*|[^\"]*))?\"[X\\t]*\"\\s*(?:|,|\\)\\s*;)\\s*$/ ||\n\t\t    $line =~ /^\\+\\s*\"[^\"]*\"\\s*(?:\\s*|,|\\)\\s*;)\\s*$/) &&\n\t\t    $length > 80)\n\t\t{\n\t\t\tWARN(\"line over 80 characters\\n\" . $herecurr);\n\t\t}\n\n# check for spaces before a quoted newline\n\t\tif ($rawline =~ /^.*\\\".*\\s\\\\n/) {\n\t\t\tWARN(\"unnecessary whitespace before a quoted newline\\n\" . $herecurr);\n\t\t}\n\n# check for adding lines without a newline.\n\t\tif ($line =~ /^\\+/ && defined $lines[$linenr] && $lines[$linenr] =~ /^\\\\ No newline at end of file/) {\n\t\t\tWARN(\"adding a line without newline at end of file\\n\" . $herecurr);\n\t\t}\n\n# Blackfin: use hi/lo macros\n\t\tif ($realfile =~ m@arch/blackfin/.*\\.S$@) {\n\t\t\tif ($line =~ /\\.[lL][[:space:]]*=.*&[[:space:]]*0x[fF][fF][fF][fF]/) {\n\t\t\t\tmy $herevet = \"$here\\n\" . cat_vet($line) . \"\\n\";\n\t\t\t\tERROR(\"use the LO() macro, not (... & 0xFFFF)\\n\" . $herevet);\n\t\t\t}\n\t\t\tif ($line =~ /\\.[hH][[:space:]]*=.*>>[[:space:]]*16/) {\n\t\t\t\tmy $herevet = \"$here\\n\" . cat_vet($line) . \"\\n\";\n\t\t\t\tERROR(\"use the HI() macro, not (... >> 16)\\n\" . $herevet);\n\t\t\t}\n\t\t}\n\n# check we are in a valid source file C or perl if not then ignore this hunk\n\t\tnext if ($realfile !~ /\\.(h|c|pl)$/);\n\n# at the beginning of a line any tabs must come first and anything\n# more than 8 must use tabs.\n\t\tif ($rawline =~ /^\\+\\s* \\t\\s*\\S/ ||\n\t\t    $rawline =~ /^\\+\\s*        \\s*/) {\n\t\t\tmy $herevet = \"$here\\n\" . cat_vet($rawline) . \"\\n\";\n\t\t\tERROR(\"code indent should use tabs where possible\\n\" . $herevet);\n\t\t\t$rpt_cleaners = 1;\n\t\t}\n\n# check for space before tabs.\n\t\tif ($rawline =~ /^\\+/ && $rawline =~ / \\t/) {\n\t\t\tmy $herevet = \"$here\\n\" . cat_vet($rawline) . \"\\n\";\n\t\t\tWARN(\"please, no space before tabs\\n\" . $herevet);\n\t\t}\n\n# check for spaces at the beginning of a line.\n# Exceptions:\n#  1) within comments\n#  2) indented preprocessor commands\n#  3) hanging labels\n\t\tif ($rawline =~ /^\\+ / && $line !~ /\\+ *(?:$;|#|$Ident:)/)  {\n\t\t\tmy $herevet = \"$here\\n\" . cat_vet($rawline) . \"\\n\";\n\t\t\tWARN(\"please, no spaces at the start of a line\\n\" . $herevet);\n\t\t}\n\n# check we are in a valid C source file if not then ignore this hunk\n\t\tnext if ($realfile !~ /\\.(h|c)$/);\n\n# check for RCS/CVS revision markers\n\t\tif ($rawline =~ /^\\+.*\\$(Revision|Log|Id)(?:\\$|)/) {\n\t\t\tWARN(\"CVS style keyword markers, these will _not_ be updated\\n\". $herecurr);\n\t\t}\n\n# Blackfin: don't use __builtin_bfin_[cs]sync\n\t\tif ($line =~ /__builtin_bfin_csync/) {\n\t\t\tmy $herevet = \"$here\\n\" . cat_vet($line) . \"\\n\";\n\t\t\tERROR(\"use the CSYNC() macro in asm/blackfin.h\\n\" . $herevet);\n\t\t}\n\t\tif ($line =~ /__builtin_bfin_ssync/) {\n\t\t\tmy $herevet = \"$here\\n\" . cat_vet($line) . \"\\n\";\n\t\t\tERROR(\"use the SSYNC() macro in asm/blackfin.h\\n\" . $herevet);\n\t\t}\n\n# Check for potential 'bare' types\n\t\tmy ($stat, $cond, $line_nr_next, $remain_next, $off_next,\n\t\t    $realline_next);\n\t\tif ($realcnt && $line =~ /.\\s*\\S/) {\n\t\t\t($stat, $cond, $line_nr_next, $remain_next, $off_next) =\n\t\t\t\tctx_statement_block($linenr, $realcnt, 0);\n\t\t\t$stat =~ s/\\n./\\n /g;\n\t\t\t$cond =~ s/\\n./\\n /g;\n\n\t\t\t# Find the real next line.\n\t\t\t$realline_next = $line_nr_next;\n\t\t\tif (defined $realline_next &&\n\t\t\t    (!defined $lines[$realline_next - 1] ||\n\t\t\t     substr($lines[$realline_next - 1], $off_next) =~ /^\\s*$/)) {\n\t\t\t\t$realline_next++;\n\t\t\t}\n\n\t\t\tmy $s = $stat;\n\t\t\t$s =~ s/{.*$//s;\n\n\t\t\t# Ignore goto labels.\n\t\t\tif ($s =~ /$Ident:\\*$/s) {\n\n\t\t\t# Ignore functions being called\n\t\t\t} elsif ($s =~ /^.\\s*$Ident\\s*\\(/s) {\n\n\t\t\t} elsif ($s =~ /^.\\s*else\\b/s) {\n\n\t\t\t# declarations always start with types\n\t\t\t} elsif ($prev_values eq 'E' && $s =~ /^.\\s*(?:$Storage\\s+)?(?:$Inline\\s+)?(?:const\\s+)?((?:\\s*$Ident)+?)\\b(?:\\s+$Sparse)?\\s*\\**\\s*(?:$Ident|\\(\\*[^\\)]*\\))(?:\\s*$Modifier)?\\s*(?:;|=|,|\\()/s) {\n\t\t\t\tmy $type = $1;\n\t\t\t\t$type =~ s/\\s+/ /g;\n\t\t\t\tpossible($type, \"A:\" . $s);\n\n\t\t\t# definitions in global scope can only start with types\n\t\t\t} elsif ($s =~ /^.(?:$Storage\\s+)?(?:$Inline\\s+)?(?:const\\s+)?($Ident)\\b\\s*(?!:)/s) {\n\t\t\t\tpossible($1, \"B:\" . $s);\n\t\t\t}\n\n\t\t\t# any (foo ... *) is a pointer cast, and foo is a type\n\t\t\twhile ($s =~ /\\(($Ident)(?:\\s+$Sparse)*[\\s\\*]+\\s*\\)/sg) {\n\t\t\t\tpossible($1, \"C:\" . $s);\n\t\t\t}\n\n\t\t\t# Check for any sort of function declaration.\n\t\t\t# int foo(something bar, other baz);\n\t\t\t# void (*store_gdt)(x86_descr_ptr *);\n\t\t\tif ($prev_values eq 'E' && $s =~ /^(.(?:typedef\\s*)?(?:(?:$Storage|$Inline)\\s*)*\\s*$Type\\s*(?:\\b$Ident|\\(\\*\\s*$Ident\\))\\s*)\\(/s) {\n\t\t\t\tmy ($name_len) = length($1);\n\n\t\t\t\tmy $ctx = $s;\n\t\t\t\tsubstr($ctx, 0, $name_len + 1, '');\n\t\t\t\t$ctx =~ s/\\)[^\\)]*$//;\n\n\t\t\t\tfor my $arg (split(/\\s*,\\s*/, $ctx)) {\n\t\t\t\t\tif ($arg =~ /^(?:const\\s+)?($Ident)(?:\\s+$Sparse)*\\s*\\**\\s*(:?\\b$Ident)?$/s || $arg =~ /^($Ident)$/s) {\n\n\t\t\t\t\t\tpossible($1, \"D:\" . $s);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n#\n# Checks which may be anchored in the context.\n#\n\n# Check for switch () and associated case and default\n# statements should be at the same indent.\n\t\tif ($line=~/\\bswitch\\s*\\(.*\\)/) {\n\t\t\tmy $err = '';\n\t\t\tmy $sep = '';\n\t\t\tmy @ctx = ctx_block_outer($linenr, $realcnt);\n\t\t\tshift(@ctx);\n\t\t\tfor my $ctx (@ctx) {\n\t\t\t\tmy ($clen, $cindent) = line_stats($ctx);\n\t\t\t\tif ($ctx =~ /^\\+\\s*(case\\s+|default:)/ &&\n\t\t\t\t\t\t\t$indent != $cindent) {\n\t\t\t\t\t$err .= \"$sep$ctx\\n\";\n\t\t\t\t\t$sep = '';\n\t\t\t\t} else {\n\t\t\t\t\t$sep = \"[...]\\n\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ($err ne '') {\n\t\t\t\tERROR(\"switch and case should be at the same indent\\n$hereline$err\");\n\t\t\t}\n\t\t}\n\n# if/while/etc brace do not go on next line, unless defining a do while loop,\n# or if that brace on the next line is for something else\n\t\tif ($line =~ /(.*)\\b((?:if|while|for|switch)\\s*\\(|do\\b|else\\b)/ && $line !~ /^.\\s*\\#/) {\n\t\t\tmy $pre_ctx = \"$1$2\";\n\n\t\t\tmy ($level, @ctx) = ctx_statement_level($linenr, $realcnt, 0);\n\t\t\tmy $ctx_cnt = $realcnt - $#ctx - 1;\n\t\t\tmy $ctx = join(\"\\n\", @ctx);\n\n\t\t\tmy $ctx_ln = $linenr;\n\t\t\tmy $ctx_skip = $realcnt;\n\n\t\t\twhile ($ctx_skip > $ctx_cnt || ($ctx_skip == $ctx_cnt &&\n\t\t\t\t\tdefined $lines[$ctx_ln - 1] &&\n\t\t\t\t\t$lines[$ctx_ln - 1] =~ /^-/)) {\n\t\t\t\t##print \"SKIP<$ctx_skip> CNT<$ctx_cnt>\\n\";\n\t\t\t\t$ctx_skip-- if (!defined $lines[$ctx_ln - 1] || $lines[$ctx_ln - 1] !~ /^-/);\n\t\t\t\t$ctx_ln++;\n\t\t\t}\n\n\t\t\t#print \"realcnt<$realcnt> ctx_cnt<$ctx_cnt>\\n\";\n\t\t\t#print \"pre<$pre_ctx>\\nline<$line>\\nctx<$ctx>\\nnext<$lines[$ctx_ln - 1]>\\n\";\n\n\t\t\tif ($ctx !~ /{\\s*/ && defined($lines[$ctx_ln -1]) && $lines[$ctx_ln - 1] =~ /^\\+\\s*{/) {\n\t\t\t\tERROR(\"that open brace { should be on the previous line\\n\" .\n\t\t\t\t\t\"$here\\n$ctx\\n$rawlines[$ctx_ln - 1]\\n\");\n\t\t\t}\n\t\t\tif ($level == 0 && $pre_ctx !~ /}\\s*while\\s*\\($/ &&\n\t\t\t    $ctx =~ /\\)\\s*\\;\\s*$/ &&\n\t\t\t    defined $lines[$ctx_ln - 1])\n\t\t\t{\n\t\t\t\tmy ($nlength, $nindent) = line_stats($lines[$ctx_ln - 1]);\n\t\t\t\tif ($nindent > $indent) {\n\t\t\t\t\tWARN(\"trailing semicolon indicates no statements, indent implies otherwise\\n\" .\n\t\t\t\t\t\t\"$here\\n$ctx\\n$rawlines[$ctx_ln - 1]\\n\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n# Check relative indent for conditionals and blocks.\n\t\tif ($line =~ /\\b(?:(?:if|while|for)\\s*\\(|do\\b)/ && $line !~ /^.\\s*#/ && $line !~ /\\}\\s*while\\s*/) {\n\t\t\tmy ($s, $c) = ($stat, $cond);\n\n\t\t\tsubstr($s, 0, length($c), '');\n\n\t\t\t# Make sure we remove the line prefixes as we have\n\t\t\t# none on the first line, and are going to readd them\n\t\t\t# where necessary.\n\t\t\t$s =~ s/\\n./\\n/gs;\n\n\t\t\t# Find out how long the conditional actually is.\n\t\t\tmy @newlines = ($c =~ /\\n/gs);\n\t\t\tmy $cond_lines = 1 + $#newlines;\n\n\t\t\t# We want to check the first line inside the block\n\t\t\t# starting at the end of the conditional, so remove:\n\t\t\t#  1) any blank line termination\n\t\t\t#  2) any opening brace { on end of the line\n\t\t\t#  3) any do (...) {\n\t\t\tmy $continuation = 0;\n\t\t\tmy $check = 0;\n\t\t\t$s =~ s/^.*\\bdo\\b//;\n\t\t\t$s =~ s/^\\s*{//;\n\t\t\tif ($s =~ s/^\\s*\\\\//) {\n\t\t\t\t$continuation = 1;\n\t\t\t}\n\t\t\tif ($s =~ s/^\\s*?\\n//) {\n\t\t\t\t$check = 1;\n\t\t\t\t$cond_lines++;\n\t\t\t}\n\n\t\t\t# Also ignore a loop construct at the end of a\n\t\t\t# preprocessor statement.\n\t\t\tif (($prevline =~ /^.\\s*#\\s*define\\s/ ||\n\t\t\t    $prevline =~ /\\\\\\s*$/) && $continuation == 0) {\n\t\t\t\t$check = 0;\n\t\t\t}\n\n\t\t\tmy $cond_ptr = -1;\n\t\t\t$continuation = 0;\n\t\t\twhile ($cond_ptr != $cond_lines) {\n\t\t\t\t$cond_ptr = $cond_lines;\n\n\t\t\t\t# If we see an #else/#elif then the code\n\t\t\t\t# is not linear.\n\t\t\t\tif ($s =~ /^\\s*\\#\\s*(?:else|elif)/) {\n\t\t\t\t\t$check = 0;\n\t\t\t\t}\n\n\t\t\t\t# Ignore:\n\t\t\t\t#  1) blank lines, they should be at 0,\n\t\t\t\t#  2) preprocessor lines, and\n\t\t\t\t#  3) labels.\n\t\t\t\tif ($continuation ||\n\t\t\t\t    $s =~ /^\\s*?\\n/ ||\n\t\t\t\t    $s =~ /^\\s*#\\s*?/ ||\n\t\t\t\t    $s =~ /^\\s*$Ident\\s*:/) {\n\t\t\t\t\t$continuation = ($s =~ /^.*?\\\\\\n/) ? 1 : 0;\n\t\t\t\t\tif ($s =~ s/^.*?\\n//) {\n\t\t\t\t\t\t$cond_lines++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tmy (undef, $sindent) = line_stats(\"+\" . $s);\n\t\t\tmy $stat_real = raw_line($linenr, $cond_lines);\n\n\t\t\t# Check if either of these lines are modified, else\n\t\t\t# this is not this patch's fault.\n\t\t\tif (!defined($stat_real) ||\n\t\t\t    $stat !~ /^\\+/ && $stat_real !~ /^\\+/) {\n\t\t\t\t$check = 0;\n\t\t\t}\n\t\t\tif (defined($stat_real) && $cond_lines > 1) {\n\t\t\t\t$stat_real = \"[...]\\n$stat_real\";\n\t\t\t}\n\n\t\t\t#print \"line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\\n\";\n\n\t\t\tif ($check && (($sindent % 8) != 0 ||\n\t\t\t    ($sindent <= $indent && $s ne ''))) {\n\t\t\t\tWARN(\"suspect code indent for conditional statements ($indent, $sindent)\\n\" . $herecurr . \"$stat_real\\n\");\n\t\t\t}\n\t\t}\n\n\t\t# Track the 'values' across context and added lines.\n\t\tmy $opline = $line; $opline =~ s/^./ /;\n\t\tmy ($curr_values, $curr_vars) =\n\t\t\t\tannotate_values($opline . \"\\n\", $prev_values);\n\t\t$curr_values = $prev_values . $curr_values;\n\t\tif ($dbg_values) {\n\t\t\tmy $outline = $opline; $outline =~ s/\\t/ /g;\n\t\t\tprint \"$linenr > .$outline\\n\";\n\t\t\tprint \"$linenr > $curr_values\\n\";\n\t\t\tprint \"$linenr >  $curr_vars\\n\";\n\t\t}\n\t\t$prev_values = substr($curr_values, -1);\n\n#ignore lines not being added\n\t\tif ($line=~/^[^\\+]/) {next;}\n\n# TEST: allow direct testing of the type matcher.\n\t\tif ($dbg_type) {\n\t\t\tif ($line =~ /^.\\s*$Declare\\s*$/) {\n\t\t\t\tERROR(\"TEST: is type\\n\" . $herecurr);\n\t\t\t} elsif ($dbg_type > 1 && $line =~ /^.+($Declare)/) {\n\t\t\t\tERROR(\"TEST: is not type ($1 is)\\n\". $herecurr);\n\t\t\t}\n\t\t\tnext;\n\t\t}\n# TEST: allow direct testing of the attribute matcher.\n\t\tif ($dbg_attr) {\n\t\t\tif ($line =~ /^.\\s*$Modifier\\s*$/) {\n\t\t\t\tERROR(\"TEST: is attr\\n\" . $herecurr);\n\t\t\t} elsif ($dbg_attr > 1 && $line =~ /^.+($Modifier)/) {\n\t\t\t\tERROR(\"TEST: is not attr ($1 is)\\n\". $herecurr);\n\t\t\t}\n\t\t\tnext;\n\t\t}\n\n# check for initialisation to aggregates open brace on the next line\n\t\tif ($line =~ /^.\\s*{/ &&\n\t\t    $prevline =~ /(?:^|[^=])=\\s*$/) {\n\t\t\tERROR(\"that open brace { should be on the previous line\\n\" . $hereprev);\n\t\t}\n\n#\n# Checks which are anchored on the added line.\n#\n\n# check for malformed paths in #include statements (uses RAW line)\n\t\tif ($rawline =~ m{^.\\s*\\#\\s*include\\s+[<\"](.*)[\">]}) {\n\t\t\tmy $path = $1;\n\t\t\tif ($path =~ m{//}) {\n\t\t\t\tERROR(\"malformed #include filename\\n\" .\n\t\t\t\t\t$herecurr);\n\t\t\t}\n\t\t}\n\n# no C99 // comments\n\t\tif ($line =~ m{//}) {\n\t\t\tERROR(\"do not use C99 // comments\\n\" . $herecurr);\n\t\t}\n\t\t# Remove C99 comments.\n\t\t$line =~ s@//.*@@;\n\t\t$opline =~ s@//.*@@;\n\n# EXPORT_SYMBOL should immediately follow the thing it is exporting, consider\n# the whole statement.\n#print \"APW <$lines[$realline_next - 1]>\\n\";\n\t\tif (defined $realline_next &&\n\t\t    exists $lines[$realline_next - 1] &&\n\t\t    !defined $suppress_export{$realline_next} &&\n\t\t    ($lines[$realline_next - 1] =~ /EXPORT_SYMBOL.*\\((.*)\\)/ ||\n\t\t     $lines[$realline_next - 1] =~ /EXPORT_UNUSED_SYMBOL.*\\((.*)\\)/)) {\n\t\t\t# Handle definitions which produce identifiers with\n\t\t\t# a prefix:\n\t\t\t#   XXX(foo);\n\t\t\t#   EXPORT_SYMBOL(something_foo);\n\t\t\tmy $name = $1;\n\t\t\tif ($stat =~ /^.([A-Z_]+)\\s*\\(\\s*($Ident)/ &&\n\t\t\t    $name =~ /^${Ident}_$2/) {\n#print \"FOO C name<$name>\\n\";\n\t\t\t\t$suppress_export{$realline_next} = 1;\n\n\t\t\t} elsif ($stat !~ /(?:\n\t\t\t\t\\n.}\\s*$|\n\t\t\t\t^.DEFINE_$Ident\\(\\Q$name\\E\\)|\n\t\t\t\t^.DECLARE_$Ident\\(\\Q$name\\E\\)|\n\t\t\t\t^.LIST_HEAD\\(\\Q$name\\E\\)|\n\t\t\t\t^.(?:$Storage\\s+)?$Type\\s*\\(\\s*\\*\\s*\\Q$name\\E\\s*\\)\\s*\\(|\n\t\t\t\t\\b\\Q$name\\E(?:\\s+$Attribute)*\\s*(?:;|=|\\[|\\()\n\t\t\t    )/x) {\n#print \"FOO A<$lines[$realline_next - 1]> stat<$stat> name<$name>\\n\";\n\t\t\t\t$suppress_export{$realline_next} = 2;\n\t\t\t} else {\n\t\t\t\t$suppress_export{$realline_next} = 1;\n\t\t\t}\n\t\t}\n\t\tif (!defined $suppress_export{$linenr} &&\n\t\t    $prevline =~ /^.\\s*$/ &&\n\t\t    ($line =~ /EXPORT_SYMBOL.*\\((.*)\\)/ ||\n\t\t     $line =~ /EXPORT_UNUSED_SYMBOL.*\\((.*)\\)/)) {\n#print \"FOO B <$lines[$linenr - 1]>\\n\";\n\t\t\t$suppress_export{$linenr} = 2;\n\t\t}\n\t\tif (defined $suppress_export{$linenr} &&\n\t\t    $suppress_export{$linenr} == 2) {\n\t\t\tWARN(\"EXPORT_SYMBOL(foo); should immediately follow its function/variable\\n\" . $herecurr);\n\t\t}\n\n# check for global initialisers.\n\t\tif ($line =~ /^.$Type\\s*$Ident\\s*(?:\\s+$Modifier)*\\s*=\\s*(0|NULL|false)\\s*;/) {\n\t\t\tERROR(\"do not initialise globals to 0 or NULL\\n\" .\n\t\t\t\t$herecurr);\n\t\t}\n# check for static initialisers.\n\t\tif ($line =~ /\\bstatic\\s.*=\\s*(0|NULL|false)\\s*;/) {\n\t\t\tERROR(\"do not initialise statics to 0 or NULL\\n\" .\n\t\t\t\t$herecurr);\n\t\t}\n\n# check for static const char * arrays.\n\t\tif ($line =~ /\\bstatic\\s+const\\s+char\\s*\\*\\s*(\\w+)\\s*\\[\\s*\\]\\s*=\\s*/) {\n\t\t\tWARN(\"static const char * array should probably be static const char * const\\n\" .\n\t\t\t\t$herecurr);\n               }\n\n# check for static char foo[] = \"bar\" declarations.\n\t\tif ($line =~ /\\bstatic\\s+char\\s+(\\w+)\\s*\\[\\s*\\]\\s*=\\s*\"/) {\n\t\t\tWARN(\"static char array declaration should probably be static const char\\n\" .\n\t\t\t\t$herecurr);\n               }\n\n# check for declarations of struct pci_device_id\n\t\tif ($line =~ /\\bstruct\\s+pci_device_id\\s+\\w+\\s*\\[\\s*\\]\\s*\\=\\s*\\{/) {\n\t\t\tWARN(\"Use DEFINE_PCI_DEVICE_TABLE for struct pci_device_id\\n\" . $herecurr);\n\t\t}\n\n# check for new typedefs, only function parameters and sparse annotations\n# make sense.\n\t\tif ($line =~ /\\btypedef\\s/ &&\n\t\t    $line !~ /\\btypedef\\s+$Type\\s*\\(\\s*\\*?$Ident\\s*\\)\\s*\\(/ &&\n\t\t    $line !~ /\\btypedef\\s+$Type\\s+$Ident\\s*\\(/ &&\n\t\t    $line !~ /\\b$typeTypedefs\\b/ &&\n\t\t    $line !~ /\\b__bitwise(?:__|)\\b/) {\n\t\t\tWARN(\"do not add new typedefs\\n\" . $herecurr);\n\t\t}\n\n# * goes on variable not on type\n\t\t# (char*[ const])\n\t\tif ($line =~ m{\\($NonptrType(\\s*(?:$Modifier\\b\\s*|\\*\\s*)+)\\)}) {\n\t\t\tmy ($from, $to) = ($1, $1);\n\n\t\t\t# Should start with a space.\n\t\t\t$to =~ s/^(\\S)/ $1/;\n\t\t\t# Should not end with a space.\n\t\t\t$to =~ s/\\s+$//;\n\t\t\t# '*'s should not have spaces between.\n\t\t\twhile ($to =~ s/\\*\\s+\\*/\\*\\*/) {\n\t\t\t}\n\n\t\t\t#print \"from<$from> to<$to>\\n\";\n\t\t\tif ($from ne $to) {\n\t\t\t\tERROR(\"\\\"(foo$from)\\\" should be \\\"(foo$to)\\\"\\n\" .  $herecurr);\n\t\t\t}\n\t\t} elsif ($line =~ m{\\b$NonptrType(\\s*(?:$Modifier\\b\\s*|\\*\\s*)+)($Ident)}) {\n\t\t\tmy ($from, $to, $ident) = ($1, $1, $2);\n\n\t\t\t# Should start with a space.\n\t\t\t$to =~ s/^(\\S)/ $1/;\n\t\t\t# Should not end with a space.\n\t\t\t$to =~ s/\\s+$//;\n\t\t\t# '*'s should not have spaces between.\n\t\t\twhile ($to =~ s/\\*\\s+\\*/\\*\\*/) {\n\t\t\t}\n\t\t\t# Modifiers should have spaces.\n\t\t\t$to =~ s/(\\b$Modifier$)/$1 /;\n\n\t\t\t#print \"from<$from> to<$to> ident<$ident>\\n\";\n\t\t\tif ($from ne $to && $ident !~ /^$Modifier$/) {\n\t\t\t\tERROR(\"\\\"foo${from}bar\\\" should be \\\"foo${to}bar\\\"\\n\" .  $herecurr);\n\t\t\t}\n\t\t}\n\n# # no BUG() or BUG_ON()\n# \t\tif ($line =~ /\\b(BUG|BUG_ON)\\b/) {\n# \t\t\tprint \"Try to use WARN_ON & Recovery code rather than BUG() or BUG_ON()\\n\";\n# \t\t\tprint \"$herecurr\";\n# \t\t\t$clean = 0;\n# \t\t}\n\n\t\tif ($line =~ /\\bLINUX_VERSION_CODE\\b/) {\n\t\t\tWARN(\"LINUX_VERSION_CODE should be avoided, code should be for the version to which it is merged\\n\" . $herecurr);\n\t\t}\n\n# check for uses of printk_ratelimit\n\t\tif ($line =~ /\\bprintk_ratelimit\\s*\\(/) {\n\t\t\tWARN(\"Prefer printk_ratelimited or pr_<level>_ratelimited to printk_ratelimit\\n\" . $herecurr);\n\t\t}\n\n# printk should use KERN_* levels.  Note that follow on printk's on the\n# same line do not need a level, so we use the current block context\n# to try and find and validate the current printk.  In summary the current\n# printk includes all preceding printk's which have no newline on the end.\n# we assume the first bad printk is the one to report.\n\t\tif ($line =~ /\\bprintk\\((?!KERN_)\\s*\"/) {\n\t\t\tmy $ok = 0;\n\t\t\tfor (my $ln = $linenr - 1; $ln >= $first_line; $ln--) {\n\t\t\t\t#print \"CHECK<$lines[$ln - 1]\\n\";\n\t\t\t\t# we have a preceding printk if it ends\n\t\t\t\t# with \"\\n\" ignore it, else it is to blame\n\t\t\t\tif ($lines[$ln - 1] =~ m{\\bprintk\\(}) {\n\t\t\t\t\tif ($rawlines[$ln - 1] !~ m{\\\\n\"}) {\n\t\t\t\t\t\t$ok = 1;\n\t\t\t\t\t}\n\t\t\t\t\tlast;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ($ok == 0) {\n\t\t\t\tWARN(\"printk() should include KERN_ facility level\\n\" . $herecurr);\n\t\t\t}\n\t\t}\n\n# function brace can't be on same line, except for #defines of do while,\n# or if closed on same line\n\t\tif (($line=~/$Type\\s*$Ident\\(.*\\).*\\s{/) and\n\t\t    !($line=~/\\#\\s*define.*do\\s{/) and !($line=~/}/)) {\n\t\t\tERROR(\"open brace '{' following function declarations go on the next line\\n\" . $herecurr);\n\t\t}\n\n# open braces for enum, union and struct go on the same line.\n\t\tif ($line =~ /^.\\s*{/ &&\n\t\t    $prevline =~ /^.\\s*(?:typedef\\s+)?(enum|union|struct)(?:\\s+$Ident)?\\s*$/) {\n\t\t\tERROR(\"open brace '{' following $1 go on the same line\\n\" . $hereprev);\n\t\t}\n\n# missing space after union, struct or enum definition\n\t\tif ($line =~ /^.\\s*(?:typedef\\s+)?(enum|union|struct)(?:\\s+$Ident)?(?:\\s+$Ident)?[=\\{]/) {\n\t\t    WARN(\"missing space after $1 definition\\n\" . $herecurr);\n\t\t}\n\n# check for spacing round square brackets; allowed:\n#  1. with a type on the left -- int [] a;\n#  2. at the beginning of a line for slice initialisers -- [0...10] = 5,\n#  3. inside a curly brace -- = { [0...10] = 5 }\n\t\twhile ($line =~ /(.*?\\s)\\[/g) {\n\t\t\tmy ($where, $prefix) = ($-[1], $1);\n\t\t\tif ($prefix !~ /$Type\\s+$/ &&\n\t\t\t    ($where != 0 || $prefix !~ /^.\\s+$/) &&\n\t\t\t    $prefix !~ /{\\s+$/) {\n\t\t\t\tERROR(\"space prohibited before open square bracket '['\\n\" . $herecurr);\n\t\t\t}\n\t\t}\n\n# check for spaces between functions and their parentheses.\n\t\twhile ($line =~ /($Ident)\\s+\\(/g) {\n\t\t\tmy $name = $1;\n\t\t\tmy $ctx_before = substr($line, 0, $-[1]);\n\t\t\tmy $ctx = \"$ctx_before$name\";\n\n\t\t\t# Ignore those directives where spaces _are_ permitted.\n\t\t\tif ($name =~ /^(?:\n\t\t\t\tif|for|while|switch|return|case|\n\t\t\t\tvolatile|__volatile__|\n\t\t\t\t__attribute__|format|__extension__|\n\t\t\t\tasm|__asm__)$/x)\n\t\t\t{\n\n\t\t\t# cpp #define statements have non-optional spaces, ie\n\t\t\t# if there is a space between the name and the open\n\t\t\t# parenthesis it is simply not a parameter group.\n\t\t\t} elsif ($ctx_before =~ /^.\\s*\\#\\s*define\\s*$/) {\n\n\t\t\t# cpp #elif statement condition may start with a (\n\t\t\t} elsif ($ctx =~ /^.\\s*\\#\\s*elif\\s*$/) {\n\n\t\t\t# If this whole things ends with a type its most\n\t\t\t# likely a typedef for a function.\n\t\t\t} elsif ($ctx =~ /$Type$/) {\n\n\t\t\t} else {\n\t\t\t\tWARN(\"space prohibited between function name and open parenthesis '('\\n\" . $herecurr);\n\t\t\t}\n\t\t}\n# Check operator spacing.\n\t\tif (!($line=~/\\#\\s*include/)) {\n\t\t\tmy $ops = qr{\n\t\t\t\t<<=|>>=|<=|>=|==|!=|\n\t\t\t\t\\+=|-=|\\*=|\\/=|%=|\\^=|\\|=|&=|\n\t\t\t\t=>|->|<<|>>|<|>|=|!|~|\n\t\t\t\t&&|\\|\\||,|\\^|\\+\\+|--|&|\\||\\+|-|\\*|\\/|%|\n\t\t\t\t\\?|:\n\t\t\t}x;\n\t\t\tmy @elements = split(/($ops|;)/, $opline);\n\t\t\tmy $off = 0;\n\n\t\t\tmy $blank = copy_spacing($opline);\n\n\t\t\tfor (my $n = 0; $n < $#elements; $n += 2) {\n\t\t\t\t$off += length($elements[$n]);\n\n\t\t\t\t# Pick up the preceding and succeeding characters.\n\t\t\t\tmy $ca = substr($opline, 0, $off);\n\t\t\t\tmy $cc = '';\n\t\t\t\tif (length($opline) >= ($off + length($elements[$n + 1]))) {\n\t\t\t\t\t$cc = substr($opline, $off + length($elements[$n + 1]));\n\t\t\t\t}\n\t\t\t\tmy $cb = \"$ca$;$cc\";\n\n\t\t\t\tmy $a = '';\n\t\t\t\t$a = 'V' if ($elements[$n] ne '');\n\t\t\t\t$a = 'W' if ($elements[$n] =~ /\\s$/);\n\t\t\t\t$a = 'C' if ($elements[$n] =~ /$;$/);\n\t\t\t\t$a = 'B' if ($elements[$n] =~ /(\\[|\\()$/);\n\t\t\t\t$a = 'O' if ($elements[$n] eq '');\n\t\t\t\t$a = 'E' if ($ca =~ /^\\s*$/);\n\n\t\t\t\tmy $op = $elements[$n + 1];\n\n\t\t\t\tmy $c = '';\n\t\t\t\tif (defined $elements[$n + 2]) {\n\t\t\t\t\t$c = 'V' if ($elements[$n + 2] ne '');\n\t\t\t\t\t$c = 'W' if ($elements[$n + 2] =~ /^\\s/);\n\t\t\t\t\t$c = 'C' if ($elements[$n + 2] =~ /^$;/);\n\t\t\t\t\t$c = 'B' if ($elements[$n + 2] =~ /^(\\)|\\]|;)/);\n\t\t\t\t\t$c = 'O' if ($elements[$n + 2] eq '');\n\t\t\t\t\t$c = 'E' if ($elements[$n + 2] =~ /^\\s*\\\\$/);\n\t\t\t\t} else {\n\t\t\t\t\t$c = 'E';\n\t\t\t\t}\n\n\t\t\t\tmy $ctx = \"${a}x${c}\";\n\n\t\t\t\tmy $at = \"(ctx:$ctx)\";\n\n\t\t\t\tmy $ptr = substr($blank, 0, $off) . \"^\";\n\t\t\t\tmy $hereptr = \"$hereline$ptr\\n\";\n\n\t\t\t\t# Pull out the value of this operator.\n\t\t\t\tmy $op_type = substr($curr_values, $off + 1, 1);\n\n\t\t\t\t# Get the full operator variant.\n\t\t\t\tmy $opv = $op . substr($curr_vars, $off, 1);\n\n\t\t\t\t# Ignore operators passed as parameters.\n\t\t\t\tif ($op_type ne 'V' &&\n\t\t\t\t    $ca =~ /\\s$/ && $cc =~ /^\\s*,/) {\n\n#\t\t\t\t# Ignore comments\n#\t\t\t\t} elsif ($op =~ /^$;+$/) {\n\n\t\t\t\t# ; should have either the end of line or a space or \\ after it\n\t\t\t\t} elsif ($op eq ';') {\n\t\t\t\t\tif ($ctx !~ /.x[WEBC]/ &&\n\t\t\t\t\t    $cc !~ /^\\\\/ && $cc !~ /^;/) {\n\t\t\t\t\t\tERROR(\"space required after that '$op' $at\\n\" . $hereptr);\n\t\t\t\t\t}\n\n\t\t\t\t# // is a comment\n\t\t\t\t} elsif ($op eq '//') {\n\n\t\t\t\t# No spaces for:\n\t\t\t\t#   ->\n\t\t\t\t#   :   when part of a bitfield\n\t\t\t\t} elsif ($op eq '->' || $opv eq ':B') {\n\t\t\t\t\tif ($ctx =~ /Wx.|.xW/) {\n\t\t\t\t\t\tERROR(\"spaces prohibited around that '$op' $at\\n\" . $hereptr);\n\t\t\t\t\t}\n\n\t\t\t\t# , must have a space on the right.\n\t\t\t\t} elsif ($op eq ',') {\n\t\t\t\t\tif ($ctx !~ /.x[WEC]/ && $cc !~ /^}/) {\n\t\t\t\t\t\tERROR(\"space required after that '$op' $at\\n\" . $hereptr);\n\t\t\t\t\t}\n\n\t\t\t\t# '*' as part of a type definition -- reported already.\n\t\t\t\t} elsif ($opv eq '*_') {\n\t\t\t\t\t#warn \"'*' is part of type\\n\";\n\n\t\t\t\t# unary operators should have a space before and\n\t\t\t\t# none after.  May be left adjacent to another\n\t\t\t\t# unary operator, or a cast\n\t\t\t\t} elsif ($op eq '!' || $op eq '~' ||\n\t\t\t\t\t $opv eq '*U' || $opv eq '-U' ||\n\t\t\t\t\t $opv eq '&U' || $opv eq '&&U') {\n\t\t\t\t\tif ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\\)|!|~|\\*|-|\\&|\\||\\+\\+|\\-\\-|\\{)$/) {\n\t\t\t\t\t\tERROR(\"space required before that '$op' $at\\n\" . $hereptr);\n\t\t\t\t\t}\n\t\t\t\t\tif ($op eq '*' && $cc =~/\\s*$Modifier\\b/) {\n\t\t\t\t\t\t# A unary '*' may be const\n\n\t\t\t\t\t} elsif ($ctx =~ /.xW/) {\n\t\t\t\t\t\tERROR(\"space prohibited after that '$op' $at\\n\" . $hereptr);\n\t\t\t\t\t}\n\n\t\t\t\t# unary ++ and unary -- are allowed no space on one side.\n\t\t\t\t} elsif ($op eq '++' or $op eq '--') {\n\t\t\t\t\tif ($ctx !~ /[WEOBC]x[^W]/ && $ctx !~ /[^W]x[WOBEC]/) {\n\t\t\t\t\t\tERROR(\"space required one side of that '$op' $at\\n\" . $hereptr);\n\t\t\t\t\t}\n\t\t\t\t\tif ($ctx =~ /Wx[BE]/ ||\n\t\t\t\t\t    ($ctx =~ /Wx./ && $cc =~ /^;/)) {\n\t\t\t\t\t\tERROR(\"space prohibited before that '$op' $at\\n\" . $hereptr);\n\t\t\t\t\t}\n\t\t\t\t\tif ($ctx =~ /ExW/) {\n\t\t\t\t\t\tERROR(\"space prohibited after that '$op' $at\\n\" . $hereptr);\n\t\t\t\t\t}\n\n\n\t\t\t\t# << and >> may either have or not have spaces both sides\n\t\t\t\t} elsif ($op eq '<<' or $op eq '>>' or\n\t\t\t\t\t $op eq '&' or $op eq '^' or $op eq '|' or\n\t\t\t\t\t $op eq '+' or $op eq '-' or\n\t\t\t\t\t $op eq '*' or $op eq '/' or\n\t\t\t\t\t $op eq '%')\n\t\t\t\t{\n\t\t\t\t\tif ($ctx =~ /Wx[^WCE]|[^WCE]xW/) {\n\t\t\t\t\t\tERROR(\"need consistent spacing around '$op' $at\\n\" .\n\t\t\t\t\t\t\t$hereptr);\n\t\t\t\t\t}\n\n\t\t\t\t# A colon needs no spaces before when it is\n\t\t\t\t# terminating a case value or a label.\n\t\t\t\t} elsif ($opv eq ':C' || $opv eq ':L') {\n\t\t\t\t\tif ($ctx =~ /Wx./) {\n\t\t\t\t\t\tERROR(\"space prohibited before that '$op' $at\\n\" . $hereptr);\n\t\t\t\t\t}\n\n\t\t\t\t# All the others need spaces both sides.\n\t\t\t\t} elsif ($ctx !~ /[EWC]x[CWE]/) {\n\t\t\t\t\tmy $ok = 0;\n\n\t\t\t\t\t# Ignore email addresses <foo@bar>\n\t\t\t\t\tif (($op eq '<' &&\n\t\t\t\t\t     $cc =~ /^\\S+\\@\\S+>/) ||\n\t\t\t\t\t    ($op eq '>' &&\n\t\t\t\t\t     $ca =~ /<\\S+\\@\\S+$/))\n\t\t\t\t\t{\n\t\t\t\t\t    \t$ok = 1;\n\t\t\t\t\t}\n\n\t\t\t\t\t# Ignore ?:\n\t\t\t\t\tif (($opv eq ':O' && $ca =~ /\\?$/) ||\n\t\t\t\t\t    ($op eq '?' && $cc =~ /^:/)) {\n\t\t\t\t\t    \t$ok = 1;\n\t\t\t\t\t}\n\n\t\t\t\t\tif ($ok == 0) {\n\t\t\t\t\t\tERROR(\"spaces required around that '$op' $at\\n\" . $hereptr);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t$off += length($elements[$n + 1]);\n\t\t\t}\n\t\t}\n\n# check for multiple assignments\n\t\tif ($line =~ /^.\\s*$Lval\\s*=\\s*$Lval\\s*=(?!=)/) {\n\t\t\tCHK(\"multiple assignments should be avoided\\n\" . $herecurr);\n\t\t}\n\n## # check for multiple declarations, allowing for a function declaration\n## # continuation.\n## \t\tif ($line =~ /^.\\s*$Type\\s+$Ident(?:\\s*=[^,{]*)?\\s*,\\s*$Ident.*/ &&\n## \t\t    $line !~ /^.\\s*$Type\\s+$Ident(?:\\s*=[^,{]*)?\\s*,\\s*$Type\\s*$Ident.*/) {\n##\n## \t\t\t# Remove any bracketed sections to ensure we do not\n## \t\t\t# falsly report the parameters of functions.\n## \t\t\tmy $ln = $line;\n## \t\t\twhile ($ln =~ s/\\([^\\(\\)]*\\)//g) {\n## \t\t\t}\n## \t\t\tif ($ln =~ /,/) {\n## \t\t\t\tWARN(\"declaring multiple variables together should be avoided\\n\" . $herecurr);\n## \t\t\t}\n## \t\t}\n\n#need space before brace following if, while, etc\n\t\tif (($line =~ /\\(.*\\){/ && $line !~ /\\($Type\\){/) ||\n\t\t    $line =~ /do{/) {\n\t\t\tERROR(\"space required before the open brace '{'\\n\" . $herecurr);\n\t\t}\n\n# closing brace should have a space following it when it has anything\n# on the line\n\t\tif ($line =~ /}(?!(?:,|;|\\)))\\S/) {\n\t\t\tERROR(\"space required after that close brace '}'\\n\" . $herecurr);\n\t\t}\n\n# check spacing on square brackets\n\t\tif ($line =~ /\\[\\s/ && $line !~ /\\[\\s*$/) {\n\t\t\tERROR(\"space prohibited after that open square bracket '['\\n\" . $herecurr);\n\t\t}\n\t\tif ($line =~ /\\s\\]/) {\n\t\t\tERROR(\"space prohibited before that close square bracket ']'\\n\" . $herecurr);\n\t\t}\n\n# check spacing on parentheses\n\t\tif ($line =~ /\\(\\s/ && $line !~ /\\(\\s*(?:\\\\)?$/ &&\n\t\t    $line !~ /for\\s*\\(\\s+;/) {\n\t\t\tERROR(\"space prohibited after that open parenthesis '('\\n\" . $herecurr);\n\t\t}\n\t\tif ($line =~ /(\\s+)\\)/ && $line !~ /^.\\s*\\)/ &&\n\t\t    $line !~ /for\\s*\\(.*;\\s+\\)/ &&\n\t\t    $line !~ /:\\s+\\)/) {\n\t\t\tERROR(\"space prohibited before that close parenthesis ')'\\n\" . $herecurr);\n\t\t}\n\n#goto labels aren't indented, allow a single space however\n\t\tif ($line=~/^.\\s+[A-Za-z\\d_]+:(?![0-9]+)/ and\n\t\t   !($line=~/^. [A-Za-z\\d_]+:/) and !($line=~/^.\\s+default:/)) {\n\t\t\tWARN(\"labels should not be indented\\n\" . $herecurr);\n\t\t}\n\n# Return is not a function.\n\t\tif (defined($stat) && $stat =~ /^.\\s*return(\\s*)(\\(.*);/s) {\n\t\t\tmy $spacing = $1;\n\t\t\tmy $value = $2;\n\n\t\t\t# Flatten any parentheses\n\t\t\t$value =~ s/\\(/ \\(/g;\n\t\t\t$value =~ s/\\)/\\) /g;\n\t\t\twhile ($value =~ s/\\[[^\\{\\}]*\\]/1/ ||\n\t\t\t       $value !~ /(?:$Ident|-?$Constant)\\s*\n\t\t\t\t\t     $Compare\\s*\n\t\t\t\t\t     (?:$Ident|-?$Constant)/x &&\n\t\t\t       $value =~ s/\\([^\\(\\)]*\\)/1/) {\n\t\t\t}\n#print \"value<$value>\\n\";\n\t\t\tif ($value =~ /^\\s*(?:$Ident|-?$Constant)\\s*$/) {\n\t\t\t\tERROR(\"return is not a function, parentheses are not required\\n\" . $herecurr);\n\n\t\t\t} elsif ($spacing !~ /\\s+/) {\n\t\t\t\tERROR(\"space required before the open parenthesis '('\\n\" . $herecurr);\n\t\t\t}\n\t\t}\n# Return of what appears to be an errno should normally be -'ve\n\t\tif ($line =~ /^.\\s*return\\s*(E[A-Z]*)\\s*;/) {\n\t\t\tmy $name = $1;\n\t\t\tif ($name ne 'EOF' && $name ne 'ERROR') {\n\t\t\t\tWARN(\"return of an errno should typically be -ve (return -$1)\\n\" . $herecurr);\n\t\t\t}\n\t\t}\n\n# Need a space before open parenthesis after if, while etc\n\t\tif ($line=~/\\b(if|while|for|switch)\\(/) {\n\t\t\tERROR(\"space required before the open parenthesis '('\\n\" . $herecurr);\n\t\t}\n\n# Check for illegal assignment in if conditional -- and check for trailing\n# statements after the conditional.\n\t\tif ($line =~ /do\\s*(?!{)/) {\n\t\t\tmy ($stat_next) = ctx_statement_block($line_nr_next,\n\t\t\t\t\t\t$remain_next, $off_next);\n\t\t\t$stat_next =~ s/\\n./\\n /g;\n\t\t\t##print \"stat<$stat> stat_next<$stat_next>\\n\";\n\n\t\t\tif ($stat_next =~ /^\\s*while\\b/) {\n\t\t\t\t# If the statement carries leading newlines,\n\t\t\t\t# then count those as offsets.\n\t\t\t\tmy ($whitespace) =\n\t\t\t\t\t($stat_next =~ /^((?:\\s*\\n[+-])*\\s*)/s);\n\t\t\t\tmy $offset =\n\t\t\t\t\tstatement_rawlines($whitespace) - 1;\n\n\t\t\t\t$suppress_whiletrailers{$line_nr_next +\n\t\t\t\t\t\t\t\t$offset} = 1;\n\t\t\t}\n\t\t}\n\t\tif (!defined $suppress_whiletrailers{$linenr} &&\n\t\t    $line =~ /\\b(?:if|while|for)\\s*\\(/ && $line !~ /^.\\s*#/) {\n\t\t\tmy ($s, $c) = ($stat, $cond);\n\n\t\t\tif ($c =~ /\\bif\\s*\\(.*[^<>!=]=[^=].*/s) {\n\t\t\t\tERROR(\"do not use assignment in if condition\\n\" . $herecurr);\n\t\t\t}\n\n\t\t\t# Find out what is on the end of the line after the\n\t\t\t# conditional.\n\t\t\tsubstr($s, 0, length($c), '');\n\t\t\t$s =~ s/\\n.*//g;\n\t\t\t$s =~ s/$;//g; \t# Remove any comments\n\t\t\tif (length($c) && $s !~ /^\\s*{?\\s*\\\\*\\s*$/ &&\n\t\t\t    $c !~ /}\\s*while\\s*/)\n\t\t\t{\n\t\t\t\t# Find out how long the conditional actually is.\n\t\t\t\tmy @newlines = ($c =~ /\\n/gs);\n\t\t\t\tmy $cond_lines = 1 + $#newlines;\n\t\t\t\tmy $stat_real = '';\n\n\t\t\t\t$stat_real = raw_line($linenr, $cond_lines)\n\t\t\t\t\t\t\t. \"\\n\" if ($cond_lines);\n\t\t\t\tif (defined($stat_real) && $cond_lines > 1) {\n\t\t\t\t\t$stat_real = \"[...]\\n$stat_real\";\n\t\t\t\t}\n\n\t\t\t\tERROR(\"trailing statements should be on next line\\n\" . $herecurr . $stat_real);\n\t\t\t}\n\t\t}\n\n# Check for bitwise tests written as boolean\n\t\tif ($line =~ /\n\t\t\t(?:\n\t\t\t\t(?:\\[|\\(|\\&\\&|\\|\\|)\n\t\t\t\t\\s*0[xX][0-9]+\\s*\n\t\t\t\t(?:\\&\\&|\\|\\|)\n\t\t\t|\n\t\t\t\t(?:\\&\\&|\\|\\|)\n\t\t\t\t\\s*0[xX][0-9]+\\s*\n\t\t\t\t(?:\\&\\&|\\|\\||\\)|\\])\n\t\t\t)/x)\n\t\t{\n\t\t\tWARN(\"boolean test with hexadecimal, perhaps just 1 \\& or \\|?\\n\" . $herecurr);\n\t\t}\n\n# if and else should not have general statements after it\n\t\tif ($line =~ /^.\\s*(?:}\\s*)?else\\b(.*)/) {\n\t\t\tmy $s = $1;\n\t\t\t$s =~ s/$;//g; \t# Remove any comments\n\t\t\tif ($s !~ /^\\s*(?:\\sif|(?:{|)\\s*\\\\?\\s*$)/) {\n\t\t\t\tERROR(\"trailing statements should be on next line\\n\" . $herecurr);\n\t\t\t}\n\t\t}\n# if should not continue a brace\n\t\tif ($line =~ /}\\s*if\\b/) {\n\t\t\tERROR(\"trailing statements should be on next line\\n\" .\n\t\t\t\t$herecurr);\n\t\t}\n# case and default should not have general statements after them\n\t\tif ($line =~ /^.\\s*(?:case\\s*.*|default\\s*):/g &&\n\t\t    $line !~ /\\G(?:\n\t\t\t(?:\\s*$;*)(?:\\s*{)?(?:\\s*$;*)(?:\\s*\\\\)?\\s*$|\n\t\t\t\\s*return\\s+\n\t\t    )/xg)\n\t\t{\n\t\t\tERROR(\"trailing statements should be on next line\\n\" . $herecurr);\n\t\t}\n\n\t\t# Check for }<nl>else {, these must be at the same\n\t\t# indent level to be relevant to each other.\n\t\tif ($prevline=~/}\\s*$/ and $line=~/^.\\s*else\\s*/ and\n\t\t\t\t\t\t$previndent == $indent) {\n\t\t\tERROR(\"else should follow close brace '}'\\n\" . $hereprev);\n\t\t}\n\n\t\tif ($prevline=~/}\\s*$/ and $line=~/^.\\s*while\\s*/ and\n\t\t\t\t\t\t$previndent == $indent) {\n\t\t\tmy ($s, $c) = ctx_statement_block($linenr, $realcnt, 0);\n\n\t\t\t# Find out what is on the end of the line after the\n\t\t\t# conditional.\n\t\t\tsubstr($s, 0, length($c), '');\n\t\t\t$s =~ s/\\n.*//g;\n\n\t\t\tif ($s =~ /^\\s*;/) {\n\t\t\t\tERROR(\"while should follow close brace '}'\\n\" . $hereprev);\n\t\t\t}\n\t\t}\n\n#studly caps, commented out until figure out how to distinguish between use of existing and adding new\n#\t\tif (($line=~/[\\w_][a-z\\d]+[A-Z]/) and !($line=~/print/)) {\n#\t\t    print \"No studly caps, use _\\n\";\n#\t\t    print \"$herecurr\";\n#\t\t    $clean = 0;\n#\t\t}\n\n#no spaces allowed after \\ in define\n\t\tif ($line=~/\\#\\s*define.*\\\\\\s$/) {\n\t\t\tWARN(\"Whitepspace after \\\\ makes next lines useless\\n\" . $herecurr);\n\t\t}\n\n#warn if <asm/foo.h> is #included and <linux/foo.h> is available (uses RAW line)\n\t\tif ($tree && $rawline =~ m{^.\\s*\\#\\s*include\\s*\\<asm\\/(.*)\\.h\\>}) {\n\t\t\tmy $file = \"$1.h\";\n\t\t\tmy $checkfile = \"include/linux/$file\";\n\t\t\tif (-f \"$root/$checkfile\" &&\n\t\t\t    $realfile ne $checkfile &&\n\t\t\t    $1 !~ /$allowed_asm_includes/)\n\t\t\t{\n\t\t\t\tif ($realfile =~ m{^arch/}) {\n\t\t\t\t\tCHK(\"Consider using #include <linux/$file> instead of <asm/$file>\\n\" . $herecurr);\n\t\t\t\t} else {\n\t\t\t\t\tWARN(\"Use #include <linux/$file> instead of <asm/$file>\\n\" . $herecurr);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n# multi-statement macros should be enclosed in a do while loop, grab the\n# first statement and ensure its the whole macro if its not enclosed\n# in a known good container\n\t\tif ($realfile !~ m@/vmlinux.lds.h$@ &&\n\t\t    $line =~ /^.\\s*\\#\\s*define\\s*$Ident(\\()?/) {\n\t\t\tmy $ln = $linenr;\n\t\t\tmy $cnt = $realcnt;\n\t\t\tmy ($off, $dstat, $dcond, $rest);\n\t\t\tmy $ctx = '';\n\n\t\t\tmy $args = defined($1);\n\n\t\t\t# Find the end of the macro and limit our statement\n\t\t\t# search to that.\n\t\t\twhile ($cnt > 0 && defined $lines[$ln - 1] &&\n\t\t\t\t$lines[$ln - 1] =~ /^(?:-|..*\\\\$)/)\n\t\t\t{\n\t\t\t\t$ctx .= $rawlines[$ln - 1] . \"\\n\";\n\t\t\t\t$cnt-- if ($lines[$ln - 1] !~ /^-/);\n\t\t\t\t$ln++;\n\t\t\t}\n\t\t\t$ctx .= $rawlines[$ln - 1];\n\n\t\t\t($dstat, $dcond, $ln, $cnt, $off) =\n\t\t\t\tctx_statement_block($linenr, $ln - $linenr + 1, 0);\n\t\t\t#print \"dstat<$dstat> dcond<$dcond> cnt<$cnt> off<$off>\\n\";\n\t\t\t#print \"LINE<$lines[$ln-1]> len<\" . length($lines[$ln-1]) . \"\\n\";\n\n\t\t\t# Extract the remainder of the define (if any) and\n\t\t\t# rip off surrounding spaces, and trailing \\'s.\n\t\t\t$rest = '';\n\t\t\twhile ($off != 0 || ($cnt > 0 && $rest =~ /\\\\\\s*$/)) {\n\t\t\t\t#print \"ADDING cnt<$cnt> $off <\" . substr($lines[$ln - 1], $off) . \"> rest<$rest>\\n\";\n\t\t\t\tif ($off != 0 || $lines[$ln - 1] !~ /^-/) {\n\t\t\t\t\t$rest .= substr($lines[$ln - 1], $off) . \"\\n\";\n\t\t\t\t\t$cnt--;\n\t\t\t\t}\n\t\t\t\t$ln++;\n\t\t\t\t$off = 0;\n\t\t\t}\n\t\t\t$rest =~ s/\\\\\\n.//g;\n\t\t\t$rest =~ s/^\\s*//s;\n\t\t\t$rest =~ s/\\s*$//s;\n\n\t\t\t# Clean up the original statement.\n\t\t\tif ($args) {\n\t\t\t\tsubstr($dstat, 0, length($dcond), '');\n\t\t\t} else {\n\t\t\t\t$dstat =~ s/^.\\s*\\#\\s*define\\s+$Ident\\s*//;\n\t\t\t}\n\t\t\t$dstat =~ s/$;//g;\n\t\t\t$dstat =~ s/\\\\\\n.//g;\n\t\t\t$dstat =~ s/^\\s*//s;\n\t\t\t$dstat =~ s/\\s*$//s;\n\n\t\t\t# Flatten any parentheses and braces\n\t\t\twhile ($dstat =~ s/\\([^\\(\\)]*\\)/1/ ||\n\t\t\t       $dstat =~ s/\\{[^\\{\\}]*\\}/1/ ||\n\t\t\t       $dstat =~ s/\\[[^\\{\\}]*\\]/1/)\n\t\t\t{\n\t\t\t}\n\n\t\t\tmy $exceptions = qr{\n\t\t\t\t$Declare|\n\t\t\t\tmodule_param_named|\n\t\t\t\tMODULE_PARAM_DESC|\n\t\t\t\tDECLARE_PER_CPU|\n\t\t\t\tDEFINE_PER_CPU|\n\t\t\t\t__typeof__\\(|\n\t\t\t\tunion|\n\t\t\t\tstruct|\n\t\t\t\t\\.$Ident\\s*=\\s*|\n\t\t\t\t^\\\"|\\\"$\n\t\t\t}x;\n\t\t\t#print \"REST<$rest> dstat<$dstat> ctx<$ctx>\\n\";\n\t\t\tif ($rest ne '' && $rest ne ',') {\n\t\t\t\tif ($rest !~ /while\\s*\\(/ &&\n\t\t\t\t    $dstat !~ /$exceptions/)\n\t\t\t\t{\n\t\t\t\t\tERROR(\"Macros with multiple statements should be enclosed in a do - while loop\\n\" . \"$here\\n$ctx\\n\");\n\t\t\t\t}\n\n\t\t\t} elsif ($ctx !~ /;/) {\n\t\t\t\tif ($dstat ne '' &&\n\t\t\t\t    $dstat !~ /^(?:$Ident|-?$Constant)$/ &&\n\t\t\t\t    $dstat !~ /$exceptions/ &&\n\t\t\t\t    $dstat !~ /^\\.$Ident\\s*=/ &&\n\t\t\t\t    $dstat =~ /$Operators/)\n\t\t\t\t{\n\t\t\t\t\tERROR(\"Macros with complex values should be enclosed in parenthesis\\n\" . \"$here\\n$ctx\\n\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n# make sure symbols are always wrapped with VMLINUX_SYMBOL() ...\n# all assignments may have only one of the following with an assignment:\n#\t.\n#\tALIGN(...)\n#\tVMLINUX_SYMBOL(...)\n\t\tif ($realfile eq 'vmlinux.lds.h' && $line =~ /(?:(?:^|\\s)$Ident\\s*=|=\\s*$Ident(?:\\s|$))/) {\n\t\t\tWARN(\"vmlinux.lds.h needs VMLINUX_SYMBOL() around C-visible symbols\\n\" . $herecurr);\n\t\t}\n\n# check for redundant bracing round if etc\n\t\tif ($line =~ /(^.*)\\bif\\b/ && $1 !~ /else\\s*$/) {\n\t\t\tmy ($level, $endln, @chunks) =\n\t\t\t\tctx_statement_full($linenr, $realcnt, 1);\n\t\t\t#print \"chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\\n\";\n\t\t\t#print \"APW: <<$chunks[1][0]>><<$chunks[1][1]>>\\n\";\n\t\t\tif ($#chunks > 0 && $level == 0) {\n\t\t\t\tmy $allowed = 0;\n\t\t\t\tmy $seen = 0;\n\t\t\t\tmy $herectx = $here . \"\\n\";\n\t\t\t\tmy $ln = $linenr - 1;\n\t\t\t\tfor my $chunk (@chunks) {\n\t\t\t\t\tmy ($cond, $block) = @{$chunk};\n\n\t\t\t\t\t# If the condition carries leading newlines, then count those as offsets.\n\t\t\t\t\tmy ($whitespace) = ($cond =~ /^((?:\\s*\\n[+-])*\\s*)/s);\n\t\t\t\t\tmy $offset = statement_rawlines($whitespace) - 1;\n\n\t\t\t\t\t#print \"COND<$cond> whitespace<$whitespace> offset<$offset>\\n\";\n\n\t\t\t\t\t# We have looked at and allowed this specific line.\n\t\t\t\t\t$suppress_ifbraces{$ln + $offset} = 1;\n\n\t\t\t\t\t$herectx .= \"$rawlines[$ln + $offset]\\n[...]\\n\";\n\t\t\t\t\t$ln += statement_rawlines($block) - 1;\n\n\t\t\t\t\tsubstr($block, 0, length($cond), '');\n\n\t\t\t\t\t$seen++ if ($block =~ /^\\s*{/);\n\n\t\t\t\t\t#print \"cond<$cond> block<$block> allowed<$allowed>\\n\";\n\t\t\t\t\tif (statement_lines($cond) > 1) {\n\t\t\t\t\t\t#print \"APW: ALLOWED: cond<$cond>\\n\";\n\t\t\t\t\t\t$allowed = 1;\n\t\t\t\t\t}\n\t\t\t\t\tif ($block =~/\\b(?:if|for|while)\\b/) {\n\t\t\t\t\t\t#print \"APW: ALLOWED: block<$block>\\n\";\n\t\t\t\t\t\t$allowed = 1;\n\t\t\t\t\t}\n\t\t\t\t\tif (statement_block_size($block) > 1) {\n\t\t\t\t\t\t#print \"APW: ALLOWED: lines block<$block>\\n\";\n\t\t\t\t\t\t$allowed = 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif ($seen && !$allowed) {\n\t\t\t\t\tWARN(\"braces {} are not necessary for any arm of this statement\\n\" . $herectx);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (!defined $suppress_ifbraces{$linenr - 1} &&\n\t\t\t\t\t$line =~ /\\b(if|while|for|else)\\b/) {\n\t\t\tmy $allowed = 0;\n\n\t\t\t# Check the pre-context.\n\t\t\tif (substr($line, 0, $-[0]) =~ /(\\}\\s*)$/) {\n\t\t\t\t#print \"APW: ALLOWED: pre<$1>\\n\";\n\t\t\t\t$allowed = 1;\n\t\t\t}\n\n\t\t\tmy ($level, $endln, @chunks) =\n\t\t\t\tctx_statement_full($linenr, $realcnt, $-[0]);\n\n\t\t\t# Check the condition.\n\t\t\tmy ($cond, $block) = @{$chunks[0]};\n\t\t\t#print \"CHECKING<$linenr> cond<$cond> block<$block>\\n\";\n\t\t\tif (defined $cond) {\n\t\t\t\tsubstr($block, 0, length($cond), '');\n\t\t\t}\n\t\t\tif (statement_lines($cond) > 1) {\n\t\t\t\t#print \"APW: ALLOWED: cond<$cond>\\n\";\n\t\t\t\t$allowed = 1;\n\t\t\t}\n\t\t\tif ($block =~/\\b(?:if|for|while)\\b/) {\n\t\t\t\t#print \"APW: ALLOWED: block<$block>\\n\";\n\t\t\t\t$allowed = 1;\n\t\t\t}\n\t\t\tif (statement_block_size($block) > 1) {\n\t\t\t\t#print \"APW: ALLOWED: lines block<$block>\\n\";\n\t\t\t\t$allowed = 1;\n\t\t\t}\n\t\t\t# Check the post-context.\n\t\t\tif (defined $chunks[1]) {\n\t\t\t\tmy ($cond, $block) = @{$chunks[1]};\n\t\t\t\tif (defined $cond) {\n\t\t\t\t\tsubstr($block, 0, length($cond), '');\n\t\t\t\t}\n\t\t\t\tif ($block =~ /^\\s*\\{/) {\n\t\t\t\t\t#print \"APW: ALLOWED: chunk-1 block<$block>\\n\";\n\t\t\t\t\t$allowed = 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ($level == 0 && $block =~ /^\\s*\\{/ && !$allowed) {\n\t\t\t\tmy $herectx = $here . \"\\n\";;\n\t\t\t\tmy $cnt = statement_rawlines($block);\n\n\t\t\t\tfor (my $n = 0; $n < $cnt; $n++) {\n\t\t\t\t\t$herectx .= raw_line($linenr, $n) . \"\\n\";;\n\t\t\t\t}\n\n\t\t\t\tWARN(\"braces {} are not necessary for single statement blocks\\n\" . $herectx);\n\t\t\t}\n\t\t}\n\n# don't include deprecated include files (uses RAW line)\n\t\tfor my $inc (@dep_includes) {\n\t\t\tif ($rawline =~ m@^.\\s*\\#\\s*include\\s*\\<$inc>@) {\n\t\t\t\tERROR(\"Don't use <$inc>: see Documentation/feature-removal-schedule.txt\\n\" . $herecurr);\n\t\t\t}\n\t\t}\n\n# don't use deprecated functions\n\t\tfor my $func (@dep_functions) {\n\t\t\tif ($line =~ /\\b$func\\b/) {\n\t\t\t\tERROR(\"Don't use $func(): see Documentation/feature-removal-schedule.txt\\n\" . $herecurr);\n\t\t\t}\n\t\t}\n\n# no volatiles please\n\t\tmy $asm_volatile = qr{\\b(__asm__|asm)\\s+(__volatile__|volatile)\\b};\n\t\tif ($line =~ /\\bvolatile\\b/ && $line !~ /$asm_volatile/) {\n\t\t\tWARN(\"Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt\\n\" . $herecurr);\n\t\t}\n\n# warn about #if 0\n\t\tif ($line =~ /^.\\s*\\#\\s*if\\s+0\\b/) {\n\t\t\tCHK(\"if this code is redundant consider removing it\\n\" .\n\t\t\t\t$herecurr);\n\t\t}\n\n# check for needless kfree() checks\n\t\tif ($prevline =~ /\\bif\\s*\\(([^\\)]*)\\)/) {\n\t\t\tmy $expr = $1;\n\t\t\tif ($line =~ /\\bkfree\\(\\Q$expr\\E\\);/) {\n\t\t\t\tWARN(\"kfree(NULL) is safe this check is probably not required\\n\" . $hereprev);\n\t\t\t}\n\t\t}\n# check for needless usb_free_urb() checks\n\t\tif ($prevline =~ /\\bif\\s*\\(([^\\)]*)\\)/) {\n\t\t\tmy $expr = $1;\n\t\t\tif ($line =~ /\\busb_free_urb\\(\\Q$expr\\E\\);/) {\n\t\t\t\tWARN(\"usb_free_urb(NULL) is safe this check is probably not required\\n\" . $hereprev);\n\t\t\t}\n\t\t}\n\n# prefer usleep_range over udelay\n\t\tif ($line =~ /\\budelay\\s*\\(\\s*(\\w+)\\s*\\)/) {\n\t\t\t# ignore udelay's < 10, however\n\t\t\tif (! (($1 =~ /(\\d+)/) && ($1 < 10)) ) {\n\t\t\t\tCHK(\"usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt\\n\" . $line);\n\t\t\t}\n\t\t}\n\n# warn about unexpectedly long msleep's\n\t\tif ($line =~ /\\bmsleep\\s*\\((\\d+)\\);/) {\n\t\t\tif ($1 < 20) {\n\t\t\t\tWARN(\"msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.txt\\n\" . $line);\n\t\t\t}\n\t\t}\n\n# warn about #ifdefs in C files\n#\t\tif ($line =~ /^.\\s*\\#\\s*if(|n)def/ && ($realfile =~ /\\.c$/)) {\n#\t\t\tprint \"#ifdef in C files should be avoided\\n\";\n#\t\t\tprint \"$herecurr\";\n#\t\t\t$clean = 0;\n#\t\t}\n\n# warn about spacing in #ifdefs\n\t\tif ($line =~ /^.\\s*\\#\\s*(ifdef|ifndef|elif)\\s\\s+/) {\n\t\t\tERROR(\"exactly one space required after that #$1\\n\" . $herecurr);\n\t\t}\n\n# check for spinlock_t definitions without a comment.\n\t\tif ($line =~ /^.\\s*(struct\\s+mutex|spinlock_t)\\s+\\S+;/ ||\n\t\t    $line =~ /^.\\s*(DEFINE_MUTEX)\\s*\\(/) {\n\t\t\tmy $which = $1;\n\t\t\tif (!ctx_has_comment($first_line, $linenr)) {\n\t\t\t\tCHK(\"$1 definition without comment\\n\" . $herecurr);\n\t\t\t}\n\t\t}\n# check for memory barriers without a comment.\n\t\tif ($line =~ /\\b(mb|rmb|wmb|read_barrier_depends|smp_mb|smp_rmb|smp_wmb|smp_read_barrier_depends)\\(/) {\n\t\t\tif (!ctx_has_comment($first_line, $linenr)) {\n\t\t\t\tCHK(\"memory barrier without comment\\n\" . $herecurr);\n\t\t\t}\n\t\t}\n# check of hardware specific defines\n\t\tif ($line =~ m@^.\\s*\\#\\s*if.*\\b(__i386__|__powerpc64__|__sun__|__s390x__)\\b@ && $realfile !~ m@include/asm-@) {\n\t\t\tCHK(\"architecture specific defines should be avoided\\n\" .  $herecurr);\n\t\t}\n\n# Check that the storage class is at the beginning of a declaration\n\t\tif ($line =~ /\\b$Storage\\b/ && $line !~ /^.\\s*$Storage\\b/) {\n\t\t\tWARN(\"storage class should be at the beginning of the declaration\\n\" . $herecurr)\n\t\t}\n\n# check the location of the inline attribute, that it is between\n# storage class and type.\n\t\tif ($line =~ /\\b$Type\\s+$Inline\\b/ ||\n\t\t    $line =~ /\\b$Inline\\s+$Storage\\b/) {\n\t\t\tERROR(\"inline keyword should sit between storage class and type\\n\" . $herecurr);\n\t\t}\n\n# Check for __inline__ and __inline, prefer inline\n\t\tif ($line =~ /\\b(__inline__|__inline)\\b/) {\n\t\t\tWARN(\"plain inline is preferred over $1\\n\" . $herecurr);\n\t\t}\n\n# Check for __attribute__ packed, prefer __packed\n\t\tif ($line =~ /\\b__attribute__\\s*\\(\\s*\\(.*\\bpacked\\b/) {\n\t\t\tWARN(\"__packed is preferred over __attribute__((packed))\\n\" . $herecurr);\n\t\t}\n\n# check for sizeof(&)\n\t\tif ($line =~ /\\bsizeof\\s*\\(\\s*\\&/) {\n\t\t\tWARN(\"sizeof(& should be avoided\\n\" . $herecurr);\n\t\t}\n\n# check for line continuations in quoted strings with odd counts of \"\n\t\tif ($rawline =~ /\\\\$/ && $rawline =~ tr/\"/\"/ % 2) {\n\t\t\tWARN(\"Avoid line continuations in quoted strings\\n\" . $herecurr);\n\t\t}\n\n# check for new externs in .c files.\n\t\tif ($realfile =~ /\\.c$/ && defined $stat &&\n\t\t    $stat =~ /^.\\s*(?:extern\\s+)?$Type\\s+($Ident)(\\s*)\\(/s)\n\t\t{\n\t\t\tmy $function_name = $1;\n\t\t\tmy $paren_space = $2;\n\n\t\t\tmy $s = $stat;\n\t\t\tif (defined $cond) {\n\t\t\t\tsubstr($s, 0, length($cond), '');\n\t\t\t}\n\t\t\tif ($s =~ /^\\s*;/ &&\n\t\t\t    $function_name ne 'uninitialized_var')\n\t\t\t{\n\t\t\t\tWARN(\"externs should be avoided in .c files\\n\" .  $herecurr);\n\t\t\t}\n\n\t\t\tif ($paren_space =~ /\\n/) {\n\t\t\t\tWARN(\"arguments for function declarations should follow identifier\\n\" . $herecurr);\n\t\t\t}\n\n\t\t} elsif ($realfile =~ /\\.c$/ && defined $stat &&\n\t\t    $stat =~ /^.\\s*extern\\s+/)\n\t\t{\n\t\t\tWARN(\"externs should be avoided in .c files\\n\" .  $herecurr);\n\t\t}\n\n# checks for new __setup's\n\t\tif ($rawline =~ /\\b__setup\\(\"([^\"]*)\"/) {\n\t\t\tmy $name = $1;\n\n\t\t\tif (!grep(/$name/, @setup_docs)) {\n\t\t\t\tCHK(\"__setup appears un-documented -- check Documentation/kernel-parameters.txt\\n\" . $herecurr);\n\t\t\t}\n\t\t}\n\n# check for pointless casting of kmalloc return\n\t\tif ($line =~ /\\*\\s*\\)\\s*[kv][czm]alloc(_node){0,1}\\b/) {\n\t\t\tWARN(\"unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\\n\" . $herecurr);\n\t\t}\n\n# check for multiple semicolons\n\t\tif ($line =~ /;\\s*;\\s*$/) {\n\t\t    WARN(\"Statements terminations use 1 semicolon\\n\" . $herecurr);\n\t\t}\n\n# check for gcc specific __FUNCTION__\n\t\tif ($line =~ /__FUNCTION__/) {\n\t\t\tWARN(\"__func__ should be used instead of gcc specific __FUNCTION__\\n\"  . $herecurr);\n\t\t}\n\n# check for semaphores initialized locked\n\t\tif ($line =~ /^.\\s*sema_init.+,\\W?0\\W?\\)/) {\n\t\t\tWARN(\"consider using a completion\\n\" . $herecurr);\n\n\t\t}\n# recommend kstrto* over simple_strto*\n\t\tif ($line =~ /\\bsimple_(strto.*?)\\s*\\(/) {\n\t\t\tWARN(\"consider using kstrto* in preference to simple_$1\\n\" . $herecurr);\n\t\t}\n# check for __initcall(), use device_initcall() explicitly please\n\t\tif ($line =~ /^.\\s*__initcall\\s*\\(/) {\n\t\t\tWARN(\"please use device_initcall() instead of __initcall()\\n\" . $herecurr);\n\t\t}\n# check for various ops structs, ensure they are const.\n\t\tmy $struct_ops = qr{acpi_dock_ops|\n\t\t\t\taddress_space_operations|\n\t\t\t\tbacklight_ops|\n\t\t\t\tblock_device_operations|\n\t\t\t\tdentry_operations|\n\t\t\t\tdev_pm_ops|\n\t\t\t\tdma_map_ops|\n\t\t\t\textent_io_ops|\n\t\t\t\tfile_lock_operations|\n\t\t\t\tfile_operations|\n\t\t\t\thv_ops|\n\t\t\t\tide_dma_ops|\n\t\t\t\tintel_dvo_dev_ops|\n\t\t\t\titem_operations|\n\t\t\t\tiwl_ops|\n\t\t\t\tkgdb_arch|\n\t\t\t\tkgdb_io|\n\t\t\t\tkset_uevent_ops|\n\t\t\t\tlock_manager_operations|\n\t\t\t\tmicrocode_ops|\n\t\t\t\tmtrr_ops|\n\t\t\t\tneigh_ops|\n\t\t\t\tnlmsvc_binding|\n\t\t\t\tpci_raw_ops|\n\t\t\t\tpipe_buf_operations|\n\t\t\t\tplatform_hibernation_ops|\n\t\t\t\tplatform_suspend_ops|\n\t\t\t\tproto_ops|\n\t\t\t\trpc_pipe_ops|\n\t\t\t\tseq_operations|\n\t\t\t\tsnd_ac97_build_ops|\n\t\t\t\tsoc_pcmcia_socket_ops|\n\t\t\t\tstacktrace_ops|\n\t\t\t\tsysfs_ops|\n\t\t\t\ttty_operations|\n\t\t\t\tusb_mon_operations|\n\t\t\t\twd_ops}x;\n\t\tif ($line !~ /\\bconst\\b/ &&\n\t\t    $line =~ /\\bstruct\\s+($struct_ops)\\b/) {\n\t\t\tWARN(\"struct $1 should normally be const\\n\" .\n\t\t\t\t$herecurr);\n\t\t}\n\n# use of NR_CPUS is usually wrong\n# ignore definitions of NR_CPUS and usage to define arrays as likely right\n\t\tif ($line =~ /\\bNR_CPUS\\b/ &&\n\t\t    $line !~ /^.\\s*\\s*#\\s*if\\b.*\\bNR_CPUS\\b/ &&\n\t\t    $line !~ /^.\\s*\\s*#\\s*define\\b.*\\bNR_CPUS\\b/ &&\n\t\t    $line !~ /^.\\s*$Declare\\s.*\\[[^\\]]*NR_CPUS[^\\]]*\\]/ &&\n\t\t    $line !~ /\\[[^\\]]*\\.\\.\\.[^\\]]*NR_CPUS[^\\]]*\\]/ &&\n\t\t    $line !~ /\\[[^\\]]*NR_CPUS[^\\]]*\\.\\.\\.[^\\]]*\\]/)\n\t\t{\n\t\t\tWARN(\"usage of NR_CPUS is often wrong - consider using cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\\n\" . $herecurr);\n\t\t}\n\n# check for %L{u,d,i} in strings\n\t\tmy $string;\n\t\twhile ($line =~ /(?:^|\")([X\\t]*)(?:\"|$)/g) {\n\t\t\t$string = substr($rawline, $-[1], $+[1] - $-[1]);\n\t\t\t$string =~ s/%%/__/g;\n\t\t\tif ($string =~ /(?<!%)%L[udi]/) {\n\t\t\t\tWARN(\"\\%Ld/%Lu are not-standard C, use %lld/%llu\\n\" . $herecurr);\n\t\t\t\tlast;\n\t\t\t}\n\t\t}\n\n# whine mightly about in_atomic\n\t\tif ($line =~ /\\bin_atomic\\s*\\(/) {\n\t\t\tif ($realfile =~ m@^drivers/@) {\n\t\t\t\tERROR(\"do not use in_atomic in drivers\\n\" . $herecurr);\n\t\t\t} elsif ($realfile !~ m@^kernel/@) {\n\t\t\t\tWARN(\"use of in_atomic() is incorrect outside core kernel code\\n\" . $herecurr);\n\t\t\t}\n\t\t}\n\n# check for lockdep_set_novalidate_class\n\t\tif ($line =~ /^.\\s*lockdep_set_novalidate_class\\s*\\(/ ||\n\t\t    $line =~ /__lockdep_no_validate__\\s*\\)/ ) {\n\t\t\tif ($realfile !~ m@^kernel/lockdep@ &&\n\t\t\t    $realfile !~ m@^include/linux/lockdep@ &&\n\t\t\t    $realfile !~ m@^drivers/base/core@) {\n\t\t\t\tERROR(\"lockdep_no_validate class is reserved for device->mutex.\\n\" . $herecurr);\n\t\t\t}\n\t\t}\n\n\t\tif ($line =~ /debugfs_create_file.*S_IWUGO/ ||\n\t\t    $line =~ /DEVICE_ATTR.*S_IWUGO/ ) {\n\t\t\tWARN(\"Exporting world writable files is usually an error. Consider more restrictive permissions.\\n\" . $herecurr);\n\t\t}\n\n\t\t# Check for memset with swapped arguments\n\t\tif ($line =~ /memset.*\\,(\\ |)(0x|)0(\\ |0|)\\);/) {\n\t\t\tERROR(\"memset size is 3rd argument, not the second.\\n\" . $herecurr);\n\t\t}\n\t}\n\n\t# If we have no input at all, then there is nothing to report on\n\t# so just keep quiet.\n\tif ($#rawlines == -1) {\n\t\texit(0);\n\t}\n\n\t# In mailback mode only produce a report in the negative, for\n\t# things that appear to be patches.\n\tif ($mailback && ($clean == 1 || !$is_patch)) {\n\t\texit(0);\n\t}\n\n\t# This is not a patch, and we are are in 'no-patch' mode so\n\t# just keep quiet.\n\tif (!$chk_patch && !$is_patch) {\n\t\texit(0);\n\t}\n\n\tif (!$is_patch) {\n\t\tERROR(\"Does not appear to be a unified-diff format patch\\n\");\n\t}\n\tif ($is_patch && $chk_signoff && $signoff == 0) {\n\t\tERROR(\"Missing Signed-off-by: line(s)\\n\");\n\t}\n\n\tprint report_dump();\n\tif ($summary && !($clean == 1 && $quiet == 1)) {\n\t\tprint \"$filename \" if ($summary_file);\n\t\tprint \"total: $cnt_error errors, $cnt_warn warnings, \" .\n\t\t\t(($check)? \"$cnt_chk checks, \" : \"\") .\n\t\t\t\"$cnt_lines lines checked\\n\";\n\t\tprint \"\\n\" if ($quiet == 0);\n\t}\n\n\tif ($quiet == 0) {\n\t\t# If there were whitespace errors which cleanpatch can fix\n\t\t# then suggest that.\n\t\tif ($rpt_cleaners) {\n\t\t\tprint \"NOTE: whitespace errors detected, you may wish to use scripts/cleanpatch or\\n\";\n\t\t\tprint \"      scripts/cleanfile\\n\\n\";\n\t\t\t$rpt_cleaners = 0;\n\t\t}\n\t}\n\n\tif ($clean == 1 && $quiet == 0) {\n\t\tprint \"$vname has no obvious style problems and is ready for submission.\\n\"\n\t}\n\tif ($clean == 0 && $quiet == 0) {\n\t\tprint \"$vname has style problems, please review.  If any of these errors\\n\";\n\t\tprint \"are false positives report them to the maintainer, see\\n\";\n\t\tprint \"CHECKPATCH in MAINTAINERS.\\n\";\n\t}\n\n\treturn $clean;\n}\n"
  },
  {
    "path": "scripts/lio_target_passthru.sh",
    "content": "#!/bin/bash\n\nif [ $# -ne 1 ]; then\n\techo \"Usage: $0 initiator_iqn (to add to iSCSI ACL)\"\n\texit\nfi\n# Use $1 if defined, otherwise default to this IQN iniator addr\nINIT_IQN=${1:-iqn.1994-05.com.redhat:e284d58153b4}\n\n# Reference:\n# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=880576\n\nIQN=\"iqn.2019-03.com.mhvtl:target\"\n\nHBA=`lsscsi -H | awk '/mhvtl/ {print $1}' | sed -e 's/\\[//' -e 's/\\]//'`\n\n# Extract SCSI h:b:t:l of each dev\nSCSI_ADDR=`lsscsi $HBA | awk '{print $1}'`\n\ntargetcli /iscsi/ create $IQN\n\n# Setup LIO backing store - Walk each device, extract /dev/sg path\nfor dev in $SCSI_ADDR\ndo\n \tread -r hba channel id lun <<< `echo $dev | awk -F: '{print $1,$2,$3,$4}' | sed -e 's/\\[//' -e 's/\\]//g'`\n\n\t# Extract the SCSI Passthru device (/dev/sg) of this h:b:t:l\n\tPASSTHRU=`lsscsi -g $hba $channel $id $lun | awk '{print $7}'`\n\n\techo \"hba: $hba, Channel: $channel, SCSI ID: $id, SCSI LUN: $lun - scsi passthru path: $PASSTHRU\"\n\tMHVTL=$(printf \"h%db%dt%dl%d\" $hba $channel $id $lun)\n\n\tTLD=\"/sys/kernel/config/target/core/pscsi_0/mhVTL${MHVTL}\"\n\tmkdir -p $TLD\n\tuuidgen > $TLD/wwn/vpd_unit_serial\n\techo scsi_host_id=$hba,scsi_channel_id=$channel,scsi_target_id=$id,scsi_lun_id=$lun >  $TLD/control\n\techo $PASSTHRU > $TLD/udev_path\n\techo 1 > $TLD/enable\n\n\t# Map LIO backing store to mhVTL /dev/sgXX path\n\ttargetcli /iscsi/$IQN/tpg1/luns/ create /backstores/pscsi/mhVTL${MHVTL}\n#\ttargetcli ls\n#\tsleep 2\ndone\n\ntargetcli /iscsi/$IQN/tpg1/acls/ create $INIT_IQN\n\ntargetcli ls\n\n# Open up TCP port 3260 through iptables\n# CentOS7 anyway..\nfirewall-cmd --add-port 3260/tcp\n\n"
  },
  {
    "path": "scripts/mhvtl-1.4.ebuild",
    "content": "# Copyright 1999-2010 Gentoo Foundation\n# Distributed under the terms of the GNU General Public License v2\n# $Header:\n\nEAPI=\"2\"\n\ninherit linux-mod eutils\n\nMY_P=\"${PN}-2012-09-13\"\nDESCRIPTION=\"mhvtl module provides Virtual (SCSI) Tape Library\"\nHOMEPAGE=\"http://sites.google.com/site/linuxvtl2\"\nSRC_URI=\"http://sites.google.com/site/linuxvtl2/${MY_P}.tgz\"\n\nLICENSE=\"GPL-2\"\nSLOT=\"0\"\nKEYWORDS=\"~amd64 ~x86\"\nIUSE=\"doc\"\n\nDEPEND=\">=virtual/linux-sources-2.6.19\n\t\tsys-fs/lsscsi\n\t\tsys-libs/zlib\n\t\tsys-libs/lzo\n\t\tsys-apps/sg3_utils\"\nRDEPEND=\"\"\n\nMODULE_NAMES=\"mhvtl(block:${S}/kernel:${S}/kernel)\"\nBUILD_TARGETS=\"clean default\"\nMHVTL_HOME_PATH=/var/spool/media/vtl\n\npkg_setup() {\n\tCONFIG_CHECK=\"~BLK_DEV_SR ~CHR_DEV_SG\"\n\tcheck_extra_config\n\tBUILD_PARAMS=\"KDIR=${KV_DIR}\"\n\tlinux-mod_pkg_setup\n}\n\nsrc_prepare() {\n\tepatch \"${FILESDIR}/1.2-kerneldir.patch\"\n\tepatch \"${FILESDIR}/1.2-etc.patch\"\n\tepatch \"${FILESDIR}/1.2-make_vtl_media.patch\"\n\tepatch \"${FILESDIR}/1.2-mhvtl.patch\"\n}\n\nsrc_compile() {\n\temake clean || die\n\tlinux-mod_src_compile || die \"linux-mod_src_compile\"\n\temake MHVTL_HOME_PATH=${MHVTL_HOME_PATH} || die \"emake failed\"\n}\n\nsrc_install() {\n\tlinux-mod_src_install || die \"Error: installing module failed!\"\n\n\temake MHVTL_HOME_PATH=${MHVTL_HOME_PATH} DESTDIR=${D} install || die \"emake failed\"\n\n\teinfo \"Generating udev rules ...\"\n\tdodir /etc/udev/rules.d/\n\tcat > \"${D}\"/etc/udev/rules.d/70-mhvtl.rules <<-EOF || die\n\t# do not edit this file, it will be overwritten on update\n\t#\n\tKERNEL==\"mhvtl[0-9]*\", MODE=\"0660\", OWNER=\"root\", GROUP=\"root\"\n\tEOF\n\n\tnewinitd \"${FILESDIR}\"/mhvtl.init.d mhvtl || die\n\n\tif use doc; then\n\t\tdohtml -r doc/* || die\n\tfi\n\n\tdoman man/*.1 || die\n\tdodoc README INSTALL\n}\n\npkg_postinst() {\n\tlinux-mod_pkg_postinst\n}\n"
  },
  {
    "path": "scripts/rescan-scsi-bus.sh",
    "content": "#!/bin/bash\n# Skript to rescan SCSI bus, using the\n# scsi add-single-device mechanism\n# (c) 1998--2008 Kurt Garloff <kurt@garloff.de>, GNU GPL v2 or later\n# (c) 2006--2008 Hannes Reinecke, GNU GPL v2 or later\n# $Id: rescan-scsi-bus.sh,v 1.48 2010/08/10 19:32:22 garloff Exp $\n\nsetcolor ()\n{\n  red=\"\\e[0;31m\"\n  green=\"\\e[0;32m\"\n  yellow=\"\\e[0;33m\"\n  bold=\"\\e[0;1m\"\n  norm=\"\\e[0;0m\"\n}\n\nunsetcolor ()\n{\n  red=\"\"; green=\"\"\n  yellow=\"\"; norm=\"\"\n}\n\n# Output some text and return cursor to previous position\n# (only works for simple strings)\n# Stores length of string in LN and returns it\nprint_and_scroll_back ()\n{\n  STRG=\"$1\"\n  LN=${#STRG}\n  BK=\"\"\n  declare -i cntr=0\n  while test $cntr -lt $LN; do BK=\"$BK\\e[D\"; let cntr+=1; done\n  echo -en \"$STRG$BK\"\n  return $LN\n}\n\n# Overwrite a text of length $1 (fallback to $LN) with whitespace\nwhite_out ()\n{\n  BK=\"\"; WH=\"\"\n  if test -n \"$1\"; then LN=$1; fi\n  declare -i cntr=0\n  while test $cntr -lt $LN; do BK=\"$BK\\e[D\"; WH=\"$WH \"; let cntr+=1; done\n  echo -en \"$WH$BK\"\n}\n\n# Return hosts. sysfs must be mounted\nfindhosts_26 ()\n{\n  hosts=\n  for hostdir in /sys/class/scsi_host/host*; do\n    hostno=${hostdir#/sys/class/scsi_host/host}\n    if [ -f $hostdir/isp_name ] ; then\n      hostname=\"qla2xxx\"\n    elif [ -f $hostdir/lpfc_drvr_version ] ; then\n      hostname=\"lpfc\"\n    else\n      hostname=`cat $hostdir/proc_name`\n    fi\n    hosts=\"$hosts $hostno\"\n    echo \"Host adapter $hostno ($hostname) found.\"\n  done\n  if [ -z \"$hosts\" ] ; then\n    echo \"No SCSI host adapters found in sysfs\"\n    exit 1;\n  fi\n  hosts=`echo $hosts | sed 's/ /\\n/g' | sort -n`\n}\n\n# Return hosts. /proc/scsi/HOSTADAPTER/? must exist\nfindhosts ()\n{\n  hosts=\n  for driverdir in /proc/scsi/*; do\n    driver=${driverdir#/proc/scsi/}\n    if test $driver = scsi -o $driver = sg -o $driver = dummy -o $driver = device_info; then continue; fi\n    for hostdir in $driverdir/*; do\n      name=${hostdir#/proc/scsi/*/}\n      if test $name = add_map -o $name = map -o $name = mod_parm; then continue; fi\n      num=$name\n      driverinfo=$driver\n      if test -r $hostdir/status; then\n\tnum=$(printf '%d\\n' `sed -n 's/SCSI host number://p' $hostdir/status`)\n\tdriverinfo=\"$driver:$name\"\n      fi\n      hosts=\"$hosts $num\"\n      echo \"Host adapter $num ($driverinfo) found.\"\n    done\n  done\n}\n\nprinttype ()\n{\n  local type=$1\n\n  case \"$type\" in\n    0) echo \"Direct-Access    \" ;;\n    1) echo \"Sequential-Access\" ;;\n    2) echo \"Printer          \" ;;\n    3) echo \"Processor        \" ;;\n    4) echo \"WORM             \" ;;\n    5) echo \"CD-ROM           \" ;;\n    6) echo \"Scanner          \" ;;\n    7) echo \"Optical Device   \" ;;\n    8) echo \"Medium Changer   \" ;;\n    9) echo \"Communications   \" ;;\n    10) echo \"Unknown          \" ;;\n    11) echo \"Unknown          \" ;;\n    12) echo \"RAID             \" ;;\n    13) echo \"Enclosure        \" ;;\n    14) echo \"Direct-Access-RBC\" ;;\n    *) echo \"Unknown          \" ;;\n  esac\n}\n\nprint02i()\n{\n    if [ \"$1\" = \"*\" ] ; then\n        echo \"00\"\n    else\n        printf \"%02i\" \"$1\"\n    fi\n}\n\n# Get /proc/scsi/scsi info for device $host:$channel:$id:$lun\n# Optional parameter: Number of lines after first (default = 2),\n# result in SCSISTR, return code 1 means empty.\nprocscsiscsi ()\n{\n  if test -z \"$1\"; then LN=2; else LN=$1; fi\n  CHANNEL=`print02i \"$channel\"`\n  ID=`print02i \"$id\"`\n  LUN=`print02i \"$lun\"`\n  if [ -d /sys/class/scsi_device ]; then\n    SCSIPATH=\"/sys/class/scsi_device/${host}:${channel}:${id}:${lun}\"\n    if [ -d  \"$SCSIPATH\" ] ; then\n      SCSISTR=\"Host: scsi${host} Channel: $CHANNEL Id: $ID Lun: $LUN\"\n      if [ \"$LN\" -gt 0 ] ; then\n\tIVEND=$(cat ${SCSIPATH}/device/vendor)\n\tIPROD=$(cat ${SCSIPATH}/device/model)\n\tIPREV=$(cat ${SCSIPATH}/device/rev)\n\tSCSIDEV=$(printf '  Vendor: %-08s Model: %-16s Rev: %-4s' \"$IVEND\" \"$IPROD\" \"$IPREV\")\n\tSCSISTR=\"$SCSISTR\n$SCSIDEV\"\n      fi\n      if [ \"$LN\" -gt 1 ] ; then\n\tILVL=$(cat ${SCSIPATH}/device/scsi_level)\n\ttype=$(cat ${SCSIPATH}/device/type)\n\tITYPE=$(printtype $type)\n\tSCSITMP=$(printf '  Type:   %-16s                ANSI SCSI revision: %02d' \"$ITYPE\" \"$((ILVL - 1))\")\n\tSCSISTR=\"$SCSISTR\n$SCSITMP\"\n      fi\n    else\n      return 1\n    fi\n  else\n    grepstr=\"scsi$host Channel: $CHANNEL Id: $ID Lun: $LUN\"\n    SCSISTR=`cat /proc/scsi/scsi | grep -A$LN -e\"$grepstr\"`\n  fi\n  if test -z \"$SCSISTR\"; then return 1; else return 0; fi\n}\n\n# Find sg device with 2.6 sysfs support\nsgdevice26 ()\n{\n  if test -e /sys/class/scsi_device/$host\\:$channel\\:$id\\:$lun/device/generic; then\n    SGDEV=`readlink /sys/class/scsi_device/$host\\:$channel\\:$id\\:$lun/device/generic`\n    SGDEV=`basename $SGDEV`\n  else\n    for SGDEV in /sys/class/scsi_generic/sg*; do\n      DEV=`readlink $SGDEV/device`\n      if test \"${DEV##*/}\" = \"$host:$channel:$id:$lun\"; then\n\tSGDEV=`basename $SGDEV`; return\n      fi\n    done\n    SGDEV=\"\"\n  fi\n}\n\n# Find sg device with 2.4 report-devs extensions\nsgdevice24 ()\n{\n  if procscsiscsi 3; then\n    SGDEV=`echo \"$SCSISTR\" | grep 'Attached drivers:' | sed 's/^ *Attached drivers: \\(sg[0-9]*\\).*/\\1/'`\n  fi\n}\n\n# Find sg device that belongs to SCSI device $host $channel $id $lun\n# and return in SGDEV\nsgdevice ()\n{\n  SGDEV=\n  if test -d /sys/class/scsi_device; then\n    sgdevice26\n  else\n    DRV=`grep 'Attached drivers:' /proc/scsi/scsi 2>/dev/null`\n    repdevstat=$((1-$?))\n    if [ $repdevstat = 0 ]; then\n      echo \"scsi report-devs 1\" >/proc/scsi/scsi\n      DRV=`grep 'Attached drivers:' /proc/scsi/scsi 2>/dev/null`\n      if [ $? = 1 ]; then return; fi\n    fi\n    if ! `echo $DRV | grep 'drivers: sg' >/dev/null`; then\n      modprobe sg\n    fi\n    sgdevice24\n    if [ $repdevstat = 0 ]; then\n      echo \"scsi report-devs 0\" >/proc/scsi/scsi\n    fi\n  fi\n}\n\n# Test if SCSI device is still responding to commands\ntestonline ()\n{\n  : testonline\n  RC=0\n  if test ! -x /usr/bin/sg_turs; then return 0; fi\n  sgdevice\n  if test -z \"$SGDEV\"; then return 0; fi\n  sg_turs /dev/$SGDEV >/dev/null 2>&1\n  RC=$?\n  # Handle in progress of becoming ready and unit attention -- wait at max 11s\n  declare -i ctr=0\n  if test $RC = 2 -o $RC = 6; then\n    RMB=`sg_inq /dev/$SGDEV | grep 'RMB=' | sed 's/^.*RMB=\\(.\\).*$/\\1/'`\n    print_and_scroll_back \"$host:$channel:$id:$lun $SGDEV ($RMB) \"\n  fi\n  while test $RC = 2 -o $RC = 6 && test $ctr -le 8; do\n    if test $RC = 2 -a \"$RMB\" != \"1\"; then echo -n \".\"; let $LN+=1; sleep 1\n    else usleep 20000; fi\n    let ctr+=1\n    sg_turs /dev/$SGDEV >/dev/null 2>&1\n    RC=$?\n  done\n  if test $ctr != 0; then white_out; fi\n  # echo -e \"\\e[A\\e[A\\e[A${yellow}Test existence of $SGDEV = $RC ${norm} \\n\\n\\n\"\n  if test $RC = 1; then return $RC; fi\n  # Reset RC (might be !=0 for passive paths)\n  RC=0\n  # OK, device online, compare INQUIRY string\n  INQ=`sg_inq $sg_len_arg /dev/$SGDEV 2>/dev/null`\n  IVEND=`echo \"$INQ\" | grep 'Vendor identification:' | sed 's/^[^:]*: \\(.*\\)$/\\1/'`\n  IPROD=`echo \"$INQ\" | grep 'Product identification:' | sed 's/^[^:]*: \\(.*\\)$/\\1/'`\n  IPREV=`echo \"$INQ\" | grep 'Product revision level:' | sed 's/^[^:]*: \\(.*\\)$/\\1/'`\n  STR=`printf \"  Vendor: %-08s Model: %-16s Rev: %-4s\" \"$IVEND\" \"$IPROD\" \"$IPREV\"`\n  IPTYPE=`echo \"$INQ\" | sed -n 's/.* Device_type=\\([0-9]*\\) .*/\\1/p'`\n  IPQUAL=`echo \"$INQ\" | sed -n 's/ *PQual=\\([0-9]*\\)  Device.*/\\1/p'`\n  if [ \"$IPQUAL\" != 0 ] ; then\n    echo -e \"\\e[A\\e[A\\e[A\\e[A${red}$SGDEV changed: ${bold}LU not available (PQual $IPQUAL)${norm}    \\n\\n\\n\"\n    return 2\n  fi\n\n  TYPE=$(printtype $IPTYPE)\n  procscsiscsi\n  TMPSTR=`echo \"$SCSISTR\" | grep 'Vendor:'`\n  if [ \"$TMPSTR\" != \"$STR\" ]; then\n    echo -e \"\\e[A\\e[A\\e[A\\e[A${red}$SGDEV changed: ${bold}\\nfrom:${SCSISTR#* } \\nto: $STR ${norm} \\n\\n\\n\"\n    return 1\n  fi\n  TMPSTR=`echo \"$SCSISTR\" | sed -n 's/.*Type: *\\(.*\\) *ANSI.*/\\1/p'`\n  if [ $TMPSTR != $TYPE ] ; then\n    echo -e \"\\e[A\\e[A\\e[A\\e[A${red}$SGDEV changed: ${bold}\\nfrom:${TMPSTR} \\nto: $TYPE ${norm} \\n\\n\\n\"\n    return 1\n  fi\n  return $RC\n}\n\n# Test if SCSI device $host $channen $id $lun exists\n# Outputs description from /proc/scsi/scsi (unless arg passed)\n# Returns SCSISTR (empty if no dev)\ntestexist ()\n{\n  : testexist\n  SCSISTR=\n  if procscsiscsi && test -z \"$1\"; then\n    echo \"$SCSISTR\" | head -n1\n    echo \"$SCSISTR\" | tail -n2 | pr -o4 -l1\n  fi\n}\n\n# Returns the list of existing channels per host\nchanlist ()\n{\n  local hcil\n  local cil\n  local chan\n  local tmpchan\n\n  for dev in /sys/class/scsi_device/${host}:* ; do\n    [ -d $dev ] || continue;\n    hcil=${dev##*/}\n    cil=${hcil#*:}\n    chan=${cil%%:*}\n    for tmpchan in $channelsearch ; do\n      if test \"$chan\" -eq $tmpchan ; then\n\tchan=\n      fi\n    done\n    if test -n \"$chan\" ; then\n      channelsearch=\"$channelsearch $chan\"\n    fi\n  done\n  if test -z \"$channelsearch\"; then channelsearch=\"0\"; fi\n}\n\n# Returns the list of existing targets per host\nidlist ()\n{\n  local hcil\n  local cil\n  local il\n  local target\n  local tmpid\n\n  for dev in /sys/class/scsi_device/${host}:${channel}:* ; do\n    [ -d $dev ] || continue;\n    hcil=${dev##*/}\n    cil=${hcil#*:}\n    il=${cil#*:}\n    target=${il%%:*}\n    for tmpid in $idsearch ; do\n      if test \"$target\" -eq $tmpid ; then\n\ttarget=\n\tbreak\n      fi\n    done\n    if test -n \"$target\" ; then\n      idsearch=\"$idsearch $target\"\n    fi\n  done\n}\n\n# Returns the list of existing LUNs from device $host $channel $id $lun\n# and returns list to stdout\ngetluns()\n{\n  sgdevice\n  if test -z \"$SGDEV\"; then return; fi\n  if test ! -x /usr/bin/sg_luns; then echo 0; return; fi\n  LLUN=`sg_luns -d /dev/$SGDEV 2>/dev/null`\n  if test $? != 0; then echo 0; return; fi\n  echo \"$LLUN\" | sed -n 's/.*lun=\\(.*\\)/\\1/p'\n}\n\n# Wait for udev to settle (create device nodes etc.)\nudevadm_settle()\n{\n  if test -x /sbin/udevadm; then\n    print_and_scroll_back \" Calling udevadm settle (can take a while) \"\n    /sbin/udevadm settle\n    white_out\n  else\n    usleep 20000\n  fi\n}\n\n# Perform scan on a single lun $host $channel $id $lun\ndolunscan()\n{\n  SCSISTR=\n  devnr=\"$host $channel $id $lun\"\n  echo \"Scanning for device $devnr ... \"\n  printf \"${yellow}OLD: $norm\"\n  testexist\n  # Special case: lun 0 just got added (for reportlunscan),\n  # so make sure we correctly treat it as new\n  if test \"$lun\" = \"0\" -a \"$1\"; then\n    SCSISTR=\"\"\n    printf \"\\r\\e[A\\e[A\\e[A\"\n  fi\n  : f $remove s $SCSISTR\n  if test \"$remove\" -a \"$SCSISTR\"; then\n    # Device exists: Test whether it's still online\n    # (testonline returns 1 if it's gone or has changed)\n    testonline\n    RC=$?\n    if test $RC != 0 -o ! -z \"$forceremove\"; then\n      echo -en \"\\r\\e[A\\e[A\\e[A${red}REM: \"\n      echo \"$SCSISTR\" | head -n1\n      echo -e \"${norm}\\e[B\\e[B\"\n      if test -e /sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device; then\n        echo 1 > /sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device/delete\n\tif test $RC -eq 1 -o $lun -eq 0 ; then\n          # Try readding, should fail if device is gone\n          echo \"$channel $id $lun\" > /sys/class/scsi_host/host${host}/scan\n\tfi\n\t# FIXME: Can we skip udevadm settle for removal?\n\t#udevadm_settle\n\tusleep 20000\n      else\n        echo \"scsi remove-single-device $devnr\" > /proc/scsi/scsi\n\tif test $RC -eq 1 -o $lun -eq 0 ; then\n          # Try readding, should fail if device is gone\n          echo \"scsi add-single-device $devnr\" > /proc/scsi/scsi\n\tfi\n      fi\n    fi\n    if test $RC = 0 -o \"$forcerescan\" ; then\n      if test -e /sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device; then\n        echo 1 > /sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device/rescan\n\tudevadm_settle\n      fi\n    fi\n    printf \"\\r\\e[A\\e[A\\e[A${yellow}OLD: $norm\"\n    testexist\n    if test -z \"$SCSISTR\"; then\n      printf \"\\r${red}DEL: $norm\\r\\n\\n\"\n      let rmvd+=1;\n      return 1\n    fi\n  fi\n  if test -z \"$SCSISTR\"; then\n    # Device does not exist, try to add\n    printf \"\\r${green}NEW: $norm\"\n    if test -e /sys/class/scsi_host/host${host}/scan; then\n      echo \"$channel $id $lun\" > /sys/class/scsi_host/host${host}/scan 2> /dev/null\n      udevadm_settle\n    else\n      echo \"scsi add-single-device $devnr\" > /proc/scsi/scsi\n    fi\n    testexist\n    if test -z \"$SCSISTR\"; then\n      # Device not present\n      printf \"\\r\\e[A\";\n      # Optimization: if lun==0, stop here (only if in non-remove mode)\n      if test $lun = 0 -a -z \"$remove\" -a $optscan = 1; then\n        break;\n      fi\n    else\n      let found+=1;\n    fi\n  fi\n}\n\n# Perform report lun scan on $host $channel $id using REPORT_LUNS\ndoreportlun()\n{\n  lun=0\n  SCSISTR=\n  devnr=\"$host $channel $id $lun\"\n  echo -en \"Scanning for device $devnr ...\\r\"\n  lun0added=\n  #printf \"${yellow}OLD: $norm\"\n  # Phase one: If LUN0 does not exist, try to add\n  testexist -q\n  if test -z \"$SCSISTR\"; then\n    # Device does not exist, try to add\n    #printf \"\\r${green}NEW: $norm\"\n    if test -e /sys/class/scsi_host/host${host}/scan; then\n      echo \"$channel $id $lun\" > /sys/class/scsi_host/host${host}/scan 2> /dev/null\n      udevadm_settle\n    else\n      echo \"scsi add-single-device $devnr\" > /proc/scsi/scsi\n    fi\n    testexist -q\n    if test -n \"$SCSISTR\"; then\n      lun0added=1\n      #testonline\n    else\n      # Device not present\n      # return\n      # Find alternative LUN to send getluns to\n      for dev in /sys/class/scsi_device/${host}:${channel}:${id}:*; do\n        [ -d \"$dev\" ] || continue\n\tlun=${dev##*:}\n        break\n      done\n    fi\n  fi\n  targetluns=`getluns`\n  lunremove=\n  #echo \"getluns reports \" $targetluns\n  # Check existing luns\n  for dev in /sys/class/scsi_device/${host}:${channel}:${id}:*; do\n    [ -d \"$dev\" ] || continue\n    lun=${dev##*:}\n    newsearch=\n    inlist=\n    # OK, is existing $lun (still) in reported list\n    for tmplun in $targetluns; do\n      if test $tmplun -eq $lun ; then\n\tinlist=1\n\tdolunscan $lun0added\n      else\n\tnewsearch=\"$newsearch $tmplun\"\n      fi\n    done\n    # OK, we have now done a lunscan on $lun and\n    # $newsearch is the old $targetluns without $lun\n    if [ -z \"$inlist\" ]; then\n      # Stale lun\n      lunremove=\"$lunremove $lun\"\n    fi\n    # $lun removed from $lunsearch (echo for whitespace cleanup)\n    targetluns=`echo $newsearch`\n  done\n  # Add new ones and check stale ones\n  for lun in $targetluns $lunremove; do\n    dolunscan $lun0added\n  done\n}\n\n# Perform search (scan $host)\ndosearch ()\n{\n  if test -z \"$channelsearch\" ; then\n    chanlist\n  fi\n  for channel in $channelsearch; do\n    if test -z \"$idsearch\" ; then\n      idlist\n    fi\n    for id in $idsearch; do\n      if test -z \"$lunsearch\" ; then\n\tdoreportlun\n      else\n\tfor lun in $lunsearch; do\n          dolunscan\n        done\n      fi\n    done\n  done\n}\n\nexpandlist ()\n{\n  list=$1\n  result=\"\"\n  first=${list%%,*}\n  rest=${list#*,}\n  while test ! -z \"$first\"; do\n    beg=${first%%-*};\n    if test \"$beg\" = \"$first\"; then\n      result=\"$result $beg\";\n    else\n      end=${first#*-}\n      result=\"$result `seq $beg $end`\"\n    fi\n    test \"$rest\" = \"$first\" && rest=\"\"\n    first=${rest%%,*}\n    rest=${rest#*,}\n  done\n  echo $result\n}\n\n# main\nif test @$1 = @--help -o @$1 = @-h -o @$1 = @-?; then\n    echo \"Usage: rescan-scsi-bus.sh [options] [host [host ...]]\"\n    echo \"Options:\"\n    echo \" -l      activates scanning for LUNs 0--7   [default: 0]\"\n    echo \" -L NUM  activates scanning for LUNs 0--NUM [default: 0]\"\n    echo \" -w      scan for target device IDs 0--15   [default: 0--7]\"\n    echo \" -c      enables scanning of channels 0 1   [default: 0 / all detected ones]\"\n    echo \" -r      enables removing of devices        [default: disabled]\"\n    echo \" -i      issue a FibreChannel LIP reset     [default: disabled]\"\n    echo \"--remove:        same as -r\"\n    echo \"--issue-lip:     same as -i\"\n    echo \"--forcerescan:   Rescan existing devices\"\n    echo \"--forceremove:   Remove and readd every device (DANGEROUS)\"\n    echo \"--nooptscan:     don't stop looking for LUNs is 0 is not found\"\n    echo \"--color:         use coloured prefixes OLD/NEW/DEL\"\n    echo \"--hosts=LIST:    Scan only host(s) in LIST\"\n    echo \"--channels=LIST: Scan only channel(s) in LIST\"\n    echo \"--ids=LIST:      Scan only target ID(s) in LIST\"\n    echo \"--luns=LIST:     Scan only lun(s) in LIST\"\n    echo \"--sync/nosync:   Issue a sync / no sync [default: sync if remove]\"\n    echo \"--attachpq3:     Tell kernel to attach sg to LUN 0 that reports PQ=3\"\n    echo \"--reportlun2:    Tell kernel to try REPORT_LUN even on SCSI2 devices\"\n    echo \"--largelun:      Tell kernel to support LUNs > 7 even on SCSI2 devs\"\n    echo \"--sparselun:     Tell kernel to support sparse LUN numbering\"\n    echo \" Host numbers may thus be specified either directly on cmd line (deprecated) or\"\n    echo \" or with the --hosts=LIST parameter (recommended).\"\n    echo \"LIST: A[-B][,C[-D]]... is a comma separated list of single values and ranges\"\n    echo \" (No spaces allowed.)\"\n    exit 0\nfi\n\nif test ! -d /sys/class/scsi_host/ -a ! -d /proc/scsi/; then\n  echo \"Error: SCSI subsystem not active\"\n  exit 1\nfi\n\n# Make sure sg is there\nmodprobe sg >/dev/null 2>&1\n\nif test -x /usr/bin/sg_inq; then\n    sg_version=$(sg_inq -V 2>&1 | cut -d \" \" -f 3)\n    sg_version=${sg_version##0.}\n    #echo \"\\\"$sg_version\\\"\"\n    if [ -z \"$sg_version\" -o \"$sg_version\" -lt 70 ] ; then\n        sg_len_arg=\"-36\"\n    else\n        sg_len_arg=\"--len=36\"\n    fi\nfi\n\n# defaults\nunsetcolor\nlunsearch=\nopt_idsearch=`seq 0 7`\nopt_channelsearch=\nremove=\nforceremove=\noptscan=1\nsync=1\ndeclare -i scan_flags=0\nif test -d /sys/class/scsi_host; then\n  findhosts_26\nelse\n  findhosts\nfi\n\n# Scan options\nopt=\"$1\"\nwhile test ! -z \"$opt\" -a -z \"${opt##-*}\"; do\n  opt=${opt#-}\n  case \"$opt\" in\n    l) lunsearch=`seq 0 7` ;;\n    L) lunsearch=`seq 0 $2`; shift ;;\n    w) opt_idsearch=`seq 0 15` ;;\n    c) opt_channelsearch=\"0 1\" ;;\n    r) remove=1 ;;\n    i) lipreset=1 ;;\n    -remove)      remove=1 ;;\n    -forcerescan) remove=1; forcerescan=1 ;;\n    -forceremove) remove=1; forceremove=1 ;;\n    -hosts=*)     arg=${opt#-hosts=};   hosts=`expandlist $arg` ;;\n    -channels=*)  arg=${opt#-channels=};opt_channelsearch=`expandlist $arg` ;;\n    -ids=*)   arg=${opt#-ids=};         opt_idsearch=`expandlist $arg` ;;\n    -luns=*)  arg=${opt#-luns=};        lunsearch=`expandlist $arg` ;;\n    -color) setcolor ;;\n    -nooptscan) optscan=0 ;;\n    -issue-lip) lipreset=1 ;;\n    -sync) sync=2 ;;\n    -nosync) sync=0 ;;\n    -attachpq3) scan_flags=$(($scan_flags|0x1000000)) ;;\n    -reportlun2) scan_flags=$(($scan_flags|0x20000)) ;;\n    -largelun) scan_flags=$(($scan_flags|0x200)) ;;\n    -sparselun) scan_flags=$((scan_flags|0x40)) ;;\n    *) echo \"Unknown option -$opt !\" ;;\n  esac\n  shift\n  opt=\"$1\"\ndone\n\n# Hosts given ?\nif test \"@$1\" != \"@\"; then\n  hosts=$*\nfi\n\nif [ -d /sys/class/scsi_host -a ! -w /sys/class/scsi_host ]; then\n  echo \"You need to run scsi-rescan-bus.sh as root\"\n  exit 2\nfi\nif test \"$sync\" = 1 -a \"$remove\" = 1; then sync=2; fi\nif test \"$sync\" = 2; then echo \"Syncing file systems\"; sync; fi\nif test -w /sys/module/scsi_mod/parameters/default_dev_flags -a $scan_flags != 0; then\n  OLD_SCANFLAGS=`cat /sys/module/scsi_mod/parameters/default_dev_flags`\n  NEW_SCANFLAGS=$(($OLD_SCANFLAGS|$scan_flags))\n  if test \"$OLD_SCANFLAGS\" != \"$NEW_SCANFLAGS\"; then\n    echo -n \"Temporarily setting kernel scanning flags from \"\n    printf \"0x%08x to 0x%08x\\n\" $OLD_SCANFLAGS $NEW_SCANFLAGS\n    echo $NEW_SCANFLAGS > /sys/module/scsi_mod/parameters/default_dev_flags\n  else\n    unset OLD_SCANFLAGS\n  fi\nfi\necho \"Scanning SCSI subsystem for new devices\"\ntest -z \"$remove\" || echo \" and remove devices that have disappeared\"\ndeclare -i found=0\ndeclare -i rmvd=0\nfor host in $hosts; do\n  echo -n \"Scanning host $host \"\n  if test -e /sys/class/fc_host/host$host ; then\n    # It's pointless to do a target scan on FC\n    if test -n \"$lipreset\" ; then\n      echo 1 > /sys/class/fc_host/host$host/issue_lip 2> /dev/null;\n    fi\n    # Always trigger a rescan for FC to update channels and targets\n    echo \"- - -\" > /sys/class/scsi_host/host$host/scan 2> /dev/null;\n    channelsearch=\n    idsearch=\n    udevadm_settle\n  else\n    channelsearch=$opt_channelsearch\n    idsearch=$opt_idsearch\n  fi\n  [ -n \"$channelsearch\" ] && echo -n \"channels $channelsearch \"\n  echo -n \"for \"\n  if [ -n \"$idsearch\" ] ; then\n    echo -n \" SCSI target IDs \" $idsearch\n  else\n    echo -n \" all SCSI target IDs\"\n  fi\n  if [ -n \"$lunsearch\" ] ; then\n    echo \", LUNs \" $lunsearch\n  else\n    echo \", all LUNs\"\n  fi\n  dosearch\ndone\nif test -n \"$OLD_SCANFLAGS\"; then\n  echo $OLD_SCANFLAGS > /sys/module/scsi_mod/parameters/default_dev_flags\nfi\necho \"$found new device(s) found.               \"\necho \"$rmvd device(s) removed.                 \"\n"
  },
  {
    "path": "scripts/start-mhvtl-scst.sh",
    "content": "#!/bin/sh\n\nmodprobe mpt2sas\nmodprobe pl2303\n\nmodprobe scst\nmodprobe scst-vdisk\nmodprobe scst_tape\nmodprobe scst_changer\n\n# for iSCSI\nmodprobe scsi_transport_iscsi\nmodprobe iscsi-scst\niscsi-scstd\niscsid\n\n# for FC\nmodprobe qla2x00tgt\n\nmodprobe scst_user\nmodprobe scst_local\n\n/opt/fast/application/fileio/fileio_tgt_gpu -o -e 1 -b 4096 gpu01 gpu -- -o -s $((1000*1024*1024*1024)) $(/opt/fast/scripts/diskmapper.sh /opt/fast/scripts/disks_shelf_2.lst) &\n\nsleep 3\n\necho \"add gpu01 0\" > /sys/kernel/scst_tgt/targets/scst_local/scst_local_tgt/luns/mgmt\n\nDEVICE=`lsscsi | grep gpu01 | awk '{print $6;}'`\n\necho \"Formatting GPU Device: $DEVICE\"\n\nmkfs.ext4 $DEVICE\n\nmount $DEVICE /mnt\n\nmkdir -p /mnt/mhvtl-data\nchown vtl:vtl /mnt/mhvtl-data\nln -s /mnt/mhvtl-data /opt/mhvtl\nmake_vtl_media\n\nsystemctl start mhvtl\n\nsleep 5\n\n# create SCST config\n\n(\ncat << 'EOF'\n\nHANDLER dev_tape {\n        DEVICE 7:0:1:0\n        DEVICE 7:0:2:0\n}\n\nHANDLER dev_changer {\n        DEVICE 7:0:0:0\n}\n\nTARGET_DRIVER qla2x00t {\n        enabled 1\n\n        TARGET 21:00:00:24:ff:05:7b:1a {\n                LUN 1 7:0:0:0\n                LUN 2 7:0:1:0\n                LUN 3 7:0:2:0\n                enabled 1\n        }\n}\n\nEOF\n) > /etc/scst.conf\n\nscstadmin -config\n"
  },
  {
    "path": "scripts/stgt-target-setup.conf",
    "content": "# This is a sample config file for tgt-admin.\n# By default, tgt-admin looks for its config file in /etc/tgt/targets.conf\n\n# Set the driver. If not specified, defaults to \"iscsi\".\ndefault-driver iscsi\n\n# Sample target with one LUN only. Defaults to allow access for all initiators:\n\n<target iqn.2016-10.com.mhvtl:lto5.test>\n    device-type pt\n    bs-type sg\n    backing-store /dev/sg2\n    backing-store /dev/sg3\n    allow-in-use yes\n</target>\n\n"
  },
  {
    "path": "scripts/test_lbp.sh",
    "content": "#!/bin/bash\n\n#systemctl stop mhvtl\n#systemctl start mhvtl\n\nif [[ $EUID -ne 0 ]]; then\n   echo \"Sorry, this script needs to be run as root\"\n   exit 1\nfi\n\n# Library source slot to move tape to/from\nSOURCE_SLOT=1\n# Which drive are we testing - /etc/mhvtl/device.conf\nDRV_INDEX=18\n\nwhile [[ $# -gt 0 ]]; do\n\tcase $1 in\n\t-i|--index)\n\t\tif [ -z \"$2\" ]; then # Check for missing arg\n\t\t\techo \"Usage: Need to specify drive index\"\n\t\t\techo \"e.g. $0 -i 11\"\n\t\t\texit 1\n\t\tfi\n\t\tDRV_INDEX=\"$2\"\n\t\tshift # past argument\n\t\tshift # past value\n\t\t;;\n\n\t-s|--source)\n\t\tif [ -z \"$2\" ]; then # Check for missing arg\n\t\t\techo \"Usage: Need to specify source slot\"\n\t\t\techo \"e.g. $0 -s 1\"\n\t\t\texit 1\n\t\tfi\n\t\tSOURCE_SLOT=\"$2\"\n\t\tshift # past argument\n\t\tshift # past value\n\t\t;;\n\n\t*)\n\t\tshift # past argument\n\t;;\n\tesac\ndone\n\n\ni=`grep -A6 \"^Drive: ${DRV_INDEX} \" /etc/mhvtl/device.conf | awk '/Library/ {print $5}'`\n# Convert into hex - leading '0' typically means it's an octal value\nTARGET_DRIVE=$((16#${i}-1))\nif [ ${TARGET_DRIVE} -lt 0 ]; then\n\techo \"Unable to find drive at index ${DRV_INDEX}... Exiting\"\n\techo \"Perhaps provide drive index using \\\"-i <num>\\\"\"\n\techo \"e.g. $0 -i 11\"\n\texit\nfi\n\nread -r channel id lun <<< `grep \"^Drive: ${DRV_INDEX} \" /etc/mhvtl/device.conf | awk '{print $4,$6,$8}'`\n#echo \"Channel: $channel, id: $id, lun: $lun\"\n\nHBA=`lsscsi -H | awk '/mhvtl/ {print $1}' | sed -e 's/\\[//g' -e 's/\\]//g'`\nSG=`lsscsi -g ${HBA} ${channel} ${id} ${lun} | awk '{print $7}'`\nST=`lsscsi -g ${HBA} ${channel} ${id} ${lun} | awk '{print $6}'`\n\nMTX=`lsscsi -g ${HBA} 0 0 0 | awk '{print $7}'`\n\n#echo \"HBA: ${HBA}\"\n#echo \"st : ${ST}\"\n#echo \"sg : ${SG}\"\n#echo \"mtx : ${MTX}\"\n\necho \"++ Moving tape slot: ${SOURCE_SLOT} to drive: ${TARGET_DRIVE}\"\nmtx -f ${MTX} load ${SOURCE_SLOT} ${TARGET_DRIVE}\nvtlcmd ${DRV_INDEX} verbose\nvtlcmd ${DRV_INDEX} verbose\n\necho\n\necho \"++ Checking status of ${ST}\"\nmt -f ${ST} status\n\necho\n\nCRC32C=2\nRSCRC=1\nLBP_W=\"40\"\nLBP_R=\"80\"\nLBP_RW=\"c0\"\n## Set LBP_W\n#sg_wr_mode -p 0x0a,0xf0 -d -c 0a,f0,00,1c,${CRC32C},4,${LBP_W},0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ${SG}\n## Set LBP_R\n#sg_wr_mode -p 0x0a,0xf0 -d -c 0a,f0,00,1c,${CRC32C},4,${LBP_R},0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ${SG}\n\n# Set LBP_R & LBP_W\necho -e \"++ Enable LBP CRC32C RW\\n\"\nsg_wr_mode -p 0x0a,0xf0 -d -c 0a,f0,00,1c,${CRC32C},4,${LBP_RW},0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ${SG}\n\necho -e \"++ Reading 64k + 4 to /tmp/CRC32c.out\"\ndd if=${ST} of=/tmp/CRC32c.out bs=65540 count=1\n\necho\n\necho -e \"++ Enable LBP Reed-Solomon CRC RW\\n\"\nsg_wr_mode -p 0x0a,0xf0 -d -c 0a,f0,00,1c,${RSCRC},4,${LBP_RW},0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ${SG}\n\necho \"++ Reading 64k + 4 to /tmp/RS-CRC.out\"\ndd if=${ST} of=/tmp/RS-CRC.out bs=65540 count=1\n\necho\n\n# Turn off LBP\necho -e \"++ Turn off LBP\\n\"\nsg_wr_mode -p 0x0a,0xf0 -d -c 0a,f0,00,1c,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ${SG}\n\necho \"++ Reading 64k to /tmp/NO_LBP.out\"\ndd if=${ST} of=/tmp/NO_LBP.out bs=65540 count=1\n\necho\n\necho \"Offline drive\"\nmt -f ${ST} offline\n\necho \"Moving tape from drive: ${TARGET_DRIVE} to slot: ${SOURCE_SLOT}\"\nmtx -f ${MTX} unload ${SOURCE_SLOT} ${TARGET_DRIVE}\n"
  },
  {
    "path": "scripts/update_device.conf.in",
    "content": "#!/usr/bin/perl -w\n#\n# Copyright (C) 2005 - 2025 Mark Harvey       markh794@gmail.com\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; version 2 of the License.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n#\n\nuse strict;\n\nmy $if;\nmy $lib;\nmy $slt = 1;\nmy $num_drives = 0;\nmy $old_device_conf = \"@CONF_PATH@/device.conf\";\nmy $new_device_conf = \"@CONF_PATH@/device.conf_$$\";\n\nif (! -e $old_device_conf ) {\n\tdie \"Can not find $old_device_conf\";\n}\n\n# Confirm device.conf not current version..\n# Also count number of drives.\nopen(IF, \" < $old_device_conf\") || die \"Can't open $old_device_conf\";\nwhile($if = <IF>) {\n\tif ($if =~ /VERSION:\\s+(\\d+)/) {\n\t\tif ($1 == 4) {\n\t\t\tprint \"Nothing to upgrade.. Exiting\\n\";\n\t\t\texit 0;\n\t\t}\n\t}\n\tif ($if =~ /Library\\sID:.*Slot:/) { # Found V4 type entry.. Exit\n\t\texit 0;\n\t}\n\tif ($if =~ /^Drive/) {\n\t\t$num_drives++;\n\t}\n}\nclose IF;\n\n# Now create new temporary device.conf\n$lib = $num_drives + 1;\nopen(IF, \" < $old_device_conf\") || die \"Can't open $old_device_conf for reading\";\nopen(OF, \" > $new_device_conf\") || die \"Can't open $new_device_conf for writing\";\nwhile($if = <IF>) {\n\t# Update library 'index' with max drives + 1\n\t$if =~ s/^Library:\\s(\\d+)/Library: $lib/g;\n\tif ($if =~ /VERSION:/) {\n\t\tprint OF \"VERSION: 4\\n\";\n\t} else {\n\t\tprint OF $if;\n\t}\n\tif ($if =~ /^Drive:\\s(\\d+)/) {\n\t\tprint OF \" Library ID: $lib Slot: $slt\\n\";\n\t\t$slt++;\n\t}\n}\nclose IF;\nclose OF;\n\n# Now remove original config file and replace with new one\nunlink($old_device_conf);\nsystem(\"mv $new_device_conf $old_device_conf\");\n\n# Now 'move' library_contents to library_contents.$lib\n$new_device_conf = \"@CONF_PATH@/library_contents.$lib\";\n$old_device_conf = \"@CONF_PATH@/library_contents\";\nopen(IF, \" < $old_device_conf\") || die \"Can't open $old_device_conf for reading\";\nopen(OF, \" > $new_device_conf\") || die \"Can't open $new_device_conf for writing\";\nwhile($if = <IF>) {\n\tprint OF $if;\n}\nclose IF;\nclose OF;\n\n# Now remove original file(s)\nunlink($old_device_conf);\n\nexit 0;\n\n"
  },
  {
    "path": "tcopy/Makefile",
    "content": "# Makefile for linux port of Tcopy\n# By Nicholas Harbour, 2000\n\nCURDIR = \"../\"\ninclude ../config.mk\n\nBINARY=tcopy\nMANPAGE=tcopy.1\nBIN_PATH=$(PREFIX)/bin/\nMAN_PATH=$(PREFIX)/$(MANDIR)/man1/\nOBJS=tcopy.o\nCC=gcc\nOPTS=-Wall\n\nall: tcopy install\n\ntcopy: clean $(OBJS)\n\t$(CC) $(OPTS) -o $(BINARY) $(OBJS) \n\ninstall:\ttcopy\n\tcp $(BINARY) $(BIN_PATH)\n\tcp $(MANPAGE) $(MAN_PATH)\n\nclean:\n\trm -f $(OBJS) tcopy\n\n"
  },
  {
    "path": "tcopy/pathnames.h",
    "content": "/*\n * Copyright (c) 1989, 1993\n *\tThe Regents of the University of California.  All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. All advertising materials mentioning features or use of this software\n *    must display the following acknowledgement:\n *\tThis product includes software developed by the University of\n *\tCalifornia, Berkeley and its contributors.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *\t@(#)pathnames.h\t8.1 (Berkeley) 6/6/93\n */\n\n#define\t_PATH_DEFTAPE\t\"/dev/nst0\"\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "tcopy/tcopy.1",
    "content": ".\\\" Copyright (c) 1985, 1990, 1991, 1993\n.\\\"\tThe Regents of the University of California.  All rights reserved.\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in the\n.\\\"    documentation and/or other materials provided with the distribution.\n.\\\" 3. All advertising materials mentioning features or use of this software\n.\\\"    must display the following acknowledgement:\n.\\\"\tThis product includes software developed by the University of\n.\\\"\tCalifornia, Berkeley and its contributors.\n.\\\" 4. Neither the name of the University nor the names of its contributors\n.\\\"    may be used to endorse or promote products derived from this software\n.\\\"    without specific prior written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n.\\\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n.\\\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n.\\\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n.\\\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n.\\\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n.\\\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n.\\\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n.\\\" SUCH DAMAGE.\n.\\\"\n.\\\"     @(#)tcopy.1\t8.2 (Berkeley) 4/17/94\n.\\\" $FreeBSD: src/usr.bin/tcopy/tcopy.1,v 1.7 2000/03/01 12:20:12 sheldonh Exp $\n.\\\"\n.Dd April 17, 1994\n.Dt TCOPY 1\n.Os BSD 4.3\n.Sh NAME\n.Nm tcopy\n.Nd copy and/or verify mag tapes\n.Sh SYNOPSIS\n.Nm\n.Op Fl cvx\n.Op Fl s Ar maxblk\n.Oo Ar src Op Ar dest\n.Oc\n.Sh DESCRIPTION\n.Nm Tcopy\nis designed to copy magnetic tapes.  The only assumption made\nabout the tape is that there are two tape marks at the end.\n.Nm Tcopy\nwith only a source tape\n.Pf ( Ar /dev/nst0\nby default) specified will print\ninformation about the sizes of records and tape files.  If a destination\nis specified a copy will be made of the source tape.  The blocking on the\ndestination tape will be identical to that used on the source tape.  Copying\na tape will yield the same output as if just printing the sizes.\n.Pp\nOptions:\n.Bl -tag -width s_maxblk\n.It Fl c\nCopy\n.Ar src\nto\n.Ar dest\nand then verify that the two tapes are identical.\n.It Fl s Ar maxblk\nSpecify a maximum block size,\n.Ar maxblk .\n.It Fl v\nGiven the two tapes,\n.ar src\nand\n.Ar dest\nverify that they are identical.\n.It Fl x\nOutput all informational messages to the standard error.\nThis option is useful when\n.Ar dest\nis\n.Pa /dev/stdout .\n.El\n.Sh SEE ALSO\n.Xr mtio 4\n.Sh HISTORY\nThe\n.Nm\ncommand appeared in\n.Bx 4.3 .\n.Sh BUGS\nWritting an image of a tape to a file does not preserve much more than\nthe raw data.\nBlock size(s) and tape EOF marks are lost which would\notherwise be preserved in a tape-to-tape copy.\n\nEOD is determined by two sequential EOF marks with no data between.\nThere are old systems which typically wrote three EOF's between tape\nfiles.\n.Xr tcopy 1\nwill erroneously stop copying early in this case.\n\nWhen using the copy/verify option \\-c\n.Xr tcopy 1\ndoes not rewind the tapes prior to start.\nA rewind is performed\nafter writing prior to the verification stage.\nIf one doesn't start\nat BOT then the comparison may not be of the intended data.\n"
  },
  {
    "path": "tcopy/tcopy.c",
    "content": "/*\n * Copyright (c) 1985, 1987, 1993\n *\tThe Regents of the University of California.  All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. All advertising materials mentioning features or use of this software\n *    must display the following acknowledgement:\n *\tThis product includes software developed by the University of\n *\tCalifornia, Berkeley and its contributors.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n/* Linux port - Nicholas Harbour 2000 */\n\n#ifndef lint\nstatic const char copyright[] =\n\"@(#) Copyright (c) 1985, 1987, 1993\\n\\\n\tThe Regents of the University of California.  All rights reserved.\\n\";\n#endif /* not lint */\n\n#ifndef lint\n#if 0\nstatic const char sccsid[] = \"@(#)tcopy.c\t8.2 (Berkeley) 4/17/94\";\n#endif\nstatic const char rcsid[] =\n  \"$FreeBSD: src/usr.bin/tcopy/tcopy.c,v 1.2.2.4 1999/09/05 11:33:13 peter Exp $\";\n#endif /* not lint */\n\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <sys/ioctl.h>\n#include <sys/mtio.h>\n\n#include <err.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <signal.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n\n#include \"pathnames.h\"\n\n#define\tMAXREC\t(640 * 1024)\n#define\tNOCOUNT\t(-2)\n\nint\tfilen, guesslen, maxblk = MAXREC;\nu_long\tlastrec, record, size, tsize;\n/*FILE\t*msg = stdout;*/\nFILE *msg;  /*njh 2000*/\n\nvoid\t*getspace __P((int));\nvoid\t intr __P((int));\nstatic void\t usage __P((void));\nvoid\t verify __P((int, int, char *));\nvoid\t writeop __P((int, int));\n\nint main(int argc, char *argv[])\n{\n\tregister int lastnread, nread, nw, inp, outp;\n\tenum {READ, VERIFY, COPY, COPYVERIFY} op = READ;\n\tsig_t oldsig;\n\tint ch, needeof;\n\tchar *buff, *inf;\n\n\tmsg = stdout;\n\tguesslen = 1;\n\twhile ((ch = getopt(argc, argv, \"cs:vx\")) != -1)\n\t\tswitch ((char)ch) {\n\t\tcase 'c':\n\t\t\top = COPYVERIFY;\n\t\t\tbreak;\n\t\tcase 's':\n\t\t\tmaxblk = atoi(optarg);\n\t\t\tif (maxblk <= 0) {\n\t\t\t\twarnx(\"illegal block size\");\n\t\t\t\tusage();\n\t\t\t}\n\t\t\tguesslen = 0;\n\t\t\tbreak;\n\t\tcase 'v':\n\t\t\top = VERIFY;\n\t\t\tbreak;\n\t\tcase 'x':\n\t\t\tmsg = stderr;\n\t\t\tbreak;\n\t\tcase '?':\n\t\tdefault:\n\t\t\tusage();\n\t\t}\n\targc -= optind;\n\targv += optind;\n\n\tswitch (argc) {\n\tcase 0:\n\t\tif (op != READ)\n\t\t\tusage();\n\t\tinf = _PATH_DEFTAPE;\n\t\tbreak;\n\tcase 1:\n\t\tif (op != READ)\n\t\t\tusage();\n\t\tinf = argv[0];\n\t\tbreak;\n\tcase 2:\n\t\tif (op == READ)\n\t\t\top = COPY;\n\t\tinf = argv[0];\n\t\toutp = open(argv[1], op == VERIFY ? O_RDONLY :\n\t\t\t    op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE);\n\t\tif (outp < 0)\n\t\t\terr(3, \"%s\", argv[1]);\n\t\tbreak;\n\tdefault:\n\t\tusage();\n\t}\n\n\tinp = open(inf, O_RDONLY, 0);\n\tif (inp < 0)\n\t\terr(1, \"%s\", inf);\n\n\tbuff = getspace(maxblk);\n\n\tif (op == VERIFY) {\n\t\tverify(inp, outp, buff);\n\t\texit(0);\n\t}\n\n\toldsig = signal(SIGINT, SIG_IGN);\n\tif (oldsig != SIG_IGN)\n\t\t(void) signal(SIGINT, intr);\n\n\tneedeof = 0;\n\tfor (lastnread = NOCOUNT;;) {\n\t\tnread = read(inp, buff, maxblk);\n\t\tif (nread == -1) {\n\t\t\twhile (errno == EINVAL && (maxblk -= 1024)) {\n\t\t\t\tnread = read(inp, buff, maxblk);\n\t\t\t\tif (nread >= 0)\n\t\t\t\t\tgoto r1;\n\t\t\t}\n\t\t\terr(1, \"read err, File %d, Record %ld\", filen, record);\n\t\t} else if (nread != lastnread) {\n\t\t\tif (lastnread != 0 && lastnread != NOCOUNT) {\n\t\t\t\tif (lastrec == 0 && nread == 0)\n\t\t\t\t\tfprintf(msg, \"%ld records\\n\", record);\n\t\t\t\telse if (record - lastrec > 1)\n\t\t\t\t\tfprintf(msg, \"records %ld to %ld\\n\",\n\t\t\t\t\t    lastrec, record);\n\t\t\t\telse\n\t\t\t\t\tfprintf(msg, \"record %ld\\n\", lastrec);\n\t\t\t}\n\t\t\tif (nread != 0)\n\t\t\t\tfprintf(msg, \"file %d: block size %d: \",\n\t\t\t\t    filen, nread);\n\t\t\t(void) fflush(stdout);\n\t\t\tlastrec = record;\n\t\t}\nr1:\t\tguesslen = 0;\n\t\tif (nread > 0) {\n\t\t\tif (op == COPY || op == COPYVERIFY) {\n\t\t\t\tif (needeof) {\n\t\t\t\t\twriteop(outp, MTWEOF);\n\t\t\t\t\tneedeof = 0;\n\t\t\t\t}\n\t\t\t\tnw = write(outp, buff, nread);\n\t\t\t\tif (nw != nread) {\n\t\t\t\t\tif (nw == -1) {\n\t\t\t\t\t\twarn(\"write err, File %d, \"\n\t\t\t\t\t\t\t\"Record %ld\",\n\t\t\t\t\t\t\tfilen, record);\n\t\t\t\t\t} else {\n\t\t\t\t\twarnx(\"write err, File %d, Record %ld\",\n\t\t\t\t\t\t\tfilen, record);\n\t\t\t\t\twarnx(\"write (%d) != read (%d)\",\n\t\t\t\t\t\t\tnw, nread);\n\t\t\t\t\t}\n\t\t\t\t\terrx(5, \"copy aborted\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tsize += nread;\n\t\t\trecord++;\n\t\t} else {\n\t\t\tif (lastnread <= 0 && lastnread != NOCOUNT) {\n\t\t\t\tfprintf(msg, \"eot\\n\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tfprintf(msg,\n\t\t\t    \"file %d: eof after %lu records: %lu bytes\\n\",\n\t\t\t    filen, record, size);\n\t\t\tneedeof = 1;\n\t\t\tfilen++;\n\t\t\ttsize += size;\n\t\t\tsize = record = lastrec = 0;\n\t\t\tlastnread = 0;\n\t\t}\n\t\tlastnread = nread;\n\t}\n\tfprintf(msg, \"total length: %lu bytes\\n\", tsize);\n\t(void)signal(SIGINT, oldsig);\n\tif (op == COPY || op == COPYVERIFY) {\n\t\twriteop(outp, MTWEOF);\n\t\twriteop(outp, MTWEOF);\n\t\tif (op == COPYVERIFY) {\n\t\t\twriteop(outp, MTREW);\n\t\t\twriteop(inp, MTREW);\n\t\t\tverify(inp, outp, buff);\n\t\t}\n\t}\n\texit(0);\n}\n\nvoid verify(register int inp, register int outp, register char *outb)\n{\n\tregister int eot, inmaxblk, inn, outmaxblk, outn;\n\tregister char *inb;\n\n\tinb = getspace(maxblk);\n\tinmaxblk = outmaxblk = maxblk;\n\tfor (eot = 0;; guesslen = 0) {\n\t\tinn = read(inp, inb, inmaxblk);\n\t\tif (inn == -1) {\n\t\t\tif (guesslen)\n\t\t\t\twhile (errno == EINVAL && (inmaxblk -= 1024)) {\n\t\t\t\t\tinn = read(inp, inb, inmaxblk);\n\t\t\t\t\tif (inn >= 0)\n\t\t\t\t\t\tgoto r1;\n\t\t\t\t}\n\t\t\twarn(\"read error\");\n\t\t\tbreak;\n\t\t}\nr1:\t\toutn = read(outp, outb, outmaxblk);\n\t\tif (outn == -1) {\n\t\t\tif (guesslen)\n\t\t\t\twhile (errno == EINVAL && (outmaxblk -= 1024)) {\n\t\t\t\t\toutn = read(outp, outb, outmaxblk);\n\t\t\t\t\tif (outn >= 0)\n\t\t\t\t\t\tgoto r2;\n\t\t\t\t}\n\t\t\twarn(\"read error\");\n\t\t\tbreak;\n\t\t}\nr2:\t\tif (inn != outn) {\n\t\t\tfprintf(msg,\n\t\t\t    \"%s: tapes have different block sizes; %d != %d.\\n\",\n\t\t\t    \"tcopy\", inn, outn);\n\t\t\tbreak;\n\t\t}\n\t\tif (!inn) {\n\t\t\tif (eot++) {\n\t\t\t\tfprintf(msg, \"tcopy: tapes are identical.\\n\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t} else {\n\t\t\tif (bcmp(inb, outb, inn)) {\n\t\t\t\tfprintf(msg,\n\t\t\t\t    \"tcopy: tapes have different data.\\n\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\teot = 0;\n\t\t}\n\t}\n\texit(1);\n}\n\nvoid intr(int signo)\n{\n\tif (record)\n\t\tif (record - lastrec > 1)\n\t\t\tfprintf(msg, \"records %ld to %ld\\n\", lastrec, record);\n\t\telse\n\t\t\tfprintf(msg, \"record %ld\\n\", lastrec);\n\tfprintf(msg, \"interrupt at file %d: record %ld\\n\", filen, record);\n\tfprintf(msg, \"total length: %ld bytes\\n\", tsize + size);\n\texit(1);\n}\n\nvoid *getspace(int blk)\n{\n\tvoid *bp;\n\n\tbp = malloc((size_t)blk);\n\tif (bp == NULL)\n\t\terrx(11, \"no memory\");\n\treturn bp;\n}\n\nvoid writeop(int fd, int type)\n{\n\tstruct mtop op;\n\n\top.mt_op = type;\n\top.mt_count = (daddr_t)1;\n\tif (ioctl(fd, MTIOCTOP, (char *)&op) < 0)\n\t\terr(6, \"tape op\");\n}\n\nstatic void usage(void)\n{\n\tfprintf(stderr, \"usage: tcopy [-cvx] [-s maxblk] [src [dest]]\\n\");\n\texit(1);\n}\n"
  },
  {
    "path": "todo",
    "content": " - Review return values from functions and make consistent.\n   Some functions return SAM_STAT_XXX, some return *sam_status\n\n - Major -> Add personality modules to library\n  ================================\n\n"
  },
  {
    "path": "usr/.gitignore",
    "content": "mhvtl-device-conf-generator\ndump_messageQ\ndump_tape\nedit_tape\npreload_tape\nlibvtlcart.so\nlibvtlscsi.so\nmake_vtl_media\nmktape\ntapeexerciser\nvtlcmd\nvtllibrary\nvtltape\nTAGS\n*.d"
  },
  {
    "path": "usr/Makefile",
    "content": "#\n# This makefile needs to be invoked as follows:\n#\n#make <options>\n#\n# Here, options include:\n#\n# \tall \tto build all utilities\n# \tclean\tto clean up all intermediate files\n#\n#\n# Makefile magic\n# $@ is a variable that expands to the name of the file being built\n# $< is a variable that expands to the name of the source file\n# @ at the beginning of the first line tell make not to echo the commands as it run it.\n#\n\nCURDIR = \"../\"\n\ninclude ../config.mk\n\nIFLAGS = -I ../include -I ../include/utils -I ../include/common -I ../ccan\n\nCFLAGS = -Wall -Wshadow -g -O2 -D_LARGEFILE64_SOURCE $(RPM_OPT_FLAGS) $(IFLAGS)\nCFLAGS += -MMD -MP # create header dependencies dynamically (.d files)\nCFLAGS += -std=gnu99\nCFLAGS += -DMHVTL_VERSION=\\\"$(VERSION).$(EXTRAVERSION)\\\"\nCFLAGS += -DMHVTL_GITDATE=\\\"$(GITDATE)\\\"\nCFLAGS += -DMHVTL_GITHASH=\\\"$(GITHASH)\\\"\nCFLAGS += -D_GNU_SOURCE\nCFLAGS += -DMHVTL_DEBUG\nCFLAGS += -DMHVTL_HOME_PATH=\\\"$(MHVTL_HOME_PATH)\\\"\nCFLAGS += -DMHVTL_CONFIG_PATH=\\\"$(MHVTL_CONFIG_PATH)\\\"\nCFLAGS += -DSYSTEMD_SERVICE_DIR=\\\"$(SYSTEMD_SERVICE_DIR)\\\"\n\nCLFLAGS = -shared ${RPM_OPT_FLAGS}\n\n# Enable LZODEBUG\n#LZODEBUG = -DLZO_DEBUG\nLZODEBUG =\n\n# files that need to be generated\nGENERATED_FILES = $(patsubst cmd/%.in,bin/%,$(wildcard cmd/*.in))\n\nBINARIES = $(patsubst cmd/%.c,bin/%,$(wildcard cmd/*.c)) bin/dump_tape\nLIBRARIES = libvtlscsi.so\n\nall: | bin\nall: $(LIBRARIES) $(BINARIES) $(GENERATED_FILES) validate_crc\n\nbin :\n\tinstall -d -m 755 $@\n\t\n# ================== objects ==================\n\n# ------------ VTL objects\nVTL_SRC = $(wildcard ./*.c)\nVTL_DEP = $(VTL_SRC:.c=.d)\n-include $(VTL_DEP)\n%.o: %.c\n\t$(CC) $(CFLAGS) -o $@ -c $<\n\nmhvtl_log.o mode.o \\\nsmc.o spc.o \\\nvtlcart.o vtllib.o: \\\n\tCFLAGS += -fpic\n\n\n# ------------ personality modules\nPM_SRC = $(wildcard pm/*.c)\nPM_DEP = $(PM_SRC:.c=.d)\n-include $(PM_DEP)\npm/%.o: pm/%.c\n\t$(CC) $(CFLAGS) -o $@ -c $<\n\n\n# ------------ cmds\nCMD_SRC = $(wildcard cmd/*.c)\nCMD_DEP = $(CMD_SRC:.c=.d)\n-include $(CMD_DEP)\ncmd/%.o: cmd/%.c\n\t$(CC) $(CFLAGS) -o $@ -c $<\n\ncmd/tape_util.o: \\\n\tCFLAGS += -fPIC\n\n\n# ------------ utils\nUTILS_SRC = $(wildcard utils/*.c)\nUTILS_DEP = $(UTILS_SRC:.c=.d)\n-include $(UTILS_DEP)\nutils/%.o: utils/%.c\n\t$(CC) $(CFLAGS) -o $@ -c $< \n\nutils/minilzo.o: \\\n\t\tCFLAGS += $(LZODEBUG)\n\nutils/q.o utils/subprocess.o utils/mhvtl_update.o: \\\n\t\tCFLAGS += -fpic\n\n\n# ================== libs ==================\n\nlibvtlscsi.so: vtllib.o mhvtl_log.o mode.o \\\n\t\tvtlcart.o \\\n\t \tspc.o smc.o \\\n\t \tutils/q.o \\\n\t \tutils/subprocess.o \\\n\t\tutils/mhvtl_update.o\n\t$(CC) $(CLFLAGS) -o $@ $^ -lpthread\n\n# ================== Commands and scripts ==================\n\nbin/validate_crc: utils/validate_crc.o utils/crc32c.o utils/reed-solomon.o\n\t@$(CC) $(CFLAGS) -o $@ $^\n\n.PHONY: validate_crc\nvalidate_crc: bin/validate_crc\n\t@./bin/validate_crc\n\nbin/tapeexerciser: cmd/tapeexerciser.o\n\t$(CC) $(CFLAGS) -o $@ $^\n\nDUMP_MESSAGEQ_OBJ = cmd/dump_messageQ.o\nbin/dump_messageQ: $(DUMP_MESSAGEQ_OBJ) libvtlscsi.so\n\t$(CC) $(CFLAGS) -o $@ $(DUMP_MESSAGEQ_OBJ) -L. -lvtlscsi\n\nVTLCMD_OBJ = cmd/vtlcmd.o\nbin/vtlcmd:\t$(VTLCMD_OBJ) libvtlscsi.so\n\t$(CC) $(CFLAGS) -o $@ $(VTLCMD_OBJ) -L. -lvtlscsi\n\nbin/preload_tape: bin/dump_tape\n\t@rm -f $@\n\tln -s $? $@\n\nbin/tape_util:\n\t@true\n\nDUMP_TAPE_OBJ = cmd/tape_util.o \\\n\t\tmhvtl_io.o \\\n\t\tutils/minilzo.o \\\n\t\tutils/crc32c.o \\\n\t\tutils/reed-solomon.o \\\n\t\tpm/default_ssc_pm.o\nbin/dump_tape: $(DUMP_TAPE_OBJ) libvtlscsi.so\n\t$(CC) $(CFLAGS) -o $@ $(DUMP_TAPE_OBJ) -L. -lz -lvtlscsi\n\t\t\nMKTAPE_OBJ = cmd/mktape.o\nbin/mktape: $(MKTAPE_OBJ) libvtlscsi.so\n\t$(CC) $(CFLAGS) -o $@ $(MKTAPE_OBJ) -L. -lvtlscsi\n\nEDIT_TAPE_OBJ = cmd/edit_tape.o\nbin/edit_tape: $(EDIT_TAPE_OBJ) libvtlscsi.so\n\t$(CC) $(CFLAGS) -o $@ $(EDIT_TAPE_OBJ) -L. -lvtlscsi\n\nVTLLIBRARY_OBJ = cmd/vtllibrary.o \\\n\t\tvtl_cart_type.o \\\n\t\tpm/stklxx_pm.o \\\n\t\tpm/hp_smc_pm.o \\\n\t\tpm/overland_pm.o \\\n\t\tpm/spectra_pm.o \\\n\t\tpm/scalar_pm.o \\\n\t\tpm/ibm_smc_pm.o \\\n\t\tpm/default_smc_pm.o\nbin/vtllibrary:\t$(VTLLIBRARY_OBJ) libvtlscsi.so\n\t$(CC) $(CFLAGS) -o $@ $(VTLLIBRARY_OBJ) -L. -lvtlscsi\n\nVTLTAPE_OBJ = cmd/vtltape.o \\\n\t\tmhvtl_io.o ssc.o \\\n\t\tutils/minilzo.o \\\n\t\tutils/crc32c.o \\\n\t\tutils/reed-solomon.o \\\n\t\tpm/default_ssc_pm.o \\\n\t\tpm/ult3580_pm.o \\\n\t\tpm/hp_ultrium_pm.o \\\n\t\tpm/stk9x40_pm.o \\\n\t\tpm/quantum_dlt_pm.o \\\n\t\tpm/ait_pm.o \\\n\t\tpm/t10000_pm.o \\\n\t\tpm/ibm_03592_pm.o\nbin/vtltape: $(VTLTAPE_OBJ) libvtlscsi.so\n\t$(CC) $(CFLAGS) -o $@ $(VTLTAPE_OBJ) -lz -L. -lvtlscsi\n\nMHVTL_DEVICE_CONF_GENERATOR_OBJ = cmd/mhvtl-device-conf-generator.o\nbin/mhvtl-device-conf-generator: $(MHVTL_DEVICE_CONF_GENERATOR_OBJ) libvtlscsi.so\n\t$(CC) $(CFLAGS) -o $@ $(MHVTL_DEVICE_CONF_GENERATOR_OBJ) -L. -lvtlscsi\n\n\n\nbin/make_vtl_media: cmd/make_vtl_media.in\n\tsed -e s'/@CONF_PATH@/$(CONFIG_PATH)/' \\\n\t    -e s'/@HOME_PATH@/$(HOME_PATH)/' $< > $@\n\tchmod 755 $@\n\nbin/mhvtl_kernel_mod_build: cmd/mhvtl_kernel_mod_build.in\n\tsed -e s'|@FIRMWAREDIR@|${FIRMWAREDIR}|' $< > $@\n\tchmod 755 $@\n\n.PHONY:clean\nclean:\n\t$(RM) *.d *.o *.so \\\n\t\tpm/*.d pm/*.o \\\n\t\tutils/*.d utils/*.o \\\n\t\tcmd/*.d cmd/*.o \\\n\t\tbin/*\n\t$(RM) TAGS\n\n\n\n# ========== command targets ==========\n\n$(DESTDIR)$(PREFIX)/bin:\n\tinstall -d -m 755 $@\n$(DESTDIR)$(LIBDIR):\n\tinstall -d -m 755 $@\n\n$(DESTDIR)$(LIBDIR)/%.so: %.so | $(DESTDIR)$(LIBDIR)\n\tinstall -m 755 $< $@\n$(DESTDIR)$(PREFIX)/bin/%: bin/% | $(DESTDIR)$(PREFIX)/bin\n\tinstall -m 755 $< $@\n$(DESTDIR)$(PREFIX)/bin/tape_util: bin/tape_util\n\t@true\n\n.PHONY:install\ninstall: all \\\n\t\t $(addprefix $(DESTDIR)$(PREFIX)/,$(BINARIES) $(GENERATED_FILES)) \\\n\t\t $(addprefix $(DESTDIR)$(LIBDIR)/,$(LIBRARIES)) \n\t@rm -f $(DESTDIR)$(PREFIX)/bin/preload_tape\n\tln $(DESTDIR)$(PREFIX)/bin/dump_tape $(DESTDIR)$(PREFIX)/bin/preload_tape\n\t[ -d $(DESTDIR)$(SYSTEMD_GENERATOR_DIR) ] || install -d -m 755 $(DESTDIR)$(SYSTEMD_GENERATOR_DIR)\n\tinstall -m 755 bin/mhvtl-device-conf-generator $(DESTDIR)$(SYSTEMD_GENERATOR_DIR)/\n\trestorecon -R -v  $(DESTDIR)$(SYSTEMD_GENERATOR_DIR)\nifeq ($(ROOTUID),YES)\n\tldconfig \nendif\n\n.PHONY: uninstall\nuninstall:\n\trm -f $(addprefix $(DESTDIR)$(PREFIX)/,$(BINARIES) $(GENERATED_FILES)) \\\n\t\t  $(addprefix $(DESTDIR)$(LIBDIR)/,$(LIBRARIES)) \\\n\t\t  $(DESTDIR)$(SYSTEMD_GENERATOR_DIR)/mhvtl-device-conf-generator\n\trestorecon -R -v  $(DESTDIR)$(SYSTEMD_GENERATOR_DIR)\nifeq ($(ROOTUID),YES)\n\tldconfig \nendif\t\n\n.PHONY:tar\ntar:\n\tmake -C ../ tar\n\n.PHONY:tags\ntags:\n\tetags -R *.[ch] ../kernel/*.h\n\n# ========== Cleaning ==========\n\n.PHONY:clean\nclean:\n\t$(RM) *.d *.o *.so \\\n\t\tpm/*.d pm/*.o \\\n\t\tutils/*.d utils/*.o \\\n\t\tcmd/*.d cmd/*.o \\\n\t\tbin/*\n\t$(RM) TAGS\n\n.PHONY:distclean\ndistclean: clean"
  },
  {
    "path": "usr/cmd/dump_messageQ.c",
    "content": "/*\n * dump_messageQ - A utility to empty & examine a message queue\n *\n * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n *\n * Modification History:\n *    2010-03-31 hstadler - source code revision, argument checking\n *\n * Dump any existing data in the messageQ.\n */\n\n#include <stdio.h>\n#include <sys/ipc.h>\n#include <sys/msg.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"q.h\"\n\nchar mhvtl_driver_name[] = \"dump_messageQ\";\n\nstatic void usage(char *prog) {\n\tfprintf(stdout, \"Usage  : %s [-h|-help]\\n\", prog);\n\tfprintf(stdout, \"Version: %s\\n\\n\", MHVTL_VERSION);\n\tfprintf(stdout, \"Dumping message queue content of \"\n\t\t\t\t\t\"library/tape queue.\\n\");\n\tfprintf(stdout, \"Primarily used for debugging purposes.\\n\\n\");\n}\n\nint main(int argc, char **argv) {\n\tint\t\t\t   r_qid;\n\tlong\t\t   mcounter = 0;\n\tint\t\t\t   i;\n\tstruct q_entry r_entry;\n\n\tmy_id = 0;\n\n\t/* checking several positions of -h/-help */\n\tfor (i = 1; i < argc; i++) {\n\t\tif (!strcmp(argv[i], \"-h\")) {\n\t\t\tusage(argv[0]);\n\t\t\texit(1);\n\t\t}\n\t\tif (!strcmp(argv[i], \"-?\")) {\n\t\t\tusage(argv[0]);\n\t\t\texit(1);\n\t\t}\n\t\tif (!strcmp(argv[i], \"/h\")) {\n\t\t\tusage(argv[0]);\n\t\t\texit(1);\n\t\t}\n\t\tif (!strcmp(argv[i], \"/?\")) {\n\t\t\tusage(argv[0]);\n\t\t\texit(1);\n\t\t}\n\t\tif (!strcmp(argv[i], \"-help\")) {\n\t\t\tusage(argv[0]);\n\t\t\texit(1);\n\t\t}\n\t}\n\n\tif (argc > 1) {\n\t\tprintf(\"Invalid option: %s\\n\", argv[1]);\n\t\tprintf(\"Try '%s -h' for more information\\n\", argv[0]);\n\t\texit(1);\n\t}\n\n\t/* Initialize message queue as necessary */\n\tr_qid = init_queue();\n\tif (r_qid == -1)\n\t\texit(1);\n\n\twhile (msgrcv(r_qid, &r_entry, MAXOBN, 0, IPC_NOWAIT) > 0) {\n\t\tmcounter++;\n\t\tif (mcounter == 1) {\n\t\t\tprintf(\"\\nDump Message Queue Content\\n\\n\");\n\t\t\tprintf(\"%6s %6s %6s %-55s\\n\", \"MessNo\", \"RcvID\",\n\t\t\t\t   \"SndID\", \"MessageText\");\n\t\t}\n\t\tprintf(\"%6ld %6ld %6ld %-55s\\n\", mcounter, r_entry.rcv_id,\n\t\t\t   r_entry.msg.snd_id, r_entry.msg.text);\n\t}\n\tif (mcounter == 0)\n\t\tprintf(\"Message queue empty\\n\");\n\n\texit(0);\n}\n"
  },
  {
    "path": "usr/cmd/edit_tape.c",
    "content": "/*\n * edit_tape is portion of the mhVTL package.\n *\n * The vtl package consists of:\n *   a kernel module (vlt.ko) - Currently on 2.6.x Linux kernel support.\n *   SCSI target daemons for both SMC and SSC devices.\n *\n * Copyright (C) 2005 - 2025 Mark Harvey       markh794@gmail.com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <errno.h>\n#include <string.h>\n#include <inttypes.h>\n#include \"be_byteshift.h\"\n#include \"vtlcart.h\"\n#include \"vtllib.h\"\n#include \"logging.h\"\n\n#if defined _LARGEFILE64_SOURCE\nstatic void *largefile_support = \"large file support\";\n#else\nstatic void *largefile_support = \"No largefile support\";\n#endif\n\n/* The following variables are needed for the MHVTL_DBG() macro to work. */\n\nchar\t   mhvtl_driver_name[] = \"edit_tape\";\nstatic int wp\t\t\t\t   = 0; /* Write protect flag */\n\n#define WRITE_PROTECT_OFF 1\n#define WRITE_PROTECT_ON  2\n\nvoid usage(char *progname) {\n\tprintf(\"Usage: %s -l lib -m PCL [-s size] [-t type] [-d density]\"\n\t\t   \" [-w on|off]\\n\",\n\t\t   progname);\n\tprintf(\"       Where 'size' is in Megabytes\\n\");\n\tprintf(\"             'lib' is Library number\\n\");\n\tprintf(\"             'type' is data | clean | WORM\\n\");\n\tprintf(\"             'PCL' is Physical Cartridge Label (barcode)\\n\");\n\tprintf(\"             '-w on|off' enable/disable write protect flag\\n\");\n\tprintf(\"             'density' can be on of the following:\\n\");\n\tprintf(\"           AIT1     AIT2     AIT3     AIT4\\n\");\n\tprintf(\"           DDS1     DDS2     DDS3     DDS4\\n\");\n\tprintf(\"           DLT3     DLT4\\n\");\n\tprintf(\"           SDLT1    SDLT220  SDLT320  SDLT600\\n\");\n\tprintf(\"           LTO1     LTO2     LTO3     LTO4\\n\");\n\tprintf(\"           LTO5     LTO6     LTO7     LTO8\\n\");\n\tprintf(\"           LTO9\\n\");\n\tprintf(\"           T10KA    T10KB    T10KC\\n\");\n\tprintf(\"           9840A    9840B    9840C    9840D\\n\");\n\tprintf(\"           9940A    9940B\\n\");\n\tprintf(\"           J1A      E05      E06\\n\\n\");\n}\n\nint main(int argc, char *argv[]) {\n\tchar\t\t  device_conf[CONF_FILE_SZ];\n\tunsigned char sam_stat;\n\tchar\t\t *progname\t\t= argv[0];\n\tchar\t\t *pcl\t\t\t= NULL;\n\tchar\t\t *mediaType\t\t= NULL;\n\tchar\t\t *mediaCapacity = NULL;\n\tchar\t\t *density\t\t= NULL;\n\tuint64_t\t  size;\n\tstruct MAM\t  new_mam;\n\tchar\t\t *lib\t= NULL;\n\tint\t\t\t  libno = 0;\n\tint\t\t\t  indx;\n\tint\t\t\t  rc;\n\tFILE\t\t *conf;\n\tchar\t\t *b; /* Read from file into this buffer */\n\tchar\t\t *s; /* Somewhere for sscanf to store results */\n\n\tif (get_config(device_conf, DEVICE_CONF, my_id) < 0)\n\t\texit(1);\n\n\tif (argc < 2) {\n\t\tusage(progname);\n\t\texit(1);\n\t}\n\n\twhile (argc > 0) {\n\t\tif (argv[0][0] == '-') {\n\t\t\tswitch (argv[0][1]) {\n\t\t\tcase 'd':\n\t\t\t\tif (argc > 1)\n\t\t\t\t\tdensity = argv[1];\n\t\t\t\tbreak;\n\t\t\tcase 'l':\n\t\t\t\tif (argc > 1) {\n\t\t\t\t\tlib = argv[1];\n\t\t\t\t} else {\n\t\t\t\t\tputs(\"    More args needed for -l\\n\");\n\t\t\t\t\texit(1);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'm':\n\t\t\t\tif (argc > 1) {\n\t\t\t\t\tpcl = argv[1];\n\t\t\t\t} else {\n\t\t\t\t\tputs(\"    More args needed for -m\\n\");\n\t\t\t\t\texit(1);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 's':\n\t\t\t\tif (argc > 1) {\n\t\t\t\t\tmediaCapacity = argv[1];\n\t\t\t\t} else {\n\t\t\t\t\tputs(\"    More args needed for -s\\n\");\n\t\t\t\t\texit(1);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 't':\n\t\t\t\tif (argc > 1) {\n\t\t\t\t\tmediaType = argv[1];\n\t\t\t\t} else {\n\t\t\t\t\tputs(\"    More args needed for -t\\n\");\n\t\t\t\t\texit(1);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'V':\n\t\t\t\tprintf(\"%s: version %s\\n%s\\n\\n\",\n\t\t\t\t\t   progname, MHVTL_VERSION,\n\t\t\t\t\t   (char *)largefile_support);\n\t\t\t\tbreak;\n\t\t\tcase 'v':\n\t\t\t\tverbose++;\n\t\t\t\tbreak;\n\t\t\tcase 'w':\n\t\t\t\tif (argc > 1) {\n\t\t\t\t\tif (!strncasecmp(\"yes\", argv[1], 3))\n\t\t\t\t\t\twp = WRITE_PROTECT_ON;\n\t\t\t\t\telse if (!strncasecmp(\"on\", argv[1], 3))\n\t\t\t\t\t\twp = WRITE_PROTECT_ON;\n\t\t\t\t\telse\n\t\t\t\t\t\twp = WRITE_PROTECT_OFF;\n\t\t\t\t} else {\n\t\t\t\t\tputs(\"    More args needed for -m\\n\");\n\t\t\t\t\texit(1);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\targv++;\n\t\targc--;\n\t}\n\n\tif (pcl == NULL) {\n\t\tprintf(\"Please supply a barcode (-m barcode)\\n\\n\");\n\t\tusage(progname);\n\t\texit(1);\n\t}\n\n\tconf = fopen(device_conf, \"r\");\n\tif (!conf) {\n\t\tprintf(\"Can not open config file %s : %s\", device_conf,\n\t\t\t   strerror(errno));\n\t\tperror(\"Can not open config file\");\n\t\texit(1);\n\t}\n\ts = zalloc(MALLOC_SZ);\n\tif (!s) {\n\t\tperror(\"Could not allocate memory\");\n\t\texit(1);\n\t}\n\tb = zalloc(MALLOC_SZ);\n\tif (!b) {\n\t\tperror(\"Could not allocate memory\");\n\t\texit(1);\n\t}\n\n\trc = ENOENT;\n\n\tif (lib) {\n\t\tsscanf(lib, \"%d\", &libno);\n\t\tprintf(\"Looking for PCL: %s in library %d\\n\", pcl, libno);\n\t\tfind_media_home_directory(NULL, libno);\n\t\trc = load_tape(pcl, &sam_stat);\n\t} else { /* Walk thru all defined libraries looking for media */\n\t\twhile (readline(b, MALLOC_SZ, conf) != NULL) {\n\t\t\tif (b[0] == '#') /* Ignore comments */\n\t\t\t\tcontinue;\n\t\t\t/* If found a library: Attempt to load media\n\t\t\t * Break out of loop if found. Otherwise try next lib.\n\t\t\t */\n\t\t\tif (sscanf(b, \"Library: %d CHANNEL:\", &indx)) {\n\t\t\t\tfind_media_home_directory(NULL, indx);\n\t\t\t\trc = load_tape(pcl, &sam_stat);\n\t\t\t\tif (!rc)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tfclose(conf);\n\tfree(s);\n\tfree(b);\n\n\tif (rc) {\n\t\tfprintf(stderr, \"PCL %s cannot be dumped, \"\n\t\t\t\t\t\t\"load_tape() returned %d\\n\",\n\t\t\t\tpcl, rc);\n\t\texit(1);\n\t}\n\n\t/* Copy media MAM into temp location */\n\tmemcpy(&new_mam, &mam, sizeof(mam));\n\n\tsize = 0L;\n\tif (mediaCapacity) {\n\t\tsscanf(mediaCapacity, \"%\" PRId64, &size);\n\t\tprintf(\"New capacity for %s: %ldMB\\n\",\n\t\t\t   pcl, (unsigned long)size);\n\t}\n\n\tif (mediaType) {\n\t\tif (!strncasecmp(\"clean\", mediaType, 5)) {\n\t\t\tMHVTL_DBG(1, \"Setting media type to CLEAN\");\n\t\t\tnew_mam.MediumType\t\t\t  = MEDIA_TYPE_CLEAN;\n\t\t\tnew_mam.MediumTypeInformation = 20;\n\t\t} else if (!strncasecmp(\"data\", mediaType, 4)) {\n\t\t\tMHVTL_DBG(1, \"Setting media type to DATA\");\n\t\t\tnew_mam.MediumType = MEDIA_TYPE_DATA;\n\t\t} else if (!strncasecmp(\"null\", mediaType, 4)) {\n\t\t\tMHVTL_DBG(1, \"Setting media type to NULL\");\n\t\t\tnew_mam.MediumType = MEDIA_TYPE_NULL;\n\t\t} else if (!strncasecmp(\"WORM\", mediaType, 4)) {\n\t\t\tMHVTL_DBG(1, \"Setting media type to WORM\");\n\t\t\tnew_mam.MediumType = MEDIA_TYPE_WORM;\n\t\t} else {\n\t\t\tprintf(\"Unknown media type: %s\\n\", mediaType);\n\t\t\tusage(progname);\n\t\t\texit(1);\n\t\t}\n\t}\n\tif (density) {\n\t\tprintf(\"Setting density to %s\\n\", density);\n\t\tif (set_media_params(&new_mam, density)) {\n\t\t\tprintf(\"Could not determine media density: %s\\n\",\n\t\t\t\t   density);\n\t\t\tunload_tape(&sam_stat);\n\t\t\texit(1);\n\t\t}\n\t}\n\tif (size) {\n\t\tput_unaligned_be64(size * 1048576, &new_mam.max_capacity);\n\t\t/* This will set incorrect value to start with but next media\n\t\t * Usage, this will be recalculated correctly\n\t\t */\n\t\tput_unaligned_be64(size * 1048576, &new_mam.remaining_capacity);\n\t}\n\tswitch (wp) {\n\tcase WRITE_PROTECT_ON:\n\t\tnew_mam.Flags |= MAM_FLAGS_MEDIA_WRITE_PROTECT;\n\t\tprintf(\"Setting write-protect for %s\\n\", pcl);\n\t\tbreak;\n\tcase WRITE_PROTECT_OFF:\n\t\tnew_mam.Flags &= ~MAM_FLAGS_MEDIA_WRITE_PROTECT;\n\t\tprintf(\"Turning off write-protect for %s\\n\", pcl);\n\t\tbreak;\n\t}\n\n\tput_unaligned_be64(new_mam.max_capacity - sizeof(struct MAM), &new_mam.MAMSpaceRemaining);\n\n\tmemcpy(&mam, &new_mam, sizeof(mam));\n\trewriteMAM(&sam_stat);\n\tunload_tape(&sam_stat);\n\n\texit(0);\n}\n"
  },
  {
    "path": "usr/cmd/make_scsi_dev",
    "content": "#!/usr/bin/perl -w\n#\n# * perl replacement for the VERITAS /usr/openv/volmgr/bin/make_scsi_dev\n# *\n# * Re-creates the /dev/sg/ & /dev/st/ symlinks back to the native linux\n# * device nodes.\n# *\n# *\n# * $Id: make_scsi_dev,v 1.2.2.1 2006-08-06 07:58:44 markh Exp $\n# *\n# * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com\n# *\n# * This program is free software; you can redistribute it and/or modify\n# * it under the terms of the GNU General Public License as published by\n# * the Free Software Foundation; either version 2 of the License, or\n# * (at your option) any later version.\n# *\n# * This program is distributed in the hope that it will be useful,\n# * but WITHOUT ANY WARRANTY; without even the implied warranty of\n# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# * GNU General Public License for more details.\n# *\n# * You should have received a copy of the GNU General Public License\n# * along with this program; if not, write to the Free Software\n# * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n#\n\nuse strict;\n\nmy $line;\nmy $type;\nmy $hba;\nmy $bus;\nmy $target;\nmy $lun;\nmy $path;\nmy $st;\nmy $sg;\n\nsystem(\"rm -f /dev/st/*\");\nsystem(\"rm -f /dev/sg/*\");\n\nopen(D, \"lsscsi -g|\") || die \"Could not execute \\'lsscsi -g\\'\\n\";\nwhile($line = <D>) {\n\tchomp $line;\n\tnext unless ($line =~ /tape|mediumx/);\n#\tprint \"$line\\n\";\n\t($hba,$bus,$target,$lun,$type) = ($line =~ /(\\d+):(\\d+):(\\d+):(\\d+)]\\s+([a-z]*)/);\n#\tprint \"HBA: $hba, BUS: $bus, ID: $target, LUN: $lun\\n\";\n\t$path = \"h\" . $hba . \"c\" . $bus . \"t\" . $target . \"l\" . $lun;\n\t($st) = ($line =~ /\\/dev\\/(st\\d+)/);\n\t($sg) = ($line =~ /\\/dev\\/(sg\\d+)/);\n\tif($type =~ /tape/) {\n\t\tsystem(\"ln -s /dev/$st /dev/st/$path\");\n\t\tsystem(\"ln -s /dev/n$st /dev/st/n$path\");\n\t}\n\tsystem(\"ln -s /dev/$sg /dev/sg/$path\");\n}\nclose (D);\n\n"
  },
  {
    "path": "usr/cmd/make_vtl_media.in",
    "content": "#!/bin/bash\n#\n# Designed to be called from mhvtl rc script\n#\n# * Copyright (C) 2005 - 2025 Mark Harvey markh794@gmail.com\n# *\n# * This program is free software; you can redistribute it and/or modify\n# * it under the terms of the GNU General Public License as published by\n# * the Free Software Foundation; either version 2 of the License, or\n# * (at your option) any later version.\n# *\n# * This program is distributed in the hope that it will be useful,\n# * but WITHOUT ANY WARRANTY; without even the implied warranty of\n# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# * GNU General Public License for more details.\n# *\n# * You should have received a copy of the GNU General Public License\n# * along with this program; if not, write to the Free Software\n# * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n#\n# TODO:\n#\t- ensure we are root?\n#\n\nDEVICE_CONF=\"device.conf\"\nPROG_NAME=\"$0\"\nCONFIG_FILE='@CONF_PATH@/mhvtl.conf'\nFORCE=''\nCREATE_DIR=''\nMKTAPE_PATH=''\n\n# print usage info\nusage()\n{\n\techo \"Usage: $PROG_NAME: [OPTIONS] -- generate the tape device database\"\n\techo \"where OPTIONS are from:\"\n\techo \"  [-h|--help]            -- print this message and exit\"\n\techo \"  [-H|--home-dir MHVTL_HOME_PATH]\"\n\techo \"                         -- home path [default $MHVTL_HOME_PATH]\"\n\techo \"  [-C|--config-dir DIR]  -- configuration dir [default @CONF_PATH@]\"\n\techo \"  [-f|--force]           -- overwrite files if present\"\n\techo \"  [-c|--create-dir]      -- mkdir MHVTL_HOME_PATH if needed\"\n\techo \"  [-m|--mktape-path MKTAPE] -- pass in dir where mktape lives [default uses PATH]\"\n}\n\n#\n# set_media_type -- set global variable MEDIA_TYPE\n#\nset_media_type()\n{\n\tif [[ $# -ne 1 ]] ; then\n\t\techo \"internal error: wrong number of arguments\" 1>&1\n\t\texit 1\n\tfi\n\ttype=$1\n\n\te0_regex='[A-Z0-9]{6,8}([J])([WXY])$'\n\tlto_regex='[A-Z0-9]{6,8}([L])([TUVW])$'\n\n\t# default to data type\n\tMEDIA_TYPE=\"data\"\n\n\tif [[ $type =~ ^\"W\" ]]; then\n\t\tMEDIA_TYPE=\"WORM\"\n\telif [[ $type =~ ^\"CLN\" ]]; then\n\t\tMEDIA_TYPE=\"clean\"\n\t# Match JW / JX as 'worm' media\n\telif [[ $type =~ $e0_regex ]]; then\n\t\tMEDIA_TYPE=\"WORM\"\n\telif [[ $type =~ $lto_regex ]]; then\n\t\tMEDIA_TYPE=\"WORM\"\n\tfi\n}\n\n#\n# set_density -- set global variable DENSITY\n#\nset_density()\n{\n\tif [[ $# -ne 1 ]] ; then\n\t\techo \"internal error: wrong number of arguments\" 1>&1\n\t\texit 1\n\tfi\n\tdensity=$1\n\n\t# I'm sure there is a better method then this...\n\t# There is.. Thanks to Gavin Barnard.\n\tregex='[A-Z0-9]{6,8}([SLXTJD])([12345678ABKUVWXYZ])$'\n\t#regex='[A-Z0-9]{4,6}([SLXTJ])([123456ABWX])[0-9]*$' # for bacula\n\tDENSITY=UNKNOWN\n\n\tif [[ $density =~ $regex ]]; then\n\t\t#matches=${#BASH_REMATCH[*]}\n\t\tif [ ${BASH_REMATCH[1]} = 'L' ]; then\n\t\t\tif [ ${BASH_REMATCH[2]} = 'T' ]; then\n\t\t\t\tDENSITY=\"LTO3\"\n\t\t\telif [ ${BASH_REMATCH[2]} = 'U' ]; then\n\t\t\t\tDENSITY=\"LTO4\"\n\t\t\telif [ ${BASH_REMATCH[2]} = 'V' ]; then\n\t\t\t\tDENSITY=\"LTO5\"\n\t\t\telif [ ${BASH_REMATCH[2]} = 'W' ]; then\n\t\t\t\tDENSITY=\"LTO6\"\n\t\t\telse\n\t\t\t\tDENSITY=\"LTO${BASH_REMATCH[2]}\"\n\t\t\tfi\n\t\telif [ ${BASH_REMATCH[1]} = 'D' ]; then\n\t\t\tif [ ${BASH_REMATCH[2]} = '7' ]; then\n\t\t\t\tDENSITY=\"DLT4\"\n\t\t\tfi\n\t\telif [ ${BASH_REMATCH[1]} = 'S' ]; then\n\t\t\tif [ ${BASH_REMATCH[2]} = '3' ]; then\n\t\t\t\tDENSITY=\"SDLT600\"\n\t\t\telif [ ${BASH_REMATCH[2]} = '2' ]; then\n\t\t\t\tDENSITY=\"SDLT320\"\n\t\t\telif [ ${BASH_REMATCH[2]} = '1' ]; then\n\t\t\t\tDENSITY=\"SDLT220\"\n\t\t\telse\n\t\t\t\tDENSITY=\"SDLT\"\n\t\t\tfi\n\t\telif [ ${BASH_REMATCH[1]} = 'J' ]; then\n\t\t\tif [ ${BASH_REMATCH[2]} = 'A' ]; then\n\t\t\t\tDENSITY=\"J1A\"\n\t\t\telif [ ${BASH_REMATCH[2]} = 'B' ]; then\n\t\t\t\tDENSITY=\"E05\"\n\t\t\telif [ ${BASH_REMATCH[2]} = 'W' ]; then\n\t\t\t\tDENSITY=\"E05\"\n\t\t\telif [ ${BASH_REMATCH[2]} = 'X' ]; then\n\t\t\t\tDENSITY=\"E05\"\n\t\t\telif [ ${BASH_REMATCH[2]} = 'Y' ]; then\n\t\t\t\tDENSITY=\"E07\"\n\t\t\telif [ ${BASH_REMATCH[2]} = 'K' ]; then\n\t\t\t\tDENSITY=\"E07\"\n\t\t\tfi\n\t\telif [ ${BASH_REMATCH[1]} = 'X' ]; then\n\t\t\tDENSITY=\"AIT${BASH_REMATCH[2]}\"\n\t\telif [ ${BASH_REMATCH[1]} = 'T' ]; then\n\t\t\tif [ ${BASH_REMATCH[2]} = 'Z' ]; then\n\t\t\t\tDENSITY=\"9840A\"\n\t\t\telif [ ${BASH_REMATCH[2]} = 'Y' ]; then\n\t\t\t\tDENSITY=\"9840B\"\n\t\t\telif [ ${BASH_REMATCH[2]} = 'X' ]; then\n\t\t\t\tDENSITY=\"9840C\"\n\t\t\telif [ ${BASH_REMATCH[2]} = 'W' ]; then\n\t\t\t\tDENSITY=\"9840D\"\n\t\t\telif [ ${BASH_REMATCH[2]} = 'V' ]; then\n\t\t\t\tDENSITY=\"9940A\"\n\t\t\telif [ ${BASH_REMATCH[2]} = 'U' ]; then\n\t\t\t\tDENSITY=\"9940B\"\n\t\t\telse\n\t\t\t\tDENSITY=\"T10K${BASH_REMATCH[2]}\"\n\t\t\tfi\n\t\tfi\n\tfi\n}\n\n#\n# find_mktape -- set MKTAPE_PATH to path to 'mktape' or exit if not found\n#\nfind_mktape_path()\n{\n\tif [[ $# -gt 0 ]] ; then\n\t\techo \"internal error: $0: no argument expected\" 1>&2\n\t\texit 1\n\tfi\n\tif [[ -s \"$MKTAPE_PATH\" ]] ; then\n\t\t# make sure supplied path works\n\t\tif [[ ! -x $MKTAPE_PATH/mktape ]] ; then\n\t\t\techo \"error: no 'mktape' at specified path: $MKTAPE_PATh\" 1>&2\n\t\t\texit 1\n\t\tfi\n\telse\n\t\t# we must find mktape in our PATH\n\t\tOIFS=\"$IFS\"\n\t\tIFS=':'\n\t\tfor d in $PATH; do\n\t\t\tif [[ -x $d/mktape ]] ; then\n\t\t\t\tMKTAPE_PATH=\"$d\"\n\t\t\t\tIFS=\"$OIFS\"\n\t\t\t\treturn\n\t\t\tfi\n\t\tdone\n\t\techo \"error: no 'mktape' found in PATH\" 1>&2\n\t\texit 1\n\tfi\n}\n\n##################################################################\n## Main starts here...\n##################################################################\n\nTEMP=$(getopt -o 'hH:C:fcm:' --long 'help,home-dir:,config-dir:,force,create-dir,mktape-path:' -n \"$PROG_NAME\" -- \"$@\")\nif [[ $? -ne 0 ]] ; then\n\tusage\n\texit 1\nfi\neval set - \"$TEMP\"\nunset TEMP\n\nwhile true; do\n\tcase \"$1\" in\n\t'-h'|'--help')\n\t\tusage\n\t\texit 0\n\t\t;;\n\t'-H'|'--home-dir')\n\t\tPARAM_MHVTL_HOME_PATH=\"$2\"\n\t\tshift 2\n\t\tcontinue\n\t\t;;\n\t'-C'|'--config-dir')\n\t\tMHVTL_CONFIG_PATH=\"$2\"\n\t\tshift 2\n\t\tcontinue\n\t\t;;\n\t'-f'|'--force')\n\t\tFORCE='1'\n\t\tshift\n\t\tcontinue\n\t\t;;\n\t'-c'|'--create-dir')\n\t\tCREATE_DIR='1'\n\t\tshift\n\t\tcontinue\n\t\t;;\n\t'-m'|'--mktape-path')\n\t\tMKTAPE_PATH=\"$2\"\n\t\tshift 2\n\t\tcontinue\n\t\t;;\n\t'--')\n\t\tshift\n\t\tbreak\n\t\t;;\n\t*)\n\t\techo \"internal error: unknown arg: $1\" 1>&2\n\t\texit 1\n\tesac\ndone\n\n# should be no more arguments\nif [[ $# -gt 0 ]] ; then\n\techo \"error: too many arguments\"\n\tusage\n\texit 1\nfi\n\nif [[ ! -z \"$MHVTL_CONFIG_PATH\" ]] ; then\n\tCONFIG_FILE=\"$MHVTL_CONFIG_PATH/mhvtl.conf\"\nfi\nif [[ ! -r $CONFIG_FILE ]] ; then\n\techo \"error: config file not found: $CONFIG_FILE\" 1>&2\n\texit 1\nfi\n\n# get default capacity\n. $CONFIG_FILE\n\n# Set default capacity to 500M if not defined.\nCAPACITY=${CAPACITY:=500}\n\n# override home dir if passed in by user\nif [[ ! -z \"$PARAM_MHVTL_HOME_PATH\" ]] ; then\n\tMHVTL_HOME_PATH=$PARAM_MHVTL_HOME_PATH\nfi\n\nif [[ ! -d $MHVTL_HOME_PATH ]] ; then\n\tif [[ -z \"$CREATE_DIR\" ]] ; then\n\t\techo \"error: no such directory: $MHVTL_HOME_PATH\" 1>&2\n\t\tusage\n\t\texit 1\n\tfi\n\techo \"warning: creating directory: $MHVTL_HOME_PATH\" 1>&2\n\tmkdir -p $MHVTL_HOME_PATH\n\tchmod 755 $MHVTL_HOME_PATH\nfi\n\n# Create any media specified in library config.\numask 022\n\nif [[ ! -r $MHVTL_CONFIG_PATH/$DEVICE_CONF ]] ; then\n\techo \"error: not found: $MHVTL_CONFIG_PATH/$DEVICE_CONF\" 1>&2\n\texit 1\nfi\n\n# make sure we can find mktape\nfind_mktape_path\n\n# for LIBCONTENTS in $MHVTL_CONFIG_PATH/library_contents.*\necho '===>' \"Reading from $MHVTL_CONFIG_PATH/$DEVICE_CONF file to find Tape Libraries and Drives ...\"\nfor LIBID in $(awk '/Library:/ {print $2}' $MHVTL_CONFIG_PATH/$DEVICE_CONF) ; do\n\tLIBCONTENTS=\"$MHVTL_CONFIG_PATH/library_contents.$LIBID\"\n\n\tif [[ ! -r $LIBCONTENTS ]] ; then\n\t\techo \"error: not found: $LIBCONTENTS\" 1>&2\n\t\techo \"have you ran 'generate_library_contents'?\" 1>&2\n\t\texit 1\n\tfi\n\techo '===>' \"Scanning for 'Slot' entries in $LIBCONTENTS ...\"\n\tfor a in $(awk '/^Slot/ {print $3}' <$LIBCONTENTS|sort -u) ; do\n\t\tif [[ -d $MHVTL_HOME_PATH/$a ]] ; then\n\t\t\tif [[ -z \"$FORCE\" ]] ; then\n\t\t\t\techo \"Directory already exists: $MHVTL_HOME_PATH/$a: skipping\"\n\t\t\t\tcontinue\n\t\t\tfi\n\t\t\techo \"warning: removing entry: $MHVTL_HOME_PATH/$a\"\n\t\t\trm -rf $MHVTL_HOME_PATH/$a\n\t\tfi\n\t\techo '===>' \"Creating entry: $MHVTL_HOME_PATH/$a ...\"\n\t\tset_density $a\n\t\tset_media_type $a\n\t\t# pass in \"-D[0-9]\" for debugging, \"-v\" for verbosity\n\t\t$MKTAPE_PATH/mktape -v -D5 -l $LIBID -s $CAPACITY -t $MEDIA_TYPE -m $a -d $DENSITY \\\n\t\t\t-C $MHVTL_CONFIG_PATH -H $MHVTL_HOME_PATH\n\t\tres=$?\n\t\t[[ $res -eq 0 ]] || exit 1\n\tdone\ndone\n"
  },
  {
    "path": "usr/cmd/mhvtl-device-conf-generator.c",
    "content": "/*\n * mhvtl-device-conf-generator -- systemd generator for mhvtl\n *\n * This program read device.conf and creates the appropriate systemd\n * unit files and dependencies\n *\n * NOTE: This program assumes the existance of systemd template\n * files for vtllibrary and vtltape\n */\n\n#include <sys/stat.h>\n#include <stdarg.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <fcntl.h>\n#include <errno.h>\n#include \"vtllib.h\"\n\n#define MAX_LINE_WIDTH 1024\n\n#ifndef MHVTL_CONFIG_PATH\n#define MHVTL_CONFIG_PATH \"/etc/mhvtl\"\n#endif\n\nextern char *__progname;\nstatic int\t debug_mode\t\t\t = 0;\nchar\t\t mhvtl_driver_name[] = \"\";\n\nstruct vtl_info {\n\tint\t\t\t\t num;\n\tstruct vtl_info *next;\n};\n\nstatic struct vtl_info our_tapes\t = {.num = -1, .next = NULL};\nstatic struct vtl_info our_libraries = {.num = -1, .next = NULL};\n\nstatic struct vtl_info *last_tape\t = &our_tapes;\nstatic struct vtl_info *last_library = &our_libraries;\n\n/*\n * A very thin wrapper to print to the kernel log. Since when the device\n * config generator is run, syslog is not up yet, generally, nothing is up yet,\n * the only place really to print information that needs to be preserved to\n * is the kernel log. Since it is the only place, it is done here on a\n * best-effort basis.\n * For the description of the levels, see\n * https://www.kernel.org/doc/html/latest/core-api/printk-basics.html\n * Broadly speaking, 3 (ERR) or 2 (CRIT) should cover this tool's needs\n */\n__attribute__((__format__(__printf__, 2, 3))) static void pr_klog(int level, const char *fmt, ...) {\n\tint\t\tfd;\n\tchar\tbuf[1024];\n\tva_list ap;\n\tint\t\trc;\n\tint\t\tsaved_errno = errno; /* Don't clobber errno */\n\n\tif (level < 0 || level > 7)\n\t\tlevel = 3;\n\n\tsnprintf(buf, sizeof(buf), \"<%d>\", level);\n\tva_start(ap, fmt);\n\tvsnprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), fmt, ap);\n\tva_end(ap);\n\n\tfd = open(\"/dev/kmsg\", O_WRONLY);\n\tif (fd == -1) {\n\t\tif (debug_mode)\n\t\t\t(void)fprintf(stderr, \"Cannot open /dev/kmsg: %s\\n\", strerror(errno));\n\t\terrno = saved_errno;\n\t\treturn;\n\t}\n\n\trc = write(fd, buf, strlen(buf));\n\tif (rc) {}; /* Silence warn_unused_result - not much to do if it fails */\n\tclose(fd);\n\n\terrno = saved_errno;\n\treturn;\n}\n\n/*\n * return 1 if path is a writable directory, else return 0\n */\nstatic int is_writable_dir(char *path) {\n\tstruct stat sb;\n\tint\t\t\tres = 0; /* default to \"no\" */\n\n\tif (lstat(path, &sb) < 0)\n\t\tgoto dun;\n\tif (!S_ISDIR(sb.st_mode))\n\t\tgoto dun;\n\tres = (access(path, W_OK) == 0);\ndun:\n\tif (debug_mode)\n\t\t(void)printf(\"DEBUG: %s is%s writable\\n\", path,\n\t\t\t\t\t res ? \"\" : \" not\");\n\treturn res;\n}\n\n/*\n * scan arguments and return the \"normal_dir\" if all goes well,\n * else return NULL\n */\nstatic char *get_working_dir(int argc, char **argv) {\n\tchar *normal_dir;\n\n\t/* skip program name */\n\targc--;\n\targc++;\n\n\tif ((argc > 1) && !strcmp(argv[1], \"-d\")) {\n\t\tdebug_mode++;\n\t\targc--;\n\t\targv++;\n\t}\n\n\tif (argc != 4) {\n\t\tif (debug_mode)\n\t\t\t(void)fprintf(stderr, \"DEBUG: error: expected 3 arguments, got %d\\n\", argc);\n\t\treturn NULL;\n\t}\n\n\tif (debug_mode)\n\t\t(void)printf(\"DEBUG: normal=%s, early=%s, late=%s\\n\",\n\t\t\t\t\t argv[1], argv[2], argv[3]);\n\tnormal_dir = argv[1];\n\n\t/* we care about normal dir, so make sure it's real */\n\tif (!is_writable_dir(normal_dir)) {\n\t\tif (debug_mode)\n\t\t\t(void)fprintf(stderr, \"DEBUG: error: not a writable dir: %s\\n\", normal_dir);\n\t\treturn NULL;\n\t}\n\n\treturn normal_dir;\n}\n\n/*\n * add to the end of the linked list of libraries\n *\n * return bool success (0 -> fail, else success)\n */\nstatic int add_to_libraries(int lib_num) {\n\tstruct vtl_info *info;\n\n\tif (debug_mode)\n\t\t(void)printf(\"DEBUG: add_to_libraries(%d): entering\\n\", lib_num);\n\n\tif (lib_num <= 0)\n\t\treturn 0;\n\n\tinfo = malloc(sizeof(struct vtl_info));\n\tif (info == NULL) {\n\t\tif (debug_mode)\n\t\t\t(void)fprintf(stderr, \"DEBUG: error: no memory\\n\");\n\t\treturn 0;\n\t}\n\n\tinfo->num  = lib_num;\n\tinfo->next = NULL;\n\n\tlast_library->next = info;\n\tlast_library\t   = info;\n\n\treturn 1;\n}\n\n/*\n * add to the end of the linked list of drives for a library\n *\n * return bool success (0 -> fail, else success)\n */\nstatic int add_to_tapes(int tape_num) {\n\tstruct vtl_info *info;\n\n\tif (debug_mode)\n\t\t(void)printf(\"DEBUG: add_to_tapes(%d): entering\\n\", tape_num);\n\n\tif (tape_num <= 0)\n\t\treturn 0;\n\n\tinfo = malloc(sizeof(struct vtl_info));\n\tif (info == NULL) {\n\t\tif (debug_mode)\n\t\t\t(void)fprintf(stderr, \"DEBUG: error: no memory\\n\");\n\t\treturn 0;\n\t}\n\n\tinfo->num  = tape_num;\n\tinfo->next = NULL;\n\n\tlast_tape->next = info;\n\tlast_tape\t\t= info;\n\n\treturn 1;\n}\n\n/*\n * parse the device.conf configuration file into our_tape_library\n *\n * This file has \"Library\" entries, and it has \"Drive\" entries. The\n * default configuration file has two library entries, and each\n * of those is followed by a number of drive entriess that go with\n * that library. But do NOT assume the file will be sorted in\n * this order. But DO assume that a library will not be referenced\n * before it is mentioned by a drive that uses it\n */\nstatic int parse_config_file(char *path) {\n\tFILE *fp = NULL;\n\tchar  line_buf[MAX_LINE_WIDTH + 1];\n\tchar *cp\t\t  = NULL;\n\tint\t  tape_num\t  = -1;\n\tint\t  library_num = -1;\n\n\tif (debug_mode)\n\t\t(void)fprintf(stderr, \"DEBUG: parsing config file: %s\\n\",\n\t\t\t\t\t  path);\n\tif ((fp = fopen(path, \"r\")) == NULL) {\n\t\tpr_klog(3, \"%s: Cannot open config file %s: %s\\n\",\n\t\t\t\t__progname, path, strerror(errno));\n\t\tif (debug_mode)\n\t\t\t(void)fprintf(stderr, \"DEBUG: error: cannot open config file %s: %s\\n\",\n\t\t\t\t\t\t  path, strerror(errno));\n\t\treturn -1;\n\t}\n\n\twhile ((cp = fgets(line_buf, MAX_LINE_WIDTH, fp)) != NULL) {\n\t\tif (*cp == '\\n')\n\t\t\tcontinue; // blank line\n\t\tif (*cp == '#')\n\t\t\tcontinue; // comment line\n\t\tif (*cp == ' ')\n\t\t\tcontinue; // the middle of some record\n\t\tif (strncmp(cp, \"Library: \", 9) == 0) {\n\t\t\t/* found a Library entry */\n\t\t\tlibrary_num = strtol(cp + 9, NULL, 0);\n\t\t\tif (!add_to_libraries(library_num))\n\t\t\t\tgoto dun;\n\t\t} else if (strncmp(cp, \"Drive: \", 7) == 0) {\n\t\t\t/* found a Drive entry */\n\t\t\ttape_num = strtol(cp + 7, NULL, 0);\n\t\t\tif (!add_to_tapes(tape_num))\n\t\t\t\tgoto dun;\n\t\t}\n\t}\n\ndun:\n\t(void)fclose(fp);\n\treturn 0;\n}\n\nint main(int argc, char **argv) {\n\tchar\t\t\t device_conf[CONF_FILE_SZ];\n\tchar\t\t\t*working_dir;\n\tstruct vtl_info *ip;\n\tconst char\t\t dirname[] = \"mhvtl.target.wants\";\n\tchar\t\t\t*path;\n\tint\t\t\t\t rc;\n\n\tif (get_config(device_conf, DEVICE_CONF, my_id) < 0)\n\t\texit(1);\n\n\tworking_dir = get_working_dir(argc, argv);\n\tif (!working_dir)\n\t\texit(1);\n\n\t/*\n\t * parse the device.conf config file\n\t *\n\t * for each library found:\n\t *\t- set up vtllibrary unit\n\t *\t- for each tape that uses that library\n\t *\t\t- set up vtltape for that tape unit\n\t */\n\n\t/* put config in our_tape_library */\n\trc = parse_config_file(device_conf);\n\tif (rc == -1)\n\t\texit(1);\n\n\tif (debug_mode) {\n\t\t(void)printf(\"DEBUG: Libraries:\\n\");\n\t\tfor (ip = our_libraries.next; ip != NULL; ip = ip->next)\n\t\t\t(void)printf(\"DEBUG:  %d\\n\", ip->num);\n\n\t\t(void)printf(\"DEBUG: Tapes:\\n\");\n\t\tfor (ip = our_tapes.next; ip != NULL; ip = ip->next)\n\t\t\t(void)printf(\"DEBUG:  %d\\n\", ip->num);\n\t}\n\n\tif (asprintf(&path, \"%s/%s\", working_dir, dirname) < 0) {\n\t\tperror(\"Could not allocate memory (for directory path)\");\n\t\texit(1);\n\t}\n\tif (debug_mode)\n\t\tprintf(\"DEBUG: creating dir: %s\\n\", path);\n\tif (mkdir(path, 0755) < 0) {\n\t\tif (debug_mode)\n\t\t\t(void)fprintf(stderr, \"DEBUG: error: can't mkdir %s: %s\\n\",\n\t\t\t\t\t\t  path, strerror(errno));\n\t\t// clean up?\n\t\texit(1);\n\t}\n\tfree(path);\n\n\tif (debug_mode)\n\t\tprintf(\"DEBUG: scanning libraries ...\\n\");\n\tfor (ip = our_libraries.next; ip != NULL; ip = ip->next) {\n\t\tchar *from_path, *to_path;\n\t\tif ((asprintf(&from_path, \"%s/%s/vtllibrary@%d.service\", working_dir, dirname, ip->num) < 0) ||\n\t\t\t(asprintf(&to_path, \"%s/vtllibrary@.service\", SYSTEMD_SERVICE_DIR) < 0)) {\n\t\t\tperror(\"Could not allocate memory (for vtllibrary template symlink)\");\n\t\t\texit(1);\n\t\t}\n\t\tif (debug_mode)\n\t\t\t(void)fprintf(stderr, \"DEBUG: creating symlink: %s => %s\\n\", from_path, to_path);\n\t\tif (symlink(to_path, from_path) < 0) {\n\t\t\tif (debug_mode)\n\t\t\t\t(void)fprintf(stderr, \"DEBUG: error: can't create symlink (%d): %s => %s\\n\",\n\t\t\t\t\t\t\t  errno, from_path, to_path);\n\t\t\t// clean up?\n\t\t\texit(1);\n\t\t}\n\t\tfree(from_path);\n\t\tfree(to_path);\n\t}\n\tif (debug_mode)\n\t\tprintf(\"DEBUG: scanning tapes ...\\n\");\n\tfor (ip = our_tapes.next; ip != NULL; ip = ip->next) {\n\t\tchar *from_path, *to_path;\n\t\tif ((asprintf(&from_path, \"%s/%s/vtltape@%d.service\", working_dir, dirname, ip->num) < 0) ||\n\t\t\t(asprintf(&to_path, \"%s/vtltape@.service\", SYSTEMD_SERVICE_DIR) < 0)) {\n\t\t\tperror(\"Could not allocate memory (for vtltape template symlink)\");\n\t\t\texit(1);\n\t\t}\n\t\tif (debug_mode)\n\t\t\t(void)fprintf(stderr, \"DEBUG: creating symlink: %s => %s\\n\", from_path, to_path);\n\t\tif (symlink(to_path, from_path) < 0) {\n\t\t\tif (debug_mode)\n\t\t\t\t(void)fprintf(stderr, \"DEBUG: error: can't create symlink (%d): %s => %s\\n\",\n\t\t\t\t\t\t\t  errno, from_path, to_path);\n\t\t\t// clean up?\n\t\t\texit(1);\n\t\t}\n\t\tfree(from_path);\n\t\tfree(to_path);\n\t}\n\n\texit(0);\n}\n"
  },
  {
    "path": "usr/cmd/mhvtl_kernel_mod_build.in",
    "content": "#!/bin/bash\n\n# Used to automate the building of the mhvtl.ko module\n# on a running system - without requiring the whole source\n\nBUILD=$(mktemp -u -t tmp.XXXXXXXXXX)\n\nmodule_source=@FIRMWAREDIR@/mhvtl/mhvtl_kernel.tgz\n\nif [ ! -d ${BUILD} ]; then\n\tmkdir -p ${BUILD}\nfi\n\ncd ${BUILD}\ntar xfz ${module_source}\n\nmake && sudo make install\n\nrm -r ${BUILD}\n"
  },
  {
    "path": "usr/cmd/mktape.c",
    "content": "/*\n * mktape\n *\n */\n\n#include <unistd.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n#include <inttypes.h>\n#include \"be_byteshift.h\"\n#include \"vtlcart.h\"\n#include \"vtllib.h\"\n\n#if defined _LARGEFILE64_SOURCE\nstatic void *largefile_support = \"large file support\";\n#else\nstatic void *largefile_support = \"No largefile support\";\n#endif\n\n/* The following variables are needed for the MHVTL_DBG() macro to work. */\n\nchar mhvtl_driver_name[] = \"mktape\";\n\nstatic void usage(char *progname) {\n\tprintf(\"Usage: %s [OPTIONS] [REQUIRED-PARAMS]\", progname);\n\tprintf(\"Where OPTIONS are from:\\n\");\n\tprintf(\"      -h    -- print this message and exit\\n\");\n\tprintf(\"      -v    -- verbose\\n\");\n\tprintf(\"      -D[N] -- set debug level to N [1]\\n\");\n\tprintf(\"      -V    -- print Version and exit\\n\");\n\tprintf(\"      -C config-dir -- override default config dir [ %s ]\\n\",\n\t\t   MHVTL_CONFIG_PATH);\n\tprintf(\"      -H home-dir   -- override default home dir [ %s ]\\n\",\n\t\t   MHVTL_HOME_PATH);\n\tprintf(\"And REQUIRED-PARAMS are:\\n\");\n\tprintf(\"      -l lib      -- set Library number\\n\");\n\tprintf(\"      -m PCL      -- set Physical Cartrige Label (barcode)\\n\");\n\tprintf(\"      -s size     -- set size in Megabytes\\n\");\n\tprintf(\"      -t type     -- set to data, clean, WORM, or NULL\\n\");\n\tprintf(\"      -d density  -- set density to one of:\\n\");\n\tprintf(\"           AIT1     AIT2     AIT3     AIT4\\n\");\n\tprintf(\"           DDS1     DDS2     DDS3     DDS4\\n\");\n\tprintf(\"           DLT3     DLT4\\n\");\n\tprintf(\"           SDLT1    SDLT220  SDLT320  SDLT600\\n\");\n\tprintf(\"           LTO1     LTO2     LTO3     LTO4\\n\");\n\tprintf(\"           LTO5     LTO6     LTO7     LTO8\\n\");\n\tprintf(\"           T10KA    T10KB    T10KC\\n\");\n\tprintf(\"           9840A    9840B    9840C    9840D\\n\");\n\tprintf(\"           9940A    9940B\\n\");\n\tprintf(\"           J1A      E05      E06      E07\\n\");\n\tprintf(\"\\n\");\n}\n\nint gettime() {\n\tconst char *source_date_epoch = getenv(\"SOURCE_DATE_EPOCH\");\n\ttime_t\t\tt;\n\tif (source_date_epoch == NULL || (t = (time_t)strtoll(source_date_epoch, NULL, 10)) <= 0)\n\t\tt = time(NULL);\n\treturn t;\n}\n\nint main(int argc, char *argv[]) {\n\tunsigned char sam_stat;\n\tchar\t\t *progname\t\t= argv[0];\n\tchar\t\t *pcl\t\t\t= NULL;\n\tchar\t\t *mediaType\t\t= NULL;\n\tchar\t\t *mediaCapacity = NULL;\n\tchar\t\t *density\t\t= NULL;\n\tchar\t\t *lib\t\t\t= NULL;\n\tuint64_t\t  size;\n\tint\t\t\t  libno;\n\tint\t\t\t  opt;\n\tint\t\t\t  res;\n\tchar\t\t *param_config_dir = NULL;\n\tchar\t\t *param_home_dir   = NULL;\n\tchar\t\t  ver[64];\n\tint\t\t\t  major, minor;\n\tint\t\t\t  ret;\n\n\tif (argc < 2) {\n\t\tfprintf(stderr, \"error: not enough arguments\\n\");\n\t\tusage(progname);\n\t\texit(1);\n\t}\n\n\twhile ((opt = getopt(argc, argv, \"d:l:m:s:t:VvD::hC:H:\")) != -1) {\n\t\tswitch (opt) {\n\t\tcase 'h':\n\t\t\tusage(progname);\n\t\t\texit(0);\n\t\tcase 'd':\n\t\t\tdensity = strdup(optarg);\n\t\t\tbreak;\n\t\tcase 'l':\n\t\t\tlib = strdup(optarg);\n\t\t\tbreak;\n\t\tcase 'm':\n\t\t\tpcl = strdup(optarg);\n\t\t\tbreak;\n\t\tcase 's':\n\t\t\tmediaCapacity = strdup(optarg);\n\t\t\tbreak;\n\t\tcase 't':\n\t\t\tmediaType = strdup(optarg);\n\t\t\tbreak;\n\t\tcase 'C':\n\t\t\tparam_config_dir = strdup(optarg);\n\t\t\tbreak;\n\t\tcase 'H':\n\t\t\tparam_home_dir = strdup(optarg);\n\t\t\tbreak;\n\t\tcase 'V':\n\t\t\tprintf(\"%s: version %s\\n\", progname, MHVTL_VERSION);\n\t\t\tprintf(\"%s\\n\", (char *)largefile_support);\n\t\t\texit(0);\n\t\tcase 'D':\n\t\t\tif (optarg)\n\t\t\t\tdebug = strtol(optarg, NULL, 0);\n\t\t\telse\n\t\t\t\tdebug++;\n\t\t\tbreak;\n\t\tcase 'v':\n\t\t\tverbose++;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tfprintf(stderr, \"error: unknown option: %c\\n\", opt);\n\t\t\tusage(progname);\n\t\t\texit(1);\n\t\t}\n\t}\n\n\tif (pcl == NULL) {\n\t\tfprintf(stderr, \"error: Please supply a barcode (-m barcode)\\n\\n\");\n\t\tusage(progname);\n\t\texit(1);\n\t}\n\tif (mediaCapacity == NULL) {\n\t\tfprintf(stderr, \"error: Please supply media capacity (-s xx)\\n\\n\");\n\t\tusage(progname);\n\t\texit(1);\n\t}\n\tif (mediaType == NULL) {\n\t\tfprintf(stderr, \"error: Please supply cart type (-t data|clean|WORM|NULL)\\n\\n\");\n\t\tusage(progname);\n\t\texit(1);\n\t}\n\tif (lib == NULL) {\n\t\tfprintf(stderr, \"error: Please supply Library number (-l xx)\\n\\n\");\n\t\tusage(progname);\n\t\texit(1);\n\t}\n\tif (density == NULL) {\n\t\tfprintf(stderr, \"error: Please supply media density (-d xx)\\n\\n\");\n\t\tusage(progname);\n\t\texit(1);\n\t}\n\n\tsscanf(mediaCapacity, \"%\" PRId64, &size);\n\tif (size == 0)\n\t\tsize = 8000;\n\n\tsscanf(lib, \"%d\", &libno);\n\tif (!libno) {\n\t\tfprintf(stderr, \"error: Invalid library number\\n\");\n\t\texit(1);\n\t}\n\n\tret = sscanf(MHVTL_VERSION, \"%d.%d\", &major, &minor);\n\tsprintf(ver, \"vtl-%d.%d      \", major, minor);\n\tif (ret != 2) {\n\t\tprintf(\"Warning: Attempting to retrieve version string from %s failed\\n\", MHVTL_VERSION);\n\t}\n\n\tif (param_home_dir)\n\t\tstrncpy(home_directory, param_home_dir, HOME_DIR_PATH_SZ);\n\telse\n\t\tfind_media_home_directory(param_config_dir, libno);\n\n\tif (strlen(pcl) > MAX_BARCODE_LEN) {\n\t\tfprintf(stderr, \"error: Max barcode length (%d) exceeded\\n\\n\", MAX_BARCODE_LEN);\n\t\tusage(progname);\n\t\texit(1);\n\t}\n\n\t/* Initialize the contents of the MAM to be used for the new PCL. */\n\tinit_mam(&mam);\n\n\tmam.tape_fmt_version = TAPE_FMT_VERSION;\n\tmam.mam_fmt_version\t = MAM_VERSION;\n\tput_unaligned_be64(size * 1048576, &mam.max_capacity);\n\tput_unaligned_be64(size * 1048576, &mam.remaining_capacity);\n\tput_unaligned_be64(mam.max_capacity - sizeof(struct MAM), &mam.MAMSpaceRemaining);\n\n\tmemcpy(&mam.MediumManufacturer, \"linuxVTL\", 8);\n\tmemcpy(&mam.ApplicationVendor, &ver, 8);\n\tsprintf((char *)mam.ApplicationVersion, \"%d\", TAPE_FMT_VERSION);\n\n\tif (!strncmp(\"clean\", mediaType, 5)) {\n\t\tmam.MediumType\t\t\t  = MEDIA_TYPE_CLEAN; /* Cleaning cart */\n\t\tmam.MediumTypeInformation = 20;\t\t\t\t  /* Max cleaning loads */\n\t} else if (!strncmp(\"NULL\", mediaType, 4)) {\n\t\tmam.MediumType = MEDIA_TYPE_NULL; /* save metadata only */\n\t} else if (!strncmp(\"WORM\", mediaType, 4)) {\n\t\tmam.MediumType = MEDIA_TYPE_WORM; /* WORM cart */\n\t} else {\n\t\tmam.MediumType = MEDIA_TYPE_DATA; /* Normal data cart */\n\t}\n\tset_media_params(&mam, density);\n\n\tsprintf((char *)mam.MediumSerialNumber, \"%s_%d\", pcl, (int)gettime());\n\tsprintf((char *)mam.MediumManufactureDate, \"%d\", (int)gettime());\n\tsprintf((char *)mam.Barcode, \"%-31s\", pcl);\n\n\t/* Create the PCL using the initialized MAM. */\n\n\tif (verbose)\n\t\tprintf(\"Creating tape data ...\\n\");\n\tres = create_tape(pcl, &sam_stat);\n\n\texit(res);\n}\n"
  },
  {
    "path": "usr/cmd/tape_util.c",
    "content": "/*\n *\tDump headers of 'tape' datafile\n *\n * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n */\n\n#define _FILE_OFFSET_BITS 64\n\n#include <unistd.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <string.h>\n#include <inttypes.h>\n#include <zlib.h>\n#include \"minilzo.h\"\n#include \"be_byteshift.h\"\n#include \"mhvtl_scsi.h\"\n#include \"mhvtl_list.h\"\n#include \"vtl_common.h\"\n#include \"vtllib.h\"\n#include \"vtlcart.h\"\n#include \"q.h\"\n#include \"ssc.h\"\n\n#define MEDIA_WRITABLE 0\n#define MEDIA_READONLY 1\n\nchar\t   mhvtl_driver_name[] = \"tape_util\";\nstatic int dump_tape\t\t   = 0; /* dual personality - dump_tape & preload_tape */\n\nstatic char *progname;\n\nstatic void print_mam_info(void) {\n\tuint64_t\t\t  size;\n\tuint64_t\t\t  remaining;\n\tchar\t\t\t  size_mul;\t  /* K/M/G/T/P multiplier */\n\tchar\t\t\t  remain_mul; /* K/M/G/T/P multiplier */\n\tint\t\t\t\t  a;\n\tstatic const char mul[] = \" KMGT\";\n\n\tsize\t  = get_unaligned_be64(&mam.max_capacity);\n\tremaining = get_unaligned_be64(&mam.remaining_capacity);\n\n\tsize_mul = remain_mul = ' ';\n\tfor (a = 0; a < 4; a++) {\n\t\tif (size > 5121) {\n\t\t\tsize >>= 10; /* divide by 1024 */\n\t\t\tsize_mul = mul[a + 1];\n\t\t}\n\t}\n\tfor (a = 0; a < 4; a++) {\n\t\tif (remaining > 5121) {\n\t\t\tremaining >>= 10; /* divide by 1024 */\n\t\t\tremain_mul = mul[a + 1];\n\t\t}\n\t}\n\n\tprintf(\"Media density code: 0x%02x\\n\", mam.MediumDensityCode);\n\tprintf(\"Media type code   : 0x%02x\\n\", mam.MediaType);\n\tprintf(\"Media description : %s\\n\", mam.media_info.description);\n\tprintf(\"Tape Capacity     : %\" PRId64 \" (%\" PRId64 \" %cBytes)\\n\",\n\t\t   get_unaligned_be64(&mam.max_capacity),\n\t\t   size, size_mul);\n\tswitch (mam.MediumType) {\n\tcase MEDIA_TYPE_CLEAN:\n\t\tprintf(\"Media type        : Cleaning media\\n\");\n\t\tbreak;\n\tcase MEDIA_TYPE_DATA:\n\t\tprintf(\"Media type        : Normal data\\n\");\n\t\tbreak;\n\tcase MEDIA_TYPE_NULL:\n\t\tprintf(\"Media type        : NULL - Use with caution !!\\n\");\n\t\tbreak;\n\tcase MEDIA_TYPE_WORM:\n\t\tprintf(\"Media type        : Write Once Read Many (WORM)\\n\");\n\t\tbreak;\n\tdefault:\n\t\tprintf(\"Media type        : Unknown - please report !!\\n\");\n\t\tbreak;\n\t}\n\n\tprintf(\"Media             : %s\\n\",\n\t\t   (mam.Flags & MAM_FLAGS_MEDIA_WRITE_PROTECT) ? \"Write-protected\" : \"read-write\");\n\tprintf(\"Remaining Tape Capacity : %\" PRId64 \" (%\" PRId64 \" %cBytes)\\n\",\n\t\t   get_unaligned_be64(&mam.remaining_capacity),\n\t\t   remaining, remain_mul);\n}\n\nstatic void init_lunit(struct lu_phy_attr *lu, struct priv_lu_ssc *priv_lu) {\n\tif (debug)\n\t\tprintf(\"Entering %s() +++\\n\", __func__);\n\tmemset(lu, 0, sizeof(struct lu_phy_attr));\n\n\tlu->lu_private = priv_lu;\n\tlu->sense_p\t   = sense;\n\tstrncpy(lu->lu_serial_no, \"ABC123\", 7);\n\tstrncpy(lu->vendor_id, \"TAPE_UTL\", 9);\n\tstrncpy(lu->product_id, \"xyzz\", 5);\n\tINIT_LIST_HEAD(&lu->den_list);\n\tINIT_LIST_HEAD(&lu->mode_pg);\n\tINIT_LIST_HEAD(&lu->log_pg);\n}\n\nstatic void init_lu_ssc(struct priv_lu_ssc *lu_priv) {\n\tif (debug)\n\t\tprintf(\"Entering %s() +++\\n\", __func__);\n\tmemset(lu_priv, 0, sizeof(struct priv_lu_ssc));\n\n\tlu_priv->bufsize\t\t\t\t = 2 * 1024 * 1024;\n\tlu_priv->load_status\t\t\t = TAPE_UNLOADED;\n\tlu_priv->inLibrary\t\t\t\t = 0;\n\tlu_priv->sam_status\t\t\t\t = SAM_STAT_GOOD;\n\tlu_priv->MediaWriteProtect\t\t = MEDIA_WRITABLE;\n\tlu_priv->capacity_unit\t\t\t = 1;\n\tlu_priv->configCompressionFactor = Z_BEST_SPEED;\n\tlu_priv->bytesRead_I\t\t\t = 0;\n\tlu_priv->bytesRead_M\t\t\t = 0;\n\tlu_priv->bytesWritten_I\t\t\t = 0;\n\tlu_priv->bytesWritten_M\t\t\t = 0;\n\tlu_priv->c_pos\t\t\t\t\t = c_pos;\n\tlu_priv->KEY_INSTANCE_COUNTER\t = 0;\n\tlu_priv->DECRYPT_MODE\t\t\t = 0;\n\tlu_priv->ENCRYPT_MODE\t\t\t = 0;\n\tlu_priv->app_encr_info\t\t\t = &app_encryption_state;\n\tlu_priv->OK_2_write\t\t\t\t = &OK_to_write;\n\tlu_priv->mamp\t\t\t\t\t = &mam;\n\tINIT_LIST_HEAD(&lu_priv->supported_media_list);\n\tlu_priv->pm\t\t\t\t= NULL;\n\tlu_priv->state_msg\t\t= NULL;\n\tlu_priv->delay_load\t\t= 0;\n\tlu_priv->delay_unload\t= 0;\n\tlu_priv->delay_thread\t= 0;\n\tlu_priv->delay_position = 0;\n\tlu_priv->delay_rewind\t= 0;\n}\n\n/* Fix me - make sure it's not a WORM, cleaning cart etc */\nuint8_t check_restrictions(struct scsi_cmd *cmd) {\n\tif (debug)\n\t\tprintf(\"Entering %s() +++\\n\", __func__);\n\t*lu_ssc.OK_2_write = 1;\n\treturn 1;\n}\n\nuint8_t valid_encryption_blk(struct scsi_cmd *cmd) {\n\tif (debug)\n\t\tprintf(\"Entering %s() +++\\n\", __func__);\n\treturn TRUE;\n}\n\nvoid register_ops(struct lu_phy_attr *lu, int op, void *f, void *g, void *h) {\n\tif (debug)\n\t\tprintf(\"Entering %s() +++\\n\", __func__);\n}\n\nvoid ssc_personality_module_register(struct ssc_personality_template *pm) {\n\tif (debug)\n\t\tprintf(\"Entering %s() +++\\n\", __func__);\n\tlu_ssc.pm = pm;\n\tif (debug)\n\t\tprintf(\"Exiting %s() ++\\n\", __func__);\n}\n\nstatic struct media_details *check_media_can_load(struct list_head *mdl, int mt) {\n\tstruct media_details *m_detail;\n\tif (debug)\n\t\tprintf(\"Entering %s() +++\\n\", __func__);\n\n\tif (debug)\n\t\tprintf(\"Looking for media_type: 0x%02x\\n\", mt);\n\n\tlist_for_each_entry(m_detail, mdl, siblings) {\n\t\tif (debug)\n\t\t\tprintf(\"testing against m_detail->media_type (0x%02x)\\n\",\n\t\t\t\t   m_detail->media_type);\n\t\tif (m_detail->media_type == (unsigned int)mt)\n\t\t\treturn m_detail;\n\t}\n\treturn NULL;\n}\n\nstatic int lookup_media_int(struct name_to_media_info *media_info, char *s) {\n\tunsigned int i;\n\tif (debug)\n\t\tprintf(\"Entering %s() +++\\n\", __func__);\n\n\tif (debug)\n\t\tprintf(\"looking for media type %s\\n\", s);\n\n\tfor (i = 0; media_info[i].media_density != 0; i++)\n\t\tif (!strcmp(media_info[i].name, s))\n\t\t\treturn media_info[i].media_type;\n\n\treturn Media_undefined;\n}\n\nint add_drive_media_list(struct lu_phy_attr *lu, int status, char *s) {\n\tstruct priv_lu_ssc\t *lu_tape;\n\tstruct media_details *m_detail;\n\tstruct list_head\t *den_list;\n\tint\t\t\t\t\t  media_type;\n\n\tif (debug)\n\t\tprintf(\"Entering %s() +++\\n\", __func__);\n\tlu_tape\t = (struct priv_lu_ssc *)lu->lu_private;\n\tden_list = &lu_tape->supported_media_list;\n\n\tif (debug)\n\t\tprintf(\"Adding %s, status: 0x%02x\\n\", s, status);\n\tmedia_type = lookup_media_int(lu_tape->pm->media_handling, s);\n\tm_detail   = check_media_can_load(den_list, media_type);\n\n\tif (m_detail) {\n\t\tif (debug)\n\t\t\tprintf(\"Existing status for %s, Load Capability: 0x%02x\\n\",\n\t\t\t\t   s, m_detail->load_capability);\n\t\tm_detail->load_capability |= status;\n\t\tif (debug)\n\t\t\tprintf(\"Updating entry for %s, new Load Capability: 0x%02x\\n\",\n\t\t\t\t   s, m_detail->load_capability);\n\t} else {\n\t\tif (debug)\n\t\t\tprintf(\"Adding new entry for %s\\n\", s);\n\t\tm_detail = zalloc(sizeof(struct media_details));\n\t\tif (!m_detail) {\n\t\t\tprintf(\"Failed to allocate %d bytes\\n\",\n\t\t\t\t   (int)sizeof(m_detail));\n\t\t\treturn -ENOMEM;\n\t\t}\n\t\tm_detail->media_type\t  = media_type;\n\t\tm_detail->load_capability = status;\n\t\tlist_add_tail(&m_detail->siblings, den_list);\n\t}\n\n\treturn 0;\n}\n\nstatic void set_compression(struct priv_lu_ssc *lu_priv, char *compression) {\n\tif (!strcasecmp(compression, \"LZO\")) {\n\t\tif (verbose)\n\t\t\tprintf(\"Setting compression to LZO\\n\");\n\t\tlu_priv->compressionType = LZO;\n\t} else if (!strcasecmp(compression, \"ZLIB\")) {\n\t\tif (verbose)\n\t\t\tprintf(\"Setting compression to ZLIB\\n\");\n\t\tlu_priv->compressionType = ZLIB;\n\t} else {\n\t\tif (verbose)\n\t\t\tprintf(\"Setting compression to NONE\\n\");\n\t\tlu_priv->compressionType = 0;\n\t}\n}\n\nstatic int write_tape(char *source_file, uint32_t block_size, char *compression, uint8_t *sam_stat) {\n\tuint8_t\t\t   *b;\n\tint\t\t\t\tfd = -1;\n\tint\t\t\t\trc = 0;\n\tint\t\t\t\tretval;\n\tsize_t\t\t\tcount = 1;\n\tstruct scsi_cmd cmd;\n\tstruct mhvtl_ds ds;\n\tvoid (*drive_init)(struct lu_phy_attr *) = init_default_ssc;\n\n\tif (debug)\n\t\tprintf(\"Entering %s() +++\\n\", __func__);\n\n\t/* fake scsi_cmd & lu_private structures for write operations */\n\tmemset(&cmd, 0, sizeof(cmd));\n\tmemset(&ds, 0, sizeof(ds));\n\n\tcmd.lu\t\t = &lunit;\n\tcmd.dbuf_p\t = &ds;\n\tds.sense_buf = sense;\n\n\tlu_ssc.max_capacity = get_unaligned_be64(&mam.max_capacity);\n\n\tdrive_init(&lunit);\n\n\tinit_default_ssc(&lunit);\n\n\tif (verbose) {\n\t\tprintf(\"Opening %s for reading\\n\", source_file);\n\t\tprintf(\"Block size: %d\\n\", block_size);\n\t\tprintf(\"Compression : %s\\n\", compression);\n\n\t\tprintf(\"Tape max capacity is %\" PRIu64 \"\\n\", lu_ssc.max_capacity);\n\t}\n\n\tb = malloc(block_size);\n\tif (!b)\n\t\treturn -ENOMEM;\n\tif (debug)\n\t\tprintf(\"malloc(%d) successfully\\n\", block_size);\n\tds.data = b;\n\tds.sz\t= block_size;\n\n\tset_compression(lunit.lu_private, compression);\n\n\tfd = open(source_file, O_LARGEFILE);\n\tif (fd < 0) {\n\t\tprintf(\"Could not open file '%s', returned error: %s\\n\", source_file, strerror(errno));\n\t\trc = -EBADF;\n\t\tgoto abort;\n\t}\n\twhile (count > 0) {\n\t\tcount = read(fd, b, block_size);\n\t\tif (count > 0) {\n\t\t\tif (count < block_size) {\n\t\t\t\tprintf(\"zeroing out remaining block: %\" PRIu32 \"\\n\", (uint32_t)(block_size - count));\n\t\t\t\tmemset(b + count, 0, block_size - count); /* Zero out remaining block */\n\t\t\t}\n\t\t\tretval = writeBlock(&cmd, count);\n\t\t\tif (retval < count) {\n\t\t\t\tif (sense[2] == (VOLUME_OVERFLOW | SD_EOM) && sense[13] == E_EOM) {\n\t\t\t\t\tprintf(\"No space left on media, hit EOM while writing\\n\");\n\t\t\t\t} else {\n\t\t\t\t\tprintf(\"Tried to write %d, only succeeded in writing %d, SAM status: 0x%02x 0x%02x 0x%02x\\n\",\n\t\t\t\t\t\t   block_size, retval, sense[2], sense[12], sense[13]);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\twrite_filemarks(1, sam_stat);\n\nabort:\n\tclose(fd);\n\tfree(b);\n\treturn rc;\n}\n\nstatic int read_data(uint8_t *sam_stat) {\n\tuint8_t *p;\n\tuint32_t ret;\n\tuint32_t requested_blk_size = c_pos->blk_size;\n\n\tprintf(\"c_pos->blk_size: %d\\n\", c_pos->blk_size);\n\n\tif (requested_blk_size <= 0) {\n\t\tprintf(\"Data size: %d - skipping read\\n\", requested_blk_size);\n\t\treturn 0;\n\t}\n\tp = malloc(requested_blk_size);\n\tif (!p) {\n\t\tfprintf(stderr, \"Unable to allocate %d bytes\\n\", requested_blk_size);\n\t\treturn -ENOMEM;\n\t}\n\tret = readBlock(p, requested_blk_size, 1, 0, sam_stat);\n\n\tif (verbose) { /* put option to display all data */\n\t\tprintf(\"Data:\\n%.*sEnd of data\\n\", requested_blk_size, p);\n\t}\n\n\tif (ret != requested_blk_size) {\n\t\tprintf(\"Requested %d bytes, received %d\\n\",\n\t\t\t   requested_blk_size, ret);\n\t}\n\n\tfree(p);\n\tputs(\"\\n\");\n\treturn ret;\n}\n\nstatic void usage(char *errmsg) {\n\tif (errmsg)\n\t\tprintf(\"%s\\n\", errmsg);\n\tprintf(\"Usage: %s OPTIONS\\n\", progname);\n\tprintf(\"Where OPTIONS are from:\\n\");\n\tprintf(\"  -h               Print this message and exit\\n\");\n\tprintf(\"  -d               Enable debugging\\n\");\n\tprintf(\"  -v               Be verbose\\n\");\n\tif (dump_tape == 1) {\n\t\tprintf(\"  -D               Dump data\\n\");\n\t\tprintf(\"  -l lib_no        Look in specified library\\n\");\n\t\tprintf(\"  -m pcl           Look for specified PCL\\n\");\n\t} else if (dump_tape == 2) {\n\t\tprintf(\"  -l lib_no        Look in specified library\\n\");\n\t\tprintf(\"  -m pcl           Look for specified PCL\\n\");\n\t\tprintf(\"  -b <block size>  tape block size\\n\");\n\t\tprintf(\"  -c <compression> Compression type (NONE|LZO|ZLIB)\\n\");\n\t\tprintf(\"  -F <inputfile>   Filename to read data from\\n\");\n\t} else {\n\t\tprintf(\"\\n\\nNot sure of my personality (dump_tape or preload_tape)\\n\");\n\t}\n\texit(errmsg ? 1 : 0);\n}\n\nstatic void dump_tape_metadata(int dump_data, uint8_t *sam_stat) {\n\n\tif (lzo_init() != LZO_E_OK) {\n\t\tfprintf(stderr, \"internal error - lzo_init() failed !!!\\n\");\n\t\tfprintf(stderr,\n\t\t\t\t\"(this usually indicates a compiler bug - try recompiling\\nwithout optimizations, and enable '-DLZO_DEBUG' for diagnostics)\\n\");\n\t\texit(3);\n\t}\n\tprint_mam_info();\n\n\tprint_filemark_count();\n\tif (verbose) {\n\t\tprintf(\"Dumping filemark meta info\\n\");\n\t\tprint_metadata();\n\t}\n\n\twhile (c_pos->blk_type != B_EOD) {\n\t\tprint_raw_header();\n\t\tif (dump_data) {\n\t\t\tread_data(sam_stat);\n\t\t}\n\t\twhile (c_pos->blk_type == B_FILEMARK) {\n\t\t\tprintf(\"Filemark at block : %u , skipping\\n\", c_pos->blk_number);\n\t\t\tposition_blocks_forw(1, sam_stat);\n\t\t}\n\t}\n\tprint_raw_header();\n}\n\nint main(int argc, char *argv[]) {\n\tchar\tdevice_conf[CONF_FILE_SZ];\n\tuint8_t sam_stat;\n\tchar   *pcl = NULL;\n\tint\t\trc;\n\tint\t\tlibno = 0;\n\tint\t\tindx;\n\tint\t\tblock_size\t= 0;\n\tint\t\tdump_data\t= FALSE;\n\tchar   *source_file = NULL;\n\tchar   *compression = NULL;\n\tFILE   *conf;\n\tchar   *b; /* Read from file into this buffer */\n\tchar   *s; /* Somewhere for sscanf to store results */\n\n\tif (get_config(device_conf, DEVICE_CONF, my_id) < 0)\n\t\texit(1);\n\n\tprogname = argv[0];\n\tif (strcasestr(progname, \"dump_tape\")) {\n\t\tdump_tape = 1;\n\t} else if (strcasestr(progname, \"preload_tape\")) {\n\t\tdump_tape = 2;\n\t} else {\n\t\tusage(\"program name not correct\");\n\t}\n\n\tif (argc < 2)\n\t\tusage(\"Not enough arguments\");\n\n\twhile (argc > 1) {\n\t\tif (argv[1][0] == '-') {\n\t\t\tswitch (argv[1][1]) {\n\t\t\tcase 'h':\n\t\t\t\tusage(NULL);\n\t\t\t\tbreak;\n\t\t\tcase 'd':\n\t\t\t\tdebug++;\n\t\t\t\tverbose = 9; /* If debug, make verbose... */\n\t\t\t\tbreak;\n\t\t\tcase 'm':\n\t\t\t\tif (argc > 1)\n\t\t\t\t\tpcl = argv[2];\n\t\t\t\telse\n\t\t\t\t\tusage(\"More args needed for -m\");\n\t\t\t\tbreak;\n\t\t\tcase 'l':\n\t\t\t\tif (argc > 1)\n\t\t\t\t\tlibno = atoi(argv[1]);\n\t\t\t\telse\n\t\t\t\t\tusage(\"More args needed for -l\");\n\t\t\t\tbreak;\n\t\t\tcase 'D':\n\t\t\t\tdump_data = TRUE;\n\t\t\t\tbreak;\n\t\t\tcase 'v':\n\t\t\t\tverbose++;\n\t\t\t\tbreak;\n\t\t\tcase 'b': /* block size */\n\t\t\t\tif (dump_tape == 2) {\n\t\t\t\t\tif (argc > 1) {\n\t\t\t\t\t\tblock_size = atoi(argv[2]);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tusage(\"-b requires additional block size\");\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tusage(\"-b is not a supported option\");\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'c': /* compression type (NONE/LZO/ZLIB) */\n\t\t\t\tif (dump_tape == 2) {\n\t\t\t\t\tif (argc > 1) {\n\t\t\t\t\t\tcompression = argv[2];\n\t\t\t\t\t} else {\n\t\t\t\t\t\tusage(\"-c requires additional compression type\");\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tusage(\"-c is not a supported option\");\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'F': /* File to read from */\n\t\t\t\tif (dump_tape == 2) {\n\t\t\t\t\tif (argc > 1) {\n\t\t\t\t\t\tsource_file = argv[2];\n\t\t\t\t\t} else {\n\t\t\t\t\t\tusage(\"-F requires additional filename\");\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tusage(\"-F is not a supported option\");\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tusage(\"Unknown option\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\targv++;\n\t\targc--;\n\t}\n\n\tif (pcl == NULL)\n\t\tusage(\"No PCL number supplied\");\n\tif (dump_tape == 2) {\n\t\tif (source_file == NULL)\n\t\t\tusage(\"Need to specify the filename to read data from\");\n\t\tif (compression == NULL)\n\t\t\tusage(\"Need to specify the compression type NONE|LZO|ZLIB\");\n\t\tif (block_size == 0)\n\t\t\tusage(\"Need to specify a block size\");\n\t}\n\n#ifdef __x86_64__\n\tif (verbose) {\n\t\tif (__builtin_cpu_supports(\"sse4.2\")) {\n\t\t\tprintf(\"crc32c using Intel sse4.2 hardware optimization\\n\");\n\t\t} else {\n\t\t\tprintf(\"crc32c not using Intel sse4.2 optimization\\n\");\n\t\t}\n\t}\n#endif\n\n\tinit_lu_ssc(&lu_ssc);\n\tinit_lunit(&lunit, &lu_ssc);\n\n\tconf = fopen(device_conf, \"r\");\n\tif (!conf) {\n\t\tfprintf(stderr, \"Cannot open config file %s: %s\\n\", device_conf,\n\t\t\t\tstrerror(errno));\n\t\texit(1);\n\t}\n\ts = malloc(MALLOC_SZ);\n\tif (!s) {\n\t\tperror(\"Could not allocate memory\");\n\t\texit(1);\n\t}\n\tb = malloc(MALLOC_SZ);\n\tif (!b) {\n\t\tperror(\"Could not allocate memory\");\n\t\texit(1);\n\t}\n\n\trc = ENOENT;\n\n\tif (libno) {\n\t\tprintf(\"Looking for PCL: %s in library %d\\n\", pcl, libno);\n\t\tfind_media_home_directory(NULL, libno);\n\t\trc = load_tape(pcl, &sam_stat);\n\t} else { /* Walk thru all defined libraries looking for media */\n\t\twhile (readline(b, MALLOC_SZ, conf) != NULL) {\n\t\t\tif (b[0] == '#') /* Ignore comments */\n\t\t\t\tcontinue;\n\t\t\t/* If found a library: Attempt to load media\n\t\t\t * Break out of loop if found. Otherwise try next lib.\n\t\t\t */\n\t\t\tif (sscanf(b, \"Library: %d CHANNEL:\", &indx)) {\n\t\t\t\tfind_media_home_directory(NULL, indx);\n\t\t\t\trc = load_tape(pcl, &sam_stat);\n\t\t\t\tif (!rc)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tfclose(conf);\n\tfree(s);\n\tfree(b);\n\n\tif (rc) {\n\t\tfprintf(stderr, \"PCL %s cannot be opened, \"\n\t\t\t\t\t\t\"load_tape() returned %d\\n\",\n\t\t\t\tpcl, rc);\n\t\texit(1);\n\t}\n\n\tif (dump_tape == 1) {\n\t\tfor (int k = 0; k < mam.num_partitions; k++) {\n\t\t\tprintf(\"Dumping partition %d\\n\", k);\n\t\t\tchange_partition(k);\n\t\t\tdump_tape_metadata(dump_data, &sam_stat);\n\t\t}\n\t\tunload_tape(&sam_stat);\n\t} else if (dump_tape == 2) {\n\t\twrite_tape(source_file, block_size, compression, &sam_stat);\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "usr/cmd/tapeexerciser.c",
    "content": "/*\n * Put a tape device thru a set of exercises\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <sys/mtio.h>\n#include <fcntl.h>\n#include <string.h>\n#include <errno.h>\n\nstatic int space_forward_filemark(int fd, int count) {\n\tstruct mtop mtop;\n\tint\t\t\terr;\n\n\tprintf(\"%s(%d)\", __func__, count);\n\tmtop.mt_op\t  = MTFSF; /* Forward Space over count Filemarks */\n\tmtop.mt_count = count;\n\terr\t\t\t  = ioctl(fd, MTIOCTOP, &mtop);\n\tif (err)\n\t\tprintf(\" %s\", strerror(errno));\n\tprintf(\"\\n\");\n\treturn err;\n}\n\nstatic int space_back_filemark(int fd, int count) {\n\tstruct mtop mtop;\n\tint\t\t\terr;\n\n\tprintf(\"%s(%d)\", __func__, count);\n\tmtop.mt_op\t  = MTBSF; /* Back Space over count Filemarks */\n\tmtop.mt_count = count;\n\terr\t\t\t  = ioctl(fd, MTIOCTOP, &mtop);\n\tif (err)\n\t\tprintf(\" %s\", strerror(errno));\n\tprintf(\"\\n\");\n\treturn err;\n}\n\nstatic int space_forward_block(int fd, int count) {\n\tstruct mtop mtop;\n\tint\t\t\terr;\n\n\tprintf(\"%s(%d)\", __func__, count);\n\tmtop.mt_op\t  = MTFSR; /* Forward count block */\n\tmtop.mt_count = count;\n\terr\t\t\t  = ioctl(fd, MTIOCTOP, &mtop);\n\tif (err)\n\t\tprintf(\" %s\", strerror(errno));\n\tprintf(\"\\n\");\n\treturn err;\n}\n\nstatic int write_filemarks(int fd, int count) {\n\tstruct mtop mtop;\n\tint\t\t\terr;\n\n\tprintf(\"%s(%d)\", __func__, count);\n\tmtop.mt_op\t  = MTWEOF;\n\tmtop.mt_count = count;\n\terr\t\t\t  = ioctl(fd, MTIOCTOP, &mtop);\n\tif (err)\n\t\tprintf(\" %s\", strerror(errno));\n\tprintf(\"\\n\");\n\treturn err;\n}\n\nstatic int space_back_block(int fd, int count) {\n\tstruct mtop mtop;\n\tint\t\t\terr;\n\n\tprintf(\"%s(%d)\", __func__, count);\n\tmtop.mt_op\t  = MTBSR; /* Back count block */\n\tmtop.mt_count = 1;\n\terr\t\t\t  = ioctl(fd, MTIOCTOP, &mtop);\n\tif (err)\n\t\tprintf(\" %s\", strerror(errno));\n\tprintf(\"\\n\");\n\treturn err;\n}\n\nstatic int set_compression(int fd, int state) {\n\tstruct mtop mtop;\n\tint\t\t\terr;\n\n\tprintf(\"%s()\", __func__);\n\tmtop.mt_op\t  = MTCOMPRESSION; /* Set compression */\n\tmtop.mt_count = state;\n\terr\t\t\t  = ioctl(fd, MTIOCTOP, &mtop);\n\tif (err)\n\t\tprintf(\" %s\", strerror(errno));\n\tprintf(\"\\n\");\n\treturn err;\n}\n\nstatic int rewind_tape(int fd) {\n\tstruct mtop mtop;\n\tint\t\t\terr;\n\n\tprintf(\"%s()\", __func__);\n\tmtop.mt_op\t  = MTREW;\n\tmtop.mt_count = 1;\n\terr\t\t\t  = ioctl(fd, MTIOCTOP, &mtop);\n\tif (err)\n\t\tprintf(\" %s\", strerror(errno));\n\tprintf(\"\\n\");\n\treturn err;\n}\n\nstatic int read_block_position(int fd) {\n\tstruct mtpos mtpos;\n\tint\t\t\t err;\n\n\terr = ioctl(fd, MTIOCPOS, &mtpos);\n\tif (err) {\n\t\tprintf(\"%s: %s\\n\", __func__, strerror(errno));\n\t\treturn -1;\n\t}\n\n\treturn mtpos.mt_blkno;\n}\n\nstatic int read_block(int fd, int size) {\n\tchar *buf;\n\tint\t  err;\n\n\tbuf = malloc(size);\n\tif (!buf)\n\t\treturn -ENOMEM;\n\n\tprintf(\"%s(%d)\", __func__, size);\n\terr = read(fd, buf, size);\n\tif (err < 0)\n\t\tprintf(\" %s\", strerror(errno));\n\tprintf(\"\\n\");\n\tfree(buf);\n\treturn err;\n}\n\nstatic int write_block(int fd, int size) {\n\tchar *buf;\n\tint\t  err;\n\n\tbuf = malloc(size);\n\tif (!buf)\n\t\treturn -ENOMEM;\n\n\tmemset(buf, 0x45, size);\n\n\tprintf(\"%s(%d)\", __func__, size);\n\terr = write(fd, buf, size);\n\tif (err < 0)\n\t\tprintf(\" %s\", strerror(errno));\n\tprintf(\"\\n\");\n\tfree(buf);\n\treturn err;\n}\n\nstatic void usage(char *arg) {\n\tprintf(\"Usage: %s -f tape_path\\n\", arg);\n\tprintf(\"       WARNING: %s will overwrite the tape\\n\\n\", arg);\n}\n\nvoid write_tape_pattern_1(int fd) {\n\trewind_tape(fd);\n\n\twrite_block(fd, 8 * 1024);\n\twrite_block(fd, 64 * 1024);\n\twrite_filemarks(fd, 1);\n\twrite_block(fd, 64 * 1024);\n\twrite_block(fd, 64 * 1024);\n\twrite_block(fd, 64 * 1024);\n\twrite_block(fd, 64 * 1024);\n\twrite_block(fd, 64 * 1024);\n\twrite_filemarks(fd, 0); /* Flush data */\n\twrite_filemarks(fd, 1);\n}\n\nvoid write_tape_pattern_2(int fd) {\n\trewind_tape(fd);\n\n\tspace_forward_filemark(fd, 1);\n\tspace_forward_block(fd, 5); /* should be at end filemark */\n\n\twrite_block(fd, 128 * 1024);\n\twrite_block(fd, 128 * 1024);\n\twrite_block(fd, 128 * 1024);\n\twrite_filemarks(fd, 1);\n\twrite_block(fd, 128 * 1024);\n\twrite_filemarks(fd, 1);\n\twrite_block(fd, 128 * 1024);\n\twrite_filemarks(fd, 2);\n}\n\nint read_test_1(int fd) {\n\trewind_tape(fd);\n\tread_block(fd, 8 * 1024);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tspace_forward_filemark(fd, 3);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tread_block(fd, 64 * 1024);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tspace_back_block(fd, 1);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tread_block(fd, 32 * 1024);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\treturn 0;\n}\n\nint read_test_2(int fd) {\n\trewind_tape(fd);\n\tspace_forward_filemark(fd, 3);\n\tread_block(fd, 64 * 1024);\n\tspace_forward_block(fd, 1);\n\tread_block(fd, 64 * 1024);\n\tprintf(\"%s: Did we error here ??\\n\", __func__);\n\n\trewind_tape(fd);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tprintf(\"%s: Note: following space_forward_filemark(100000)\"\n\t\t   \" should error\\n\",\n\t\t   __func__);\n\tspace_forward_filemark(fd, 100000);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tspace_back_filemark(fd, 2);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tspace_back_block(fd, 1);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tread_block(fd, 64 * 1024);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\treturn 0;\n}\n\nint read_test_3(int fd) {\n\trewind_tape(fd);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tread_block(fd, 8 * 1024);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tspace_forward_filemark(fd, 3);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tread_block(fd, 64 * 1024);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tspace_back_block(fd, 1);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tread_block(fd, 64 * 1024);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tprintf(\"%s: Note: following space_forward_block() should error\\n\",\n\t\t   __func__);\n\tspace_forward_block(fd, 1);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\treturn 0;\n}\n\nint read_test_4(int fd) {\n\trewind_tape(fd);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tspace_forward_filemark(fd, 1);\n\tprintf(\"*** Should be at block 3 ==> \\t\");\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\n\trewind_tape(fd);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tread_block(fd, 8 * 1024);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tspace_forward_filemark(fd, 1);\n\tprintf(\"*** Should be at block 3 ==> \\t\");\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tread_block(fd, 64 * 1024);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tspace_back_block(fd, 1);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tread_block(fd, 64 * 1024);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tspace_forward_block(fd, 1);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tspace_forward_filemark(fd, 1);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\treturn 0;\n}\n\nint read_test_5(int fd) {\n\trewind_tape(fd);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tspace_forward_filemark(fd, 1);\n\tprintf(\"*** Should be at block 3 ==> \\t\");\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\n\trewind_tape(fd);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tread_block(fd, 8 * 1024);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\tspace_forward_filemark(fd, 1);\n\tprintf(\"*** Should be at block 3 ==> \\t\");\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\n\tprintf(\"Only reading 32k of a 64k block\\n\");\n\tread_block(fd, 32 * 1024);\n\tprintf(\"%s: Block %d\\n\", __func__, read_block_position(fd));\n\n\treturn 0;\n}\n\nint main(int argc, char *argv[]) {\n\tstruct mtget mtstat;\n\tstruct mtpos mtpos;\n\tchar\t\t*dev = NULL;\n\tint\t\t\t tape_fd;\n\tint\t\t\t err;\n\tint\t\t\t count;\n\n\tif (argc != 3) {\n\t\tusage(argv[0]);\n\t\texit(1);\n\t}\n\n\t/* checking several positions of -h/-help */\n\tfor (count = 1; count < argc; count++) {\n\t\tif (!strcmp(argv[count], \"-f\")) {\n\t\t\tif (argc < count + 1) {\n\t\t\t\tusage(argv[0]);\n\t\t\t\texit(1);\n\t\t\t}\n\t\t\tdev = argv[count + 1];\n\t\t}\n\t}\n\tif (!dev) {\n\t\tusage(argv[0]);\n\t\texit(1);\n\t}\n\n\tmemset(&mtstat, 0, sizeof(struct mtget));\n\tmemset(&mtpos, 0, sizeof(struct mtpos));\n\n\ttape_fd = open(dev, O_RDWR);\n\tif (tape_fd < 0) {\n\t\tprintf(\"Failed to open %s: %s\\n\",\n\t\t\t   dev, strerror(errno));\n\t\texit(-1);\n\t}\n\n\t/* Disable Compression */\n\tset_compression(tape_fd, 0);\n\n\twrite_tape_pattern_1(tape_fd);\n\twrite_tape_pattern_2(tape_fd);\n\n\tread_test_1(tape_fd);\n\tread_test_2(tape_fd);\n\tread_test_3(tape_fd);\n\tread_test_4(tape_fd);\n\tread_test_5(tape_fd);\n\n\terr = ioctl(tape_fd, MTIOCGET, &mtstat); /* Query device status */\n\tif (err) {\n\t\tprintf(\"%s: %s\\n\", __func__, strerror(errno));\n\t\texit(-1);\n\t}\n\tprintf(\"  =======================\\n\");\n\tprintf(\"    Querying type drive\\n\");\n\tprintf(\"  =======================\\n\");\n\tprintf(\"Status from tape device: type: %s\\n\",\n\t\t   (mtstat.mt_type == MT_ISSCSI1) ? \"SCSI-1\" : \"SCSI-2\");\n\tprintf(\"Position: fileno: %d, blockno: %d\\n\",\n\t\t   mtstat.mt_fileno, mtstat.mt_blkno);\n\tprintf(\"Block size: %d, density: 0x%02x\\n\",\n\t\t   (unsigned int)mtstat.mt_dsreg & MT_ST_BLKSIZE_MASK,\n\t\t   (unsigned int)mtstat.mt_dsreg >> MT_ST_DENSITY_SHIFT);\n\tprintf(\"Drive is %sline\\n\", GMT_ONLINE(mtstat.mt_gstat) ? \"On\" : \"Off\");\n\tprintf(\"Drive is EOF: %s\\n\", GMT_EOF(mtstat.mt_gstat) ? \"Yes\" : \"No\");\n\tprintf(\"Drive is BOT: %s\\n\", GMT_BOT(mtstat.mt_gstat) ? \"Yes\" : \"No\");\n\tprintf(\"Drive is EOT: %s\\n\", GMT_EOT(mtstat.mt_gstat) ? \"Yes\" : \"No\");\n\tprintf(\"Drive is EOD: %s\\n\", GMT_EOD(mtstat.mt_gstat) ? \"Yes\" : \"No\");\n\tprintf(\"Drive is SM: %s\\n\", GMT_SM(mtstat.mt_gstat) ? \"Yes\" : \"No\");\n\tprintf(\"Drive is WRITE PROTECT: %s\\n\",\n\t\t   GMT_WR_PROT(mtstat.mt_gstat) ? \"Yes\" : \"No\");\n\tprintf(\"Tape is %sloaded in the drive\\n\",\n\t\t   GMT_DR_OPEN(mtstat.mt_gstat) ? \"not \" : \"\");\n\n\tprintf(\"  =======================\\n\\n\");\n\n\tclose(tape_fd);\n\texit(0);\n}\n"
  },
  {
    "path": "usr/cmd/vtlcmd.c",
    "content": "/*\n * vtlcmd - A utility to send a message queue to the vtltape/vtllibrary\n *\t    userspace daemons\n *\n * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n *\n * Modification History:\n *    2010-03-15 hstadler - source code revision, argument checking\n *\n *\n * FIXME: Server & Client are writing in the same queue, it would be better\n *        the client opens a \"private\" queue and the server writes the\n *        answers in this queue. In this case nobody can disturb the answer\n *        from the server. I think this is called connectionless protocol.\n *        But this means a redesign of some c-sources.\n *\n */\n\n#define _FILE_OFFSET_BITS 64\n\n#include <stdio.h>\n#include <sys/ipc.h>\n#include <errno.h>\n#include <string.h>\n#include <sys/msg.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <sys/types.h>\n#include <fcntl.h>\n#include <ctype.h>\n#include <inttypes.h>\n#include \"q.h\"\n#include \"vtllib.h\"\n\nchar mhvtl_driver_name[] = \"vtlcmd\";\n\n#define TYPE_UNKNOWN 0\n#define TYPE_LIBRARY 1\n#define TYPE_DRIVE\t 2\n\nstatic void usage(char *prog) {\n\tfprintf(stderr, \"Usage  : %s <DeviceNo> <command> [-h|-help]\\n\", prog);\n\tfprintf(stderr, \"Version: %s %s %s\\n\", MHVTL_VERSION, MHVTL_GITHASH, MHVTL_GITDATE);\n\tfprintf(stderr, \"   Where 'DeviceNo' is the number\"\n\t\t\t\t\t\" associated with tape/library daemon\\n\\n\");\n\tfprintf(stderr, \"Global commands:\\n\");\n\tfprintf(stderr, \"   verbose           -> To enable verbose logging\\n\");\n\t/*\n\tfprintf(stderr, \"   debug             -> To enable debug logging\\n\");\n\t*/\n\tfprintf(stderr, \"   TapeAlert #       -> 64bit TapeAlert mask (hex)\\n\");\n\tfprintf(stderr, \"   InquiryDataChange -> Set LU state to indicate Inquiry Data Has Changed\\n\");\n\tfprintf(stderr, \"   exit              -> To shutdown tape/library \"\n\t\t\t\t\t\"daemon/device\\n\");\n\tfprintf(stderr, \"\\nTape specific commands:\\n\");\n\tfprintf(stderr, \"   Append Only [Yes|No] -> To 'load' media ID\\n\");\n\tfprintf(stderr, \"   compression [zlib|lzo] -> Use zlib or lzo \"\n\t\t\t\t\t\"compression\\n\");\n\tfprintf(stderr, \"   load ID        -> To 'load' media ID\\n\");\n\tfprintf(stderr, \"   unload ID      -> To 'unload' media ID\\n\");\n\tfprintf(stderr, \"   delay load n   -> Set load delay to n seconds\\n\");\n\tfprintf(stderr, \"   delay unload n -> Set unload delay to n seconds\\n\");\n\tfprintf(stderr, \"   delay rewind n -> Set rewind delay to n seconds\\n\");\n\tfprintf(stderr, \"   delay position n -> Set position delay to n seconds\\n\");\n\tfprintf(stderr, \"   delay thread n -> Set thread delay to n seconds\\n\");\n\tfprintf(stderr, \"\\nLibrary specific commands:\\n\");\n\tfprintf(stderr, \"   add slot     -> Add a slot to library\\n\");\n\tfprintf(stderr, \"   online       -> To enable library\\n\");\n\tfprintf(stderr, \"   offline      -> To take library offline\\n\");\n\tfprintf(stderr, \"   list map     -> To list map contents\\n\");\n\tfprintf(stderr, \"   empty map    -> To remove media from map\\n\");\n\tfprintf(stderr, \"   open map     -> Open map to allow media export\\n\");\n\tfprintf(stderr, \"   close map    -> Close map to allow media import\\n\");\n\tfprintf(stderr, \"   load map ID  -> Load media ID into map\\n\");\n}\n\n/* check if media (tape) exists in directory (/opt/mhvtl/..) */\nint check_media(int libno, char *barcode) {\n\tchar currentMedia[1024];\n\tint\t datafile;\n\tint\t path_len;\n\n\tfind_media_home_directory(NULL, libno);\n\tpath_len = snprintf((char *)currentMedia, ARRAY_SIZE(currentMedia), \"%s/%s/data\", home_directory, barcode);\n\tif (path_len >= ARRAY_SIZE(currentMedia)) {\n\t\tfprintf(stderr, \"Warning: path to %s/%s/data truncated to %\" PRIu32 \" bytes\",\n\t\t\t\thome_directory, barcode, (uint32_t)ARRAY_SIZE(currentMedia));\n\t}\n\tdatafile = open(currentMedia, O_RDWR | O_LARGEFILE);\n\tif (datafile < 0) {\n\t\tfprintf(stderr, \"Could not open %s: %s\\n\",\n\t\t\t\tcurrentMedia, strerror(errno));\n\t\treturn 1;\n\t}\n\tclose(datafile);\n\treturn 0;\n}\n\n/* Display the answer from daemon/service */\nvoid DisplayResponse(int msqid, char *s) {\n\tstruct q_entry r_entry;\n\n\tif (msgrcv(msqid, &r_entry, MAXOBN, VTLCMD_Q, 0) > 0)\n\t\tprintf(\"%s%s\\n\", s, r_entry.msg.text);\n}\n\nint ishex(char *str) {\n\twhile (*str) {\n\t\tif (!isxdigit(*str))\n\t\t\treturn 0;\n\t\tstr++;\n\t}\n\treturn 1;\n}\n\nint isnumeric(char *str) {\n\twhile (*str) {\n\t\tif (!isdigit(*str))\n\t\t\treturn 0;\n\t\tstr++;\n\t}\n\treturn 1;\n}\n\nvoid PrintErrorExit(char *prog, char *s) {\n\tfprintf(stderr, \"Please check command, parameter \\'%s\\' wrong.\\n\\n\", s);\n\tusage(prog);\n\texit(1);\n}\n\nvoid Check_TapeAlert(int argc, char **argv) {\n\tif (argc > 3) {\n\t\tif (!ishex(argv[3])) {\n\t\t\tfprintf(stderr, \"Value not hexadecimal: %s\\n\", argv[3]);\n\t\t\texit(1);\n\t\t}\n\t\tif (argc == 4)\n\t\t\treturn;\n\n\t\tPrintErrorExit(argv[0], \"TapeAlert\");\n\t}\n\tPrintErrorExit(argv[0], \"TapeAlert\");\n}\n\nvoid Check_Load(int argc, char **argv) {\n\tif (argc > 3) {\n\t\tif (!strcmp(argv[3], \"map\")) {\n\t\t\tif (argc == 5)\n\t\t\t\treturn;\n\n\t\t\tPrintErrorExit(argv[0], \"load map\");\n\t\t}\n\n\t\tif (argc == 4)\n\t\t\treturn;\n\n\t\tPrintErrorExit(argv[0], \"load\");\n\t}\n\tPrintErrorExit(argv[0], \"load\");\n}\n\nvoid Check_delay(int argc, char **argv) {\n\tif (argc > 4) {\n\t\tif (argc == 5) {\n\t\t\tif (atoi(argv[4]) >= 0)\n\t\t\t\treturn;\n\t\t\tPrintErrorExit(argv[0], \"delay: Negative value\");\n\t\t}\n\t\tPrintErrorExit(argv[0], \"delay\");\n\t}\n\tPrintErrorExit(argv[0], \"delay\");\n}\n\nvoid Check_Unload(int argc, char **argv) {\n\tif (argc > 3) {\n\t\tif (argc == 4)\n\t\t\treturn;\n\n\t\tPrintErrorExit(argv[0], \"unload\");\n\t}\n\tPrintErrorExit(argv[0], \"unload\");\n}\n\nvoid Check_Compression(int argc, char **argv) {\n\tif (argc > 3) {\n\t\tif (argc == 4)\n\t\t\treturn;\n\n\t\tPrintErrorExit(argv[0], \"compression\");\n\t}\n\tPrintErrorExit(argv[0], \"compression : missing lzo or zlib\");\n}\n\nvoid Check_append_only(int argc, char **argv) {\n\tif (argc > 4) {\n\t\tif (argc == 5)\n\t\t\treturn;\n\n\t\tPrintErrorExit(argv[0], \"Append Only\");\n\t}\n\tPrintErrorExit(argv[0], \"Append Only : missing Yes / No\");\n}\n\nvoid Check_List(int argc, char **argv) {\n\tif (argc != 4)\n\t\tPrintErrorExit(argv[0], \"list map : too many args\");\n\telse if (strcmp(argv[3], \"map\"))\n\t\tPrintErrorExit(argv[0], \"list map : Can only list map\");\n}\n\nvoid Check_Empty(int argc, char **argv) {\n\tif (argc > 3) {\n\t\tif (!strcmp(argv[3], \"map\")) {\n\t\t\tif (argc == 4)\n\t\t\t\treturn;\n\t\t}\n\t\tPrintErrorExit(argv[0], \"empty map\");\n\t}\n\tPrintErrorExit(argv[0], \"empty map\");\n}\n\nvoid Check_Open(int argc, char **argv) {\n\tif (argc > 3) {\n\t\tif (!strcmp(argv[3], \"map\")) {\n\t\t\tif (argc == 4)\n\t\t\t\treturn;\n\t\t}\n\t\tPrintErrorExit(argv[0], \"open map\");\n\t}\n\tPrintErrorExit(argv[0], \"open map\");\n}\n\nvoid Check_Close(int argc, char **argv) {\n\tif (argc > 3) {\n\t\tif (!strcmp(argv[3], \"map\")) {\n\t\t\tif (argc == 4)\n\t\t\t\treturn;\n\t\t}\n\t\tPrintErrorExit(argv[0], \"close map\");\n\t}\n\tPrintErrorExit(argv[0], \"close map\");\n}\n\nvoid Check_Params(int argc, char **argv) {\n\tif (argc > 1) {\n\t\tif (!isnumeric(argv[1])) {\n\t\t\tfprintf(stderr, \"DeviceNo not numeric: %s\\n\", argv[1]);\n\t\t\texit(1);\n\t\t}\n\t\tif (argc > 2) {\n\t\t\t/* global commands */\n\t\t\tif (!strcmp(argv[2], \"verbose\")) {\n\t\t\t\tif (argc == 3)\n\t\t\t\t\treturn;\n\t\t\t\tPrintErrorExit(argv[0], \"verbose\");\n\t\t\t}\n\t\t\tif (!strcmp(argv[2], \"dump\")) {\n\t\t\t\tif (argc == 3)\n\t\t\t\t\treturn;\n\t\t\t\tPrintErrorExit(argv[0], \"dump\");\n\t\t\t}\n\t\t\tif (!strcmp(argv[2], \"debug\")) {\n\t\t\t\tif (argc == 3)\n\t\t\t\t\treturn;\n\t\t\t\tPrintErrorExit(argv[0], \"debug\");\n\t\t\t}\n\t\t\tif (!strcmp(argv[2], \"exit\")) {\n\t\t\t\tif (argc == 3)\n\t\t\t\t\treturn;\n\t\t\t\tPrintErrorExit(argv[0], \"exit\");\n\t\t\t}\n\t\t\tif (!strncasecmp(argv[2], \"InquiryDataChange\", 17)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!strncasecmp(argv[2], \"TapeAlert\", 9)) {\n\t\t\t\tCheck_TapeAlert(argc, argv);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t/* Tape commands */\n\t\t\tif (!strncasecmp(argv[2], \"load\", 4)) {\n\t\t\t\tCheck_Load(argc, argv);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!strncasecmp(argv[2], \"unload\", 6)) {\n\t\t\t\tCheck_Unload(argc, argv);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!strncasecmp(argv[2], \"delay\", 5)) {\n\t\t\t\tCheck_delay(argc, argv);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!strncasecmp(argv[2], \"compression\", 11)) {\n\t\t\t\tCheck_Compression(argc, argv);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!strncasecmp(argv[2], \"Append\", 6)) {\n\t\t\t\tCheck_append_only(argc, argv);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t/* Library commands */\n\t\t\tif (!strcmp(argv[2], \"add\")) {\n\t\t\t\tif (argc == 4)\n\t\t\t\t\treturn;\n\t\t\t\tPrintErrorExit(argv[0], \"add slot\");\n\t\t\t}\n\t\t\tif (!strcmp(argv[2], \"online\")) {\n\t\t\t\tif (argc == 3)\n\t\t\t\t\treturn;\n\t\t\t\tPrintErrorExit(argv[0], \"online\");\n\t\t\t}\n\t\t\tif (!strcmp(argv[2], \"offline\")) {\n\t\t\t\tif (argc == 3)\n\t\t\t\t\treturn;\n\t\t\t\tPrintErrorExit(argv[0], \"offline\");\n\t\t\t}\n\t\t\tif (!strcmp(argv[2], \"list\")) {\n\t\t\t\tCheck_List(argc, argv);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!strcmp(argv[2], \"empty\")) {\n\t\t\t\tCheck_Empty(argc, argv);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!strcmp(argv[2], \"open\")) {\n\t\t\t\tCheck_Open(argc, argv);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!strcmp(argv[2], \"close\")) {\n\t\t\t\tCheck_Close(argc, argv);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tPrintErrorExit(argv[0], \"check param\");\n\t\t}\n\t\tPrintErrorExit(argv[0], \"\");\n\t}\n\tPrintErrorExit(argv[0], \"\");\n}\n\n/* Open a new queue (for answers from server) */\nint CreateNewQueue(void) {\n\tlong queue_id;\n\n\t/* Attempt to create a message queue */\n\tqueue_id = msgget(IPC_PRIVATE,\n\t\t\t\t\t  IPC_CREAT | S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH);\n\tif (queue_id == -1)\n\t\tfprintf(stderr, \"%s: %s\\n\", __func__, strerror(errno));\n\n\treturn queue_id;\n}\n\n/* Open an alreay opened queue (opened by server) */\nint OpenExistingQueue(key_t key) {\n\tlong queue_id;\n\n\t/* Attempt to open an existing message queue */\n\tqueue_id = msgget(key, 0);\n\tif (queue_id == -1)\n\t\tfprintf(stderr, \"%s: %s\\n\", __func__, strerror(errno));\n\n\treturn queue_id;\n}\n\n/* Send command to queue */\nint SendMsg(long ReceiverQid, long ReceiverMtyp, char *sndbuf) {\n\tstruct q_entry s_entry;\n\n\ts_entry.rcv_id\t\t= ReceiverMtyp;\n\ts_entry.msg.snd_id\t= VTLCMD_Q;\n\ts_entry.msg.text[0] = '\\0';\n\tstrncat(s_entry.msg.text, sndbuf, MAXTEXTLEN);\n\n\tint len = strlen(s_entry.msg.text) + 1 + sizeof(s_entry.msg.snd_id);\n\tif (msgsnd(ReceiverQid, &s_entry, len, 0) == -1)\n\t\treturn -1;\n\n\treturn 0;\n}\n\nint main(int argc, char **argv) {\n\tchar  device_conf[CONF_FILE_SZ];\n\tFILE *conf;\n\tchar  b[1024];\n\tint\t  device_type = TYPE_UNKNOWN;\n\tlong  deviceNo, indx;\n\tint\t  count;\n\tchar  buf[1024];\n\tchar *p;\n\n\tmy_id = VTLCMD_Q;\n\n\tif (get_config(device_conf, DEVICE_CONF, my_id) < 0)\n\t\texit(1);\n\n\tif ((argc < 2) || (argc > 6)) {\n\t\tusage(argv[0]);\n\t\texit(1);\n\t}\n\n\t/* checking several positions of -h/-help */\n\tfor (count = 1; count < argc; count++) {\n\t\tif (!strcmp(argv[count], \"-h\")) {\n\t\t\tusage(argv[0]);\n\t\t\texit(1);\n\t\t}\n\t\tif (!strcmp(argv[count], \"/h\")) {\n\t\t\tusage(argv[0]);\n\t\t\texit(1);\n\t\t}\n\t\tif (!strcmp(argv[count], \"-help\")) {\n\t\t\tusage(argv[0]);\n\t\t\texit(1);\n\t\t}\n\t\tif (!strcasecmp(argv[count], \"-v\")) {\n\t\t\tfprintf(stderr, \"Version: %s %s %s\\n\", MHVTL_VERSION, MHVTL_GITHASH, MHVTL_GITDATE);\n\t\t\texit(1);\n\t\t}\n\t}\n\n\tCheck_Params(argc, argv);\n\n\tdeviceNo = atol(argv[1]);\n\tif ((deviceNo < 0) || (deviceNo >= VTLCMD_Q)) {\n\t\tfprintf(stderr, \"Invalid device number for \"\n\t\t\t\t\t\t\"tape/library: %s\\n\",\n\t\t\t\targv[1]);\n\t\texit(1);\n\t}\n\n\tconf = fopen(device_conf, \"r\");\n\tif (!conf) {\n\t\tfprintf(stderr, \"Can not open config file %s : %s\\n\",\n\t\t\t\tdevice_conf, strerror(errno));\n\t\texit(1);\n\t}\n\n\tp\t   = buf;\n\tbuf[0] = '\\0';\n\n\t/* While read in a line */\n\twhile (fgets(b, sizeof(b), conf) != NULL) {\n\t\tif (sscanf(b, \"Drive: %ld \", &indx) == 1 &&\n\t\t\tindx == deviceNo) {\n\t\t\tdevice_type = TYPE_DRIVE;\n\t\t\tbreak;\n\t\t}\n\t\tif (sscanf(b, \"Library: %ld \", &indx) == 1 &&\n\t\t\tindx == deviceNo) {\n\t\t\tdevice_type = TYPE_LIBRARY;\n\t\t\tbreak;\n\t\t}\n\t}\n\tfclose(conf);\n\n\tif (device_type == TYPE_UNKNOWN) {\n\t\tfprintf(stderr, \"No tape/library (%s) configured with \"\n\t\t\t\t\t\t\"device number: %ld\\n\",\n\t\t\t\tdevice_conf, deviceNo);\n\t\texit(1);\n\t}\n\n\t/* Concat all args into one string.\n\t * Bound each write by remaining buffer space so an oversized argv\n\t * cannot overflow buf[] (the outgoing message queue slot is\n\t * sizeof(buf) bytes).\n\t */\n\t{\n\t\tsize_t remaining = sizeof(buf);\n\t\tp\t\t\t\t = buf;\n\t\tbuf[0]\t\t\t = '\\0';\n\t\tfor (count = 2; count < argc; count++) {\n\t\t\tint n = snprintf(p, remaining, \"%s \", argv[count]);\n\t\t\tif (n < 0 || (size_t)n >= remaining) {\n\t\t\t\tfprintf(stderr, \"Command line too long \"\n\t\t\t\t\t\t\t\t\"(max %zu bytes)\\n\",\n\t\t\t\t\t\tsizeof(buf) - 1);\n\t\t\t\texit(1);\n\t\t\t}\n\t\t\tp += n;\n\t\t\tremaining -= n;\n\t\t}\n\t}\n\n\t/* check if command to the specific device is allowed */\n\tif (device_type == TYPE_LIBRARY) {\n\t\tif (!strncmp(buf, \"online\", 6)) {\n\t\t} else if (!strncmp(buf, \"add slot\", 8)) {\n\t\t} else if (!strncmp(buf, \"offline\", 7)) {\n\t\t} else if (!strncmp(buf, \"open map\", 8)) {\n\t\t} else if (!strncmp(buf, \"close map\", 9)) {\n\t\t} else if (!strncmp(buf, \"empty map\", 9)) {\n\t\t} else if (!strncmp(buf, \"list map\", 8)) {\n\t\t} else if (!strncmp(buf, \"load map\", 8)) {\n\t\t} else if (!strncmp(buf, \"verbose\", 7)) {\n\t\t} else if (!strncmp(buf, \"debug\", 5)) {\n\t\t} else if (!strncmp(buf, \"exit\", 4)) {\n\t\t} else if (!strncmp(buf, \"TapeAlert\", 9)) {\n\t\t} else if (!strncmp(buf, \"InquiryDataChange\", 17)) {\n\t\t} else {\n\t\t\tfprintf(stderr, \"Command for library not allowed\\n\");\n\t\t\texit(1);\n\t\t}\n\t}\n\n\tif (device_type == TYPE_DRIVE) {\n\t\tif (!strncmp(buf, \"load\", 4)) {\n\t\t} else if (!strncmp(buf, \"unload\", 6)) {\n\t\t} else if (!strncmp(buf, \"verbose\", 7)) {\n\t\t} else if (!strncmp(buf, \"debug\", 5)) {\n\t\t} else if (!strncmp(buf, \"dump\", 4)) {\n\t\t} else if (!strncmp(buf, \"exit\", 4)) {\n\t\t} else if (!strncmp(buf, \"compression\", 11)) {\n\t\t} else if (!strncmp(buf, \"TapeAlert\", 9)) {\n\t\t} else if (!strncmp(buf, \"InquiryDataChange\", 17)) {\n\t\t} else if (!strncasecmp(buf, \"append\", 6)) {\n\t\t} else if (!strncasecmp(buf, \"delay load\", 10)) {\n\t\t} else if (!strncasecmp(buf, \"delay unload\", 12)) {\n\t\t} else if (!strncasecmp(buf, \"delay rewind\", 12)) {\n\t\t} else if (!strncasecmp(buf, \"delay position\", 14)) {\n\t\t} else if (!strncasecmp(buf, \"delay thread\", 12)) {\n\t\t} else {\n\t\t\tfprintf(stderr, \"Command for tape not allowed\\n\");\n\t\t\texit(1);\n\t\t}\n\t}\n\n\t/* Check for the existance of a datafile first - abort if not there */\n\tif (device_type == TYPE_LIBRARY) {\n\t\tif (!strcmp(argv[2], \"load\") && !strcmp(argv[3], \"map\")) {\n\t\t\tif (check_media(deviceNo, argv[4])) {\n\t\t\t\tfprintf(stderr, \"Hint: Use command 'mktape' to \"\n\t\t\t\t\t\t\t\t\"create media first\\n\");\n\t\t\t\texit(1);\n\t\t\t}\n\t\t}\n\t}\n\n\tlong ReceiverQid;\n\tReceiverQid = OpenExistingQueue(QKEY);\n\tif (ReceiverQid == -1) {\n\t\tfprintf(stderr, \"MessageQueue not available\\n\");\n\t\texit(1);\n\t}\n\n\tif (SendMsg(ReceiverQid, deviceNo, buf) < 0) {\n\t\tfprintf(stderr, \"Message Queue Error: send message\\n\");\n\t\texit(1);\n\t}\n\n\tif (device_type == TYPE_LIBRARY) {\n\t\tif (!strcmp(argv[2], \"add\") && !strcmp(argv[3], \"slot\"))\n\t\t\tDisplayResponse(ReceiverQid, \"\");\n\t\tif (!strcmp(argv[2], \"open\") && !strcmp(argv[3], \"map\"))\n\t\t\tDisplayResponse(ReceiverQid, \"\");\n\t\tif (!strcmp(argv[2], \"close\") && !strcmp(argv[3], \"map\"))\n\t\t\tDisplayResponse(ReceiverQid, \"\");\n\t\tif (!strcmp(argv[2], \"empty\") && !strcmp(argv[3], \"map\"))\n\t\t\tDisplayResponse(ReceiverQid, \"\");\n\t\tif (!strcmp(argv[2], \"list\") && !strcmp(argv[3], \"map\"))\n\t\t\tDisplayResponse(ReceiverQid, \"Contents: \");\n\t\tif (!strcmp(argv[2], \"load\") && !strcmp(argv[3], \"map\"))\n\t\t\tDisplayResponse(ReceiverQid, \"\");\n\t}\n\n\texit(0);\n}\n"
  },
  {
    "path": "usr/cmd/vtllibrary.c",
    "content": "/*\n * This daemon is the SCSI SMC target (Medium Changer) portion of the\n * vtl package.\n *\n * The vtl package consists of:\n *   a kernel module (vlt.ko) - Currently on 2.6.x Linux kernel support.\n *   SCSI target daemons for both SMC and SSC devices.\n *\n * Copyright (C) 2005 - 2025 Mark Harvey       markh794@gmail.com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n * See comments in vtltape.c for a more complete version release...\n *\n * 0.14 13 Feb 2008\n *\tSince ability to define device serial number, increased ver from\n *\t0.12 to 0.14\n *\n * v0.12 -> Forked into 'stable' (0.12) and 'devel' (0.13).\n *          My current thinking : This is a dead end anyway.\n *          An iSCSI target done in user-space is now my perferred solution.\n *          This means I don't have to do any kernel level drivers\n *          and leaverage the hosts native iSCSI initiator.\n */\n\n#include <unistd.h>\n#include <sys/ipc.h>\n#include <string.h>\n#include <sys/msg.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <errno.h>\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <sys/wait.h>\n#include <syslog.h>\n#include <ctype.h>\n#include <inttypes.h>\n#include <signal.h>\n#include \"vtl_common.h\"\n#include \"mhvtl_scsi.h\"\n#include \"mhvtl_list.h\"\n#include \"q.h\"\n#include \"logging.h\"\n#include \"vtllib.h\"\n#include \"spc.h\"\n#include \"smc.h\"\n#include \"mode.h\"\n#include \"be_byteshift.h\"\n#include \"mhvtl_log.h\"\n\nchar mhvtl_driver_name[] = \"vtllibrary\";\n\n#define CAP_CLOSED 1\n#define CAP_OPEN   0\n#define OPERATOR   1\n#define ROBOT_ARM  0\n\n#define SMC_BUF_SIZE 1024 * 1024 /* Default size of buffer */\n\nstatic uint8_t sam_status = 0; /* Non-zero if Sense-data is valid */\nstatic long\t   backoff;\t\t   /* Backoff value for polling char device */\n\nstatic struct smc_priv smc_slots;\n\nstruct s_info *add_new_slot(struct lu_phy_attr *lu);\n\nstatic void usage(char *progname) {\n\tprintf(\"Usage: %s [OPTIONS] -q <Q-number>\\n\", progname);\n\tprintf(\"Where:\\n\");\n\tprintf(\"       '-q <Q-number>' is the queue priority number\\n\");\n\tprintf(\"and where OPTIONS are from:\\n\");\n\tprintf(\"       '-d'       enable debug mode -> Don't run as daemon\\n\");\n\tprintf(\"       'v[N]'     enable verbose syslog messages level N [1]\\n\");\n\tprintf(\"       '-f FIFO'  use FIFO to report real-time data\\n\");\n\tprintf(\"       '-F'       run in the foreground\\n\");\n}\n\n#ifndef Solaris\nint ioctl(int, int, void *);\n#endif\n\nstruct device_type_template smc_template = {\n\t.ops = {\n\t\tSCSI_OP_RANGE(0x00, 0xff, spc_illegal_op),\n\n\t\t/* 0x00 -> 0x0f */\n\t\tSCSI_OP(0x00, spc_tur),\n\t\tSCSI_OP(0x01, smc_rezero),\n\t\tSCSI_OP(0x03, spc_request_sense),\n\t\tSCSI_OP(0x07, smc_initialize_element_status),\n\n\t\t/* 0x10 -> 0x1f */\n\t\tSCSI_OP(0x12, spc_inquiry),\n\t\tSCSI_OP(0x15, spc_mode_select),\n\t\tSCSI_OP(0x16, spc_reserve),\n\t\tSCSI_OP(0x17, spc_release),\n\t\tSCSI_OP(0x1a, spc_mode_sense),\n\t\tSCSI_OP(0x1b, smc_open_close_import_export_element),\n\t\tSCSI_OP(0x1c, spc_recv_diagnostics),\n\t\tSCSI_OP(0x1d, spc_send_diagnostics),\n\t\tSCSI_OP(0x1e, smc_allow_removal),\n\n\t\t/* 0x20 -> 0x2f */\n\t\t/* 0x30 -> 0x3f */\n\t\t/* 0x40 -> 0x4f */\n\t\tSCSI_OP(0x4c, spc_log_select),\n\t\tSCSI_OP(0x4d, smc_log_sense),\n\n\t\t/* 0x50 -> 0x5f */\n\t\tSCSI_OP(0x55, spc_mode_select),\n\t\tSCSI_OP(0x56, spc_reserve),\n\t\tSCSI_OP(0x57, spc_release),\n\t\tSCSI_OP(0x5a, spc_mode_sense),\n\n\t\t/* 0x60 -> 0x6f */\n\t\t/* 0x70 -> 0x7f */\n\t\t/* 0x80 -> 0x8f */\n\t\t/* 0x90 -> 0x9f */\n\t\t/* 0xa0 -> 0xaf */\n\t\tSCSI_OP(0xa0, spc_illegal_op), /* processed in the kernel module */\n\t\tSCSI_OP(0xa5, smc_move_medium),\n\n\t\t/* 0xb0 -> 0xbf */\n\t\tSCSI_OP(0xb8, smc_read_element_status),\n\n\t\t/* 0xc0 -> 0xcf */\n\t\t/* 0xd0 -> 0xdf */\n\t\t/* 0xe0 -> 0xef */\n\t\tSCSI_OP(0xe7, smc_initialize_element_status_with_range),\n\n\t\t/* 0xf0 -> 0xff */\n\t}};\n\n__attribute__((constructor)) static void smc_init(void) {\n\tdevice_type_register(&lunit, &smc_template);\n}\n\n/*\n * Update ops[xx] with new/updated/custom function 'f'\n */\nvoid register_ops(struct lu_phy_attr *lu, int op,\n\t\t\t\t  void *f, void *g, void *h) {\n\tlu->scsi_ops->ops[op].cmd_perform\t   = f;\n\tlu->scsi_ops->ops[op].pre_cmd_perform  = g;\n\tlu->scsi_ops->ops[op].post_cmd_perform = h;\n}\n\n/*\n *\n * Process the SCSI command\n *\n * Called with:\n *\tcdev          -> Char dev file handle,\n *\tcdb           -> SCSI Command buffer pointer,\n *\tstruct mhvtl_ds -> general purpose data structure... Need better name\n *\n * Return:\n *\tSAM status returned in struct mhvtl_ds.sam_stat\n */\nstatic void processCommand(int cdev, uint8_t *cdb, struct mhvtl_ds *dbuf_p,\n\t\t\t\t\t\t   useconds_t pollInterval) {\n\tint\t\t\t\t err = 0;\n\tstruct scsi_cmd\t _cmd;\n\tstruct scsi_cmd *cmd;\n\tcmd = &_cmd;\n\n\tcmd->scb\t\t  = cdb;\n\tcmd->scb_len\t  = 16; /* fixme */\n\tcmd->dbuf_p\t\t  = dbuf_p;\n\tcmd->lu\t\t\t  = &lunit;\n\tcmd->pollInterval = pollInterval;\n\tcmd->cdev\t\t  = cdev;\n\n\tMHVTL_DBG_PRT_CDB(1, cmd);\n\n\tswitch (cdb[0]) {\n\tcase INQUIRY: /* INQUIRY does not need to check PowerOn/reset, however the Inquiry Data may have changed */\n\t\tif (check_inquiry_data_has_changed(&dbuf_p->sam_stat))\n\t\t\treturn;\n\tcase REPORT_LUNS:\n\tcase REQUEST_SENSE:\n\tcase MODE_SELECT:\n\t\tdbuf_p->sam_stat = SAM_STAT_GOOD;\n\t\tbreak;\n\tdefault:\n\t\tif (cmd->lu->online == 0) {\n\t\t\tsam_not_ready(E_OFFLINE, &dbuf_p->sam_stat);\n\t\t\treturn;\n\t\t}\n\t\tif (check_reset(&dbuf_p->sam_stat))\n\t\t\treturn;\n\t}\n\n\t/* Skip main op code processing if pre-cmd returns non-zero */\n\tif (cmd->lu->scsi_ops->ops[cdb[0]].pre_cmd_perform)\n\t\terr = cmd->lu->scsi_ops->ops[cdb[0]].pre_cmd_perform(cmd, NULL);\n\n\tif (!err)\n\t\tdbuf_p->sam_stat = cmd->lu->scsi_ops->ops[cdb[0]].cmd_perform(cmd);\n\n\t/* Post op code processing regardless */\n\tif (cmd->lu->scsi_ops->ops[cdb[0]].post_cmd_perform)\n\t\tcmd->lu->scsi_ops->ops[cdb[0]].post_cmd_perform(cmd, NULL);\n\n\treturn;\n}\n\n/*\n * Respond to messageQ 'list map' by sending a list of PCLs to messageQ\n */\nstatic void list_map(struct q_msg *msg) {\n\tstruct list_head *slot_head = &smc_slots.slot_list;\n\tstruct s_info\t *sp;\n\tchar\t\t\t  buf[MAXOBN];\n\tchar\t\t\t *c = buf;\n\t*c\t\t\t\t\t= '\\0';\n\n\tlist_for_each_entry(sp, slot_head, siblings) {\n\t\tif (slotOccupied(sp) && sp->element_type == MAP_ELEMENT) {\n\t\t\tstrncat(c, (char *)sp->media->barcode, MAX_BARCODE_LEN + 1);\n\t\t\tMHVTL_DBG(2, \"MAP slot %d full\", sp->slot_location);\n\t\t} else {\n\t\t\tMHVTL_DBG(2, \"MAP slot %d empty\", sp->slot_location);\n\t\t}\n\t}\n\tMHVTL_DBG(2, \"map contents: %s\", buf);\n\tsend_msg(buf, msg->snd_id);\n}\n\n/* Check existing MAP & Storage slots for existing barcode */\nint already_in_slot(char *barcode) {\n\tstruct list_head *slot_head = &smc_slots.slot_list;\n\tstruct s_info\t *sp\t\t= NULL;\n\tint\t\t\t\t  len;\n\n\tlen = strlen(barcode);\n\n\tlist_for_each_entry(sp, slot_head, siblings) {\n\t\tif (slotOccupied(sp)) {\n\t\t\tif (!strncmp((char *)sp->media->barcode, barcode, len)) {\n\t\t\t\tMHVTL_DBG(3, \"Match: %s %s\",\n\t\t\t\t\t\t  sp->media->barcode, barcode);\n\t\t\t\treturn 1;\n\t\t\t} else\n\t\t\t\tMHVTL_DBG(3, \"No match: %s %s\",\n\t\t\t\t\t\t  sp->media->barcode, barcode);\n\t\t}\n\t}\n\treturn 0;\n}\n\nstatic struct s_info *locate_empty_map(void) {\n\tstruct s_info\t *sp\t\t= NULL;\n\tstruct list_head *slot_head = &smc_slots.slot_list;\n\n\tlist_for_each_entry(sp, slot_head, siblings) {\n\t\tif (!slotOccupied(sp) && sp->element_type == MAP_ELEMENT)\n\t\t\treturn sp;\n\t}\n\n\treturn NULL;\n}\n\nstatic struct m_info *lookup_barcode(struct lu_phy_attr *lu, char *barcode) {\n\tstruct list_head *media_list_head;\n\tstruct m_info\t *m;\n\tint\t\t\t\t  match;\n\n\tmedia_list_head = &((struct smc_priv *)lu->lu_private)->media_list;\n\n\tlist_for_each_entry(m, media_list_head, siblings) {\n\t\tmatch = strncmp(m->barcode, barcode, MAX_BARCODE_LEN + 1);\n\t\tif (!match) {\n\t\t\tMHVTL_DBG(3, \"Match barcodes: %s %s: %d\",\n\t\t\t\t\t  barcode, m->barcode, match);\n\t\t\treturn m;\n\t\t}\n\t}\n\n\treturn NULL;\n}\n\nstatic struct m_info *add_barcode(struct lu_phy_attr *lu, char *barcode) {\n\tstruct list_head *media_list_head;\n\tstruct m_info\t *m;\n\n\tif (strlen(barcode) > MAX_BARCODE_LEN) {\n\t\tMHVTL_ERR(\"Barcode \\'%s\\' exceeds max barcode lenght: %d\",\n\t\t\t\t  barcode, MAX_BARCODE_LEN);\n\t\texit(1);\n\t}\n\tif (lookup_barcode(lu, barcode)) {\n\t\tMHVTL_ERR(\"Duplicate barcode %s.. Exiting\", barcode);\n\t\texit(1);\n\t}\n\n\tm = zalloc(sizeof(struct m_info));\n\tif (!m) {\n\t\tMHVTL_ERR(\"Out of memory allocating memory for barcode %s\",\n\t\t\t\t  barcode);\n\t\texit(-ENOMEM);\n\t}\n\n\tmedia_list_head = &((struct smc_priv *)lu->lu_private)->media_list;\n\n\tmemset(m, 0, sizeof(struct m_info));\n\n\tsnprintf((char *)m->barcode, MAX_BARCODE_LEN + 1, LEFT_JUST_16_STR,\n\t\t\t barcode);\n\tm->barcode[MAX_BARCODE_LEN] = '\\0';\n\tm->cart_type\t\t\t\t= get_cart_type(barcode);\n\tif (!strncmp((char *)m->barcode, \"NOBAR\", 5))\n\t\tm->internal_status = INSTATUS_NO_BARCODE;\n\telse\n\t\tm->internal_status = 0;\n\n\tlist_add_tail(&m->siblings, media_list_head);\n\treturn m;\n}\n\n/* Return zero - failed, non-zero - success */\nstatic int load_map(struct q_msg *msg) {\n\tstruct s_info *sp = NULL;\n\tstruct m_info *mp = NULL;\n\tchar\t\t  *barcode;\n\tint\t\t\t   i;\n\tint\t\t\t   str_len;\n\tchar\t\t  *text = &msg->text[9]; /* skip past \"load map \" */\n\n\tMHVTL_DBG(2, \"Loading %s into MAP\", text);\n\n\tif (smc_slots.cap_closed) {\n\t\tsend_msg(\"MAP not opened\", msg->snd_id);\n\t\treturn 0;\n\t}\n\n\tstr_len = strlen(text);\n\tbarcode = NULL;\n\tfor (i = 0; i < str_len; i++)\n\t\tif (isalnum(text[i])) {\n\t\t\tbarcode = &text[i];\n\t\t\tbreak;\n\t\t}\n\n\t/* No barcode - reject load */\n\tif (!barcode) {\n\t\tsend_msg(\"Bad barcode\", msg->snd_id);\n\t\treturn 0;\n\t}\n\n\tif (already_in_slot(barcode)) {\n\t\tsend_msg(\"barcode already in library\", msg->snd_id);\n\t\treturn 0;\n\t}\n\n\tif (strlen(barcode) > MAX_BARCODE_LEN) {\n\t\tsend_msg(\"barcode length too long\", msg->snd_id);\n\t\treturn 0;\n\t}\n\n\tsp = locate_empty_map();\n\tif (sp) {\n\t\tmp = lookup_barcode(&lunit, barcode);\n\t\tif (!mp)\n\t\t\tmp = add_barcode(&lunit, barcode);\n\n\t\tsnprintf((char *)mp->barcode, MAX_BARCODE_LEN + 1, LEFT_JUST_16_STR,\n\t\t\t\t barcode);\n\t\tmp->barcode[MAX_BARCODE_LEN] = '\\0';\n\n\t\t/* 1 = data, 2 = Clean */\n\t\tmp->cart_type = get_cart_type(barcode);\n\t\tsp->status\t  = STATUS_InEnab | STATUS_ExEnab |\n\t\t\t\t\t STATUS_Access | STATUS_ImpExp |\n\t\t\t\t\t STATUS_Full;\n\t\t/* Media placed by operator */\n\t\tsetImpExpStatus(sp, OPERATOR);\n\t\tsp->media\t\t\t\t   = mp;\n\t\tsp->media->internal_status = 0;\n\t\tsend_msg(\"OK\", msg->snd_id);\n\t\treturn 1;\n\t}\n\tsend_msg(\"MAP Full\", msg->snd_id);\n\treturn 0;\n}\n\nstatic void open_map(struct q_msg *msg) {\n\tMHVTL_DBG(1, \"Called\");\n\n\tcurrent_state = MHVTL_STATE_OPENING_MAP;\n\n\tsmc_slots.cap_closed = CAP_OPEN;\n\tsend_msg(\"OK\", msg->snd_id);\n}\n\nstatic void close_map(struct q_msg *msg) {\n\tMHVTL_DBG(1, \"Called\");\n\n\tcurrent_state = MHVTL_STATE_CLOSING_MAP;\n\n\tsmc_slots.cap_closed = CAP_CLOSED;\n\tsend_msg(\"OK\", msg->snd_id);\n}\n\n/* add new slot && assignment && initialization memory */\nstatic void add_storage_slot(struct q_msg *msg) {\n\tint\t\t\t\t buffer_size;\n\tint\t\t\t\t slt_no;\n\tchar\t\t\t message[20];\n\tstruct s_info\t*sp1   = NULL;\n\tstruct smc_priv *smc_p = lunit.lu_private;\n\n\tsp1 = add_new_slot(&lunit);\n\n\tsmc_p->num_storage++;\n\tslt_no\t\t\t   = smc_p->num_storage;\n\tsp1->element_type  = STORAGE_ELEMENT;\n\tsp1->status\t\t   = STATUS_Access;\n\tsp1->slot_location = slt_no + smc_p->pm->start_storage - 1;\n\n\t/* Slot status to Empty */\n\tsetSlotEmpty(sp1);\n\n\tinit_smc_log_pages(&lunit);\n\tinit_smc_mode_pages(&lunit);\n\tMHVTL_DBG(1, \"add slot && init smc\");\n\n\t/* malloc a big enough buffer to fit worst case read element status */\n\tbuffer_size\t\t  = (smc_slots.num_drives + smc_slots.num_picker + smc_slots.num_map + smc_slots.num_storage) * 80;\n\tbuffer_size\t\t  = max(SMC_BUF_SIZE, buffer_size);\n\tsmc_slots.bufsize = buffer_size;\n\tMHVTL_DBG(1, \"Setting buffer size to %d\", buffer_size);\n\n\tsprintf(message, \"slot=%d\", slt_no);\n\tsend_msg(message, msg->snd_id);\n\treturn;\n}\n\n/*\n * Respond to messageQ 'empty map' by clearing 'ocuplied' status in map slots.\n * Return 0 on failure, non-zero - success.\n */\nstatic int empty_map(struct q_msg *msg) {\n\tstruct s_info\t *sp;\n\tstruct list_head *slot_head = &smc_slots.slot_list;\n\n\tif (smc_slots.cap_closed) {\n\t\tMHVTL_DBG(1, \"MAP slot empty failed - CAP Not open\");\n\t\tsend_msg(\"Can't empty map while MAP is closed\", msg->snd_id);\n\t\treturn 0;\n\t}\n\n\tlist_for_each_entry(sp, slot_head, siblings) {\n\t\tif (slotOccupied(sp) && sp->element_type == MAP_ELEMENT) {\n\t\t\tsetSlotEmpty(sp);\n\t\t\tMHVTL_DBG(2, \"MAP slot %d emptied\",\n\t\t\t\t\t  sp->slot_location -\n\t\t\t\t\t\t  smc_slots.pm->start_map);\n\t\t}\n\t}\n\n\tsend_msg(\"OK\", msg->snd_id);\n\treturn 1;\n}\n\n/* Extract the id of the tape sending notification a tape was ejected\n * Set the 'access' bit in the READ_ELEMENT_STATUS page\n */\nstatic int set_access_bit(struct q_msg *msg) {\n\tstruct s_info\t *sp;\n\tstruct list_head *slot_head = &smc_slots.slot_list;\n\n\tlist_for_each_entry(sp, slot_head, siblings) {\n\t\tif (slotOccupied(sp) && sp->element_type == DATA_TRANSFER) {\n\t\t\tif (sp->drive->drv_id == msg->snd_id) {\n\t\t\t\tsetAccessStatus(sp, 1);\n\t\t\t\tMHVTL_DBG(2, \"Enabling access bit for drive id %ld\", sp->drive->drv_id);\n\t\t\t}\n\t\t}\n\t}\n\treturn 0;\n}\n\n/*\n * Return 1, exit program\n */\nstatic int processMessageQ(struct q_msg *msg) {\n\n\tMHVTL_DBG(1, \"%ld: Received from sender id: %ld, msg : %s\", my_id, msg->snd_id, msg->text);\n\n\tif (!strncmp(msg->text, \"debug\", 5)) {\n\t\tif (debug) {\n\t\t\tdebug--;\n\t\t} else {\n\t\t\tdebug++;\n\t\t\tverbose = 2;\n\t\t}\n\t}\n\tif (!strncmp(msg->text, \"add slot\", 8))\n\t\tadd_storage_slot(msg);\n\tif (!strncmp(msg->text, \"empty map\", 9))\n\t\tempty_map(msg);\n\tif (!strncmp(msg->text, msg_eject, strlen(msg_eject)))\n\t\tset_access_bit(msg);\n\tif (!strncmp(msg->text, \"exit\", 4))\n\t\treturn 1;\n\tif (!strncmp(msg->text, \"open map\", 8))\n\t\topen_map(msg);\n\tif (!strncmp(msg->text, \"close map\", 9))\n\t\tclose_map(msg);\n\tif (!strncmp(msg->text, \"list map\", 8))\n\t\tlist_map(msg);\n\tif (!strncmp(msg->text, \"load map \", 9))\n\t\tload_map(msg);\n\tif (!strncmp(msg->text, \"InquiryDataChange\", 17))\n\t\tset_inquiry_data_changed();\n\tif (!strncmp(msg->text, \"offline\", 7)) {\n\t\tcurrent_state = MHVTL_STATE_OFFLINE;\n\t\tlunit.online  = 0;\n\t}\n\tif (!strncmp(msg->text, \"online\", 6)) {\n\t\tcurrent_state = MHVTL_STATE_ONLINE;\n\t\tlunit.online  = 1;\n\t}\n\tif (!strncmp(msg->text, \"TapeAlert\", 9)) {\n\t\tuint64_t flg = TA_NONE;\n\t\tsscanf(msg->text, \"TapeAlert %\" PRIx64, &flg);\n\t\tset_TapeAlert(flg);\n\t}\n\tif (!strncmp(msg->text, \"verbose\", 7)) {\n\t\tif (verbose)\n\t\t\tverbose--;\n\t\telse\n\t\t\tverbose = 3;\n\t\tMHVTL_LOG(\"verbose: %s at level %d\",\n\t\t\t\t  verbose ? \"enabled\" : \"disabled\", verbose);\n\t}\n\n\treturn 0;\n}\n\nstatic struct d_info *lookup_drive(struct lu_phy_attr *lu, int drive_no) {\n\tstruct list_head *drive_list_head;\n\tstruct d_info\t *d;\n\tuint32_t\t\t  slot_offset;\n\n\tdrive_list_head = &((struct smc_priv *)lu->lu_private)->drive_list;\n\tslot_offset\t\t= ((struct smc_priv *)lu->lu_private)->pm->start_drive;\n\n\t/* Drive numbering starts from 1, decrement slot_offset */\n\tslot_offset--;\n\n\tlist_for_each_entry(d, drive_list_head, siblings) {\n\t\tMHVTL_DBG(3, \"Slot location: %d, offset + drive_no: %d\",\n\t\t\t\t  d->slot->slot_location, slot_offset + drive_no);\n\t\tif (d->slot->slot_location == slot_offset + drive_no)\n\t\t\treturn d;\n\t}\n\n\treturn NULL;\n}\n\nstruct s_info *add_new_slot(struct lu_phy_attr *lu) {\n\tstruct s_info\t *new;\n\tstruct list_head *slot_list_head;\n\n\tslot_list_head = &((struct smc_priv *)lu->lu_private)->slot_list;\n\n\tnew = zalloc(sizeof(struct s_info));\n\tif (!new) {\n\t\tMHVTL_ERR(\"Could not allocate memory for new slot struct\");\n\t\texit(-ENOMEM);\n\t}\n\n\tlist_add_tail(&new->siblings, slot_list_head);\n\treturn new;\n}\n\n/* Open device config file and update device information\n */\nstatic void update_drive_details(struct lu_phy_attr *lu) {\n\tchar\t\t\t device_conf[CONF_FILE_SZ];\n\tFILE\t\t\t*conf;\n\tchar\t\t\t*b; /* Read from file into this buffer */\n\tchar\t\t\t*s; /* Somewhere for sscanf to store results */\n\tint\t\t\t\t slot;\n\tlong\t\t\t drv_id, lib_id;\n\tstruct d_info\t*dp;\n\tstruct s_info\t*sp;\n\tstruct smc_priv *smc_p = lu->lu_private;\n\n\tif (get_config(device_conf, DEVICE_CONF, my_id) < 0)\n\t\texit(1);\n\n\tconf = fopen(device_conf, \"r\");\n\tif (!conf) {\n\t\tMHVTL_DBG(1, \"Can not open config file %s : %s\", device_conf,\n\t\t\t\t  strerror(errno));\n\t\tperror(\"Can not open config file\");\n\t\texit(1);\n\t}\n\ts = zalloc(MALLOC_SZ);\n\tif (!s) {\n\t\tperror(\"Could not allocate memory\");\n\t\texit(1);\n\t}\n\tb = zalloc(MALLOC_SZ);\n\tif (!b) {\n\t\tperror(\"Could not allocate memory\");\n\t\texit(1);\n\t}\n\n\tdrv_id = -1;\n\tdp\t   = NULL;\n\n\t/* While read in a line */\n\twhile (readline(b, MALLOC_SZ, conf) != NULL) {\n\t\tif (b[0] == '#') /* Ignore comments */\n\t\t\tcontinue;\n\t\tif (sscanf(b, \"Drive: %ld\", &drv_id) > 0)\n\t\t\tcontinue;\n\t\tif (sscanf(b, \" Library ID: %ld Slot: %d\", &lib_id, &slot) == 2 && lib_id == my_id && drv_id >= 0) {\n\t\t\tMHVTL_DBG(2, \"Found Drive %ld in slot %d\",\n\t\t\t\t\t  drv_id, slot);\n\t\t\tdp = lookup_drive(lu, slot);\n\t\t\tif (!dp) {\n\t\t\t\tMHVTL_LOG(\"WARNING: Creating new entry for %ld\",\n\t\t\t\t\t\t  drv_id);\n\t\t\t\tdp = zalloc(sizeof(struct d_info));\n\t\t\t\tif (!dp) {\n\t\t\t\t\tMHVTL_ERR(\"Couldn't malloc memory\");\n\t\t\t\t\texit(-ENOMEM);\n\t\t\t\t}\n\t\t\t\tsp\t\t\t\t = add_new_slot(lu);\n\t\t\t\tsp->element_type = DATA_TRANSFER;\n\t\t\t\tdp->slot\t\t = sp;\n\t\t\t\tsp->drive\t\t = dp;\n\t\t\t\tlist_add_tail(&dp->siblings,\n\t\t\t\t\t\t\t  &smc_p->drive_list);\n\t\t\t}\n\t\t\tMHVTL_DBG(3, \"Updating drive id in slot %d to : %ld\",\n\t\t\t\t\t  dp->slot->slot_location,\n\t\t\t\t\t  drv_id);\n\t\t\tdp->drv_id = drv_id;\n\t\t\tcontinue;\n\t\t}\n\t\tif (dp) {\n\t\t\tif (sscanf(b, \" Unit serial number: %s\", s) > 0) {\n\t\t\t\tstrncpy(dp->inq_product_sno, s, 10);\n\t\t\t\trmnl(dp->inq_product_sno, ' ', 10);\n\t\t\t}\n\t\t\tif (sscanf(b, \" Product identification: %16c\", s) > 0) {\n\t\t\t\t/* sscanf does not NULL terminate */\n\t\t\t\t/* 25 is len of ' Product identification: ' */\n\t\t\t\ts[strlen(b) - 25] = '\\0';\n\t\t\t\tstrncpy(dp->inq_product_id, s, 16);\n\t\t\t\tdp->inq_product_id[16] = 0;\n\t\t\t\tMHVTL_DBG(3, \"id: \\'%s\\', inq_product_id: \\'%s\\'\",\n\t\t\t\t\t\t  s, dp->inq_product_id);\n\t\t\t}\n\t\t\tif (sscanf(b, \" Product revision level: %s\", s) > 0) {\n\t\t\t\tstrncpy(dp->inq_product_rev, s, 4);\n\t\t\t\trmnl(dp->inq_product_rev, ' ', 4);\n\t\t\t}\n\t\t\tif (sscanf(b, \" Vendor identification: %s\", s) > 0) {\n\t\t\t\tstrncpy(dp->inq_vendor_id, s, 8);\n\t\t\t\trmnl(dp->inq_vendor_id, ' ', 8);\n\t\t\t}\n\t\t}\n\t\tif (strlen(b) == 1) { /* Blank line => Reset device pointer */\n\t\t\tdrv_id = -1;\n\t\t\tdp\t   = NULL;\n\t\t}\n\t}\n\n\tfree(b);\n\tfree(s);\n\tfclose(conf);\n}\n\n/*\n * Return 0 - no address space conflict\n * Return 1 - overlap address with another slot type\n */\nstatic int check_overflow(struct lu_phy_attr *lu, int slot, char type) {\n\tstruct smc_priv *smc_p;\n\tint\t\t\t\t co;\n\n\tsmc_p = lu->lu_private;\n\tco\t  = 0;\n\n\tswitch (type) {\n\tcase MAP_ELEMENT:\n\t\tco = slot + smc_p->pm->start_map;\n\t\tif (smc_p->pm->start_map < smc_p->pm->start_storage &&\n\t\t\tco > smc_p->pm->start_storage) {\n\t\t\tMHVTL_LOG(\"MAP: %d, overlaps with storage slot\", slot);\n\t\t\treturn 1;\n\t\t}\n\t\tif (smc_p->pm->start_map < smc_p->pm->start_picker &&\n\t\t\tco > smc_p->pm->start_picker) {\n\t\t\tMHVTL_LOG(\"MAP: %d, overlaps with Picker slot\", slot);\n\t\t\treturn 1;\n\t\t}\n\t\tif (smc_p->pm->start_map < smc_p->pm->start_drive &&\n\t\t\tco > smc_p->pm->start_drive) {\n\t\t\tMHVTL_LOG(\"MAP: %d, overlaps with Drives\", slot);\n\t\t\treturn 1;\n\t\t}\n\t\tbreak;\n\tcase DATA_TRANSFER:\n\t\tco = slot + smc_p->pm->start_drive;\n\t\tif (smc_p->pm->start_drive < smc_p->pm->start_storage &&\n\t\t\tco > smc_p->pm->start_storage) {\n\t\t\tMHVTL_LOG(\"Drive: %d, overlaps with storage slot\",\n\t\t\t\t\t  slot);\n\t\t\treturn 1;\n\t\t}\n\t\tif (smc_p->pm->start_drive < smc_p->pm->start_picker &&\n\t\t\tco > smc_p->pm->start_picker) {\n\t\t\tMHVTL_LOG(\"Drive: %d, overlaps with picker slot\",\n\t\t\t\t\t  slot);\n\t\t\treturn 1;\n\t\t}\n\t\tif (smc_p->pm->start_drive < smc_p->pm->start_map &&\n\t\t\tco > smc_p->pm->start_map) {\n\t\t\tMHVTL_LOG(\"Drive: %d, overlaps with MAP slot\",\n\t\t\t\t\t  slot);\n\t\t\treturn 1;\n\t\t}\n\t\tbreak;\n\tcase MEDIUM_TRANSPORT:\n\t\tco = slot + smc_p->pm->start_picker;\n\t\tif (smc_p->pm->start_picker < smc_p->pm->start_map &&\n\t\t\tco > smc_p->pm->start_map) {\n\t\t\tMHVTL_LOG(\"Picker slot: %d overlaps with MAP\", slot);\n\t\t\treturn 1;\n\t\t}\n\t\tif (smc_p->pm->start_picker < smc_p->pm->start_drive &&\n\t\t\tco > smc_p->pm->start_drive) {\n\t\t\tMHVTL_LOG(\"Picker slot: %d overlaps with drives\", slot);\n\t\t\treturn 1;\n\t\t}\n\t\tif (smc_p->pm->start_picker < smc_p->pm->start_storage &&\n\t\t\tco > smc_p->pm->start_storage) {\n\t\t\tMHVTL_LOG(\"Picker slot: %d overlaps with Storage\",\n\t\t\t\t\t  slot);\n\t\t\treturn 1;\n\t\t}\n\t\tbreak;\n\tcase STORAGE_ELEMENT:\n\t\tco = slot + smc_p->pm->start_storage;\n\t\tif (smc_p->pm->start_storage < smc_p->pm->start_map &&\n\t\t\tco > smc_p->pm->start_map) {\n\t\t\tMHVTL_LOG(\"Storage slot: %d, overlaps with MAP\", slot);\n\t\t\treturn 1;\n\t\t}\n\t\tif (smc_p->pm->start_storage < smc_p->pm->start_picker &&\n\t\t\tco > smc_p->pm->start_picker) {\n\t\t\tMHVTL_LOG(\"Storage slot: %d, overlaps with picker\",\n\t\t\t\t\t  slot);\n\t\t\treturn 1;\n\t\t}\n\t\tif (smc_p->pm->start_storage < smc_p->pm->start_drive &&\n\t\t\tco > smc_p->pm->start_drive) {\n\t\t\tMHVTL_LOG(\"Storage slot: %d, overlaps with drives\",\n\t\t\t\t\t  slot);\n\t\t\treturn 1;\n\t\t}\n\t\tbreak;\n\t}\n\treturn 0;\n}\n\nvoid init_drive_slot(struct lu_phy_attr *lu, int slt, char *s) {\n\tstruct s_info\t*sp\t   = NULL;\n\tstruct d_info\t*dp\t   = NULL;\n\tstruct smc_priv *smc_p = lu->lu_private;\n\n\tif (check_overflow(lu, slt, DATA_TRANSFER))\n\t\treturn;\n\n\tdp = lookup_drive(lu, slt);\n\tif (!dp) {\n\t\tdp = zalloc(sizeof(struct d_info));\n\t\tif (!dp) {\n\t\t\tMHVTL_ERR(\"Couldn't malloc memory\");\n\t\t\texit(-ENOMEM);\n\t\t}\n\t\tsp\t\t\t\t = add_new_slot(lu);\n\t\tsp->element_type = DATA_TRANSFER;\n\t\tdp->slot\t\t = sp;\n\t\tsp->drive\t\t = dp;\n\t\tlist_add_tail(&dp->siblings, &smc_p->drive_list);\n\t}\n\tdp->slot->slot_location = slt + smc_p->pm->start_drive - 1;\n\tdp->slot->status\t\t= STATUS_Access;\n\tsmc_p->num_drives++;\n\tif (strlen(s)) {\n\t\tstrncpy(dp->inq_product_sno, s, 10);\n\t\tMHVTL_DBG(2, \"Drive s/no: %s\", s);\n\t}\n\tMHVTL_DBG(3, \"Slot: %d, start_drive: %d, slot_location: %d\",\n\t\t\t  slt, smc_p->pm->start_drive, dp->slot->slot_location);\n}\n\nvoid init_map_slot(struct lu_phy_attr *lu, int slt, char *barcode) {\n\tstruct s_info\t*sp\t   = NULL;\n\tstruct smc_priv *smc_p = lu->lu_private;\n\n\tif (check_overflow(lu, slt, MAP_ELEMENT))\n\t\treturn;\n\n\tsp\t\t\t\t = add_new_slot(lu);\n\tsp->element_type = MAP_ELEMENT;\n\tsmc_p->num_map++;\n\n\tsp->slot_location = slt + smc_p->pm->start_map - 1;\n\tsp->status\t\t  = STATUS_InEnab | STATUS_ExEnab |\n\t\t\t\t STATUS_Access | STATUS_ImpExp;\n\n\tif (strlen(barcode)) {\n\t\tMHVTL_DBG(2, \"Barcode %s in MAP %d\", barcode, slt);\n\t\tsp->media = add_barcode(lu, barcode);\n\t\tsp->status |= STATUS_Full;\n\t}\n}\n\nvoid init_transport_slot(struct lu_phy_attr *lu, int slt, char *barcode) {\n\tstruct s_info\t*sp\t   = NULL;\n\tstruct smc_priv *smc_p = lu->lu_private;\n\n\tif (check_overflow(lu, slt, MEDIUM_TRANSPORT))\n\t\treturn;\n\n\tsp\t\t\t\t = add_new_slot(lu);\n\tsp->element_type = MEDIUM_TRANSPORT;\n\tsmc_p->num_picker++;\n\tsp->slot_location = slt + smc_p->pm->start_picker - 1;\n\tsp->status\t\t  = 0;\n\n\tif (strlen(barcode)) {\n\t\tMHVTL_DBG(2, \"Barcode %s in Picker %d\", barcode, slt);\n\t\tsp->media\t\t  = add_barcode(lu, barcode);\n\t\tsp->slot_location = slt + smc_p->pm->start_picker - 1;\n\t\tsp->status |= STATUS_Full;\n\t}\n}\n\nvoid init_storage_slot(struct lu_phy_attr *lu, int slt, char *barcode) {\n\tstruct s_info\t*sp\t   = NULL;\n\tstruct smc_priv *smc_p = lu->lu_private;\n\n\tif (check_overflow(lu, slt, STORAGE_ELEMENT))\n\t\treturn;\n\n\tsp\t\t\t\t = add_new_slot(lu);\n\tsp->element_type = STORAGE_ELEMENT;\n\tsmc_p->num_storage++;\n\tsp->status\t\t  = STATUS_Access;\n\tsp->slot_location = slt + smc_p->pm->start_storage - 1;\n\tif (strlen(barcode)) {\n\t\tMHVTL_DBG(2, \"Barcode %s in slot %d\", barcode, slt);\n\t\tsp->media = add_barcode(lu, barcode);\n\t\t/* Slot full */\n\t\tsp->status |= STATUS_Full;\n\t}\n}\n\nstatic void __init_slot_info(struct lu_phy_attr *lu, int type) {\n\tchar\t\tlib_conf[CONF_FILE_SZ];\n\tFILE\t   *ctrl;\n\tchar\t   *b; /* Read from file into this buffer */\n\tchar\t   *s; /* Somewhere for sscanf to store results */\n\tint\t\t\tslt;\n\tstruct stat configstat;\n\tstruct stat persiststat;\n\tint\t\t\tfilestat;\n\tint\t\t\tstart_slot = 1; /* Slot creation needs to start with 1 */\n\tint\t\t\tz;\n\n\tfilestat = -1; /* Default to .persist file does not exist */\n\n\t/* Lets stat each (potential) file and identify the last one modified */\n\tget_config(lib_conf, LIBCONTENTS_PERSIST, my_id);\n\n\tif (lu->persist) /* If enabled - stat .persist file */\n\t\tfilestat = stat(lib_conf, &persiststat);\n\n\tif (filestat < 0) {\n\t\t/* PERSIST is either disabled or .persist file does not exist\n\t\t * - Update config filename to master 'library_contents.<id>\n\t\t */\n\t\tget_config(lib_conf, LIBCONTENTS, my_id);\n\t} else {\n\t\t/* stat original config file */\n\t\tget_config(lib_conf, LIBCONTENTS, my_id);\n\t\tfilestat = stat(lib_conf, &configstat);\n\t\tif (filestat < 0) { /* Does not exist !! */\n\t\t\tMHVTL_ERR(\"Can not stat config file %s: %s\",\n\t\t\t\t\t  lib_conf, strerror(errno));\n\t\t\texit(1);\n\t\t}\n\t\tif (configstat.st_mtime > persiststat.st_mtime) {\n\t\t\t/* Don't do anything - leave config filename alone */\n\t\t\tMHVTL_DBG(1, \"%s is newer than %s.persist file. \"\n\t\t\t\t\t\t \"Using %s instead\",\n\t\t\t\t\t  lib_conf, lib_conf, lib_conf);\n\t\t} else {\n\t\t\t/* Update the config file to\n\t\t\t   library_contents.<id>.persist\n\t\t\t*/\n\t\t\tget_config(lib_conf, LIBCONTENTS_PERSIST, my_id);\n\t\t}\n\t}\n\n\t/* By the time we get here -\n\t * - If PERSIST is enabled\n\t *   - We have stat'ed each file - so unless it's been removed within\n\t *     last few millisecs we should be good.\n\t * - Filename will be latest modify date\n\t */\n\tctrl = fopen(lib_conf, \"r\");\n\tif (!ctrl) {\n\t\tMHVTL_ERR(\"Can not open config file %s : %s\", lib_conf,\n\t\t\t\t  strerror(errno));\n\t\texit(1);\n\t}\n\n\t/* Log which config file is being used to read in data */\n\tMHVTL_DBG(2, \"Reading %s configuration information from %s\",\n\t\t\t  slot_type_str(type),\n\t\t\t  lib_conf);\n\n\t/* Grab a couple of generic MALLOC_SZ buffers.. */\n\ts = zalloc(MALLOC_SZ);\n\tif (!s) {\n\t\tperror(\"Could not allocate memory\");\n\t\texit(1);\n\t}\n\tb = zalloc(MALLOC_SZ);\n\tif (!b) {\n\t\tperror(\"Could not allocate memory\");\n\t\texit(1);\n\t}\n\n\trewind(ctrl);\n\twhile (readline(b, MALLOC_SZ, ctrl) != NULL) {\n\t\tif (b[0] == '#') /* Ignore comments */\n\t\t\tcontinue;\n\t\ts[0] = '\\0';\n\n\t\tswitch (type) {\n\t\tcase DATA_TRANSFER:\n\t\t\tif (sscanf(b, \"Drive %d: %s\", &slt, s)) {\n\t\t\t\tif (slt > start_slot) {\n\t\t\t\t\t/* Config file has holes - fill in empty slots */\n\t\t\t\t\tMHVTL_DBG(1, \"Config file is missing Drive %d - Creating empty records up to drive %d\", start_slot, slt);\n\t\t\t\t\tfor (z = start_slot; z < slt; z++) {\n\t\t\t\t\t\tinit_drive_slot(lu, z, \"\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tinit_drive_slot(lu, slt, s);\n\t\t\t\tstart_slot = slt + 1;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase MAP_ELEMENT:\n\t\t\tif (sscanf(b, \"MAP %d: %s\", &slt, s))\n\t\t\t\tinit_map_slot(lu, slt, s);\n\t\t\tbreak;\n\n\t\tcase MEDIUM_TRANSPORT:\n\t\t\tif (sscanf(b, \"Picker %d: %s\", &slt, s))\n\t\t\t\tinit_transport_slot(lu, slt, s);\n\t\t\tbreak;\n\n\t\tcase STORAGE_ELEMENT:\n\t\t\tif (sscanf(b, \"Slot %d: %s\", &slt, s)) {\n\t\t\t\tif (slt > start_slot) {\n\t\t\t\t\t/* Config file has holes - fill in empty slots */\n\t\t\t\t\tMHVTL_DBG(1, \"Config file is missing Slot %d - Creating empty slots up to %d\", start_slot, slt);\n\t\t\t\t\tfor (z = start_slot; z < slt; z++) {\n\t\t\t\t\t\tinit_storage_slot(lu, z, \"\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tinit_storage_slot(lu, slt, s);\n\t\t\t\tstart_slot = slt + 1;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\tfclose(ctrl);\n\tfree(b);\n\tfree(s);\n}\n\n/* Linked list data needs to be built in slot order */\nvoid init_slot_info(struct lu_phy_attr *lu) {\n\tint\t\t\t\t\t i;\n\tstruct smc_type_slot arr[4];\n\n\tsort_library_slot_type(lu, &arr[0]);\n\n\tfor (i = 0; i < 4; i++)\n\t\t__init_slot_info(lu, arr[i].type);\n}\n\n/* Return original slot location if empty\n */\nstatic struct s_info *previous_storage_slot(struct s_info\t *s,\n\t\t\t\t\t\t\t\t\t\t\tstruct list_head *slot_head) {\n\tstruct s_info *sp; /* Slot Pointer */\n\n\t/* Find slot info for 'previous location' */\n\tlist_for_each_entry(sp, slot_head, siblings) {\n\t\tif (sp->element_type == STORAGE_ELEMENT)\n\t\t\tif (sp->slot_location == s->last_location)\n\t\t\t\tif (!slotOccupied(sp))\n\t\t\t\t\t/* previous location is empty */\n\t\t\t\t\treturn sp;\n\t}\n\n\treturn NULL;\n}\n\n/* Return first empty storage slot.\n */\nstatic struct s_info *find_empty_storage_slot(struct s_info\t   *s,\n\t\t\t\t\t\t\t\t\t\t\t  struct list_head *slot_head) {\n\tstruct s_info *sp; /* Slot Pointer */\n\n\t/* If previous location is no good - lets find first empty slot */\n\tlist_for_each_entry(sp, slot_head, siblings) {\n\t\tif (!slotOccupied(sp) && sp->element_type == STORAGE_ELEMENT)\n\t\t\treturn sp;\n\t}\n\n\treturn NULL;\n}\n\n/* Save config on shutdown - Not to be called at other times !! */\nstatic void save_config(struct lu_phy_attr *lu) {\n\tFILE\t\t\t *ctrl;\n\tchar\t\t\t  lib_conf[CONF_FILE_SZ];\n\tstruct smc_priv\t *lu_priv;\n\tstruct list_head *slot_head;\n\tstruct list_head *drive_head;\n\tstruct s_info\t *sp; /* Slot Pointer */\n\tstruct d_info\t *dp; /* Drive Pointer */\n\tint\t\t\t\t  last_element_type = 0;\n\n\tget_config(lib_conf, LIBCONTENTS_PERSIST, my_id);\n\tctrl = fopen(lib_conf, \"w\");\n\tif (!ctrl) {\n\t\tMHVTL_ERR(\"Can not open file %s to save state : %s\", lib_conf,\n\t\t\t\t  strerror(errno));\n\t\treturn;\n\t}\n\n\tlu_priv = lu->lu_private;\n\n\tdrive_head = &lu_priv->drive_list;\n\tslot_head  = &lu_priv->slot_list;\n\n\t/* Walk each drive and force-unload into previous location\n\t * - if possible */\n\tlist_for_each_entry(dp, drive_head, siblings) {\n\t\tif (slotOccupied(dp->slot)) {\n\t\t\t/* Force a move of media from drive into\n\t\t\t * empty storage slot on shutdown\n\t\t\t */\n\t\t\tsp = dp->slot;\n\t\t\tMHVTL_DBG(1, \"Found %s in drive %d from %d\",\n\t\t\t\t\t  sp->media->barcode,\n\t\t\t\t\t  sp->slot_location -\n\t\t\t\t\t\t  lu_priv->pm->start_drive + 1,\n\t\t\t\t\t  sp->last_location);\n\t\t\tunload_drive_on_shutdown(sp,\n\t\t\t\t\t\t\t\t\t previous_storage_slot(sp, slot_head));\n\t\t}\n\t}\n\n\t/* Walk each drive and force-unload into first empty storage slot */\n\tlist_for_each_entry(dp, drive_head, siblings) {\n\t\tif (slotOccupied(dp->slot)) {\n\t\t\t/* Force a move of media from drive into\n\t\t\t * empty storage slot on shutdown\n\t\t\t */\n\t\t\tsp = dp->slot;\n\t\t\tMHVTL_DBG(1, \"Found %s in drive %d from %d\",\n\t\t\t\t\t  sp->media->barcode,\n\t\t\t\t\t  sp->slot_location -\n\t\t\t\t\t\t  lu_priv->pm->start_drive + 1,\n\t\t\t\t\t  sp->last_location);\n\t\t\tunload_drive_on_shutdown(sp,\n\t\t\t\t\t\t\t\t\t find_empty_storage_slot(sp, slot_head));\n\t\t}\n\t}\n\n\t/* Walk the list of all slots and write data into .persist file */\n\tlist_for_each_entry(sp, slot_head, siblings) {\n\t\t/* Pretty up conf file -\n\t\t * Place a blank line between element types\n\t\t */\n\t\tif (last_element_type != sp->element_type) {\n\t\t\tlast_element_type = sp->element_type;\n\t\t\tfprintf(ctrl, \"\\n\");\n\t\t}\n\n\t\tswitch (sp->element_type) {\n\t\tcase DATA_TRANSFER:\n\t\t\tfprintf(ctrl, \"Drive %d:\\n\",\n\t\t\t\t\tsp->slot_location -\n\t\t\t\t\t\tlu_priv->pm->start_drive + 1);\n\t\t\tbreak;\n\t\tcase MEDIUM_TRANSPORT:\n\t\t\tfprintf(ctrl, \"Picker %d: %s\\n\",\n\t\t\t\t\tsp->slot_location -\n\t\t\t\t\t\tlu_priv->pm->start_picker + 1,\n\t\t\t\t\tslotOccupied(sp) ? sp->media->barcode : \"\");\n\t\t\tbreak;\n\t\tcase MAP_ELEMENT:\n\t\t\tfprintf(ctrl, \"MAP %d: %s\\n\",\n\t\t\t\t\tsp->slot_location -\n\t\t\t\t\t\tlu_priv->pm->start_map + 1,\n\t\t\t\t\tslotOccupied(sp) ? sp->media->barcode : \"\");\n\t\t\tbreak;\n\t\tcase STORAGE_ELEMENT:\n\t\t\tfprintf(ctrl, \"Slot %d: %s\\n\",\n\t\t\t\t\tsp->slot_location -\n\t\t\t\t\t\tlu_priv->pm->start_storage + 1,\n\t\t\t\t\tslotOccupied(sp) ? sp->media->barcode : \"\");\n\t\t\tbreak;\n\t\t}\n\t}\n\tfclose(ctrl);\n}\n\nstatic int init_lu(struct lu_phy_attr *lu, unsigned minor, struct mhvtl_ctl *ctl) {\n\n\tstruct vpd **lu_vpd = lu->lu_vpd;\n\n\tchar\t\t\t device_conf[CONF_FILE_SZ];\n\tFILE\t\t\t*conf;\n\tchar\t\t\t*b; /* Read from file into this buffer */\n\tchar\t\t\t*s; /* Somewhere for sscanf to store results */\n\tint\t\t\t\t indx;\n\tstruct mhvtl_ctl tmpctl;\n\tint\t\t\t\t found = 0;\n\tint\t\t\t\t linecount;\n\n\tbackoff\t\t= DEFLT_BACKOFF_VALUE;\n\tlu->persist = FALSE;\n\n\tif (get_config(device_conf, DEVICE_CONF, my_id) < 0)\n\t\texit(1);\n\n\t/* Set static 'home_directory' var - used for get_cart_type() function */\n\tupdate_home_dir(my_id);\n\n\t/* Configure default inquiry data */\n\tmemset(&lu->inquiry, 0, MAX_INQUIRY_SZ);\n\tlu->inquiry[0] = TYPE_MEDIUM_CHANGER; /* SMC device */\n\tlu->inquiry[1] = 0x80;\t\t\t\t  /* Removable bit set */\n\tlu->inquiry[2] = 0x05;\t\t\t\t  /* SCSI Version (v3) */\n\tlu->inquiry[3] = 0x02;\t\t\t\t  /* Response Data Format */\n\tlu->inquiry[4] = 59;\t\t\t\t  /* Additional Length */\n\tlu->inquiry[6] = 0x01;\t\t\t\t  /* Addr16 */\n\tlu->inquiry[7] = 0x20;\t\t\t\t  /* Wbus16 */\n\n\tput_unaligned_be16(0x0300, &lu->inquiry[58]); /* SPC-3 No ver claimed */\n\tput_unaligned_be16(0x0960, &lu->inquiry[60]); /* iSCSI */\n\tput_unaligned_be16(0x0200, &lu->inquiry[62]); /* SSC */\n\n\tlu->ptype = TYPE_MEDIUM_CHANGER; /* SSC */\n\n\tlu->sense_p = &sense[0]; /* Save pointer to sense buffer */\n\n\tconf = fopen(device_conf, \"r\");\n\tif (!conf) {\n\t\tMHVTL_ERR(\"Can not open config file %s : %s\", device_conf,\n\t\t\t\t  strerror(errno));\n\t\tperror(\"Can not open config file\");\n\t\texit(1);\n\t}\n\ts = zalloc(MALLOC_SZ);\n\tif (!s) {\n\t\tperror(\"Could not allocate memory\");\n\t\texit(1);\n\t}\n\tb = zalloc(MALLOC_SZ);\n\tif (!b) {\n\t\tperror(\"Could not allocate memory\");\n\t\texit(1);\n\t}\n\n\tlu->fifoname  = NULL;\n\tlu->fifo_fd\t  = NULL;\n\tlu->fifo_flag = 0;\n\n\tsmc_slots.movecommand\t = NULL;\n\tsmc_slots.commandtimeout = 20;\n\n\t/* While read in a line */\n\tlinecount = 0; /* Line count */\n\twhile (readline(b, MALLOC_SZ, conf) != NULL) {\n\t\tlinecount++;\n\t\tif (b[0] == '#') /* Ignore comments */\n\t\t\tcontinue;\n\t\tif (strlen(b) == 1) /* Reset drive number of blank line */\n\t\t\tindx = 0xff;\n\t\tif (sscanf(b, \"Library: %d CHANNEL: %d TARGET: %d LUN: %d\",\n\t\t\t\t   &indx, &tmpctl.channel,\n\t\t\t\t   &tmpctl.id, &tmpctl.lun)) {\n\t\t\tMHVTL_DBG(2, \"Found Library %d, looking for %u\",\n\t\t\t\t\t  indx, minor);\n\t\t\tif (indx == minor) {\n\t\t\t\tfound = 1;\n\t\t\t\tmemcpy(ctl, &tmpctl, sizeof(tmpctl));\n\t\t\t}\n\t\t}\n\t\tif (indx == minor) {\n\t\t\tunsigned int c, d, e, f, g, h, j, k;\n\t\t\tint\t\t\t i;\n\n\t\t\tif (sscanf(b, \" Unit serial number: %s\", s)) {\n\t\t\t\tcheckstrlen(s, SCSI_SN_LEN, linecount);\n\t\t\t\tsnprintf(lu->lu_serial_no, SCSI_SN_LEN, \"%-14s\", s);\n\t\t\t}\n\t\t\tif (sscanf(b, \" Product identification: %16c\", s) > 0) {\n\t\t\t\t/* sscanf does not NULL terminate */\n\t\t\t\ti\t = strlen(b) - 25; /* len of ' Product identification: ' */\n\t\t\t\ts[i] = '\\0';\n\t\t\t\tsnprintf(lu->product_id, PRODUCT_ID_LEN + 1, \"%-16s\", s);\n\t\t\t\tsnprintf(&lu->inquiry[16], PRODUCT_ID_LEN + 1, \"%-16s\", s);\n\t\t\t}\n\t\t\tif (sscanf(b, \" Product revision level: %s\", s)) {\n\t\t\t\tcheckstrlen(s, PRODUCT_REV_LEN, linecount);\n\t\t\t\tsnprintf(&lu->inquiry[32], PRODUCT_REV_LEN + 1, \"%-4s\", s);\n\t\t\t}\n\t\t\tif (sscanf(b, \" Vendor identification: %s\", s)) {\n\t\t\t\tcheckstrlen(s, VENDOR_ID_LEN, linecount);\n\t\t\t\tsnprintf(lu->vendor_id, VENDOR_ID_LEN + 1, \"%-8s\", s);\n\t\t\t\tsnprintf(&lu->inquiry[8], VENDOR_ID_LEN + 1, \"%-8s\", s);\n\t\t\t}\n\t\t\tif (sscanf(b, \" fifo: %s\", s))\n\t\t\t\tprocess_fifoname(lu, s, 0);\n\t\t\tif (sscanf(b, \" PERSIST: %s\", s)) {\n\t\t\t\tif (!strncasecmp(s, \"yes\", 3) ||\n\t\t\t\t\t(!strncasecmp(s, \"true\", 4)))\n\t\t\t\t\tlu->persist = TRUE;\n\t\t\t}\n\t\t\tif (sscanf(b, \" movecommand: %s\", s))\n\t\t\t\tsmc_slots.movecommand = strndup(s, MALLOC_SZ);\n\t\t\tif (sscanf(b, \" commandtimeout: %d\", &d))\n\t\t\t\tsmc_slots.commandtimeout = d;\n\t\t\tif (sscanf(b, \" Backoff: %d\", &i)) {\n\t\t\t\tif ((i > 1) && (i < 10000)) {\n\t\t\t\t\tMHVTL_DBG(1, \"Backoff value: %d\", i);\n\t\t\t\t\tbackoff = i;\n\t\t\t\t}\n\t\t\t}\n\t\t\ti = sscanf(b,\n\t\t\t\t\t   \" NAA: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\",\n\t\t\t\t\t   &c, &d, &e, &f, &g, &h, &j, &k);\n\t\t\tif (i == 8) {\n\t\t\t\tfree(lu->naa);\n\t\t\t\tlu->naa = zalloc(48);\n\t\t\t\tif (lu->naa)\n\t\t\t\t\tsprintf((char *)lu->naa,\n\t\t\t\t\t\t\t\"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\",\n\t\t\t\t\t\t\tc, d, e, f, g, h, j, k);\n\t\t\t\tMHVTL_DBG(2, \"Setting NAA: to %s\", lu->naa);\n\t\t\t} else if (i > 0) {\n\t\t\t\tfree(lu->naa);\n\t\t\t\tlu->naa = NULL;\n\t\t\t\t/* Cleanup string (replace 'nl' with null)\n\t\t\t\t * for logging */\n\t\t\t\trmnl(b, '\\0', MALLOC_SZ);\n\t\t\t\tMHVTL_DBG(1, \"NAA: Incorrect params: %s\"\n\t\t\t\t\t\t\t \", Using defaults\",\n\t\t\t\t\t\t  b);\n\t\t\t}\n\t\t}\n\t}\n\tfclose(conf);\n\tfree(b);\n\tfree(s);\n\n\tif (found && !lu->inquiry[32]) {\n\t\tchar *v;\n\n\t\t/* Default rev with mhvtl release info */\n\t\tv = get_version();\n\t\tMHVTL_DBG(1, \"Adding default vers info: %s\", v);\n\t\tsprintf(&lu->inquiry[32], \"%-4s\", v);\n\t\tfree(v);\n\t}\n\n\tINIT_LIST_HEAD(&lu->den_list);\n\tINIT_LIST_HEAD(&lu->log_pg);\n\tINIT_LIST_HEAD(&lu->mode_pg);\n\tINIT_LIST_HEAD(&smc_slots.slot_list);\n\tINIT_LIST_HEAD(&smc_slots.drive_list);\n\tINIT_LIST_HEAD(&smc_slots.media_list);\n\n\tfree(smc_slots.state_msg);\n\n\tsmc_slots.num_drives  = 0;\n\tsmc_slots.num_picker  = 0;\n\tsmc_slots.num_map\t  = 0;\n\tsmc_slots.num_storage = 0;\n\tsmc_slots.bufsize\t  = SMC_BUF_SIZE;\n\tsmc_slots.state_msg\t  = NULL;\n\n\t/* Unit Serial Number */\n\tlu_vpd[PCODE_OFFSET(0x80)] = alloc_vpd(strlen(lu->lu_serial_no));\n\tupdate_vpd_80(lu, lu->lu_serial_no);\n\n\tlu->lu_private\t\t = &smc_slots;\n\tsmc_slots.cap_closed = CAP_CLOSED;\n\treturn found;\n}\n\nstatic void process_cmd(int cdev, uint8_t *buf, struct mhvtl_header *mhvtl_cmd,\n\t\t\t\t\t\tuseconds_t pollInterval) {\n\tstruct mhvtl_ds dbuf;\n\tuint8_t\t\t   *cdb;\n\n\t/* Get the SCSI cdb from vtl driver\n\t * - Returns SCSI command S/No. */\n\n\tcdb = (uint8_t *)&mhvtl_cmd->cdb;\n\n\t/* Interpret the SCSI command & process\n\t-> Returns no. of bytes to send back to kernel\n\t */\n\tdbuf.sz\t\t   = 0;\n\tdbuf.serialNo  = mhvtl_cmd->serialNo;\n\tdbuf.data\t   = buf;\n\tdbuf.sam_stat  = sam_status;\n\tdbuf.sense_buf = &sense;\n\n\tprocessCommand(cdev, cdb, &dbuf, pollInterval);\n\n\t/* Complete SCSI cmd processing */\n\tcompleteSCSICommand(cdev, &dbuf);\n\n\t/* dbuf.sam_stat was zeroed in completeSCSICommand */\n\tsam_status = dbuf.sam_stat;\n}\n\n/*\n * Be nice and free all malloc() on exit\n */\nstatic void cleanup_lu(struct lu_phy_attr *lu) {\n\tint\t\t\t\t  i;\n\tstruct smc_priv\t *lu_priv;\n\tstruct list_head *slot_head;\n\tstruct s_info\t *sp, *sn; /* Slot */\n\tstruct d_info\t *dp, *dn; /* Drive */\n\tstruct m_info\t *mp, *mn; /* Media */\n\n\tlu_priv = lu->lu_private;\n\n\t/* Free all VPD pages */\n\tfor (i = 0x80; i < 0x100; i++) {\n\t\tif (lu->lu_vpd[PCODE_OFFSET(i)]) {\n\t\t\tdealloc_vpd(lu->lu_vpd[PCODE_OFFSET(i)]);\n\t\t\tlu->lu_vpd[PCODE_OFFSET(i)] = NULL;\n\t\t}\n\t}\n\tfree(lu->naa);\n\tlu->naa = NULL;\n\n\tdealloc_all_mode_pages(lu);\n\tdealloc_all_log_pages(lu);\n\n\tslot_head = &lu_priv->slot_list;\n\tlist_for_each_entry_safe(sp, sn, slot_head, siblings) {\n\t\tlist_del(&sp->siblings);\n\t\tfree(sp);\n\t}\n\n\tslot_head = &lu_priv->drive_list;\n\tlist_for_each_entry_safe(dp, dn, slot_head, siblings) {\n\t\tlist_del(&dp->siblings);\n\t\tfree(dp);\n\t}\n\n\tslot_head = &lu_priv->media_list;\n\tlist_for_each_entry_safe(mp, mn, slot_head, siblings) {\n\t\tlist_del(&mp->siblings);\n\t\tfree(mp);\n\t}\n\tfree(lu_priv->state_msg);\n\tlu_priv->state_msg = NULL;\n}\n\nstatic void customise_ibm_lu(struct lu_phy_attr *lu) {\n\tif (!strncasecmp(lu->product_id, \"3573-TL\", 7))\n\t\tinit_ibmts3100(lu);\n\telse if (!strncasecmp(lu->product_id, \"03584\", 5))\n\t\tinit_ibm3584(lu);\n\telse\n\t\tinit_default_smc(lu);\n}\n\nstatic void customise_stk_lu(struct lu_phy_attr *lu) {\n\tif (!strncasecmp(lu->product_id, \"SL500\", 5))\n\t\tinit_stkslxx(lu); /* STK SL series */\n\telse if (!strncasecmp(lu->product_id, \"L20\", 3))\n\t\tinit_stkl20(lu); /* L20/40/80 */\n\telse if (!strncasecmp(lu->product_id, \"L40\", 3))\n\t\tinit_stkl20(lu); /* L20/40/80 */\n\telse if (!strncasecmp(lu->product_id, \"L80\", 3))\n\t\tinit_stkl20(lu); /* L20/40/80 */\n\telse\n\t\tinit_stklxx(lu); /* STK L series */\n}\n\nstatic void customise_hp_lu(struct lu_phy_attr *lu) {\n\tif (!strncasecmp(lu->product_id, \"MSL\", 3))\n\t\tinit_hp_msl_smc(lu);\n\telse\n\t\tinit_hp_eml_smc(lu);\n}\n\nstatic void customise_spectra_lu(struct lu_phy_attr *lu) {\n\tif (!strncasecmp(lu->product_id, \"PYTHON\", 6))\n\t\tinit_spectra_logic_smc(lu);\n\telse if (!strncasecmp(lu->product_id, \"GATOR\", 5))\n\t\tinit_spectra_gator_smc(lu);\n\telse if (!strncasecmp(lu->product_id, \"215\", 3))\n\t\tinit_spectra_215_smc(lu);\n\telse\n\t\tinit_spectra_logic_smc(lu);\n}\n\nstatic void customise_lu(struct lu_phy_attr *lu) {\n\tif (!strncasecmp(lu->vendor_id, \"stk\", 3))\n\t\tcustomise_stk_lu(lu);\n\telse if (!strncasecmp(lu->vendor_id, \"IBM\", 3))\n\t\tcustomise_ibm_lu(lu);\n\telse if (!strncasecmp(lu->vendor_id, \"HP\", 2))\n\t\tcustomise_hp_lu(lu);\n\telse if (!strncasecmp(lu->product_id, \"OVERLAND\", 8))\n\t\tinit_overland_smc(lu);\n\telse if (!strncasecmp(lu->product_id, \"ADIC\", 4))\n\t\tinit_scalar_smc(lu);\n\telse if (!strncasecmp(lu->product_id, \"QUANTUM\", 7))\n\t\tinit_scalar_smc(lu);\n\telse if (!strncasecmp(lu->vendor_id, \"SPECTRA \", 7))\n\t\tcustomise_spectra_lu(lu);\n\telse\n\t\tinit_default_smc(lu);\n}\n\nvoid rereadconfig(int sig) {\n\tstruct mhvtl_ctl ctl;\n\tint\t\t\t\t buffer_size;\n\n\tlunit.online = 0; /* Report library offline until finished */\n\n\tMHVTL_DBG(1, \"Caught signal (%d): Re-initialising library %d\",\n\t\t\t  sig, (int)my_id);\n\n\tcleanup_lu(&lunit);\n\n\tif (lunit.fifo_fd) {\n\t\tfclose(lunit.fifo_fd);\n\t\tfree(lunit.fifoname);\n\t\tlunit.fifo_fd = NULL;\n\t}\n\n\tif (!init_lu(&lunit, my_id, &ctl)) {\n\t\tfprintf(stderr, \"error: Cannot find entry for '%ld' in config file\\n\",\n\t\t\t\tmy_id);\n\t\texit(1);\n\t}\n\n\tif (lunit.fifoname)\n\t\topen_fifo(&lunit.fifo_fd, lunit.fifoname);\n\n\tcustomise_lu(&lunit);\n\n\tupdate_drive_details(&lunit);\n\n\t/* malloc a big enough buffer to fit worst case read element status */\n\tbuffer_size = (smc_slots.num_drives +\n\t\t\t\t   smc_slots.num_picker +\n\t\t\t\t   smc_slots.num_map +\n\t\t\t\t   smc_slots.num_storage) *\n\t\t\t\t  80;\n\treset_device(); /* Force a POWER-ON/RESET sense code */\n\tif (buffer_size > smc_slots.bufsize) {\n\t\tMHVTL_LOG(\"Too many slots configured\"\n\t\t\t\t  \" - possible buffer overflow\");\n\t\tMHVTL_LOG(\"Please shutdown this daemon and restart so\"\n\t\t\t\t  \" correct buffer allocation can be performed\");\n\t\t/* Leave library offline */\n\t} else {\n\t\tlunit.online = 1; /* Should be good to go */\n\t}\n}\n\nvoid smc_personality_module_register(struct smc_personality_template *pm) {\n\tMHVTL_LOG(\"%s\", pm->name);\n\tsmc_slots.pm = pm;\n}\n\nstatic void caught_signal(int signo) {\n\tMHVTL_DBG(1, \" %d\", signo);\n\tprintf(\"Please use 'vtlcmd <index> exit' to shutdown nicely\\n\");\n\tMHVTL_LOG(\"Please use 'vtlcmd <index> exit' to shutdown nicely,\"\n\t\t\t  \" Received signal: %d\",\n\t\t\t  signo);\n}\n\n/*\n * main()\n *\n * e'nuf sed\n */\nint main(int argc, char *argv[]) {\n\tint\t\t cdev;\n\tint\t\t ret;\n\tlong\t pollInterval = 0L;\n\tuint8_t *buf;\n\tint\t\t buffer_size;\n\tint\t\t fifo_retval;\n\tint\t\t opt;\n\tint\t\t foreground\t  = 0;\n\tint\t\t time_to_exit = 0;\n\n\tint last_state = MHVTL_STATE_UNKNOWN;\n\n\tstruct list_head *slot_head = &smc_slots.slot_list;\n\tstruct s_info\t *sp;\n\tstruct d_info\t *dp;\n\n\tstruct mhvtl_header mhvtl_cmd;\n\tstruct mhvtl_ctl\tctl;\n\tchar\t\t\t\ts[100];\n\n\tpid_t\t\t\t pid, sid, child_cleanup;\n\tstruct sigaction new_action, old_action;\n\n\tchar *progname = argv[0];\n\tchar *name\t   = \"mhvtl\";\n\tchar *fifoname = NULL;\n\n\tmemset(&mhvtl_cmd, 0, sizeof(struct mhvtl_header));\n\tmemset(&ctl, 0, sizeof(struct mhvtl_ctl));\n\n\t/* Message Q */\n\tint\t\t\t   mlen, r_qid;\n\tstruct q_entry r_entry;\n\n\twhile ((opt = getopt(argc, argv, \"dv::q:f::F\")) != -1) {\n\t\tswitch (opt) {\n\t\tcase 'd':\n\t\t\tdebug++;\n\t\t\tverbose\t   = 9; /* If debug, make verbose... */\n\t\t\tforeground = 1;\n\t\t\tbreak;\n\t\tcase 'v':\n\t\t\tif (optarg)\n\t\t\t\tverbose = atoi(optarg);\n\t\t\telse\n\t\t\t\tverbose++;\n\t\t\t/* limit verbosity to single digit */\n\t\t\tif (verbose > 9)\n\t\t\t\tverbose = 9;\n\t\t\tbreak;\n\t\tcase 'q':\n\t\t\tmy_id = atoi(optarg);\n\t\t\tif ((my_id < 0) || (my_id > MAXPRIOR)) {\n\t\t\t\tfprintf(stderr, \"error: queue ID out of range [1..%u]\\n\",\n\t\t\t\t\t\tMAXPRIOR);\n\t\t\t\tusage(progname);\n\t\t\t\texit(1);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'f':\n\t\t\tif (optarg)\n\t\t\t\tfifoname = strdup(optarg);\n\t\t\tbreak;\n\t\tcase 'F':\n\t\t\tforeground = 1;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tusage(progname);\n\t\t\texit(1);\n\t\t}\n\t}\n\n\tif (my_id < 0) {\n\t\tfprintf(stderr, \"error: must supply queue ID\\n\");\n\t\tusage(progname);\n\t\texit(1);\n\t}\n\n\topenlog(progname, LOG_PID, LOG_DAEMON | LOG_WARNING);\n\n\t/* Clear Sense arr */\n\tmemset(sense, 0, sizeof(sense));\n\treset_device(); /* power-on reset */\n\n\tif (!init_lu(&lunit, my_id, &ctl)) {\n\t\tfprintf(stderr, \"error: Can not find entry for '%ld' in config file\\n\",\n\t\t\t\tmy_id);\n\t\texit(1);\n\t}\n\n\t/* Personality module init call */\n\tcustomise_lu(&lunit);\n\n\tupdate_drive_details(&lunit);\n\n\tlunit.online = 1; /* Mark unit online */\n\n\tif (chrdev_create(my_id)) {\n\t\tMHVTL_DBG(1, \"Error creating device node mhvtl%d\", (int)my_id);\n\t\texit(1);\n\t}\n\n\tnew_action.sa_handler = caught_signal;\n\tnew_action.sa_flags\t  = 0;\n\tsigemptyset(&new_action.sa_mask);\n\tsigaction(SIGALRM, &new_action, &old_action);\n\tsigaction(SIGINT, &new_action, &old_action);\n\tsigaction(SIGPIPE, &new_action, &old_action);\n\tsigaction(SIGTERM, &new_action, &old_action);\n\tsigaction(SIGUSR1, &new_action, &old_action);\n\tsigaction(SIGUSR2, &new_action, &old_action);\n\n\tnew_action.sa_handler = rereadconfig;\n\tsigaction(SIGHUP, &new_action, &old_action);\n\n\t/* Initialise message queue as necessary */\n\tr_qid = init_queue();\n\tif (r_qid == -1) {\n\t\tfprintf(stderr, \"error: Could not initialise message queue\\n\");\n\t\texit(1);\n\t}\n\n\tif (check_for_running_daemons(my_id)) {\n\t\tMHVTL_LOG(\"%s: version %s %s %s, found another running daemon... exiting\", progname, MHVTL_VERSION, MHVTL_GITHASH, MHVTL_GITDATE);\n\t\texit(2);\n\t}\n\n\t/* Clear out message Q by reading anything there. */\n\tmlen = msgrcv(r_qid, &r_entry, MAXOBN, my_id, IPC_NOWAIT);\n\twhile (mlen > 0) {\n\t\tMHVTL_DBG(2, \"Found \\\"%s\\\" still in message Q\", r_entry.msg.text);\n\t\tmlen = msgrcv(r_qid, &r_entry, MAXOBN, my_id, IPC_NOWAIT);\n\t}\n\n\tcdev = chrdev_open(name, my_id);\n\tif (cdev == -1) {\n\t\tMHVTL_ERR(\"Could not open /dev/%s%ld: %s\",\n\t\t\t\t  name, my_id, strerror(errno));\n\t\tfflush(NULL);\n\t\texit(1);\n\t}\n\n\t/* malloc a big enough buffer to fit worst case read element status */\n\tbuffer_size = (smc_slots.num_drives +\n\t\t\t\t   smc_slots.num_picker +\n\t\t\t\t   smc_slots.num_map +\n\t\t\t\t   smc_slots.num_storage) *\n\t\t\t\t  80;\n\tbuffer_size\t\t  = max(SMC_BUF_SIZE, buffer_size);\n\tsmc_slots.bufsize = buffer_size;\n\tMHVTL_DBG(1, \"Setting buffer size to %d\", buffer_size);\n\tbuf = (uint8_t *)zalloc(buffer_size);\n\tif (NULL == buf) {\n\t\tperror(\"Problems allocating memory\");\n\t\texit(1);\n\t}\n\n\t/* Send a message to each tape drive so they know the\n\t * controlling library's message Q id\n\t */\n\tlist_for_each_entry(sp, slot_head, siblings) {\n\t\tif (sp->element_type == DATA_TRANSFER) {\n\t\t\tdp = sp->drive;\n\t\t\tMHVTL_DBG(1, \"Registering driveId: %ld\", dp->drv_id);\n\t\t\tsend_msg(\"Register\", dp->drv_id);\n\n\t\t\tif (debug) {\n\n\t\t\t\tMHVTL_DBG(3, \"\\nDrive %d\", sp->slot_location);\n\n\t\t\t\tstrncpy(s, dp->inq_vendor_id, 8 + 2);\n\t\t\t\trmnl(s, ' ', 8);\n\t\t\t\ts[8] = '\\0';\n\t\t\t\tMHVTL_DBG(3, \"Vendor ID     : \\\"%s\\\"\", s);\n\n\t\t\t\tstrncpy(s, dp->inq_product_id, 16 + 2);\n\t\t\t\trmnl(s, ' ', 16);\n\t\t\t\ts[16] = '\\0';\n\t\t\t\tMHVTL_DBG(3, \"Product ID    : \\\"%s\\\"\", s);\n\n\t\t\t\tstrncpy(s, dp->inq_product_rev, 4 + 2);\n\t\t\t\trmnl(s, ' ', 4);\n\t\t\t\ts[4] = '\\0';\n\t\t\t\tMHVTL_DBG(3, \"Revision Level: \\\"%s\\\"\", s);\n\n\t\t\t\tstrncpy(s, dp->inq_product_sno, 10 + 2);\n\t\t\t\trmnl(s, ' ', 10);\n\t\t\t\ts[10] = '\\0';\n\t\t\t\tMHVTL_DBG(3, \"Product S/No  : \\\"%s\\\"\", s);\n\n\t\t\t\tMHVTL_DBG(3, \"Drive location: %d\",\n\t\t\t\t\t\t  dp->slot->slot_location);\n\t\t\t\tMHVTL_DBG(3, \"Drive occupied: %s\",\n\t\t\t\t\t\t  (dp->slot->status & STATUS_Full) ? \"No\" : \"Yes\");\n\t\t\t}\n\t\t}\n\t}\n\n\t/* If debug or 'F' specified don't fork/run in background */\n\tif (!foreground) {\n\t\tswitch (pid = fork()) {\n\t\tcase 0: /* Child */\n\t\t\tbreak;\n\t\tcase -1:\n\t\t\tfprintf(stderr, \"error: Failed to fork daemon\\n\");\n\t\t\texit(-1);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tprintf(\"%s process PID is %d\\n\", progname, (int)pid);\n\t\t\texit(0);\n\t\t}\n\n\t\tumask(0); /* Change the file mode mask */\n\n\t\tsid = setsid();\n\t\tif (sid < 0)\n\t\t\texit(-1);\n\n\t\tif ((chdir(MHVTL_HOME_PATH)) < 0) {\n\t\t\tperror(\"Unable to change directory to \" MHVTL_HOME_PATH);\n\t\t\texit(-1);\n\t\t}\n\n\t\tclose(STDIN_FILENO);\n\t\tclose(STDERR_FILENO);\n\t}\n\n\tMHVTL_LOG(\"[%ld] Started %s: version %s %s %s verbose log lvl: %d, lu [%d:%d:%d]\",\n\t\t\t  (long)getpid(), progname, MHVTL_VERSION, MHVTL_GITHASH, MHVTL_GITDATE, verbose,\n\t\t\t  ctl.channel, ctl.id, ctl.lun);\n\n\toom_adjust();\n\n\t/* If fifoname passed as switch */\n\tif (fifoname)\n\t\tprocess_fifoname(&lunit, fifoname, 1);\n\t/* fifoname can be defined in device.conf */\n\tif (lunit.fifoname)\n\t\topen_fifo(&lunit.fifo_fd, lunit.fifoname);\n\n\tfifo_retval = inc_fifo_count();\n\tif (fifo_retval == -ENOMEM) {\n\t\tMHVTL_ERR(\"shared memory setup failed - exiting...\");\n\t\tgoto exit;\n\t} else if (fifo_retval < 0) {\n\t\tMHVTL_ERR(\"Failed to set fifo count()...\");\n\t}\n\n\tchild_cleanup = add_lu(my_id, &ctl);\n\tif (!child_cleanup) {\n\t\tfprintf(stderr, \"error: Could not create logical unit\\n\");\n\t\texit(1);\n\t}\n\n\tfor (;;) {\n\t\t/* Check for any messages */\n\t\tmlen = msgrcv(r_qid, &r_entry, MAXOBN, my_id, IPC_NOWAIT);\n\t\tif (mlen > 0) {\n\t\t\tif (processMessageQ(&r_entry.msg))\n\t\t\t\ttime_to_exit = 1;\n\t\t} else if (mlen < 0) {\n\t\t\tr_qid = init_queue();\n\t\t\tif (r_qid == -1)\n\t\t\t\tMHVTL_ERR(\"Can not open message queue: %s\",\n\t\t\t\t\t\t  strerror(errno));\n\t\t}\n\n\t\tret = ioctl(cdev, VTL_POLL_AND_GET_HEADER, &mhvtl_cmd);\n\t\tif (ret < 0) {\n\t\t\tMHVTL_LOG(\"ret: %d : %s\", ret, strerror(errno));\n\t\t} else {\n\t\t\tif (child_cleanup) {\n\t\t\t\tif (waitpid(child_cleanup, NULL, WNOHANG)) {\n\t\t\t\t\tMHVTL_DBG(1,\n\t\t\t\t\t\t\t  \"[%ld] Cleaning up after add_lu \"\n\t\t\t\t\t\t\t  \"child pid: %d\",\n\t\t\t\t\t\t\t  (long)getpid(), child_cleanup);\n\t\t\t\t\tchild_cleanup = 0;\n\t\t\t\t} else {\n\t\t\t\t\tMHVTL_DBG(2, \"[%ld] Child cleanup of %ld still outstanding\", (long)getpid(), (long)child_cleanup);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (debug)\n\t\t\t\tfflush(NULL); /* So I can pipe debug o/p thru tee */\n\t\t\tswitch (ret) {\n\t\t\tcase VTL_QUEUE_CMD:\n\t\t\t\tif (smc_slots.bufsize != buffer_size) {\n\t\t\t\t\tbuffer_size = smc_slots.bufsize;\n\t\t\t\t\tbuf\t\t\t= realloc(buf, buffer_size);\n\t\t\t\t\tif (!buf) {\n\t\t\t\t\t\tperror(\"Problems allocating memory\");\n\t\t\t\t\t\texit(1);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tprocess_cmd(cdev, buf, &mhvtl_cmd, pollInterval);\n\t\t\t\tpollInterval = MIN_SLEEP_TIME;\n\t\t\t\tbreak;\n\n\t\t\tcase VTL_IDLE:\n\t\t\t\tusleep(pollInterval);\n\n\t\t\t\tif (pollInterval < 1000000)\n\t\t\t\t\tpollInterval += backoff;\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tMHVTL_LOG(\"ioctl(0x%x) returned %d\",\n\t\t\t\t\t\t  VTL_POLL_AND_GET_HEADER, ret);\n\t\t\t\tsleep(1);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (current_state != last_state) {\n\t\t\t\tstatus_change(lunit.fifo_fd,\n\t\t\t\t\t\t\t  current_state,\n\t\t\t\t\t\t\t  my_id,\n\t\t\t\t\t\t\t  &smc_slots.state_msg);\n\t\t\t\tlast_state = current_state;\n\t\t\t}\n\t\t\tif (pollInterval > 0xf000) /* enough time to ensure no outstanding op in flight */\n\t\t\t\tif (time_to_exit)\n\t\t\t\t\tgoto exit;\n\t\t\tif (pollInterval > 0x18000)\n\t\t\t\tif (current_state != MHVTL_STATE_OFFLINE)\n\t\t\t\t\tcurrent_state = MHVTL_STATE_IDLE;\n\t\t}\n\t}\nexit:\n\tioctl(cdev, VTL_REMOVE_LU, &ctl);\n\tif (lunit.persist)\n\t\tsave_config(&lunit);\n\tcleanup_lu(&lunit);\n\tclose(cdev);\n\tfree(buf);\n\tdec_fifo_count();\n\tif (lunit.fifo_fd) {\n\t\tfclose(lunit.fifo_fd);\n\t\tunlink(lunit.fifoname);\n\t\tfree(lunit.fifoname);\n\t}\n\tfree_lock(my_id);\n\texit(0);\n}\n"
  },
  {
    "path": "usr/cmd/vtltape.c",
    "content": "/*\n * This daemon is the SCSI SSC target (Sequential device - tape drive)\n * portion of the vtl package.\n *\n * The vtl package consists of:\n *   a kernel module (vlt.ko) - Currently on 2.6.x Linux kernel support.\n *   SCSI target daemons for both SMC and SSC devices.\n *\n * Copyright (C) 2005 - 2025 Mark Harvey       markh794@gmail.com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n\n * v0.1 -> Proof (proof of concept) that this may actually work (just)\n * v0.2 -> Get queueCommand() callback working -\n *         (Note to self: Sleeping in kernel is bad!)\n * v0.3 -> Message queues + make into daemon\n *\t   changed lseek to lseek64\n * v0.4 -> First copy given to anybody,\n * v0.10 -> First start of a Solaris x86 port.. Still underway.\n * v0.11 -> First start of a Linux 2.4 kernel port.. Still underway.\n *\t    However I'm scrapping this kfifo stuff and passing a pointer\n *\t    and using copy{to|from}_user routines instead.\n * v0.12 -> Forked into 'stable' (0.12) and 'devel' (0.13).\n *          My current thinking : This is a dead end anyway.\n *          An iSCSI target done in user-space is now my perferred solution.\n *          This means I don't have to do any kernel level drivers\n *          and leaverage the hosts native iSCSI initiator.\n * 0.14 13 Feb 2008\n *\tSince ability to define device serial number, increased ver from\n *\t0.12 to 0.14\n *\n * 0.16 Jun 2009\n *\tMoved SCSI Inquiry into user-space.\n *\tSCSI lu are created/destroyed as the daemon is started/shutdown\n */\n\n#define _FILE_OFFSET_BITS 64\n#define _XOPEN_SOURCE\t  500\n\n#define __STDC_FORMAT_MACROS /* for PRId64 */\n\n#include <unistd.h>\n#include <sys/ipc.h>\n#include <string.h>\n#include <sys/msg.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <errno.h>\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <sys/wait.h>\n#include <sys/ioctl.h>\n#include <strings.h>\n#include <syslog.h>\n#include <inttypes.h>\n#include <signal.h>\n#include <ctype.h>\n#include \"mhvtl_list.h\"\n#include \"be_byteshift.h\"\n#include \"vtl_common.h\"\n#include \"mhvtl_scsi.h\"\n#include \"q.h\"\n#include \"logging.h\"\n#include \"vtllib.h\"\n#include \"vtlcart.h\"\n#include \"spc.h\"\n#include \"ssc.h\"\n#include \"mhvtl_log.h\"\n#include \"mode.h\"\n\nchar mhvtl_driver_name[] = \"vtltape\";\n\n/* Variables for simple, logical only SCSI Encryption system */\n\nstruct encryption app_encryption_state; /* Stores the encryption info the application sent us */\n\n#define UKAD_LENGTH app_encryption_state.ukad_length\n#define AKAD_LENGTH app_encryption_state.akad_length\n#define KEY_LENGTH\tapp_encryption_state.key_length\n#define UKAD\t\tapp_encryption_state.ukad\n#define AKAD\t\tapp_encryption_state.akad\n#define KEY\t\t\tapp_encryption_state.key\n\n#include <zlib.h>\n#include \"minilzo.h\"\n\nstatic uint8_t last_cmd;\n\n/* Suppress Incorrect Length Indicator */\n#define SILI 0x2\n/* Fixed block format */\n#define FIXED 0x1\n\n#ifndef Solaris\n/* I'm sure there must be a header where lseek64() is defined */\nloff_t lseek64(int, loff_t, int);\n#endif\n\n#define SEND_MSG_AND_LOG(s, id)                                                        \\\n\t{                                                                                  \\\n\t\tsend_msg(s, id);                                                               \\\n\t\tMHVTL_DBG(1, \"%ld: Replying to snd_id %\" PRIu64 \" with \\\"%s\\\"\", my_id, id, s); \\\n\t}\n\n/* Backoff algrithm..\n * Each empty poll of kernel module, add backoff to sleep time\n * and call usleep() before polling again.\n */\nstatic long backoff;\n\nstatic useconds_t cumul_pollInterval;\n\nstatic int library_id = 0;\n\n#define MEDIA_WRITABLE 0\n#define MEDIA_READONLY 1\n\nstatic struct tape_drives_table {\n\tchar *name;\n\tvoid (*init)(struct lu_phy_attr *);\n} tape_drives[] = {\n\t{\"ULT3580-TD1     \", init_ult3580_td1},\n\t{\"ULT3580-TD2     \", init_ult3580_td2},\n\t{\"ULT3580-TD3     \", init_ult3580_td3},\n\t{\"ULT3580-TD4     \", init_ult3580_td4},\n\t{\"ULT3580-TD5     \", init_ult3580_td5},\n\t{\"ULT3580-TD6     \", init_ult3580_td6},\n\t{\"ULT3580-TD7     \", init_ult3580_td7},\n\t{\"ULT3580-HH7     \", init_ult3580_td7},\n\t{\"ULT3580-TD8     \", init_ult3580_td8},\n\t{\"ULT3580-HH8     \", init_ult3580_td8},\n\t{\"ULT3580-TD9     \", init_ult3580_td9},\n\t{\"ULT3580-HH9     \", init_ult3580_td9},\n\t{\"ULTRIUM-TD1     \", init_ult3580_td1},\n\t{\"ULTRIUM-TD2     \", init_ult3580_td2},\n\t{\"ULTRIUM-HH2     \", init_ult3580_td2},\n\t{\"ULTRIUM-TD3     \", init_ult3580_td3},\n\t{\"ULTRIUM-HH3     \", init_ult3580_td3},\n\t{\"ULTRIUM-TD4     \", init_ult3580_td4},\n\t{\"ULTRIUM-HH4     \", init_ult3580_td4},\n\t{\"ULTRIUM-TD5     \", init_ult3580_td5},\n\t{\"ULTRIUM-HH5     \", init_ult3580_td5},\n\t{\"ULTRIUM-TD6     \", init_ult3580_td6},\n\t{\"ULTRIUM-HH6     \", init_ult3580_td6},\n\t{\"ULTRIUM-TD7     \", init_ult3580_td7},\n\t{\"ULTRIUM-HH7     \", init_ult3580_td7},\n\t{\"ULTRIUM-TD8     \", init_ult3580_td8},\n\t{\"ULTRIUM-HH8     \", init_ult3580_td8},\n\t{\"ULTRIUM-TD9     \", init_ult3580_td9},\n\t{\"ULTRIUM-HH9     \", init_ult3580_td9},\n\t{\"Ultrium 1-SCSI  \", init_hp_ult_1},\n\t{\"Ultrium 2-SCSI  \", init_hp_ult_2},\n\t{\"Ultrium 3-SCSI  \", init_hp_ult_3},\n\t{\"Ultrium 4-SCSI  \", init_hp_ult_4},\n\t{\"Ultrium 5-SCSI  \", init_hp_ult_5},\n\t{\"Ultrium 6-SCSI  \", init_hp_ult_6},\n\t{\"Ultrium 7-SCSI  \", init_hp_ult_7},\n\t{\"Ultrium 8-SCSI  \", init_hp_ult_8},\n\t{\"SDX-300C        \", init_ait1_ssc},\n\t{\"SDX-500C        \", init_ait2_ssc},\n\t{\"SDX-500V        \", init_ait2_ssc},\n\t{\"SDX-700C        \", init_ait3_ssc},\n\t{\"SDX-700V        \", init_ait3_ssc},\n\t{\"SDX-900V        \", init_ait4_ssc},\n\t{\"03592J1A        \", init_3592_j1a},\n\t{\"03592E05        \", init_3592_E05},\n\t{\"03592E06        \", init_3592_E06},\n\t{\"03592E07        \", init_3592_E07},\n\t{\"T10000C         \", init_t10kC_ssc},\n\t{\"T10000B         \", init_t10kB_ssc},\n\t{\"T10000A         \", init_t10kA_ssc},\n\t{\"T9840D          \", init_9840D_ssc},\n\t{\"T9840C          \", init_9840C_ssc},\n\t{\"T9840B          \", init_9840B_ssc},\n\t{\"T9840A          \", init_9840A_ssc},\n\t{\"T9940B          \", init_9940B_ssc},\n\t{\"T9940A          \", init_9940A_ssc},\n\t{\"DLT7000         \", init_dlt7000_ssc},\n\t{\"DLT8000         \", init_dlt8000_ssc},\n\t{\"SDLT 320        \", init_sdlt320_ssc},\n\t{\"SDLT600         \", init_sdlt600_ssc},\n\t{NULL, NULL},\n};\n\nstatic void (*drive_init)(struct lu_phy_attr *) = init_default_ssc;\n\nstatic void usage(char *progname) {\n\tprintf(\"Usage: %s [OPTIONS] -q <Q-number>\\n\", progname);\n\tprintf(\"Where:\\n\");\n\tprintf(\"       '-q <Q-number>' is the queue priority number\\n\");\n\tprintf(\"and where OPTIONS are from:\\n\");\n\tprintf(\"       '-d'       enable debug mode -> Don't run as daemon\\n\");\n\tprintf(\"       'v[N]'     enable verbose syslog messages level N [1]\\n\");\n\tprintf(\"       '-f FIFO'  use FIFO to report real-time data\\n\");\n\tprintf(\"       '-F'       run in the foreground\\n\");\n}\n\nstatic int lookup_media_int(struct name_to_media_info *media_info, char *s) {\n\tunsigned int i;\n\n\tMHVTL_DBG(2, \"looking for media type %s\", s);\n\n\tfor (i = 0; media_info[i].media_density != 0; i++)\n\t\tif (!strcmp(media_info[i].name, s))\n\t\t\treturn media_info[i].media_type;\n\n\treturn Media_undefined;\n}\n\n#ifdef MHVTL_DEBUG\nstatic const char *lookup_density_name(\n\tstruct name_to_media_info *media_info,\n\tint\t\t\t\t\t\t   den) {\n\tunsigned int i;\n\n\tMHVTL_DBG(2, \"looking for density type 0x%02x\", den);\n\n\tfor (i = 0; media_info[i].media_density != 0; i++)\n\t\tif (media_info[i].media_density == den)\n\t\t\treturn media_info[i].name;\n\n\treturn \"(UNKNOWN density)\";\n}\n#endif\n\nstatic const char *lookup_media_type(struct name_to_media_info *media_info,\n\t\t\t\t\t\t\t\t\t int\t\t\t\t\t\tmed) {\n\tunsigned int i;\n\n\tMHVTL_DBG(2, \"looking for media type 0x%02x\", med);\n\n\tfor (i = 0; media_info[i].media_density != 0; i++)\n\t\tif (media_info[i].media_type == med)\n\t\t\treturn media_info[i].name;\n\n\treturn \"(UNKNOWN media type)\";\n}\n\nint lookup_mode_media_type(struct name_to_media_info *media_info, int med) {\n\tunsigned int i;\n\n\tMHVTL_DBG(2, \"looking for mode media type for 0x%02x\", med);\n\n\tfor (i = 0; media_info[i].media_density != 0; i++) {\n\t\tMHVTL_DBG(3, \"%s : 0x%02x mode media type 0x%02x\",\n\t\t\t\t  media_info[i].name,\n\t\t\t\t  media_info[i].media_type,\n\t\t\t\t  media_info[i].mode_media_type);\n\t\tif (media_info[i].media_type == med)\n\t\t\treturn media_info[i].mode_media_type;\n\t}\n\n\treturn media_type_unknown;\n}\n\nstatic void finish_mount(int sig) {\n\tMHVTL_DBG(3, \"+++ Trace - Received signal %d +++\", sig);\n\tif (get_tape_load_status() == TAPE_LOADING)\n\t\tset_tape_load_status(TAPE_LOADED);\n}\n\nstatic void set_mount_timer(int t) {\n\tMHVTL_DBG(3, \"+++ Trace +++ Setting alarm for %d\", t);\n\tsignal(SIGALRM, finish_mount);\n\talarm(t);\n}\n\nvoid delay_opcode(int what, int value) {\n\tMHVTL_DBG(3, \"+++ Trace --> what: %d, value: %d\", what, value);\n\n\tswitch (what) {\n\tcase DELAY_LOAD:\n\t\tif (value)\n\t\t\tset_mount_timer(value);\n\t\telse\n\t\t\tfinish_mount(1);\n\t\tbreak;\n\tdefault:\n\t\tsleep(value);\n\t\tbreak;\n\t}\n\tMHVTL_DBG(2, \"Completed %d, sleep(%d)\", what, value);\n}\n\n/***********************************************************************/\n\n/*\n * Report supported densities\n */\n\n#define REPORT_DENSITY_LEN 52\nint resp_report_density(struct priv_lu_ssc *lu_priv, uint8_t media,\n\t\t\t\t\t\tstruct mhvtl_ds *dbuf_p) {\n\tuint8_t\t\t\t\t\t\t  *buf = (uint8_t *)dbuf_p->data;\n\tstruct list_head\t\t\t  *l_head;\n\tstruct density_info\t\t\t  *di;\n\tstruct supported_density_list *den;\n\tint\t\t\t\t\t\t\t   count;\n\tuint32_t\t\t\t\t\t   a;\n\tuint8_t\t\t\t\t\t\t  *ds; /* Density Support Data Block Descriptor */\n\n\tl_head = &lu_priv->pm->lu->den_list;\n\n\t/* Zero out buf */\n\tds\t  = &buf[4];\n\tcount = 0;\n\n\tbuf[2] = 0; /* Reserved */\n\tbuf[3] = 0; /* Reserved */\n\n\t/* Assigning Oranization (8 chars long) */\n\tif (media) { /* Report supported density by this media */\n\t\tcount = 1;\n\n\t\tds[0] = mam.MediumDensityCode;\n\t\tds[1] = mam.MediumDensityCode;\n\t\tds[2] = (OK_to_write) ? 0xa0 : 0x20; /* Set write OK flg */\n\n\t\ta = get_unaligned_be32(&mam.media_info.bits_per_mm);\n\t\tput_unaligned_be24(a, &ds[5]);\n\n\t\ta = get_unaligned_be32(&mam.MediumWidth);\n\t\tput_unaligned_be16(a, &ds[8]);\n\n\t\ta = get_unaligned_be16(&mam.media_info.tracks);\n\t\tput_unaligned_be16(a, &ds[10]);\n\n\t\ta = get_unaligned_be32(&mam.max_capacity);\n\t\tput_unaligned_be32(a, &ds[12]);\n\n\t\tsnprintf((char *)&ds[16], 9, \"%-8s\",\n\t\t\t\t mam.AssigningOrganization_1);\n\t\tsnprintf((char *)&ds[24], 9, \"%-8s\",\n\t\t\t\t mam.media_info.density_name);\n\t\tsnprintf((char *)&ds[32], 21, \"%-20.20s\",\n\t\t\t\t mam.media_info.description);\n\t\t/* Fudge.. Now 'fix' up the spaces. */\n\t\tfor (a = 16; a < REPORT_DENSITY_LEN; a++)\n\t\t\tif (!ds[a])\n\t\t\t\tds[a] = 0x20; /* replace 0 with ' ' */\n\t} else {\t\t\t\t  /* Report supported density by this drive */\n\t\tlist_for_each_entry(den, l_head, siblings) {\n\t\t\tdi = den->density_info;\n\t\t\tcount++;\n\n\t\t\tMHVTL_DBG(2, \"%s -> %s\", di->description,\n\t\t\t\t\t  (den->rw) ? \"RW\" : \"RO\");\n\n\t\t\tds[0] = di->density;\n\t\t\tds[1] = di->density;\n\t\t\tds[2] = (den->rw) ? 0xa0 : 0x20; /* Set write OK flg */\n\t\t\tput_unaligned_be16(REPORT_DENSITY_LEN, &ds[3]);\n\t\t\tput_unaligned_be24(di->bits_per_mm, &ds[5]);\n\t\t\tput_unaligned_be16(di->media_width, &ds[8]);\n\t\t\tput_unaligned_be16(di->tracks, &ds[10]);\n\t\t\tput_unaligned_be32(di->capacity, &ds[12]);\n\t\t\tsnprintf((char *)&ds[16], 9, \"%-8s\", di->assigning_org);\n\t\t\tsnprintf((char *)&ds[24], 9, \"%-8s\", di->density_name);\n\t\t\tsnprintf((char *)&ds[32], 21, \"%-20s\",\n\t\t\t\t\t di->description);\n\t\t\t/* Fudge.. Now 'fix' up the spaces. */\n\t\t\tfor (a = 16; a < REPORT_DENSITY_LEN; a++)\n\t\t\t\tif (!ds[a])\n\t\t\t\t\tds[a] = 0x20; /* replace 0 with ' ' */\n\t\t\tds += REPORT_DENSITY_LEN;\n\t\t}\n\t}\n\tput_unaligned_be16((REPORT_DENSITY_LEN * count) + 2, &buf[0]);\n\treturn REPORT_DENSITY_LEN * count + 4;\n}\n\n/*\n * Read Attribute\n *\n * Fill in 'buf' with data and return number of bytes\n */\nint resp_read_attribute(struct scsi_cmd *cmd) {\n\tuint8_t\t\t*cdb\t  = cmd->scb;\n\tuint8_t\t\t*buf\t  = cmd->dbuf_p->data;\n\tuint8_t\t\t*sam_stat = &cmd->dbuf_p->sam_stat;\n\tuint16_t\t attrib;\n\tuint32_t\t alloc_len;\n\tuint32_t\t ret_val\t= 4; /* Available data length */\n\tunsigned int byte_index = 4;\n\tint\t\t\t indx, found_attribute;\n\tstruct s_sd\t sd;\n\n\tattrib\t  = get_unaligned_be16(&cdb[8]);\n\talloc_len = get_unaligned_be32(&cdb[10]);\n\tMHVTL_DBG(2, \"Attribute : 0x%04x, allocation len: %d\",\n\t\t\t  attrib, alloc_len);\n\n\tmemset_ssc_buf(cmd, alloc_len); /* Clear memory */\n\n\tif (cdb[1] == 0) {\n\t\t/* Attribute Values */\n\t\tfor (indx = found_attribute = 0; mam.attributes[indx].length; indx++) {\n\t\t\tif (attrib == mam.attributes[indx].attribute_id)\n\t\t\t\tfound_attribute = 1;\n\n\t\t\tif (found_attribute) {\n\t\t\t\t/* calculate available data length */\n\t\t\t\tret_val += mam.attributes[indx].length + 5;\n\t\t\t\tif (ret_val <= alloc_len) {\n\t\t\t\t\t/* add it to output */\n\t\t\t\t\tMHVTL_DBG(2, \"Attribute : %02x %02x %02x %02x %02x %02x\\n\",\n\t\t\t\t\t\t\t  buf[byte_index], buf[byte_index + 1],\n\t\t\t\t\t\t\t  buf[byte_index + 2], buf[byte_index + 3],\n\t\t\t\t\t\t\t  buf[byte_index + 4], buf[byte_index + 5]);\n\t\t\t\t\tbuf[byte_index++] = mam.attributes[indx].attribute_id >> 8;\n\t\t\t\t\tbuf[byte_index++] = mam.attributes[indx].attribute_id;\n\t\t\t\t\tbuf[byte_index++] = (mam.attributes[indx].read_only << 7) | mam.attributes[indx].format;\n\t\t\t\t\tbuf[byte_index++] = mam.attributes[indx].length >> 8;\n\t\t\t\t\tbuf[byte_index++] = mam.attributes[indx].length;\n\t\t\t\t\tmemcpy(&buf[byte_index], mam.attributes[indx].value, mam.attributes[indx].length);\n\t\t\t\t\tbyte_index += mam.attributes[indx].length;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (!found_attribute) {\n\t\t\tMHVTL_DBG(2, \"Attribute not found\");\n\t\t\tsd.byte0\t\t = SKSV | CD;\n\t\t\tsd.field_pointer = 8;\n\t\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd,\n\t\t\t\t\t\t\t\tsam_stat);\n\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t}\n\t} else {\n\t\t/* Attribute List */\n\t\tfor (indx = found_attribute = 0; mam.attributes[indx].length; indx++) {\n\t\t\t/* calculate available data length */\n\t\t\tret_val += 2;\n\t\t\tif (ret_val <= alloc_len) {\n\t\t\t\t/* add it to output */\n\t\t\t\tbuf[byte_index++] = mam.attributes[indx].attribute_id >> 8;\n\t\t\t\tbuf[byte_index++] = mam.attributes[indx].attribute_id;\n\t\t\t}\n\t\t}\n\t}\n\n\tput_unaligned_be32(ret_val, &buf[0]);\n\n\treturn ret_val;\n}\n\n/*\n * Process WRITE ATTRIBUTE scsi command\n * Returns 0 if OK\n *         or 1 if MAM needs to be written.\n *         or -1 on failure.\n */\nint resp_write_attribute(struct scsi_cmd *cmd) {\n\tuint8_t\t\t\t   *sam_stat = &cmd->dbuf_p->sam_stat;\n\tuint8_t\t\t\t   *cdb\t\t = cmd->scb;\n\tuint8_t\t\t\t   *buf\t\t = (uint8_t *)cmd->dbuf_p->data;\n\tstruct priv_lu_ssc *lu_priv\t = cmd->lu->lu_private;\n\tstruct MAM\t\t   *mamp\t = lu_priv->mamp;\n\n\tstruct MAM\t mam_backup;\n\tuint32_t\t alloc_len;\n\tuint16_t\t attrib;\n\tuint16_t\t attribute_length;\n\tunsigned int byte_index = 4;\n\tint\t\t\t indx, found_attribute;\n\tstruct s_sd\t sd;\n\n\talloc_len = get_unaligned_be32(&cdb[10]);\n\tattrib\t  = get_unaligned_be16(&buf[byte_index]);\n\n\tMHVTL_DBG(2, \"Write Attribute: 0x%x, allocation len: %d\",\n\t\t\t  attrib, alloc_len);\n\n\tmemcpy(&mam_backup, mamp, sizeof(struct MAM)); /* In case of error, keep former state of mam */\n\n\tfor (byte_index = 4; byte_index < alloc_len;) {\n\t\tattrib = get_unaligned_be16(&buf[byte_index]);\n\n\t\tfor (indx = found_attribute = 0; mam.attributes[indx].length; indx++) {\n\t\t\tif (attrib == mam.attributes[indx].attribute_id) {\n\t\t\t\tfound_attribute\t = 1;\n\t\t\t\tattribute_length = get_unaligned_be16(&buf[byte_index + 3]);\n\t\t\t\tbyte_index += 5;\t\t /* positioning to the actual value */\n\t\t\t\tif ((attrib == 0x408) && /* Attribute == Medium Type */\n\t\t\t\t\t(attribute_length == 1) &&\n\t\t\t\t\t(buf[byte_index] == 0x80)) {\n\t\t\t\t\t/* set media to worm */\n\t\t\t\t\tMHVTL_LOG(\"Converted media to WORM\");\n\t\t\t\t\tmamp->MediumType = MEDIA_TYPE_WORM;\n\t\t\t\t} else {\n\t\t\t\t\tmemcpy(mam.attributes[indx].value,\n\t\t\t\t\t\t   &buf[byte_index],\n\t\t\t\t\t\t   mam.attributes[indx].length);\n\t\t\t\t}\n\t\t\t\tbyte_index += attribute_length; /* Positioning to the next attribute if any */\n\t\t\t\tbreak;\n\t\t\t} else {\n\t\t\t\tfound_attribute\t = 0;\n\t\t\t\tsd.field_pointer = indx;\n\t\t\t}\n\t\t}\n\t\tif (!found_attribute) {\n\t\t\tmemcpy(&mamp, &mam_backup, sizeof(mamp));\n\t\t\tsd.byte0 = SKSV;\n\t\t\tsam_illegal_request(E_INVALID_FIELD_IN_PARMS, &sd,\n\t\t\t\t\t\t\t\tsam_stat);\n\t\t\treturn 0;\n\t\t}\n\t}\n\treturn found_attribute;\n}\n\n/*\n * Space over (to) x filemarks. Setmarks not supported as yet.\n */\nvoid resp_space(int64_t count, int code, uint8_t *sam_stat) {\n\tstruct s_sd sd;\n\n\tswitch (code) {\n\t/* Space 'count' blocks */\n\tcase 0:\n\t\tif (count >= 0)\n\t\t\tposition_blocks_forw(count, sam_stat);\n\t\telse\n\t\t\tposition_blocks_back(-count, sam_stat);\n\t\tbreak;\n\t/* Space 'count' filemarks */\n\tcase 1:\n\t\tif (count >= 0)\n\t\t\tposition_filemarks_forw(count, sam_stat);\n\t\telse\n\t\t\tposition_filemarks_back(-count, sam_stat);\n\t\tbreak;\n\t/* Space to end-of-data - Ignore 'count' */\n\tcase 3:\n\t\tposition_to_eod(sam_stat);\n\t\tbreak;\n\n\tdefault:\n\t\tsd.byte0\t\t = SKSV | CD;\n\t\tsd.field_pointer = 1;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\tbreak;\n\t}\n\tdelay_opcode(DELAY_POSITION, lu_ssc.delay_position);\n}\n\n#ifdef MHVTL_DEBUG\nstatic char *sps_pg0\t  = \"Tape Data Encyrption in Support page\";\nstatic char *sps_pg1\t  = \"Tape Data Encyrption Out Support Page\";\nstatic char *sps_pg16\t  = \"Data Encryption Capabilities page\";\nstatic char *sps_pg17\t  = \"Supported key formats page\";\nstatic char *sps_pg18\t  = \"Data Encryption management capabilities page\";\nstatic char *sps_pg32\t  = \"Data Encryption Status page\";\nstatic char *sps_pg33\t  = \"Next Block Encryption Status Page\";\nstatic char *sps_pg48\t  = \"Random Number Page\";\nstatic char *sps_pg49\t  = \"Device Server Key Wrapping Public Key page\";\nstatic char *sps_reserved = \"Security Protcol Specific : reserved value\";\n\nstatic char *lookup_sp_specific(uint16_t field) {\n\tMHVTL_DBG(3, \"Lookup %d\", field);\n\tswitch (field) {\n\tcase 0: return sps_pg0;\n\tcase 1: return sps_pg1;\n\tcase 16: return sps_pg16;\n\tcase 17: return sps_pg17;\n\tcase 18: return sps_pg18;\n\tcase 32: return sps_pg32;\n\tcase 33: return sps_pg33;\n\tcase 48: return sps_pg48;\n\tcase 49: return sps_pg49;\n\tdefault:\n\t\treturn sps_reserved;\n\t\tbreak;\n\t}\n}\n#endif\n\n#define SUPPORTED_SECURITY_PROTOCOL_LIST 0\n#define CERTIFICATE_DATA\t\t\t\t 1\n#define SECURITY_PROTOCOL_INFORMATION\t 0\n#define TAPE_DATA_ENCRYPTION\t\t\t 0x20\n\n/* FIXME:\n * Took this certificate from my Ubuntu install\n *          /usr/share/doc/libssl-dev/demos/tunala/CA.pem\n *\t\tI wonder if RIAA is in NZ ?\n *\n * Need to insert a valid certificate of my own here...\n */\n#include \"vtltape_pem.h\"\n\n/*\n * Returns number of bytes in struct\n */\nstatic int resp_spin_page_0(uint8_t *buf, uint16_t sps, uint32_t alloc_len, uint8_t *sam_stat) {\n\tint\t\t\tret = SAM_STAT_GOOD;\n\tstruct s_sd sd;\n\n\tMHVTL_DBG(2, \"%s\", lookup_sp_specific(sps));\n\n\tswitch (sps) {\n\tcase SUPPORTED_SECURITY_PROTOCOL_LIST:\n\t\tbuf[6] = 0; /* list length (MSB) */\n\t\tbuf[7] = 2; /* list length (LSB) */\n\t\tbuf[8] = SECURITY_PROTOCOL_INFORMATION;\n\t\tbuf[9] = TAPE_DATA_ENCRYPTION;\n\t\tret\t   = 10;\n\t\tbreak;\n\n\tcase CERTIFICATE_DATA:\n\t\tstrncpy((char *)&buf[4], certificate, alloc_len - 4);\n\t\tif (strlen(certificate) >= alloc_len - 4) {\n\t\t\tput_unaligned_be16(alloc_len - 4, &buf[2]);\n\t\t\tret = alloc_len;\n\t\t} else {\n\t\t\tput_unaligned_be16(strlen(certificate), &buf[2]);\n\t\t\tret = strlen(certificate) + 4;\n\t\t}\n\t\tbreak;\n\n\tdefault:\n\t\tsd.byte0\t\t = SKSV | CD;\n\t\tsd.field_pointer = 2;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\tret = SAM_STAT_CHECK_CONDITION;\n\t}\n\treturn ret;\n}\n\n/*\n * Return number of valid bytes in data structure\n */\nstatic int resp_spin_page_20(struct scsi_cmd *cmd) {\n\tint\t\t\t\t\tret = 0;\n\tint\t\t\t\t\ti, correct_key;\n\tunsigned int\t\tcount;\n\tuint8_t\t\t\t   *buf\t\t = (uint8_t *)cmd->dbuf_p->data;\n\tuint8_t\t\t\t   *sam_stat = &cmd->dbuf_p->sam_stat;\n\tuint16_t\t\t\tsps\t\t = get_unaligned_be16(&cmd->scb[2]);\n\tstruct priv_lu_ssc *lu_priv;\n\tlu_priv = (struct priv_lu_ssc *)cmd->lu->lu_private;\n\tstruct s_sd sd;\n\n\tMHVTL_DBG(2, \"%s\", lookup_sp_specific(sps));\n\n\tswitch (sps) {\n\tcase ENCR_IN_SUPPORT_PAGES:\n\t\tput_unaligned_be16(ENCR_IN_SUPPORT_PAGES, &buf[0]);\n\t\tput_unaligned_be16(14, &buf[2]); /* List length */\n\t\tput_unaligned_be16(ENCR_IN_SUPPORT_PAGES, &buf[4]);\n\t\tput_unaligned_be16(ENCR_OUT_SUPPORT_PAGES, &buf[6]);\n\t\tput_unaligned_be16(ENCR_CAPABILITIES, &buf[8]);\n\t\tput_unaligned_be16(ENCR_KEY_FORMATS, &buf[10]);\n\t\tput_unaligned_be16(ENCR_KEY_MGT_CAPABILITIES, &buf[12]);\n\t\tput_unaligned_be16(ENCR_DATA_ENCR_STATUS, &buf[14]);\n\t\tput_unaligned_be16(ENCR_NEXT_BLK_ENCR_STATUS, &buf[16]);\n\t\tret = 18;\n\t\tbreak;\n\n\tcase ENCR_OUT_SUPPORT_PAGES:\n\t\tput_unaligned_be16(ENCR_OUT_SUPPORT_PAGES, &buf[0]);\n\t\tput_unaligned_be16(2, &buf[2]); /* List length */\n\t\tput_unaligned_be16(ENCR_SET_DATA_ENCRYPTION, &buf[4]);\n\t\tret = 6;\n\t\tbreak;\n\n\tcase ENCR_CAPABILITIES:\n\t\tret = lu_priv->pm->encryption_capabilities(cmd);\n\t\tbreak;\n\n\tcase ENCR_KEY_FORMATS:\n\t\tput_unaligned_be16(ENCR_KEY_FORMATS, &buf[0]);\n\t\tput_unaligned_be16(2, &buf[2]); /* List length */\n\t\tput_unaligned_be16(0, &buf[4]); /* Plain text */\n\t\tret = 6;\n\t\tbreak;\n\n\tcase ENCR_KEY_MGT_CAPABILITIES:\n\t\tput_unaligned_be16(ENCR_KEY_MGT_CAPABILITIES, &buf[0]);\n\t\tput_unaligned_be16(0x0c, &buf[2]); /* List length */\n\t\tbuf[4] = 1;\t\t\t\t\t\t   /* LOCK_C */\n\t\tbuf[5] = 7;\t\t\t\t\t\t   /* CKOD_C, DKOPR_C, CKORL_C */\n\t\tbuf[6] = 0;\t\t\t\t\t\t   /* Reserved */\n\t\tbuf[7] = 7;\t\t\t\t\t\t   /* AITN_C, LOCAL_C, PUBLIC_C */\n\t\t/* buf 8 - 15 reserved */\n\t\tret = 16;\n\t\tbreak;\n\n\tcase ENCR_DATA_ENCR_STATUS:\n\t\tput_unaligned_be16(ENCR_DATA_ENCR_STATUS, &buf[0]);\n\t\tput_unaligned_be16(0x20, &buf[2]); /* List length */\n\t\tbuf[4] = 0x21;\t\t\t\t\t   /* I_T Nexus scope and Key Scope */\n\t\tbuf[5] = lu_priv->ENCRYPT_MODE;\n\t\tbuf[6] = lu_priv->DECRYPT_MODE;\n\t\tbuf[7] = 0x01; /* Algorithm Index */\n\t\tput_unaligned_be32(lu_priv->KEY_INSTANCE_COUNTER, &buf[8]);\n\t\tret = 24;\n\t\ti\t= 24;\n\t\tif (UKAD_LENGTH) {\n\t\t\tbuf[3] += 4 + UKAD_LENGTH;\n\t\t\tbuf[i++] = 0x00;\n\t\t\tbuf[i++] = 0x00;\n\t\t\tbuf[i++] = 0x00;\n\t\t\tbuf[i++] = UKAD_LENGTH;\n\t\t\tfor (count = 0; count < UKAD_LENGTH; ++count)\n\t\t\t\tbuf[i++] = UKAD[count];\n\n\t\t\tret += 4 + UKAD_LENGTH;\n\t\t}\n\t\tif (AKAD_LENGTH) {\n\t\t\tbuf[3] += 4 + AKAD_LENGTH;\n\t\t\tbuf[i++] = 0x01;\n\t\t\tbuf[i++] = 0x00;\n\t\t\tbuf[i++] = 0x00;\n\t\t\tbuf[i++] = AKAD_LENGTH;\n\t\t\tfor (count = 0; count < AKAD_LENGTH; ++count)\n\t\t\t\tbuf[i++] = AKAD[count];\n\n\t\t\tret += 4 + AKAD_LENGTH;\n\t\t}\n\t\tbreak;\n\n\tcase ENCR_NEXT_BLK_ENCR_STATUS:\n\t\tif (get_tape_load_status() != TAPE_LOADED) {\n\t\t\tsam_not_ready(E_MEDIUM_NOT_PRESENT, sam_stat);\n\t\t\tbreak;\n\t\t}\n\t\t/* c_pos contains the NEXT block's header info already */\n\t\tput_unaligned_be16(ENCR_NEXT_BLK_ENCR_STATUS, &buf[0]);\n\t\tbuf[2] = 0;\t /* List length (MSB) */\n\t\tbuf[3] = 12; /* List length (MSB) */\n\t\tif (sizeof(loff_t) > 32)\n\t\t\tput_unaligned_be64(c_pos->blk_number, &buf[4]);\n\t\telse\n\t\t\tput_unaligned_be32(c_pos->blk_number, &buf[8]);\n\t\tif (c_pos->blk_type != B_DATA)\n\t\t\tbuf[12] = 0x2; /* not a logical block */\n\t\telse\n\t\t\tbuf[12] = 0x3; /* not encrypted */\n\t\tbuf[13] = 0x01;\t   /* Algorithm Index */\n\t\tret\t\t= 16;\n\t\tif (c_pos->blk_flags & BLKHDR_FLG_ENCRYPTED) {\n\t\t\tcorrect_key = TRUE;\n\t\t\ti\t\t\t= 16;\n\t\t\tif (c_pos->blk_encryption_info.ukad_length) {\n\t\t\t\tbuf[3] += 4 + c_pos->blk_encryption_info.ukad_length;\n\t\t\t\tbuf[i++] = 0x00;\n\t\t\t\tbuf[i++] = 0x01;\n\t\t\t\tbuf[i++] = 0x00;\n\t\t\t\tbuf[i++] = c_pos->blk_encryption_info.ukad_length;\n\t\t\t\tfor (count = 0; count < c_pos->blk_encryption_info.ukad_length; ++count)\n\t\t\t\t\tbuf[i++] = c_pos->blk_encryption_info.ukad[count];\n\t\t\t\tret += 4 + c_pos->blk_encryption_info.ukad_length;\n\t\t\t}\n\t\t\tif (c_pos->blk_encryption_info.akad_length) {\n\t\t\t\tbuf[3] += 4 + c_pos->blk_encryption_info.akad_length;\n\t\t\t\tbuf[i++] = 0x01;\n\t\t\t\tbuf[i++] = 0x03;\n\t\t\t\tbuf[i++] = 0x00;\n\t\t\t\tbuf[i++] = c_pos->blk_encryption_info.akad_length;\n\t\t\t\tfor (count = 0; count < c_pos->blk_encryption_info.akad_length; ++count)\n\t\t\t\t\tbuf[i++] = c_pos->blk_encryption_info.akad[count];\n\t\t\t\tret += 4 + c_pos->blk_encryption_info.akad_length;\n\t\t\t}\n\t\t\t/* compare the keys */\n\t\t\tif (correct_key) {\n\t\t\t\tif (c_pos->blk_encryption_info.key_length != KEY_LENGTH)\n\t\t\t\t\tcorrect_key = FALSE;\n\t\t\t\tfor (count = 0; count < c_pos->blk_encryption_info.key_length; ++count) {\n\t\t\t\t\tif (c_pos->blk_encryption_info.key[count] != KEY[count]) {\n\t\t\t\t\t\tcorrect_key = FALSE;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (correct_key)\n\t\t\t\tbuf[12] = 0x5; /* encrypted, correct key */\n\t\t\telse\n\t\t\t\tbuf[12] = 0x6; /* encrypted, need key */\n\t\t}\n\t\tbreak;\n\n\tdefault:\n\t\tsd.byte0\t\t = SKSV | CD;\n\t\tsd.field_pointer = 2;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t}\n\treturn ret;\n}\n\n/*\n * Retrieve Security Protocol Information\n */\nuint8_t resp_spin(struct scsi_cmd *cmd) {\n\tuint8_t\t\t\t   *sam_stat  = &cmd->dbuf_p->sam_stat;\n\tuint8_t\t\t\t   *buf\t\t  = (uint8_t *)cmd->dbuf_p->data;\n\tuint8_t\t\t\t   *cdb\t\t  = cmd->scb;\n\tuint16_t\t\t\tsps\t\t  = get_unaligned_be16(&cmd->scb[2]);\n\tuint32_t\t\t\talloc_len = get_unaligned_be32(&cdb[6]);\n\tuint8_t\t\t\t\tinc_512\t  = (cdb[4] & 0x80) ? 1 : 0;\n\tstruct priv_lu_ssc *lu_priv;\n\tstruct s_sd\t\t\tsd;\n\n\tlu_priv = (struct priv_lu_ssc *)cmd->lu->lu_private;\n\n\tcmd->dbuf_p->sz = 0;\n\n\tif (inc_512)\n\t\talloc_len = alloc_len * 512;\n\n\tif (alloc_len > lu_priv->bufsize) {\n\t\tMHVTL_LOG(\"buffer too large - aborting\");\n\t\tsd.byte0\t\t = SKSV | CD;\n\t\tsd.field_pointer = 6;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tmemset_ssc_buf(cmd, alloc_len);\n\n\tswitch (cdb[1]) {\n\tcase SECURITY_PROTOCOL_INFORMATION:\n\t\tcmd->dbuf_p->sz = resp_spin_page_0(buf, sps, alloc_len, sam_stat);\n\t\tbreak;\n\tcase TAPE_DATA_ENCRYPTION:\n\t\tcmd->dbuf_p->sz = resp_spin_page_20(cmd);\n\t\tbreak;\n\tdefault:\n\t\tMHVTL_DBG(1, \"Security protocol 0x%04x unknown\", cdb[1]);\n\t\tsd.byte0\t\t = SKSV | CD;\n\t\tsd.field_pointer = 1;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t}\n\treturn *sam_stat;\n}\n\nuint8_t resp_spout(struct scsi_cmd *cmd) {\n\tuint8_t\t\t\t   *sam_stat = &cmd->dbuf_p->sam_stat;\n\tuint8_t\t\t\t   *buf\t\t = (uint8_t *)cmd->dbuf_p->data;\n\tstruct lu_phy_attr *lu;\n\tstruct priv_lu_ssc *lu_priv;\n\tunsigned int\t\tcount;\n\tstruct s_sd\t\t\tsd;\n#ifdef MHVTL_DEBUG\n\tuint16_t sps\t = get_unaligned_be16(&cmd->scb[2]);\n\tuint8_t\t inc_512 = (cmd->scb[4] & 0x80) ? 1 : 0;\n#endif\n\n\tlu\t\t= cmd->lu;\n\tlu_priv = (struct priv_lu_ssc *)cmd->lu->lu_private;\n\n\tif (cmd->scb[1] != TAPE_DATA_ENCRYPTION) {\n\t\tMHVTL_DBG(1, \"Security protocol 0x%02x unknown\", cmd->scb[1]);\n\t\tsd.byte0\t\t = SKSV | CD;\n\t\tsd.field_pointer = 1;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\tMHVTL_DBG(2, \"Tape Data Encryption, %s, \"\n\t\t\t\t \" alloc len: 0x%02x, inc_512: %s\",\n\t\t\t  lookup_sp_specific(sps),\n\t\t\t  cmd->dbuf_p->sz, (inc_512) ? \"Set\" : \"Unset\");\n\n\t/* check for a legal \"set data encryption page\" */\n\tif ((buf[0] != 0x00) || (buf[1] != 0x10) ||\n\t\t(buf[2] != 0x00) || (buf[3] < 16) ||\n\t\t(buf[8] != 0x01) || (buf[9] != 0x00)) {\n\t\tsd.byte0 = SKSV;\n\t\t/* Make sure the 'byte closest to [0]' is the one reported */\n\t\tif (buf[9])\n\t\t\tsd.field_pointer = 9;\n\t\tif (buf[8] != 1)\n\t\t\tsd.field_pointer = 8;\n\t\tif (buf[3] < 16)\n\t\t\tsd.field_pointer = 3;\n\t\tif (buf[2])\n\t\t\tsd.field_pointer = 2;\n\t\tif (buf[1] != 0x10)\n\t\t\tsd.field_pointer = 1;\n\t\tif (buf[0])\n\t\t\tsd.field_pointer = 0;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_PARMS, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tlu_ssc.KEY_INSTANCE_COUNTER++;\n\tlu_ssc.ENCRYPT_MODE = buf[6];\n\tlu_ssc.DECRYPT_MODE = buf[7];\n\tUKAD_LENGTH\t\t\t= 0;\n\tAKAD_LENGTH\t\t\t= 0;\n\tKEY_LENGTH\t\t\t= get_unaligned_be16(&buf[18]);\n\tfor (count = 0; count < KEY_LENGTH; ++count) {\n\t\tKEY[count] = buf[20 + count];\n\t}\n\n\tMHVTL_DBG(2, \"Encrypt mode: %d Decrypt mode: %d, \"\n\t\t\t\t \"ukad len: %d akad len: %d\",\n\t\t\t  lu_ssc.ENCRYPT_MODE, lu_ssc.DECRYPT_MODE,\n\t\t\t  UKAD_LENGTH, AKAD_LENGTH);\n\n\tif (cmd->dbuf_p->sz > (19 + KEY_LENGTH + 4)) {\n\t\tif (buf[20 + KEY_LENGTH] == 0x00) {\n\t\t\tMHVTL_DBG(2, \"Unauthenticated Key Associated Data (UKAD) provided\");\n\t\t\tUKAD_LENGTH = get_unaligned_be16(&buf[22 + KEY_LENGTH]);\n\t\t\tfor (count = 0; count < UKAD_LENGTH; ++count) {\n\t\t\t\tUKAD[count] = buf[24 + KEY_LENGTH + count];\n\t\t\t}\n\t\t} else if (buf[20 + KEY_LENGTH] == 0x01) {\n\t\t\tMHVTL_DBG(2, \"Authenticated Key Associated Data (AKAD) provided\");\n\t\t\tAKAD_LENGTH = get_unaligned_be16(&buf[22 + KEY_LENGTH]);\n\t\t\tfor (count = 0; count < AKAD_LENGTH; ++count) {\n\t\t\t\tAKAD[count] = buf[24 + KEY_LENGTH + count];\n\t\t\t}\n\t\t}\n\t}\n\n\tcount = lu_priv->pm->kad_validation(lu_ssc.ENCRYPT_MODE, UKAD_LENGTH, AKAD_LENGTH);\n\n\t/* For some reason, this command needs to be failed */\n\tif (count) {\n\t\tlu_ssc.KEY_INSTANCE_COUNTER--;\n\t\tlu_ssc.ENCRYPT_MODE = 0;\n\t\tlu_ssc.DECRYPT_MODE = buf[7];\n\t\tUKAD_LENGTH\t\t\t= 0;\n\t\tAKAD_LENGTH\t\t\t= 0;\n\t\tKEY_LENGTH\t\t\t= 0;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, NULL, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tif (lu_priv->pm->update_encryption_mode)\n\t\tlu_priv->pm->update_encryption_mode(&lu->mode_pg, NULL, lu_ssc.ENCRYPT_MODE);\n\n\treturn SAM_STAT_GOOD;\n}\n\n/*\n * Update MAM contents with current counters\n */\nstatic void updateMAM(uint8_t *sam_stat, int load) {\n\tuint64_t bw;\t\t /* Bytes Written */\n\tuint64_t br;\t\t /* Bytes Read */\n\tuint64_t load_count; /* load count */\n\n\tMHVTL_DBG(2, \"updateMAM(%s)\", (load) ? \"load\" : \"unload\");\n\n\t/* Update on load */\n\tif (load) {\n\t\tmam.record_dirty = 1;\n\t\tload_count\t\t = get_unaligned_be64(&mam.LoadCount);\n\t\tload_count++;\n\t\tput_unaligned_be64(load_count, &mam.LoadCount);\n\n\t\tmemcpy(&mam.DevMakeSerialLastLoad3, &mam.DevMakeSerialLastLoad2,\n\t\t\t   40);\n\t\tmemcpy(&mam.DevMakeSerialLastLoad2, &mam.DevMakeSerialLastLoad1,\n\t\t\t   40);\n\t\tmemcpy(&mam.DevMakeSerialLastLoad1, &mam.DevMakeSerialLastLoad,\n\t\t\t   40);\n\t\t/* Initialise with ' ' space char */\n\t\tmemset(&mam.DevMakeSerialLastLoad, 0x20, 40);\n\t\tmemcpy(&mam.DevMakeSerialLastLoad, &lunit.vendor_id,\n\t\t\t   VENDOR_ID_LEN);\n\t\tmemcpy(&mam.DevMakeSerialLastLoad[8], &lunit.lu_serial_no,\n\t\t\t   SCSI_SN_LEN);\n\t} else { /* Update on unload */\n\t\tmam.record_dirty = 0;\n\t\t/* Update bytes written this load. */\n\t\tput_unaligned_be64(lu_ssc.bytesWritten_I,\n\t\t\t\t\t\t   &mam.WrittenInLastLoad);\n\t\tput_unaligned_be64(lu_ssc.bytesRead_I, &mam.ReadInLastLoad);\n\n\t\t/* Update total bytes read/written */\n\t\tbw = get_unaligned_be64(&mam.WrittenInMediumLife);\n\t\tbw += lu_ssc.bytesWritten_I;\n\t\tput_unaligned_be64(bw, &mam.WrittenInMediumLife);\n\n\t\tbr = get_unaligned_be64(&mam.ReadInMediumLife);\n\t\tbr += lu_ssc.bytesRead_I;\n\t\tput_unaligned_be64(br, &mam.ReadInMediumLife);\n\t}\n\n\trewriteMAM(sam_stat);\n}\n\n/*\n *\n * Process the SCSI command\n *\n * Called with:\n *\tcdev     -> Char dev file handle,\n *\tcdb      -> SCSI Command buffer pointer,\n *\tdbuf     -> struct mhvtl_ds *\n */\nstatic void processCommand(int cdev, uint8_t *cdb, struct mhvtl_ds *dbuf_p,\n\t\t\t\t\t\t   useconds_t pollInterval) {\n\tstatic int\t\t last_count;\n\tstatic uint64_t\t tot_delay;\n\tint\t\t\t\t err = 0;\n\tstruct scsi_cmd\t _cmd;\n\tstruct scsi_cmd *cmd;\n\tcmd = &_cmd;\n\n\tcmd->scb\t\t  = cdb;\n\tcmd->scb_len\t  = 16; /* fixme */\n\tcmd->dbuf_p\t\t  = dbuf_p;\n\tcmd->lu\t\t\t  = &lunit;\n\tcmd->cdev\t\t  = cdev;\n\tcmd->pollInterval = pollInterval;\n\n\tif ((cdb[0] == READ_6 || cdb[0] == WRITE_6) && cdb[0] == last_cmd) {\n\t\tMHVTL_DBG_PRT_CDB(2, cmd);\n\t\ttot_delay += cmd->pollInterval;\n\t\tif ((++last_count % 50) == 0) {\n\t\t\tMHVTL_DBG(1, \"%dth contiguous %s request (%ld) \"\n\t\t\t\t\t\t \"(delay %\" PRId64 \")\",\n\t\t\t\t\t  last_count,\n\t\t\t\t\t  last_cmd == READ_6 ? \"READ_6\" : \"WRITE_6\",\n\t\t\t\t\t  (long)dbuf_p->serialNo, tot_delay);\n\t\t\ttot_delay = 0;\n\t\t}\n\t} else {\n\t\tMHVTL_DBG_PRT_CDB(1, cmd);\n\t\tlast_count = 0;\n\t\ttot_delay  = 0;\n\t}\n\n\t/* Limited subset of commands don't need to check for power-on reset */\n\tswitch (cdb[0]) {\n\tcase INQUIRY: /* Inquiry does not need power-on/reset, however the inquiry data may have changed */\n\t\tif (check_inquiry_data_has_changed(&dbuf_p->sam_stat))\n\t\t\treturn;\n\tcase REPORT_LUNS:\n\tcase REQUEST_SENSE:\n\tcase MODE_SELECT:\n\t\tdbuf_p->sam_stat = SAM_STAT_GOOD;\n\t\tbreak;\n\tdefault:\n\t\tif (check_reset(&dbuf_p->sam_stat))\n\t\t\treturn;\n\t}\n\n\t/* Skip main op code processing if pre-cmd returns non-zero */\n\tif (cmd->lu->scsi_ops->ops[cdb[0]].pre_cmd_perform)\n\t\terr = cmd->lu->scsi_ops->ops[cdb[0]].pre_cmd_perform(cmd, NULL);\n\n\tif (!err)\n\t\tdbuf_p->sam_stat = cmd->lu->scsi_ops->ops[cdb[0]].cmd_perform(cmd);\n\t/* Post op code processing regardless */\n\tif (cmd->lu->scsi_ops->ops[cdb[0]].post_cmd_perform)\n\t\tcmd->lu->scsi_ops->ops[cdb[0]].post_cmd_perform(cmd, NULL);\n\n\tlast_cmd = cdb[0];\n\n\treturn;\n}\n\nstatic struct media_details *check_media_can_load(struct list_head *mdl, int mt) {\n\tstruct media_details *m_detail;\n\n\tMHVTL_DBG(2, \"Looking for media_type: 0x%02x\", mt);\n\n\tlist_for_each_entry(m_detail, mdl, siblings) {\n\t\tMHVTL_DBG(3, \"testing against m_detail->media_type (0x%02x)\",\n\t\t\t\t  m_detail->media_type);\n\t\tif (m_detail->media_type == (unsigned int)mt)\n\t\t\treturn m_detail;\n\t}\n\treturn NULL;\n}\n\n/*\n * Attempt to load PCL - i.e. Open datafile and read in BOT header & MAM\n *\n * Returns:\n * == 0 -> Load OK\n * == 1 -> Tape already loaded.\n * == 2 -> format corrupt.\n * == 3 -> cartridge does not exist or cannot be opened.\n */\n\nint loadTape(char *PCL, uint8_t *sam_stat) {\n\tint\t\t\t\t\t  rc;\n\tuint64_t\t\t\t  fg = TA_NONE; /* TapeAlert flags */\n\tint\t\t\t\t\t  overflow;\n\tstruct media_details *m_detail;\n\tstruct lu_phy_attr\t *lu;\n\n\tlu_ssc.bytesWritten_I = 0; /* Global - Bytes written this load */\n\tlu_ssc.bytesWritten_M = 0; /* Global - Bytes written this load */\n\tlu_ssc.bytesRead_I\t  = 0; /* Global - Bytes read this load */\n\tlu_ssc.bytesRead_M\t  = 0; /* Global - Bytes read this load */\n\tlu\t\t\t\t\t  = lu_ssc.pm->lu;\n\n\trc = load_tape(PCL, sam_stat);\n\tif (rc) {\n\t\tMHVTL_ERR(\"Media load failed.. Unsupported format\");\n\t\tlu_ssc.mediaSerialNo[0] = '\\0';\n\t\tif (rc == 2) {\n\t\t\t/* TapeAlert - Unsupported format */\n\t\t\tfg = TA_MEDIA_NOT_SUPPORTED;\n\t\t\tupdate_TapeAlert(fg);\n\t\t}\n\t\tMHVTL_LOG(\"Tape Load (%s) failed with status: %d\", PCL, rc);\n\t\treturn rc;\n\t}\n\n\tset_tape_load_status(TAPE_LOADING);\n\tlu_ssc.pm->media_load(lu, TAPE_LOADED);\n\n\toverflow = snprintf((char *)lu_ssc.mediaSerialNo,\n\t\t\t\t\t\tsizeof(mam.MediumSerialNumber) - 1,\n\t\t\t\t\t\t\"%s\",\n\t\t\t\t\t\t(char *)mam.MediumSerialNumber);\n\tif (overflow >= sizeof(mam.MediumSerialNumber) - 1) {\n\t\tMHVTL_ERR(\"MAM medium serial number truncated to %s\", mam.MediumSerialNumber);\n\t}\n\n\tMHVTL_DBG(1, \"Media type '%s' loaded with S/No. : %s\",\n\t\t\t  lookup_media_type(lu_ssc.pm->media_handling,\n\t\t\t\t\t\t\t\tmam.MediaType),\n\t\t\t  mam.MediumSerialNumber);\n\n\trewind_tape(sam_stat);\n\n\tlu_ssc.max_capacity = get_unaligned_be64(&mam.max_capacity);\n\n\tswitch (mam.MediumType) {\n\tcase MEDIA_TYPE_DATA:\n\t\tset_current_state(MHVTL_STATE_LOADING);\n\t\tOK_to_write = 1; /* Reset flag to OK. */\n\t\tif (lu_ssc.pm->clear_WORM)\n\t\t\tlu_ssc.pm->clear_WORM(&lu->mode_pg);\n\t\tsam_unit_attention(E_NOT_READY_TO_TRANSITION, sam_stat);\n\t\tbreak;\n\tcase MEDIA_TYPE_CLEAN:\n\t\tset_current_state(MHVTL_STATE_LOADING_CLEAN);\n\t\tOK_to_write = 0;\n\t\tif (lu_ssc.pm->clear_WORM)\n\t\t\tlu_ssc.pm->clear_WORM(&lu->mode_pg);\n\t\tif (lu_ssc.pm->cleaning_media)\n\t\t\tlu_ssc.pm->cleaning_media(&lu_ssc);\n\t\tfg |= TA_CLEANING_MEDIA;\n\t\tMHVTL_DBG(1, \"Cleaning media loaded\");\n\t\tsam_unit_attention(E_CLEANING_CART_INSTALLED, sam_stat);\n\t\tbreak;\n\tcase MEDIA_TYPE_WORM:\n\t\tset_current_state(MHVTL_STATE_LOADING_WORM);\n\t\t/* Special condition...\n\t\t * If we\n\t\t * - rewind,\n\t\t * - write filemark\n\t\t * - EOD\n\t\t * We set this as writable media as the tape is blank.\n\t\t */\n\t\tif (!lu_ssc.pm->set_WORM) { /* PM doesn't support WORM */\n\t\t\tMHVTL_DBG(1, \"load failed - WORM media,\"\n\t\t\t\t\t\t \" but drive doesn't support WORM\");\n\t\t\tgoto mismatchmedia;\n\t\t}\n\n\t\tif (c_pos->blk_type == B_EOD) {\n\t\t\tOK_to_write = 1;\n\t\t} else if (c_pos->blk_type != B_FILEMARK) {\n\t\t\tOK_to_write = 0;\n\n\t\t\t/* Check that this header is a filemark and\n\t\t\t * the next header is End of Data.\n\t\t\t * If it is, we are OK to write\n\t\t\t */\n\t\t} else if (position_to_block(1, sam_stat)) {\n\t\t\tOK_to_write = 0;\n\t\t} else {\n\t\t\tif (c_pos->blk_type == B_EOD)\n\t\t\t\tOK_to_write = 1;\n\t\t\telse\n\t\t\t\tOK_to_write = 0;\n\t\t\trewind_tape(sam_stat);\n\t\t}\n\t\tlu_ssc.pm->set_WORM(&lu->mode_pg);\n\t\tMHVTL_DBG(1, \"Write Once Read Many (WORM) media loaded\");\n\t\tbreak;\n\tcase MEDIA_TYPE_NULL: /* Special - don't save data, just metadata */\n\t\tset_current_state(MHVTL_STATE_LOADING);\n\t\tOK_to_write = 1; /* Reset flag to OK. */\n\t\tsam_unit_attention(E_NOT_READY_TO_TRANSITION, sam_stat);\n\t\tbreak;\n\t}\n\n\t/* Set TapeAlert flg 32h => */\n\t/*\tLost Statics */\n\tif (mam.record_dirty != 0) {\n\t\tfg = TA_LOST_STATISTICS;\n\t\tMHVTL_DBG(1, \"Previous unload was not clean\");\n\t}\n\n\tif (lu_ssc.max_capacity) {\n\t\tlu_ssc.early_warning_position =\n\t\t\tlu_ssc.max_capacity -\n\t\t\tlu_ssc.early_warning_sz;\n\n\t\tlu_ssc.prog_early_warning_position =\n\t\t\tlu_ssc.early_warning_position -\n\t\t\tlu_ssc.prog_early_warning_sz;\n\t}\n\n\tif (lu_ssc.pm->drive_supports_early_warning) {\n\t\tif (lu_ssc.pm->drive_supports_prog_early_warning) {\n\t\t\tMHVTL_DBG(2, \"Tape capacity: %\" PRId64 \" + Early Warning %\" PRId64 \" + Prog Early Warning %\" PRId64,\n\t\t\t\t\t  lu_ssc.max_capacity,\n\t\t\t\t\t  lu_ssc.early_warning_sz,\n\t\t\t\t\t  lu_ssc.prog_early_warning_sz);\n\n\t\t} else {\n\t\t\tMHVTL_DBG(2, \"Tape capacity: %\" PRId64 \" + Early Warning %\" PRId64,\n\t\t\t\t\t  lu_ssc.max_capacity,\n\t\t\t\t\t  lu_ssc.early_warning_sz);\n\t\t}\n\t} else {\n\t\tMHVTL_DBG(2, \"Tape capacity: %\" PRId64, lu_ssc.max_capacity);\n\t}\n\n\t/* Increment load count */\n\tupdateMAM(sam_stat, 1);\n\n\tm_detail = check_media_can_load(&lu_ssc.supported_media_list,\n\t\t\t\t\t\t\t\t\tmam.MediaType);\n\n\tif (!m_detail) { /* Media not defined.. Reject */\n\t\tMHVTL_DBG(3, \"Undefined Media rejected\");\n\t\tgoto mismatchmedia;\n\t}\n\n\tMHVTL_DBG(2, \"Load Capability: 0x%02x\", m_detail->load_capability);\n\n\t/* Now check for WORM support */\n\tswitch (mam.MediumType) {\n\tcase MEDIA_TYPE_WORM:\n\t\t/* If media is WORM, check drive will allow mount */\n\t\tif (m_detail->load_capability & (LOAD_WORM | LOAD_RW)) {\n\t\t\t/* Prev check will correctly set OK_to_write flag */\n\t\t\tMHVTL_DBG(2, \"Allow LOAD as R/W WORM\");\n\t\t} else if (m_detail->load_capability & (LOAD_WORM | LOAD_RO)) {\n\t\t\tMHVTL_DBG(2, \"Allow LOAD as R/O WORM\");\n\t\t\tOK_to_write = 0;\n\t\t} else {\n\t\t\tMHVTL_ERR(\"Load failed: Unable to load as WORM\");\n\t\t\tgoto mismatchmedia;\n\t\t}\n\t\tbreak;\n\tcase MEDIA_TYPE_DATA:\n\t\t/* Allow media to be either RO or RW */\n\t\tif (m_detail->load_capability & LOAD_RO) {\n\t\t\tMHVTL_DBG(2, \"Mounting READ ONLY\");\n\t\t\tlu_ssc.MediaWriteProtect = MEDIA_READONLY;\n\t\t\tOK_to_write\t\t\t\t = 0;\n\t\t} else if (m_detail->load_capability & LOAD_RW) {\n\t\t\tif (mam.Flags & MAM_FLAGS_MEDIA_WRITE_PROTECT) {\n\t\t\t\tset_lp_11_wp(1); /* Update WriteProtect bit in LogPage 0x11 */\n\t\t\t\tMHVTL_DBG(2, \"Mounting READ ONLY - WP set\");\n\t\t\t\tlu_ssc.MediaWriteProtect = MEDIA_READONLY;\n\t\t\t\tOK_to_write\t\t\t\t = 0;\n\t\t\t} else {\n\t\t\t\tMHVTL_DBG(2, \"Mounting READ/WRITE\");\n\t\t\t\tset_lp_11_wp(0); /* Update WriteProtect bit in LogPage 0x11 */\n\t\t\t\tlu_ssc.MediaWriteProtect = MEDIA_WRITABLE;\n\t\t\t\tOK_to_write\t\t\t\t = 1;\n\t\t\t}\n\t\t} else if (m_detail->load_capability & LOAD_FAIL) {\n\t\t\tMHVTL_ERR(\"Load failed: Data format not suitable for \"\n\t\t\t\t\t  \"read/write or read-only\");\n\t\t\tgoto mismatchmedia;\n\t\t}\n\t\tbreak;\n\tcase MEDIA_TYPE_NULL:\n\t\tbreak;\n\tdefault: /* Can't write to cleaning media */\n\t\tOK_to_write = 0;\n\t\tbreak;\n\t}\n\n\t/* Update TapeAlert flags */\n\tupdate_TapeAlert(fg);\n\n\tMHVTL_DBG(1, \"Media is%s writable\", (OK_to_write) ? \"\" : \" not\");\n\n\tmodeBlockDescriptor[0] = mam.MediumDensityCode;\n\n\tMHVTL_DBG(1, \"Setting MediumDensityCode to %s (0x%02x)\"\n\t\t\t\t \" Media type: 0x%02x\",\n\t\t\t  lookup_density_name(lu_ssc.pm->media_handling,\n\t\t\t\t\t\t\t\t  mam.MediumDensityCode),\n\t\t\t  mam.MediumDensityCode,\n\t\t\t  (uint8_t)lu->mode_media_type);\n\n\tdelay_opcode(DELAY_LOAD, lu_ssc.delay_load);\n\tset_current_state(MHVTL_STATE_LOADED);\n\treturn 0; /* Return successful load */\n\nmismatchmedia:\n\tunload_tape(sam_stat);\n\tfg |= TA_MEDIA_NOT_SUPPORTED; /* Unsupported format */\n\tupdate_TapeAlert(fg);\n\tMHVTL_ERR(\"Tape %s failed to load with type '%s' in drive type '%s'\",\n\t\t\t  PCL,\n\t\t\t  lookup_media_type(lu_ssc.pm->media_handling,\n\t\t\t\t\t\t\t\tmam.MediaType),\n\t\t\t  lu_ssc.pm->name);\n\tset_tape_load_status(TAPE_UNLOADED);\n\tlu_ssc.pm->media_load(lu, TAPE_UNLOADED);\n\tdelay_opcode(DELAY_LOAD, lu_ssc.delay_load);\n\tset_current_state(MHVTL_STATE_LOAD_FAILED);\n\treturn 1;\n}\n\nstatic void dump_linked_list(void) {\n\tstruct media_details *m_detail;\n\tstruct list_head\t *mdl;\n\n\tMHVTL_DBG(3, \"Dumping media type support\");\n\n\tmdl = &lu_ssc.supported_media_list;\n\n\tlist_for_each_entry(m_detail, mdl, siblings) {\n\t\tMHVTL_DBG(3, \"Media type: 0x%02x, status: 0x%02x\",\n\t\t\t\t  m_detail->media_type,\n\t\t\t\t  m_detail->load_capability);\n\t}\n}\n\n/* Strip (recover) the 'Physical Cartridge Label'\n *   Well at least the data filename which relates to the same thing\n */\nstatic char *strip_PCL(char *str, int start) {\n\tchar *q;\n\tchar *p;\n\tint\t  a;\n\n\tp = str + start;\n\n\t/* p += 'start' (skip over 'load' string)\n\t * Then keep going until '*p' is a space or NULL\n\t */\n\tfor (a = 0, q = p; a < strlen(str) - start; a++, q++) {\n\t\tif (isspace(*q) || *q == '\\0') {\n\t\t\t*q = '\\0';\n\t\t\tbreak;\n\t\t}\n\t}\n\tMHVTL_DBG(3, \"Returning: \\\"%s\\\"\", p);\n\treturn p;\n}\n\nvoid unloadTape(int update_library, uint8_t *sam_stat) {\n\tstruct lu_phy_attr *lu = lu_ssc.pm->lu;\n\n\tswitch (get_tape_load_status()) {\n\tcase TAPE_LOADING:\n\tcase TAPE_LOADED:\n\t\t/* Don't update load count on unload -done at load time */\n\t\tupdateMAM(sam_stat, 0);\n\t\tunload_tape(sam_stat);\n\t\tif (lu_ssc.pm->clear_WORM)\n\t\t\tlu_ssc.pm->clear_WORM(&lu->mode_pg);\n\t\tif (lu_ssc.cleaning_media_state)\n\t\t\tlu_ssc.cleaning_media_state = NULL;\n\t\tlu_ssc.pm->media_load(lu, TAPE_UNLOADED);\n\t\tdelay_opcode(DELAY_UNLOAD, lu_ssc.delay_unload);\n\t\tbreak;\n\tdefault:\n\t\tMHVTL_DBG(2, \"Tape not mounted\");\n\t\tbreak;\n\t}\n\tif (update_library && lu_ssc.inLibrary && library_id > 0) {\n\t\tSEND_MSG_AND_LOG(msg_eject, (uint64_t)library_id);\n\t}\n\tset_tape_load_status(TAPE_UNLOADED);\n\tOK_to_write = 0;\n}\n\nstatic int processMessageQ(struct q_msg *msg, uint8_t *sam_stat) {\n\tchar\t\t\t   *pcl;\n\tchar\t\t\t\ts[128];\n\tchar\t\t\t   *z;\n\tint\t\t\t\t\trc;\n\tstruct lu_phy_attr *lu;\n\tint\t\t\t\t\tpcl_len;\n\tuint64_t\t\t\tfg = TA_NONE; /* TapeAlert flags */\n\n\tlu = lu_ssc.pm->lu;\n\n\tMHVTL_DBG(1, \"%ld: Received message \\\"%s\\\" from snd_id %ld\",\n\t\t\t  my_id, msg->text, msg->snd_id);\n\n\t/* Tape Load message from Library */\n\tif (!strncmp(msg->text, \"lload\", 5)) {\n\t\tif (!lu_ssc.inLibrary) {\n\t\t\tMHVTL_DBG(2, \"lload & drive not in library\");\n\t\t\treturn 0;\n\t\t}\n\n\t\tif (lu_ssc.barcode) {\n\t\t\tMHVTL_ERR(\"%ld: snd_id %ld: Tape \\\"%s\\\" already in mouth of drive\",\n\t\t\t\t\t  my_id, msg->snd_id, lu_ssc.barcode);\n\t\t\tsnprintf(s, sizeof(s), \"Load failed - %s is already in mouth of drive\", lu_ssc.barcode);\n\t\t} else {\n\t\t\t/* 'lload ' => offset of 6 */\n\t\t\tpcl\t\t= strip_PCL(msg->text, 6);\n\t\t\tpcl_len = strlen(pcl) + 2;\n\n\t\t\tlu_ssc.barcode = malloc(pcl_len);\n\t\t\tif (!lu_ssc.barcode) {\n\t\t\t\tMHVTL_ERR(\"Ugghhh... out of memory allocating buffer for barcode: %s\", pcl);\n\t\t\t\tsnprintf(s, sizeof(s), \"%s: %s\", msg_load_failed, pcl);\n\t\t\t} else {\n\t\t\t\trc = loadTape(pcl, sam_stat);\n\t\t\t\tstrncpy(lu_ssc.barcode, pcl, pcl_len);\n\t\t\t\tsnprintf(s, sizeof(s), \"%s: %s\", (get_tape_load_status() == TAPE_UNLOADED) ? msg_load_failed : msg_load_ok, pcl);\n\t\t\t\t/* If load fails - clean up 'barcode' */\n\t\t\t\tif (rc) {\n\t\t\t\t\tMHVTL_LOG(\"Mount of %s failed, return code: %d\", pcl, rc);\n\t\t\t\t\tfree(lu_ssc.barcode);\n\t\t\t\t\tlu_ssc.barcode = NULL;\n\t\t\t\t\tif (rc == 2) {\n\t\t\t\t\t\t/* TapeAlert - Unsupported format */\n\t\t\t\t\t\tfg = TA_MEDIA_NOT_SUPPORTED;\n\t\t\t\t\t\tupdate_TapeAlert(fg);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tSEND_MSG_AND_LOG(s, msg->snd_id);\n\t\tif (lu_ssc.barcode)\n\t\t\tset_lp11_medium_present(1);\n\t\telse\n\t\t\tset_lp11_medium_present(0);\n\t}\n\n\t/* Tape Load message from User space */\n\tif (!strncmp(msg->text, \"load\", 4)) {\n\t\tpcl\t\t= strip_PCL(msg->text, 5);\n\t\tpcl_len = strlen(pcl) + 2;\n\t\tif (lu_ssc.inLibrary)\n\t\t\tMHVTL_ERR(\"Warn: Tape assigned to library - The library can't remove this tape !\");\n\t\tif (get_tape_load_status() == TAPE_LOADED) {\n\t\t\tMHVTL_DBG(2, \"A tape is already mounted\");\n\t\t} else {\n\t\t\tloadTape(pcl, sam_stat);\n\t\t}\n\t\t/* Prevent a manual load, and the library moving another in it's place\n\t\t * Feature: There is no logic to remove the tape from 'mouth' of drive\n\t\t *          A restart of the daemon will be required..\n\t\t */\n\t\tif (lu_ssc.barcode) {\n\t\t\tfree(lu_ssc.barcode);\n\t\t}\n\t\tlu_ssc.barcode = malloc(pcl_len);\n\t\tif (lu_ssc.barcode) {\n\t\t\tstrncpy(lu_ssc.barcode, pcl, pcl_len);\n\t\t\tset_lp11_medium_present(1);\n\t\t} else {\n\t\t\tMHVTL_ERR(\"Ugghhh... out of memory allocating buffer for barcode: %s\", pcl);\n\t\t}\n\t}\n\n\t/* This needs to be called if an 'mt -f /dev/st* offline' rather than an 'unload' from library daemon */\n\tif (!strncmp(msg->text, msg_set_empty, strlen(msg_set_empty))) {\n\t\t/* string define in q.h */\n\t\tunloadTape(FALSE, sam_stat); /* Unload - in case something is loaded */\n\t\tfree(lu_ssc.barcode);\n\t\tlu_ssc.barcode = NULL;\n\t\tSEND_MSG_AND_LOG(msg_unload_ok, msg->snd_id);\n\t\tset_lp11_medium_present(0);\n\t}\n\n\tif (!strncmp(msg->text, msg_mount_state, strlen(msg_mount_state))) {\n\t\t/* string define in q.h */\n\t\tsprintf(s, \"%s\", (lu_ssc.barcode) ? msg_occupied : msg_not_occupied);\n\t\tSEND_MSG_AND_LOG(s, msg->snd_id);\n\t}\n\n\tif (!strncmp(msg->text, \"unload\", 6)) {\n\t\tunloadTape(FALSE, sam_stat);\n\t\tSEND_MSG_AND_LOG(msg_unload_ok, msg->snd_id);\n\t\tfree(lu_ssc.barcode);\n\t\tlu_ssc.barcode = NULL;\n\t\tset_lp11_medium_present(0);\n\t}\n\n\tif (!strncmp(msg->text, \"exit\", 4))\n\t\treturn 1;\n\n\tif (!strncmp(msg->text, \"Register\", 8)) {\n\t\tlu_ssc.inLibrary = 1;\n\t\tMHVTL_DBG(1, \"Notice from Library controller : %s\", msg->text);\n\t\t/*\t\tfind_media_home_directory(NULL, library_id); */\n\t}\n\n\tif (!strncmp(msg->text, \"verbose\", 7)) {\n\t\tif (verbose)\n\t\t\tverbose--;\n\t\telse\n\t\t\tverbose = 3;\n\t\tMHVTL_LOG(\"Verbose: %s at level %d\",\n\t\t\t\t  verbose ? \"enabled\" : \"disabled\", verbose);\n\t}\n\n\tif (!strncmp(msg->text, \"InquiryDataChange\", 17))\n\t\tset_inquiry_data_changed();\n\n\tif (!strncmp(msg->text, \"TapeAlert\", 9)) {\n\t\tuint64_t flg = TA_NONE;\n\t\tsscanf(msg->text, \"TapeAlert %\" PRIx64, &flg);\n\t\tupdate_TapeAlert(flg);\n\t}\n\n\tif (!strncmp(msg->text, \"compression\", 11)) {\n\t\tsscanf(msg->text, \"compression %s\", &s[0]);\n\t\tif (!strncasecmp(s, \"lzo\", 3))\n\t\t\tlu_ssc.compressionType = LZO;\n\t\tif (!strncasecmp(s, \"zlib\", 4))\n\t\t\tlu_ssc.compressionType = ZLIB;\n\t\tMHVTL_DBG(1, \"Compression set to %s\",\n\t\t\t\t  (lu_ssc.compressionType == LZO) ? \"LZO\" : \"ZLIB\");\n\t}\n\n\tif (!strncasecmp(msg->text, \"append\", 6)) {\n\t\ts[0] = '\\0';\n\t\tsscanf(msg->text, \"Append Only %s\", &s[0]);\n\t\tif (strlen(s) < 2)\n\t\t\tsscanf(msg->text, \"APPEND ONLY %s\", &s[0]);\n\t\tif (strlen(s) < 2)\n\t\t\tsscanf(msg->text, \"append only %s\", &s[0]);\n\n\t\tif (lu_ssc.pm->drive_supports_append_only_mode) {\n\t\t\tstruct mode *m;\n\n\t\t\tm = lookup_mode_pg(&lu->mode_pg, 0x10, 1);\n\t\t\tif (!m) {\n\t\t\t\tMHVTL_LOG(\"Can't find Append Only mode page\"\n\t\t\t\t\t\t  \", Drive should support Append Only\");\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif (!strncasecmp(s, \"Yes\", 3)) {\n\t\t\t\tm->pcodePointer[5] |= 0x10;\n\t\t\t\tlu_ssc.append_only_mode = 1;\n\t\t\t\tMHVTL_DBG(1, \"Append Only set to \\\"Yes\\\"\");\n\t\t\t} else if (!strncasecmp(s, \"No\", 2)) {\n\t\t\t\tm->pcodePointer[5] &= 0x0f;\n\t\t\t\tlu_ssc.append_only_mode = 0;\n\t\t\t\tMHVTL_DBG(1, \"Append Only set to \\\"No\\\"\");\n\t\t\t} else {\n\t\t\t\tMHVTL_LOG(\"Append Only value: %s unknown,\"\n\t\t\t\t\t\t  \" Leaving unchanged at: %s\",\n\t\t\t\t\t\t  s,\n\t\t\t\t\t\t  (m->pcodePointer[5] & 0xf0) ? \"Yes\" : \"No\");\n\t\t\t}\n\t\t} else\n\t\t\tMHVTL_LOG(\"This drive does not support Append Only mode\");\n\t}\n\tif (!strncasecmp(msg->text, \"delay load\", 10)) {\n\t\tz = strtok(msg->text, \" \");\n\t\tz = strtok(NULL, \" \");\n\t\tz = strtok(NULL, \" \");\n\t\tif (atoi(z) > 0)\n\t\t\tlu_ssc.delay_load = min(atoi(z), MAX_DELAY_LOAD);\n\t\telse\n\t\t\tlu_ssc.delay_load = 0;\n\t\tMHVTL_DBG(2, \"Setting delay_load to %d\", lu_ssc.delay_load);\n\t}\n\tif (!strncasecmp(msg->text, \"delay unload\", 12)) {\n\t\tz = strtok(msg->text, \" \");\n\t\tz = strtok(NULL, \" \");\n\t\tz = strtok(NULL, \" \");\n\t\tif (atoi(z) > 0)\n\t\t\tlu_ssc.delay_unload = min(atoi(z), MAX_DELAY_UNLOAD);\n\t\telse\n\t\t\tlu_ssc.delay_unload = 0;\n\t\tMHVTL_DBG(2, \"Setting delay_unload to %d\", lu_ssc.delay_unload);\n\t}\n\tif (!strncasecmp(msg->text, \"delay rewind\", 12)) {\n\t\tz = strtok(msg->text, \" \");\n\t\tz = strtok(NULL, \" \");\n\t\tz = strtok(NULL, \" \");\n\t\tif (atoi(z) > 0)\n\t\t\tlu_ssc.delay_rewind = min(atoi(z), MAX_DELAY_REWIND);\n\t\telse\n\t\t\tlu_ssc.delay_rewind = 0;\n\t\tMHVTL_DBG(2, \"Setting delay_rewind to %d\", lu_ssc.delay_rewind);\n\t}\n\tif (!strncasecmp(msg->text, \"delay thread\", 12)) {\n\t\tz = strtok(msg->text, \" \");\n\t\tz = strtok(NULL, \" \");\n\t\tz = strtok(NULL, \" \");\n\t\tif (atoi(z) > 0)\n\t\t\tlu_ssc.delay_thread = min(atoi(z), MAX_DELAY_THREAD);\n\t\telse\n\t\t\tlu_ssc.delay_thread = 0;\n\t\tMHVTL_DBG(2, \"Setting delay_thread to %d\", lu_ssc.delay_thread);\n\t}\n\tif (!strncasecmp(msg->text, \"delay position\", 14)) {\n\t\tz = strtok(msg->text, \" \");\n\t\tz = strtok(NULL, \" \");\n\t\tz = strtok(NULL, \" \");\n\t\tif (atoi(z) > 0)\n\t\t\tlu_ssc.delay_position = min(atoi(z), MAX_DELAY_POSITION);\n\t\telse\n\t\t\tlu_ssc.delay_position = 0;\n\t\tMHVTL_DBG(2, \"Setting delay_position to %d\", lu_ssc.delay_position);\n\t}\n\tif (!strncmp(msg->text, \"debug\", 5)) {\n\t\tif (debug > 4) {\n\t\t\tdebug = 1;\n\t\t} else if (debug > 1) {\n\t\t\tdebug++;\n\t\t} else {\n\t\t\tdebug++;\n\t\t\tverbose = 4;\n\t\t}\n\t\tprintf(\"Debug: %d\\n\", debug);\n\t}\n\n\tif (!strncmp(msg->text, \"dump\", 4))\n\t\tdump_linked_list();\n\n\treturn 0;\n}\n\n/*\n * A place to setup any customisations (WORM / Security handling)\n */\nstatic void config_lu(struct lu_phy_attr *lu) {\n\tint i;\n\n\tfor (i = 0; tape_drives[i].name; i++) {\n\t\tif (!strncmp(tape_drives[i].name, lu->product_id,\n\t\t\t\t\t max(strlen(tape_drives[i].name),\n\t\t\t\t\t\t strlen(lu->product_id)))) {\n\n\t\t\tdrive_init = tape_drives[i].init;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tlu_ssc.early_warning_sz\t\t = EARLY_WARNING_SZ;\n\tlu_ssc.prog_early_warning_sz = 0;\n\n\tdrive_init(lu);\n\n\tif (lu_ssc.configCompressionEnabled) {\n\t\tlu_ssc.pm->set_compression(&lu->mode_pg, lu_ssc.configCompressionFactor);\n\t\tset_lp11_compression(1);\n\t} else {\n\t\tlu_ssc.pm->clear_compression(&lu->mode_pg);\n\t\tset_lp11_compression(0);\n\t}\n\n\tMHVTL_DBG(1, \"%s: supports WORM : %s\", lu_ssc.pm->name, lu_ssc.pm->drive_supports_WORM ? \"Yes\" : \"No\");\n\tMHVTL_DBG(1, \"%s: supports append-only mode : %s\", lu_ssc.pm->name, lu_ssc.pm->drive_supports_append_only_mode ? \"Yes\" : \"No\");\n\tMHVTL_DBG(1, \"%s: supports Security Protocol : %s\", lu_ssc.pm->name, lu_ssc.pm->drive_supports_SP ? \"Yes\" : \"No\");\n\tMHVTL_DBG(1, \"%s: supports early warning mode : %s\", lu_ssc.pm->name, lu_ssc.pm->drive_supports_early_warning ? \"Yes\" : \"No\");\n\tMHVTL_DBG(1, \"%s: supports prog early warning mode : %s\", lu_ssc.pm->name, lu_ssc.pm->drive_supports_prog_early_warning ? \"Yes\" : \"No\");\n\tMHVTL_DBG(1, \"%s: supports SCSI Persistent Reservation : %s\", lu_ssc.pm->name, lu_ssc.pm->drive_supports_SPR ? \"Yes\" : \"No\");\n\tMHVTL_DBG(1, \"%s: supports Data Integrity Validation (Logical Block Protection) : %s\", lu_ssc.pm->name,\n\t\t\t  lu_ssc.pm->drive_supports_LBP == 0 ? \"No\" : lu_ssc.pm->drive_supports_LBP == 1 ? \"RS-CRC only\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t  : lu_ssc.pm->drive_supports_LBP == 2\t ? \"RS-CRC and CRC32C\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t : \"Invalid\");\n\tset_timestamp(0, 0); /* timestamp source - num mS from initialisation */\n}\n\nstatic void cleanup_drive_media_list(struct lu_phy_attr *lu) {\n\tstruct priv_lu_ssc\t *lu_tape;\n\tstruct media_details *mdp, *ndp;\n\tstruct list_head\t *den_list;\n\n\tlu_tape\t = (struct priv_lu_ssc *)lu->lu_private;\n\tden_list = &lu_tape->supported_media_list;\n\n\tlist_for_each_entry_safe(mdp, ndp, den_list, siblings) {\n\t\tlist_del(&mdp->siblings);\n\t\tfree(mdp);\n\t}\n}\n\nint add_drive_media_list(struct lu_phy_attr *lu, int status, char *s) {\n\tstruct priv_lu_ssc\t *lu_tape;\n\tstruct media_details *m_detail;\n\tstruct list_head\t *den_list;\n\tint\t\t\t\t\t  media_type;\n\n\tlu_tape\t = (struct priv_lu_ssc *)lu->lu_private;\n\tden_list = &lu_tape->supported_media_list;\n\n\tMHVTL_DBG(2, \"Adding %s, status: 0x%02x\", s, status);\n\tmedia_type = lookup_media_int(lu_tape->pm->media_handling, s);\n\tm_detail   = check_media_can_load(den_list, media_type);\n\n\tif (m_detail) {\n\t\tMHVTL_DBG(2, \"Existing status for %s, status: 0x%02x\",\n\t\t\t\t  s, m_detail->load_capability);\n\t\tm_detail->load_capability |= status;\n\t\tMHVTL_DBG(2, \"Already have an entry for %s, new status: 0x%02x\",\n\t\t\t\t  s, m_detail->load_capability);\n\t} else {\n\t\tMHVTL_DBG(2, \"Adding new entry for %s\", s);\n\t\tm_detail = zalloc(sizeof(struct media_details));\n\t\tif (!m_detail) {\n\t\t\tMHVTL_ERR(\"Failed to allocate %d bytes\",\n\t\t\t\t\t  (int)sizeof(m_detail));\n\t\t\treturn -ENOMEM;\n\t\t}\n\t\tm_detail->media_type\t  = media_type;\n\t\tm_detail->load_capability = status;\n\t\tlist_add_tail(&m_detail->siblings, den_list);\n\t}\n\n\tset_TapeAlert(0);\n\treturn 0;\n}\n\nstatic struct device_type_template ssc_ops = {\n\t.ops = {\n\t\tSCSI_OP_RANGE(0x00, 0xff, spc_illegal_op),\n\n\t\t/* 0x00 -> 0x0f */\n\t\tSCSI_OP(0x00, ssc_tur),\n\t\tSCSI_OP(0x01, ssc_rewind),\n\t\tSCSI_OP(0x03, spc_request_sense),\n\t\tSCSI_OP(0x04, ssc_format_medium),\n\t\tSCSI_OP(0x05, ssc_read_block_limits),\n\t\tSCSI_OP(0x08, ssc_read_6),\n\t\tSCSI_OP(0x0a, ssc_write_6),\n\t\tSCSI_OP(0x0b, ssc_set_capacity),\n\n\t\t/* 0x10 -> 0x1f */\n\t\tSCSI_OP(0x10, ssc_write_filemarks),\n\t\tSCSI_OP(0x11, ssc_space_6),\n\t\tSCSI_OP(0x12, spc_inquiry),\n\t\tSCSI_OP(0x13, ssc_verify_6),\n\t\tSCSI_OP(0x15, ssc_mode_select),\n\t\tSCSI_OP(0x16, ssc_reserve),\n\t\tSCSI_OP(0x17, ssc_release),\n\t\tSCSI_OP(0x19, ssc_erase),\n\t\tSCSI_OP(0x1a, spc_mode_sense),\n\t\tSCSI_OP(0x1b, ssc_load_unload),\n\t\tSCSI_OP(0x1c, ssc_recv_diagnostics),\n\t\tSCSI_OP(0x1d, ssc_send_diagnostics),\n\t\tSCSI_OP(0x1e, ssc_allow_prevent_removal),\n\n\t\t/* 0x20 -> 0x2f */\n\t\tSCSI_OP(0x2b, ssc_locate),\n\n\t\t/* 0x30 -> 0x3f */\n\t\tSCSI_OP(0x34, ssc_read_position),\n\t\tSCSI_OP(0x3c, spc_read_buffer),\n\n\t\t/* 0x40 -> 0x4f */\n\t\tSCSI_OP(0x44, ssc_report_density_support),\n\t\tSCSI_OP(0x4c, ssc_log_select),\n\t\tSCSI_OP(0x4d, ssc_log_sense),\n\n\t\t/* 0x50 -> 0x5f */\n\t\tSCSI_OP(0x55, ssc_mode_select),\n\t\tSCSI_OP(0x56, ssc_reserve),\n\t\tSCSI_OP(0x57, ssc_release),\n\t\tSCSI_OP(0x5a, spc_mode_sense),\n\n\t\t/* 0x60 -> 0x6f */\n\t\t/* 0x70 -> 0x7f */\n\t\t/* 0x80 -> 0x8f */\n\t\tSCSI_OP(0x82, ssc_allow_overwrite),\n\t\tSCSI_OP(0x8c, ssc_read_attributes),\n\t\tSCSI_OP(0x8d, ssc_write_attributes),\n\n\t\t/* 0x90 -> 0x9f */\n\t\tSCSI_OP(0x91, ssc_space_16),\n\t\tSCSI_OP(0x92, ssc_locate),\n\n\t\t/* 0xa0 -> 0xaf */\n\t\tSCSI_OP(0xa0, spc_illegal_op), /* processed in the kernel module */\n\t\tSCSI_OP(0xa3, ssc_a3_service_action),\n\t\tSCSI_OP(0xa4, ssc_a4_service_action),\n\t\tSCSI_OP(0xab, ssc_read_media_sn),\n\n\t\t/* 0xb0 -> 0xbf */\n\t\t/* 0xc0 -> 0xcf */\n\t\t/* 0xd0 -> 0xdf */\n\t\t/* 0xe0 -> 0xef */\n\t\t/* 0xf0 -> 0xff */\n\t}};\n\n/*\n * Update ops[xx] with new/updated/custom function 'f'\n */\nvoid register_ops(struct lu_phy_attr *lu, int op,\n\t\t\t\t  void *f, void *g, void *h) {\n\tlu->scsi_ops->ops[op].cmd_perform\t   = f;\n\tlu->scsi_ops->ops[op].pre_cmd_perform  = g;\n\tlu->scsi_ops->ops[op].post_cmd_perform = h;\n}\n\n#define MALLOC_SZ 512\nstatic int init_lu(struct lu_phy_attr *lu, unsigned minor, struct mhvtl_ctl *ctl) {\n\tstruct vpd **lu_vpd = lu->lu_vpd;\n\n\tchar\t\t\t device_conf[CONF_FILE_SZ];\n\tFILE\t\t\t*conf;\n\tchar\t\t\t*b; /* Read from file into this buffer */\n\tchar\t\t\t*s; /* Somewhere for sscanf to store results */\n\tint\t\t\t\t indx;\n\tstruct mhvtl_ctl tmpctl;\n\tint\t\t\t\t found = 0;\n\tint\t\t\t\t linecount;\n\n\tif (get_config(device_conf, DEVICE_CONF, my_id) < 0) {\n\t\texit(1);\n\t}\n\n\tINIT_LIST_HEAD(&lu->den_list);\n\tINIT_LIST_HEAD(&lu->log_pg);\n\tINIT_LIST_HEAD(&lu->mode_pg);\n\n\tlu->scsi_ops = &ssc_ops;\n\n\tstrncpy(home_directory, MHVTL_HOME_PATH, HOME_DIR_PATH_SZ);\n\n\tlu->fifoname  = NULL;\n\tlu->fifo_fd\t  = NULL;\n\tlu->fifo_flag = 0;\n\tlu->ptype\t  = TYPE_TAPE;\n\n\tbackoff\t\t = DEFLT_BACKOFF_VALUE;\n\tlbp_rscrc_be = 1; /* Default RSCRC is big-endian */\n\n\tlu->sense_p = &sense[0];\n\n\t/* Default inquiry bits */\n\tmemset(&lu->inquiry, 0, MAX_INQUIRY_SZ);\n\tlu->inquiry[0] = TYPE_TAPE; /* SSC device */\n\tlu->inquiry[1] = 0x80;\t\t/* Removable bit set */\n\tlu->inquiry[2] = 0x05;\t\t/* SCSI Version (v3) */\n\tlu->inquiry[3] = 0x02;\t\t/* Response Data Format */\n\tlu->inquiry[4] = 59;\t\t/* Additional Length */\n\tlu->inquiry[6] = 0x01;\t\t/* Addr16 */\n\tlu->inquiry[7] = 0x20;\t\t/* Wbus16 */\n\n\tput_unaligned_be16(0x0300, &lu->inquiry[58]); /* SPC-3 No ver claimed */\n\tput_unaligned_be16(0x0960, &lu->inquiry[60]); /* iSCSI */\n\tput_unaligned_be16(0x0200, &lu->inquiry[62]); /* SSC */\n\n\tconf = fopen(device_conf, \"r\");\n\tif (!conf) {\n\t\tMHVTL_ERR(\"Can not open config file %s : %s\",\n\t\t\t\t  device_conf, strerror(errno));\n\t\tperror(\"Can not open config file\");\n\t\texit(1);\n\t}\n\ts = zalloc(MALLOC_SZ);\n\tif (!s) {\n\t\tperror(\"Could not allocate memory\");\n\t\texit(1);\n\t}\n\tb = zalloc(MALLOC_SZ);\n\tif (!b) {\n\t\tperror(\"Could not allocate memory\");\n\t\texit(1);\n\t}\n\n\t/* While read in a line */\n\tlinecount = 0;\n\twhile (readline(b, MALLOC_SZ, conf) != NULL) {\n\t\tlinecount++;\n\t\tif (b[0] == '#') /* Ignore comments */\n\t\t\tcontinue;\n\t\tif (strlen(b) == 1) /* Reset drive number of blank line */\n\t\t\tindx = 0xff;\n\t\tif (sscanf(b, \"Drive: %d CHANNEL: %d TARGET: %d LUN: %d\",\n\t\t\t\t   &indx, &tmpctl.channel,\n\t\t\t\t   &tmpctl.id, &tmpctl.lun)) {\n\t\t\tMHVTL_DBG(2, \"Looking for %d, Found drive %u\",\n\t\t\t\t\t  minor, indx);\n\t\t\tif (indx == minor) {\n\t\t\t\tfound = 1;\n\t\t\t\tmemcpy(ctl, &tmpctl, sizeof(tmpctl));\n\t\t\t}\n\t\t}\n\t\tif (indx == minor) {\n\t\t\tunsigned int c, d, e, f, g, h, j, k;\n\t\t\tint\t\t\t i;\n\n\t\t\tmemset(s, 0x20, MALLOC_SZ);\n\n\t\t\tif (sscanf(b, \" Unit serial number: %s\", s)) {\n\t\t\t\tcheckstrlen(s, SCSI_SN_LEN, linecount);\n\t\t\t\tsnprintf(lu->lu_serial_no, sizeof(lu->lu_serial_no), \"%-10s\", s);\n\t\t\t}\n\t\t\tif (sscanf(b, \" Vendor identification: %s\", s)) {\n\t\t\t\tcheckstrlen(s, VENDOR_ID_LEN, linecount);\n\t\t\t\tsnprintf(lu->vendor_id, VENDOR_ID_LEN + 1, \"%-8s\", s);\n\t\t\t\tsnprintf(&lu->inquiry[8], VENDOR_ID_LEN + 1, \"%-8s\", s);\n\t\t\t}\n\t\t\tif (sscanf(b, \" Product identification: %16c\", s)) {\n\t\t\t\t/* sscanf does not NULL terminate */\n\t\t\t\t/* 25 is len of ' Product identification: ' */\n\t\t\t\ts[strlen(b) - 25] = '\\0';\n\t\t\t\tcheckstrlen(s, PRODUCT_ID_LEN, linecount);\n\t\t\t\tsnprintf(lu->product_id, PRODUCT_ID_LEN + 1, \"%-16s\", s);\n\t\t\t\tsnprintf(&lu->inquiry[16], PRODUCT_ID_LEN + 1, \"%-16s\", s);\n\t\t\t}\n\t\t\tif (sscanf(b, \" Product revision level: %s\", s)) {\n\t\t\t\tcheckstrlen(s, PRODUCT_REV_LEN, linecount);\n\t\t\t\tsnprintf(&lu->inquiry[32], PRODUCT_REV_LEN + 1, \"%-4s\", s);\n\t\t\t}\n\t\t\tif (sscanf(b, \" Library ID: %d\", &library_id)) {\n\t\t\t\tMHVTL_DBG(2, \"Library ID: %d\", library_id);\n\t\t\t}\n\t\t\tif (sscanf(b, \" LBP RSCRC BE: %d\", &lbp_rscrc_be)) {\n\t\t\t\tMHVTL_DBG(2, \"Logical Block Protection RSCRC: %d\", lbp_rscrc_be);\n\t\t\t}\n\t\t\tif (sscanf(b, \" Backoff: %d\", &i)) {\n\t\t\t\tif ((i > 1) && (i < 10000)) {\n\t\t\t\t\tMHVTL_DBG(1, \"Backoff value: %d\", i);\n\t\t\t\t\tbackoff = i;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (sscanf(b, \" Compression type: %s\", s)) {\n\t\t\t\tif (!strncasecmp(s, \"lzo\", 3))\n\t\t\t\t\tlu_ssc.compressionType = LZO;\n\t\t\t\tif (!strncasecmp(s, \"zlib\", 4))\n\t\t\t\t\tlu_ssc.compressionType = ZLIB;\n\t\t\t\tMHVTL_DBG(2, \"Compression set to %s\",\n\t\t\t\t\t\t  (lu_ssc.compressionType == LZO) ? \"LZO\" : \"ZLIB\");\n\t\t\t}\n\t\t\tif (sscanf(b, \" Compression: factor %d enabled %d\",\n\t\t\t\t\t   &i, &j)) {\n\t\t\t\tlu_ssc.configCompressionFactor\t= i;\n\t\t\t\tlu_ssc.configCompressionEnabled = j;\n\t\t\t} else if (sscanf(b, \" Compression: %d\", &i)) {\n\t\t\t\tif ((i > Z_NO_COMPRESSION) && (i <= Z_BEST_COMPRESSION))\n\t\t\t\t\tlu_ssc.configCompressionFactor = i;\n\t\t\t\telse\n\t\t\t\t\tlu_ssc.configCompressionFactor = 0;\n\t\t\t}\n\t\t\tif (sscanf(b, \" fifo: %s\", s))\n\t\t\t\tprocess_fifoname(lu, s, 0);\n\t\t\ti = sscanf(b,\n\t\t\t\t\t   \" NAA: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\",\n\t\t\t\t\t   &c, &d, &e, &f, &g, &h, &j, &k);\n\t\t\tif (i == 8) {\n\t\t\t\tfree(lu->naa);\n\t\t\t\tlu->naa = zalloc(48);\n\t\t\t\tif (lu->naa)\n\t\t\t\t\tsprintf((char *)lu->naa,\n\t\t\t\t\t\t\t\"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\",\n\t\t\t\t\t\t\tc, d, e, f, g, h, j, k);\n\t\t\t\tMHVTL_DBG(2, \"Setting NAA: to %s\", lu->naa);\n\t\t\t} else if (i > 0) {\n\t\t\t\tint y;\n\n\t\t\t\tfree(lu->naa);\n\t\t\t\tlu->naa = NULL;\n\t\t\t\tfor (y = 0; y < MALLOC_SZ; y++)\n\t\t\t\t\tif (b[y] == '\\n')\n\t\t\t\t\t\tb[y] = 0;\n\t\t\t\tMHVTL_DBG(1, \"NAA: Incorrect params %s\"\n\t\t\t\t\t\t\t \" : using defaults\",\n\t\t\t\t\t\t  b);\n\t\t\t}\n\t\t}\n\t}\n\tfclose(conf);\n\tfree(b);\n\tfree(s);\n\n\tif (found && !lu->inquiry[32]) {\n\t\tchar *v;\n\n\t\t/* Default rev with mhvtl release info */\n\t\tv = get_version();\n\t\tMHVTL_DBG(1, \"Adding default vers info: %s\", v);\n\t\tsnprintf(&lu->inquiry[32], PRODUCT_REV_LEN + 1, \"%-4s\", v);\n\t\tfree(v);\n\t}\n\n\t/* Unit Serial Number */\n\tlu_vpd[PCODE_OFFSET(0x80)] = alloc_vpd(strlen(lu->lu_serial_no));\n\tupdate_vpd_80(lu, lu->lu_serial_no);\n\n\t/* Device Identification */\n\tlu_vpd[PCODE_OFFSET(0x83)] = alloc_vpd(VPD_83_SZ);\n\tupdate_vpd_83(lu, NULL);\n\n\tif (library_id)\n\t\tfind_media_home_directory(NULL, library_id);\n\n\tif ((backoff < 10) || (backoff > 10000)) {\n\t\tbackoff = DEFLT_BACKOFF_VALUE;\n\t\tMHVTL_LOG(\"Set default backoff value to %ld\", backoff);\n\t}\n\n\treturn found;\n}\n\nstatic void process_cmd(int cdev, uint8_t *buf, struct mhvtl_header *mhvtl_cmd,\n\t\t\t\t\t\tuseconds_t pollInterval) {\n\tstruct mhvtl_ds dbuf;\n\tuint8_t\t\t   *cdb;\n\n\t/* Get the SCSI cdb from vtl driver\n\t * - Returns SCSI command S/No. */\n\n\tcdb = (uint8_t *)&mhvtl_cmd->cdb;\n\n\t/* Interpret the SCSI command & process\n\t-> Returns no. of bytes to send back to kernel\n\t */\n\tdbuf.sz\t\t   = 0;\n\tdbuf.serialNo  = mhvtl_cmd->serialNo;\n\tdbuf.data\t   = buf;\n\tdbuf.sam_stat  = lu_ssc.sam_status;\n\tdbuf.sense_buf = &sense;\n\n\tprocessCommand(cdev, cdb, &dbuf, pollInterval);\n\n\t/* Complete SCSI cmd processing */\n\tcompleteSCSICommand(cdev, &dbuf);\n\n\t/* dbuf.sam_stat was zeroed in completeSCSICommand */\n\tlu_ssc.sam_status = dbuf.sam_stat;\n}\n\nstatic void init_lu_ssc(struct priv_lu_ssc *lu_priv) {\n\tlu_priv->bufsize\t\t\t\t = 2 * 1024 * 1024;\n\tlu_priv->load_status\t\t\t = TAPE_UNLOADED;\n\tlu_priv->inLibrary\t\t\t\t = 0;\n\tlu_priv->sam_status\t\t\t\t = SAM_STAT_GOOD;\n\tlu_priv->MediaWriteProtect\t\t = MEDIA_WRITABLE;\n\tlu_priv->capacity_unit\t\t\t = 1;\n\tlu_priv->configCompressionFactor = Z_BEST_SPEED;\n\tlu_priv->bytesRead_I\t\t\t = 0;\n\tlu_priv->bytesRead_M\t\t\t = 0;\n\tlu_priv->bytesWritten_I\t\t\t = 0;\n\tlu_priv->bytesWritten_M\t\t\t = 0;\n\tlu_priv->c_pos\t\t\t\t\t = c_pos;\n\tlu_priv->KEY_INSTANCE_COUNTER\t = 0;\n\tlu_priv->DECRYPT_MODE\t\t\t = 0;\n\tlu_priv->ENCRYPT_MODE\t\t\t = 0;\n\tlu_priv->app_encr_info\t\t\t = &app_encryption_state;\n\tlu_priv->OK_2_write\t\t\t\t = &OK_to_write;\n\tlu_priv->barcode\t\t\t\t = NULL;\n\tlu_priv->mamp\t\t\t\t\t = &mam;\n\tINIT_LIST_HEAD(&lu_priv->supported_media_list);\n\tlu_priv->pm\t\t   = NULL;\n\tlu_priv->state_msg = NULL;\n\n\tcumul_pollInterval = 0L;\n\n\tlu_priv->delay_load\t\t= 0;\n\tlu_priv->delay_unload\t= 0;\n\tlu_priv->delay_thread\t= 0;\n\tlu_priv->delay_position = 0;\n\tlu_priv->delay_rewind\t= 0;\n}\n\n/*\n * Be nice and free all malloc() on exit\n */\nstatic void cleanup_lu(struct lu_phy_attr *lu) {\n\tint i;\n\n\t/* Free all VPD pages */\n\tfor (i = 0x80; i < 0x100; i++) {\n\t\tif (lu->lu_vpd[PCODE_OFFSET(i)]) {\n\t\t\tdealloc_vpd(lu->lu_vpd[PCODE_OFFSET(i)]);\n\t\t\tlu->lu_vpd[PCODE_OFFSET(i)] = NULL;\n\t\t}\n\t}\n\n\tdealloc_all_mode_pages(lu);\n\tdealloc_all_log_pages(lu);\n\n\tcleanup_drive_media_list(lu);\n\tcleanup_density_support(&lu->den_list);\n\n\tfree(lu->naa);\n\n\tcart_deinit();\n}\n\nvoid ssc_personality_module_register(struct ssc_personality_template *pm) {\n\tMHVTL_DBG(2, \"%s\", pm->name);\n\tlu_ssc.pm = pm;\n\n\tif (pm->drive_supports_SP) {\n\t\tregister_ops(pm->lu, SECURITY_PROTOCOL_IN,\n\t\t\t\t\t ssc_spin, NULL, NULL);\n\t\tregister_ops(pm->lu, SECURITY_PROTOCOL_OUT,\n\t\t\t\t\t ssc_spout, NULL, NULL);\n\t}\n\tif (pm->drive_supports_SPR) {\n\t\tregister_ops(pm->lu, PERSISTENT_RESERVE_IN,\n\t\t\t\t\t ssc_pr_in, NULL, NULL);\n\t\tregister_ops(pm->lu, PERSISTENT_RESERVE_OUT,\n\t\t\t\t\t ssc_pr_out, NULL, NULL);\n\t}\n}\n\nstatic void caught_signal(int signo) {\n\tprintf(\"Please use 'vtlcmd <index> exit' to shutdown nicely\\n\"\n\t\t   \" Received signal: %d\\n\\n\",\n\t\t   signo);\n\tMHVTL_LOG(\"Please use 'vtlcmd <index> exit' to shutdown nicely,\"\n\t\t\t  \" Received signal: %d\",\n\t\t\t  signo);\n}\n\nint main(int argc, char *argv[]) {\n\tint\t\t\t\t cdev;\n\tint\t\t\t\t ret;\n\tint\t\t\t\t last_state = MHVTL_STATE_UNKNOWN;\n\tuseconds_t\t\t sleep_time = 50000L; /* Used as backoff counter */\n\tuint8_t\t\t\t*buf;\n\tpid_t\t\t\t child_cleanup, pid, ppid, sid;\n\tstruct sigaction new_action, old_action;\n\tint\t\t\t\t fifo_retval;\n\tint\t\t\t\t opt;\n\tint\t\t\t\t foreground\t  = 0;\n\tconst pid_t\t\t not_started  = -2;\n\tint\t\t\t\t time_to_exit = 0;\n\n\tchar\t   *progname = argv[0];\n\tchar\t   *fifoname = NULL;\n\tconst char *name\t = \"mhvtl\";\n\tunsigned\tminor\t = 0;\n\n\tstruct mhvtl_header\t mhvtl_cmd;\n\tstruct mhvtl_header *cmd;\n\tstruct mhvtl_ctl\t ctl;\n\n\t/* Message Q */\n\tint mlen, r_qid;\n\n\tmemset(&mhvtl_cmd, 0, sizeof(struct mhvtl_header));\n\tmemset(&ctl, 0, sizeof(struct mhvtl_ctl));\n\n\tcurrent_state = MHVTL_STATE_INIT;\n\n\twhile ((opt = getopt(argc, argv, \"dv::q:f::F\")) != -1) {\n\t\tswitch (opt) {\n\t\tcase 'd':\n\t\t\t/* If debug, make verbose... */\n\t\t\tdebug\t   = 4;\n\t\t\tverbose\t   = 9;\n\t\t\tforeground = 1;\n\t\t\tbreak;\n\t\tcase 'v':\n\t\t\tif (optarg)\n\t\t\t\tverbose = atoi(optarg);\n\t\t\telse\n\t\t\t\tverbose++;\n\t\t\t/* limit verbosity to single digit */\n\t\t\tif (verbose > 9)\n\t\t\t\tverbose = 9;\n\t\t\tbreak;\n\t\tcase 'q':\n\t\t\tmy_id = atoi(optarg);\n\t\t\tif ((my_id < 0) || (my_id > MAXPRIOR)) {\n\t\t\t\tfprintf(stderr, \"error: queue ID out of range [1..%u]\\n\",\n\t\t\t\t\t\tMAXPRIOR);\n\t\t\t\tusage(progname);\n\t\t\t\texit(1);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'f':\n\t\t\tif (optarg)\n\t\t\t\tfifoname = strdup(optarg);\n\t\t\tbreak;\n\t\tcase 'F':\n\t\t\tforeground = 1;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tusage(progname);\n\t\t\texit(1);\n\t\t}\n\t}\n\n\tif (my_id < 0) {\n\t\tfprintf(stderr, \"error: must supply queue ID\\n\");\n\t\tusage(progname);\n\t\texit(1);\n\t}\n\n\tminor = my_id; /* Minor == Message Queue priority */\n\n\topenlog(progname, LOG_PID, LOG_DAEMON | LOG_WARNING);\n\n\tif (check_for_running_daemons(minor)) {\n\t\tprintf(\"check_for_running_daemons(%d) returned true\\n\", minor);\n\t\tMHVTL_LOG(\"%s: version %s %s %s, found another running daemon... exiting\", progname, MHVTL_VERSION, MHVTL_GITHASH, MHVTL_GITDATE);\n\t\texit(2);\n\t} else {\n\t\tMHVTL_DBG(1, \"No lock file found... Continuing\");\n\t}\n\n\tif (lzo_init() != LZO_E_OK) {\n\t\tMHVTL_ERR(\"Could not initialize LZO... Exiting\");\n\t\texit(1);\n\t}\n\n\t/* Clear Sense arr */\n\tmemset(sense, 0, sizeof(sense));\n\n\t/* Powered on / reset flag */\n\treset_device();\n\n\t/* Initialise lu_ssc 'global vars' used by this daemon */\n\tinit_lu_ssc(&lu_ssc);\n\n\tlunit.lu_private = &lu_ssc;\n\n\t/* Parse config file and build up each device */\n\tif (!init_lu(&lunit, minor, &ctl)) {\n\t\tfprintf(stderr, \"error: Can not find entry for '%u' in config file\\n\",\n\t\t\t\tminor);\n\t\texit(1);\n\t}\n\n\t/*\n\t * Determine drive type\n\t * register personality module\n\t * Indirectly, mode page tables are initialised\n\t */\n\tconfig_lu(&lunit);\n\n\tif (chrdev_create(minor)) {\n\t\tMHVTL_DBG(1, \"Unable to create device node mhvtl%u\", minor);\n\t\texit(1);\n\t}\n\n\t/* Initialise message queue as necessary */\n\tif ((r_qid = init_queue()) == -1) {\n\t\tfprintf(stderr, \"error: Could not initialise message queue\\n\");\n\t\texit(1);\n\t}\n\n\tcdev = chrdev_open(name, minor);\n\tif (cdev == -1) {\n\t\tMHVTL_ERR(\"Could not open /dev/%s%u: %s\", name, minor, strerror(errno));\n\t\tfflush(NULL);\n\t\texit(1);\n\t}\n\n\tbuf = (uint8_t *)zalloc(lu_ssc.bufsize);\n\tif (NULL == buf) {\n\t\tperror(\"Problems allocating memory\");\n\t\texit(1);\n\t}\n\n\tif ((chdir(MHVTL_HOME_PATH)) < 0) {\n\t\tperror(\"Unable to change directory to \" MHVTL_HOME_PATH);\n\t\texit(-1);\n\t}\n\n\t/* If debug or 'F' specified don't fork/run in background */\n\tif (!foreground) {\n\t\tppid = getpid();\n\n\t\tswitch (pid = fork()) {\n\t\tcase 0: /* Child */\n\t\t\tbreak;\n\t\tcase -1:\n\t\t\tperror(\"Failed to fork daemon\");\n\t\t\texit(-1);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tMHVTL_DBG(1, \"Parent PID: %ld successfully started daemon: PID %ld\",\n\t\t\t\t\t  (long)ppid, (long)pid);\n\t\t\texit(0);\n\t\t\tbreak;\n\t\t}\n\n\t\tumask(0); /* Change the file mode mask */\n\n\t\tsid = setsid();\n\t\tif (sid < 0)\n\t\t\texit(-1);\n\n\t\tclose(STDIN_FILENO);\n\t\tclose(STDERR_FILENO);\n\t}\n\n\tMHVTL_LOG(\"[%ld] Started %s: version %s %s %s verbose log lvl: %d, lu [%d:%d:%d]\",\n\t\t\t  (long)getpid(), progname, MHVTL_VERSION, MHVTL_GITHASH, MHVTL_GITDATE, verbose,\n\t\t\t  ctl.channel, ctl.id, ctl.lun);\n\tMHVTL_DBG(1, \"Size of buffer is %d\", lu_ssc.bufsize);\n\n#ifdef __x86_64__\n\tif (__builtin_cpu_supports(\"sse4.2\")) {\n\t\tMHVTL_DBG(1, \"crc32c using Intel sse4.2 hardware optimization\");\n\t} else {\n\t\tMHVTL_DBG(1, \"crc32c not using Intel sse4.2 optimization\");\n\t}\n#endif\n\n\toom_adjust();\n\n\tnew_action.sa_handler = caught_signal;\n\tnew_action.sa_flags\t  = 0;\n\tsigemptyset(&new_action.sa_mask);\n\tsigaction(SIGALRM, &new_action, &old_action);\n\tsigaction(SIGHUP, &new_action, &old_action);\n\tsigaction(SIGINT, &new_action, &old_action);\n\tsigaction(SIGPIPE, &new_action, &old_action);\n\tsigaction(SIGTERM, &new_action, &old_action);\n\tsigaction(SIGUSR1, &new_action, &old_action);\n\tsigaction(SIGUSR2, &new_action, &old_action);\n\n\t/* If fifoname passed as switch */\n\tif (fifoname)\n\t\tprocess_fifoname(&lunit, fifoname, 1);\n\t/* fifoname can be defined in device.conf */\n\tif (lunit.fifoname)\n\t\topen_fifo(&lunit.fifo_fd, lunit.fifoname);\n\n\tfifo_retval = inc_fifo_count();\n\tif (fifo_retval == -ENOMEM) {\n\t\tMHVTL_ERR(\"shared memory setup failed - exiting...\");\n\t\tgoto exit;\n\t} else if (fifo_retval < 0) {\n\t\tMHVTL_ERR(\"Failed to set fifo count()...\");\n\t}\n\n\tchild_cleanup = not_started;\n\n\tfor (;;) {\n\t\t/* Check for anything in the messages Q */\n\t\tmlen = msgrcv(r_qid, &lu_ssc.r_entry, MAXOBN, my_id, IPC_NOWAIT);\n\t\tif (mlen > 0) {\n\t\t\tif (processMessageQ(&lu_ssc.r_entry.msg, &lu_ssc.sam_status)) {\n\t\t\t\ttime_to_exit = 1; /* Flag that we need to exit */\n\t\t\t\tMHVTL_DBG(1, \"Exit called\");\n\t\t\t}\n\t\t} else if (mlen < 0) {\n\t\t\tif ((r_qid = init_queue()) == -1) {\n\t\t\t\tMHVTL_ERR(\"Can not open message queue: %s\",\n\t\t\t\t\t\t  strerror(errno));\n\t\t\t}\n\t\t}\n\t\tret = ioctl(cdev, VTL_POLL_AND_GET_HEADER, &mhvtl_cmd);\n\t\tif (ret < 0) {\n\t\t\tMHVTL_DBG(2,\n\t\t\t\t\t  \"ioctl(VTL_POLL_AND_GET_HEADER): %d : %s\",\n\t\t\t\t\t  ret, strerror(errno));\n\t\t} else {\n\t\t\tif (debug)\n\t\t\t\tprintf(\"ioctl(VX_TAPE_POLL_STATUS) \"\n\t\t\t\t\t   \"returned: %d, interval: %ld\\n\",\n\t\t\t\t\t   ret, (long)sleep_time);\n\t\t\tif (child_cleanup) {\n\t\t\t\tif (child_cleanup == not_started) {\n\t\t\t\t\tchild_cleanup = add_lu(my_id, &ctl);\n\t\t\t\t\tif (!child_cleanup) {\n\t\t\t\t\t\tMHVTL_ERR(\"Failed to create logical unit - exiting...\");\n\t\t\t\t\t\tgoto exit;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (waitpid(child_cleanup, NULL, WNOHANG)) {\n\t\t\t\t\tMHVTL_DBG(1,\n\t\t\t\t\t\t\t  \"[%ld] Cleaning up after add_lu \"\n\t\t\t\t\t\t\t  \"child pid: %d\",\n\t\t\t\t\t\t\t  (long)getpid(), child_cleanup);\n\t\t\t\t\tchild_cleanup = 0;\n\t\t\t\t} else {\n\t\t\t\t\tMHVTL_DBG(2, \"[%ld] Child cleanup of %ld still outstanding\", (long)getpid(), (long)child_cleanup);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (debug)\n\t\t\t\tfflush(NULL);\n\t\t\tswitch (ret) {\n\t\t\tcase VTL_QUEUE_CMD: /* A cdb to process */\n\t\t\t\tcmd = malloc(sizeof(struct mhvtl_header));\n\t\t\t\tif (!cmd) {\n\t\t\t\t\tMHVTL_ERR(\"Out of memory\");\n\t\t\t\t\tsleep_time = 1000000;\n\t\t\t\t} else {\n\t\t\t\t\tmemcpy(cmd, &mhvtl_cmd, sizeof(mhvtl_cmd));\n\t\t\t\t\tprocess_cmd(cdev, buf, cmd, sleep_time);\n\t\t\t\t\t/* Something to do, reduce poll time */\n\t\t\t\t\tsleep_time = MIN_SLEEP_TIME;\n\t\t\t\t\tfree(cmd);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase VTL_IDLE:\n\t\t\t\tusleep(sleep_time);\n\n\t\t\t\t/* While nothing to do, increase\n\t\t\t\t * time we sleep before polling again.\n\t\t\t\t */\n\t\t\t\tif (sleep_time < 1000000)\n\t\t\t\t\tsleep_time += backoff;\n\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tMHVTL_LOG(\"ioctl(0x%x) returned %d\",\n\t\t\t\t\t\t  VTL_POLL_AND_GET_HEADER, ret);\n\t\t\t\tsleep(1);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (current_state != last_state) {\n\t\t\t\tstatus_change(lunit.fifo_fd,\n\t\t\t\t\t\t\t  current_state,\n\t\t\t\t\t\t\t  my_id,\n\t\t\t\t\t\t\t  &lu_ssc.state_msg);\n\t\t\t\tlast_state = current_state;\n\t\t\t}\n\t\t\tif (sleep_time > 0xf000) {\n\t\t\t\tif (sleep_time < (0xf000 + backoff)) {\n\t\t\t\t\tif (get_tape_load_status() == TAPE_LOADED)\n\t\t\t\t\t\tset_current_state(MHVTL_STATE_LOADED_IDLE);\n\t\t\t\t\telse\n\t\t\t\t\t\tset_current_state(MHVTL_STATE_IDLE);\n\t\t\t\t}\n\t\t\t\tif (time_to_exit) /* enough cycles to ensure no outstanding work remains */\n\t\t\t\t\tgoto exit;\n\t\t\t}\n\t\t}\n\t}\n\nexit:\n\tioctl(cdev, VTL_REMOVE_LU, &ctl);\n\tcleanup_lu(&lunit);\n\tclose(cdev);\n\tfree(buf);\n\tdec_fifo_count();\n\tif (lunit.fifo_fd) {\n\t\tfclose(lunit.fifo_fd);\n\t\tunlink(lunit.fifoname);\n\t\tfree(lunit.fifoname);\n\t}\n\tfree_lock(minor);\n\texit(0);\n}\n"
  },
  {
    "path": "usr/mhvtl_io.c",
    "content": "/*\n * mhvtl_io.c\n *\n * deduplicate code - Move Read/Write routines\n *\n * dump_tape / vtltape both use same functions\n * which are currently duplicated\n */\n#include <stdio.h>\n#include <stdlib.h>\n#include <errno.h>\n#include <sys/types.h>\n#include <string.h>\n#include <inttypes.h>\n#include \"be_byteshift.h\"\n#include \"vtl_common.h\"\n#include \"mhvtl_scsi.h\"\n#include \"logging.h\"\n#include \"vtllib.h\"\n#include \"vtlcart.h\"\n#include \"ssc.h\"\n#include \"mhvtl_log.h\"\n#include \"ccan/crc32c/crc32c.h\"\n#include <zlib.h>\n#include \"minilzo.h\"\n\nuint32_t GenerateRSCRC(uint32_t crc, uint32_t size, const void *buf);\nuint32_t BlockVerifyRSCRC(const uint8_t *blkbuf, uint32_t blklen, int32_t bigendian);\nuint32_t BlockProtectRSCRC(uint8_t *blkbuf, uint32_t blklen, int32_t bigendian);\n\nstatic void\nmk_sense_short_block(uint32_t requested, uint32_t processed, uint8_t *sense_valid) {\n\tint difference = (int)requested - (int)processed;\n\n\t/* No sense, ILI bit set */\n\tsam_no_sense(SD_ILI, NO_ADDITIONAL_SENSE, sense_valid);\n\n\tMHVTL_DBG(2, \"Short block read: Requested: %d, Read: %d,\"\n\t\t\t\t \" short by %d bytes\",\n\t\t\t  requested, processed, difference);\n\n\t/* Now fill in the datablock with number of bytes not read/written */\n\tput_unaligned_be32(difference, &sense[3]);\n}\n\nstatic int uncompress_lzo_block(uint8_t *buf, uint32_t tgtsize, uint8_t *sam_stat) {\n\tuint8_t *cbuf, *c2buf;\n\tuint32_t disk_blk_size, blk_size;\n\tint\t\t rc, z;\n\tloff_t\t nread = 0;\n\tlzo_uint uncompress_sz;\n\n\t/* The tape block is compressed.\n\t   Save field values we will need after the read which\n\t   causes the tape block to advance.\n\t*/\n\tblk_size\t  = c_pos->blk_size;\n\tdisk_blk_size = c_pos->disk_blk_size;\n\n\t/* Malloc a buffer to hold the compressed data, and read the\n\t   data into it.\n\t*/\n\tcbuf = (uint8_t *)malloc(disk_blk_size);\n\tif (!cbuf) {\n\t\tMHVTL_ERR(\"Out of memory: %d\", __LINE__);\n\t\tsam_medium_error(E_DECOMPRESSION_CRC, sam_stat);\n\t\treturn 0;\n\t}\n\n\t/* Can't reference c_pos after this point\n\t * read_tape_block increments c_pos to next block header\n\t */\n\tnread = read_tape_block(cbuf, disk_blk_size, sam_stat);\n\tif (nread != disk_blk_size) {\n\t\tMHVTL_ERR(\"read failed, %s\", strerror(errno));\n\t\tsam_medium_error(E_UNRECOVERED_READ, sam_stat);\n\t\tfree(cbuf);\n\t\treturn 0;\n\t}\n\n\trc\t\t\t  = tgtsize;\n\tuncompress_sz = blk_size;\n\n\t/* If the scsi read buffer is at least as big as the size of\n\t   the uncompressed data then we can uncompress directly into\n\t   the read buffer.  If not, then we need an extra buffer to\n\t   uncompress into, then memcpy the subrange we need to the\n\t   read buffer.\n\t*/\n\n\tif (tgtsize >= blk_size) {\n\t\t/* block sizes match, uncompress directly into buf */\n\t\tz = lzo1x_decompress_safe(cbuf, disk_blk_size, buf, &uncompress_sz, NULL);\n\t} else {\n\t\t/* Initiator hasn't requested same size as data block */\n\t\tc2buf = (uint8_t *)malloc(uncompress_sz);\n\t\tif (c2buf == NULL) {\n\t\t\tMHVTL_ERR(\"Out of memory: %d\", __LINE__);\n\t\t\tsam_medium_error(E_DECOMPRESSION_CRC, sam_stat);\n\t\t\tfree(cbuf);\n\t\t\treturn 0;\n\t\t}\n\t\tz = lzo1x_decompress_safe(cbuf, disk_blk_size, c2buf, &uncompress_sz, NULL);\n\t\t/* Only copy out decompressed data on success; otherwise c2buf\n\t\t * contains uninitialized / partial data and would silently\n\t\t * corrupt the caller's read buffer. The switch (z) below will\n\t\t * set the appropriate sense for failure cases.\n\t\t */\n\t\tif (z == LZO_E_OK)\n\t\t\tmemcpy(buf, c2buf, tgtsize);\n\t\tfree(c2buf);\n\t}\n\n\tswitch (z) {\n\tcase LZO_E_OK:\n\t\tMHVTL_DBG(2, \"Read %u bytes of lzo compressed\"\n\t\t\t\t\t \" data, have %u bytes for result\",\n\t\t\t\t  (uint32_t)nread, blk_size);\n\t\tgoto complete;\n\t\tbreak;\n\tcase LZO_E_INPUT_NOT_CONSUMED:\n\t\tMHVTL_DBG(1, \"The end of compressed block has been detected before all %d bytes\", blk_size);\n\t\tbreak;\n\tcase LZO_E_INPUT_OVERRUN:\n\t\tMHVTL_ERR(\"The decompressor requested more bytes from the compressed block\");\n\t\tbreak;\n\tcase LZO_E_OUTPUT_OVERRUN:\n\t\tMHVTL_ERR(\"The decompressor requested to write more bytes than the uncompressed block can hold\");\n\t\tbreak;\n\tcase LZO_E_LOOKBEHIND_OVERRUN:\n\t\tMHVTL_ERR(\"Look behind overrun - data is corrupted\");\n\t\tbreak;\n\tcase LZO_E_EOF_NOT_FOUND:\n\t\tMHVTL_ERR(\"No EOF code was found in the compressed block\");\n\t\tbreak;\n\tcase LZO_E_ERROR:\n\t\tMHVTL_ERR(\"Data is corrupt - generic lzo error received\");\n\t\tbreak;\n\t}\n\n\tsam_medium_error(E_DECOMPRESSION_CRC, sam_stat);\n\trc = 0;\n\ncomplete:\n\tfree(cbuf);\n\n\treturn rc;\n}\n\nstatic int uncompress_zlib_block(uint8_t *buf, uint32_t tgtsize, uint8_t *sam_stat) {\n\tuint8_t *cbuf, *c2buf;\n\tloff_t\t nread = 0;\n\tuLongf\t uncompress_sz;\n\tuint32_t disk_blk_size, blk_size;\n\tint\t\t rc, z;\n\n\t/* The tape block is compressed.\n\t   Save field values we will need after the read which\n\t   causes the tape block to advance.\n\t*/\n\tblk_size\t  = c_pos->blk_size;\n\tdisk_blk_size = c_pos->disk_blk_size;\n\n\t/* Malloc a buffer to hold the compressed data, and read the\n\t   data into it.\n\t*/\n\tcbuf = (uint8_t *)malloc(disk_blk_size);\n\tif (!cbuf) {\n\t\tMHVTL_ERR(\"Out of memory: %d\", __LINE__);\n\t\tsam_medium_error(E_DECOMPRESSION_CRC, sam_stat);\n\t\treturn 0;\n\t}\n\n\tnread = read_tape_block(cbuf, disk_blk_size, sam_stat);\n\tif (nread != disk_blk_size) {\n\t\tMHVTL_ERR(\"read failed, %s\", strerror(errno));\n\t\tsam_medium_error(E_UNRECOVERED_READ, sam_stat);\n\t\tfree(cbuf);\n\t\treturn 0;\n\t}\n\n\trc\t\t\t  = tgtsize;\n\tuncompress_sz = blk_size;\n\n\t/* If the scsi read buffer is at least as big as the size of\n\t   the uncompressed data then we can uncompress directly into\n\t   the read buffer.  If not, then we need an extra buffer to\n\t   uncompress into, then memcpy the subrange we need to the\n\t   read buffer.\n\t*/\n\n\tif (tgtsize >= blk_size) {\n\t\t/* block sizes match, uncompress directly into buf */\n\t\tz = uncompress(buf, &uncompress_sz, cbuf, disk_blk_size);\n\t} else {\n\t\t/* Initiator hasn't requested same size as data block */\n\t\tc2buf = (uint8_t *)malloc(uncompress_sz);\n\t\tif (c2buf == NULL) {\n\t\t\tMHVTL_ERR(\"Out of memory: %d\", __LINE__);\n\t\t\tsam_medium_error(E_DECOMPRESSION_CRC, sam_stat);\n\t\t\tfree(cbuf);\n\t\t\treturn 0;\n\t\t}\n\t\tz = uncompress(c2buf, &uncompress_sz, cbuf, disk_blk_size);\n\t\t/* Only copy out decompressed data on success; otherwise c2buf\n\t\t * contains uninitialized / partial data and would silently\n\t\t * corrupt the caller's read buffer. The switch (z) below will\n\t\t * set the appropriate sense for failure cases.\n\t\t */\n\t\tif (z == Z_OK)\n\t\t\tmemcpy(buf, c2buf, tgtsize);\n\t\tfree(c2buf);\n\t}\n\n\tswitch (z) {\n\tcase Z_OK:\n\t\tMHVTL_DBG(2, \"Read %u bytes of zlib compressed\"\n\t\t\t\t\t \" data, have %u bytes for result\",\n\t\t\t\t  (uint32_t)nread, blk_size);\n\t\tbreak;\n\tcase Z_MEM_ERROR:\n\t\tMHVTL_ERR(\"Not enough memory to decompress\");\n\t\tsam_medium_error(E_DECOMPRESSION_CRC, sam_stat);\n\t\trc = 0;\n\t\tbreak;\n\tcase Z_DATA_ERROR:\n\t\tMHVTL_ERR(\"Block corrupt or incomplete\");\n\t\tsam_medium_error(E_DECOMPRESSION_CRC, sam_stat);\n\t\trc = 0;\n\t\tbreak;\n\tcase Z_BUF_ERROR:\n\t\tMHVTL_ERR(\"Not enough memory in destination buf\");\n\t\tsam_medium_error(E_DECOMPRESSION_CRC, sam_stat);\n\t\trc = 0;\n\t\tbreak;\n\t}\n\n\tfree(cbuf);\n\n\treturn rc;\n}\n\n/* CRC32C */\nstatic uint32_t mhvtl_crc32c(unsigned char const *buf, size_t size) {\n\treturn crc32c(0, buf, size);\n}\n\n/*\n * Return number of bytes read.\n *        0 on error with sense[] filled in...\n */\nint readBlock(uint8_t *buf, uint32_t request_sz, int sili, int lbp_method, uint8_t *sam_stat) {\n\tuint32_t disk_blk_size, blk_size, blk_number;\n\tuint32_t rc;\n\tuint32_t save_sense;\n\tuint32_t pre_crc;\n\tuint32_t blk_flags;\n\tuint32_t post_crc;\n\tuint32_t lbp_crc;\n\tuint8_t *bounce_buffer;\n\tint\t\t lbp_sz;\n\n\tMHVTL_DBG(3, \"Request to read: %u bytes at partition/header %u/%u, SILI: %d, LBP_method: %s\",\n\t\t\t  request_sz, c_pos->partition_id, c_pos->blk_number, sili,\n\t\t\t  (lbp_method == 0) ? \"None\" : (lbp_method == 1) ? \"RS-CRC\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t : \"CRC32c\");\n\n\t/* check for a zero length read\n\t * This is not an error, and shouldn't change the tape position */\n\tif (request_sz == 0)\n\t\treturn 0;\n\n\t/** Note: lbp_method will only be set if LBP_R is also set.\n\t ** Logical Block Protection - account for 4 byte CRC\n\t **/\n\tlbp_sz = (lbp_method) ? request_sz - 4 : request_sz;\n\n\tswitch (c_pos->blk_type) {\n\tcase B_DATA:\n\t\tbreak;\n\tcase B_FILEMARK:\n\t\tMHVTL_DBG(1, \"Expected to find DATA header, found: FILEMARK\");\n\t\tposition_blocks_forw(1, sam_stat);\n\t\tmk_sense_short_block(lbp_sz, 0, sam_stat);\n\t\tsave_sense = get_unaligned_be32(&sense[3]);\n\t\tsam_no_sense(SD_FILEMARK, E_MARK, sam_stat);\n\t\tput_unaligned_be32(save_sense, &sense[3]);\n\t\treturn 0;\n\t\tbreak;\n\tcase B_EOD:\n\t\tMHVTL_DBG(1, \"Expected to find DATA header, found: EOD\");\n\t\tmk_sense_short_block(lbp_sz, 0, sam_stat);\n\t\tsave_sense = get_unaligned_be32(&sense[3]);\n\t\tsam_blank_check(E_END_OF_DATA, sam_stat);\n\t\tput_unaligned_be32(save_sense, &sense[3]);\n\t\treturn 0;\n\t\tbreak;\n\tdefault:\n\t\tMHVTL_ERR(\"Unknown blk header at offset %u\"\n\t\t\t\t  \" - Abort read cmd\",\n\t\t\t\t  c_pos->blk_number);\n\t\tsam_medium_error(E_UNRECOVERED_READ, sam_stat);\n\t\treturn 0;\n\t\tbreak;\n\t}\n\n\t/* The tape block is compressed.  Save field values we will need after\n\t   the read causes the tape block to advance.\n\t*/\n\tblk_size\t  = c_pos->blk_size;\n\tblk_number\t  = c_pos->blk_number;\n\tdisk_blk_size = c_pos->disk_blk_size;\n\tpre_crc\t\t  = c_pos->uncomp_crc;\n\tblk_flags\t  = c_pos->blk_flags;\n\n\tif (blk_size > request_sz) {\n\t\t/* Add a fudge of 4 bytes in case LBP is calculated */\n\t\tbounce_buffer = malloc(blk_size + 4);\n\t\tif (!bounce_buffer) {\n\t\t\tMHVTL_ERR(\"Unable to allocate %d bytes for bounce buffer\",\n\t\t\t\t\t  blk_size);\n\t\t\tsam_medium_error(E_UNRECOVERED_READ, sam_stat);\n\t\t\treturn 0;\n\t\t}\n\t} else {\n\t\tbounce_buffer = buf;\n\t}\n\n\tif (blk_flags & BLKHDR_FLG_LZO_COMPRESSED)\n\t\trc = uncompress_lzo_block(bounce_buffer, blk_size, sam_stat);\n\telse if (blk_flags & BLKHDR_FLG_ZLIB_COMPRESSED)\n\t\trc = uncompress_zlib_block(bounce_buffer, blk_size, sam_stat);\n\telse {\n\t\t/* If the tape block is uncompressed, we can read the number of bytes\n\t\t   we need directly into the scsi read buffer and we are done.\n\t\t*/\n\t\tif (read_tape_block(bounce_buffer, blk_size, sam_stat) != blk_size) {\n\t\t\tMHVTL_ERR(\"read failed, %s\", strerror(errno));\n\t\t\tsam_medium_error(E_UNRECOVERED_READ, sam_stat);\n\t\t\tgoto free_bounce_buf;\n\t\t}\n\t\trc = blk_size;\n\t}\n\n\t/* At this point, rc should now contain the actual uncompressed size of the block just read */\n\n\tif (blk_flags & BLKHDR_FLG_CRC) {\n\t\tpost_crc = mhvtl_crc32c(bounce_buffer, rc);\n\n\t\tif (pre_crc != post_crc) {\n\t\t\tMHVTL_ERR(\"Recorded CRC: 0x%08x, Calculated CRC: 0x%08x\", pre_crc, post_crc);\n\t\t\tsam_medium_error(E_DECOMPRESSION_CRC, sam_stat);\n\t\t\tgoto free_bounce_buf;\n\t\t}\n\t\tMHVTL_DBG(3, \"Recorded CRC: 0x%08x, calculated CRC: 0x%08x\", pre_crc, post_crc);\n\t}\n\n\t/* Update Logical Block Protection CRC */\n\tswitch (lbp_method) {\n\tcase 1:\n\t\trc = BlockProtectRSCRC(bounce_buffer, rc, lbp_rscrc_be);\n\t\tif (rc == 0) {\n\t\t\tMHVTL_ERR(\"Failed to generate/append RSCRC: lbp_be: %d\", lbp_rscrc_be);\n\t\t}\n\t\tMHVTL_DBG(2, \"READ block %d LBP RSCRC : 0x%02x 0x%02x 0x%02x 0x%02x\", blk_number, bounce_buffer[rc - 4], bounce_buffer[rc - 3], bounce_buffer[rc - 2], bounce_buffer[rc - 1]);\n\t\tbreak;\n\tcase 2:\n\t\tMHVTL_DBG(2, \"rc: %d, request_sz: %d bounce buffer before LBP: 0x%08x %08x\", rc, request_sz, get_unaligned_be32(&bounce_buffer[rc - 4]), get_unaligned_be32(&bounce_buffer[rc]));\n\t\t/* If we don't have a LBP CRC32C format, re-calculate now */\n\t\tlbp_crc = (blk_flags & BLKHDR_FLG_CRC) ? pre_crc : mhvtl_crc32c(bounce_buffer, rc);\n\t\tmemcpy(&bounce_buffer[rc], &lbp_crc, 4);\n\t\tMHVTL_DBG(2, \"Logical Block Protection - CRC32C, rc: %d, request_sz: %d, lbp_size: %d, CRC32C: 0x%8x\", rc, request_sz, lbp_sz, lbp_crc);\n\t\tMHVTL_DBG(2, \"rc: %d, request_sz: %d bounce buffer after LBP: 0x%08x %08x\", rc, request_sz, get_unaligned_be32(&bounce_buffer[rc - 4]), get_unaligned_be32(&bounce_buffer[rc]));\n\t\tMHVTL_DBG(2, \"READ block %d LBP RSCRC : 0x%02x 0x%02x 0x%02x 0x%02x\", blk_number, bounce_buffer[rc], bounce_buffer[rc + 1], bounce_buffer[rc + 2], bounce_buffer[rc + 3]);\n\t\trc += 4; /* Account for LBP checksum */\n\t\tbreak;\n\tcase 3:\n\t\t/* This should never occur - MODE 0a/f0 should not accept this value */\n\t\tMHVTL_ERR(\"LBP method 3 not supported : Returning E_LOGICAL_BLOCK_GUARD_FAILED\");\n\t\tsam_hardware_error(E_LOGICAL_BLOCK_GUARD_FAILED, sam_stat);\n\t\trc = 0;\n\t\tgoto free_bounce_buf;\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\n\t/* If bounce_buffer != buf then we're reading a large block and need to copy\n\t * data back into buf\n\t */\n\tif (bounce_buffer != buf) {\n\t\tMHVTL_DBG(1, \"Bounce buffer in use: request_sz: %d\", request_sz);\n\t\tmemcpy(buf, bounce_buffer, request_sz);\n\t\tfree(bounce_buffer);\n\t\trc = request_sz;\n\t}\n\n\tlu_ssc.bytesRead_I += blk_size;\n\tlu_ssc.bytesRead_M += disk_blk_size;\n\n\t/*\n\t * What SSC4-r01e says about incorrect length reads\n\n\tIf the SILI bit is zero and an incorrect-length logical block is read,\n\tCHECK CONDITION status shall be returned.\n\n\tThe ILI and VALID bits shall be set to one in the sense data and the\n\tadditional sense code shall be set to NO ADDITIONAL SENSE INFORMATION.\n\n\tUpon termination, the logical position shall be after the\n\tincorrect-length logical block (i.e., end-of-partition side).\n\n\tIf the FIXED bit is one, the INFORMATION field shall be set to the\n\trequested transfer length minus the actual number of logical blocks\n\tread, not including the incorrect-length logical block.\n\tIf the FIXED bit is zero, the INFORMATION field shall be set to the\n\trequested transfer length minus the actual logical block length.\n\tLogical units that do not support negative values shall set the\n\tINFORMATION field to zero if the overlength condition exists.\n\n\t\tNOTE 35 - In the above case with the FIXED bit of one, only\n\t\tthe position of the incorrect-length logical block may be\n\t\tdetermined from the sense data. The actual length of the\n\t\tincorrect logical block is not reported. Other means may\n\t\tbe used to determine its actual length (e.g., read it again\n\t\twith the fixed bit set to zero).\n\t*/\n\tif (rc != request_sz)\n\t\tmk_sense_short_block(request_sz, rc, sam_stat);\n\telse if (!sili) {\n\t\tif (lbp_sz < blk_size)\n\t\t\tmk_sense_short_block(lbp_sz, blk_size, sam_stat);\n\t}\n\n\treturn rc;\n\nfree_bounce_buf:\n\tif (bounce_buffer != buf)\n\t\tfree(bounce_buffer);\n\n\treturn 0;\n}\n\nstatic lzo_uint mhvtl_compressBound(lzo_uint src_sz) {\n\treturn src_sz + src_sz / 16 + 67;\n}\n\n/* Determine whether or not to store the crypto info in the tape\n * blk_header.\n * We may adjust this decision for the 3592. (See ibm_3592_xx.pm)\n */\nstatic void setup_crypto(struct scsi_cmd *cmd, struct priv_lu_ssc *lu_priv) {\n\tlu_priv->app_encr_info = lu_priv->ENCRYPT_MODE == 2 ? &app_encryption_state : NULL;\n\n\tif (lu_priv->pm->valid_encryption_media)\n\t\tlu_priv->pm->valid_encryption_media(cmd);\n}\n\n/** Call with\n ** LBP method, bufer and size, and CRC32C CRC which was already calculated\n **\n ** Return -1 on error or 0 on success (LBP CRC match)\n */\nstatic int32_t verify_lbp_crc(int lbp_method, unsigned char const *buf, size_t src_sz, uint32_t crc32c) {\n\tuint32_t lbp_crc = 0;\n\n\tswitch (lbp_method) {\n\tcase 0: /* No method defined - skip check */\n\t\tbreak;\n\tcase 1:\n\t\tMHVTL_DBG(2, \"WRITE block %d LBP RSCRC : 0x%02x 0x%02x 0x%02x 0x%02x\", c_pos->blk_number - 1, buf[src_sz], buf[src_sz + 1], buf[src_sz + 2], buf[src_sz + 3]);\n\t\tif (!BlockVerifyRSCRC(buf, src_sz + 4, lbp_rscrc_be)) {\n\t\t\tif (lbp_rscrc_be) {\n\t\t\t\tMHVTL_ERR(\"RSCRC mismatch: lbp_be: %d - LBP provided: 0x%08x, calculated RSCRC: 0x%08x\", lbp_rscrc_be, get_unaligned_be32(&buf[src_sz]), GenerateRSCRC(0, src_sz, buf));\n\t\t\t} else {\n\t\t\t\tMHVTL_ERR(\"RSCRC mismatch: lbp_be: %d - LBP provided: 0x%08x, calculated RSCRC: 0x%08x\", lbp_rscrc_be, get_unaligned_be32(&buf[src_sz]), __bswap_32(GenerateRSCRC(0, src_sz, buf)));\n\t\t\t}\n\t\t\treturn -1; /* CRC mismatch */\n\t\t}\n\t\tbreak;\n\tcase 2:\n\t\tMHVTL_DBG(2, \"WRITE block %d LBP CRC32C : 0x%02x 0x%02x 0x%02x 0x%02x\", c_pos->blk_number - 1, buf[src_sz], buf[src_sz + 1], buf[src_sz + 2], buf[src_sz + 3]);\n\t\tlbp_crc = get_unaligned_be32(&crc32c);\n\t\tif (lbp_crc != get_unaligned_be32(&buf[src_sz])) {\n\t\t\tMHVTL_ERR(\"CRC32C mismatch - LBP: 0x%08x, calculated: 0x%08x\", get_unaligned_be32(&buf[src_sz]), lbp_crc);\n\t\t\treturn -1; /* CRC mismatch */\n\t\t}\n\t\tbreak;\n\tdefault:\n\t\tMHVTL_ERR(\"Undefined LBP_method - failing check\");\n\t\treturn -1;\n\t\tbreak;\n\t}\n\n\treturn 0;\n}\n\nstatic void log_crc_options(int lbp_method, unsigned char const *buf, size_t size, uint32_t crc) {\n\tMHVTL_ERR(\"Legacy CRC32C: 0x%08x\", crc);\n\n\tswitch (lbp_method) {\n\tcase 1:\n\t\tMHVTL_ERR(\"Reed-Solomon CRC with seed 0: 0x%08x\", GenerateRSCRC(0, size, buf));\n\t\tMHVTL_ERR(\"Inverted Reed-Solomon CRC with seed 0: 0x%08x\", ~GenerateRSCRC(0, size, buf));\n\t\tMHVTL_ERR(\"Reed-Solomon CRC with seed 0xffffffff: 0x%08x\", GenerateRSCRC(0xffffffff, size, buf));\n\t\tMHVTL_ERR(\"Inverted Reed-Solomon CRC with seed 0xffffffff: 0x%08x\", ~GenerateRSCRC(0xffffffff, size, buf));\n\t\tbreak;\n\tcase 2:\n\t\tMHVTL_ERR(\"CRC32C with seed 0: 0x%08x\", crc32c(0, buf, size));\n\t\tMHVTL_ERR(\"Inverted CRC32C with seed 0: 0x%08x\", ~crc32c(0, buf, size));\n\t\tMHVTL_ERR(\"CRC32C with seed 0xffffffff: 0x%08x\", crc32c(0xffffffff, buf, size));\n\t\tMHVTL_ERR(\"Inverted CRC32C with seed 0xffffffff: 0x%08x\", ~crc32c(0xffffffff, buf, size));\n\t\tbreak;\n\tdefault:\n\t\tMHVTL_ERR(\"No matching LBP method\");\n\t\tbreak;\n\t}\n}\n\nstatic void log_lbp_method(int lbp_method) {\n\tswitch (lbp_method) {\n\tcase 1:\n\t\tMHVTL_DBG(2, \"Drive supports RS-CRC Logical Block Protection, lbp_be: %d\", lbp_rscrc_be);\n\t\tbreak;\n\tcase 2:\n\t\tMHVTL_DBG(2, \"Drive supports RS-CRC and CRC32C Logical Block Protection\");\n\t\tbreak;\n\tdefault:\n\t\tMHVTL_DBG(2, \"Drive supports Logical Block Protection (LBP) but unsupported LBP method provided: %d\", lbp_method);\n\t\tbreak;\n\t}\n}\n\n/*\n * Return number of bytes written to 'file'\n *\n * Zero on error with sense buffer already filled in\n */\nstatic int writeBlock_nocomp(struct scsi_cmd *cmd, uint32_t src_sz, uint8_t null_wr, int lbp_method) {\n\tuint8_t\t\t\t   *sam_stat = &cmd->dbuf_p->sam_stat;\n\tuint8_t\t\t\t   *src_buf\t = (uint8_t *)cmd->dbuf_p->data;\n\tstruct priv_lu_ssc *lu_priv;\n\tuint32_t\t\t\tcrc;\n\tint\t\t\t\t\trc;\n\n\tlu_priv = (struct priv_lu_ssc *)cmd->lu->lu_private;\n\n\tcrc = mhvtl_crc32c((unsigned char const *)src_buf, (size_t)src_sz);\n\tsetup_crypto(cmd, lu_priv);\n\n\trc = write_tape_block(src_buf, src_sz, 0, lu_priv->app_encr_info, 0, null_wr, crc, sam_stat);\n\n\tif (lu_priv->pm->drive_supports_LBP && lbp_method) {\n\t\tlog_lbp_method(lbp_method);\n\t\tif (verify_lbp_crc(lbp_method, src_buf, src_sz, crc) < 0) {\n\t\t\tMHVTL_ERR(\"LBP mis-compare on write : Returning E_LOGICAL_BLOCK_GUARD_FAILED\");\n\t\t\tsam_hardware_error(E_LOGICAL_BLOCK_GUARD_FAILED, sam_stat);\n\t\t\tlog_crc_options(lbp_method, src_buf, src_sz, crc);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tlu_priv->bytesWritten_M += src_sz;\n\tlu_priv->bytesWritten_I += src_sz;\n\n\tif (rc < 0)\n\t\treturn 0;\n\n\treturn src_sz;\n}\n\n/*\n * Return number of bytes written to 'file'\n *\n * Zero on error with sense buffer already filled in\n */\nstatic int writeBlock_lzo(struct scsi_cmd *cmd, uint32_t src_sz, uint8_t null_wr, int lbp_method) {\n\tlzo_uint  dest_len;\n\tlzo_uint  src_len = src_sz;\n\tlzo_bytep dest_buf;\n\tlzo_bytep wrkmem = NULL;\n\tuint32_t  crc;\n\n\tlzo_bytep src_buf = (lzo_bytep)cmd->dbuf_p->data;\n\n\tuint8_t *sam_stat = &cmd->dbuf_p->sam_stat;\n\n\tstruct priv_lu_ssc *lu_priv;\n\tint\t\t\t\t\trc;\n\tint\t\t\t\t\tz;\n\n\tlu_priv = (struct priv_lu_ssc *)cmd->lu->lu_private;\n\n\tcrc = mhvtl_crc32c((unsigned char const *)src_buf, (size_t)src_sz);\n\tsetup_crypto(cmd, lu_priv);\n\n\tdest_len = mhvtl_compressBound(src_sz);\n\tdest_buf = (lzo_bytep)malloc(dest_len);\n\twrkmem\t = (lzo_bytep)malloc(LZO1X_1_MEM_COMPRESS);\n\n\tif (unlikely(!dest_buf)) {\n\t\tMHVTL_ERR(\"dest_buf malloc(%d) failed\", (int)dest_len);\n\t\tsam_medium_error(E_WRITE_ERROR, sam_stat);\n\t\tfree(wrkmem);\n\t\treturn 0;\n\t}\n\n\tif (unlikely(!wrkmem)) {\n\t\tMHVTL_ERR(\"wrkmem malloc(%d) failed\", (int)LZO1X_1_MEM_COMPRESS);\n\t\tsam_medium_error(E_WRITE_ERROR, sam_stat);\n\t\tfree(dest_buf);\n\t\treturn 0;\n\t}\n\n\tz = lzo1x_1_compress(src_buf, src_sz, dest_buf, &dest_len, wrkmem);\n\tif (unlikely(z != LZO_E_OK)) {\n\t\tMHVTL_ERR(\"LZO compression error\");\n\t\tsam_hardware_error(E_COMPRESSION_CHECK, sam_stat);\n\t\treturn 0;\n\t}\n\n\tMHVTL_DBG(2, \"Compression: Orig %d, after comp: %ld\", src_sz, (unsigned long)dest_len);\n\n\trc = write_tape_block(dest_buf, src_len, dest_len, lu_priv->app_encr_info, LZO, null_wr, crc, sam_stat);\n\n\tfree(dest_buf);\n\tfree(wrkmem);\n\tlu_priv->bytesWritten_M += dest_len;\n\tlu_priv->bytesWritten_I += src_len;\n\n\tif (lu_priv->pm->drive_supports_LBP && lbp_method) {\n\t\tlog_lbp_method(lbp_method);\n\t\tif (verify_lbp_crc(lbp_method, src_buf, src_sz, crc) < 0) {\n\t\t\tMHVTL_ERR(\"LBP mis-compare on write : Returning E_LOGICAL_BLOCK_GUARD_FAILED - but wrote block anyway...\");\n\t\t\tsam_hardware_error(E_LOGICAL_BLOCK_GUARD_FAILED, sam_stat);\n\t\t\tlog_crc_options(lbp_method, src_buf, src_sz, crc);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tif (rc < 0)\n\t\treturn 0;\n\n\treturn src_len;\n}\n\n/*\n * Return number of bytes written to 'file'\n *\n * Zero on error with sense buffer already filled in\n */\nstatic int writeBlock_zlib(struct scsi_cmd *cmd, uint32_t src_sz, uint8_t null_wr, int lbp_method) {\n\tBytef\t\t\t   *dest_buf;\n\tuLong\t\t\t\tdest_len;\n\tuLong\t\t\t\tsrc_len\t = src_sz;\n\tuint8_t\t\t\t   *sam_stat = &cmd->dbuf_p->sam_stat;\n\tuint8_t\t\t\t   *src_buf\t = (uint8_t *)cmd->dbuf_p->data;\n\tstruct priv_lu_ssc *lu_priv;\n\tuint32_t\t\t\tcrc;\n\tint\t\t\t\t\trc;\n\tint\t\t\t\t\tz;\n\n\tlu_priv = (struct priv_lu_ssc *)cmd->lu->lu_private;\n\n\tcrc = mhvtl_crc32c((unsigned char const *)src_buf, (size_t)src_sz);\n\tsetup_crypto(cmd, lu_priv);\n\n\tdest_len = compressBound(src_sz);\n\tdest_buf = (Bytef *)malloc(dest_len);\n\tif (!dest_buf) {\n\t\tMHVTL_ERR(\"malloc(%d) failed\", (int)dest_len);\n\t\tsam_medium_error(E_WRITE_ERROR, sam_stat);\n\t\treturn 0;\n\t}\n\n\tz = compress2(dest_buf, &dest_len, src_buf, src_sz,\n\t\t\t\t  *lu_priv->compressionFactor);\n\tif (z != Z_OK) {\n\t\tswitch (z) {\n\t\tcase Z_MEM_ERROR:\n\t\t\tMHVTL_ERR(\"Not enough memory to compress data\");\n\t\t\tbreak;\n\t\tcase Z_BUF_ERROR:\n\t\t\tMHVTL_ERR(\"Not enough memory in destination \"\n\t\t\t\t\t  \"buf to compress data\");\n\t\t\tbreak;\n\t\tcase Z_DATA_ERROR:\n\t\t\tMHVTL_ERR(\"Input data corrupt / incomplete\");\n\t\t\tbreak;\n\t\t}\n\t\tsam_hardware_error(E_COMPRESSION_CHECK, sam_stat);\n\t\treturn 0;\n\t}\n\tMHVTL_DBG(2, \"Compression: Orig %d, after comp: %ld\"\n\t\t\t\t \", Compression factor: %d\",\n\t\t\t  src_sz, (unsigned long)dest_len,\n\t\t\t  *lu_priv->compressionFactor);\n\n\trc = write_tape_block(dest_buf, src_len, dest_len, lu_priv->app_encr_info, ZLIB, null_wr, crc, sam_stat);\n\n\tfree(dest_buf);\n\tlu_priv->bytesWritten_M += dest_len;\n\tlu_priv->bytesWritten_I += src_len;\n\n\tif (lu_priv->pm->drive_supports_LBP && lbp_method) {\n\t\tlog_lbp_method(lbp_method);\n\t\tif (verify_lbp_crc(lbp_method, src_buf, src_sz, crc) < 0) {\n\t\t\tMHVTL_ERR(\"LBP mis-compare on write : Returning E_LOGICAL_BLOCK_GUARD_FAILED\");\n\t\t\tsam_hardware_error(E_LOGICAL_BLOCK_GUARD_FAILED, sam_stat);\n\t\t\tlog_crc_options(lbp_method, src_buf, src_sz, crc);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tif (rc < 0)\n\t\treturn 0;\n\n\treturn src_len;\n}\n\nint writeBlock(struct scsi_cmd *cmd, uint32_t src_sz) {\n\tstruct priv_lu_ssc *lu_priv;\n\tint\t\t\t\t\tsrc_len;\n\tuint64_t\t\t\tcurrent_position;\n\tint64_t\t\t\t\tremaining_capacity;\n\tuint8_t\t\t\t   *sam_stat   = &cmd->dbuf_p->sam_stat;\n\tuint32_t\t\t\tlbp_sz\t   = src_sz;\n\tint\t\t\t\t\tlbp_method = 0;\n\n\tlu_priv = (struct priv_lu_ssc *)cmd->lu->lu_private;\n\tsrc_len = 0;\n\n\tif (lu_priv->pm->drive_supports_LBP) {\n\t\tif (lu_priv->LBP_W) {\n\t\t\tMHVTL_DBG(2, \"Write using LBP (CRC: %s)\",\n\t\t\t\t\t  (lu_priv->LBP_method == 0) ? \"Off\" : (lu_priv->LBP_method == 1) ? \"RS-CRC\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t   : (lu_priv->LBP_method == 2)\t  ? \"CRC32C\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  : \"Invalid\");\n\t\t\tswitch (lu_priv->LBP_method) {\n\t\t\tcase 1:\n\t\t\t\tlbp_method = 1;\n\t\t\t\tlbp_sz\t   = src_sz - 4;\n\t\t\t\tbreak;\n\t\t\tcase 2:\n\t\t\t\tlbp_method = 2;\n\t\t\t\tlbp_sz\t   = src_sz - 4;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t/* Check if we hit EOT and fail before attempting to write */\n\tcurrent_position = current_tape_offset();\n\tif (current_position >= lu_priv->max_capacity) {\n\t\tmam.remaining_capacity = 0L;\n\t\tMHVTL_DBG(1, \"End of Medium - VOLUME_OVERFLOW/EOM\");\n\t\tsam_no_sense(VOLUME_OVERFLOW | SD_EOM, E_EOM, sam_stat);\n\t\treturn src_len;\n\t}\n\n\tif (lu_priv->mamp->MediumType == MEDIA_TYPE_NULL) {\n\t\t/* Don't compress if null tape media */\n\t\tsrc_len = writeBlock_nocomp(cmd, lbp_sz, TRUE, 0);\n\t} else if (*lu_priv->compressionFactor == MHVTL_NO_COMPRESSION) {\n\t\t/* No compression - use the no-compression function */\n\t\tsrc_len = writeBlock_nocomp(cmd, lbp_sz, FALSE, lbp_method);\n\t} else {\n\t\tswitch (lu_priv->compressionType) {\n\t\tcase LZO:\n\t\t\tsrc_len = writeBlock_lzo(cmd, lbp_sz, FALSE, lbp_method);\n\t\t\tbreak;\n\t\tcase ZLIB:\n\t\t\tsrc_len = writeBlock_zlib(cmd, lbp_sz, FALSE, lbp_method);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tsrc_len = writeBlock_nocomp(cmd, lbp_sz, FALSE, lbp_method);\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (!src_len) {\n\t\t/* Set 'Read/Write error' TapeAlert flag */\n\t\tuint64_t fg = TA_HARD | TA_WRITE;\n\t\tset_TapeAlert(fg);\n\t\treturn 0;\n\t}\n\n\tcurrent_position = current_tape_offset();\n\n\tif ((lu_priv->pm->drive_supports_early_warning) &&\n\t\t(current_position >= (uint64_t)lu_priv->early_warning_position)) {\n\t\tMHVTL_DBG(1, \"End of Medium - Early Warning\");\n\t\tsam_no_sense(SD_EOM, NO_ADDITIONAL_SENSE, sam_stat);\n\t} else if ((lu_priv->pm->drive_supports_prog_early_warning) &&\n\t\t\t   (current_position >= (uint64_t)lu_priv->prog_early_warning_position)) {\n\t\t/* FIXME: Need to implement REW bit in Device Configuration Mode Page\n\t\t *\t  REW == Report Early Warning\n\t\t */\n\t\tMHVTL_DBG(1, \"End of Medium - Programmable Early Warning\");\n\t\tsam_no_sense(SD_EOM, E_PROGRAMMABLE_EARLY_WARNING, sam_stat);\n\t}\n\tremaining_capacity = lu_priv->max_capacity - current_position;\n\tif (remaining_capacity < 0)\n\t\tremaining_capacity = 0L;\n\n\tput_unaligned_be64(remaining_capacity, &mam.remaining_capacity);\n\n\treturn src_len;\n}\n"
  },
  {
    "path": "usr/mhvtl_log.c",
    "content": "/*\n * This handles any SCSI OP 'mode sense / mode select'\n *\n * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n * See comments in vtltape.c for a more complete version release...\n *\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <inttypes.h>\n#include <errno.h>\n#include \"mhvtl_list.h\"\n#include \"logging.h\"\n#include \"vtllib.h\"\n#include \"ssc.h\"\n#include \"be_byteshift.h\"\n#include \"mhvtl_log.h\"\n\n#define LOG_PG_HEADER(pageCode) \\\n\t{(uint8_t)(pageCode), 0x00, 0x00}\n#define LOG_PARAM(paramCode, flags, name) \\\n\t{                                     \\\n\t\t(uint8_t)((paramCode) >> 8),      \\\n\t\t(uint8_t)((paramCode) & 0xFF),    \\\n\t\t(flags),                          \\\n\t\tsizeof(pg->name),                 \\\n\t},                                    \\\n\t\t.name\n\nconst char *log_page_desc[0x38] = {\n\t[0x00 ... 0x37]\t\t\t\t  = \"Unsupported Log page\",\n\t[SUPPORTED_LOG_PAGES]\t\t  = \"Supported Log pages\",\n\t[BUFFER_UNDER_OVER_RUN]\t\t  = \"Buffer Under/Over Run\",\n\t[WRITE_ERROR_COUNTER]\t\t  = \"Write Error Counter\",\n\t[READ_ERROR_COUNTER]\t\t  = \"Read Error Counter\",\n\t[READ_REVERSE_ERROR_COUNTER]  = \"Read Reverse Error Counter\",\n\t[VERIFY_ERROR_COUNTER]\t\t  = \"Verify Error Counter\",\n\t[NON_MEDIUM_ERROR_COUNTER]\t  = \"Non-Medium Error Counter\",\n\t[LAST_n_ERROR]\t\t\t\t  = \"Last N Error\",\n\t[FORMAT_STATUS]\t\t\t\t  = \"Format Status\",\n\t[LAST_n_DEFERRED_ERROR]\t\t  = \"Last N Deferred Error\",\n\t[SEQUENTIAL_ACCESS_DEVICE]\t  = \"Sequential Access Device\",\n\t[TEMPERATURE_PAGE]\t\t\t  = \"Temperature Page\",\n\t[START_STOP_CYCLE_COUNTER]\t  = \"Start/Stop Cycle Counter\",\n\t[APPLICATION_CLIENT]\t\t  = \"Application Client\",\n\t[SELFTEST_RESULTS]\t\t\t  = \"Selftest Results\",\n\t[VOLUME_STATISTICS]\t\t\t  = \"Volume Statistics\",\n\t[DEVICE_STATUS]\t\t\t\t  = \"VHF Device Status\",\n\t[TAPE_ALERT]\t\t\t\t  = \"Tape Alert\",\n\t[INFORMATIONAL_EXCEPTIONS]\t  = \"Informational Exceptions\",\n\t[TAPE_USAGE]\t\t\t\t  = \"Tape Usage\",\n\t[TAPE_CAPACITY]\t\t\t\t  = \"Tape Capacity\",\n\t[DATA_COMPRESSION]\t\t\t  = \"Data Compression\",\n\t[PERFORMANCE_CHARACTERISTICS] = \"Performance Characteristics\",\n};\n\nstruct log_pg_list *lookup_log_pg(struct list_head *l, uint8_t page, uint8_t subpage) {\n\tstruct log_pg_list *log_pg;\n\n\tMHVTL_DBG(3, \"fetching log page (0x%02x - 0x%02x)\", page, subpage);\n\n\tlist_for_each_entry(log_pg, l, siblings) {\n\t\tif (log_pg->log_page_num == page && log_pg->log_subpage_num == subpage) {\n\t\t\tMHVTL_DBG(2, \"log page (0x%02x - 0x%02x) found : %s\", page, subpage, log_page_desc[page]);\n\t\t\treturn log_pg;\n\t\t}\n\t}\n\n\t/* If no page found, ignore subpage */\n\tlist_for_each_entry(log_pg, l, siblings) {\n\t\tif (log_pg->log_page_num == page) {\n\t\t\tMHVTL_DBG(2, \"log page (0x%02x - 0x%02x) found but wrong supbage: %s\", page, subpage, log_page_desc[page]);\n\t\t\treturn log_pg;\n\t\t}\n\t}\n\n\tMHVTL_DBG(3, \"log page (0x%02x - 0x%02x) not found\", page, subpage);\n\n\treturn NULL;\n}\n\nint alloc_log_page(struct lu_phy_attr *lu,\n\t\t\t\t   uint8_t page, uint8_t subpage,\n\t\t\t\t   init_pg_fn init_log_pg,\n\t\t\t\t   size_t\t  pg_size) {\n\tstruct log_pg_list *log_pg;\n\tint\t\t\t\t\tcreation = 0;\n\n\tMHVTL_DBG(3, \"%p : Allocate log page (0x%02x - 0x%02x), size %d\",\n\t\t\t  &lu->log_pg, page, subpage, (int)pg_size);\n\n\t/* Getting the entry, create it if does not exist */\n\tlog_pg = lookup_log_pg(&lu->log_pg, page, subpage);\n\tif (!log_pg) {\n\t\tcreation = 1;\n\t\tlog_pg\t = malloc(sizeof(struct log_pg_list));\n\t}\n\n\tif (log_pg) {\n\t\tlog_pg->log_page_num\t= page;\n\t\tlog_pg->log_subpage_num = subpage;\n\t\tlog_pg->size\t\t\t= pg_size;\n\t\tlog_pg->p\t\t\t\t= malloc(pg_size);\n\t\tif (log_pg->p) {\n\t\t\tinit_log_pg(log_pg->p);\n\t\t\tput_unaligned_be16(pg_size - sizeof(struct log_pg_header), /* Setting the real len of the log page */\n\t\t\t\t\t\t\t   &((struct log_pg_header *)log_pg->p)->len);\n\t\t\tif (creation)\n\t\t\t\tlist_add_tail(&log_pg->siblings, &lu->log_pg);\n\t\t\treturn 0;\n\t\t} else {\n\t\t\tMHVTL_ERR(\"Unable to malloc log page buffer (%zu)\", pg_size);\n\t\t\tfree(log_pg);\n\t\t\treturn -ENOMEM;\n\t\t}\n\t}\n\n\tMHVTL_ERR(\"Unable to malloc log page entry (%zu)\", pg_size);\n\treturn -ENOMEM;\n}\n\nvoid dealloc_all_log_pages(struct lu_phy_attr *lu) {\n\tstruct log_pg_list *lp, *ln;\n\n\tlist_for_each_entry_safe(lp, ln, &lu->log_pg, siblings) {\n\t\tMHVTL_DBG(2, \"Removing %s\", lp->description);\n\t\tfree(lp->p);\n\t\tlist_del(&lp->siblings);\n\t\tfree(lp);\n\t}\n}\n\nstatic void init_log_write_err_counter(void *log_ptr) {\n\tstruct ErrorCounter_pg *pg = log_ptr;\n\t*pg\t\t\t\t\t\t   = (struct ErrorCounter_pg){\n\t\t   LOG_PG_HEADER(WRITE_ERROR_COUNTER),\n\t\t   LOG_PARAM(0x0000, 0x60, err_correctedWODelay) = 0x00,\n\t\t   LOG_PARAM(0x0001, 0x60, err_correctedWDelay)\t = 0x00,\n\t\t   LOG_PARAM(0x0002, 0x60, totalReTry)\t\t\t = 0x00,\n\t\t   LOG_PARAM(0x0003, 0x60, totalErrorsCorrected) = 0x00,\n\t\t   LOG_PARAM(0x0004, 0x60, correctAlgorithm)\t = 0x00,\n\t\t   LOG_PARAM(0x0005, 0x60, bytesProcessed)\t\t = 0x00,\n\t\t   LOG_PARAM(0x0006, 0x60, uncorrectedErrors)\t = 0x00,\n\t\t   LOG_PARAM(0x8000, 0x60, readErrorsSinceLast)\t = 0x00,\n\t\t   LOG_PARAM(0x8001, 0x60, totalRawReadError)\t = 0x00,\n\t\t   LOG_PARAM(0x8002, 0x60, totalDropoutError)\t = 0x00,\n\t\t   LOG_PARAM(0x8003, 0x60, totalServoTracking)\t = 0x00,\n\t   };\n}\nint add_log_write_err_counter(struct lu_phy_attr *lu) {\n\treturn alloc_log_page(lu, WRITE_ERROR_COUNTER, NO_SUBPAGE,\n\t\t\t\t\t\t  init_log_write_err_counter, sizeof(struct ErrorCounter_pg));\n}\n\nstatic void init_log_read_err_counter(void *log_ptr) {\n\tstruct ErrorCounter_pg *pg = log_ptr;\n\t*pg\t\t\t\t\t\t   = (struct ErrorCounter_pg){\n\t\t   LOG_PG_HEADER(READ_ERROR_COUNTER),\n\t\t   LOG_PARAM(0x0000, 0x60, err_correctedWODelay) = 0x00,\n\t\t   LOG_PARAM(0x0001, 0x60, err_correctedWDelay)\t = 0x00,\n\t\t   LOG_PARAM(0x0002, 0x60, totalReTry)\t\t\t = 0x00,\n\t\t   LOG_PARAM(0x0003, 0x60, totalErrorsCorrected) = 0x00,\n\t\t   LOG_PARAM(0x0004, 0x60, correctAlgorithm)\t = 0x00,\n\t\t   LOG_PARAM(0x0005, 0x60, bytesProcessed)\t\t = 0x00,\n\t\t   LOG_PARAM(0x0006, 0x60, uncorrectedErrors)\t = 0x00,\n\t\t   LOG_PARAM(0x8000, 0x60, readErrorsSinceLast)\t = 0x00,\n\t\t   LOG_PARAM(0x8001, 0x60, totalRawReadError)\t = 0x00,\n\t\t   LOG_PARAM(0x8002, 0x60, totalDropoutError)\t = 0x00,\n\t\t   LOG_PARAM(0x8003, 0x60, totalServoTracking)\t = 0x00,\n\t   };\n}\nint add_log_read_err_counter(struct lu_phy_attr *lu) {\n\treturn alloc_log_page(lu, READ_ERROR_COUNTER, NO_SUBPAGE,\n\t\t\t\t\t\t  init_log_read_err_counter, sizeof(struct ErrorCounter_pg));\n}\n\nstatic void init_log_sequential_access(void *log_ptr) {\n\tstruct SequentialAccessDevice_pg *pg = log_ptr;\n\t*pg\t\t\t\t\t\t\t\t\t = (struct SequentialAccessDevice_pg){\n\t\t LOG_PG_HEADER(SEQUENTIAL_ACCESS_DEVICE),\n\t\t LOG_PARAM(0x0000, 0x40, writeDataB4Compression) = 0x00,\n\t\t LOG_PARAM(0x0001, 0x40, writeDataAfCompression) = 0x00,\n\t\t LOG_PARAM(0x0002, 0x40, readDataB4Compression)\t = 0x00,\n\t\t LOG_PARAM(0x0003, 0x40, readDataAfCompression)\t = 0x00,\n\t\t LOG_PARAM(0x0004, 0x40, capacity_bop_eod)\t\t = 0x00,\n\t\t LOG_PARAM(0x0005, 0x40, capacity_bop_ew)\t\t = 0x00,\n\t\t LOG_PARAM(0x0006, 0x40, capacity_ew_leop)\t\t = 0x00,\n\t\t LOG_PARAM(0x0007, 0x40, capacity_bop_curr)\t\t = 0x00,\n\t\t LOG_PARAM(0x0008, 0x40, capacity_buffer)\t\t = 0x00,\n\t\t LOG_PARAM(0x0100, 0x40, TapeAlert)\t\t\t\t = 0x00,\n\t\t LOG_PARAM(0x8000, 0x40, mbytes_processed)\t\t = 0x00,\n\t\t LOG_PARAM(0x8001, 0x40, load_cycle)\t\t\t = 0x00,\n\t\t LOG_PARAM(0x8002, 0x40, clean_cycle)\t\t\t = 0x00,\n\t };\n}\nint add_log_sequential_access(struct lu_phy_attr *lu) {\n\treturn alloc_log_page(lu, SEQUENTIAL_ACCESS_DEVICE, NO_SUBPAGE,\n\t\t\t\t\t\t  init_log_sequential_access, sizeof(struct SequentialAccessDevice_pg));\n}\n\nstatic void init_log_temperature_page(void *log_ptr) {\n\tstruct Temperature_pg *pg = log_ptr;\n\t*pg\t\t\t\t\t\t  = (struct Temperature_pg){\n\t\t  LOG_PG_HEADER(TEMPERATURE_PAGE),\n\t\t  LOG_PARAM(0x0000, 0x60, temperature) = 0x00,\n\t  };\n}\nint add_log_temperature_page(struct lu_phy_attr *lu) {\n\treturn alloc_log_page(lu, TEMPERATURE_PAGE, NO_SUBPAGE,\n\t\t\t\t\t\t  init_log_temperature_page, sizeof(struct Temperature_pg));\n}\n\nstatic void init_log_selftest_results(void *log_ptr) {\n\tstruct SelfTestResults_pg *pg = log_ptr;\n\t*pg\t\t\t\t\t\t\t  = (struct SelfTestResults_pg){\n\t\t  LOG_PG_HEADER(SELFTEST_RESULTS),\n\t\t  LOG_PARAM(0x0001, 0x00, data01) = {0},\n\t\t  LOG_PARAM(0x0002, 0x00, data02) = {0},\n\t\t  LOG_PARAM(0x0003, 0x00, data03) = {0},\n\t\t  LOG_PARAM(0x0004, 0x00, data04) = {0},\n\t\t  LOG_PARAM(0x0005, 0x00, data05) = {0},\n\t\t  LOG_PARAM(0x0006, 0x00, data06) = {0},\n\t\t  LOG_PARAM(0x0007, 0x00, data07) = {0},\n\t\t  LOG_PARAM(0x0008, 0x00, data08) = {0},\n\t\t  LOG_PARAM(0x0009, 0x00, data09) = {0},\n\t\t  LOG_PARAM(0x000a, 0x00, data0a) = {0},\n\t\t  LOG_PARAM(0x000b, 0x00, data0b) = {0},\n\t\t  LOG_PARAM(0x000c, 0x00, data0c) = {0},\n\t\t  LOG_PARAM(0x000d, 0x00, data0d) = {0},\n\t\t  LOG_PARAM(0x000e, 0x00, data0e) = {0},\n\t\t  LOG_PARAM(0x000f, 0x00, data0f) = {0},\n\t\t  LOG_PARAM(0x0010, 0x00, data10) = {0},\n\t\t  LOG_PARAM(0x0011, 0x00, data11) = {0},\n\t\t  LOG_PARAM(0x0012, 0x00, data12) = {0},\n\t\t  LOG_PARAM(0x0013, 0x00, data13) = {0},\n\t\t  LOG_PARAM(0x0014, 0x00, data14) = {0},\n\t  };\n}\nint add_log_selftest_results(struct lu_phy_attr *lu) {\n\treturn alloc_log_page(lu, SELFTEST_RESULTS, NO_SUBPAGE,\n\t\t\t\t\t\t  init_log_selftest_results, sizeof(struct SelfTestResults_pg));\n}\n\nstatic void init_log_volume_statistics(void *log_ptr) {\n\tstruct VolumeStatistics_pg *pg = log_ptr;\n\t*pg\t\t\t\t\t\t\t   = (struct VolumeStatistics_pg){\n\t\t   LOG_PG_HEADER(VOLUME_STATISTICS),\n\t\t   LOG_PARAM(0x0000, 0x03, PageValid)\t\t\t\t\t\t  = 0x01,\n\t\t   LOG_PARAM(0x0001, 0x03, VolumeMounts)\t\t\t\t\t  = 0x00,\n\t\t   LOG_PARAM(0x0002, 0x03, VolumeDatasetsWritten)\t\t\t  = 0x00,\n\t\t   LOG_PARAM(0x0003, 0x03, RecoveredWriteDataErrors)\t\t  = 0x00,\n\t\t   LOG_PARAM(0x0004, 0x03, UnrecoveredWriteDataErrors)\t\t  = 0x00,\n\t\t   LOG_PARAM(0x0005, 0x03, WriteServoErrors)\t\t\t\t  = 0x00,\n\t\t   LOG_PARAM(0x0006, 0x03, UnrecoveredWriteServoErrors)\t\t  = 0x00,\n\t\t   LOG_PARAM(0x0007, 0x03, VolumeDatasetsRead)\t\t\t\t  = 0x00,\n\t\t   LOG_PARAM(0x0008, 0x03, RecoveredReadErrors)\t\t\t\t  = 0x00,\n\t\t   LOG_PARAM(0x0009, 0x03, UnrecoveredReadErrors)\t\t\t  = 0x00,\n\t\t   LOG_PARAM(0x000C, 0x03, LastMountUnrecoveredWriteErrors)\t  = 0x00,\n\t\t   LOG_PARAM(0x000D, 0x03, LastMountUnrecoveredReadErrors)\t  = 0x00,\n\t\t   LOG_PARAM(0x000E, 0x03, LastMountMBWritten)\t\t\t\t  = 0x00,\n\t\t   LOG_PARAM(0x000F, 0x03, LastMountMBRead)\t\t\t\t\t  = 0x00,\n\t\t   LOG_PARAM(0x0010, 0x03, LifetimeMBWritten)\t\t\t\t  = 0x00,\n\t\t   LOG_PARAM(0x0011, 0x03, LifetimeMBRead)\t\t\t\t\t  = 0x00,\n\t\t   LOG_PARAM(0x0012, 0x03, LastLoadWriteCompressionRatio)\t  = 0x00,\n\t\t   LOG_PARAM(0x0013, 0x03, LastLoadReadCompressionRatio)\t  = 0x00,\n\t\t   LOG_PARAM(0x0014, 0x03, MediumMountTime)\t\t\t\t\t  = {0},\n\t\t   LOG_PARAM(0x0015, 0x03, MediumReadyTime)\t\t\t\t\t  = {0},\n\t\t   LOG_PARAM(0x0016, 0x03, TotalNativeCapacity)\t\t\t\t  = 0xfffffffe,\n\t\t   LOG_PARAM(0x0017, 0x03, TotalUsedNativeCapacity)\t\t\t  = 0xfffffffe,\n\t\t   LOG_PARAM(0x0018, 0x03, AppDesignCapacity)\t\t\t\t  = 0x00,\n\t\t   LOG_PARAM(0x0019, 0x03, VolumeLifetimeRemaining)\t\t\t  = 0x00,\n\t\t   LOG_PARAM(0x0040, 0x01, VolumeSerialNumber)\t\t\t\t  = {0},\n\t\t   LOG_PARAM(0x0041, 0x01, TapeLotIdentifier)\t\t\t\t  = {0},\n\t\t   LOG_PARAM(0x0042, 0x01, VolumeBarcode)\t\t\t\t\t  = {0},\n\t\t   LOG_PARAM(0x0043, 0x01, VolumeManufacturer)\t\t\t\t  = {0},\n\t\t   LOG_PARAM(0x0044, 0x01, VolumeLicenseCode)\t\t\t\t  = {0},\n\t\t   LOG_PARAM(0x0045, 0x01, VolumePersonality)\t\t\t\t  = {0},\n\t\t   LOG_PARAM(0x0080, 0x03, WriteProtect)\t\t\t\t\t  = 0x00,\n\t\t   LOG_PARAM(0x0081, 0x03, WORM)\t\t\t\t\t\t\t  = 0x00,\n\t\t   LOG_PARAM(0x0082, 0x03, TempExceeded)\t\t\t\t\t  = 0x00,\n\t\t   LOG_PARAM(0x0101, 0x03, BOMPasses)\t\t\t\t\t\t  = 0x00,\n\t\t   LOG_PARAM(0x0102, 0x03, MOTPasses)\t\t\t\t\t\t  = 0x00,\n\t\t   LOG_PARAM(0x0200, 0x03, FirstEncryptedLogicalObj)\t\t  = {{{0}}},\n\t\t   LOG_PARAM(0x0201, 0x03, FirstUnencryptedLogicalObj)\t\t  = {{{0}}},\n\t\t   LOG_PARAM(0x0202, 0x03, ApproxNativeCapacityPartition)\t  = {{{0}}},\n\t\t   LOG_PARAM(0x0203, 0x03, ApproxUsedNativeCapacityPartition) = {{{0}}},\n\t\t   LOG_PARAM(0x0204, 0x03, RemainingCapacityToEWPartition)\t  = {{{0}}},\n\t   };\n\tfor (int k = 0; k < MAX_PARTITIONS; k++) {\n\t\tpg->FirstEncryptedLogicalObj[k].header.len = sizeof(struct partition_record_size6) - 1;\n\t\tput_unaligned_be16(k, &pg->FirstEncryptedLogicalObj[k].header.partition_no);\n\t\tpg->FirstUnencryptedLogicalObj[k].header.len = sizeof(struct partition_record_size6) - 1;\n\t\tput_unaligned_be16(k, &pg->FirstUnencryptedLogicalObj[k].header.partition_no);\n\t\tpg->ApproxNativeCapacityPartition[k].header.len = sizeof(struct partition_record_size4) - 1;\n\t\tput_unaligned_be16(k, &pg->ApproxNativeCapacityPartition[k].header.partition_no);\n\t\tpg->ApproxUsedNativeCapacityPartition[k].header.len = sizeof(struct partition_record_size4) - 1;\n\t\tput_unaligned_be16(k, &pg->ApproxUsedNativeCapacityPartition[k].header.partition_no);\n\t\tpg->RemainingCapacityToEWPartition[k].header.len = sizeof(struct partition_record_size4) - 1;\n\t\tput_unaligned_be16(k, &pg->RemainingCapacityToEWPartition[k].header.partition_no);\n\t};\n}\nint add_log_volume_statistics(struct lu_phy_attr *lu) {\n\treturn alloc_log_page(lu, VOLUME_STATISTICS, NO_SUBPAGE,\n\t\t\t\t\t\t  init_log_volume_statistics, sizeof(struct VolumeStatistics_pg));\n}\n\nstatic void init_log_tape_alert(void *log_ptr) {\n\tstruct TapeAlert_pg *pg = log_ptr;\n\t*pg\t\t\t\t\t\t= (struct TapeAlert_pg){\n\t\tLOG_PG_HEADER(TAPE_ALERT),\n\t};\n\tfor (int i = 0; i < 64; i++) {\n\t\tpg->TapeAlert[i] = (struct TapeAlert_flag){{0x00, i + 1, 0xc0, 1}, 0x00};\n\t}\n}\nint add_log_tape_alert(struct lu_phy_attr *lu) {\n\treturn alloc_log_page(lu, TAPE_ALERT, NO_SUBPAGE,\n\t\t\t\t\t\t  init_log_tape_alert, sizeof(struct TapeAlert_pg));\n}\n\nstatic void init_log_tape_usage(void *log_ptr) {\n\tstruct TapeUsage_pg *pg = log_ptr;\n\t*pg\t\t\t\t\t\t= (struct TapeUsage_pg){\n\t\tLOG_PG_HEADER(TAPE_USAGE),\n\t\tLOG_PARAM(0x0001, 0xc0, volumeMounts)\t\t\t = 0x00,\n\t\tLOG_PARAM(0x0002, 0xc0, volumeDatasetsWritten)\t = 0x00,\n\t\tLOG_PARAM(0x0003, 0xc0, volWriteRetries)\t\t = 0x00,\n\t\tLOG_PARAM(0x0004, 0xc0, volWritePerms)\t\t\t = 0x00,\n\t\tLOG_PARAM(0x0005, 0xc0, volSuspendedWrites)\t\t = 0x00,\n\t\tLOG_PARAM(0x0006, 0xc0, volFatalSuspendedWrites) = 0x00,\n\t\tLOG_PARAM(0x0007, 0xc0, volDatasetsRead)\t\t = 0x00,\n\t\tLOG_PARAM(0x0008, 0xc0, volReadRetries)\t\t\t = 0x00,\n\t\tLOG_PARAM(0x0009, 0xc0, volReadPerms)\t\t\t = 0x00,\n\t\tLOG_PARAM(0x000a, 0xc0, volSuspendedReads)\t\t = 0x00,\n\t\tLOG_PARAM(0x000b, 0xc0, volFatalSuspendedReads)\t = 0x00,\n\t};\n}\nint add_log_tape_usage(struct lu_phy_attr *lu) {\n\treturn alloc_log_page(lu, TAPE_USAGE, NO_SUBPAGE,\n\t\t\t\t\t\t  init_log_tape_usage, sizeof(struct TapeUsage_pg));\n}\n\nstatic void init_log_device_status(void *log_ptr) {\n\tstruct DeviceStatus_pg *pg = log_ptr;\n\t*pg\t\t\t\t\t\t   = (struct DeviceStatus_pg){\n\t\t   LOG_PG_HEADER(DEVICE_STATUS),\n\t\t   LOG_PARAM(0x0000, 0x03, vhf) = {{0x01, 0x00, 0x00, 0x01}},\n\t   };\n}\nint add_log_device_status(struct lu_phy_attr *lu) {\n\treturn alloc_log_page(lu, DEVICE_STATUS, NO_SUBPAGE,\n\t\t\t\t\t\t  init_log_device_status, sizeof(struct DeviceStatus_pg));\n}\n\nstatic struct DeviceStatus_pg *lookup_device_status_pg(void) {\n\tstruct log_pg_list *log_pg;\n\n\tlog_pg = lookup_log_pg(&lunit.log_pg, DEVICE_STATUS, NO_SUBPAGE);\n\tif (!log_pg)\n\t\treturn NULL;\n\n\treturn (struct DeviceStatus_pg *)log_pg->p;\n}\n\nstatic void init_log_tape_capacity(void *log_ptr) {\n\tstruct TapeCapacity_pg *pg = log_ptr;\n\t*pg\t\t\t\t\t\t   = (struct TapeCapacity_pg){\n\t\t   LOG_PG_HEADER(TAPE_CAPACITY),\n\t\t   LOG_PARAM(0x0001, 0xc0, partition0remaining) = 0xfffffffe,\n\t\t   LOG_PARAM(0x0002, 0xc0, partition1remaining) = 0xfffffffe,\n\t\t   LOG_PARAM(0x0003, 0xc0, partition0maximum)\t= 0xfffffffe,\n\t\t   LOG_PARAM(0x0004, 0xc0, partition1maximum)\t= 0xfffffffe,\n\t   };\n}\nint add_log_tape_capacity(struct lu_phy_attr *lu) {\n\treturn alloc_log_page(lu, TAPE_CAPACITY, NO_SUBPAGE,\n\t\t\t\t\t\t  init_log_tape_capacity, sizeof(struct TapeCapacity_pg));\n}\n\nstatic void init_log_data_compression(void *log_ptr) {\n\tstruct DataCompression_pg *pg = log_ptr;\n\t*pg\t\t\t\t\t\t\t  = (struct DataCompression_pg){\n\t\t  LOG_PG_HEADER(DATA_COMPRESSION),\n\t\t  LOG_PARAM(0x0000, 0x40, ReadCompressionRatio)\t = 0x00,\n\t\t  LOG_PARAM(0x0001, 0x40, WriteCompressionRatio) = 0x00,\n\t\t  LOG_PARAM(0x0002, 0x40, MBytesToServer)\t\t = 0x00,\n\t\t  LOG_PARAM(0x0003, 0x40, BytesToServer)\t\t = 0x00,\n\t\t  LOG_PARAM(0x0004, 0x40, MBytesReadFromTape)\t = 0x00,\n\t\t  LOG_PARAM(0x0005, 0x40, BytesReadFromTape)\t = 0x00,\n\t\t  LOG_PARAM(0x0006, 0x40, MBytesFromServer)\t\t = 0x00,\n\t\t  LOG_PARAM(0x0007, 0x40, BytesFromServer)\t\t = 0x00,\n\t\t  LOG_PARAM(0x0008, 0x40, MBytesWrittenToTape)\t = 0x00,\n\t\t  LOG_PARAM(0x0009, 0x40, BytesWrittenToTape)\t = 0x00,\n\t  };\n}\nint add_log_data_compression(struct lu_phy_attr *lu) {\n\treturn alloc_log_page(lu, DATA_COMPRESSION, NO_SUBPAGE,\n\t\t\t\t\t\t  init_log_data_compression, sizeof(struct DataCompression_pg));\n}\n\nstatic void init_log_performance_characteristics(void *log_ptr) {\n\tstruct PerformanceCharacteristics_pg *pg = log_ptr;\n\t*pg\t\t\t\t\t\t\t\t\t\t = (struct PerformanceCharacteristics_pg){\n\t\t LOG_PG_HEADER(PERFORMANCE_CHARACTERISTICS),\n\t\t LOG_PARAM(0x0000, 0x00, DriveEfficiency) = 0x00,\n\t };\n}\nint add_log_performance_characteristics(struct lu_phy_attr *lu) {\n\treturn alloc_log_page(lu, PERFORMANCE_CHARACTERISTICS, NO_SUBPAGE,\n\t\t\t\t\t\t  init_log_performance_characteristics, sizeof(struct PerformanceCharacteristics_pg));\n}\n\n/* Update MAM Accessible bit in LogPage 0x11 */\nvoid set_lp_11_macc(int flag) {\n\tstruct DeviceStatus_pg *lp = lookup_device_status_pg();\n\tif (lp)\n\t\tlp->vhf.b4.MACC = flag;\n}\n\nvoid set_lp11_compression(int flag) {\n\tstruct DeviceStatus_pg *lp = lookup_device_status_pg();\n\tif (lp)\n\t\tlp->vhf.b4.CMPR = flag;\n}\n\nvoid set_lp_11_crqst(int flag) {\n\tstruct DeviceStatus_pg *lp = lookup_device_status_pg();\n\tif (lp)\n\t\tlp->vhf.b4.CRQST = flag;\n}\n\nvoid set_lp_11_crqrd(int flag) {\n\tstruct DeviceStatus_pg *lp = lookup_device_status_pg();\n\tif (lp)\n\t\tlp->vhf.b4.CRQRD = flag;\n}\n\n/* Update WriteProtect bit in LogPage 0x11 */\nvoid set_lp_11_wp(int flag) {\n\tstruct DeviceStatus_pg *lp = lookup_device_status_pg();\n\tif (lp)\n\t\tlp->vhf.b4.WRTP = flag;\n}\n\nvoid set_lp11_medium_present(int flag) {\n\tstruct DeviceStatus_pg *lp = lookup_device_status_pg();\n\tif (!lp)\n\t\treturn;\n\n\tlp->vhf.b5.MPRSNT = flag;\n\n\tif (!flag) {\t\t   /* Clearing bit - also set state to unloaded */\n\t\tset_lp_11_macc(0); /* MAM Accessible */\n\t\tset_current_state(MHVTL_STATE_UNLOADED);\n\t}\n}\n\n#define SET_VOLSTAT_PARAM_H(paramCode, paramFlags, paramStruct)                               \\\n\tdo {                                                                                      \\\n\t\tput_unaligned_be16((paramCode), header);                                              \\\n\t\t((struct pc_header *)header)->flags = (paramFlags);                                   \\\n\t\t((struct pc_header *)header)->len\t= mam.num_partitions * sizeof(paramStruct);       \\\n\t\tfor (i = 0; i < mam.num_partitions; ++i) {                                            \\\n\t\t\tparamStruct *p_header = ((paramStruct *)(header + sizeof(struct pc_header))) + i; \\\n\t\t\tp_header->header.len  = sizeof(paramStruct) - 1;                                  \\\n\t\t\tput_unaligned_be16(i, &p_header->header.partition_no);                            \\\n\t\t}                                                                                     \\\n\t} while (0)\n#define SET_VOLSTAT_PARAM_H4(paramCode, paramFlags) \\\n\tSET_VOLSTAT_PARAM_H((paramCode), (paramFlags), struct partition_record_size4)\n#define SET_VOLSTAT_PARAM_H6(paramCode, paramFlags) \\\n\tSET_VOLSTAT_PARAM_H((paramCode), (paramFlags), struct partition_record_size6)\n\n/* Rewriting the page with the real number of partitions */\nvoid update_VolumeStatistics(struct VolumeStatistics_pg *pg, struct priv_lu_ssc *lu_priv) {\n\tuint8_t *header;\n\tuint64_t cap __attribute__((unused)); /* fixme : should be used instead of telling max cap */\n\tint\t\t i;\n\n\t/* First partition dependant parameter */\n\tmemset(&pg->h_FirstEncryptedLogicalObj, 0,\n\t\t   sizeof(struct VolumeStatistics_pg) - offsetof(struct VolumeStatistics_pg, h_FirstEncryptedLogicalObj));\n\n\t/* h_FirstEncryptedLogicalObj */\n\theader = (uint8_t *)pg + offsetof(struct VolumeStatistics_pg, h_FirstEncryptedLogicalObj);\n\tSET_VOLSTAT_PARAM_H6(0x0200, 0x03);\n\tfor (i = 0; i < mam.num_partitions; ++i) {\n\t\tstruct partition_record_size6 *p_header =\n\t\t\t((struct partition_record_size6 *)(header + sizeof(struct pc_header))) + i;\n\t\tput_unaligned_be48(0, &p_header->data);\n\t}\n\n\t/* h_FirstUnencryptedLogicalObj */\n\theader += sizeof(struct pc_header) + ((struct pc_header *)header)->len;\n\tSET_VOLSTAT_PARAM_H6(0x0201, 0x03);\n\tfor (i = 0; i < mam.num_partitions; ++i) {\n\t\tstruct partition_record_size6 *p_header =\n\t\t\t((struct partition_record_size6 *)(header + sizeof(struct pc_header))) + i;\n\t\tput_unaligned_be48(0, &p_header->data);\n\t}\n\n\t/* h_ApproxNativeCapacityPartition */\n\theader += sizeof(struct pc_header) + ((struct pc_header *)header)->len;\n\tSET_VOLSTAT_PARAM_H4(0x0202, 0x03);\n\tif (get_tape_load_status() == TAPE_LOADED) {\n\t\tfor (i = 0; i < mam.num_partitions; ++i) {\n\t\t\tstruct partition_record_size4 *p_header =\n\t\t\t\t((struct partition_record_size4 *)(header + sizeof(struct pc_header))) + i;\n\t\t\tcap = get_unaligned_be64(&mam.max_capacity) / lu_priv->capacity_unit;\n\t\t\tput_unaligned_be32(0xfffffffe, &p_header->data);\n\t\t\tMHVTL_DBG(1, \"approx native capacity for partition %d : %u\",\n\t\t\t\t\t  i, get_unaligned_be32(&p_header->data));\n\t\t}\n\t}\n\n\t/* h_ApproxUsedNativeCapacityPartition */\n\theader += sizeof(struct pc_header) + ((struct pc_header *)header)->len;\n\tSET_VOLSTAT_PARAM_H4(0x0203, 0x03);\n\tfor (i = 0; i < mam.num_partitions; ++i) {\n\t\tstruct partition_record_size4 *p_header =\n\t\t\t((struct partition_record_size4 *)(header + sizeof(struct pc_header))) + i;\n\t\tput_unaligned_be32(0xfffffffe, &p_header->data);\n\t\tMHVTL_DBG(1, \"approx used native capacity for partition %d : %u\",\n\t\t\t\t  i, get_unaligned_be32(&p_header->data));\n\t}\n\n\t/* h_RemainingCapacityToEWPartition */\n\theader += sizeof(struct pc_header) + ((struct pc_header *)header)->len;\n\tSET_VOLSTAT_PARAM_H4(0x0204, 0x03);\n\tif (get_tape_load_status() == TAPE_LOADED) {\n\t\tfor (i = 0; i < mam.num_partitions; ++i) {\n\t\t\tstruct partition_record_size4 *p_header =\n\t\t\t\t((struct partition_record_size4 *)(header + sizeof(struct pc_header))) + i;\n\t\t\tcap = get_unaligned_be64(&mam.remaining_capacity) / lu_priv->capacity_unit;\n\t\t\tput_unaligned_be32(0xfffffffe, &p_header->data);\n\t\t\tMHVTL_DBG(1, \"remaining capacity to EW for partition %d : %u\",\n\t\t\t\t\t  i, get_unaligned_be32(&p_header->data));\n\t\t}\n\t}\n}\n\n/* Only valid for SSC devices */\nint update_TapeAlert(uint64_t flags) {\n\tstruct SequentialAccessDevice_pg *sad;\n\tstruct log_pg_list\t\t\t\t *l;\n\tuint64_t\t\t\t\t\t\t  ta;\n\n\tl = lookup_log_pg(&lunit.log_pg, SEQUENTIAL_ACCESS_DEVICE, NO_SUBPAGE);\n\tif (l) {\n\t\tsad = (struct SequentialAccessDevice_pg *)l->p;\n\t\tta\t= get_unaligned_be64(&sad->TapeAlert);\n\t\tMHVTL_DBG(2, \"Adding flags: %.8x %.8x to %.8x %.8x\",\n\t\t\t\t  (uint32_t)(flags >> 32) & 0xffffffff,\n\t\t\t\t  (uint32_t)flags & 0xffffffff,\n\t\t\t\t  (uint32_t)(ta >> 32) & 0xffffffff,\n\t\t\t\t  (uint32_t)ta & 0xffffffff);\n\t\tset_TapeAlert(ta | flags);\n\t\tif (flags & 1L << 19) /* Clean Now (required) */\n\t\t\tset_lp_11_crqrd(1);\n\t\telse\n\t\t\tset_lp_11_crqrd(0);\n\t\tif (flags & 1L << 20) /* Clean Periodic (requested) */\n\t\t\tset_lp_11_crqst(1);\n\t\telse\n\t\t\tset_lp_11_crqst(0);\n\n\t\treturn 0;\n\t}\n\treturn -1;\n}\n\nint set_TapeAlert(uint64_t flags) {\n\tstruct SequentialAccessDevice_pg *sad;\n\tstruct TapeAlert_pg\t\t\t\t *ta;\n\tstruct DeviceStatus_pg\t\t\t *ds;\n\tstruct log_pg_list\t\t\t\t *l;\n\tint\t\t\t\t\t\t\t\t  i;\n\n\t/* Set LP 0x11 'TAFC' bit (TapeAlert Flag Changed) */\n\tds = lookup_device_status_pg();\n\tif (ds) {\n\t\tif (flags) {\n\t\t\tds->vhf.b7.TAFC = 1;\n\t\t\tMHVTL_DBG(2, \"Setting TAFC bit true\");\n\t\t} else {\n\t\t\tds->vhf.b7.TAFC = 0;\n\t\t\tMHVTL_DBG(3, \"Not setting TAFC bit as flags is zero\");\n\t\t}\n\t}\n\n\tl = lookup_log_pg(&lunit.log_pg, TAPE_ALERT, NO_SUBPAGE);\n\tif (!l)\n\t\treturn -1;\n\n\tta = (struct TapeAlert_pg *)l->p;\n\n\tMHVTL_DBG(2, \"Setting TapeAlert flags 0x%.8x %.8x\",\n\t\t\t  (uint32_t)(flags >> 32) & 0xffffffff,\n\t\t\t  (uint32_t)flags & 0xffffffff);\n\n\tfor (i = 0; i < 64; i++)\n\t\tta->TapeAlert[i].value = (flags & (1ull << i)) ? 1 : 0;\n\n\t/* Don't treat not having a SEQUENTIAL ACCESS DEVICE log page\n\t * as fatal (e.g. SMC devices)\n\t */\n\tl = lookup_log_pg(&lunit.log_pg, SEQUENTIAL_ACCESS_DEVICE, NO_SUBPAGE);\n\tif (l) {\n\t\tsad = (struct SequentialAccessDevice_pg *)l->p;\n\t\tput_unaligned_be64(flags, &sad->TapeAlert);\n\t}\n\tif (flags & 1L << 19) /* Clean Now (required) */\n\t\tset_lp_11_crqrd(1);\n\telse\n\t\tset_lp_11_crqrd(0);\n\tif (flags & 1L << 20) /* Clean Periodic (requested) */\n\t\tset_lp_11_crqst(1);\n\telse\n\t\tset_lp_11_crqst(0);\n\n\treturn 0;\n}\n\nvoid update_TapeUsage(struct TapeUsage_pg *b) {\n\tuint64_t datasets = count_filemarks(-1);\n\tuint64_t load_count;\n\n\t/* if we have more than 1 filemark,\n\t * most apps write 2 filemarks to flag EOD\n\t * So, lets subtract one from the filemark count to\n\t * present a more accurate 'Data Set' count\n\t */\n\tif (datasets > 1)\n\t\tdatasets--;\n\n\tload_count = get_unaligned_be64(&lu_ssc.mamp->LoadCount);\n\tput_unaligned_be32(load_count, &b->volumeMounts);\n\n\tput_unaligned_be64(datasets, &b->volumeDatasetsWritten);\n}\n\nvoid update_TapeCapacity(struct TapeCapacity_pg *pg) {\n\tuint64_t cap __attribute__((unused)); /* fixme : should be used instead of telling max cap */\n\tif (get_tape_load_status() == TAPE_LOADED) {\n\t\tcap = get_unaligned_be64(&mam.remaining_capacity) / lu_ssc.capacity_unit;\n\t\tput_unaligned_be32(0xfffffffe, &pg->partition0remaining);\n\t\tput_unaligned_be32(0xfffffffe, &pg->partition1remaining);\n\n\t\tcap = get_unaligned_be64(&mam.max_capacity) / lu_ssc.capacity_unit;\n\t\tput_unaligned_be32(0xfffffffe, &pg->partition0maximum);\n\t\tput_unaligned_be32(0xfffffffe, &pg->partition1maximum);\n\t} else {\n\t\tpg->partition0remaining = 0;\n\t\tpg->partition0maximum\t= 0;\n\t\tpg->partition1remaining = 0;\n\t\tpg->partition1maximum\t= 0;\n\t}\n}\n\nvoid update_SequentialAccessDevice(struct SequentialAccessDevice_pg *sa) {\n\tput_unaligned_be64(lu_ssc.bytesWritten_I,\n\t\t\t\t\t   &sa->writeDataB4Compression);\n\tput_unaligned_be64(lu_ssc.bytesWritten_M,\n\t\t\t\t\t   &sa->writeDataAfCompression);\n\tput_unaligned_be64(lu_ssc.bytesRead_M,\n\t\t\t\t\t   &sa->readDataB4Compression);\n\tput_unaligned_be64(lu_ssc.bytesRead_I,\n\t\t\t\t\t   &sa->readDataAfCompression);\n\n\t/* Values in MBytes */\n\tif (get_tape_load_status() == TAPE_LOADED) {\n\t\tput_unaligned_be32(lu_ssc.max_capacity >> 20,\n\t\t\t\t\t\t   &sa->capacity_bop_eod);\n\t\tput_unaligned_be32(lu_ssc.early_warning_position >> 20,\n\t\t\t\t\t\t   &sa->capacity_bop_ew);\n\t\tput_unaligned_be32(lu_ssc.early_warning_sz >> 20,\n\t\t\t\t\t\t   &sa->capacity_ew_leop);\n\t\tput_unaligned_be32(current_tape_offset() >> 20,\n\t\t\t\t\t\t   &sa->capacity_bop_curr);\n\t} else {\n\t\tput_unaligned_be32(0xffffffff, &sa->capacity_bop_eod);\n\t\tput_unaligned_be32(0xffffffff, &sa->capacity_bop_ew);\n\t\tput_unaligned_be32(0xffffffff, &sa->capacity_ew_leop);\n\t\tput_unaligned_be32(0xffffffff, &sa->capacity_bop_curr);\n\t}\n}\n\nvoid set_current_state(int s) {\n\tstruct DeviceStatus_pg *lp = lookup_device_status_pg();\n\n\tcurrent_state = s;\n\n\t/* Now translate the 'mhVTL' state into DT Device Activity values */\n\tif (lp) {\n\t\tswitch (s) {\n\t\tcase MHVTL_STATE_UNLOADED:\n\t\t\tlp->vhf.b6 = 0;\n\t\t\tbreak;\n\t\tcase MHVTL_STATE_LOADING:\n\t\t\tlp->vhf.b6 = 2;\n\t\t\tbreak;\n\t\tcase MHVTL_STATE_LOADING_CLEAN:\n\t\t\tlp->vhf.b6 = 1;\n\t\t\tbreak;\n\t\tcase MHVTL_STATE_LOADING_WORM:\n\t\t\tlp->vhf.b6 = 2;\n\t\t\tbreak;\n\t\tcase MHVTL_STATE_LOADED:\n\t\t\tlp->vhf.b6 = 0;\n\t\t\tbreak;\n\t\tcase MHVTL_STATE_LOADED_IDLE:\n\t\t\tlp->vhf.b6 = 0;\n\t\t\tbreak;\n\t\tcase MHVTL_STATE_LOAD_FAILED:\n\t\t\tlp->vhf.b6 = 0;\n\t\t\tset_lp_11_macc(0); /* MAM Accessible - False */\n\t\t\tbreak;\n\t\tcase MHVTL_STATE_REWIND:\n\t\t\tlp->vhf.b6 = 0x8;\n\t\t\tbreak;\n\t\tcase MHVTL_STATE_POSITIONING:\n\t\t\tlp->vhf.b6 = 0x7;\n\t\t\tbreak;\n\t\tcase MHVTL_STATE_LOCATE:\n\t\t\tlp->vhf.b6 = 0x7;\n\t\t\tbreak;\n\t\tcase MHVTL_STATE_READING:\n\t\t\tlp->vhf.b6 = 0x5;\n\t\t\tbreak;\n\t\tcase MHVTL_STATE_WRITING:\n\t\t\tlp->vhf.b6 = 0x6;\n\t\t\tbreak;\n\t\tcase MHVTL_STATE_UNLOADING:\n\t\t\tlp->vhf.b6 = 0x3;\n\t\t\tbreak;\n\t\tcase MHVTL_STATE_ERASE:\n\t\t\tlp->vhf.b6 = 0x9;\n\t\t\tbreak;\n\t\tcase MHVTL_STATE_VERIFY:\n\t\t\tlp->vhf.b6 = 0x4;\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/* FIXME: Add VHF log page stuff here */\nint get_tape_load_status(void) {\n\treturn lu_ssc.load_status;\n}\n\nvoid set_tape_load_status(int s) {\n\tstruct DeviceStatus_pg *lp = lookup_device_status_pg();\n\n\tlu_ssc.load_status = s;\n\n\tif (lp) {\n\t\tswitch (s) {\n\t\tcase TAPE_UNLOADED:\n\t\t\tlp->vhf.b5.INXTN   = 1; /* In transition */\n\t\t\tlp->vhf.b5.MSTD\t   = 0; /* Medium seated */\n\t\t\tlp->vhf.b5.MTHRD   = 0; /* Medium threaded */\n\t\t\tlp->vhf.b5.MOUNTED = 0; /* Medium mounted */\n\t\t\tlp->vhf.b5.MPRSNT  = 0; /* Medium Present */\n\t\t\tlp->vhf.b5.RAA\t   = 1; /* Robotic access allowed */\n\t\t\tlp->vhf.b5.INXTN   = 0; /* Completed updates */\n\t\t\tset_lp_11_macc(0);\t\t/* MAM Accessible */\n\t\t\tbreak;\n\t\tcase TAPE_LOADED:\n\t\t\tlp->vhf.b5.INXTN   = 1; /* In transition */\n\t\t\tlp->vhf.b5.MSTD\t   = 1; /* Medium seated */\n\t\t\tlp->vhf.b5.MTHRD   = 1; /* Medium threaded */\n\t\t\tlp->vhf.b5.MOUNTED = 1; /* Medium mounted */\n\t\t\tlp->vhf.b5.MPRSNT  = 1; /* Medium Present */\n\t\t\tlp->vhf.b5.RAA\t   = 1; /* Robotic access allowed */\n\t\t\tlp->vhf.b5.INXTN   = 0; /* Completed updates */\n\t\t\tset_lp_11_macc(1);\t\t/* MAM Accessible */\n\t\t\tbreak;\n\t\tcase TAPE_LOADING:\n\t\t\tlp->vhf.b5.INXTN   = 1; /* In transition */\n\t\t\tlp->vhf.b5.MSTD\t   = 1; /* Medium seated */\n\t\t\tlp->vhf.b5.MTHRD   = 0; /* Medium threaded */\n\t\t\tlp->vhf.b5.MOUNTED = 0; /* Medium mounted */\n\t\t\tlp->vhf.b5.MPRSNT  = 1; /* Medium Present */\n\t\t\tlp->vhf.b5.RAA\t   = 1; /* Robotic access allowed */\n\t\t\tlp->vhf.b5.INXTN   = 0; /* Completed updates */\n\t\t\tset_lp_11_macc(0);\t\t/* MAM Accessible */\n\t\t\tbreak;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "usr/mode.c",
    "content": "/*\n * This handles any SCSI OP 'mode sense / mode select'\n *\n * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n * See comments in vtltape.c for a more complete version release...\n *\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <inttypes.h>\n#include <errno.h>\n#include \"mhvtl_scsi.h\"\n#include \"mhvtl_list.h\"\n#include \"logging.h\"\n#include \"vtllib.h\"\n#include \"ssc.h\"\n#include \"smc.h\"\n#include \"be_byteshift.h\"\n#include \"mode.h\"\n#include \"mhvtl_log.h\"\n\nstatic char *mode_rw_error_recover\t\t  = \"Read/Write Error Recovery\";\nstatic char *mode_disconnect_reconnect\t  = \"Disconnect/Reconnect\";\nstatic char *mode_control\t\t\t\t  = \"Control\";\nstatic char *mode_control_extension\t\t  = \"Control Extension\";\nstatic char *mode_control_data_protection = \"Control Data Protection\";\nstatic char *mode_data_compression\t\t  = \"Data Compression\";\nstatic char *mode_device_configuration\t  = \"Device Configuration\";\nstatic char *mode_device_configuration_extension =\n\t\"Device Configuration Extension\";\nstatic char *mode_medium_partition\t\t   = \"Medium Partition\";\nstatic char *mode_power_condition\t\t   = \"Power Condition\";\nstatic char *mode_information_exception\t   = \"Information Exception\";\nstatic char *mode_medium_configuration\t   = \"Medium Configuration\";\nstatic char *mode_vendor_24h\t\t\t   = \"Vendor (IBM) unique page 24h\"\n\t\t\t\t\t\t\t\t\t\t\t \" - Advise ENCRYPTION Capable device\";\nstatic char *mode_vendor_25h\t\t\t   = \"Vendor (IBM) unique page 25h\"\n\t\t\t\t\t\t\t\t\t\t\t \" - Early Warning\";\nstatic char *mode_encryption_mode\t\t   = \"Encryption Mode\";\nstatic char *mode_behaviour_configuration  = \"Behaviour Configuration\";\nstatic char *mode_ait_device_configuration = \"AIT Device Configuration\";\nstatic char *mode_element_address\t\t   = \"Element Address\";\nstatic char *mode_transport_geometry\t   = \"Transport Geometry\";\nstatic char *mode_device_capabilities\t   = \"Device Capabilities\";\nstatic char *drive_configuration_page\t   = \"STK Vendor-Unique Drive Configuration\";\n\nstruct mode *lookup_mode_pg(struct list_head *m, uint8_t page, uint8_t subpage) {\n\tstruct mode *mp;\n\n\tMHVTL_DBG(3, \"fetching mode page (0x%02x - 0x%02x)\", page, subpage);\n\n\tlist_for_each_entry(mp, m, siblings) {\n\t\tif (mp->pcode == page && mp->subpcode == subpage) {\n\t\t\tMHVTL_DBG(3, \"mode page (0x%02x - 0x%02x) found : %s\", page, subpage, mp->description);\n\t\t\treturn mp;\n\t\t}\n\t}\n\n\tMHVTL_DBG(3, \"mode page (0x%02x - 0x%02x) not found\", page, subpage);\n\n\treturn NULL;\n}\n\n/*\n * Used by mode sense/mode select struct.\n *\n * Allocate 'size' bytes & init to 0\n * set first 2 bytes:\n *  byte[0] = pcode\n *  byte[1] = size - sizeof(byte[0])\n *\n * Return pointer to mode structure being init. or NULL if alloc failed\n */\nstatic struct mode *alloc_mode_page(struct list_head *m,\n\t\t\t\t\t\t\t\t\tuint8_t pcode, uint8_t subpcode, int size) {\n\tstruct mode *mp;\n\n\tMHVTL_DBG(3, \"Allocating %d bytes for (%02x/%02x)\",\n\t\t\t  size, pcode, subpcode);\n\n\tmp = lookup_mode_pg(m, pcode, subpcode);\n\tif (!mp) { /* Create a new entry */\n\t\tmp = (struct mode *)zalloc(sizeof(struct mode));\n\t}\n\tif (mp) {\n\t\tmp->pcodePointer = (uint8_t *)zalloc(size);\n\t\tif (mp->pcodePointer) { /* If ! null, set size of data */\n\t\t\tmp->pcode\t  = pcode;\n\t\t\tmp->subpcode  = subpcode;\n\t\t\tmp->pcodeSize = size;\n\n\t\t\t/* Allocate a 'changeable bitmap' mode page info */\n\t\t\tmp->pcodePointerBitMap = zalloc(size);\n\t\t\tif (!mp->pcodePointerBitMap) {\n\t\t\t\tfree(mp);\n\t\t\t\tMHVTL_ERR(\"Mode Pointer bitmap: Unable to malloc(%d)\", size);\n\t\t\t\treturn NULL;\n\t\t\t}\n\n\t\t\tlist_add_tail(&mp->siblings, m);\n\t\t\treturn mp;\n\t\t} else {\n\t\t\tMHVTL_ERR(\"Unable to malloc(%d)\", size);\n\t\t\tfree(mp);\n\t\t}\n\t}\n\treturn NULL;\n}\n\nvoid dealloc_all_mode_pages(struct lu_phy_attr *lu) {\n\tstruct mode *mp, *mn;\n\n\tlist_for_each_entry_safe(mp, mn, &lu->mode_pg, siblings) {\n\t\tMHVTL_DBG(2, \"Removing %s\", mp->description);\n\t\tfree(mp->pcodePointer);\n\t\tfree(mp->pcodePointerBitMap);\n\t\tlist_del(&mp->siblings);\n\t\tfree(mp);\n\t}\n}\n\n/*\n * READ/WRITE Error Recovery\n * SSC3-8.3.5\n */\nint add_mode_page_rw_err_recovery(struct lu_phy_attr *lu) {\n\tstruct list_head *mode_pg;\n\tstruct mode\t\t *mp;\n\tuint8_t\t\t\t  pcode;\n\tuint8_t\t\t\t  subpcode;\n\tuint8_t\t\t\t  size;\n\n\tpcode\t = MODE_RW_ERROR_RECOVER;\n\tsubpcode = 0;\n\tsize\t = 12;\n\n\tmode_pg = &lu->mode_pg;\n\n\tMHVTL_DBG(3, \"Adding mode page %s (%02x/%02x)\",\n\t\t\t  mode_rw_error_recover, pcode, subpcode);\n\n\tmp = alloc_mode_page(mode_pg, pcode, subpcode, size);\n\tif (!mp)\n\t\treturn -ENOMEM;\n\n\tmp->pcodePointer[0] = pcode;\n\tmp->pcodePointer[1] = size - sizeof(mp->pcodePointer[0]) - sizeof(mp->pcodePointer[1]);\n\n\t/* And copy pcode/size into bitmap structure */\n\tmp->pcodePointerBitMap[0] = mp->pcodePointer[0];\n\tmp->pcodePointerBitMap[1] = mp->pcodePointer[1];\n\n\tmp->description = mode_rw_error_recover;\n\n\treturn 0;\n}\n\n/*\n * Disconnect / Reconnect\n * SPC3-7.4.8\n */\nint add_mode_disconnect_reconnect(struct lu_phy_attr *lu) {\n\tstruct list_head *mode_pg;\n\tstruct mode\t\t *mp;\n\tuint8_t\t\t\t  pcode;\n\tuint8_t\t\t\t  subpcode;\n\tuint8_t\t\t\t  size;\n\n\tmode_pg\t = &lu->mode_pg;\n\tpcode\t = MODE_DISCONNECT_RECONNECT;\n\tsubpcode = 0;\n\tsize\t = 0x0e + 2;\n\n\tMHVTL_DBG(3, \"Adding mode page %s (%02x/%02x)\",\n\t\t\t  mode_disconnect_reconnect, pcode, subpcode);\n\n\tmp = alloc_mode_page(mode_pg, pcode, subpcode, size);\n\tif (!mp)\n\t\treturn -ENOMEM;\n\n\tmp->pcodePointer[0] = pcode;\n\tmp->pcodePointer[1] = size - sizeof(mp->pcodePointer[0]) - sizeof(mp->pcodePointer[1]);\n\n\t/* And copy pcode/size into bitmap structure */\n\tmp->pcodePointerBitMap[0] = mp->pcodePointer[0];\n\tmp->pcodePointerBitMap[1] = mp->pcodePointer[1];\n\n\tmp->pcodePointer[2]\t = 50; /* Buffer full ratio */\n\tmp->pcodePointer[3]\t = 50; /* Buffer empty ratio */\n\tmp->pcodePointer[10] = 4;\n\n\tmp->description = mode_disconnect_reconnect;\n\n\treturn 0;\n}\n\n/*\n * Control\n * SPC3\n */\nint add_mode_control(struct lu_phy_attr *lu) {\n\tstruct list_head *mode_pg;\n\tstruct mode\t\t *mp;\n\tuint8_t\t\t\t  pcode;\n\tuint8_t\t\t\t  subpcode;\n\tuint8_t\t\t\t  size;\n\n\tmode_pg\t = &lu->mode_pg;\n\tpcode\t = MODE_CONTROL;\n\tsubpcode = 0;\n\tsize\t = 12;\n\n\tMHVTL_DBG(3, \"Adding mode page %s (%02x/%02x)\",\n\t\t\t  mode_control, pcode, subpcode);\n\n\tmp = alloc_mode_page(mode_pg, pcode, subpcode, size);\n\tif (!mp)\n\t\treturn -ENOMEM;\n\n\tmp->pcodePointer[0] = pcode;\n\tmp->pcodePointer[1] = size - sizeof(mp->pcodePointer[0]) - sizeof(mp->pcodePointer[1]);\n\n\t/* And copy pcode/size into bitmap structure */\n\tmp->pcodePointerBitMap[0] = mp->pcodePointer[0];\n\tmp->pcodePointerBitMap[1] = mp->pcodePointer[1];\n\n\tmp->description = mode_control;\n\n\treturn 0;\n}\n\n/*\n * Control Extension 0x0A/0x01\n * SPC3\n */\nint add_mode_control_extension(struct lu_phy_attr *lu) {\n\tstruct list_head *mode_pg;\n\tstruct mode\t\t *mp;\n\tuint8_t\t\t\t  pcode;\n\tuint8_t\t\t\t  subpcode;\n\tuint8_t\t\t\t  size;\n\n\tmode_pg\t = &lu->mode_pg;\n\tpcode\t = MODE_CONTROL;\n\tsubpcode = 1;\n\tsize\t = 0x1e; /* 0x1c + 2 for page/subpage code */\n\n\tMHVTL_DBG(3, \"Adding mode page %s (%02x/%02x)\",\n\t\t\t  mode_control_extension, pcode, subpcode);\n\n\tmp = alloc_mode_page(mode_pg, pcode, subpcode, size);\n\tif (!mp)\n\t\treturn -ENOMEM;\n\n\tmp->pcodePointer[0] = pcode;\n\tmp->pcodePointer[1] = subpcode;\n\tput_unaligned_be16(size - sizeof(mp->pcodePointer[0]) - sizeof(mp->pcodePointer[1]),\n\t\t\t\t\t   &mp->pcodePointer[2]);\n\n\t/* And copy pcode/size into bitmap structure */\n\tmp->pcodePointerBitMap[0] = mp->pcodePointer[1];\n\tmp->pcodePointerBitMap[1] = mp->pcodePointer[2];\n\n\tmp->description = mode_control_extension;\n\n\treturn 0;\n}\n\n/*\n * Control Data Protection Mode page 0x0A/0xF0\n * IBM Ultrium Logical Block Protection\n */\nint add_mode_control_data_protection(struct lu_phy_attr *lu) {\n\tstruct list_head *mode_pg;\n\tstruct mode\t\t *mp;\n\tuint8_t\t\t\t  pcode;\n\tuint8_t\t\t\t  subpcode;\n\tuint8_t\t\t\t  size;\n\n\tmode_pg\t = &lu->mode_pg;\n\tpcode\t = MODE_CONTROL;\n\tsubpcode = 0xf0;\n\tsize\t = 0x1e; /* 0x1c + two bytes for page/subpage */\n\n\tMHVTL_DBG(3, \"Adding mode page %s (%02x/%02x)\",\n\t\t\t  mode_control_extension, pcode, subpcode);\n\n\tmp = alloc_mode_page(mode_pg, pcode, subpcode, size);\n\tif (!mp)\n\t\treturn -ENOMEM;\n\n\tMHVTL_DBG(3, \"Added mode page %s (%02x/%02x)\",\n\t\t\t  mode_control_extension, pcode, subpcode);\n\n\tmp->pcodePointer[0] = pcode;\n\tmp->pcodePointer[1] = subpcode;\n\tput_unaligned_be16(size - sizeof(mp->pcodePointer[0]) - sizeof(mp->pcodePointer[1]),\n\t\t\t\t\t   &mp->pcodePointer[2]);\n\n\t/* And copy pcode/size into bitmap structure */\n\tmp->pcodePointerBitMap[0] = mp->pcodePointer[1];\n\tmp->pcodePointerBitMap[1] = mp->pcodePointer[2];\n\n\tmp->description = mode_control_data_protection;\n\n\t/* Default to off */\n\tmp->pcodePointer[4] = 0x00; /* LBP Method: 0 off, 1 Reed-Solomon CRC, 2 CRC32C */\n\tmp->pcodePointer[5] = 0x04; /* LBP length - 32bit CRC */\n\tmp->pcodePointer[6] = 0;\t/* LBP on write and LBP on read */\n\n\t/* And define changeable bits */\n\tmp->pcodePointerBitMap[4] = 0x03;\n\tmp->pcodePointerBitMap[5] = 0x07;\n\tmp->pcodePointerBitMap[6] = 0xc0;\n\n\treturn 0;\n}\n\n/*\n * Data Compression\n * SSC3-8.3.2\n */\n#define COMPRESSION_TYPE 0x10\n\nint add_mode_data_compression(struct lu_phy_attr *lu) {\n\tstruct list_head *mode_pg;\n\tstruct mode\t\t *mp;\n\tuint8_t\t\t\t  pcode;\n\tuint8_t\t\t\t  subpcode;\n\tuint8_t\t\t\t  size;\n\n\tmode_pg\t = &lu->mode_pg;\n\tpcode\t = MODE_DATA_COMPRESSION;\n\tsubpcode = 0;\n\tsize\t = 16;\n\n\tMHVTL_DBG(3, \"Adding mode page %s (%02x/%02x)\",\n\t\t\t  mode_data_compression, pcode, subpcode);\n\n\tmp = alloc_mode_page(mode_pg, pcode, subpcode, size);\n\tif (!mp)\n\t\treturn -ENOMEM;\n\n\tmp->pcodePointer[0] = pcode;\n\tmp->pcodePointer[1] = size - sizeof(mp->pcodePointer[0]) - sizeof(mp->pcodePointer[1]);\n\n\t/* And copy pcode/size into bitmap structure */\n\tmp->pcodePointerBitMap[0] = mp->pcodePointer[0];\n\tmp->pcodePointerBitMap[1] = mp->pcodePointer[1];\n\n\tmp->pcodePointer[2] = 0xc0; /* Set data compression enable */\n\tmp->pcodePointer[3] = 0x80; /* Set data decompression enable */\n\tput_unaligned_be32(COMPRESSION_TYPE, &mp->pcodePointer[4]);\n\tput_unaligned_be32(COMPRESSION_TYPE, &mp->pcodePointer[8]);\n\n\t/* Changeable fields */\n\tmp->pcodePointerBitMap[2] = 0xc0;\t\t\t\t\t  /* DCE & DCC */\n\tmp->pcodePointerBitMap[3] = 0x80;\t\t\t\t\t  /* DDE bit */\n\tput_unaligned_be32(0xffffffff, &mp->pcodePointer[4]); /* Comp alg */\n\tput_unaligned_be32(0xffffffff, &mp->pcodePointer[8]); /* De-comp alg */\n\n\tmp->description = mode_data_compression;\n\n\treturn 0;\n}\n\nvoid set_mode_compression(struct scsi_cmd *cmd, uint8_t *p) {\n\tstruct lu_phy_attr\t\t\t\t*lu\t\t = cmd->lu;\n\tstruct priv_lu_ssc\t\t\t\t*lu_priv = lu->lu_private;\n\tstruct ssc_personality_template *pm\t\t = lu_priv->pm;\n\n\tint dce = p[2] & 0x80;\n\n\tMHVTL_DBG(2, \" Data Compression Enable   : %s (0x%02x)\",\n\t\t\t  (p[2] & 0x80) ? \"Yes\" : \"No\", p[2]);\n\tMHVTL_DBG(2, \" Data Compression Capable  : %s\",\n\t\t\t  (p[2] & 0x40) ? \"Yes\" : \"No\");\n\tMHVTL_DBG(2, \" Data DeCompression Enable : %s (0x%02x)\",\n\t\t\t  (p[3] & 0x80) ? \"Yes\" : \"No\", p[3]);\n\tMHVTL_DBG(2, \" Compression Algorithm     : 0x%04x\",\n\t\t\t  get_unaligned_be32(&p[4]));\n\tMHVTL_DBG(2, \" DeCompression Algorithm   : 0x%04x\",\n\t\t\t  get_unaligned_be32(&p[8]));\n\tMHVTL_DBG(2, \" Report Exception on Decompression: 0x%02x\",\n\t\t\t  (p[3] & 0x6) >> 5);\n\n\tif (dce) { /* Data Compression Enable bit set */\n\t\tMHVTL_DBG(1, \" Setting compression\");\n\t\tif (pm->set_compression) {\n\t\t\tpm->set_compression(&lu->mode_pg,\n\t\t\t\t\t\t\t\tlu_priv->configCompressionFactor);\n\t\t\tset_lp11_compression(1); /* Update LogPage 11 compression bit */\n\t\t}\n\t} else {\n\t\tMHVTL_DBG(1, \" Clearing compression\");\n\t\tif (pm->clear_compression) {\n\t\t\tpm->clear_compression(&lu->mode_pg);\n\t\t\tset_lp11_compression(0); /* Update LogPage 11 compression bit */\n\t\t}\n\t}\n}\n\n/*\n * Device Configuration\n * SSC3-8.3.3\n */\n\nint add_mode_device_configuration(struct lu_phy_attr *lu) {\n\tstruct list_head   *mode_pg;\n\tstruct mode\t\t   *mp;\n\tstruct priv_lu_ssc *ssc;\n\tuint8_t\t\t\t\tpcode;\n\tuint8_t\t\t\t\tsubpcode;\n\tuint8_t\t\t\t\tsize;\n\n\tssc\t\t = (struct priv_lu_ssc *)lu->lu_private;\n\tmode_pg\t = &lu->mode_pg;\n\tpcode\t = MODE_DEVICE_CONFIGURATION;\n\tsubpcode = 0;\n\tsize\t = 16;\n\n\tMHVTL_DBG(3, \"Adding mode page %s (%02x/%02x)\",\n\t\t\t  mode_device_configuration, pcode, subpcode);\n\n\tmp = alloc_mode_page(mode_pg, pcode, subpcode, size);\n\tif (!mp)\n\t\treturn -ENOMEM;\n\n\tmp->pcodePointer[0] = pcode;\n\tmp->pcodePointer[1] = size - sizeof(mp->pcodePointer[0]) - sizeof(mp->pcodePointer[1]);\n\n\tmp->pcodePointer[3] = 0; /* Active partition, default = 0 */\n\n\t/* And copy pcode/size into bitmap structure */\n\tmp->pcodePointerBitMap[0] = mp->pcodePointer[0];\n\tmp->pcodePointerBitMap[1] = mp->pcodePointer[1];\n\n\tmp->pcodePointer[7]\t = 0x64; /* Write delay (100mS intervals) */\n\tmp->pcodePointer[8]\t = 0x40; /* Block Identifiers supported */\n\tmp->pcodePointer[10] = 0x18; /* Enable EOD & Sync at early warning */\n\tmp->pcodePointer[14] = ssc->configCompressionFactor;\n\tmp->pcodePointer[15] = 0x80; /* WTRE (WORM handling) */\n\n\tmp->pcodePointerBitMap[14] = 0xff; /* Compression is changeable */\n\n\t/* Set pointer for compressionFactor to correct location in\n\t * mode page struct\n\t */\n\tssc->compressionFactor = &mp->pcodePointer[14];\n\n\tmp->description = mode_device_configuration;\n\n\treturn 0;\n}\n\nvoid set_device_configuration(struct scsi_cmd *cmd, uint8_t *p) {\n\tstruct lu_phy_attr\t\t\t\t*lu\t\t = cmd->lu;\n\tstruct priv_lu_ssc\t\t\t\t*lu_priv = cmd->lu->lu_private;\n\tstruct ssc_personality_template *pm\t\t = lu_priv->pm;\n\n\tMHVTL_DBG(2, \" Report Early Warning   : %s\",\n\t\t\t  (p[8] & 0x01) ? \"Yes\" : \"No\");\n\tMHVTL_DBG(2, \" Software Write Protect : %s\",\n\t\t\t  (p[10] & 0x04) ? \"Yes\" : \"No\");\n\tMHVTL_DBG(2, \" WORM Tamper Read Enable: %s\",\n\t\t\t  (p[15] & 0x80) ? \"Yes\" : \"No\");\n\n\tMHVTL_DBG(2, \" Setting device compression Algorithm\");\n\tif (p[14]) { /* Select Data Compression Alg */\n\t\tMHVTL_DBG(2, \"  Mode Select->Setting compression: %d\", p[14]);\n\t\tif (pm->set_compression) {\n\t\t\tpm->set_compression(&lu->mode_pg,\n\t\t\t\t\t\t\t\tlu_priv->configCompressionFactor);\n\t\t\tset_lp11_compression(1); /* Update LogPage 11 compression bit */\n\t\t}\n\t} else {\n\t\tMHVTL_DBG(2, \"  Mode Select->Clearing compression\");\n\t\tif (pm->clear_compression) {\n\t\t\tpm->clear_compression(&lu->mode_pg);\n\t\t\tset_lp11_compression(0); /* Update LogPage 11 compression bit */\n\t\t}\n\t}\n}\n\nint add_mode_device_configuration_extension(struct lu_phy_attr *lu) {\n\tstruct list_head\t\t\t\t*mode_pg;\n\tstruct priv_lu_ssc\t\t\t\t*ssc;\n\tstruct ssc_personality_template *pm;\n\tstruct mode\t\t\t\t\t\t*mp;\n\tuint8_t\t\t\t\t\t\t\t pcode;\n\tuint8_t\t\t\t\t\t\t\t subpcode;\n\tuint8_t\t\t\t\t\t\t\t size;\n\n\t/* Only for TAPE (SSC) devices */\n\tif (lu->ptype != TYPE_TAPE)\n\t\treturn -ENOTTY;\n\n\tssc = lu->lu_private;\n\tpm\t= ssc->pm;\n\n\tmode_pg\t = &lu->mode_pg;\n\tpcode\t = MODE_DEVICE_CONFIGURATION;\n\tsubpcode = 0x01;\n\tsize\t = 32;\n\n\tMHVTL_DBG(3, \"Adding mode page %s (%02x/%02x)\",\n\t\t\t  mode_device_configuration_extension, pcode, subpcode);\n\n\tmp = alloc_mode_page(mode_pg, pcode, subpcode, size);\n\tif (!mp)\n\t\treturn -ENOMEM;\n\n\tmp->pcodePointer[0] = pcode;\n\tmp->pcodePointer[1] = size - sizeof(mp->pcodePointer[0]) - sizeof(mp->pcodePointer[1]);\n\n\t/* And copy pcode/size into bitmap structure */\n\tmp->pcodePointerBitMap[0] = mp->pcodePointer[0];\n\tmp->pcodePointerBitMap[1] = mp->pcodePointer[1];\n\n\tmp->pcodePointer[5] = 0x02; /* Short erase mode  - write EOD */\n\n\t/* default size of early warning */\n\tput_unaligned_be16(0, &mp->pcodePointer[6]);\n\n\t/* Update mode page bitmap to reflect changeable fields */\n\tif (pm->drive_supports_append_only_mode)\n\t\tmp->pcodePointerBitMap[5] |= 0xf0;\n\tif (pm->drive_supports_prog_early_warning) {\n\t\tmp->pcodePointerBitMap[6] |= 0xff;\n\t\tmp->pcodePointerBitMap[7] |= 0xff;\n\t}\n\n\tmp->description = mode_device_configuration_extension;\n\n\treturn 0;\n}\n\nuint8_t set_device_configuration_extension(struct scsi_cmd *cmd, uint8_t *p) {\n\tstruct lu_phy_attr\t\t\t\t*lu\t\t  = cmd->lu;\n\tstruct priv_lu_ssc\t\t\t\t*lu_priv  = cmd->lu->lu_private;\n\tstruct ssc_personality_template *pm\t\t  = lu_priv->pm;\n\tuint8_t\t\t\t\t\t\t\t*sam_stat = &cmd->dbuf_p->sam_stat;\n\n\tstruct mode *mp;\n\tstruct s_sd\t sd;\n\tint\t\t\t page_code_len;\n\tint\t\t\t write_mode;\n\tint\t\t\t pews; /* Programable Early Warning Size */\n\n\tmp = lookup_mode_pg(&lu->mode_pg, MODE_DEVICE_CONFIGURATION, 1);\n\n\t/* Code error\n\t * Any device supporting this should have this mode page defined */\n\tif (!mp) {\n\t\tsam_hardware_error(E_INTERNAL_TARGET_FAILURE, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tpage_code_len = get_unaligned_be16(&p[2]);\n\n\tif (page_code_len != 0x1c) {\n\t\tsd.byte0\t\t = SKSV;\n\t\tsd.field_pointer = 2;\n\t\tMHVTL_LOG(\"Unexpected page code length.. Unexpected results\");\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_PARMS, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\twrite_mode = (p[5] & 0xf0) >> 4;\n\tif (write_mode > 1) {\n\t\tMHVTL_LOG(\"Unsupported write mode: 0x%x\", write_mode);\n\t\tsd.byte0\t\t = SKSV | BPV | 7; /* bit 7 */\n\t\tsd.field_pointer = 5;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_PARMS, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\tMHVTL_DBG(2, \"%s mode\", write_mode ? \"Append-only\" : \"Overwrite-allowed\");\n\n\tpews = get_unaligned_be16(&p[6]);\n\tif (pm->drive_supports_prog_early_warning) {\n\t\tMHVTL_DBG(2, \"Set Programable Early Warning Size: %d\", pews);\n\t\tlu_priv->prog_early_warning_sz = pews;\n\t\tupdate_prog_early_warning(lu);\n\t} else {\n\t\tMHVTL_DBG(2, \"Programable Early Warning Size not supported\"\n\t\t\t\t\t \" by this device\");\n\t}\n\n\tMHVTL_DBG(2, \"Volume containing encrypted logical blocks \"\n\t\t\t\t \"requires encryption: %d\",\n\t\t\t  p[8] & 0x01);\n\n\tif (pm->drive_supports_append_only_mode) {\n\t\t/* Can't reset append-only mode via mode page ssc4 8.3.8 */\n\t\tif (lu_priv->append_only_mode && write_mode == 0) {\n\t\t\tMHVTL_LOG(\"Can't reset append only mode via mode page\");\n\t\t\tsam_illegal_request(E_INVALID_FIELD_IN_PARMS,\n\t\t\t\t\t\t\t\tNULL, sam_stat);\n\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t}\n\t\tif (write_mode) {\n\t\t\tlu_priv->append_only_mode = write_mode;\n\t\t\tlu_priv->allow_overwrite  = FALSE;\n\t\t}\n\t}\n\n\t/* Now update our copy of this mode page */\n\tmp->pcodePointer[5] &= 0x0f;\n\tmp->pcodePointer[5] |= write_mode << 4;\n\n\treturn SAM_STAT_GOOD;\n}\n\nint add_mode_medium_partition(struct lu_phy_attr *lu) {\n\tstruct list_head *mode_pg;\n\tstruct mode\t\t *mp;\n\tuint8_t\t\t\t  pcode;\n\tuint8_t\t\t\t  subpcode;\n\tuint8_t\t\t\t  size;\n\n\tmode_pg\t = &lu->mode_pg;\n\tpcode\t = MODE_MEDIUM_PARTITION;\n\tsubpcode = 0;\n\tsize\t = 16;\n\n\tMHVTL_DBG(3, \"Adding mode page %s (%02x/%02x)\",\n\t\t\t  mode_medium_partition, pcode, subpcode);\n\n\tmp = alloc_mode_page(mode_pg, pcode, subpcode, size);\n\tif (!mp)\n\t\treturn -ENOMEM;\n\n\tmp->pcodePointer[0] = pcode;\n\tmp->pcodePointer[1] = size - sizeof(mp->pcodePointer[0]) - sizeof(mp->pcodePointer[1]);\n\n\t/* And copy pcode/size into bitmap structure */\n\tmp->pcodePointerBitMap[0] = mp->pcodePointer[0];\n\tmp->pcodePointerBitMap[1] = mp->pcodePointer[1];\n\n\tmp->pcodePointer[2] = MAX_PARTITIONS - 1; /* Maximum Additional Partitions */\n\tmp->pcodePointer[3] = MAX_PARTITIONS - 1; /* Additional Partitions Defined\n\t\t\t\t\t\t\t\t\t\t\t\t should be dynamically set to mam.num_partitions - 1 later */\n\n\tmp->pcodePointer[4] = 0x9c; /* FDP (Fixed Data Partitions) |\n\t\t\t\t\t\t\t\t *\tPSUM (partition size unit of measure) |\n\t\t\t\t\t\t\t\t *\tPOFM (partition on Format Medium) */\n\n\tmp->pcodePointer[5] = 0x03; /* Medium Format Recognition */\n\tmp->pcodePointer[6] = 0x09; /* Partitioning Type |\n\t\t\t\t\t\t\t\t * Partition Units\t */\n\n\t/* Partition size descriptors - sizes in GB*/\n\tput_unaligned_be16(0x0002, &mp->pcodePointer[8]);\n\tput_unaligned_be16(0x0002, &mp->pcodePointer[10]);\n\tput_unaligned_be16(0x0002, &mp->pcodePointer[12]);\n\tput_unaligned_be16(0x0002, &mp->pcodePointer[14]);\n\n\t/* Changeable fields */\n\tmp->pcodePointerBitMap[3] = 0xff;\n\tmp->pcodePointerBitMap[4] = 0xf8;\n\tmp->pcodePointerBitMap[6] = 0xff;\n\tput_unaligned_be16(0xffff, &mp->pcodePointerBitMap[8]);\n\tput_unaligned_be16(0xffff, &mp->pcodePointerBitMap[10]);\n\tput_unaligned_be16(0xffff, &mp->pcodePointerBitMap[12]);\n\tput_unaligned_be16(0xffff, &mp->pcodePointerBitMap[14]);\n\n\tmp->description = mode_medium_partition;\n\n\treturn 0;\n}\n\nvoid set_medium_partition(struct scsi_cmd *cmd, uint8_t *p) {\n\tstruct lu_phy_attr *lu = cmd->lu;\n\tstruct mode\t\t   *mp = lookup_mode_pg(&lu->mode_pg, MODE_MEDIUM_PARTITION, 0);\n\n\t/* ADDITIONAL PARTITIONS DEFINED */\n\tmp->pcodePointer[3] = p[3];\n\tmam.num_partitions\t= mp->pcodePointer[3] + 1;\n\tMHVTL_DBG(3, \"New total number of partitions : %d\", mam.num_partitions);\n\n\tmp->pcodePointer[4] = p[4]; /* flags */\n\tmp->pcodePointer[5] = p[5]; /* MEDIUM FORMAT RECOGNITION */\n\tmp->pcodePointer[6] = p[6]; /* PARTITIONING TYPE | PARTITION UNITS */\n\n\t/* PARTITION SIZES */\n\tfor (int k = 0; k < mam.num_partitions; k++) {\n\t\tput_unaligned_be16(p[8 + 2 * k], &mp->pcodePointer[8 + 2 * k]);\n\t}\n}\n\nint add_mode_power_condition(struct lu_phy_attr *lu) {\n\tstruct list_head *mode_pg;\n\tstruct mode\t\t *mp;\n\tuint8_t\t\t\t  pcode;\n\tuint8_t\t\t\t  subpcode;\n\tuint8_t\t\t\t  size;\n\n\tmode_pg\t = &lu->mode_pg;\n\tpcode\t = MODE_POWER_CONDITION;\n\tsubpcode = 0;\n\tsize\t = 0x26;\n\n\tMHVTL_DBG(3, \"Adding mode page %s (%02x/%02x)\",\n\t\t\t  mode_power_condition, pcode, subpcode);\n\n\tmp = alloc_mode_page(mode_pg, pcode, subpcode, size);\n\tif (!mp)\n\t\treturn -ENOMEM;\n\n\tmp->pcodePointer[0] = pcode;\n\tmp->pcodePointer[1] = size - sizeof(mp->pcodePointer[0]) - sizeof(mp->pcodePointer[1]);\n\n\t/* And copy pcode/size into bitmap structure */\n\tmp->pcodePointerBitMap[0] = mp->pcodePointer[0];\n\tmp->pcodePointerBitMap[1] = mp->pcodePointer[1];\n\n\tmp->description = mode_power_condition;\n\n\treturn 0;\n}\n\nint add_mode_information_exception(struct lu_phy_attr *lu) {\n\tstruct list_head *mode_pg;\n\tstruct mode\t\t *mp;\n\tuint8_t\t\t\t  pcode;\n\tuint8_t\t\t\t  subpcode;\n\tuint8_t\t\t\t  size;\n\n\tmode_pg\t = &lu->mode_pg;\n\tpcode\t = MODE_INFORMATION_EXCEPTION;\n\tsubpcode = 0;\n\tsize\t = 12;\n\n\tMHVTL_DBG(3, \"Adding mode page %s (%02x/%02x)\",\n\t\t\t  mode_information_exception, pcode, subpcode);\n\n\tmp = alloc_mode_page(mode_pg, pcode, subpcode, size);\n\tif (!mp)\n\t\treturn -ENOMEM;\n\n\tmp->pcodePointer[0] = pcode;\n\tmp->pcodePointer[1] = size - sizeof(mp->pcodePointer[0]) - sizeof(mp->pcodePointer[1]);\n\n\t/* And copy pcode/size into bitmap structure */\n\tmp->pcodePointerBitMap[0] = mp->pcodePointer[0];\n\tmp->pcodePointerBitMap[1] = mp->pcodePointer[1];\n\n\tmp->pcodePointer[2] = 0x08;\n\tmp->pcodePointer[3] = 0x03;\n\n\tmp->description = mode_information_exception;\n\n\treturn 0;\n}\n\nint add_mode_medium_configuration(struct lu_phy_attr *lu) {\n\tstruct list_head *mode_pg;\n\tstruct mode\t\t *mp;\n\tuint8_t\t\t\t  pcode;\n\tuint8_t\t\t\t  subpcode;\n\tuint8_t\t\t\t  size;\n\n\tmode_pg\t = &lu->mode_pg;\n\tpcode\t = MODE_MEDIUM_CONFIGURATION;\n\tsubpcode = 0;\n\tsize\t = 32;\n\n\tMHVTL_DBG(3, \"Adding mode page %s (%02x/%02x)\",\n\t\t\t  mode_medium_configuration, pcode, subpcode);\n\n\tmp = alloc_mode_page(mode_pg, pcode, subpcode, size);\n\tif (!mp)\n\t\treturn -ENOMEM;\n\n\tmp->pcodePointer[0] = pcode;\n\tmp->pcodePointer[1] = size - sizeof(mp->pcodePointer[0]) - sizeof(mp->pcodePointer[1]);\n\n\t/* And copy pcode/size into bitmap structure */\n\tmp->pcodePointerBitMap[0] = mp->pcodePointer[0];\n\tmp->pcodePointerBitMap[1] = mp->pcodePointer[1];\n\n\tmp->pcodePointer[4] = 0x01; /* WORM mode label restrictions */\n\tmp->pcodePointer[5] = 0x01; /* WORM mode filemark restrictions */\n\n\tmp->description = mode_medium_configuration;\n\n\treturn 0;\n}\n\n/*\n * Initialise structure data for mode pages.\n * - Allocate memory for each mode page & init to 0\n * - Set up size of mode page\n * - Set initial values of mode pages\n *\n * Return void  - Nothing\n */\nint add_mode_ult_encr_mode_pages(struct lu_phy_attr *lu) {\n\tstruct list_head *mode_pg; /* Mode Page list */\n\tstruct mode\t\t *mp;\n\tuint8_t\t\t\t  pcode;\n\tuint8_t\t\t\t  subpcode;\n\tuint8_t\t\t\t  size;\n\n\tmode_pg\t = &lu->mode_pg;\n\tpcode\t = MODE_VENDOR_SPECIFIC_24H;\n\tsubpcode = 0;\n\tsize\t = 8;\n\n\t/* Vendor Unique (IBM Ultrium)\n\t * Page 151, table 118\n\t * Advise ENCRYPTION Capable device\n\t */\n\tMHVTL_DBG(3, \"Adding mode page %s (%02x/%02x)\",\n\t\t\t  mode_vendor_24h, pcode, subpcode);\n\n\tmp = alloc_mode_page(mode_pg, pcode, subpcode, size);\n\tif (!mp)\n\t\treturn -ENOMEM;\n\n\tmp->pcodePointer[0] = pcode;\n\tmp->pcodePointer[1] = size - sizeof(mp->pcodePointer[0]) - sizeof(mp->pcodePointer[1]);\n\n\t/* And copy pcode/size into bitmap structure */\n\tmp->pcodePointerBitMap[0] = mp->pcodePointer[0];\n\tmp->pcodePointerBitMap[1] = mp->pcodePointer[1];\n\n\tmp->pcodePointer[7] = ENCR_C;\n\n\tmp->description = mode_vendor_24h;\n\n\treturn 0;\n}\n\n/*\n * Initialise structure data for mode pages.\n * - Allocate memory for each mode page & init to 0\n * - Set up size of mode page\n * - Set initial values of mode pages\n *\n * Return void  - Nothing\n */\nint add_mode_vendor_25h_mode_pages(struct lu_phy_attr *lu) {\n\tstruct list_head *mode_pg; /* Mode Page list */\n\tstruct mode\t\t *mp;\n\tuint8_t\t\t\t  pcode;\n\tuint8_t\t\t\t  subpcode;\n\tuint8_t\t\t\t  size;\n\n\tmode_pg\t = &lu->mode_pg;\n\tpcode\t = MODE_VENDOR_SPECIFIC_25H;\n\tsubpcode = 0;\n\tsize\t = 32;\n\n\t/* Vendor Unique (IBM Ultrium)\n\t * Page 151, table 118\n\t * Advise ENCRYPTION Capable device\n\t */\n\tMHVTL_DBG(3, \"Adding mode page %s (%02x/%02x)\",\n\t\t\t  mode_vendor_25h, pcode, subpcode);\n\n\tmp = alloc_mode_page(mode_pg, pcode, subpcode, size);\n\tif (!mp)\n\t\treturn -ENOMEM;\n\n\tmp->pcodePointer[0] = pcode;\n\tmp->pcodePointer[1] = size - sizeof(mp->pcodePointer[0]) - sizeof(mp->pcodePointer[1]);\n\n\t/* And copy pcode/size into bitmap structure */\n\tmp->pcodePointerBitMap[0] = mp->pcodePointer[0];\n\tmp->pcodePointerBitMap[1] = mp->pcodePointer[1];\n\n\tmp->pcodePointer[5] = 1; /* LEOP to maximize medium capacity */\n\tmp->pcodePointer[6] = 1; /* Early Warning */\n\n\tmp->description = mode_vendor_25h;\n\n\treturn 0;\n}\n\nint add_mode_encryption_mode_attribute(struct lu_phy_attr *lu) {\n\tstruct list_head *mode_pg;\n\tstruct mode\t\t *mp;\n\tuint8_t\t\t\t  pcode;\n\tuint8_t\t\t\t  subpcode;\n\tuint8_t\t\t\t  size;\n\n\tmode_pg\t = &lu->mode_pg;\n\tpcode\t = MODE_ENCRYPTION_MODE;\n\tsubpcode = 0x20;\n\tsize\t = 9;\n\n\tMHVTL_DBG(3, \"Adding mode page %s (%02x/%02x)\",\n\t\t\t  mode_encryption_mode, pcode, subpcode);\n\n\tmp = alloc_mode_page(mode_pg, pcode, subpcode, size);\n\tif (!mp)\n\t\treturn -ENOMEM;\n\n\tmp->pcodePointer[0] = pcode;\n\tmp->pcodePointer[1] = size - sizeof(mp->pcodePointer[0]) - sizeof(mp->pcodePointer[1]);\n\n\t/* And copy pcode/size into bitmap structure */\n\tmp->pcodePointerBitMap[0] = mp->pcodePointer[0];\n\tmp->pcodePointerBitMap[1] = mp->pcodePointer[1];\n\n\t/* Application Managed Encryption */\n\tmp->pcodePointer[5] = 0x03; /* Encryption Solution Method */\n\tmp->pcodePointer[6] = 0x01; /* Key Path */\n\tmp->pcodePointer[7] = 0x01; /* Default Encruption State */\n\tmp->pcodePointer[8] = 0x00; /* Desnity Reporting */\n\n\tmp->description = mode_encryption_mode;\n\n\treturn 0;\n}\n\nint add_mode_ait_device_configuration(struct lu_phy_attr *lu) {\n\tstruct list_head *mode_pg;\n\tstruct mode\t\t *mp;\n\tuint8_t\t\t\t  pcode;\n\tuint8_t\t\t\t  subpcode;\n\tuint8_t\t\t\t  size;\n\n\tmode_pg\t = &lu->mode_pg;\n\tpcode\t = MODE_AIT_DEVICE_CONFIGURATION;\n\tsubpcode = 0;\n\tsize\t = 8;\n\n\tMHVTL_DBG(3, \"Adding mode page %s (%02x/%02x)\",\n\t\t\t  mode_ait_device_configuration, pcode, subpcode);\n\n\tmp = alloc_mode_page(mode_pg, pcode, subpcode, size);\n\tif (!mp)\n\t\treturn -ENOMEM;\n\n\tmp->pcodePointer[0] = pcode;\n\tmp->pcodePointer[1] = size - sizeof(mp->pcodePointer[0]) - sizeof(mp->pcodePointer[1]);\n\n\t/* And copy pcode/size into bitmap structure */\n\tmp->pcodePointerBitMap[0] = mp->pcodePointer[0];\n\tmp->pcodePointerBitMap[1] = mp->pcodePointer[1];\n\n\tmp->pcodePointer[2] = 0xf0;\n\tmp->pcodePointer[3] = 0x0a;\n\tmp->pcodePointer[4] = 0x40;\n\n\tmp->description = mode_ait_device_configuration;\n\n\treturn 0;\n}\n\nint add_mode_element_address_assignment(struct lu_phy_attr *lu) {\n\tstruct list_head\t   *mode_pg;\n\tstruct mode\t\t\t   *mp;\n\tstatic struct smc_priv *smc_p;\n\tuint8_t\t\t\t\t\tpcode;\n\tuint8_t\t\t\t\t\tsubpcode;\n\tuint8_t\t\t\t\t\tsize;\n\tuint8_t\t\t\t\t   *p;\n\n\tmode_pg\t = &lu->mode_pg;\n\tsmc_p\t = (struct smc_priv *)lu->lu_private;\n\tpcode\t = MODE_ELEMENT_ADDRESS;\n\tsubpcode = 0;\n\tsize\t = 20;\n\n\tMHVTL_DBG(3, \"Adding mode page %s (%02x/%02x)\",\n\t\t\t  mode_element_address, pcode, subpcode);\n\n\tmp = alloc_mode_page(mode_pg, pcode, subpcode, size);\n\tif (!mp)\n\t\treturn -ENOMEM;\n\n\tp = mp->pcodePointer;\n\n\tp[0] = pcode;\n\tp[1] = size - sizeof(p[0]) - sizeof(p[1]);\n\n\t/* And copy pcode/size into bitmap structure */\n\tmp->pcodePointerBitMap[0] = mp->pcodePointer[0];\n\tmp->pcodePointerBitMap[1] = mp->pcodePointer[1];\n\n\tput_unaligned_be16(smc_p->pm->start_picker, &p[2]);\n\tput_unaligned_be16(smc_p->num_picker, &p[4]);\n\tput_unaligned_be16(smc_p->pm->start_storage, &p[6]);\n\tput_unaligned_be16(smc_p->num_storage, &p[8]);\n\tput_unaligned_be16(smc_p->pm->start_map, &p[10]);\n\tput_unaligned_be16(smc_p->num_map, &p[12]);\n\tput_unaligned_be16(smc_p->pm->start_drive, &p[14]);\n\tput_unaligned_be16(smc_p->num_drives, &p[16]);\n\n\tmp->description = mode_element_address;\n\n\treturn 0;\n}\n\n/*\n * Transport Geometry Parameters mode page\n * SMC-3 7.3.4\n */\nint add_mode_transport_geometry(struct lu_phy_attr *lu) {\n\tstruct list_head *mode_pg;\n\tstruct mode\t\t *mp;\n\tuint8_t\t\t\t  pcode;\n\tuint8_t\t\t\t  subpcode;\n\tuint8_t\t\t\t  size;\n\n\tmode_pg\t = &lu->mode_pg;\n\tpcode\t = MODE_TRANSPORT_GEOMETRY;\n\tsubpcode = 0;\n\tsize\t = 4;\n\n\tMHVTL_DBG(3, \"Adding mode page %s (%02x/%02x)\",\n\t\t\t  mode_transport_geometry, pcode, subpcode);\n\n\tmp = alloc_mode_page(mode_pg, pcode, subpcode, size);\n\tif (!mp)\n\t\treturn -ENOMEM;\n\n\tmp->pcodePointer[0] = pcode;\n\tmp->pcodePointer[1] = size - sizeof(mp->pcodePointer[0]) - sizeof(mp->pcodePointer[1]);\n\n\t/* And copy pcode/size into bitmap structure */\n\tmp->pcodePointerBitMap[0] = mp->pcodePointer[0];\n\tmp->pcodePointerBitMap[1] = mp->pcodePointer[1];\n\n\tmp->description = mode_transport_geometry;\n\n\treturn 0;\n}\n\n/*\n * Device Capabilities mode page:\n * SMC-3 7.3.2\n */\nint add_mode_device_capabilities(struct lu_phy_attr *lu) {\n\tstruct list_head *mode_pg;\n\tstruct mode\t\t *mp;\n\tuint8_t\t\t\t  pcode;\n\tuint8_t\t\t\t  subpcode;\n\tuint8_t\t\t\t  size;\n\n\tmode_pg\t = &lu->mode_pg;\n\tpcode\t = MODE_DEVICE_CAPABILITIES;\n\tsubpcode = 0;\n\tsize\t = 20;\n\n\tMHVTL_DBG(3, \"Adding mode page %s (%02x/%02x)\",\n\t\t\t  mode_device_capabilities, pcode, subpcode);\n\n\tmp = alloc_mode_page(mode_pg, pcode, subpcode, size);\n\tif (!mp)\n\t\treturn -ENOMEM;\n\n\tmp->pcodePointer[0] = pcode;\n\tmp->pcodePointer[1] = size - sizeof(mp->pcodePointer[0]) - sizeof(mp->pcodePointer[1]);\n\n\t/* And copy pcode/size into bitmap structure */\n\tmp->pcodePointerBitMap[0] = mp->pcodePointer[0];\n\tmp->pcodePointerBitMap[1] = mp->pcodePointer[1];\n\n\tmp->pcodePointer[2] = 0x0f;\n\tmp->pcodePointer[3] = 0x07;\n\tmp->pcodePointer[4] = 0x0f;\n\tmp->pcodePointer[5] = 0x0f;\n\tmp->pcodePointer[6] = 0x0f;\n\tmp->pcodePointer[7] = 0x0f;\n\t/* [8-11] -> reserved */\n\tmp->pcodePointer[12] = 0x00;\n\tmp->pcodePointer[13] = 0x00;\n\tmp->pcodePointer[14] = 0x00;\n\tmp->pcodePointer[15] = 0x00;\n\t/* [16-19] -> reserved */\n\n\tmp->description = mode_device_capabilities;\n\n\treturn 0;\n}\n\n/*\n * Behavior Configuration Mode Page\n * IBM Ultrium SCSI Reference - 9th Edition\n */\nint add_mode_behavior_configuration(struct lu_phy_attr *lu) {\n\tstruct list_head *mode_pg;\n\tstruct mode\t\t *mp;\n\tuint8_t\t\t\t  pcode;\n\tuint8_t\t\t\t  subpcode;\n\tuint8_t\t\t\t  size;\n\n\tmode_pg\t = &lu->mode_pg;\n\tpcode\t = MODE_BEHAVIOR_CONFIGURATION;\n\tsubpcode = 0;\n\tsize\t = 10;\n\n\tMHVTL_DBG(3, \"Adding mode page %s (%02x/%02x)\",\n\t\t\t  mode_behaviour_configuration, pcode, subpcode);\n\n\tmp = alloc_mode_page(mode_pg, pcode, subpcode, size);\n\tif (!mp)\n\t\treturn -ENOMEM;\n\n\tmp->pcodePointer[0] = pcode;\n\tmp->pcodePointer[1] = size - sizeof(mp->pcodePointer[0]) - sizeof(mp->pcodePointer[1]);\n\n\t/* And copy pcode/size into bitmap structure */\n\tmp->pcodePointerBitMap[0] = mp->pcodePointer[0];\n\tmp->pcodePointerBitMap[1] = mp->pcodePointer[1];\n\n\tmp->pcodePointer[3] = 0; /* Clean Behavior */\n\tmp->pcodePointer[4] = 0; /* WORM Behavior */\n\n\tmp->description = mode_behaviour_configuration;\n\n\treturn 0;\n}\n\nint update_prog_early_warning(struct lu_phy_attr *lu) {\n\tuint8_t\t\t\t   *mp;\n\tstruct mode\t\t   *m;\n\tstruct list_head   *mode_pg;\n\tstruct priv_lu_ssc *lu_priv;\n\n\tmode_pg = &lu->mode_pg;\n\tlu_priv = (struct priv_lu_ssc *)lu->lu_private;\n\n\tm = lookup_mode_pg(mode_pg, MODE_DEVICE_CONFIGURATION, 1);\n\tMHVTL_DBG(3, \"l: %p, m: %p, m->pcodePointer: %p\",\n\t\t\t  mode_pg, m, m->pcodePointer);\n\tif (m) {\n\t\tmp = m->pcodePointer;\n\t\tif (!mp)\n\t\t\treturn SAM_STAT_GOOD;\n\n\t\tput_unaligned_be16(lu_priv->prog_early_warning_sz, &mp[6]);\n\t}\n\treturn SAM_STAT_GOOD;\n}\n\nint update_logical_block_protection(struct lu_phy_attr *lu, uint8_t *buf) {\n\tuint8_t\t\t\t   *mp;\n\tstruct mode\t\t   *m;\n\tstruct list_head   *mode_pg;\n\tstruct priv_lu_ssc *lu_priv;\n\n\tmode_pg = &lu->mode_pg;\n\tlu_priv = (struct priv_lu_ssc *)lu->lu_private;\n\n\tMHVTL_DBG(3, \"+++ entry +++\");\n\n\tm = lookup_mode_pg(mode_pg, MODE_CONTROL, 0xf0);\n\tMHVTL_DBG(3, \"l: %p, m: %p, m->pcodePointer: %p\",\n\t\t\t  mode_pg, m, m->pcodePointer);\n\tif (m) {\n\t\tmp = m->pcodePointer;\n\t\tif (!mp) {\n\t\t\tMHVTL_ERR(\"Could not find mode page\");\n\t\t\treturn SAM_STAT_GOOD;\n\t\t}\n\t\tmp[4]\t\t\t\t= buf[4]; /* Logical Block Protection Method */\n\t\tmp[5]\t\t\t\t= buf[5]; /* Logical Block Protection Information Length */\n\t\tmp[6]\t\t\t\t= buf[6]; /* LBP_W & LBP_R */\n\t\tlu_priv->LBP_method = buf[4] & 0x03;\n\t\tlu_priv->LBP_R\t\t= (buf[6] & 0x40) ? 1 : 0;\n\t\tlu_priv->LBP_W\t\t= (buf[6] & 0x80) ? 1 : 0;\n\t\tMHVTL_DBG(1, \"Updating Logical Block Protection: Method: 0x%02x, LBP_R: %s, LPB_W: %s\",\n\t\t\t\t  lu_priv->LBP_method,\n\t\t\t\t  lu_priv->LBP_R ? \"True\" : \"False\",\n\t\t\t\t  lu_priv->LBP_W ? \"True\" : \"False\");\n\t}\n\treturn SAM_STAT_GOOD;\n}\n\nuint8_t set_lbp(struct scsi_cmd *cmd, uint8_t *buf, int len) {\n\tstruct priv_lu_ssc\t\t\t\t*lu_priv  = cmd->lu->lu_private;\n\tstruct ssc_personality_template *pm\t\t  = lu_priv->pm;\n\tuint8_t\t\t\t\t\t\t\t*sam_stat = &cmd->dbuf_p->sam_stat;\n\tstruct s_sd\t\t\t\t\t\t sd;\n\n\t/* OK, the drive supports Logical Block Protection - good to go */\n\tif (pm->drive_supports_LBP) {\n\t\treturn update_logical_block_protection(cmd->lu, buf);\n\t}\n\tsd.byte0\t\t = SKSV | CD;\n\tsd.field_pointer = 1;\n\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\treturn SAM_STAT_CHECK_CONDITION;\n}\n\nint add_smc_mode_page_drive_configuration(struct lu_phy_attr *lu) {\n\tstruct list_head *mode_pg;\n\tstruct mode\t\t *mp;\n\tuint8_t\t\t\t  pcode;\n\tuint8_t\t\t\t  subpcode;\n\tuint8_t\t\t\t  size;\n\n\tmode_pg = &lu->mode_pg;\n\t/* A Vendor-specific page for the StorageTek L20, L40 and L80 libraries */\n\tpcode\t = 0x2d;\n\tsubpcode = 0;\n\tsize\t = 0x26;\n\t/*\n\t * FIXME: Need to fill in details from Table 4-21 L20 SCSI Reference Manual\n\t */\n\n\tMHVTL_DBG(3, \"Adding mode page %s (%02x/%02x)\",\n\t\t\t  drive_configuration_page, pcode, subpcode);\n\n\tmp = alloc_mode_page(mode_pg, pcode, subpcode, size);\n\tif (!mp)\n\t\treturn -ENOMEM;\n\n\tmp->pcodePointer[0] = pcode;\n\tmp->pcodePointer[1] = size - sizeof(mp->pcodePointer[0]) - sizeof(mp->pcodePointer[1]);\n\n\t/* And copy pcode/size into bitmap structure */\n\tmp->pcodePointerBitMap[0] = mp->pcodePointer[0];\n\tmp->pcodePointerBitMap[1] = mp->pcodePointer[1];\n\n\tmp->description = drive_configuration_page;\n\n\treturn 0;\n}\n"
  },
  {
    "path": "usr/pm/ait_pm.c",
    "content": "/*\n * This handles any SCSI OP codes defined in the standards as 'STREAM'\n *\n * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n * See comments in vtltape.c for a more complete version release...\n *\n */\n\n#include <unistd.h>\n#include <stdlib.h>\n#include <errno.h>\n#include <string.h>\n#include <inttypes.h>\n#include \"be_byteshift.h\"\n#include \"mhvtl_scsi.h\"\n#include \"vtl_common.h\"\n#include \"vtllib.h\"\n#include \"logging.h\"\n#include \"ssc.h\"\n#include \"vtlcart.h\"\n#include \"mode.h\"\n#include \"mhvtl_log.h\"\n\nstatic struct density_info density_ait1 = {\n\t0x17d6, 0x50, 1, 100, medium_density_code_ait1,\n\t\"SONY\", \"AIT-1\", \"Adv Intellgent Tape\"};\n\nstatic struct density_info density_ait2 = {\n\t0x17d6, 0x50, 1, 200, medium_density_code_ait2,\n\t\"SONY\", \"AIT-2\", \"Adv Intellgent Tape\"};\n\nstatic struct density_info density_ait3 = {\n\t0x17d6, 0x50, 1, 300, medium_density_code_ait3,\n\t\"SONY\", \"AIT-3\", \"Adv Intellgent Tape\"};\n\nstatic struct density_info density_ait4 = {\n\t0x17d6, 0x50, 1, 400, medium_density_code_ait4,\n\t\"SONY\", \"AIT-4\", \"Adv Intellgent Tape\"};\n\nstatic struct name_to_media_info media_info[] = {\n\t{\"AIT1\", Media_AIT1,\n\t media_type_unknown, medium_density_code_ait1},\n\t{\"AIT1 Clean\", Media_AIT1_CLEAN,\n\t media_type_unknown, medium_density_code_ait1},\n\t{\"AIT2\", Media_AIT2,\n\t media_type_unknown, medium_density_code_ait2},\n\t{\"AIT2 Clean\", Media_AIT2_CLEAN,\n\t media_type_unknown, medium_density_code_ait2},\n\t{\"AIT3\", Media_AIT3,\n\t media_type_unknown, medium_density_code_ait3},\n\t{\"AIT3 Clean\", Media_AIT3_CLEAN,\n\t media_type_unknown, medium_density_code_ait3},\n\t{\"AIT4\", Media_AIT4,\n\t media_type_unknown, medium_density_code_ait4},\n\t{\"AIT4 Clean\", Media_AIT4_CLEAN,\n\t media_type_unknown, medium_density_code_ait4},\n\t{\"AIT4 WORM\", Media_AIT4_WORM,\n\t media_type_unknown, medium_density_code_ait4},\n\t{\"\", 0, 0, 0},\n};\n\nstatic uint8_t clear_ait_WORM(struct list_head *l) {\n\tuint8_t\t\t*smp_dp;\n\tstruct mode *smp;\n\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", l);\n\n\tsmp = lookup_mode_pg(l, MODE_AIT_DEVICE_CONFIGURATION, 0);\n\tif (smp) {\n\t\tsmp_dp\t  = smp->pcodePointer;\n\t\tsmp_dp[4] = 0x0;\n\t}\n\n\treturn SAM_STAT_GOOD;\n}\n\nstatic uint8_t set_ait_WORM(struct list_head *l) {\n\tuint8_t\t\t*smp_dp;\n\tstruct mode *smp;\n\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", l);\n\n\tsmp = lookup_mode_pg(l, MODE_AIT_DEVICE_CONFIGURATION, 0);\n\tif (smp) {\n\t\tsmp_dp\t  = smp->pcodePointer;\n\t\tsmp_dp[4] = 0x40;\n\t}\n\n\treturn SAM_STAT_GOOD;\n}\n\nstatic uint8_t clear_ait_compression(struct list_head *l) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", l);\n\t/* default clear_compression is in libvtlscsi */\n\treturn clear_compression_mode_pg(l);\n}\n\nstatic uint8_t set_ait_compression(struct list_head *l, int lvl) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", l);\n\t/* default set_compression is in libvtlscsi */\n\treturn set_compression_mode_pg(l, lvl);\n}\n\nstatic uint8_t update_ait_encryption_mode(struct list_head *m, void *p, int value) {\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\n\treturn SAM_STAT_GOOD;\n}\n\n/* FIXME: This is a copy of LTO4/5 encryption capabilities.\n\tNeed to adjust to suit AIT4\n*/\nstatic int encr_capabilities_ait(struct scsi_cmd *cmd) {\n\tuint8_t\t\t\t   *buf\t\t= cmd->dbuf_p->data;\n\tstruct priv_lu_ssc *lu_priv = cmd->lu->lu_private;\n\n\tput_unaligned_be16(ENCR_CAPABILITIES, &buf[0]);\n\tput_unaligned_be16(40, &buf[2]); /* List length */\n\n\tbuf[20] = 1;\t\t\t\t\t\t/* Algorithm index */\n\tbuf[21] = 0;\t\t\t\t\t\t/* Reserved */\n\tput_unaligned_be16(0x14, &buf[22]); /* Descriptor length */\n\tbuf[24] = 0x3a;\t\t\t\t\t\t/* MAC C/DED_C DECRYPT_C = 2 ENCRYPT_C = 2 */\n\tbuf[25] = 0x10;\t\t\t\t\t\t/* NONCE_C = 1 */\n\t/* Max unauthenticated key data */\n\tput_unaligned_be16(0x20, &buf[26]);\n\t/* Max authenticated  key data */\n\tput_unaligned_be16(0x0c, &buf[28]);\n\t/* Key size */\n\tput_unaligned_be16(0x20, &buf[30]);\n\tbuf[32] = 0x01; /* EAREM */\n\t/* buf 12 - 19 reserved */\n\n\tbuf[40] = 0;\t/* Encryption Algorithm Id */\n\tbuf[41] = 0x01; /* Encryption Algorithm Id */\n\tbuf[42] = 0;\t/* Encryption Algorithm Id */\n\tbuf[43] = 0x14; /* Encryption Algorithm Id */\n\n\t/* adjustments for each emulated drive type */\n\tbuf[4] = 0x1; /* CFG_P == 01b */\n\tif (lu_priv->load_status == TAPE_LOADED) {\n\t\tswitch (mam.MediaType) {\n\t\tcase Media_AIT4:\n\t\t\tMHVTL_DBG(1, \"AIT4 Medium\");\n\t\t\tbuf[24] |= 0x80; /* AVFMV */\n\t\t\tbreak;\n\t\t}\n\t}\n\tbuf[32] |= 0x08; /* RDMC_C == 4 */\n\treturn 44;\n}\n\nstatic void init_ait_inquiry(struct lu_phy_attr *lu) {\n\tint\t\tpg;\n\tuint8_t worm;\n\tuint8_t local_TapeAlert[8] = {\n\t\t0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\n\n\tworm = ((struct priv_lu_ssc *)lu->lu_private)->pm->drive_supports_WORM;\n\tlu->inquiry[2] =\n\t\t((struct priv_lu_ssc *)lu->lu_private)->pm->drive_ANSI_VERSION;\n\n\t/* Sequential Access device capabilities - Ref: 8.4.2 */\n\tpg\t\t\t   = PCODE_OFFSET(0xb0);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_B0_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_b0(lu, &worm);\n\n\t/* Manufacture-assigned serial number - Ref: 8.4.3 */\n\tpg\t\t\t   = PCODE_OFFSET(0xb1);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_B1_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_b1(lu, lu->lu_serial_no);\n\n\t/* TapeAlert supported flags - Ref: 8.4.4 */\n\tpg\t\t\t   = PCODE_OFFSET(0xb2);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_B2_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_b2(lu, &local_TapeAlert);\n\n\t/* VPD page 0xC0 */\n\tpg\t\t\t   = PCODE_OFFSET(0xc0);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_C0_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_c0(lu, \"10-03-2008 19:38:00\");\n\n\t/* VPD page 0xC1 */\n\tpg\t\t\t   = PCODE_OFFSET(0xc1);\n\tlu->lu_vpd[pg] = alloc_vpd(strlen(\"Security\"));\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_c1(lu, \"Security\");\n}\n\n/* Dummy routine. Always return false */\nstatic int ait_kad_validation(int mode, int ukad, int akad) {\n\treturn FALSE;\n}\n\n/* Some comments before I forget how this is supose to work..\n - cleaning_media_state is either\n   0 - Not mounted\n   1 - Cleaning media mounted -> return Cleaning cartridge installed\n   2 - Cleaning media mounted -> return Cause not reportable\n   3 - Cleaning media mounted -> return Initializing command required\n\n On cleaning media mount, ait_cleaning() is called which:\n   Sets a pointer from priv_lu_ssc -> cleaning_media_state.\n   Sets cleaning_media_state to 1.\n   Sets a 30 second timer to call inc_cleaning_state()\n\n inc_cleaning_state()\n   Increments cleaning_media_state.\n   If cleaning media_state == 2, set another timer for 90 seconds to again\n   call inc_cleaning_state.\n\n If the application issues a TUR, ssc_tur() will return one of the\n above status codes depending on the current value of cleaning_media_state.\n\n When the cleaning media is unmounted, the pointer in priv_lu_ssc to this\n var will be re-set to NULL so the ssc_tur() will return defautl value.\n\n */\nstatic volatile sig_atomic_t cleaning_media_state;\n\nstatic void inc_cleaning_state(int sig);\n\nstatic void set_cleaning_timer(int t) {\n\tMHVTL_DBG(3, \"+++ Trace +++ Setting alarm for %d\", t);\n\tsignal(SIGALRM, inc_cleaning_state);\n\talarm(t);\n}\n\nstatic void inc_cleaning_state(int sig) {\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\tsignal(sig, inc_cleaning_state);\n\n\tcleaning_media_state++;\n\n\tif (cleaning_media_state == CLEAN_MOUNT_STAGE2)\n\t\tset_cleaning_timer(90);\n}\n\nstatic uint8_t ait_cleaning(void *ssc_priv) {\n\tstruct priv_lu_ssc *ssc;\n\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\n\tssc = ssc_priv;\n\n\tssc->cleaning_media_state = &cleaning_media_state;\n\tcleaning_media_state\t  = CLEAN_MOUNT_STAGE1;\n\n\tset_cleaning_timer(30);\n\n\treturn 0;\n}\n\n/* Table 6-29 Supported Mode pages\n * Sony SDX-900V v2.1 SCSI Reference Guide\n */\nstatic void init_ait_mode_pages(struct lu_phy_attr *lu) {\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_control(lu);\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_medium_partition(lu);\n\tadd_mode_information_exception(lu);\n\tadd_mode_ait_device_configuration(lu);\n}\n\n/* load set to 1 for load, 0 for unload */\nstatic uint8_t ait_media_load(struct lu_phy_attr *lu, int load) {\n\tuint8_t\t\t*smp_dp;\n\tstruct mode *smp;\n\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\n\tsmp = lookup_mode_pg(&lu->mode_pg, MODE_AIT_DEVICE_CONFIGURATION, 0);\n\tif (smp) {\n\t\tsmp_dp = smp->pcodePointer;\n\t\tif (load)\n\t\t\tsmp_dp[3] = 0x0a; /* SPAN -> Set to 0Ah on load */\n\t\telse\n\t\t\tsmp_dp[3] = 0x0; /* SPAN -> Set to 0 on unload */\n\t}\n\n\treturn 0;\n}\n\nstatic char *name_ait_1 = \"AIT\";\nstatic char *name_ait_2 = \"AIT-2\";\nstatic char *name_ait_3 = \"AIT-3\";\nstatic char *name_ait_4 = \"AIT-4\";\n\nstatic struct ssc_personality_template ssc_pm = {\n\t.valid_encryption_blk\t = valid_encryption_blk,\n\t.update_encryption_mode\t = update_ait_encryption_mode,\n\t.encryption_capabilities = encr_capabilities_ait,\n\t.kad_validation\t\t\t = ait_kad_validation,\n\t.check_restrictions\t\t = check_restrictions,\n\t.clear_compression\t\t = clear_ait_compression,\n\t.set_compression\t\t = set_ait_compression,\n\t.media_load\t\t\t\t = ait_media_load,\n\t.cleaning_media\t\t\t = ait_cleaning,\n\t.media_handling\t\t\t = media_info,\n};\n\nvoid init_ait1_ssc(struct lu_phy_attr *lu) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", &lu->mode_pg);\n\n\tssc_pm.name\t\t\t\t\t\t\t\t = name_ait_1;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.native_drive_density\t\t\t\t = &density_ait1;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = FALSE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = FALSE;\n\tssc_pm.drive_supports_SP\t\t\t\t = FALSE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 2;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_ait_inquiry(lu);\n\n\tinit_ait_mode_pages(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\tadd_density_support(&lu->den_list, &density_ait1, 1);\n\tadd_drive_media_list(lu, LOAD_RW, \"AIT1\");\n\tadd_drive_media_list(lu, LOAD_RO, \"AIT1 Clean\");\n}\n\nvoid init_ait2_ssc(struct lu_phy_attr *lu) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", &lu->mode_pg);\n\n\tssc_pm.name\t\t\t\t\t\t\t\t = name_ait_2;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.native_drive_density\t\t\t\t = &density_ait2;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = FALSE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = FALSE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_ait_inquiry(lu);\n\n\tinit_ait_mode_pages(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\tadd_density_support(&lu->den_list, &density_ait1, 1);\n\tadd_density_support(&lu->den_list, &density_ait2, 1);\n\n\tadd_drive_media_list(lu, LOAD_RW, \"AIT1\");\n\tadd_drive_media_list(lu, LOAD_RO, \"AIT1 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"AIT2\");\n\tadd_drive_media_list(lu, LOAD_RO, \"AIT2 Clean\");\n}\n\nvoid init_ait3_ssc(struct lu_phy_attr *lu) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", &lu->mode_pg);\n\n\tssc_pm.name\t\t\t\t\t\t\t\t = name_ait_3;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.native_drive_density\t\t\t\t = &density_ait3;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = FALSE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = FALSE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_ait_inquiry(lu);\n\n\tinit_ait_mode_pages(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\tadd_density_support(&lu->den_list, &density_ait1, 0);\n\tadd_density_support(&lu->den_list, &density_ait2, 1);\n\tadd_density_support(&lu->den_list, &density_ait3, 1);\n\n\tadd_drive_media_list(lu, LOAD_RO, \"AIT1\");\n\tadd_drive_media_list(lu, LOAD_RO, \"AIT1 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"AIT2\");\n\tadd_drive_media_list(lu, LOAD_RO, \"AIT2 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"AIT3\");\n\tadd_drive_media_list(lu, LOAD_RO, \"AIT3 Clean\");\n}\n\nvoid init_ait4_ssc(struct lu_phy_attr *lu) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", &lu->mode_pg);\n\n\tssc_pm.name\t\t\t\t\t\t\t\t = name_ait_4;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.clear_WORM\t\t\t\t\t\t = clear_ait_WORM;\n\tssc_pm.set_WORM\t\t\t\t\t\t\t = set_ait_WORM;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = FALSE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_ait_inquiry(lu);\n\n\tinit_ait_mode_pages(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\tssc_pm.native_drive_density = &density_ait4;\n\n\t((struct priv_lu_ssc *)lu->lu_private)->capacity_unit = 1L << 10; /* Capacity units in KBytes */\n\n\tadd_density_support(&lu->den_list, &density_ait2, 0);\n\tadd_density_support(&lu->den_list, &density_ait3, 1);\n\tadd_density_support(&lu->den_list, &density_ait4, 1);\n\n\tadd_drive_media_list(lu, LOAD_RO, \"AIT2\");\n\tadd_drive_media_list(lu, LOAD_RO, \"AIT2 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"AIT3\");\n\tadd_drive_media_list(lu, LOAD_RO, \"AIT3 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"AIT4\");\n\tadd_drive_media_list(lu, LOAD_RO, \"AIT4 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"AIT4 WORM\");\n}\n"
  },
  {
    "path": "usr/pm/default_smc_pm.c",
    "content": "/*\n * Personality module for default emulation\n */\n\n#include <stdio.h>\n#include <string.h>\n#include \"vtllib.h\"\n#include \"smc.h\"\n#include \"be_byteshift.h\"\n\nstatic struct smc_personality_template smc_pm = {\n\t.library_has_map\t\t\t= TRUE,\n\t.library_has_barcode_reader = TRUE,\n\t.library_has_playground\t\t= TRUE,\n\n\t.dvcid_len = 32,\n};\n\nstatic void update_default_inquiry(struct lu_phy_attr *lu) {\n\tstruct smc_priv *smc_p;\n\n\tsmc_p = lu->lu_private;\n\n\tlu->inquiry[2] = 5;\t   /* SNSI Approved Version */\n\tlu->inquiry[3] = 2;\t   /* Response data format */\n\tlu->inquiry[4] = 0x43; /* Additional length */\n\n\tmemcpy(&lu->inquiry[38], &lu->lu_serial_no, 12);\n\tlu->inquiry[55] |= smc_p->pm->library_has_barcode_reader ? 1 : 0;\n\tput_unaligned_be16(0x005c, &lu->inquiry[58]); /* SAM-2 */\n\tput_unaligned_be16(0x0b56, &lu->inquiry[60]); /* SPI-4 */\n\tput_unaligned_be16(0x02fe, &lu->inquiry[62]); /* SMC-2 */\n\tput_unaligned_be16(0x030f, &lu->inquiry[64]); /* SPC-3 */\n\n\t/* Device Identification */\n\tlu->lu_vpd[PCODE_OFFSET(0x83)] = alloc_vpd(VPD_83_SZ);\n\tif (lu->lu_vpd[PCODE_OFFSET(0x83)])\n\t\tupdate_vpd_83(lu, NULL);\n}\n\nvoid init_default_smc(struct lu_phy_attr *lu) {\n\tsmc_pm.name\t\t\t\t\t\t  = \"mhVTL - Default emulation\";\n\tsmc_pm.library_has_map\t\t\t  = TRUE;\n\tsmc_pm.library_has_barcode_reader = TRUE;\n\tsmc_pm.library_has_playground\t  = TRUE;\n\tsmc_pm.dvcid_serial_only\t\t  = FALSE;\n\n\tsmc_pm.start_drive\t = 0x001;\n\tsmc_pm.start_picker\t = 0x2f0;\n\tsmc_pm.start_map\t = 0x300;\n\tsmc_pm.start_storage = 0x400;\n\n\tsmc_pm.lu = lu;\n\tsmc_personality_module_register(&smc_pm);\n\n\tinit_slot_info(lu);\n\tupdate_default_inquiry(lu);\n\n\tinit_smc_log_pages(lu);\n\tinit_smc_mode_pages(lu);\n}\n"
  },
  {
    "path": "usr/pm/default_ssc_pm.c",
    "content": "/*\n * This handles any SCSI OP codes defined in the standards as 'STREAM'\n *\n * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n * See comments in vtltape.c for a more complete version release...\n *\n */\n\n#include <unistd.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <errno.h>\n#include <string.h>\n#include <inttypes.h>\n#include \"mhvtl_scsi.h\"\n#include \"vtl_common.h\"\n#include \"vtllib.h\"\n#include \"logging.h\"\n#include \"ssc.h\"\n#include \"spc.h\"\n#include \"mode.h\"\n#include \"mhvtl_log.h\"\n\nstatic struct density_info density_default = {\n\t1024, 127, 1, 500, medium_density_code_unknown,\n\t\"mhVTL\", \"DEFAULT\", \"linuxVTL\"};\n\nstatic struct name_to_media_info media_info[] = {\n\t{\"Undefined\", Media_undefined,\n\t media_type_unknown, medium_density_code_unknown},\n\n\t/* Ultrium media */\n\t{\"LTO1\", Media_LTO1,\n\t media_type_lto1_data, medium_density_code_lto1},\n\t{\"LTO1 Clean\", Media_LTO1_CLEAN,\n\t media_type_lto1_data, medium_density_code_lto1},\n\t{\"LTO2\", Media_LTO2,\n\t media_type_lto2_data, medium_density_code_lto2},\n\t{\"LTO2 Clean\", Media_LTO2_CLEAN,\n\t media_type_lto2_data, medium_density_code_lto2},\n\t{\"LTO3\", Media_LTO3,\n\t media_type_lto3_data, medium_density_code_lto3},\n\t{\"LTO3 Clean\", Media_LTO3_CLEAN,\n\t media_type_lto3_data, medium_density_code_lto3},\n\t{\"LTO3 WORM\", Media_LTO3_WORM,\n\t media_type_lto3_worm, medium_density_code_lto3},\n\t{\"LTO4\", Media_LTO4,\n\t media_type_lto4_data, medium_density_code_lto4},\n\t{\"LTO4 Clean\", Media_LTO4_CLEAN,\n\t media_type_lto4_data, medium_density_code_lto4},\n\t{\"LTO4 WORM\", Media_LTO4_WORM,\n\t media_type_lto4_worm, medium_density_code_lto4},\n\t{\"LTO5\", Media_LTO5,\n\t media_type_lto5_data, medium_density_code_lto5},\n\t{\"LTO5 Clean\", Media_LTO5_CLEAN,\n\t media_type_lto5_data, medium_density_code_lto5},\n\t{\"LTO5 WORM\", Media_LTO5_WORM,\n\t media_type_lto5_worm, medium_density_code_lto5},\n\t{\"LTO6\", Media_LTO6,\n\t media_type_lto6_data, medium_density_code_lto6},\n\t{\"LTO6 Clean\", Media_LTO6_CLEAN,\n\t media_type_lto6_data, medium_density_code_lto6},\n\t{\"LTO6 WORM\", Media_LTO6_WORM,\n\t media_type_lto6_worm, medium_density_code_lto6},\n\t{\"LTO7\", Media_LTO7,\n\t media_type_lto7_data, medium_density_code_lto7},\n\t{\"LTO7 Clean\", Media_LTO7_CLEAN,\n\t media_type_lto7_data, medium_density_code_lto7},\n\t{\"LTO7 WORM\", Media_LTO7_WORM,\n\t media_type_lto7_worm, medium_density_code_lto7},\n\t{\"LTO8\", Media_LTO8,\n\t media_type_lto8_data, medium_density_code_lto8},\n\t{\"LTO8 Clean\", Media_LTO8_CLEAN,\n\t media_type_lto8_data, medium_density_code_lto8},\n\t{\"LTO8 WORM\", Media_LTO8_WORM,\n\t media_type_lto8_worm, medium_density_code_lto8},\n\t{\"LTO9\", Media_LTO9,\n\t media_type_lto9_data, medium_density_code_lto9},\n\t{\"LTO9 Clean\", Media_LTO9_CLEAN,\n\t media_type_lto9_data, medium_density_code_lto9},\n\t{\"LTO9 WORM\", Media_LTO9_WORM,\n\t media_type_lto9_worm, medium_density_code_lto9},\n\n\t/* IBM 03592 media */\n\t{\"03592 JA\", Media_3592_JA,\n\t media_type_unknown, medium_density_code_j1a},\n\t{\"03592 JA Clean\", Media_3592_JA_CLEAN,\n\t media_type_unknown, medium_density_code_j1a},\n\t{\"03592 JA WORM\", Media_3592_JW,\n\t media_type_unknown, medium_density_code_j1a},\n\n\t{\"03592 JB\", Media_3592_JB,\n\t media_type_unknown, medium_density_code_e05},\n\t{\"03592 JB Clean\", Media_3592_JB_CLEAN,\n\t media_type_unknown, medium_density_code_e05},\n\t{\"03592 JB ENCR\", Media_3592_JB,\n\t media_type_unknown, medium_density_code_e05_ENCR},\n\n\t{\"03592 JC\", Media_3592_JX,\n\t media_type_unknown, medium_density_code_e06},\n\t{\"03592 JC Clean\", Media_3592_JX_CLEAN,\n\t media_type_unknown, medium_density_code_e06},\n\t{\"03592 JC ENCR\", Media_3592_JX,\n\t media_type_unknown, medium_density_code_e06_ENCR},\n\n\t/* AIT media */\n\t{\"AIT1\", Media_AIT1,\n\t media_type_unknown, medium_density_code_ait1},\n\t{\"AIT1 Clean\", Media_AIT1_CLEAN,\n\t media_type_unknown, medium_density_code_ait1},\n\t{\"AIT2\", Media_AIT2,\n\t media_type_unknown, medium_density_code_ait2},\n\t{\"AIT2 Clean\", Media_AIT2_CLEAN,\n\t media_type_unknown, medium_density_code_ait2},\n\t{\"AIT3\", Media_AIT3,\n\t media_type_unknown, medium_density_code_ait3},\n\t{\"AIT3 Clean\", Media_AIT3_CLEAN,\n\t media_type_unknown, medium_density_code_ait3},\n\t{\"AIT4\", Media_AIT4,\n\t media_type_unknown, medium_density_code_ait4},\n\t{\"AIT4 Clean\", Media_AIT4_CLEAN,\n\t media_type_unknown, medium_density_code_ait4},\n\t{\"AIT4 WORM\", Media_AIT4_WORM,\n\t media_type_unknown, medium_density_code_ait4},\n\n\t/* STK 9x40 media */\n\t{\"9840A\", Media_9840A,\n\t media_type_unknown, medium_density_code_9840A},\n\t{\"9840A Clean\", Media_9840A_CLEAN,\n\t media_type_unknown, medium_density_code_9840A},\n\t{\"9840B\", Media_9840B,\n\t media_type_unknown, medium_density_code_9840B},\n\t{\"9840B Clean\", Media_9840B_CLEAN,\n\t media_type_unknown, medium_density_code_9840B},\n\t{\"9840C\", Media_9840C,\n\t media_type_unknown, medium_density_code_9840C},\n\t{\"9840C Clean\", Media_9840C_CLEAN,\n\t media_type_unknown, medium_density_code_9840C},\n\t{\"9840D\", Media_9840D,\n\t media_type_unknown, medium_density_code_9840D},\n\t{\"9840D Clean\", Media_9840D_CLEAN,\n\t media_type_unknown, medium_density_code_9840D},\n\n\t{\"9940A\", Media_9940A,\n\t media_type_unknown, medium_density_code_9940A},\n\t{\"9940A Clean\", Media_9940A_CLEAN,\n\t media_type_unknown, medium_density_code_9940A},\n\t{\"9940B\", Media_9940B,\n\t media_type_unknown, medium_density_code_9940B},\n\t{\"9940B Clean\", Media_9940B_CLEAN,\n\t media_type_unknown, medium_density_code_9940B},\n\n\t/* STK T10000 media */\n\t{\"T10KA\", Media_T10KA,\n\t media_type_unknown, medium_density_code_10kA},\n\t{\"T10KA WORM\", Media_T10KA_WORM,\n\t media_type_unknown, medium_density_code_10kA},\n\t{\"T10KA Clean\", Media_T10KA_CLEAN,\n\t media_type_unknown, medium_density_code_10kA},\n\t{\"T10KB\", Media_T10KB,\n\t media_type_unknown, medium_density_code_10kB},\n\t{\"T10KB WORM\", Media_T10KB_WORM,\n\t media_type_unknown, medium_density_code_10kB},\n\t{\"T10KB Clean\", Media_T10KB_CLEAN,\n\t media_type_unknown, medium_density_code_10kB},\n\t{\"T10KC\", Media_T10KC,\n\t media_type_unknown, medium_density_code_10kC},\n\t{\"T10KC WORM\", Media_T10KC_WORM,\n\t media_type_unknown, medium_density_code_10kC},\n\t{\"T10KC Clean\", Media_T10KC_CLEAN,\n\t media_type_unknown, medium_density_code_10kC},\n\n\t/* Quantum DLT / SDLT media */\n\t{\"DLT2\", Media_DLT2,\n\t media_type_unknown, medium_density_code_dlt2},\n\t{\"DLT3\", Media_DLT3,\n\t media_type_unknown, medium_density_code_dlt3},\n\t{\"DLT4\", Media_DLT4,\n\t media_type_unknown, medium_density_code_dlt4},\n\t{\"SDLT\", Media_SDLT,\n\t media_type_unknown, medium_density_code_sdlt},\n\t{\"SDLT 220\", Media_SDLT220,\n\t media_type_unknown, medium_density_code_220},\n\t{\"SDLT 320\", Media_SDLT320,\n\t media_type_unknown, medium_density_code_320},\n\t{\"SDLT 320 Clean\", Media_SDLT320_CLEAN,\n\t media_type_unknown, medium_density_code_320},\n\t{\"SDLT 600\", Media_SDLT600,\n\t media_type_unknown, medium_density_code_600},\n\t{\"SDLT 600 Clean\", Media_SDLT600_CLEAN,\n\t media_type_unknown, medium_density_code_600},\n\t{\"SDLT 600 WORM\", Media_SDLT600_WORM,\n\t media_type_unknown, medium_density_code_600},\n\n\t/* 4MM DAT media */\n\t{\"DDS1\", Media_DDS1,\n\t media_type_unknown, medium_density_code_DDS1},\n\t{\"DDS2\", Media_DDS2,\n\t media_type_unknown, medium_density_code_DDS2},\n\t{\"DDS3\", Media_DDS3,\n\t media_type_unknown, medium_density_code_DDS3},\n\t{\"DDS4\", Media_DDS4,\n\t media_type_unknown, medium_density_code_DDS4},\n\t{\"DDS5\", Media_DDS5,\n\t media_type_unknown, medium_density_code_DDS5},\n\t{\"\", 0, 0, 0},\n};\n\nstatic uint8_t clear_default_comp(struct list_head *l) {\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\t/* default clear_compression is in libvtlscsi */\n\treturn clear_compression_mode_pg(l);\n}\n\nstatic uint8_t set_default_comp(struct list_head *l, int lvl) {\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\t/* default set_compression is in libvtlscsi */\n\treturn set_compression_mode_pg(l, lvl);\n}\n\nstatic uint8_t update_default_encryption_mode(struct list_head *m, void *p, int value) {\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\n\treturn SAM_STAT_GOOD;\n}\n\nstatic uint8_t set_default_WORM(struct list_head *l) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", l);\n\treturn set_WORM(l);\n}\n\nstatic uint8_t clear_default_WORM(struct list_head *l) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", l);\n\treturn clear_WORM(l);\n}\n\nstatic void init_default_inquiry(struct lu_phy_attr *lu) {\n\tint\t\tpg;\n\tuint8_t worm;\n\tuint8_t local_TapeAlert[8] =\n\t\t{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\n\n\tworm = ((struct priv_lu_ssc *)lu->lu_private)->pm->drive_supports_WORM;\n\tlu->inquiry[2] =\n\t\t((struct priv_lu_ssc *)lu->lu_private)->pm->drive_ANSI_VERSION;\n\n\t/* Sequential Access device capabilities - Ref: 8.4.2 */\n\tpg\t\t\t   = PCODE_OFFSET(0xb0);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_B0_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_b0(lu, &worm);\n\n\t/* Manufacture-assigned serial number - Ref: 8.4.3 */\n\tpg\t\t\t   = PCODE_OFFSET(0xb1);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_B1_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_b1(lu, lu->lu_serial_no);\n\n\t/* TapeAlert supported flags - Ref: 8.4.4 */\n\tpg\t\t\t   = PCODE_OFFSET(0xb2);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_B2_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_b2(lu, &local_TapeAlert);\n\n\t/* VPD page 0xC0 */\n\tpg\t\t\t   = PCODE_OFFSET(0xc0);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_C0_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_c0(lu, \"10-03-2008 19:38:00\");\n\n\t/* VPD page 0xC1 */\n\tpg\t\t\t   = PCODE_OFFSET(0xc1);\n\tlu->lu_vpd[pg] = alloc_vpd(strlen(\"Security\"));\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_c1(lu, \"Security\");\n}\n\n/* Dummy routine. Always return false */\nstatic int default_kad_validation(int mode, int ukad, int akad) {\n\treturn FALSE;\n}\n\n/* Some comments before I forget how this is supose to work..\n - cleaning_media_state is either\n   0 - Not mounted\n   1 - Cleaning media mounted -> return Cleaning cartridge installed\n   2 - Cleaning media mounted -> return Cause not reportable\n   3 - Cleaning media mounted -> return Initializing command required\n\n On cleaning media mount, default_cleaning() is called which:\n   Sets a pointer from priv_lu_ssc -> cleaning_media_state.\n   Sets cleaning_media_state to 1.\n   Sets a 30 second timer to call inc_cleaning_state()\n\n inc_cleaning_state()\n   Increments cleaning_media_state.\n   If cleaning media_state == 2, set another timer for 90 seconds to again\n   call inc_cleaning_state.\n\n If the application issues a TUR, ssc_tur() will return one of the\n above status codes depending on the current value of cleaning_media_state.\n\n When the cleaning media is unmounted, the pointer in priv_lu_ssc to this\n var will be re-set to NULL so the ssc_tur() will return defautl value.\n\n */\nstatic volatile sig_atomic_t cleaning_media_state;\n\nstatic void inc_cleaning_state(int sig);\n\nstatic void set_cleaning_timer(int t) {\n\tMHVTL_DBG(3, \"+++ Trace +++ Setting alarm for %d\", t);\n\tsignal(SIGALRM, inc_cleaning_state);\n\talarm(t);\n}\n\nstatic void inc_cleaning_state(int sig) {\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\tsignal(sig, inc_cleaning_state);\n\n\tcleaning_media_state++;\n\n\tif (cleaning_media_state == CLEAN_MOUNT_STAGE2)\n\t\tset_cleaning_timer(90);\n}\n\nstatic uint8_t default_media_load(struct lu_phy_attr *lu, int load) {\n\tMHVTL_DBG(3, \"+++ Trace +++ %s\", (load) ? \"load\" : \"unload\");\n\treturn 0;\n}\n\nstatic uint8_t default_cleaning(void *ssc_priv) {\n\tstruct priv_lu_ssc *ssc;\n\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\n\tssc = ssc_priv;\n\n\tssc->cleaning_media_state = &cleaning_media_state;\n\tcleaning_media_state\t  = CLEAN_MOUNT_STAGE1;\n\n\tset_cleaning_timer(30);\n\n\treturn 0;\n}\n\nstatic void init_default_mode_pages(struct lu_phy_attr *lu) {\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_control(lu);\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_medium_partition(lu);\n\tadd_mode_power_condition(lu);\n\tadd_mode_information_exception(lu);\n\tadd_mode_medium_configuration(lu);\n}\n\nstatic char *pm_name = \"default emulation\";\n\nstatic struct ssc_personality_template ssc_pm = {\n\t.valid_encryption_blk\t= valid_encryption_blk,\n\t.update_encryption_mode = update_default_encryption_mode,\n\t.kad_validation\t\t\t= default_kad_validation,\n\t.check_restrictions\t\t= check_restrictions,\n\t.clear_compression\t\t= clear_default_comp,\n\t.set_compression\t\t= set_default_comp,\n\t.clear_WORM\t\t\t\t= clear_default_WORM,\n\t.set_WORM\t\t\t\t= set_default_WORM,\n\t.media_load\t\t\t\t= default_media_load,\n\t.cleaning_media\t\t\t= default_cleaning,\n\t.media_handling\t\t\t= media_info,\n};\n\nvoid init_default_ssc(struct lu_phy_attr *lu) {\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.native_drive_density\t\t\t\t = &density_default;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = FALSE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = FALSE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = FALSE;\n\tssc_pm.drive_supports_SP\t\t\t\t = FALSE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 2;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_default_inquiry(lu);\n\n\tinit_default_mode_pages(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\tadd_density_support(&lu->den_list, &density_default, 1);\n\n\t/* LTO media */\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO1\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO2\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO3\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO4\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO5\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO6\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO7\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO8\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO9\");\n\n\t/* DDS media */\n\tadd_drive_media_list(lu, LOAD_RW, \"DDS1\");\n\tadd_drive_media_list(lu, LOAD_RW, \"DDS2\");\n\tadd_drive_media_list(lu, LOAD_RW, \"DDS3\");\n\tadd_drive_media_list(lu, LOAD_RW, \"DDS4\");\n\tadd_drive_media_list(lu, LOAD_RW, \"DDS5\");\n\n\t/* DLT media */\n\tadd_drive_media_list(lu, LOAD_RW, \"DLT2\");\n\tadd_drive_media_list(lu, LOAD_RW, \"DLT3\");\n\tadd_drive_media_list(lu, LOAD_RW, \"DLT4\");\n\tadd_drive_media_list(lu, LOAD_RW, \"SDLT\");\n\tadd_drive_media_list(lu, LOAD_RW, \"SDLT 220\");\n\tadd_drive_media_list(lu, LOAD_RW, \"SDLT 320\");\n\tadd_drive_media_list(lu, LOAD_RW, \"SDLT 600\");\n\n\t/* STK T10000 */\n\tadd_drive_media_list(lu, LOAD_RW, \"T10KA\");\n\tadd_drive_media_list(lu, LOAD_RW, \"T10KB\");\n\tadd_drive_media_list(lu, LOAD_RW, \"T10KC\");\n\tadd_drive_media_list(lu, LOAD_RW, \"T10KD\");\n\n\t/* STK 9x40 */\n\tadd_drive_media_list(lu, LOAD_RW, \"9840A\");\n\tadd_drive_media_list(lu, LOAD_RW, \"9840B\");\n\tadd_drive_media_list(lu, LOAD_RW, \"9840C\");\n\tadd_drive_media_list(lu, LOAD_RW, \"9840D\");\n\tadd_drive_media_list(lu, LOAD_RW, \"9940A\");\n\tadd_drive_media_list(lu, LOAD_RW, \"9940B\");\n\n\t/* AIT media */\n\tadd_drive_media_list(lu, LOAD_RW, \"AIT1\");\n\tadd_drive_media_list(lu, LOAD_RW, \"AIT2\");\n\tadd_drive_media_list(lu, LOAD_RW, \"AIT3\");\n\tadd_drive_media_list(lu, LOAD_RW, \"AIT4\");\n\n\t/* IBM 03592 series */\n\tadd_drive_media_list(lu, LOAD_RW, \"03592 JA\");\n\tadd_drive_media_list(lu, LOAD_RW, \"03592 JB\");\n\tadd_drive_media_list(lu, LOAD_RW, \"03592 JC\");\n\n\t/* Don't support PERSISTENT RESERVATION */\n\tregister_ops(lu, PERSISTENT_RESERVE_IN, spc_illegal_op, NULL, NULL);\n\tregister_ops(lu, PERSISTENT_RESERVE_OUT, spc_illegal_op, NULL, NULL);\n}\n"
  },
  {
    "path": "usr/pm/hp_smc_pm.c",
    "content": "/*\n * Personality module for HP E-Series\n */\n\n#include <stdio.h>\n#include <string.h>\n#include \"vtllib.h\"\n#include \"smc.h\"\n#include \"logging.h\"\n\nstatic void update_eml_vpd_80(struct lu_phy_attr *lu) {\n\tstruct vpd **lu_vpd = lu->lu_vpd;\n\tuint8_t\t\t*d;\n\tint\t\t\t pg;\n\n\t/* Unit Serial Number */\n\tpg = PCODE_OFFSET(0x80);\n\tif (lu_vpd[pg]) /* Free any earlier allocation */\n\t\tdealloc_vpd(lu_vpd[pg]);\n\tlu_vpd[pg] = alloc_vpd(0x12);\n\tif (lu_vpd[pg]) {\n\t\td = lu_vpd[pg]->data;\n\t\tsnprintf((char *)&d[0], 11, \"%-10.10s\", lu->lu_serial_no);\n\t\t/* Unique Logical Library Identifier */\n\t} else {\n\t\tMHVTL_ERR(\"Could not malloc(0x12) bytes, line %d\", __LINE__);\n\t}\n}\n\nstatic void update_eml_vpd_83(struct lu_phy_attr *lu) {\n\tstruct vpd **lu_vpd = lu->lu_vpd;\n\tuint8_t\t\t*d;\n\tint\t\t\t num;\n\tchar\t\t*ptr;\n\tint\t\t\t pg;\n\tint\t\t\t len, j;\n\n\tnum = VENDOR_ID_LEN + PRODUCT_ID_LEN + 10;\n\n\tpg = PCODE_OFFSET(0x83);\n\tif (lu_vpd[pg]) /* Free any earlier allocation */\n\t\tdealloc_vpd(lu_vpd[pg]);\n\tlu_vpd[pg] = alloc_vpd(num + 12);\n\tif (!lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Can't malloc() to setup for vpd_83\");\n\t\treturn;\n\t}\n\n\td = lu_vpd[pg]->data;\n\n\td[0] = 2;\n\td[1] = 1;\n\td[2] = 0;\n\td[3] = num;\n\n\tmemcpy(&d[4], &lu->vendor_id, VENDOR_ID_LEN);\n\tmemcpy(&d[12], &lu->product_id, PRODUCT_ID_LEN);\n\tmemcpy(&d[28], &lu->lu_serial_no, 10);\n\tlen = (int)strlen(lu->lu_serial_no);\n\tptr = &lu->lu_serial_no[len];\n\n\tnum += 4;\n\t/* NAA IEEE registered identifier (faked) */\n\td[num]\t\t= 0x1; /* Binary */\n\td[num + 1]\t= 0x3;\n\td[num + 2]\t= 0x0;\n\td[num + 3]\t= 0x8;\n\td[num + 4]\t= 0x51;\n\td[num + 5]\t= 0x23;\n\td[num + 6]\t= 0x45;\n\td[num + 7]\t= 0x60;\n\td[num + 8]\t= 0x3;\n\td[num + 9]\t= 0x3;\n\td[num + 10] = 0x3;\n\td[num + 11] = 0x3;\n\n\tif (lu->naa) { /* If defined in config file */\n\t\tsscanf((const char *)lu->naa,\n\t\t\t   \"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx\",\n\t\t\t   &d[num + 4],\n\t\t\t   &d[num + 5],\n\t\t\t   &d[num + 6],\n\t\t\t   &d[num + 7],\n\t\t\t   &d[num + 8],\n\t\t\t   &d[num + 9],\n\t\t\t   &d[num + 10],\n\t\t\t   &d[num + 11]);\n\t} else { /* Else munge the serial number */\n\t\tptr--;\n\t\tfor (j = 11; j > 3; ptr--, j--)\n\t\t\td[num + j] = *ptr;\n\t}\n\td[num + 4] &= 0x0f;\n\td[num + 4] |= 0x50;\n}\n\nstatic struct smc_personality_template smc_pm = {\n\t.library_has_map\t\t\t= TRUE,\n\t.library_has_barcode_reader = TRUE,\n\t.library_has_playground\t\t= FALSE,\n\t.start_picker\t\t\t\t= 0x0001,\n\t.start_map\t\t\t\t\t= 0x000a,\n\t.start_drive\t\t\t\t= 0x01f4,\n\t.start_storage\t\t\t\t= 0x03e8,\n\n\t.dvcid_len = 34,\n};\n\nvoid init_hp_eml_smc(struct lu_phy_attr *lu) {\n\tsmc_pm.name = \"mhVTL - HP EML E-Series emulation\";\n\n\tsmc_pm.lu = lu;\n\tsmc_personality_module_register(&smc_pm);\n\n\tinit_slot_info(lu);\n\n\tupdate_eml_vpd_80(lu);\n\tupdate_eml_vpd_83(lu);\n\tinit_smc_log_pages(lu);\n\tinit_smc_mode_pages(lu);\n}\n\nvoid init_hp_msl_smc(struct lu_phy_attr *lu) {\n\tsmc_pm.name = \"mhVTL - HP MSL Series emulation\";\n\n\tsmc_pm.lu\t\t\t\t = lu;\n\tsmc_pm.start_picker\t\t = 0x0001;\n\tsmc_pm.start_storage\t = 0x0020;\n\tsmc_pm.start_drive\t\t = 0x01e0;\n\tsmc_pm.start_map\t\t = 0x01c0;\n\tsmc_pm.dvcid_len\t\t = 20,\n\tsmc_pm.dvcid_serial_only = TRUE,\n\tsmc_pm.no_dvcid_flag\t = TRUE,\n\n\tlu->inquiry[2] = 2; /* Set SCSI-2 Approved Version */\n\n\tsmc_personality_module_register(&smc_pm);\n\n\tinit_slot_info(lu);\n\n\tupdate_eml_vpd_80(lu);\n\tupdate_eml_vpd_83(lu);\n\tinit_smc_log_pages(lu);\n\tinit_smc_mode_pages(lu);\n}\n"
  },
  {
    "path": "usr/pm/hp_ultrium_pm.c",
    "content": "/*\n * This handles any SCSI OP codes defined in the standards as 'STREAM'\n *\n * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n * See comments in vtltape.c for a more complete version release...\n *\n */\n\n#include <unistd.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <errno.h>\n#include <inttypes.h>\n#include \"be_byteshift.h\"\n#include \"mhvtl_scsi.h\"\n#include \"vtl_common.h\"\n#include \"vtllib.h\"\n#include \"logging.h\"\n#include \"ssc.h\"\n#include \"vtlcart.h\"\n#include \"mode.h\"\n#include \"mhvtl_log.h\"\n\nstatic struct density_info density_lto1 = {\n\t4880, 127, 384, 100000, medium_density_code_lto1,\n\t\"LTO-CVE\", \"U-18\", \"Ultrium 1/8T\"};\nstatic struct density_info density_lto2 = {\n\t4880, 127, 512, 200000, medium_density_code_lto2,\n\t\"LTO-CVE\", \"U-28\", \"Ultrium 2/8T\"};\nstatic struct density_info density_lto3 = {\n\t9638, 127, 704, 381469, medium_density_code_lto3,\n\t\"LTO-CVE\", \"U-316\", \"Ultrium 3/16T\"};\nstatic struct density_info density_lto4 = {\n\t12725, 127, 896, 800000, medium_density_code_lto4,\n\t\"LTO-CVE\", \"U-416\", \"Ultrium 4/16T\"};\nstatic struct density_info density_lto5 = {\n\t15142, 127, 1280, 1500000, medium_density_code_lto5,\n\t\"LTO-CVE\", \"U-516\", \"Ultrium 5/16T\"};\nstatic struct density_info density_lto6 = {\n\t18441, 127, 2176, 3200000, medium_density_code_lto6,\n\t\"LTO-CVE\", \"U-616\", \"Ultrium 6/16T\"};\nstatic struct density_info density_lto7 = {\n\t19107, 127, 3584, 6000000, medium_density_code_lto7,\n\t\"LTO-CVE\", \"U-732\", \"Ultrium 7/32T\"};\nstatic struct density_info density_lto8 = {\n\t20669, 127, 6656, 12000000, medium_density_code_lto8,\n\t\"LTO-CVE\", \"U-832\", \"Ultrium 8/32T\"};\n\nstatic struct name_to_media_info media_info[] = {\n\t{\"LTO1\", Media_LTO1,\n\t media_type_hp_lto_data, medium_density_code_lto1},\n\t{\"LTO1 Clean\", Media_LTO1_CLEAN,\n\t media_type_hp_lto_data, medium_density_code_lto1},\n\t{\"LTO2\", Media_LTO2,\n\t media_type_hp_lto_data, medium_density_code_lto2},\n\t{\"LTO2 Clean\", Media_LTO2_CLEAN,\n\t media_type_hp_lto_data, medium_density_code_lto2},\n\t{\"LTO3\", Media_LTO3,\n\t media_type_hp_lto_data, medium_density_code_lto3},\n\t{\"LTO3 Clean\", Media_LTO3_CLEAN,\n\t media_type_hp_lto_data, medium_density_code_lto3},\n\t{\"LTO3 WORM\", Media_LTO3_WORM,\n\t media_type_hp_lto_worm, medium_density_code_lto3},\n\t{\"LTO4\", Media_LTO4,\n\t media_type_hp_lto_data, medium_density_code_lto4},\n\t{\"LTO4 Clean\", Media_LTO4_CLEAN,\n\t media_type_hp_lto_data, medium_density_code_lto4},\n\t{\"LTO4 WORM\", Media_LTO4_WORM,\n\t media_type_hp_lto_worm, medium_density_code_lto4},\n\t{\"LTO5\", Media_LTO5,\n\t media_type_hp_lto_data, medium_density_code_lto5},\n\t{\"LTO5 Clean\", Media_LTO5_CLEAN,\n\t media_type_hp_lto_data, medium_density_code_lto5},\n\t{\"LTO5 WORM\", Media_LTO5_WORM,\n\t media_type_hp_lto_worm, medium_density_code_lto5},\n\t{\"LTO6\", Media_LTO6,\n\t media_type_hp_lto_data, medium_density_code_lto6},\n\t{\"LTO6 Clean\", Media_LTO6_CLEAN,\n\t media_type_hp_lto_data, medium_density_code_lto6},\n\t{\"LTO6 WORM\", Media_LTO6_WORM,\n\t media_type_hp_lto_worm, medium_density_code_lto6},\n\t{\"LTO7\", Media_LTO7,\n\t media_type_hp_lto_data, medium_density_code_lto7},\n\t{\"LTO7 Clean\", Media_LTO7_CLEAN,\n\t media_type_hp_lto_data, medium_density_code_lto7},\n\t{\"LTO7 WORM\", Media_LTO7_WORM,\n\t media_type_hp_lto_worm, medium_density_code_lto7},\n\t{\"LTO8\", Media_LTO8,\n\t media_type_hp_lto_data, medium_density_code_lto8},\n\t{\"LTO8 Clean\", Media_LTO8_CLEAN,\n\t media_type_hp_lto_data, medium_density_code_lto8},\n\t{\"LTO8 WORM\", Media_LTO8_WORM,\n\t media_type_hp_lto_worm, medium_density_code_lto8},\n\t{\"\", 0, 0, 0},\n};\n\nstatic uint8_t clear_ult_compression(struct list_head *m) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", m);\n\t/* default clear_compression is in libvtlscsi */\n\treturn clear_compression_mode_pg(m);\n}\n\nstatic uint8_t set_ult_compression(struct list_head *m, int lvl) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", m);\n\t/* default set_compression is in libvtlscsi */\n\treturn set_compression_mode_pg(m, lvl);\n}\n\nstatic uint8_t set_ult_WORM(struct list_head *lst) {\n\tuint8_t\t\t*mp;\n\tstruct mode *m;\n\n\tset_WORM(lst); /* Default WORM setup */\n\n\t/* Now for the Ultrium unique stuff */\n\n\tm = lookup_mode_pg(lst, MODE_BEHAVIOR_CONFIGURATION, 0);\n\tif (m) {\n\t\tMHVTL_DBG(3, \"l: %p, m: %p, m->pcodePointer: %p\",\n\t\t\t\t  lst, m, m->pcodePointer);\n\t\tmp = m->pcodePointer;\n\t\tif (!mp)\n\t\t\treturn SAM_STAT_GOOD;\n\n\t\tmp[4] = 0x01; /* WORM Behavior */\n\t} else {\n\t\tMHVTL_DBG(2, \"MODE BEHAVIOUR CONFIGURATION page not found\");\n\t}\n\n\treturn SAM_STAT_GOOD;\n}\n\nstatic uint8_t clear_ult_WORM(struct list_head *m) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", m);\n\treturn clear_WORM(m);\n}\n\nstatic uint8_t update_ult_encryption_mode(struct list_head *m, void *p, int value) {\n\tstruct mode *smp;\n\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\n\tsmp = lookup_mode_pg(m, MODE_VENDOR_SPECIFIC_24H, 0);\n\tif (smp) {\n\t\tif (value)\n\t\t\tsmp->pcodePointer[5] |= ENCR_E;\n\t\telse\n\t\t\tsmp->pcodePointer[5] &= ~ENCR_E;\n\t}\n\treturn SAM_STAT_GOOD;\n}\n\nstatic int encr_capabilities_ult(struct scsi_cmd *cmd) {\n\tuint8_t\t\t\t   *buf\t\t= cmd->dbuf_p->data;\n\tstruct priv_lu_ssc *lu_priv = cmd->lu->lu_private;\n\n\tput_unaligned_be16(ENCR_CAPABILITIES, &buf[0]);\n\tput_unaligned_be16(40, &buf[2]); /* List length */\n\n\tbuf[20] = 1;\t\t\t\t\t\t/* Algorithm index */\n\tbuf[21] = 0;\t\t\t\t\t\t/* Reserved */\n\tput_unaligned_be16(0x14, &buf[22]); /* Descriptor length */\n\tbuf[24] = 0x3a;\t\t\t\t\t\t/* MAC C/DED_C DECRYPT_C = 2 ENCRYPT_C = 2 */\n\tbuf[25] = 0x10;\t\t\t\t\t\t/* NONCE_C = 1 */\n\t/* Max unauthenticated key data */\n\tput_unaligned_be16(0x20, &buf[26]);\n\t/* Max authenticated  key data */\n\tput_unaligned_be16(0x0c, &buf[28]);\n\t/* Key size */\n\tput_unaligned_be16(0x20, &buf[30]);\n\tbuf[32] = 0x01; /* EAREM */\n\t/* buf 12 - 19 reserved */\n\n\tbuf[40] = 0;\t/* Encryption Algorithm Id */\n\tbuf[41] = 0x01; /* Encryption Algorithm Id */\n\tbuf[42] = 0;\t/* Encryption Algorithm Id */\n\tbuf[43] = 0x14; /* Encryption Algorithm Id */\n\n\t/* adjustments for each emulated drive type */\n\tbuf[4] = 0x1; /* CFG_P == 01b */\n\tif (lu_priv->load_status == TAPE_LOADED) {\n\t\tswitch (mam.MediaType) {\n\t\tcase Media_LTO4:\n\t\t\tMHVTL_DBG(1, \"LTO4 Medium - Setting AVFMV\");\n\t\t\tbuf[24] |= 0x80; /* AVFMV */\n\t\t\tbreak;\n\t\tcase Media_LTO5:\n\t\t\tMHVTL_DBG(1, \"LTO5 Medium - Setting AVFMV\");\n\t\t\tbuf[24] |= 0x80; /* AVFMV */\n\t\t\tbreak;\n\t\tcase Media_LTO6:\n\t\t\tMHVTL_DBG(1, \"LTO6 Medium - Setting AVFMV\");\n\t\t\tbuf[24] |= 0x80; /* AVFMV */\n\t\t\tbreak;\n\t\tcase Media_LTO7:\n\t\t\tMHVTL_DBG(1, \"LTO7 Medium - Setting AVFMV\");\n\t\t\tbuf[24] |= 0x80; /* AVFMV */\n\t\t\tbreak;\n\t\tcase Media_LTO8:\n\t\t\tMHVTL_DBG(1, \"LTO8 Medium - Setting AVFMV\");\n\t\t\tbuf[24] |= 0x80; /* AVFMV */\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tMHVTL_DBG(1, \"Unable to set Encryption (AVFMV) bit on mounted media\");\n\t\t\tbreak;\n\t\t}\n\t}\n\tbuf[32] |= 0x08; /* RDMC_C == 4 */\n\treturn 44;\n}\n\n/* Reference HP LTO5 v3 SCSI Reference\n\n[04 - 29] - Component \"cccc\"\n[30 - 48] - Version \"rrr.vvv\"\n[49 - 72] - Date \"yyyy/mm/dd hh:mm\"\n[73 - 95] - Variant \"xxxx\"\n\n */\n\nstatic void update_hp_vpd_cx(struct lu_phy_attr *lu, uint8_t pg, char *comp,\n\t\t\t\t\t\t\t char *vers, char *date, char *variant) {\n\tstruct vpd *vpd_p;\n\tchar\t   *data;\n\n\tvpd_p = lu->lu_vpd[PCODE_OFFSET(pg)];\n\tif (!vpd_p) {\n\t\tMHVTL_LOG(\"Arrhhh... vpd pg %d not defined...\", pg);\n\t\treturn;\n\t}\n\tdata = (char *)vpd_p->data;\n\n\tdata[3] = 0x5c;\n\tsnprintf(&data[4], 25, \"%-24.24s\", comp);\n\tsnprintf(&data[30], 19, \"%-18.18s\", vers);\n\tsnprintf(&data[49], 25, \"%-24.24s\", date);\n\tsnprintf(&data[73], 23, \"%-22.22s\", variant);\n}\n\nstatic void init_ult_inquiry(struct lu_phy_attr *lu) {\n\tint\t\tpg;\n\tuint8_t worm;\n\tuint8_t local_TapeAlert[8] =\n\t\t{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\n\n\tworm = ((struct priv_lu_ssc *)lu->lu_private)->pm->drive_supports_WORM;\n\tlu->inquiry[2] =\n\t\t((struct priv_lu_ssc *)lu->lu_private)->pm->drive_ANSI_VERSION;\n\n\tlu->inquiry[40] = worm; /* Reference 3.7.1 HP Ultrium ISV Cookbook */\n\n\tpg\t\t\t   = PCODE_OFFSET(0x86);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_86_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_86(lu, ((struct priv_lu_ssc *)lu->lu_private)->pm);\n\n\t/* Sequential Access device capabilities - Ref: 8.4.2 */\n\tpg\t\t\t   = PCODE_OFFSET(0xb0);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_B0_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_b0(lu, &worm);\n\n\t/* Manufacture-assigned serial number - Ref: 8.4.3 */\n\tpg\t\t\t   = PCODE_OFFSET(0xb1);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_B1_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_b1(lu, lu->lu_serial_no);\n\n\t/* TapeAlert supported flags - Ref: 8.4.4 */\n\tpg\t\t\t   = PCODE_OFFSET(0xb2);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_B2_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_b2(lu, &local_TapeAlert);\n\n\t/* VPD page 0xC0 - Firmware revision page */\n\tpg\t\t\t   = PCODE_OFFSET(0xc0);\n\tlu->lu_vpd[pg] = alloc_vpd(0x60);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_hp_vpd_cx(lu, pg, \"Firmware\", MHVTL_VERSION,\n\t\t\t\t\t \"2012/04/18 19:38\", \"6\");\n\n\t/* VPD page 0xC1 - Hardware */\n\tpg\t\t\t   = PCODE_OFFSET(0xc1);\n\tlu->lu_vpd[pg] = alloc_vpd(0x60);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_hp_vpd_cx(lu, pg, \"Hardware\", MHVTL_VERSION,\n\t\t\t\t\t \"2012/04/18 06:53\", \"5\");\n\n\t/* VPD page 0xC2 - PCA */\n\tpg\t\t\t   = PCODE_OFFSET(0xc2);\n\tlu->lu_vpd[pg] = alloc_vpd(0x60);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_hp_vpd_cx(lu, pg, \"PCA\", MHVTL_VERSION,\n\t\t\t\t\t \"1996/11/29 10:00\", \"4\");\n\n\t/* VPD page 0xC3 - Mechanism */\n\tpg\t\t\t   = PCODE_OFFSET(0xc3);\n\tlu->lu_vpd[pg] = alloc_vpd(0x60);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_hp_vpd_cx(lu, pg, \"Mechanism\", MHVTL_VERSION,\n\t\t\t\t\t \"1992/08/11 10:00\", \"3\");\n\n\t/* VPD page 0xC4 - Head Assembly */\n\tpg\t\t\t   = PCODE_OFFSET(0xc4);\n\tlu->lu_vpd[pg] = alloc_vpd(0x60);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_hp_vpd_cx(lu, pg, \"Head Assy\", MHVTL_VERSION,\n\t\t\t\t\t \"1966/07/28 10:00\", \"2\");\n\n\t/* VPD page 0xC5 - ACI */\n\tpg\t\t\t   = PCODE_OFFSET(0xc5);\n\tlu->lu_vpd[pg] = alloc_vpd(0x60);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_hp_vpd_cx(lu, pg, \"ACI\", MHVTL_VERSION,\n\t\t\t\t\t \"1960/03/10 10:00\", \"1\");\n}\n\nstatic int hp_lto_kad_validation(int encrypt_mode, int ukad, int akad) {\n\tint count = FALSE;\n\tif (ukad > 32 || akad > 12)\n\t\tcount = TRUE;\n\tif (!encrypt_mode && (ukad || akad))\n\t\tcount = TRUE;\n\n\treturn count;\n}\n\n/* Some comments before I forget how this is supose to work..\n - cleaning_media_state is either\n   0 - Not mounted\n   1 - Cleaning media mounted -> return Cleaning cartridge installed\n   2 - Cleaning media mounted -> return Cause not reportable\n   3 - Cleaning media mounted -> return Initializing command required\n\n On cleaning media mount, hp_cleaning() is called which:\n   Sets a pointer from priv_lu_ssc -> cleaning_media_state.\n   Sets cleaning_media_state to 1.\n   Sets a 30 second timer to call inc_cleaning_state()\n\n inc_cleaning_state()\n   Increments cleaning_media_state.\n   If cleaning media_state == 2, set another timer for 90 seconds to again\n   call inc_cleaning_state.\n\n If the application issues a TUR, ssc_tur() will return one of the\n above status codes depending on the current value of cleaning_media_state.\n\n When the cleaning media is unmounted, the pointer in priv_lu_ssc to this\n var will be re-set to NULL so the ssc_tur() will return defautl value.\n\n */\nstatic volatile sig_atomic_t cleaning_media_state;\n\nstatic void inc_cleaning_state(int sig);\n\nstatic void set_cleaning_timer(int t) {\n\tMHVTL_DBG(3, \"+++ Trace +++ Setting alarm for %d\", t);\n\tsignal(SIGALRM, inc_cleaning_state);\n\talarm(t);\n}\n\nstatic void inc_cleaning_state(int sig) {\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\tsignal(sig, inc_cleaning_state);\n\n\tcleaning_media_state++;\n\n\tif (cleaning_media_state == CLEAN_MOUNT_STAGE2)\n\t\tset_cleaning_timer(90);\n}\n\nstatic uint8_t hp_media_load(struct lu_phy_attr *lu, int load) {\n\tstruct priv_lu_ssc *lu_priv = lu->lu_private;\n\n\tMHVTL_DBG(3, \"+++ Trace +++ %s\", (load) ? \"load\" : \"unload\");\n\n\tif (load) {\n\t\tlu->mode_media_type = 0; /* Data */\n\n\t\tif (lu_priv->mamp->MediumType == MEDIA_TYPE_WORM)\n\t\t\tlu->mode_media_type = 0x01; /* WORM media */\n\t} else {\n\t\tlu->mode_media_type = 0;\n\t}\n\treturn 0;\n}\n\nstatic uint8_t hp_cleaning(void *ssc_priv) {\n\tstruct priv_lu_ssc *ssc;\n\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\n\tssc = ssc_priv;\n\n\tssc->cleaning_media_state = &cleaning_media_state;\n\tcleaning_media_state\t  = CLEAN_MOUNT_STAGE1;\n\n\tset_cleaning_timer(30);\n\n\treturn 0;\n}\n\nstatic char *pm_name_lto1 = \"HP LTO-1\";\nstatic char *pm_name_lto2 = \"HP LTO-2\";\nstatic char *pm_name_lto3 = \"HP LTO-3\";\nstatic char *pm_name_lto4 = \"HP LTO-4\";\nstatic char *pm_name_lto5 = \"HP LTO-5\";\nstatic char *pm_name_lto6 = \"HP LTO-6\";\nstatic char *pm_name_lto7 = \"HP LTO-7\";\nstatic char *pm_name_lto8 = \"HP LTO-8\";\n\nstatic struct ssc_personality_template ssc_pm = {\n\t.valid_encryption_blk = valid_encryption_blk, /* default in ssc.c */\n\t.check_restrictions\t  = check_restrictions,\t  /* default in ssc.c */\n\t.clear_compression\t  = clear_ult_compression,\n\t.set_compression\t  = set_ult_compression,\n\t.media_load\t\t\t  = hp_media_load,\n\t.cleaning_media\t\t  = hp_cleaning,\n\t.media_handling\t\t  = media_info,\n};\n\nvoid init_hp_ult_1(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_lto1;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.native_drive_density\t\t\t\t = &density_lto1;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = FALSE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = FALSE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_ult_inquiry(lu);\n\n\t/* IBM Ultrium SCSI Reference (5edition - Oct 2001)\n\t * lists these mode pages\n\t */\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_information_exception(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\t/* Capacity units in MBytes */\n\t((struct priv_lu_ssc *)lu->lu_private)->capacity_unit = 1L << 20;\n\n\tadd_density_support(&lu->den_list, &density_lto1, 1);\n\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO1\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO1 Clean\");\n}\n\nvoid init_hp_ult_2(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_lto2;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.native_drive_density\t\t\t\t = &density_lto2;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = FALSE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = FALSE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_ult_inquiry(lu);\n\n\t/* Based on 9th edition of IBM SCSI Reference */\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_control(lu);\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_information_exception(lu);\n\tadd_mode_medium_configuration(lu);\n\tadd_mode_behavior_configuration(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\t/* Capacity units in MBytes */\n\t((struct priv_lu_ssc *)lu->lu_private)->capacity_unit = 1L << 20;\n\n\tadd_density_support(&lu->den_list, &density_lto1, 1);\n\tadd_density_support(&lu->den_list, &density_lto2, 1);\n\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO1\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO1 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO2\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO2 Clean\");\n}\n\nvoid init_hp_ult_3(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_lto3;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.native_drive_density\t\t\t\t = &density_lto3;\n\tssc_pm.clear_WORM\t\t\t\t\t\t = clear_ult_WORM;\n\tssc_pm.set_WORM\t\t\t\t\t\t\t = set_ult_WORM;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = FALSE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_ult_inquiry(lu);\n\n\t/* Based on 9th edition of IBM SCSI Reference */\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_control(lu);\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_device_configuration_extension(lu);\n\tadd_mode_information_exception(lu);\n\tadd_mode_medium_configuration(lu);\n\tadd_mode_behavior_configuration(lu);\n\tadd_mode_vendor_25h_mode_pages(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\t/* Capacity units in MBytes */\n\t((struct priv_lu_ssc *)lu->lu_private)->capacity_unit = 1L << 20;\n\n\tadd_density_support(&lu->den_list, &density_lto1, 0);\n\tadd_density_support(&lu->den_list, &density_lto2, 1);\n\tadd_density_support(&lu->den_list, &density_lto3, 1);\n\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO1\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO1 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO2\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO2 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO3\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO3 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO3 WORM\");\n}\n\nvoid init_hp_ult_4(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_lto4;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = TRUE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\tssc_pm.native_drive_density\t\t\t\t = &density_lto4;\n\tssc_pm.update_encryption_mode\t\t\t = update_ult_encryption_mode;\n\tssc_pm.encryption_capabilities\t\t\t = encr_capabilities_ult;\n\tssc_pm.kad_validation\t\t\t\t\t = hp_lto_kad_validation;\n\tssc_pm.clear_WORM\t\t\t\t\t\t = clear_ult_WORM;\n\tssc_pm.set_WORM\t\t\t\t\t\t\t = set_ult_WORM;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_ult_inquiry(lu);\n\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_control(lu);\n\tadd_mode_control_extension(lu);\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_device_configuration_extension(lu);\n\tadd_mode_medium_partition(lu);\n\tadd_mode_power_condition(lu);\n\tadd_mode_information_exception(lu);\n\tadd_mode_medium_configuration(lu);\n\tadd_mode_ult_encr_mode_pages(lu); /* Extra for LTO-4 */\n\tadd_mode_vendor_25h_mode_pages(lu);\n\tadd_mode_encryption_mode_attribute(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\t/* Capacity units in MBytes */\n\t((struct priv_lu_ssc *)lu->lu_private)->capacity_unit = 1L << 20;\n\n\tregister_ops(lu, SECURITY_PROTOCOL_IN, ssc_spin, NULL, NULL);\n\tregister_ops(lu, SECURITY_PROTOCOL_OUT, ssc_spout, NULL, NULL);\n\n\tadd_density_support(&lu->den_list, &density_lto2, 0);\n\tadd_density_support(&lu->den_list, &density_lto3, 1);\n\tadd_density_support(&lu->den_list, &density_lto4, 1);\n\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO2\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO2 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO3\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO3 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO3 WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO4\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO4 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO4 WORM\");\n}\n\nvoid init_hp_ult_5(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_lto5;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = TRUE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\tssc_pm.native_drive_density\t\t\t\t = &density_lto5;\n\tssc_pm.update_encryption_mode\t\t\t = update_ult_encryption_mode;\n\tssc_pm.encryption_capabilities\t\t\t = encr_capabilities_ult;\n\tssc_pm.kad_validation\t\t\t\t\t = hp_lto_kad_validation;\n\tssc_pm.clear_WORM\t\t\t\t\t\t = clear_ult_WORM;\n\tssc_pm.set_WORM\t\t\t\t\t\t\t = set_ult_WORM;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_ult_inquiry(lu);\n\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_control(lu);\n\tadd_mode_control_extension(lu);\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_device_configuration_extension(lu);\n\tadd_mode_medium_partition(lu);\n\tadd_mode_power_condition(lu);\n\tadd_mode_information_exception(lu);\n\tadd_mode_medium_configuration(lu);\n\tadd_mode_ult_encr_mode_pages(lu); /* Extra for LTO-5 */\n\tadd_mode_vendor_25h_mode_pages(lu);\n\tadd_mode_encryption_mode_attribute(lu);\n\n\t/* Supports non-zero programable early warning */\n\tupdate_prog_early_warning(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\t/* Capacity units in MBytes */\n\t((struct priv_lu_ssc *)lu->lu_private)->capacity_unit = 1L << 20;\n\n\tregister_ops(lu, SECURITY_PROTOCOL_IN, ssc_spin, NULL, NULL);\n\tregister_ops(lu, SECURITY_PROTOCOL_OUT, ssc_spout, NULL, NULL);\n\n\tadd_density_support(&lu->den_list, &density_lto3, 0);\n\tadd_density_support(&lu->den_list, &density_lto4, 1);\n\tadd_density_support(&lu->den_list, &density_lto5, 1);\n\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO3\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO3 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO4\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO4 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO4 WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO4 ENCR\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO5\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO5 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO5 WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO5 ENCR\");\n}\n\nvoid init_hp_ult_6(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_lto6;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = TRUE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\tssc_pm.native_drive_density\t\t\t\t = &density_lto6;\n\tssc_pm.update_encryption_mode\t\t\t = update_ult_encryption_mode;\n\tssc_pm.encryption_capabilities\t\t\t = encr_capabilities_ult;\n\tssc_pm.kad_validation\t\t\t\t\t = hp_lto_kad_validation;\n\tssc_pm.clear_WORM\t\t\t\t\t\t = clear_ult_WORM;\n\tssc_pm.set_WORM\t\t\t\t\t\t\t = set_ult_WORM;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_ult_inquiry(lu);\n\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_control(lu);\n\tadd_mode_control_extension(lu);\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_device_configuration_extension(lu);\n\tadd_mode_medium_partition(lu);\n\tadd_mode_power_condition(lu);\n\tadd_mode_information_exception(lu);\n\tadd_mode_medium_configuration(lu);\n\tadd_mode_ult_encr_mode_pages(lu); /* Extra for LTO-5 */\n\tadd_mode_vendor_25h_mode_pages(lu);\n\tadd_mode_encryption_mode_attribute(lu);\n\n\t/* Supports non-zero programable early warning */\n\tupdate_prog_early_warning(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\t/* Capacity units in MBytes */\n\t((struct priv_lu_ssc *)lu->lu_private)->capacity_unit = 1L << 20;\n\n\tregister_ops(lu, SECURITY_PROTOCOL_IN, ssc_spin, NULL, NULL);\n\tregister_ops(lu, SECURITY_PROTOCOL_OUT, ssc_spout, NULL, NULL);\n\n\tadd_density_support(&lu->den_list, &density_lto4, 0);\n\tadd_density_support(&lu->den_list, &density_lto5, 1);\n\tadd_density_support(&lu->den_list, &density_lto6, 1);\n\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO4\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO4 Clean\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO4 WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO5\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO5 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO5 WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO5 ENCR\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO6\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO6 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO6 WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO6 ENCR\");\n}\n\nvoid init_hp_ult_7(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_lto7;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = TRUE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\tssc_pm.native_drive_density\t\t\t\t = &density_lto7;\n\tssc_pm.update_encryption_mode\t\t\t = update_ult_encryption_mode;\n\tssc_pm.encryption_capabilities\t\t\t = encr_capabilities_ult;\n\tssc_pm.kad_validation\t\t\t\t\t = hp_lto_kad_validation;\n\tssc_pm.clear_WORM\t\t\t\t\t\t = clear_ult_WORM;\n\tssc_pm.set_WORM\t\t\t\t\t\t\t = set_ult_WORM;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_ult_inquiry(lu);\n\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_control(lu);\n\tadd_mode_control_extension(lu);\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_device_configuration_extension(lu);\n\tadd_mode_medium_partition(lu);\n\tadd_mode_power_condition(lu);\n\tadd_mode_information_exception(lu);\n\tadd_mode_medium_configuration(lu);\n\tadd_mode_ult_encr_mode_pages(lu); /* Extra for LTO-5 */\n\tadd_mode_vendor_25h_mode_pages(lu);\n\tadd_mode_encryption_mode_attribute(lu);\n\n\t/* Supports non-zero programable early warning */\n\tupdate_prog_early_warning(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\t/* Capacity units in MBytes */\n\t((struct priv_lu_ssc *)lu->lu_private)->capacity_unit = 1L << 20;\n\n\tregister_ops(lu, SECURITY_PROTOCOL_IN, ssc_spin, NULL, NULL);\n\tregister_ops(lu, SECURITY_PROTOCOL_OUT, ssc_spout, NULL, NULL);\n\n\tadd_density_support(&lu->den_list, &density_lto5, 0);\n\tadd_density_support(&lu->den_list, &density_lto6, 1);\n\tadd_density_support(&lu->den_list, &density_lto7, 1);\n\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO5\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO5 Clean\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO5 WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO6\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO6 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO6 WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO6 ENCR\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO7\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO7 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO7 WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO7 ENCR\");\n}\nvoid init_hp_ult_8(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_lto8;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = TRUE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\tssc_pm.native_drive_density\t\t\t\t = &density_lto8;\n\tssc_pm.update_encryption_mode\t\t\t = update_ult_encryption_mode;\n\tssc_pm.encryption_capabilities\t\t\t = encr_capabilities_ult;\n\tssc_pm.kad_validation\t\t\t\t\t = hp_lto_kad_validation;\n\tssc_pm.clear_WORM\t\t\t\t\t\t = clear_ult_WORM;\n\tssc_pm.set_WORM\t\t\t\t\t\t\t = set_ult_WORM;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_ult_inquiry(lu);\n\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_control(lu);\n\tadd_mode_control_extension(lu);\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_device_configuration_extension(lu);\n\tadd_mode_medium_partition(lu);\n\tadd_mode_power_condition(lu);\n\tadd_mode_information_exception(lu);\n\tadd_mode_medium_configuration(lu);\n\tadd_mode_ult_encr_mode_pages(lu); /* Extra for LTO-5 */\n\tadd_mode_vendor_25h_mode_pages(lu);\n\tadd_mode_encryption_mode_attribute(lu);\n\n\t/* Supports non-zero programable early warning */\n\tupdate_prog_early_warning(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\t/* Capacity units in MBytes */\n\t((struct priv_lu_ssc *)lu->lu_private)->capacity_unit = 1L << 20;\n\n\tregister_ops(lu, SECURITY_PROTOCOL_IN, ssc_spin, NULL, NULL);\n\tregister_ops(lu, SECURITY_PROTOCOL_OUT, ssc_spout, NULL, NULL);\n\n\t/* LTO 8 drives cannot read LTO6 cartridges.\n\thttps://www.lto.org/lto-generation-compatibility/\n\t\"LTO drive generations 1-7 are able to read tapes from two generations prior\n\tand are able to write to tapes from the prior generation.\n\n\tLTO-8 drives can read and write to LTO-7 and LTO-8 media*/\n\n\tadd_density_support(&lu->den_list, &density_lto7, 1);\n\tadd_density_support(&lu->den_list, &density_lto8, 1);\n\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO7\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO7 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO7 WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO7 ENCR\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO8\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO8 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO8 WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO8 ENCR\");\n}\n"
  },
  {
    "path": "usr/pm/ibm_03592_pm.c",
    "content": "/*\n * This handles any SCSI OP codes defined in the standards as 'STREAM'\n *\n * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n * See comments in vtltape.c for a more complete version release...\n *\n */\n\n#include <unistd.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <errno.h>\n#include <string.h>\n#include <inttypes.h>\n#include \"be_byteshift.h\"\n#include \"mhvtl_scsi.h\"\n#include \"vtl_common.h\"\n#include \"vtllib.h\"\n#include \"logging.h\"\n#include \"ssc.h\"\n#include \"vtlcart.h\"\n#include \"mode.h\"\n#include \"mhvtl_log.h\"\n\n/* Note need to change 'medium density' if encryption is enabled / disabled */\nstatic struct density_info density_j1a = {\n\t0x2e18, 0x0d, 0x200, 0x493e0, medium_density_code_j1a,\n\t\"IBM\", \"3592A1\", \"\"};\n\nstatic struct density_info density_e05 = {\n\t0x2e18, 0x0d, 0x380, 0x7a120, medium_density_code_e05,\n\t\"IBM\", \"3592A2\", \"\"};\n\nstatic struct density_info density_e06 = {\n\t0x348c, 0x0d, 0x480, 0x7a120, medium_density_code_e06,\n\t\"IBM\", \"3592A3\", \"\"};\n\nstatic struct density_info density_e07 = {\n\t0x348c, 0x0d, 0x480, 0x7a120, medium_density_code_e07,\n\t\"IBM\", \"3592A4\", \"\"};\n\nstatic struct name_to_media_info media_info[] = {\n\t{\"03592 JA\", Media_3592_JA,\n\t media_type_unknown, medium_density_code_j1a},\n\t{\"03592 JA Clean\", Media_3592_JA_CLEAN,\n\t media_type_unknown, medium_density_code_j1a},\n\t{\"03592 JA WORM\", Media_3592_JW,\n\t media_type_unknown, medium_density_code_j1a},\n\n\t{\"03592 JB\", Media_3592_JB,\n\t media_type_unknown, medium_density_code_e05},\n\t{\"03592 JB Clean\", Media_3592_JB_CLEAN,\n\t media_type_unknown, medium_density_code_e05},\n\t{\"03592 JB ENCR\", Media_3592_JB,\n\t media_type_unknown, medium_density_code_e05_ENCR},\n\n\t{\"03592 JC\", Media_3592_JX,\n\t media_type_unknown, medium_density_code_e06},\n\t{\"03592 JC Clean\", Media_3592_JX_CLEAN,\n\t media_type_unknown, medium_density_code_e06},\n\t{\"03592 JC ENCR\", Media_3592_JX,\n\t media_type_unknown, medium_density_code_e06_ENCR},\n\n\t{\"03592 JK\", Media_3592_JK,\n\t media_type_unknown, medium_density_code_e07},\n\t{\"03592 JK Clean\", Media_3592_JK_CLEAN,\n\t media_type_unknown, medium_density_code_e07},\n\t{\"03592 JK ENCR\", Media_3592_JK,\n\t media_type_unknown, medium_density_code_e07_ENCR},\n\t{\"\", 0, 0, 0},\n};\n\nstatic uint8_t valid_encryption_media_E06(struct scsi_cmd *cmd) {\n\tuint8_t\t\t\t   *sam_stat = &cmd->dbuf_p->sam_stat;\n\tstruct lu_phy_attr *lu;\n\tstruct priv_lu_ssc *lu_priv;\n\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\n\tlu\t\t= cmd->lu;\n\tlu_priv = lu->lu_private;\n\n\tif (c_pos->blk_number == 0) {\n\t\t/* 3590 media must be formatted to allow encryption.\n\t\t * This is done by writting an ANSI like label\n\t\t * (NBU label is close enough) to the tape while\n\t\t * an encryption key is in place. The drive doesn't\n\t\t * actually use the key, but sets the tape format\n\t\t */\n\t\tif (lu_priv->pm->drive_type == drive_3592_E06) {\n\t\t\tif (lu_priv->ENCRYPT_MODE == 2) {\n\t\t\t\tlu_priv->app_encr_info = NULL;\n\t\t\t\tmam.Flags |= MAM_FLAGS_ENCRYPTION_FORMAT;\n\t\t\t} else\n\t\t\t\tmam.Flags &= ~MAM_FLAGS_ENCRYPTION_FORMAT;\n\t\t}\n\t\tmodeBlockDescriptor[0]\t = lu_priv->pm->native_drive_density->density;\n\t\tmam.MediumDensityCode\t = modeBlockDescriptor[0];\n\t\tmam.FormattedDensityCode = modeBlockDescriptor[0];\n\t\trewriteMAM(sam_stat);\n\t} else {\n\t\t/* Extra check for 3592 to be sure the cartridge is\n\t\t * formatted for encryption\n\t\t */\n\t\tif ((lu_priv->pm->drive_type == drive_3592_E06) &&\n\t\t\tlu_priv->ENCRYPT_MODE &&\n\t\t\t!(mam.Flags & MAM_FLAGS_ENCRYPTION_FORMAT)) {\n\t\t\tsam_data_protect(E_WRITE_PROTECT, sam_stat);\n\t\t\treturn 0;\n\t\t}\n\t\tif (mam.MediumDensityCode !=\n\t\t\tlu_priv->pm->native_drive_density->density) {\n\t\t\tswitch (lu_priv->pm->drive_type) {\n\t\t\tcase drive_3592_E05:\n\t\t\t\tif (mam.MediumDensityCode ==\n\t\t\t\t\tmedium_density_code_j1a)\n\t\t\t\t\tbreak;\n\t\t\t\tsam_data_protect(E_WRITE_PROTECT, sam_stat);\n\t\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t\t\tbreak;\n\t\t\tcase drive_3592_E06:\n\t\t\t\tif (mam.MediumDensityCode ==\n\t\t\t\t\tmedium_density_code_e05)\n\t\t\t\t\tbreak;\n\t\t\t\tsam_data_protect(E_WRITE_PROTECT, sam_stat);\n\t\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t\t\tbreak;\n\t\t\tcase drive_3592_E07:\n\t\t\t\tif (mam.MediumDensityCode ==\n\t\t\t\t\tmedium_density_code_e06)\n\t\t\t\t\tbreak;\n\t\t\t\tsam_data_protect(E_WRITE_PROTECT, sam_stat);\n\t\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tsam_data_protect(E_WRITE_PROTECT, sam_stat);\n\t\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn SAM_STAT_GOOD;\n}\n\nstatic uint8_t clear_3592_comp(struct list_head *m) {\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\t/* default clear_compression is in libvtlscsi */\n\treturn clear_compression_mode_pg(m);\n}\n\nstatic uint8_t set_3592_comp(struct list_head *m, int lvl) {\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\t/* default set_compression is in libvtlscsi */\n\treturn set_compression_mode_pg(m, lvl);\n}\n\nstatic uint8_t update_3592_encryption_mode(struct list_head *m, void *p, int value) {\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\n\treturn SAM_STAT_GOOD;\n}\n\nstatic uint8_t set_3592_WORM(struct list_head *m) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", m);\n\treturn set_WORM(m);\n}\n\nstatic uint8_t clear_3592_WORM(struct list_head *m) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", m);\n\treturn clear_WORM(m);\n}\n\nstatic int encr_capabilities_3592(struct scsi_cmd *cmd) {\n\tuint8_t\t\t\t   *buf\t\t= cmd->dbuf_p->data;\n\tstruct priv_lu_ssc *lu_priv = cmd->lu->lu_private;\n\n\tput_unaligned_be16(ENCR_CAPABILITIES, &buf[0]);\n\tput_unaligned_be16(40, &buf[2]); /* List length */\n\n\tbuf[20] = 1;\t\t\t\t\t\t/* Algorithm index */\n\tbuf[21] = 0;\t\t\t\t\t\t/* Reserved */\n\tput_unaligned_be16(0x14, &buf[22]); /* Descriptor length */\n\tbuf[24] = 0x3a;\t\t\t\t\t\t/* MAC C/DED_C DECRYPT_C = 2 ENCRYPT_C = 2 */\n\tbuf[25] = 0x10;\t\t\t\t\t\t/* NONCE_C = 1 */\n\t/* Max unauthenticated key data */\n\tput_unaligned_be16(0x20, &buf[26]);\n\t/* Max authenticated  key data */\n\tput_unaligned_be16(0x0c, &buf[28]);\n\t/* Key size */\n\tput_unaligned_be16(0x20, &buf[30]);\n\tbuf[32] = 0x01; /* EAREM */\n\t/* buf 12 - 19 reserved */\n\n\tbuf[40] = 0;\t/* Encryption Algorithm Id */\n\tbuf[41] = 0x01; /* Encryption Algorithm Id */\n\tbuf[42] = 0;\t/* Encryption Algorithm Id */\n\tbuf[43] = 0x14; /* Encryption Algorithm Id */\n\n\t/*\tMHVTL_DBG(1, \"Drive type: %s, Media type: %s\",\n\t\t\t\t\tdrive_name(lunit.drive_type),\n\t\t\t\t\tlookup_media_type(mam.MediaType));\n\t*/\n\n\tif (lu_priv->load_status == TAPE_LOADED) {\n\t\tbuf[24] |= 0x80; /* AVFMV */\n\t\tbuf[27] = 0x00;\t /* Max unauthenticated key data */\n\t\tbuf[32] |= 0x0e; /* RDMC_C == 7 */\n\t}\n\treturn 44;\n}\n\nstatic void init_3592_inquiry(struct lu_phy_attr *lu) {\n\tint\t\tpg;\n\tuint8_t worm;\n\tuint8_t local_TapeAlert[8] =\n\t\t{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\n\n\tworm = ((struct priv_lu_ssc *)lu->lu_private)->pm->drive_supports_WORM;\n\tlu->inquiry[2] =\n\t\t((struct priv_lu_ssc *)lu->lu_private)->pm->drive_ANSI_VERSION;\n\n\t/* Sequential Access device capabilities - Ref: 8.4.2 */\n\tpg\t\t\t   = PCODE_OFFSET(0xb0);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_B0_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_b0(lu, &worm);\n\n\t/* Manufacture-assigned serial number - Ref: 8.4.3 */\n\tpg\t\t\t   = PCODE_OFFSET(0xb1);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_B1_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_b1(lu, lu->lu_serial_no);\n\n\t/* TapeAlert supported flags - Ref: 8.4.4 */\n\tpg\t\t\t   = PCODE_OFFSET(0xb2);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_B2_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_b2(lu, &local_TapeAlert);\n\n\t/* VPD page 0xC0 */\n\tpg\t\t\t   = PCODE_OFFSET(0xc0);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_C0_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_c0(lu, \"10-03-2008 19:38:00\");\n\n\t/* VPD page 0xC1 */\n\tpg\t\t\t   = PCODE_OFFSET(0xc1);\n\tlu->lu_vpd[pg] = alloc_vpd(strlen(\"Security\"));\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_c1(lu, \"Security\");\n}\n\nstatic int e06_kad_validation(int encrypt_mode, int ukad, int akad) {\n\tint count = FALSE;\n\tif (ukad > 0 || akad > 12)\n\t\tcount = TRUE;\n\tif (!encrypt_mode && (ukad || akad))\n\t\tcount = TRUE;\n\n\treturn count;\n}\n\n/* Some comments before I forget how this is supose to work..\n - cleaning_media_state is either\n   0 - Not mounted\n   1 - Cleaning media mounted -> return Cleaning cartridge installed\n   2 - Cleaning media mounted -> return Cause not reportable\n   3 - Cleaning media mounted -> return Initializing command required\n\n On cleaning media mount, ibm_cleaning() is called which:\n   Sets a pointer from priv_lu_ssc -> cleaning_media_state.\n   Sets cleaning_media_state to 1.\n   Sets a 30 second timer to call inc_cleaning_state()\n\n inc_cleaning_state()\n   Increments cleaning_media_state.\n   If cleaning media_state == 2, set another timer for 90 seconds to again\n   call inc_cleaning_state.\n\n If the application issues a TUR, ssc_tur() will return one of the\n above status codes depending on the current value of cleaning_media_state.\n\n When the cleaning media is unmounted, the pointer in priv_lu_ssc to this\n var will be re-set to NULL so the ssc_tur() will return defautl value.\n\n */\nstatic volatile sig_atomic_t cleaning_media_state;\n\nstatic void inc_cleaning_state(int sig);\n\nstatic void set_cleaning_timer(int t) {\n\tMHVTL_DBG(3, \"+++ Trace +++ Setting alarm for %d\", t);\n\tsignal(SIGALRM, inc_cleaning_state);\n\talarm(t);\n}\n\nstatic void inc_cleaning_state(int sig) {\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\tsignal(sig, inc_cleaning_state);\n\n\tcleaning_media_state++;\n\n\tif (cleaning_media_state == CLEAN_MOUNT_STAGE2)\n\t\tset_cleaning_timer(90);\n}\n\nstatic uint8_t ibm_media_load(struct lu_phy_attr *lu, int load) {\n\tMHVTL_DBG(3, \"+++ Trace +++ %s\", (load) ? \"load\" : \"unload\");\n\treturn 0;\n}\n\nstatic uint8_t ibm_cleaning(void *ssc_priv) {\n\tstruct priv_lu_ssc *ssc;\n\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\n\tssc = ssc_priv;\n\n\tssc->cleaning_media_state = &cleaning_media_state;\n\tcleaning_media_state\t  = CLEAN_MOUNT_STAGE1;\n\n\tset_cleaning_timer(30);\n\n\treturn 0;\n}\n\nstatic void init_03592_mode_pages(struct lu_phy_attr *lu) {\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_control(lu);\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_medium_partition(lu);\n\tadd_mode_power_condition(lu);\n\tadd_mode_information_exception(lu);\n\tadd_mode_medium_configuration(lu);\n}\n\nstatic char *pm_name_j1a = \"03592J1A\";\nstatic char *pm_name_e05 = \"03592E05\";\nstatic char *pm_name_e06 = \"03592E06\";\nstatic char *pm_name_e07 = \"03592E07\";\n\nstatic struct ssc_personality_template ssc_pm = {\n\t.valid_encryption_blk\t= valid_encryption_blk,\n\t.valid_encryption_media = valid_encryption_media_E06,\n\t.update_encryption_mode = update_3592_encryption_mode,\n\t.kad_validation\t\t\t= e06_kad_validation,\n\t.check_restrictions\t\t= check_restrictions,\n\t.clear_compression\t\t= clear_3592_comp,\n\t.set_compression\t\t= set_3592_comp,\n\t.clear_WORM\t\t\t\t= clear_3592_WORM,\n\t.set_WORM\t\t\t\t= set_3592_WORM,\n\t.media_load\t\t\t\t= ibm_media_load,\n\t.cleaning_media\t\t\t= ibm_cleaning,\n\t.media_handling\t\t\t= media_info,\n};\n\nvoid init_3592_j1a(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_j1a;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.drive_type\t\t\t\t\t\t = drive_3592_J1A;\n\tssc_pm.native_drive_density\t\t\t\t = &density_j1a;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = FALSE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_3592_inquiry(lu);\n\n\tinit_03592_mode_pages(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\tadd_density_support(&lu->den_list, &density_j1a, 1);\n\tadd_drive_media_list(lu, LOAD_RW, \"03592 JA\");\n\tadd_drive_media_list(lu, LOAD_RO, \"03592 JA Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"03592 JA WORM\");\n}\n\nvoid init_3592_E05(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_e05;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.drive_type\t\t\t\t\t\t = drive_3592_E05;\n\tssc_pm.native_drive_density\t\t\t\t = &density_e05;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = TRUE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_3592_inquiry(lu);\n\n\tinit_03592_mode_pages(lu);\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\tadd_density_support(&lu->den_list, &density_j1a, 1);\n\tadd_density_support(&lu->den_list, &density_e05, 1);\n\tadd_drive_media_list(lu, LOAD_RW, \"03592 JA\");\n\tadd_drive_media_list(lu, LOAD_RO, \"03592 JA Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"03592 JA WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"03592 JB\");\n\tadd_drive_media_list(lu, LOAD_RO, \"03592 JB Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"03592 JB WORM\");\n}\n\nvoid init_3592_E06(struct lu_phy_attr *lu) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", &lu->mode_pg);\n\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_e06;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.native_drive_density\t\t\t\t = &density_e06;\n\tssc_pm.encryption_capabilities\t\t\t = encr_capabilities_3592;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = TRUE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_3592_inquiry(lu);\n\n\tinit_03592_mode_pages(lu);\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\tssc_pm.drive_type = drive_3592_E06;\n\tregister_ops(lu, SECURITY_PROTOCOL_IN, ssc_spin, NULL, NULL);\n\tregister_ops(lu, SECURITY_PROTOCOL_OUT, ssc_spout, NULL, NULL);\n\tadd_density_support(&lu->den_list, &density_j1a, 0);\n\tadd_density_support(&lu->den_list, &density_e05, 1);\n\tadd_density_support(&lu->den_list, &density_e06, 1);\n\tadd_drive_media_list(lu, LOAD_RW, \"03592 JA\");\n\tadd_drive_media_list(lu, LOAD_RO, \"03592 JA Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"03592 JA WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"03592 JB\");\n\tadd_drive_media_list(lu, LOAD_RO, \"03592 JB Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"03592 JB WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"03592 JC\");\n\tadd_drive_media_list(lu, LOAD_RO, \"03592 JC Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"03592 JC WORM\");\n}\n\nvoid init_3592_E07(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_e07;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.native_drive_density\t\t\t\t = &density_e07;\n\tssc_pm.encryption_capabilities\t\t\t = encr_capabilities_3592;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = TRUE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_3592_inquiry(lu);\n\n\tinit_03592_mode_pages(lu);\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\tssc_pm.drive_type = drive_3592_E07;\n\tregister_ops(lu, SECURITY_PROTOCOL_IN, ssc_spin, NULL, NULL);\n\tregister_ops(lu, SECURITY_PROTOCOL_OUT, ssc_spout, NULL, NULL);\n\tadd_density_support(&lu->den_list, &density_e05, 0);\n\tadd_density_support(&lu->den_list, &density_e06, 1);\n\tadd_density_support(&lu->den_list, &density_e07, 1);\n\tadd_drive_media_list(lu, LOAD_RW, \"03592 JB\");\n\tadd_drive_media_list(lu, LOAD_RO, \"03592 JB Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"03592 JB WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"03592 JC\");\n\tadd_drive_media_list(lu, LOAD_RO, \"03592 JC Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"03592 JC WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"03592 JK\");\n\tadd_drive_media_list(lu, LOAD_RO, \"03592 JK Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"03592 JK WORM\");\n}\n"
  },
  {
    "path": "usr/pm/ibm_smc_pm.c",
    "content": "/*\n * Personality module for IBM TotalStorage(c) 3584 series of robots\n * e.g. TS3500\n */\n\n#include <stdio.h>\n#include <string.h>\n#include \"vtllib.h\"\n#include \"mhvtl_scsi.h\"\n#include \"smc.h\"\n#include \"logging.h\"\n#include \"be_byteshift.h\"\n\nstatic struct smc_personality_template smc_pm = {\n\t.library_has_map\t\t\t= TRUE,\n\t.library_has_barcode_reader = TRUE,\n\t.library_has_playground\t\t= TRUE,\n\n\t.dvcid_len = 34,\n};\n\n/*\n * Undocumented page - raw dump from a real library..\n */\nstatic void update_ibm_3100_vpd_d0(struct lu_phy_attr *lu) {\n\tstruct vpd **lu_vpd;\n\tuint8_t\t\t*d;\n\tint\t\t\t pg;\n\tuint8_t\t\t pg_d0[] = {\n\t\t 0x08, 0xd0, 0x00, 0xc0, 0x04, 0x53, 0x43, 0x44,\n\t\t 0x44, 0x00, 0x04, 0x04, 0xc0, 0x00, 0x00, 0x00,\n\t\t 0x00, 0x06, 0x04, 0x22, 0x80, 0x00, 0x00, 0x00,\n\t\t 0x08, 0x07, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00,\n\t\t 0x0a, 0x00, 0x0b, 0x08, 0x80, 0x00, 0x00, 0x00,\n\t\t 0x35, 0x73, 0x00, 0x40, 0x00, 0x0e, 0x02, 0x00,\n\t\t 0xff, 0x00, 0x0f, 0x01, 0xff, 0x00, 0x10, 0x02,\n\t\t 0x00, 0xff, 0x00, 0x11, 0x10, 0x04, 0x8e, 0x82,\n\t\t 0x72, 0x04, 0x83, 0x82, 0x75, 0x3b, 0x12, 0x82,\n\t\t 0x75, 0x04, 0x12, 0x82, 0x76, 0x00, 0x14, 0x3a,\n\t\t 0x00, 0x01, 0x03, 0x01, 0x07, 0x0b, 0x12, 0x01,\n\t\t 0x15, 0x01, 0x16, 0x01, 0x17, 0x01, 0x1a, 0x01,\n\t\t 0x1b, 0x0a, 0x1d, 0x01, 0x1e, 0x01, 0x2b, 0x0a,\n\t\t 0x37, 0x0b, 0x3b, 0x03, 0x3c, 0x01, 0x4c, 0x01,\n\t\t 0x4d, 0x01, 0x55, 0x01, 0x56, 0x01, 0x57, 0x01,\n\t\t 0x5a, 0x01, 0x5e, 0x01, 0x5f, 0x01, 0xa3, 0x01,\n\t\t 0xa4, 0x01, 0xa5, 0x19, 0xb5, 0x01, 0xb6, 0x01,\n\t\t 0xb8, 0x01, 0x00, 0x16, 0x03, 0x80, 0x24, 0x02,\n\t\t 0x00, 0x17, 0x11, 0x00, 0x00, 0x10, 0x20, 0x06,\n\t\t 0x01, 0x00, 0x10, 0x20, 0x06, 0x01, 0x01, 0x00,\n\t\t 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x01, 0x60,\n\t\t 0x00, 0x1c, 0x05, 0x00, 0x00, 0x06, 0x06, 0x02,\n\t\t 0x00, 0x24, 0x0c, 0x83, 0x00, 0x83, 0x03, 0x83,\n\t\t 0x30, 0x83, 0x11, 0x3b, 0x12, 0x83, 0x02, 0x00,\n\t\t 0x26, 0x02, 0x00, 0x05};\n\n\tlu_vpd = lu->lu_vpd;\n\n\tpg = PCODE_OFFSET(0xd0);\n\tif (lu_vpd[pg]) /* Free any earlier allocation */\n\t\tdealloc_vpd(lu_vpd[pg]);\n\tlu_vpd[pg] = alloc_vpd(0xc8);\n\tif (!lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Could not malloc(0xc8) bytes, line %d\", __LINE__);\n\t\treturn;\n\t}\n\n\td = lu_vpd[pg]->data;\n\tmemcpy(d, &pg_d0[0], sizeof(pg_d0));\n}\n\n/*\n * Undocumented page - raw dump from a real library..\n */\nstatic void update_ibm_3100_vpd_ff(struct lu_phy_attr *lu) {\n\tstruct vpd **lu_vpd;\n\tuint8_t\t\t*d;\n\tint\t\t\t pg;\n\tuint8_t\t\t pg_ff[] = {\n\t\t 0x08, 0xff, 0x00, 0x20, 0xb5, 0x8e, 0xb0, 0x0e,\n\t\t 0x1c, 0x0e, 0x98, 0x0e, 0x30, 0x0b, 0x90, 0x35,\n\t\t 0x1c, 0x0b, 0x35, 0x0b, 0x98, 0x40, 0x78, 0xc0,\n\t\t 0x07, 0x71, 0xd4, 0x0b, 0x98, 0x80, 0x78, 0x00,\n\t\t 0x28, 0x0f, 0xd0, 0x34};\n\n\tlu_vpd = lu->lu_vpd;\n\n\tpg = PCODE_OFFSET(0xff);\n\tif (lu_vpd[pg]) /* Free any earlier allocation */\n\t\tdealloc_vpd(lu_vpd[pg]);\n\tlu_vpd[pg] = alloc_vpd(0x26);\n\tif (!lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Could not malloc(0x26) bytes, line %d\", __LINE__);\n\t\treturn;\n\t}\n\n\td = lu_vpd[pg]->data;\n\tmemcpy(d, &pg_ff[0], sizeof(pg_ff));\n}\n\nstatic void update_3573_device_capabilities(struct lu_phy_attr *lu) {\n\tstruct mode *mp;\n\n\tmp = lookup_mode_pg(&lu->mode_pg, MODE_DEVICE_CAPABILITIES, 0);\n\tif (!mp) { /* Can't find page ??? */\n\t\tMHVTL_ERR(\"Can't find MODE_DEVICE_CAPABILITIES page\");\n\t\treturn;\n\t}\n\n\tmp->pcodePointer[2] = 0x0e;\n\tmp->pcodePointer[3] = 0x00;\n\n\tmp->pcodePointer[4] = 0x0e; /* Medium Transport Capabilities */\n\tmp->pcodePointer[5] = 0x0e; /* Storage Element Capabilities */\n\tmp->pcodePointer[6] = 0x0e; /* MAP Element Capabilities */\n\tmp->pcodePointer[7] = 0x0e; /* Data Trans. Element Capabilities */\n\n\tmp->pcodePointer[12] = 0x0e; /* Medium Transport Capabilities */\n\tmp->pcodePointer[13] = 0x0e; /* Storage Element Capabilities */\n\tmp->pcodePointer[14] = 0x0e; /* MAP Element Capabilities */\n\tmp->pcodePointer[15] = 0x0e; /* Data Trans. Element Capabilities */\n}\n\nstatic void update_3584_device_capabilities(struct lu_phy_attr *lu) {\n\tstruct mode *mp;\n\n\tmp = lookup_mode_pg(&lu->mode_pg, MODE_DEVICE_CAPABILITIES, 0);\n\tif (!mp) { /* Can't find page ??? */\n\t\tMHVTL_ERR(\"Can't find MODE_DEVICE_CAPABILITIES page\");\n\t\treturn;\n\t}\n\n\tmp->pcodePointer[2] = 0x0e;\n\tmp->pcodePointer[3] = 0x00;\n\n\tmp->pcodePointer[4] = 0x0e; /* Medium Transport Capabilities */\n\tmp->pcodePointer[5] = 0x0e; /* Storage Element Capabilities */\n\tmp->pcodePointer[6] = 0x0e; /* MAP Element Capabilities */\n\tmp->pcodePointer[7] = 0x0e; /* Data Trans. Element Capabilities */\n\n\tmp->pcodePointer[12] = 0x0e; /* Medium Transport Capabilities */\n\tmp->pcodePointer[13] = 0x0e; /* Storage Element Capabilities */\n\tmp->pcodePointer[14] = 0x0e; /* MAP Element Capabilities */\n\tmp->pcodePointer[15] = 0x0e; /* Data Trans. Element Capabilities */\n}\n\nstatic void update_ibm_3584_vpd_80(struct lu_phy_attr *lu) {\n\tstruct vpd\t   **lu_vpd;\n\tstruct smc_priv *smc_p;\n\tuint8_t\t\t\t*d;\n\tint\t\t\t\t pg;\n\n\tlu_vpd = lu->lu_vpd;\n\tsmc_p  = lu->lu_private;\n\n\t/* Unit Serial Number */\n\tpg = PCODE_OFFSET(0x80);\n\tif (lu_vpd[pg]) /* Free any earlier allocation */\n\t\tdealloc_vpd(lu_vpd[pg]);\n\tlu_vpd[pg] = alloc_vpd(0x16);\n\tif (!lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Could not malloc(0x16) bytes, line %d\", __LINE__);\n\t\treturn;\n\t}\n\n\td = lu_vpd[pg]->data;\n\t/* d[4 - 15] Serial number of device */\n\tsnprintf((char *)&d[0], 11, \"%-10.10s\", lu->lu_serial_no);\n\t/* First Storage Element Address */\n\tsnprintf((char *)&d[12], 5, \"%04x\", smc_p->pm->start_storage);\n}\n\nstatic void update_ibm_3584_vpd_83(struct lu_phy_attr *lu) {\n\tstruct vpd\t   **lu_vpd;\n\tstruct smc_priv *smc_p;\n\tint\t\t\t\t pg;\n\tuint8_t\t\t\t*d;\n\n\tlu_vpd = lu->lu_vpd;\n\tsmc_p  = lu->lu_private;\n\n\t/* Device Identification */\n\tpg = PCODE_OFFSET(0x83);\n\tif (lu_vpd[pg]) /* Free any earlier allocation */\n\t\tdealloc_vpd(lu_vpd[pg]);\n\tlu_vpd[pg] = alloc_vpd(0x2c);\n\tif (!lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Could not malloc(0x2c) bytes, line %d\", __LINE__);\n\t\treturn;\n\t}\n\n\td\t = lu_vpd[pg]->data;\n\td[0] = 2;\t /* Code set */\n\td[1] = 1;\t /* Identifier Type */\n\td[3] = 0x28; /* Identifier length */\n\t/* Vendor ID */\n\tmemcpy(&d[4], &lu->inquiry[8], 8);\n\t/* Device type and Model Number */\n\tmemcpy(&d[12], &lu->inquiry[16], 16);\n\t/* Serial Number of device */\n\tmemcpy(&d[28], &lu->inquiry[38], 12);\n\t/* First Storage Element Address */\n\tsnprintf((char *)&d[40], 5, \"%04x\", smc_p->pm->start_storage);\n}\n\nstatic void update_ibm_3584_inquiry(struct lu_phy_attr *lu) {\n\tlu->inquiry[2] = 3;\t   /* SNSI Approved Version */\n\tlu->inquiry[3] = 2;\t   /* Response data format */\n\tlu->inquiry[4] = 0x35; /* Additional length */\n\n\tmemcpy(&lu->inquiry[38], &lu->lu_serial_no, 12);\n\tlu->inquiry[50] = 0x30;\n\tlu->inquiry[51] = 0x30;\n}\n\nstatic void update_ibm_3100_inquiry(struct lu_phy_attr *lu) {\n\tstruct smc_priv *smc_p;\n\tsmc_p = lu->lu_private;\n\n\tlu->inquiry[2] = 5;\t   /* SNSI Approved Version */\n\tlu->inquiry[3] = 2;\t   /* Response data format */\n\tlu->inquiry[4] = 0x43; /* Additional length */\n\n\tmemcpy(&lu->inquiry[38], &lu->lu_serial_no, 12);\n\tlu->inquiry[55] |= smc_p->pm->library_has_barcode_reader ? 1 : 0;\n\tput_unaligned_be16(0x005c, &lu->inquiry[58]); /* SAM-2 */\n\tput_unaligned_be16(0x0b56, &lu->inquiry[60]); /* SPI-4 */\n\tput_unaligned_be16(0x02fe, &lu->inquiry[62]); /* SMC-2 */\n\tput_unaligned_be16(0x030f, &lu->inquiry[64]); /* SPC-3 */\n}\n\nstatic void update_ibm_3100_vpd_80(struct lu_phy_attr *lu) {\n\tstruct vpd **lu_vpd = lu->lu_vpd;\n\tuint8_t\t\t*d;\n\tint\t\t\t pg;\n\n\t/* Unit Serial Number */\n\tpg = PCODE_OFFSET(0x80);\n\tif (lu_vpd[pg]) /* Free any earlier allocation */\n\t\tdealloc_vpd(lu_vpd[pg]);\n\tlu_vpd[pg] = alloc_vpd(0x10);\n\tif (!lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Could not malloc(0x10) bytes, line %d\", __LINE__);\n\t\treturn;\n\t}\n\n\td = lu_vpd[pg]->data;\n\t/* d[4 - 15] Serial number of device */\n\tsnprintf((char *)&d[0], 13, \"%-12.12s\", lu->lu_serial_no);\n\t/* Unique Logical Library Identifier */\n\tmemcpy(&d[12], \"_LL0\", 4);\n}\n\nstatic void update_ibm_3100_vpd_83(struct lu_phy_attr *lu) {\n\tstruct vpd **lu_vpd = lu->lu_vpd;\n\tint\t\t\t pg;\n\tuint8_t\t\t*d;\n\n\t/* Device Identification */\n\tpg = PCODE_OFFSET(0x83);\n\tif (lu_vpd[pg]) /* Free any earlier allocation */\n\t\tdealloc_vpd(lu_vpd[pg]);\n\tlu_vpd[pg] = alloc_vpd(0x2c);\n\tif (!lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Could not malloc(0x2c) bytes, line %d\", __LINE__);\n\t\treturn;\n\t}\n\n\td\t = lu_vpd[pg]->data;\n\td[0] = 2;\t /* Code set */\n\td[1] = 1;\t /* Identifier Type */\n\td[3] = 0x28; /* Identifier length */\n\t/* Vendor ID */\n\tmemcpy(&d[4], &lu->inquiry[8], 8);\n\t/* Device type and Model Number */\n\tmemcpy(&d[12], &lu->inquiry[16], 16);\n\t/* Serial Number of device */\n\tmemcpy(&d[28], &lu->inquiry[38], 12);\n\t/* Unique Logical Library Identifier */\n\tmemcpy(&d[40], \"_LL0\", 4);\n}\n\nstatic void update_ibm_3100_vpd_c0(struct lu_phy_attr *lu) {\n\tstruct vpd **lu_vpd = lu->lu_vpd;\n\tint\t\t\t pg;\n\tuint8_t\t\t*d;\n\tint\t\t\t y, m, dd, hh, mm, ss;\n\n\tymd(&y, &m, &dd, &hh, &mm, &ss);\n\n\t/* Device Identification */\n\tpg = PCODE_OFFSET(0xc0);\n\tif (lu_vpd[pg]) /* Free any earlier allocation */\n\t\tdealloc_vpd(lu_vpd[pg]);\n\tlu_vpd[pg] = alloc_vpd(0x40);\n\tif (!lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Could not malloc(0x40) bytes, line %d\", __LINE__);\n\t\treturn;\n\t}\n\n\td = lu_vpd[pg]->data;\n\tsprintf((char *)&d[4], \"%s\", \"DEAD\"); /* Media f/w checksum */\n\t/* Media changer firmware build date (mm-dd-yyyy) */\n\tsnprintf((char *)&d[8], 22, \"%02d-%02d-%04d\", m, dd, y);\n}\n\n/* 3573TL */\nvoid init_ibmts3100(struct lu_phy_attr *lu) {\n\tsmc_pm.name\t\t\t\t\t\t  = \"mhVTL - IBM TS3100 series emulation\";\n\tsmc_pm.library_has_map\t\t\t  = TRUE;\n\tsmc_pm.library_has_barcode_reader = TRUE;\n\tsmc_pm.library_has_playground\t  = TRUE;\n\n\t/* Follow IBM TS3100 & TS3200 SCSI Reference Manual */\n\tsmc_pm.start_picker\t = 0x0001;\n\tsmc_pm.start_map\t = 0x0010;\n\tsmc_pm.start_drive\t = 0x0100;\n\tsmc_pm.start_storage = 0x1000;\n\n\tsmc_pm.lu = lu;\n\tsmc_personality_module_register(&smc_pm);\n\n\tinit_slot_info(lu);\n\n\t/* Update vendor specific info in main INQUIRY page */\n\tupdate_ibm_3100_inquiry(lu);\n\n\t/* Need slot info before we can fill out VPD data */\n\tupdate_ibm_3100_vpd_80(lu);\n\tupdate_ibm_3100_vpd_83(lu);\n\t/* IBM Doco hints at VPD page 0xd0 & 0xff - but does not document it */\n\t/*\n\t * lsscsi -g\n\t * [2:0:1:0]    tape    IBM      ULT3580-TD4      8192  /dev/st0  /dev/sg2\n\t * [2:0:1:1]    mediumx IBM      3573-TL          6.50  -         /dev/sg3\n\t *\n\t * # sg_inq -p 0 /dev/sg3\n\t * Only hex output supported\n\t * VPD INQUIRY, page code=0x00:\n\t *   [PQual=0  Peripheral device type: medium changer]\n\t *    Supported VPD pages:\n\t *        0x0        Supported VPD pages\n\t *        0x80       Unit serial number\n\t *        0x83       Device identification\n\t *        0xc0       vendor: Firmware numbers (seagate); Unit path report (EMC)\n\t *        0xd0\n\t *        0xff\n\n\t * # sg_inq -H -p 0xc0 /dev/sg3\n\t * VPD INQUIRY, page code=0xc0:\n\t *  00     08 c0 00 3c 00 00 00 00  34 38 34 37 30 34 2d 30    ...<....484704-0\n\t *  10     33 2d 32 30 30 38 20 20  20 20 20 20 20 20 20 20    3-2008\n\t *  20     20 20 20 20 00 00 00 00  00 00 00 00 00 00 00 00        ............\n\t *  30     00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00    ................\n\t */\n\tupdate_ibm_3100_vpd_c0(lu);\n\n\t/*\n\t * # sg_inq -p 0xd0 /dev/sg3\n\t * VPD INQUIRY, page code=0xd0:\n\t *  00     08 d0 00 c0 04 53 43 44  44 00 04 04 c0 00 00 00    .....SCDD.......\n\t *  10     00 06 04 22 80 00 00 00  08 07 80 00 00 05 00 00    ...\"............\n\t *  20     0a 00 0b 08 80 00 00 00  35 73 00 40 00 0e 02 00    ........5s.@....\n\t *  30     ff 00 0f 01 ff 00 10 02  00 ff 00 11 10 04 8e 82    ................\n\t *  40     72 04 83 82 75 3b 12 82  75 04 12 82 76 00 14 3a    r...u;..u...v..:\n\t *  50     00 01 03 01 07 0b 12 01  15 01 16 01 17 01 1a 01    ................\n\t *  60     1b 0a 1d 01 1e 01 2b 0a  37 0b 3b 03 3c 01 4c 01    ......+.7.;.<.L.\n\t *  70     4d 01 55 01 56 01 57 01  5a 01 5e 01 5f 01 a3 01    M.U.V.W.Z.^._...\n\t *  80     a4 01 a5 19 b5 01 b6 01  b8 01 00 16 03 80 24 02    ..............$.\n\t *  90     00 17 11 00 00 10 20 06  01 00 10 20 06 01 01 00    ...... .... ....\n\t *  a0     00 00 00 00 00 1b 01 60  00 1c 05 00 00 06 06 02    .......`........\n\t *  b0     00 24 0c 83 00 83 03 83  30 83 11 3b 12 83 02 00    .$......0..;....\n\t *  c0     26 02 00 05                                         &...\n\t */\n\tupdate_ibm_3100_vpd_d0(lu);\n\n\t/*\n\t * # sg_inq -p 0xff /dev/sg3\n\t * VPD INQUIRY, page code=0xff:\n\t *  00     08 ff 00 20 b5 8e b0 0e  1c 0e 98 0e 30 0b 90 35    ... ........0..5\n\t *  10     1c 0b 35 0b 98 40 78 c0  07 71 d4 0b 98 80 78 00    ..5..@x..q....x.\n\t *  20     28 0f d0 34                                         (..4\n\t *\n\t */\n\tupdate_ibm_3100_vpd_ff(lu);\n\n\tinit_smc_log_pages(lu);\n\tinit_smc_mode_pages(lu);\n\tupdate_3573_device_capabilities(lu);\n}\n\n/*\n * This should be fun to keep in sync..\n *\n * 03584L22 => 03592 drives\n * 03584L32 => LTO drives\n * 03584L42 => DLT drives\n */\nvoid init_ibm3584(struct lu_phy_attr *lu) {\n\tsmc_pm.name\t\t\t\t\t\t  = \"mhVTL - IBM 03584 series emulation\";\n\tsmc_pm.library_has_map\t\t\t  = TRUE;\n\tsmc_pm.library_has_barcode_reader = TRUE;\n\tsmc_pm.library_has_playground\t  = TRUE;\n\n\t/* Follow IBM 3584 SCSI Reference Manual */\n\tsmc_pm.start_picker\t = 0x0001;\n\tsmc_pm.start_drive\t = 0x0101;\n\tsmc_pm.start_map\t = 0x0300;\n\tsmc_pm.start_storage = 0x0400;\n\n\tsmc_pm.lu = lu;\n\tsmc_personality_module_register(&smc_pm);\n\n\t/* Initialise order 'Picker, Drives, MAP, Storage */\n\tinit_slot_info(lu);\n\n\t/* Update vendor specific info in main INQUIRY page */\n\tupdate_ibm_3584_inquiry(lu);\n\n\t/* Need slot info before we can fill out VPD data */\n\tupdate_ibm_3584_vpd_80(lu);\n\tupdate_ibm_3584_vpd_83(lu);\n\t/* IBM Doco hints at VPD page 0xd0 - but does not document it */\n\n\t/* At least log what we should contain\n\t * Need to identify a sanity check on incorrect\n\t * drive config later\n\t *\n\t * Forth edition of the IBM System Storage TS3500 Tape Library SCSI\n\t * Reference (August 2011)\n\t *\n\t */\n\tif (!strncasecmp(lu->product_id, \"03584L22\", 8) || !strncasecmp(lu->product_id, \"03584L23\", 8) || !strncasecmp(lu->product_id, \"03584D22\", 8) || !strncasecmp(lu->product_id, \"03584D23\", 8)) {\n\t\tMHVTL_LOG(\"%s library should contain 03592 drives\",\n\t\t\t\t  lu->product_id);\n\t} else if (!strncasecmp(lu->product_id, \"03584L32\", 8) || !strncasecmp(lu->product_id, \"03584D32\", 8) || !strncasecmp(lu->product_id, \"03584L52\", 8) || !strncasecmp(lu->product_id, \"03584D52\", 8) || !strncasecmp(lu->product_id, \"03584L53\", 8) || !strncasecmp(lu->product_id, \"03584D53\", 8)) {\n\t\tMHVTL_LOG(\"%s library should contain LTO drives\",\n\t\t\t\t  lu->product_id);\n\t} else if (!strncasecmp(lu->product_id, \"03584L42\", 8) || !strncasecmp(lu->product_id, \"03584L42\", 8)) {\n\t\tMHVTL_LOG(\"%s library should contain DLT drives\",\n\t\t\t\t  lu->product_id);\n\t} else {\n\t\tMHVTL_ERR(\"%s library model not known\",\n\t\t\t\t  lu->product_id);\n\t}\n\n\tinit_smc_log_pages(lu);\n\tinit_smc_mode_pages(lu);\n\tupdate_3584_device_capabilities(lu);\n}\n"
  },
  {
    "path": "usr/pm/overland_pm.c",
    "content": "/*\n * Personality module for OVERLAND\n */\n\n#include <stdio.h>\n#include <string.h>\n#include \"vtllib.h\"\n#include \"smc.h\"\n#include \"logging.h\"\n\nstatic void update_eml_vpd_80(struct lu_phy_attr *lu) {\n\tstruct vpd **lu_vpd = lu->lu_vpd;\n\tuint8_t\t\t*d;\n\tint\t\t\t pg;\n\n\t/* Unit Serial Number */\n\tpg = PCODE_OFFSET(0x80);\n\tif (lu_vpd[pg]) /* Free any earlier allocation */\n\t\tdealloc_vpd(lu_vpd[pg]);\n\tlu_vpd[pg] = alloc_vpd(0x12);\n\tif (lu_vpd[pg]) {\n\t\td = lu_vpd[pg]->data;\n\t\t/* d[4 - 15] Serial number of device */\n\t\tsnprintf((char *)&d[0], 11, \"%-10.10s\", lu->lu_serial_no);\n\t\t/* Unique Logical Library Identifier */\n\t} else {\n\t\tMHVTL_ERR(\"Could not malloc(0x12) bytes, line %d\", __LINE__);\n\t}\n}\n\nstatic void update_eml_vpd_83(struct lu_phy_attr *lu) {\n\tstruct vpd *vpd_pg = lu->lu_vpd[PCODE_OFFSET(0x83)];\n\tuint8_t\t   *d;\n\tint\t\t\tnum;\n\tchar\t   *ptr;\n\tint\t\t\tlen, j;\n\n\td = vpd_pg->data;\n\n\td[0] = 2;\n\td[1] = 1;\n\td[2] = 0;\n\tnum\t = VENDOR_ID_LEN + PRODUCT_ID_LEN + 10;\n\td[3] = num;\n\n\tmemcpy(&d[4], &lu->vendor_id, VENDOR_ID_LEN);\n\tmemcpy(&d[12], &lu->product_id, PRODUCT_ID_LEN);\n\tmemcpy(&d[28], &lu->lu_serial_no, 10);\n\tlen = (int)strlen(lu->lu_serial_no);\n\tptr = &lu->lu_serial_no[len];\n\n\tnum += 4;\n\t/* NAA IEEE registered identifier (faked) */\n\td[num]\t\t= 0x1; /* Binary */\n\td[num + 1]\t= 0x3;\n\td[num + 2]\t= 0x0;\n\td[num + 3]\t= 0x8;\n\td[num + 4]\t= 0x51;\n\td[num + 5]\t= 0x23;\n\td[num + 6]\t= 0x45;\n\td[num + 7]\t= 0x60;\n\td[num + 8]\t= 0x3;\n\td[num + 9]\t= 0x3;\n\td[num + 10] = 0x3;\n\td[num + 11] = 0x3;\n\n\tif (lu->naa) { /* If defined in config file */\n\t\tsscanf((const char *)lu->naa,\n\t\t\t   \"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx\",\n\t\t\t   &d[num + 4],\n\t\t\t   &d[num + 5],\n\t\t\t   &d[num + 6],\n\t\t\t   &d[num + 7],\n\t\t\t   &d[num + 8],\n\t\t\t   &d[num + 9],\n\t\t\t   &d[num + 10],\n\t\t\t   &d[num + 11]);\n\t} else { /* Else munge the serial number */\n\t\tptr--;\n\t\tfor (j = 11; j > 3; ptr--, j--)\n\t\t\td[num + j] = *ptr;\n\t}\n\td[num + 4] &= 0x0f;\n\td[num + 4] |= 0x50;\n}\n\nstatic struct smc_personality_template smc_pm = {\n\t.library_has_map\t\t\t= TRUE,\n\t.library_has_barcode_reader = TRUE,\n\t.library_has_playground\t\t= FALSE,\n\t.start_map\t\t\t\t\t= 0x0000,\n\t.start_picker\t\t\t\t= 0x0001,\n\t.start_storage\t\t\t\t= 0x0002,\n\t.start_drive\t\t\t\t= 0x00ff,\n\n\t.dvcid_len = 34,\n};\n\nvoid init_overland_smc(struct lu_phy_attr *lu) {\n\tsmc_pm.name = \"mhVTL - Overland Series emulation\";\n\n\tsmc_pm.lu = lu;\n\tsmc_personality_module_register(&smc_pm);\n\n\tinit_slot_info(lu);\n\n\tupdate_eml_vpd_80(lu);\n\tupdate_eml_vpd_83(lu);\n\tinit_smc_log_pages(lu);\n\tinit_smc_mode_pages(lu);\n}\n"
  },
  {
    "path": "usr/pm/quantum_dlt_pm.c",
    "content": "/*\n * This handles any SCSI OP codes defined in the standards as 'STREAM'\n *\n * Copyright (C) 2005 - 2025 Mark Harvey markh794@gmail.com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n * See comments in vtltape.c for a more complete version release...\n *\n */\n\n#include <unistd.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <errno.h>\n#include <string.h>\n#include <inttypes.h>\n#include \"mhvtl_scsi.h\"\n#include \"vtl_common.h\"\n#include \"vtllib.h\"\n#include \"vtlcart.h\"\n#include \"logging.h\"\n#include \"ssc.h\"\n#include \"spc.h\"\n#include \"mode.h\"\n#include \"mhvtl_log.h\"\n\n/* FIXME: This data needs to be updated to suit SDLT range of media */\nstatic struct density_info density_dlt2 = {\n\t1000, 640, 64, 1000, medium_density_code_dlt2,\n\t\"DLT-CVE\", \"DLT II\", \"DLTtape II\"};\nstatic struct density_info density_dlt3 = {\n\t62500, 640, 64, 20000, medium_density_code_dlt3,\n\t\"DLT-CVE\", \"DLT III\", \"DLTtape III\"};\nstatic struct density_info density_dlt4 = {\n\t85937, 640, 52, 35000, medium_density_code_dlt4,\n\t\"DLT-CVE\", \"DLT IV\", \"DLTtape IV\"};\nstatic struct density_info density_sdlt = {\n\t15142, 640, 1502, 80000, medium_density_code_sdlt,\n\t\"DLT-CVE\", \"U-216\", \"SDLT\"};\nstatic struct density_info density_sdlt220 = {\n\t15142, 640, 1502, 80000, medium_density_code_220,\n\t\"DLT-CVE\", \"U-316\", \"SDLT 220\"};\nstatic struct density_info density_sdlt320 = {\n\t15142, 640, 1502, 80000, medium_density_code_320,\n\t\"DLT-CVE\", \"U-416\", \"SDLT 320\"};\nstatic struct density_info density_sdlt600 = {\n\t15142, 640, 1502, 80000, medium_density_code_600,\n\t\"DLT-CVE\", \"U-516\", \"SDLT 600\"};\n\nstatic struct name_to_media_info media_info[] = {\n\t{\"DLT2\", Media_DLT2,\n\t media_type_unknown, medium_density_code_dlt2},\n\t{\"DLT3\", Media_DLT3,\n\t media_type_unknown, medium_density_code_dlt3},\n\t{\"DLT4\", Media_DLT4,\n\t media_type_unknown, medium_density_code_dlt4},\n\t{\"SDLT\", Media_SDLT,\n\t media_type_unknown, medium_density_code_sdlt},\n\t{\"SDLT 220\", Media_SDLT220,\n\t media_type_unknown, medium_density_code_220},\n\t{\"SDLT 320\", Media_SDLT320,\n\t media_type_unknown, medium_density_code_320},\n\t{\"SDLT 320 Clean\", Media_SDLT320_CLEAN,\n\t media_type_unknown, medium_density_code_320},\n\t{\"SDLT 600\", Media_SDLT600,\n\t media_type_unknown, medium_density_code_600},\n\t{\"SDLT 600 Clean\", Media_SDLT600_CLEAN,\n\t media_type_unknown, medium_density_code_600},\n\t{\"SDLT 600 WORM\", Media_SDLT600_WORM,\n\t media_type_unknown, medium_density_code_600},\n\t{\"\", 0, 0, 0},\n};\n\nstatic uint8_t clear_dlt_compression(struct list_head *m) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", m);\n\t/* default clear_compression is in libvtlscsi */\n\treturn clear_compression_mode_pg(m);\n}\n\nstatic uint8_t set_dlt_compression(struct list_head *m, int lvl) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", m);\n\t/* default set_compression is in libvtlscsi */\n\treturn set_compression_mode_pg(m, lvl);\n}\n\n/* As per IBM LTO5 SCSI Programmers Guide..\n * Filling in compile time/date & dummy 'platform' string\n */\nstatic void update_vpd_dlt_c0(struct lu_phy_attr *lu) {\n\tuint8_t\t   *data;\n\tstruct vpd *vpd_p;\n\tint\t\t\th, m, s;\n\tint\t\t\tday, month, year;\n\n\tvpd_p = lu->lu_vpd[PCODE_OFFSET(0xc0)];\n\tdata  = vpd_p->data;\n\tmonth = 0;\n\n\tymd(&year, &month, &day, &h, &m, &s);\n\n\tdata[1] = 0xc0;\n\tdata[3] = 0x28;\n\n\t/* Controller firmware build date */\n\tsprintf((char *)&data[20], \"%02d-%02d-%04d %02d:%02d:%02d\",\n\t\t\tday, month, year, h, m, s);\n}\n\nstatic int get_product_family(struct lu_phy_attr *lu) {\n\tint ret;\n\tif (!strncmp(lu->product_id, \"SDLT600\", 7))\n\t\tret = 0xc0; /* Product Family - (300/600 GB)  */\n\telse if (!strncmp(lu->product_id, \"SDLT 320\", 8))\n\t\tret = 0xb0; /* Product Family - (160/320 GB)  */\n\telse\n\t\tret = 0xa0; /* Product Family - (110/220 GB)  */\n\n\treturn ret;\n}\n\nstatic void update_vpd_dlt_c1(struct lu_phy_attr *lu, char *sn) {\n\tuint8_t\t   *data;\n\tstruct vpd *vpd_p;\n\n\tvpd_p = lu->lu_vpd[PCODE_OFFSET(0xc1)];\n\tdata  = vpd_p->data;\n\n\tdata[1] = 0xc1;\n\tdata[3] = 0x39;\n\tdata[4] = get_product_family(lu);\n\tsnprintf((char *)&data[4], 13, \"%-12s\", sn);\n\tsnprintf((char *)&data[24], 13, \"%-12s\", sn);\n}\n\nstatic uint8_t set_dlt_WORM(struct list_head *lst) {\n\tuint8_t\t\t*mp;\n\tstruct mode *m;\n\n\tset_WORM(lst); /* Default WORM setup */\n\n\t/* Now for the Ultrium unique stuff */\n\n\tm = lookup_mode_pg(lst, MODE_BEHAVIOR_CONFIGURATION, 0);\n\tif (m) {\n\t\tMHVTL_DBG(3, \"l: %p, m: %p, m->pcodePointer: %p\",\n\t\t\t\t  lst, m, m->pcodePointer);\n\t\tmp = m->pcodePointer;\n\t\tif (!mp)\n\t\t\treturn SAM_STAT_GOOD;\n\n\t\tmp[4] = 0x01; /* WORM Behavior */\n\t} else {\n\t\tMHVTL_DBG(2, \"MODE BEHAVIOUR CONFIGURATION page not found\");\n\t}\n\n\treturn SAM_STAT_GOOD;\n}\n\nstatic uint8_t clear_dlt_WORM(struct list_head *m) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", m);\n\treturn clear_WORM(m);\n}\n\n/* DLT7000 & DLT8000 */\nstatic void init_dlt_inquiry(struct lu_phy_attr *lu) {\n\tint\t pg;\n\tchar b[32];\n\tint\t x, y, z;\n\n\tlu->inquiry[2] =\n\t\t((struct priv_lu_ssc *)lu->lu_private)->pm->drive_ANSI_VERSION;\n\n\tlu->inquiry[36] = get_product_family(lu);\n\n\tsprintf(b, \"%s\", MHVTL_VERSION);\n\tsscanf(b, \"%d.%d.%d\", &x, &y, &z);\n\tif (x) {\n\t\tlu->inquiry[37] = x;\n\t\tlu->inquiry[38] = y;\n\t} else {\n\t\tlu->inquiry[37] = y;\n\t\tlu->inquiry[38] = z;\n\t}\n\n\t/* VPD page 0xC0 */\n\tpg\t\t\t   = PCODE_OFFSET(0xc0);\n\tlu->lu_vpd[pg] = alloc_vpd(44);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_dlt_c0(lu);\n\n\t/* VPD page 0xC1 */\n\tpg\t\t\t   = PCODE_OFFSET(0xc1);\n\tlu->lu_vpd[pg] = alloc_vpd(44);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_dlt_c1(lu, lu->lu_serial_no);\n}\n\n/* SuperDLT range */\nstatic void init_sdlt_inquiry(struct lu_phy_attr *lu) {\n\tint\t\tpg;\n\tuint8_t worm;\n\tuint8_t ta[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\n\tchar\tb[32];\n\tint\t\tx, y, z;\n\n\tworm = ((struct priv_lu_ssc *)lu->lu_private)->pm->drive_supports_WORM;\n\tlu->inquiry[2] =\n\t\t((struct priv_lu_ssc *)lu->lu_private)->pm->drive_ANSI_VERSION;\n\n\tlu->inquiry[36] = get_product_family(lu);\n\n\tsprintf(b, \"%s\", MHVTL_VERSION);\n\tsscanf(b, \"%d.%d.%d\", &x, &y, &z);\n\tif (x) {\n\t\tlu->inquiry[37] = x;\n\t\tlu->inquiry[38] = y;\n\t} else {\n\t\tlu->inquiry[37] = y;\n\t\tlu->inquiry[38] = z;\n\t}\n\n\t/* Sequential Access device capabilities - Ref: 8.4.2 */\n\tpg\t\t\t   = PCODE_OFFSET(0xb0);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_B0_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_b0(lu, &worm);\n\n\t/* Manufacture-assigned serial number - Ref: 8.4.3 */\n\tpg\t\t\t   = PCODE_OFFSET(0xb1);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_B1_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_b1(lu, lu->lu_serial_no);\n\n\t/* TapeAlert supported flags - Ref: 8.4.4 */\n\tpg\t\t\t   = PCODE_OFFSET(0xb2);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_B2_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_b2(lu, &ta);\n\n\t/* VPD page 0xC0 */\n\tpg\t\t\t   = PCODE_OFFSET(0xc0);\n\tlu->lu_vpd[pg] = alloc_vpd(44);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_dlt_c0(lu);\n\n\t/* VPD page 0xC1 */\n\tpg\t\t\t   = PCODE_OFFSET(0xc1);\n\tlu->lu_vpd[pg] = alloc_vpd(44);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_dlt_c1(lu, lu->lu_serial_no);\n}\n\n/* Some comments before I forget how this is supose to work..\n - cleaning_media_state is either\n   0 - Not mounted\n   1 - Cleaning media mounted -> return Cleaning cartridge installed\n   2 - Cleaning media mounted -> return Cause not reportable\n   3 - Cleaning media mounted -> return Initializing command required\n\n On cleaning media mount, dlt_cleaning() is called which:\n   Sets a pointer from priv_lu_ssc -> cleaning_media_state.\n   Sets cleaning_media_state to 1.\n   Sets a 30 second timer to call inc_cleaning_state()\n\n inc_cleaning_state()\n   Increments cleaning_media_state.\n   If cleaning media_state == 2, set another timer for 90 seconds to again\n   call inc_cleaning_state.\n\n If the application issues a TUR, ssc_tur() will return one of the\n above status codes depending on the current value of cleaning_media_state.\n\n When the cleaning media is unmounted, the pointer in priv_lu_ssc to this\n var will be re-set to NULL so the ssc_tur() will return defautl value.\n\n */\nstatic volatile sig_atomic_t cleaning_media_state;\n\nstatic void inc_cleaning_state(int sig);\n\nstatic void set_cleaning_timer(int t) {\n\tMHVTL_DBG(3, \"+++ Trace +++ Setting alarm for %d\", t);\n\tsignal(SIGALRM, inc_cleaning_state);\n\talarm(t);\n}\n\nstatic void inc_cleaning_state(int sig) {\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\tsignal(sig, inc_cleaning_state);\n\n\tcleaning_media_state++;\n\n\tif (cleaning_media_state == CLEAN_MOUNT_STAGE2)\n\t\tset_cleaning_timer(90);\n}\n\nstatic uint8_t dlt_media_load(struct lu_phy_attr *lu, int load) {\n\tMHVTL_DBG(3, \"+++ Trace +++ %s\", (load) ? \"load\" : \"unload\");\n\treturn 0;\n}\n\nstatic uint8_t dlt_cleaning(void *ssc_priv) {\n\tstruct priv_lu_ssc *ssc;\n\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\n\tssc = ssc_priv;\n\n\tssc->cleaning_media_state = &cleaning_media_state;\n\tcleaning_media_state\t  = CLEAN_MOUNT_STAGE1;\n\n\tset_cleaning_timer(30);\n\n\treturn 0;\n}\n\nstatic char *pm_name_dlt7000 = \"DLT7000\";\nstatic char *pm_name_dlt8000 = \"DLT8000\";\nstatic char *pm_name_sdlt320 = \"SDLT320\";\nstatic char *pm_name_sdlt600 = \"SDLT600\";\n\nstatic struct ssc_personality_template ssc_pm = {\n\t.valid_encryption_blk = valid_encryption_blk,\n\t.check_restrictions\t  = check_restrictions, /* default in ssc.c */\n\t.clear_compression\t  = clear_dlt_compression,\n\t.set_compression\t  = set_dlt_compression,\n\t.media_load\t\t\t  = dlt_media_load,\n\t.cleaning_media\t\t  = dlt_cleaning,\n\t.media_handling\t\t  = media_info,\n};\n\nvoid init_dlt7000_ssc(struct lu_phy_attr *lu) {\n\tssc_pm.name = pm_name_dlt7000;\n\tssc_pm.lu\t= lu;\n\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = FALSE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = FALSE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = FALSE;\n\tssc_pm.drive_supports_SP\t\t\t\t = FALSE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 2;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_dlt_inquiry(lu);\n\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_control(lu);\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_medium_partition(lu);\n\tadd_mode_information_exception(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\tssc_pm.native_drive_density = &density_dlt4;\n\n\t/* Capacity units in MBytes */\n\t((struct priv_lu_ssc *)lu->lu_private)->capacity_unit = 1L << 20;\n\n\tadd_density_support(&lu->den_list, &density_dlt2, 0);\n\tadd_density_support(&lu->den_list, &density_dlt3, 1);\n\tadd_density_support(&lu->den_list, &density_dlt4, 1);\n\n\tadd_drive_media_list(lu, LOAD_RO, \"DLT3\");\n\tadd_drive_media_list(lu, LOAD_RW, \"DLT4\");\n\tadd_drive_media_list(lu, LOAD_RO, \"DLT4 Clean\");\n}\n\nvoid init_dlt8000_ssc(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_dlt8000;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.native_drive_density\t\t\t\t = &density_dlt4;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = FALSE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = FALSE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = FALSE;\n\tssc_pm.drive_supports_SP\t\t\t\t = FALSE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 2;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_dlt_inquiry(lu);\n\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_control(lu);\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_medium_partition(lu);\n\tadd_mode_information_exception(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\t/* Capacity units in MBytes */\n\t((struct priv_lu_ssc *)lu->lu_private)->capacity_unit = 1L << 20;\n\n\t/* Don't support PERSISTENT RESERVATION */\n\tregister_ops(lu, PERSISTENT_RESERVE_IN, spc_illegal_op, NULL, NULL);\n\tregister_ops(lu, PERSISTENT_RESERVE_OUT, spc_illegal_op, NULL, NULL);\n\n\tadd_density_support(&lu->den_list, &density_dlt2, 0);\n\tadd_density_support(&lu->den_list, &density_dlt3, 1);\n\tadd_density_support(&lu->den_list, &density_dlt4, 1);\n\tadd_drive_media_list(lu, LOAD_RO, \"DLT3\");\n\tadd_drive_media_list(lu, LOAD_RW, \"DLT4\");\n\tadd_drive_media_list(lu, LOAD_RO, \"DLT4 Clean\");\n}\n\nvoid init_sdlt320_ssc(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_sdlt320;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.native_drive_density\t\t\t\t = &density_sdlt320;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = FALSE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = FALSE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_sdlt_inquiry(lu);\n\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_control(lu);\n\tadd_mode_control_extension(lu);\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_device_configuration_extension(lu);\n\tadd_mode_medium_partition(lu);\n\tadd_mode_power_condition(lu);\n\tadd_mode_information_exception(lu);\n\tadd_mode_medium_configuration(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\t/* Capacity units in MBytes */\n\t((struct priv_lu_ssc *)lu->lu_private)->capacity_unit = 1L << 20;\n\n\tadd_density_support(&lu->den_list, &density_sdlt, 0);\n\tadd_density_support(&lu->den_list, &density_sdlt220, 1);\n\tadd_density_support(&lu->den_list, &density_sdlt320, 1);\n\tadd_drive_media_list(lu, LOAD_RO, \"SDLT\");\n\tadd_drive_media_list(lu, LOAD_RW, \"SDLT 220\");\n\tadd_drive_media_list(lu, LOAD_RW, \"SDLT 320\");\n\tadd_drive_media_list(lu, LOAD_RO, \"SDLT 320 Clean\");\n}\n\nvoid init_sdlt600_ssc(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_sdlt600;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.native_drive_density\t\t\t\t = &density_sdlt600;\n\tssc_pm.clear_WORM\t\t\t\t\t\t = clear_dlt_WORM;\n\tssc_pm.set_WORM\t\t\t\t\t\t\t = set_dlt_WORM;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = FALSE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_sdlt_inquiry(lu);\n\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_control(lu);\n\tadd_mode_control_extension(lu);\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_device_configuration_extension(lu);\n\tadd_mode_medium_partition(lu);\n\tadd_mode_power_condition(lu);\n\tadd_mode_information_exception(lu);\n\tadd_mode_medium_configuration(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\t/* Capacity units in MBytes */\n\t((struct priv_lu_ssc *)lu->lu_private)->capacity_unit = 1L << 20;\n\n\tadd_density_support(&lu->den_list, &density_sdlt220, 0);\n\tadd_density_support(&lu->den_list, &density_sdlt320, 1);\n\tadd_density_support(&lu->den_list, &density_sdlt600, 1);\n\tadd_drive_media_list(lu, LOAD_RO, \"SDLT 220\");\n\tadd_drive_media_list(lu, LOAD_RW, \"SDLT 320\");\n\tadd_drive_media_list(lu, LOAD_RO, \"SDLT 320 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"SDLT 600\");\n\tadd_drive_media_list(lu, LOAD_RO, \"SDLT 600 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"SDLT 600 WORM\");\n}\n"
  },
  {
    "path": "usr/pm/scalar_pm.c",
    "content": "/*\n * Personality module for Scalar series of robots\n */\n\n#include <stdio.h>\n#include \"vtllib.h\"\n#include \"smc.h\"\n#include \"logging.h\"\n#include \"be_byteshift.h\"\n\nstatic struct smc_personality_template smc_pm = {\n\t.library_has_map\t\t\t= TRUE,\n\t.library_has_barcode_reader = TRUE,\n\t.library_has_playground\t\t= FALSE,\n\n\t.dvcid_len = 34,\n};\n\nstatic void init_scalar_inquiry(struct lu_phy_attr *lu) {\n\tstruct smc_priv *smc_p;\n\tsmc_p = lu->lu_private;\n\n\tlu->inquiry[2] = 3;\t   /* SNSI Approved Version */\n\tlu->inquiry[3] = 2;\t   /* Response data format */\n\tlu->inquiry[4] = 0x1f; /* Additional length */\n\n\tlu->inquiry[6] |= smc_p->pm->library_has_barcode_reader ? 0x20 : 0;\n\tlu->inquiry[55] |= smc_p->pm->library_has_barcode_reader ? 1 : 0;\n\n\tput_unaligned_be16(0x005c, &lu->inquiry[58]); /* SAM-2 */\n\tput_unaligned_be16(0x008d, &lu->inquiry[60]); /* SAM-4 */\n\tput_unaligned_be16(0x0120, &lu->inquiry[62]); /* SPC-3 */\n\tput_unaligned_be16(0x02fe, &lu->inquiry[64]); /* SMC-2 */\n}\n\nstatic void update_scalar_vpd_80(struct lu_phy_attr *lu) {\n\tstruct vpd *lu_vpd;\n\tuint8_t\t   *d;\n\n\tlu_vpd = lu->lu_vpd[PCODE_OFFSET(0x80)];\n\n\t/* Unit Serial Number */\n\tif (lu_vpd) /* Free any earlier allocation */\n\t\tdealloc_vpd(lu_vpd);\n\n\tlu_vpd = alloc_vpd(24);\n\tif (lu_vpd) {\n\t\td = lu_vpd->data;\n\t\t/* d[4 - 27] Serial number prefixed by Vendor ID */\n\t\tsnprintf((char *)&d[0], 26, \"%-s%-17s\", lu->vendor_id, lu->lu_serial_no);\n\t} else {\n\t\tMHVTL_ERR(\"Could not malloc(24) bytes, line %d\", __LINE__);\n\t}\n}\n\nstatic void update_scalar_vpd_83(struct lu_phy_attr *lu) {\n\tstruct vpd *lu_vpd;\n\tuint8_t\t   *d;\n\n\tlu_vpd = lu->lu_vpd[PCODE_OFFSET(0x83)];\n\n\t/* Unit Serial Number */\n\tif (lu_vpd) /* Free any earlier allocation */\n\t\tdealloc_vpd(lu_vpd);\n\n\tlu_vpd = alloc_vpd(36);\n\tif (lu_vpd) {\n\t\td\t = lu_vpd->data;\n\t\td[0] = 0xf2;\n\t\td[1] = 0x01;\n\t\td[3] = 0x20;\n\t\tsnprintf((char *)&d[4], 9, \"%-8s\", lu->vendor_id);\n\t\tsnprintf((char *)&d[12], 25, \"%-24s\", lu->lu_serial_no);\n\n\t} else {\n\t\tMHVTL_ERR(\"Could not malloc(36) bytes, line %d\", __LINE__);\n\t}\n}\n\nvoid init_scalar_smc(struct lu_phy_attr *lu) {\n\tint h, m, sec;\n\tint day, month, year;\n\n\tsmc_pm.name\t\t\t\t\t\t  = \"mhVTL - Scalar emulation\";\n\tsmc_pm.library_has_map\t\t\t  = TRUE;\n\tsmc_pm.library_has_barcode_reader = TRUE;\n\tsmc_pm.library_has_playground\t  = FALSE;\n\tsmc_pm.dvcid_serial_only\t\t  = FALSE;\n\n\tsmc_pm.start_picker\t = 0x0001;\n\tsmc_pm.start_map\t = 0x0010;\n\tsmc_pm.start_drive\t = 0x0100;\n\tsmc_pm.start_storage = 0x1000;\n\n\tsmc_pm.lu = lu;\n\tsmc_personality_module_register(&smc_pm);\n\n\tinit_slot_info(lu);\n\n\t/* Reference Quantum 6-00423013 SCSI Reference - Rev A */\n\tymd(&year, &month, &day, &h, &m, &sec);\n\n\t/* Controller firmware build date */\n\tsprintf((char *)&lu->inquiry[36], \"%04d-%02d-%02d %02d:%02d:%02d\",\n\t\t\tyear, month, day, h, m, sec);\n\n\tinit_scalar_inquiry(lu);\n\tupdate_scalar_vpd_80(lu);\n\tupdate_scalar_vpd_83(lu);\n\n\tinit_smc_log_pages(lu);\n\tinit_smc_mode_pages(lu);\n}\n"
  },
  {
    "path": "usr/pm/spectra_pm.c",
    "content": "/*\n * Personality module for Spectra Logic\n */\n\n#include \"vtllib.h\"\n#include \"smc.h\"\n#include \"logging.h\"\n#include \"mhvtl_scsi.h\"\n\nstatic void update_spectra_215_device_capabilities(struct lu_phy_attr *lu) {\n\tstruct mode *mp;\n\n\tmp = lookup_mode_pg(&lu->mode_pg, MODE_DEVICE_CAPABILITIES, 0);\n\tif (!mp) { /* Can't find page ??? */\n\t\tMHVTL_ERR(\"Can't find MODE_DEVICE_CAPABILITIES page\");\n\t\treturn;\n\t}\n\n\tmp->pcodePointer[2] = 0x0b;\n\tmp->pcodePointer[3] = 0x00;\n\tmp->pcodePointer[4] = 0x0a;\n\tmp->pcodePointer[5] = 0x0b;\n\tmp->pcodePointer[6] = 0x00;\n\tmp->pcodePointer[7] = 0x0b;\n}\n\nstatic void update_spectra_gator_device_capabilities(struct lu_phy_attr *lu) {\n\tstruct mode *mp;\n\n\tmp = lookup_mode_pg(&lu->mode_pg, MODE_DEVICE_CAPABILITIES, 0);\n\tif (!mp) { /* Can't find page ??? */\n\t\tMHVTL_ERR(\"Can't find MODE_DEVICE_CAPABILITIES page\");\n\t\treturn;\n\t}\n\n\tmp->pcodePointer[2] = 0x0e;\n\tmp->pcodePointer[3] = 0x00;\n\tmp->pcodePointer[4] = 0x0e;\n\tmp->pcodePointer[5] = 0x0e;\n\tmp->pcodePointer[6] = 0x0e;\n\tmp->pcodePointer[7] = 0x0e;\n}\n\nstatic void update_spectra_t_series_device_capabilities(struct lu_phy_attr *lu) {\n\tstruct mode *mp;\n\n\tmp = lookup_mode_pg(&lu->mode_pg, MODE_DEVICE_CAPABILITIES, 0);\n\tif (!mp) { /* Can't find page ??? */\n\t\tMHVTL_ERR(\"Can't find MODE_DEVICE_CAPABILITIES page\");\n\t\treturn;\n\t}\n\n\tmp->pcodePointer[2] = 0x0e;\n\tmp->pcodePointer[3] = 0x00;\n\tmp->pcodePointer[4] = 0x0e;\n\tmp->pcodePointer[5] = 0x0e;\n\tmp->pcodePointer[6] = 0x0e;\n\tmp->pcodePointer[7] = 0x0e;\n}\n\nstatic struct smc_personality_template smc_pm = {\n\t.library_has_map\t\t\t= TRUE,\n\t.library_has_barcode_reader = TRUE,\n\t.library_has_playground\t\t= FALSE,\n\n\t/* Rev G of SpectraLogic Tseries states this is now 1Eh\n\t * Yet...\n\t * DVCID=1 'Identifier Length (1Eh) but goes on to describe\n\t * fields 52 through 83 are for the Device Identifier -> and that\n\t * adds up to 32 by my calculations. And in table 10-5 specifies\n\t * Identifier Length as 1Gh... (hmmm forgot to carry the one in\n\t * base 16 addition when they got to 1Fh) - which is of course\n\t * 20h (32 decimal).\n\t */\n\t.dvcid_len = 0x20,\n};\n\nvoid init_spectra_215_smc(struct lu_phy_attr *lu) {\n\tsmc_pm.name\t\t\t\t\t\t  = \"mhVTL - Spectra Treefrog emulation\";\n\tsmc_pm.library_has_map\t\t\t  = FALSE;\n\tsmc_pm.library_has_barcode_reader = TRUE;\n\tsmc_pm.dvcid_serial_only\t\t  = TRUE;\n\tsmc_pm.no_dvcid_flag\t\t\t  = TRUE;\n\tsmc_pm.dvcid_len\t\t\t\t  = 0;\n\n\t/* Extracted from Spectra Treefrog-Series SCSI Developers guide */\n\tsmc_pm.start_picker\t = 86;\n\tsmc_pm.start_map\t = 99; /* fake */\n\tsmc_pm.start_drive\t = 31;\n\tsmc_pm.start_storage = 1;\n\n\tsmc_pm.lu = lu;\n\tsmc_personality_module_register(&smc_pm);\n\n\tinit_slot_info(lu);\n\n\tinit_smc_log_pages(lu);\n\tinit_smc_mode_pages(lu);\n\t/* Now that 'init_smc_mode_pages()' has allocated device capabilities\n\t * page, update to valid default values for Spectra-Logic treefrog\n\t */\n\tupdate_spectra_215_device_capabilities(lu);\n}\n\nvoid init_spectra_gator_smc(struct lu_phy_attr *lu) {\n\tsmc_pm.name\t\t\t\t\t\t  = \"mhVTL - Spectra Gator emulation\";\n\tsmc_pm.library_has_map\t\t\t  = TRUE;\n\tsmc_pm.library_has_barcode_reader = TRUE;\n\tsmc_pm.dvcid_serial_only\t\t  = TRUE;\n\tsmc_pm.dvcid_len\t\t\t\t  = 10;\n\n\t/* Extracted from Spectra Gator SCSI Developers guide */\n\tsmc_pm.start_picker\t = 0x02c3;\n\tsmc_pm.start_map\t = 0x0001;\n\tsmc_pm.start_drive\t = 0x02a3;\n\tsmc_pm.start_storage = 0x001e;\n\n\tsmc_pm.lu = lu;\n\tsmc_personality_module_register(&smc_pm);\n\n\tinit_slot_info(lu);\n\n\tinit_smc_log_pages(lu);\n\tinit_smc_mode_pages(lu);\n\t/* Now that 'init_smc_mode_pages()' has allocated device capabilities\n\t * page, update to valid default values for Spectra-Logic Gator Series\n\t */\n\tupdate_spectra_gator_device_capabilities(lu);\n}\n\nvoid init_spectra_logic_smc(struct lu_phy_attr *lu) {\n\tsmc_pm.name\t\t\t\t\t\t  = \"mhVTL - Spectra T-Series emulation\";\n\tsmc_pm.library_has_map\t\t\t  = TRUE;\n\tsmc_pm.library_has_barcode_reader = TRUE;\n\tsmc_pm.dvcid_serial_only\t\t  = TRUE;\n\n\t/* Extracted from Spectra T-Series SCSI Developers guide */\n\tsmc_pm.start_picker\t = 0x0001;\n\tsmc_pm.start_map\t = 0x0010;\n\tsmc_pm.start_drive\t = 0x0100;\n\tsmc_pm.start_storage = 0x1000;\n\n\tsmc_pm.lu = lu;\n\tsmc_personality_module_register(&smc_pm);\n\n\tinit_slot_info(lu);\n\n\tinit_smc_log_pages(lu);\n\tinit_smc_mode_pages(lu);\n\t/* Now that 'init_smc_mode_pages()' has allocated device capabilities\n\t * page, update to valid default values for Spectra-Logic T Series\n\t */\n\tupdate_spectra_t_series_device_capabilities(lu);\n}\n"
  },
  {
    "path": "usr/pm/stk9x40_pm.c",
    "content": "/*\n * This handles any SCSI OP codes defined in the standards as 'STREAM'\n *\n * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n * See comments in vtltape.c for a more complete version release...\n *\n */\n\n#include <unistd.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <errno.h>\n#include <inttypes.h>\n#include <signal.h>\n#include \"be_byteshift.h\"\n#include \"mhvtl_scsi.h\"\n#include \"vtl_common.h\"\n#include \"vtllib.h\"\n#include \"logging.h\"\n#include \"ssc.h\"\n#include \"vtlcart.h\"\n#include \"mode.h\"\n#include \"mhvtl_log.h\"\n\nstatic struct density_info density_9840A = {\n\t0, 127, 288, 0x4e20, medium_density_code_9840A,\n\t\"STK\", \"R-20\", \"Raven 20 GB\"};\n\nstatic struct density_info density_9840B = {\n\t0, 127, 288, 0x4e20, medium_density_code_9840B,\n\t\"STK\", \"R-20\", \"Raven 20 GB\"};\n\nstatic struct density_info density_9840C = {\n\t0, 127, 288, 0x9c40, medium_density_code_9840C,\n\t\"STK\", \"R-40\", \"Raven 40 GB\"};\n\nstatic struct density_info density_9840D = {\n\t0, 127, 576, 0x124f8, medium_density_code_9840D,\n\t\"STK\", \"R-75\", \"Raven 75 GB\"};\n\nstatic struct density_info density_9940A = {\n\t0, 127, 288, 0xea60, medium_density_code_9940A,\n\t\"STK\", \"P-60\", \"PeakCapacity 60 GB\"};\n\nstatic struct density_info density_9940B = {\n\t0, 127, 576, 0x30d40, medium_density_code_9940B,\n\t\"STK\", \"P-200\", \"PeakCapacity 200 GB\"};\n\nstatic struct name_to_media_info media_info[] = {\n\t{\"9840A\", Media_9840A,\n\t media_type_unknown, medium_density_code_9840A},\n\t{\"9840A Clean\", Media_9840A_CLEAN,\n\t media_type_unknown, medium_density_code_9840A},\n\t{\"9840B\", Media_9840B,\n\t media_type_unknown, medium_density_code_9840B},\n\t{\"9840B Clean\", Media_9840B_CLEAN,\n\t media_type_unknown, medium_density_code_9840B},\n\t{\"9840C\", Media_9840C,\n\t media_type_unknown, medium_density_code_9840C},\n\t{\"9840C Clean\", Media_9840C_CLEAN,\n\t media_type_unknown, medium_density_code_9840C},\n\t{\"9840D\", Media_9840D,\n\t media_type_unknown, medium_density_code_9840D},\n\t{\"9840D Clean\", Media_9840D_CLEAN,\n\t media_type_unknown, medium_density_code_9840D},\n\n\t{\"9940A\", Media_9940A,\n\t media_type_unknown, medium_density_code_9940A},\n\t{\"9940A Clean\", Media_9940A_CLEAN,\n\t media_type_unknown, medium_density_code_9940A},\n\t{\"9940B\", Media_9940B,\n\t media_type_unknown, medium_density_code_9940B},\n\t{\"9940B Clean\", Media_9940B_CLEAN,\n\t media_type_unknown, medium_density_code_9940B},\n\t{\"\", 0, 0, 0},\n};\n\n/*\n * Returns true if blk header has correct encryption key data\n */\n#define UKAD_LENGTH (encr->ukad_length)\n#define AKAD_LENGTH (encr->akad_length)\n#define KEY_LENGTH\t(encr->key_length)\n#define UKAD\t\t(encr->ukad)\n#define AKAD\t\t(encr->akad)\n#define KEY\t\t\t(encr->key)\nuint8_t valid_encryption_blk_9840(struct scsi_cmd *cmd) {\n\tuint8_t\t\t\t\tcorrect_key;\n\tint\t\t\t\t\ti;\n\tstruct lu_phy_attr *lu = cmd->lu;\n\tstruct priv_lu_ssc *lu_priv;\n\tstruct encryption  *encr;\n\tuint8_t\t\t\t   *sam_stat = &cmd->dbuf_p->sam_stat;\n\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\n\tlu_priv = lu->lu_private;\n\tencr\t= lu_priv->app_encr_info;\n\n\t/* decryption logic */\n\tcorrect_key = TRUE;\n\tif (c_pos->blk_flags & BLKHDR_FLG_ENCRYPTED) {\n\t\t/* compare the keys  - STK requires UKAD back to decrypt */\n\t\tif (lu_priv->DECRYPT_MODE > 1) {\n\t\t\tif (c_pos->blk_encryption_info.key_length != KEY_LENGTH) {\n\t\t\t\tsam_data_protect(E_INCORRECT_KEY, sam_stat);\n\t\t\t\tcorrect_key = FALSE;\n\t\t\t\treturn correct_key;\n\t\t\t}\n\t\t\tfor (i = 0; i < c_pos->blk_encryption_info.key_length; ++i) {\n\t\t\t\tif (c_pos->blk_encryption_info.key[i] != KEY[i]) {\n\t\t\t\t\tsam_data_protect(E_INCORRECT_KEY,\n\t\t\t\t\t\t\t\t\t sam_stat);\n\t\t\t\t\tcorrect_key = FALSE;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (c_pos->blk_encryption_info.ukad_length != UKAD_LENGTH) {\n\t\t\t\tsam_data_protect(E_INCORRECT_KEY, sam_stat);\n\t\t\t\tcorrect_key = FALSE;\n\t\t\t\treturn correct_key;\n\t\t\t}\n\t\t\tfor (i = 0; i < c_pos->blk_encryption_info.ukad_length; ++i) {\n\t\t\t\tif (c_pos->blk_encryption_info.ukad[i] != UKAD[i]) {\n\t\t\t\t\tsam_data_protect(E_INCORRECT_KEY,\n\t\t\t\t\t\t\t\t\t sam_stat);\n\t\t\t\t\tcorrect_key = FALSE;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tsam_data_protect(E_UNABLE_TO_DECRYPT, sam_stat);\n\t\t\tcorrect_key = FALSE;\n\t\t}\n\t} else if (lu_priv->DECRYPT_MODE == 2) {\n\t\tsam_data_protect(E_UNENCRYPTED_DATA, sam_stat);\n\t\tcorrect_key = FALSE;\n\t}\n\treturn correct_key;\n}\n\nstatic uint8_t clear_9840_comp(struct list_head *m) {\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\t/* default clear_compression is in libvtlscsi */\n\treturn clear_compression_mode_pg(m);\n}\n\nstatic uint8_t set_9840_comp(struct list_head *m, int lvl) {\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\t/* default set_compression is in libvtlscsi */\n\treturn set_compression_mode_pg(m, lvl);\n}\n\nstatic uint8_t update_9840_encryption_mode(struct list_head *m, void *p, int value) {\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\n\treturn SAM_STAT_GOOD;\n}\n\nstatic uint8_t set_9840_WORM(struct list_head *m) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", m);\n\treturn set_WORM(m);\n}\n\nstatic uint8_t clear_9840_WORM(struct list_head *m) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", m);\n\treturn clear_WORM(m);\n}\n\nstatic int encr_capabilities_9840(struct scsi_cmd *cmd) {\n\tuint8_t *buf = cmd->dbuf_p->data;\n\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\n\tput_unaligned_be16(ENCR_CAPABILITIES, &buf[0]);\n\tput_unaligned_be16(40, &buf[2]); /* List length */\n\n\tbuf[20] = 1;\t\t\t\t\t\t/* Algorithm index */\n\tbuf[21] = 0;\t\t\t\t\t\t/* Reserved */\n\tput_unaligned_be16(0x14, &buf[22]); /* Descriptor length */\n\tbuf[24] = 0x3a;\t\t\t\t\t\t/* MAC C/DED_C DECRYPT_C = 2 ENCRYPT_C = 2 */\n\tbuf[25] = 0x10;\t\t\t\t\t\t/* NONCE_C = 1 */\n\t/* Max unauthenticated key data */\n\tput_unaligned_be16(0x20, &buf[26]);\n\t/* Max authenticated  key data */\n\tput_unaligned_be16(0x0c, &buf[28]);\n\t/* Key size */\n\tput_unaligned_be16(0x20, &buf[30]);\n\tbuf[32] = 0x01; /* EAREM */\n\t/* buf 12 - 19 reserved */\n\n\tbuf[40] = 0;\t/* Encryption Algorithm Id */\n\tbuf[41] = 0x01; /* Encryption Algorithm Id */\n\tbuf[42] = 0;\t/* Encryption Algorithm Id */\n\tbuf[43] = 0x14; /* Encryption Algorithm Id */\n\n\tbuf[4] = 0x1; /* CFG_P == 01b */\n\tif (get_tape_load_status() == TAPE_LOADED) {\n\t\tbuf[24] |= 0x80; /* AVFMV */\n\t\tbuf[27] = 0x1e;\t /* Max unauthenticated key data */\n\t\tbuf[29] = 0x00;\t /* Max authenticated key data */\n\t\tbuf[32] |= 0x42; /* DKAD_C == 1, RDMC_C == 1 */\n\t\tbuf[40] = 0x80;\t /* Encryption Algorithm Id */\n\t\tbuf[43] = 0x10;\t /* Encryption Algorithm Id */\n\t}\n\n\treturn 44;\n}\n\nstatic int T9840_kad_validation(int encrypt_mode, int ukad, int akad) {\n\tif (ukad > 30 || akad > 0)\n\t\treturn TRUE;\n\treturn FALSE;\n}\n\n/* Some comments before I forget how this is supose to work..\n - cleaning_media_state is either\n   0 - Not mounted\n   1 - Cleaning media mounted -> return Cleaning cartridge installed\n   2 - Cleaning media mounted -> return Cause not reportable\n   3 - Cleaning media mounted -> return Initializing command required\n\n On cleaning media mount, 9840_cleaning() is called which:\n   Sets a pointer from priv_lu_ssc -> cleaning_media_state.\n   Sets cleaning_media_state to 1.\n   Sets a 30 second timer to call inc_cleaning_state()\n\n inc_cleaning_state()\n   Increments cleaning_media_state.\n   If cleaning media_state == 2, set another timer for 90 seconds to again\n   call inc_cleaning_state.\n\n If the application issues a TUR, ssc_tur() will return one of the\n above status codes depending on the current value of cleaning_media_state.\n\n When the cleaning media is unmounted, the pointer in priv_lu_ssc to this\n var will be re-set to NULL so the ssc_tur() will return defautl value.\n\n */\nstatic volatile sig_atomic_t cleaning_media_state;\n\nstatic void inc_cleaning_state(int sig);\n\nstatic void set_cleaning_timer(int t) {\n\tMHVTL_DBG(3, \"+++ Trace +++ Setting alarm for %d\", t);\n\tsignal(SIGALRM, inc_cleaning_state);\n\talarm(t);\n}\n\nstatic void inc_cleaning_state(int sig) {\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\tsignal(sig, inc_cleaning_state);\n\n\tcleaning_media_state++;\n\n\tif (cleaning_media_state == CLEAN_MOUNT_STAGE2)\n\t\tset_cleaning_timer(90);\n}\n\nstatic uint8_t T9840_media_load(struct lu_phy_attr *lu, int load) {\n\tMHVTL_DBG(3, \"+++ Trace +++ %s\", (load) ? \"load\" : \"unload\");\n\treturn 0;\n}\n\nstatic uint8_t T9840_cleaning(void *ssc_priv) {\n\tstruct priv_lu_ssc *ssc;\n\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\n\tssc = ssc_priv;\n\n\tssc->cleaning_media_state = &cleaning_media_state;\n\tcleaning_media_state\t  = CLEAN_MOUNT_STAGE1;\n\n\tset_cleaning_timer(30);\n\n\treturn 0;\n}\n\nstatic void init_9840_mode_pages(struct lu_phy_attr *lu) {\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_information_exception(lu);\n}\n\nstatic char *pm_name_9840A = \"T9840A\";\nstatic char *pm_name_9840B = \"T9840B\";\nstatic char *pm_name_9840C = \"T9840C\";\nstatic char *pm_name_9840D = \"T9840D\";\nstatic char *pm_name_9940A = \"T9940A\";\nstatic char *pm_name_9940B = \"T9940B\";\n\nstatic struct ssc_personality_template ssc_pm = {\n\t.valid_encryption_blk\t = valid_encryption_blk_9840,\n\t.update_encryption_mode\t = update_9840_encryption_mode,\n\t.encryption_capabilities = encr_capabilities_9840,\n\t.kad_validation\t\t\t = T9840_kad_validation,\n\t.check_restrictions\t\t = check_restrictions,\n\t.clear_compression\t\t = clear_9840_comp,\n\t.set_compression\t\t = set_9840_comp,\n\t.clear_WORM\t\t\t\t = clear_9840_WORM,\n\t.set_WORM\t\t\t\t = set_9840_WORM,\n\t.media_load\t\t\t\t = T9840_media_load,\n\t.cleaning_media\t\t\t = T9840_cleaning,\n\t.media_handling\t\t\t = media_info,\n};\n\n#define INQUIRY_LEN 74\nstatic void init_9840_inquiry(struct lu_phy_attr *lu) {\n\tint\t\tpg;\n\tuint8_t worm;\n\n\tworm = ((struct priv_lu_ssc *)lu->lu_private)->pm->drive_supports_WORM;\n\tlu->inquiry[2] =\n\t\t((struct priv_lu_ssc *)lu->lu_private)->pm->drive_ANSI_VERSION;\n\n\tlu->inquiry[3]\t= 0x42;\n\tlu->inquiry[4]\t= INQUIRY_LEN - 5; /* Additional Length */\n\tlu->inquiry[54] = 0x04;\t\t\t   /* Key Management */\n\tlu->inquiry[55] = 0x12;\t\t\t   /* Support Encryption & Compression */\n\n\t/* Sequential Access device capabilities - Ref: 8.4.2 */\n\tpg\t\t\t   = PCODE_OFFSET(0xb0);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_B0_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_b0(lu, &worm);\n}\n\nvoid init_9840A_ssc(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_9840A;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = FALSE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = TRUE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\tssc_pm.native_drive_density\t\t\t\t = &density_9840A;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_9840_inquiry(lu);\n\n\tinit_9840_mode_pages(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\tregister_ops(lu, LOAD_DISPLAY, ssc_load_display, NULL, NULL);\n\n\tadd_density_support(&lu->den_list, &density_9840A, 1);\n\n\tadd_drive_media_list(lu, LOAD_RW, \"9840A\");\n\tadd_drive_media_list(lu, LOAD_RO, \"9840A Clean\");\n}\n\nvoid init_9840B_ssc(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_9840B;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = FALSE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = TRUE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\tssc_pm.native_drive_density\t\t\t\t = &density_9840B;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_9840_inquiry(lu);\n\n\tinit_9840_mode_pages(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\tregister_ops(lu, LOAD_DISPLAY, ssc_load_display, NULL, NULL);\n\n\tadd_density_support(&lu->den_list, &density_9840A, 1);\n\tadd_density_support(&lu->den_list, &density_9840B, 1);\n\n\tadd_drive_media_list(lu, LOAD_RW, \"9840A\");\n\tadd_drive_media_list(lu, LOAD_RO, \"9840A Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"9840B\");\n\tadd_drive_media_list(lu, LOAD_RO, \"9840B Clean\");\n}\n\nvoid init_9840C_ssc(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_9840C;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = FALSE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = TRUE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_9840_inquiry(lu);\n\n\tinit_9840_mode_pages(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\tssc_pm.native_drive_density = &density_9840C;\n\n\tregister_ops(lu, LOAD_DISPLAY, ssc_load_display, NULL, NULL);\n\n\tadd_density_support(&lu->den_list, &density_9840A, 0);\n\tadd_density_support(&lu->den_list, &density_9840B, 1);\n\tadd_density_support(&lu->den_list, &density_9840C, 1);\n\n\tadd_drive_media_list(lu, LOAD_RO, \"9840A\");\n\tadd_drive_media_list(lu, LOAD_RO, \"9840A Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"9840B\");\n\tadd_drive_media_list(lu, LOAD_RO, \"9840B Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"9840C\");\n\tadd_drive_media_list(lu, LOAD_RO, \"9840C Clean\");\n}\n\nvoid init_9840D_ssc(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t= pm_name_9840D;\n\tssc_pm.lu\t\t\t\t\t= lu;\n\tssc_pm.drive_supports_WORM\t= FALSE;\n\tssc_pm.drive_ANSI_VERSION\t= 5;\n\tssc_pm.drive_supports_SPR\t= TRUE;\n\tssc_pm.drive_supports_SP\t= TRUE;\n\tssc_pm.native_drive_density = &density_9840D;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_9840_inquiry(lu);\n\n\tinit_9840_mode_pages(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\tregister_ops(lu, LOAD_DISPLAY, ssc_load_display, NULL, NULL);\n\n\tadd_density_support(&lu->den_list, &density_9840A, 0);\n\tadd_density_support(&lu->den_list, &density_9840B, 0);\n\tadd_density_support(&lu->den_list, &density_9840C, 1);\n\tadd_density_support(&lu->den_list, &density_9840D, 1);\n\n\tadd_drive_media_list(lu, LOAD_RO, \"9840B\");\n\tadd_drive_media_list(lu, LOAD_RO, \"9840B Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"9840C\");\n\tadd_drive_media_list(lu, LOAD_RO, \"9840C Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"9840D\");\n\tadd_drive_media_list(lu, LOAD_RO, \"9840D Clean\");\n}\n\nvoid init_9940A_ssc(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t= pm_name_9940A;\n\tssc_pm.lu\t\t\t\t\t= lu;\n\tssc_pm.drive_supports_WORM\t= FALSE;\n\tssc_pm.drive_supports_SPR\t= TRUE;\n\tssc_pm.drive_supports_SP\t= TRUE;\n\tssc_pm.drive_ANSI_VERSION\t= 5;\n\tssc_pm.native_drive_density = &density_9940A;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_9840_inquiry(lu);\n\n\tinit_9840_mode_pages(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\tregister_ops(lu, LOAD_DISPLAY, ssc_load_display, NULL, NULL);\n\n\tadd_density_support(&lu->den_list, &density_9940A, 1);\n\n\tadd_drive_media_list(lu, LOAD_RW, \"9840A\");\n\tadd_drive_media_list(lu, LOAD_RO, \"9840A Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"9840A\");\n\tadd_drive_media_list(lu, LOAD_RO, \"9840A Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"9840A\");\n\tadd_drive_media_list(lu, LOAD_RO, \"9840A Clean\");\n}\n\nvoid init_9940B_ssc(struct lu_phy_attr *lu) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", &lu->mode_pg);\n\n\tssc_pm.name\t\t\t\t\t= pm_name_9940B;\n\tssc_pm.lu\t\t\t\t\t= lu;\n\tssc_pm.native_drive_density = &density_9940B;\n\tssc_pm.drive_supports_WORM\t= FALSE;\n\tssc_pm.drive_supports_SPR\t= TRUE;\n\tssc_pm.drive_supports_SP\t= TRUE;\n\tssc_pm.drive_ANSI_VERSION\t= 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_9840_inquiry(lu);\n\n\tinit_9840_mode_pages(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\n\tregister_ops(lu, LOAD_DISPLAY, ssc_load_display, NULL, NULL);\n\n\tadd_density_support(&lu->den_list, &density_9940A, 1);\n\tadd_density_support(&lu->den_list, &density_9940B, 1);\n\n\tadd_drive_media_list(lu, LOAD_RW, \"9940A\");\n\tadd_drive_media_list(lu, LOAD_RO, \"9940A Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"9940B\");\n\tadd_drive_media_list(lu, LOAD_RO, \"9940B Clean\");\n}\n"
  },
  {
    "path": "usr/pm/stklxx_pm.c",
    "content": "/*\n * Personality module for STK L series of robots\n * e.g. L180, L700, L20/40/80\n */\n\n#include <stdio.h>\n#include \"vtllib.h\"\n#include \"smc.h\"\n#include \"logging.h\"\n#include \"mode.h\"\n\nstatic struct smc_personality_template smc_pm = {\n\t.library_has_map\t\t\t= TRUE,\n\t.library_has_barcode_reader = TRUE,\n\t.library_has_playground\t\t= TRUE,\n\n\t.dvcid_len = 34,\n};\n\nstatic void update_stk_l_vpd_80(struct lu_phy_attr *lu) {\n\tstruct vpd **lu_vpd;\n\tuint8_t\t\t*d;\n\n\tlu_vpd = &lu->lu_vpd[PCODE_OFFSET(0x80)];\n\n\t/* Unit Serial Number */\n\tif (*lu_vpd) { /* Free any earlier allocation */\n\t\tdealloc_vpd(*lu_vpd);\n\t\t*lu_vpd = NULL;\n\t}\n\n\t*lu_vpd = alloc_vpd(0x12);\n\tif (*lu_vpd) {\n\t\td = (*lu_vpd)->data;\n\t\t/* d[4 - 15] Serial number of device */\n\t\tsnprintf((char *)&d[0], 13, \"%-12.12s\", lu->lu_serial_no);\n\t\t/* Unique Logical Library Identifier */\n\t} else {\n\t\tMHVTL_ERR(\"Could not malloc(0x12) bytes, line %d\", __LINE__);\n\t}\n}\n\nstatic void update_stk_l_vpd_83(struct lu_phy_attr *lu) {\n\tstruct vpd *lu_vpd;\n\n\tlu_vpd = lu->lu_vpd[PCODE_OFFSET(0x83)];\n\n\t/* STK L series do not have this VPD page - remove */\n\tif (lu_vpd) { /* Free any earlier allocation */\n\t\tdealloc_vpd(lu_vpd);\n\t\tlu->lu_vpd[PCODE_OFFSET(0x83)] = NULL;\n\t}\n}\n\nvoid init_stkl20(struct lu_phy_attr *lu) {\n\tsmc_pm.name\t\t\t\t\t\t  = \"mhVTL - STK L20/40/80 series emulation\";\n\tsmc_pm.library_has_map\t\t\t  = TRUE;\n\tsmc_pm.library_has_barcode_reader = TRUE;\n\tsmc_pm.library_has_playground\t  = TRUE;\n\n\t/* Follow L20 SCSI Reference Manual  */\n\tsmc_pm.start_picker\t = 0x0001;\n\tsmc_pm.start_map\t = 0x000a; /*   10d -   55d */\n\tsmc_pm.start_drive\t = 0x01f4; /*  500d -  519d */\n\tsmc_pm.start_storage = 0x03e8; /* 1000d - 1677d */\n\n\tsmc_pm.lu = lu;\n\tsmc_personality_module_register(&smc_pm);\n\n\tinit_slot_info(lu);\n\n\tupdate_stk_l_vpd_80(lu);\n\tupdate_stk_l_vpd_83(lu);\n\tinit_smc_log_pages(lu);\n\tinit_smc_mode_pages(lu);\n\t/* FIXME: Need to add page 0x2d - Drive Configuration Page */\n\tadd_smc_mode_page_drive_configuration(lu);\n}\n\nvoid init_stklxx(struct lu_phy_attr *lu) {\n\tsmc_pm.name\t\t\t\t\t\t  = \"mhVTL - STK L series emulation\";\n\tsmc_pm.library_has_map\t\t\t  = TRUE;\n\tsmc_pm.library_has_barcode_reader = TRUE;\n\tsmc_pm.library_has_playground\t  = TRUE;\n\n\t/* Follow L700e/L180 SCSI Reference Manual - 8th Edition */\n\tsmc_pm.start_picker\t = 0x0001;\n\tsmc_pm.start_map\t = 0x000a; /*   10d -   55d */\n\tsmc_pm.start_drive\t = 0x01f4; /*  500d -  519d */\n\tsmc_pm.start_storage = 0x03e8; /* 1000d - 1677d */\n\n\tsmc_pm.lu = lu;\n\tsmc_personality_module_register(&smc_pm);\n\n\tinit_slot_info(lu);\n\n\tupdate_stk_l_vpd_80(lu);\n\tupdate_stk_l_vpd_83(lu);\n\tinit_smc_log_pages(lu);\n\tinit_smc_mode_pages(lu);\n}\n\nvoid init_stkslxx(struct lu_phy_attr *lu) {\n\tsmc_pm.name\t\t\t\t\t\t  = \"mhVTL - STK SL series emulation\";\n\tsmc_pm.library_has_map\t\t\t  = TRUE;\n\tsmc_pm.library_has_barcode_reader = TRUE;\n\tsmc_pm.library_has_playground\t  = TRUE;\n\n\t/* Follow Streamline SL500 Interface Reference Manual - 2th Edition */\n\tsmc_pm.start_picker\t = 0x0001;\n\tsmc_pm.start_map\t = 0x000a; /*   10d -   55d */\n\tsmc_pm.start_drive\t = 0x01f4; /*  500d -  518d */\n\tsmc_pm.start_storage = 0x03e8; /* 1000d - 1628d */\n\n\tsmc_pm.lu = lu;\n\tsmc_personality_module_register(&smc_pm);\n\n\tinit_slot_info(lu);\n\n\tupdate_stk_l_vpd_80(lu);\n\tupdate_stk_l_vpd_83(lu);\n\tinit_smc_log_pages(lu);\n\tinit_smc_mode_pages(lu);\n}\n"
  },
  {
    "path": "usr/pm/t10000_pm.c",
    "content": "/*\n * This handles any SCSI OP codes defined in the standards as 'STREAM'\n *\n * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n * See comments in vtltape.c for a more complete version release...\n *\n */\n\n#include <unistd.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <errno.h>\n#include <inttypes.h>\n#include <signal.h>\n#include \"be_byteshift.h\"\n#include \"mhvtl_scsi.h\"\n#include \"vtl_common.h\"\n#include \"vtllib.h\"\n#include \"logging.h\"\n#include \"ssc.h\"\n#include \"spc.h\"\n#include \"vtlcart.h\"\n#include \"mode.h\"\n#include \"mhvtl_log.h\"\n\nstatic struct density_info density_t10kA = {\n\t0, 127, 0x300, 0x7a120, medium_density_code_10kA,\n\t\"STK\", \"T1 - 500\", \"T1 - 500 GB\"};\n\nstatic struct density_info density_t10kB = {\n\t0, 127, 0x480, 0x1d4c0, medium_density_code_10kB,\n\t\"STK\", \"T1 - 1000\", \"T1 - 1000 GB\"};\n\nstatic struct density_info density_t10kC = {\n\t0, 127, 0x600, 0x30000, medium_density_code_10kC,\n\t\"STK\", \"T2 - 5000\", \"T1 - 5000 GB\"};\n\nstatic struct name_to_media_info media_info[] = {\n\t{\"T10KA\", Media_T10KA,\n\t media_type_unknown, medium_density_code_10kA},\n\t{\"T10KA WORM\", Media_T10KA_WORM,\n\t media_type_unknown, medium_density_code_10kA},\n\t{\"T10KA Clean\", Media_T10KA_CLEAN,\n\t media_type_unknown, medium_density_code_10kA},\n\t{\"T10KB\", Media_T10KB,\n\t media_type_unknown, medium_density_code_10kB},\n\t{\"T10KB WORM\", Media_T10KB_WORM,\n\t media_type_unknown, medium_density_code_10kB},\n\t{\"T10KB Clean\", Media_T10KB_CLEAN,\n\t media_type_unknown, medium_density_code_10kB},\n\t{\"T10KC\", Media_T10KC,\n\t media_type_unknown, medium_density_code_10kC},\n\t{\"T10KC WORM\", Media_T10KC_WORM,\n\t media_type_unknown, medium_density_code_10kC},\n\t{\"T10KC Clean\", Media_T10KC_CLEAN,\n\t media_type_unknown, medium_density_code_10kC},\n\t{\"\", 0, 0, 0},\n};\n\n/*\n * Returns true if blk header has correct encryption key data\n */\n#define UKAD_LENGTH (encr->ukad_length)\n#define AKAD_LENGTH (encr->akad_length)\n#define KEY_LENGTH\t(encr->key_length)\n#define UKAD\t\t(encr->ukad)\n#define AKAD\t\t(encr->akad)\n#define KEY\t\t\t(encr->key)\nuint8_t valid_encryption_blk_t10k(struct scsi_cmd *cmd) {\n\tuint8_t\t\t\t\tcorrect_key;\n\tint\t\t\t\t\ti;\n\tstruct lu_phy_attr *lu = cmd->lu;\n\tstruct priv_lu_ssc *lu_priv;\n\tstruct encryption  *encr;\n\tuint8_t\t\t\t   *sam_stat = &cmd->dbuf_p->sam_stat;\n\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\n\tlu_priv = lu->lu_private;\n\tencr\t= lu_priv->app_encr_info;\n\n\t/* decryption logic */\n\tcorrect_key = TRUE;\n\tif (c_pos->blk_flags & BLKHDR_FLG_ENCRYPTED) {\n\t\t/* compare the keys  - STK requires UKAD back to decrypt */\n\t\tif (lu_priv->DECRYPT_MODE > 1) {\n\t\t\tif (c_pos->blk_encryption_info.key_length != KEY_LENGTH) {\n\t\t\t\tsam_data_protect(E_INCORRECT_KEY, sam_stat);\n\t\t\t\tcorrect_key = FALSE;\n\t\t\t\treturn correct_key;\n\t\t\t}\n\t\t\tfor (i = 0; i < c_pos->blk_encryption_info.key_length; ++i) {\n\t\t\t\tif (c_pos->blk_encryption_info.key[i] != KEY[i]) {\n\t\t\t\t\tsam_data_protect(E_INCORRECT_KEY,\n\t\t\t\t\t\t\t\t\t sam_stat);\n\t\t\t\t\tcorrect_key = FALSE;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (c_pos->blk_encryption_info.ukad_length != UKAD_LENGTH) {\n\t\t\t\tsam_data_protect(E_INCORRECT_KEY, sam_stat);\n\t\t\t\tcorrect_key = FALSE;\n\t\t\t\treturn correct_key;\n\t\t\t}\n\t\t\tfor (i = 0; i < c_pos->blk_encryption_info.ukad_length; ++i) {\n\t\t\t\tif (c_pos->blk_encryption_info.ukad[i] != UKAD[i]) {\n\t\t\t\t\tsam_data_protect(E_INCORRECT_KEY,\n\t\t\t\t\t\t\t\t\t sam_stat);\n\t\t\t\t\tcorrect_key = FALSE;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tsam_data_protect(E_UNABLE_TO_DECRYPT, sam_stat);\n\t\t\tcorrect_key = FALSE;\n\t\t}\n\t} else if (lu_priv->DECRYPT_MODE == 2) {\n\t\tsam_data_protect(E_UNENCRYPTED_DATA, sam_stat);\n\t\tcorrect_key = FALSE;\n\t}\n\treturn correct_key;\n}\n\nstatic uint8_t clear_t10k_comp(struct list_head *m) {\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\t/* default clear_compression is in libvtlscsi */\n\treturn clear_compression_mode_pg(m);\n}\n\nstatic uint8_t set_t10k_comp(struct list_head *m, int lvl) {\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\t/* default set_compression is in libvtlscsi */\n\treturn set_compression_mode_pg(m, lvl);\n}\n\nstatic uint8_t update_t10k_encryption_mode(struct list_head *m, void *p, int value) {\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\n\treturn SAM_STAT_GOOD;\n}\n\nstatic uint8_t set_t10k_WORM(struct list_head *m) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", m);\n\treturn set_WORM(m);\n}\n\nstatic uint8_t clear_t10k_WORM(struct list_head *m) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", m);\n\treturn clear_WORM(m);\n}\n\nstatic int encr_capabilities_t10k(struct scsi_cmd *cmd) {\n\tuint8_t *buf = cmd->dbuf_p->data;\n\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\n\tput_unaligned_be16(ENCR_CAPABILITIES, &buf[0]);\n\tput_unaligned_be16(40, &buf[2]); /* List length */\n\n\tbuf[20] = 1;\t\t\t\t\t\t/* Algorithm index */\n\tbuf[21] = 0;\t\t\t\t\t\t/* Reserved */\n\tput_unaligned_be16(0x14, &buf[22]); /* Descriptor length */\n\tbuf[24] = 0x3a;\t\t\t\t\t\t/* MAC C/DED_C DECRYPT_C = 2 ENCRYPT_C = 2 */\n\tbuf[25] = 0x10;\t\t\t\t\t\t/* NONCE_C = 1 */\n\t/* Max unauthenticated key data */\n\tput_unaligned_be16(0x20, &buf[26]);\n\t/* Max authenticated  key data */\n\tput_unaligned_be16(0x0c, &buf[28]);\n\t/* Key size */\n\tput_unaligned_be16(0x20, &buf[30]);\n\tbuf[32] = 0x01; /* EAREM */\n\t/* buf 12 - 19 reserved */\n\n\tbuf[40] = 0;\t/* Encryption Algorithm Id */\n\tbuf[41] = 0x01; /* Encryption Algorithm Id */\n\tbuf[42] = 0;\t/* Encryption Algorithm Id */\n\tbuf[43] = 0x14; /* Encryption Algorithm Id */\n\n\tbuf[4] = 0x1; /* CFG_P == 01b */\n\tif (get_tape_load_status() == TAPE_LOADED) {\n\t\tbuf[24] |= 0x80; /* AVFMV */\n\t\tbuf[27] = 0x1e;\t /* Max unauthenticated key data */\n\t\tbuf[29] = 0x00;\t /* Max authenticated key data */\n\t\tbuf[32] |= 0x42; /* DKAD_C == 1, RDMC_C == 1 */\n\t\tbuf[40] = 0x80;\t /* Encryption Algorithm Id */\n\t\tbuf[43] = 0x10;\t /* Encryption Algorithm Id */\n\t}\n\n\treturn 44;\n}\n\nstatic int t10k_kad_validation(int encrypt_mode, int ukad, int akad) {\n\tif (ukad > 30 || akad > 0)\n\t\treturn TRUE;\n\treturn FALSE;\n}\n\n/* Some comments before I forget how this is supose to work..\n - cleaning_media_state is either\n   0 - Not mounted\n   1 - Cleaning media mounted -> return Cleaning cartridge installed\n   2 - Cleaning media mounted -> return Cause not reportable\n   3 - Cleaning media mounted -> return Initializing command required\n\n On cleaning media mount, t10k_cleaning() is called which:\n   Sets a pointer from priv_lu_ssc -> cleaning_media_state.\n   Sets cleaning_media_state to 1.\n   Sets a 30 second timer to call inc_cleaning_state()\n\n inc_cleaning_state()\n   Increments cleaning_media_state.\n   If cleaning media_state == 2, set another timer for 90 seconds to again\n   call inc_cleaning_state.\n\n If the application issues a TUR, ssc_tur() will return one of the\n above status codes depending on the current value of cleaning_media_state.\n\n When the cleaning media is unmounted, the pointer in priv_lu_ssc to this\n var will be re-set to NULL so the ssc_tur() will return defautl value.\n\n */\nstatic volatile sig_atomic_t cleaning_media_state;\n\nstatic void inc_cleaning_state(int sig);\n\nstatic void set_cleaning_timer(int t) {\n\tMHVTL_DBG(3, \"+++ Trace +++ Setting alarm for %d\", t);\n\tsignal(SIGALRM, inc_cleaning_state);\n\talarm(t);\n}\n\nstatic void inc_cleaning_state(int sig) {\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\tsignal(sig, inc_cleaning_state);\n\n\tcleaning_media_state++;\n\n\tif (cleaning_media_state == CLEAN_MOUNT_STAGE2)\n\t\tset_cleaning_timer(90);\n}\n\nstatic uint8_t t10k_media_load(struct lu_phy_attr *lu, int load) {\n\tuint8_t\t\t\t   *sense_p = lu->sense_p;\n\tstruct priv_lu_ssc *ssc;\n\tssc = lu->lu_private;\n\n\tMHVTL_DBG(3, \"+++ Trace +++ %s\", (load) ? \"load\" : \"unload\");\n\n\tif (load) {\n\t\tswitch (ssc->mamp->MediumType) {\n\t\tcase MEDIA_TYPE_WORM:\n\t\t\tsense_p[24] |= 0x02; /* Data + Append-only */\n\t\t\t\t\t\t\t\t /* Now fall thru to 'Data' */\n\t\tcase MEDIA_TYPE_DATA:\n\t\t\tsense_p[24] |= 0x10;\n\t\t\tbreak;\n\t\tcase MEDIA_TYPE_CLEAN:\n\t\t\tsense_p[24] |= 0x80; /* Cleaning cart */\n\t\t\tbreak;\n\t\tcase MEDIA_TYPE_FIRMWARE:\n\t\t\tsense_p[24] |= 0x20;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tsense_p[24] &= 0x0d; /* Unknown type */\n\t\t\tbreak;\n\t\t}\n\t} else {\n\t\tsense_p[24] &= 0x0d; /* Unknown type & mask out Volsafe */\n\t}\n\n\tif (ssc->append_only_mode)\n\t\tsense_p[24] |= 0x02;\n\n\treturn 0;\n}\n\nstatic uint8_t t10k_cleaning(void *ssc_priv) {\n\tstruct priv_lu_ssc *ssc;\n\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\n\tssc = ssc_priv;\n\n\tssc->cleaning_media_state = &cleaning_media_state;\n\tcleaning_media_state\t  = CLEAN_MOUNT_STAGE1;\n\n\tset_cleaning_timer(30);\n\n\treturn 0;\n}\n\nstatic void init_t10k_mode_pages(struct lu_phy_attr *lu) {\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_control(lu);\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_medium_partition(lu);\n\tadd_mode_power_condition(lu);\n\tadd_mode_information_exception(lu);\n\tadd_mode_medium_configuration(lu);\n}\n\n/* T10K return tape type in request sense information\n *\n * Reference: T10000 Interface Reference Manual * August 2009 * Revision M\n *\n * sense[24] 7 6 5 4 3 2 1 0\n *                   | | | +- TapeEOL - Tape loaded is End-Of-Life\n *                   | | +--- Volsafe - Current tape is append-only\n *                   | +----- MIRBad  - Metadata on tape is defective\n *           | | | | +------- DAvail  - Diagnostic info available\n * Tape Type +-+-+-+\n * 1000b = Cleaning tape\n * 0100b = Dump tape\n * 0010b = Code load tape\n * 0001b = Data Tape\n * 0000b = Unknown type\n */\nstatic void t10k_init_sense(struct scsi_cmd *cmd) {\n\tuint8_t\t\t\t   *sense_buf = (uint8_t *)cmd->dbuf_p->sense_buf;\n\tstruct priv_lu_ssc *lu_priv\t  = cmd->lu->lu_private;\n\n\tif (get_tape_load_status()) {\n\t\tif (lu_priv->append_only_mode)\n\t\t\tsense_buf[24] |= 0x02;\n\n\t\tswitch (lu_priv->mamp->MediumType) {\n\t\tcase MEDIA_TYPE_WORM:\n\t\t\tsense_buf[24] |= 0x02; /* Append-only */\n\t\t\t\t\t\t\t\t   /* Fall thru to MEDIA_TYPE_DATA */\n\t\tcase MEDIA_TYPE_DATA:\n\t\t\tsense_buf[24] |= 0x10;\n\t\t\tbreak;\n\t\tcase MEDIA_TYPE_CLEAN:\n\t\t\tsense_buf[24] |= 0x80; /* Cleaning cart */\n\t\t\tbreak;\n\t\tcase MEDIA_TYPE_FIRMWARE:\n\t\t\tsense_buf[24] |= 0x20;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tsense_buf[24] &= 0x0d; /* Unknown type */\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (lu_priv->inLibrary)\n\t\tsense_buf[25] = 0x02; /* LibAtt */\n}\n\nuint8_t t10k_sense(struct scsi_cmd *cmd) {\n\tt10k_init_sense(cmd);\n\treturn spc_request_sense(cmd);\n}\n\nstatic char *pm_name_t10kA = \"T10000A\";\nstatic char *pm_name_t10kB = \"T10000B\";\nstatic char *pm_name_t10kC = \"T10000C\";\n\nstatic struct ssc_personality_template ssc_pm = {\n\t.valid_encryption_blk\t = valid_encryption_blk_t10k,\n\t.update_encryption_mode\t = update_t10k_encryption_mode,\n\t.encryption_capabilities = encr_capabilities_t10k,\n\t.kad_validation\t\t\t = t10k_kad_validation,\n\t.check_restrictions\t\t = check_restrictions,\n\t.clear_compression\t\t = clear_t10k_comp,\n\t.set_compression\t\t = set_t10k_comp,\n\t.clear_WORM\t\t\t\t = clear_t10k_WORM,\n\t.set_WORM\t\t\t\t = set_t10k_WORM,\n\t.media_load\t\t\t\t = t10k_media_load,\n\t.cleaning_media\t\t\t = t10k_cleaning,\n\t.media_handling\t\t\t = media_info,\n};\n\n#define INQUIRY_LEN 74\nstatic void init_t10k_inquiry(struct lu_phy_attr *lu) {\n\tint\t\tpg;\n\tuint8_t worm;\n\n\tworm = ((struct priv_lu_ssc *)lu->lu_private)->pm->drive_supports_WORM;\n\tlu->inquiry[2] =\n\t\t((struct priv_lu_ssc *)lu->lu_private)->pm->drive_ANSI_VERSION;\n\n\tlu->inquiry[3] = 0x42;\n\tlu->inquiry[4] = INQUIRY_LEN - 5; /* Additional Length */\n\n\tif (ssc_pm.drive_supports_SP) { /* Security Protocols */\n\t\tlu->inquiry[54] |= 0x04;\t/* Key management - DPKM SPIN/SPOUT */\n\t\tlu->inquiry[55] |= 0x10;\t/* Encrypt */\n\t}\n\n\t/* FIXME: Need to add 'LibAtt' too */\n\n\t/* WORM... */\n\tif (ssc_pm.drive_supports_WORM)\n\t\tlu->inquiry[55] |= 0x04; /* VolSafe set */\n\n\t/* Set Data Compression enabled */\n\tlu->inquiry[55] |= 0x02; /* DCMP bit enabled */\n\n\t/* Version Descriptor */\n\tput_unaligned_be16(0x0077, &lu->inquiry[58]);\n\tput_unaligned_be16(0x0314, &lu->inquiry[60]);\n\tput_unaligned_be16(0x0403, &lu->inquiry[62]);\n\tput_unaligned_be16(0x0a11, &lu->inquiry[64]);\n\n\t/* Sequential Access device capabilities - Ref: 8.4.2 */\n\tpg\t\t\t   = PCODE_OFFSET(0xb0);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_B0_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_b0(lu, &worm);\n}\n\nvoid init_t10kA_ssc(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_t10kA;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.native_drive_density\t\t\t\t = &density_t10kA;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = FALSE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = TRUE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_t10k_inquiry(lu);\n\n\tinit_t10k_mode_pages(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\tregister_ops(lu, LOAD_DISPLAY, ssc_load_display, NULL, NULL);\n\tregister_ops(lu, REQUEST_SENSE, t10k_sense, NULL, NULL);\n\n\tadd_density_support(&lu->den_list, &density_t10kA, 1);\n\n\tadd_drive_media_list(lu, LOAD_RW, \"T10KA\");\n\tadd_drive_media_list(lu, LOAD_RO, \"T10KA Clean\");\n}\n\nvoid init_t10kB_ssc(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_t10kB;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.native_drive_density\t\t\t\t = &density_t10kB;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = TRUE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_t10k_inquiry(lu);\n\n\tinit_t10k_mode_pages(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\tregister_ops(lu, LOAD_DISPLAY, ssc_load_display, NULL, NULL);\n\tregister_ops(lu, REQUEST_SENSE, t10k_sense, NULL, NULL);\n\n\tadd_density_support(&lu->den_list, &density_t10kA, 1);\n\tadd_density_support(&lu->den_list, &density_t10kB, 1);\n\n\tadd_drive_media_list(lu, LOAD_RW, \"T10KA\");\n\tadd_drive_media_list(lu, LOAD_RO, \"T10KA Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"T10KB\");\n\tadd_drive_media_list(lu, LOAD_RO, \"T10KB Clean\");\n}\n\nvoid init_t10kC_ssc(struct lu_phy_attr *lu) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", &lu->mode_pg);\n\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_t10kC;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.native_drive_density\t\t\t\t = &density_t10kC;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = TRUE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_t10k_inquiry(lu);\n\n\tinit_t10k_mode_pages(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\tregister_ops(lu, LOAD_DISPLAY, ssc_load_display, NULL, NULL);\n\tregister_ops(lu, REQUEST_SENSE, t10k_sense, NULL, NULL);\n\n\tadd_density_support(&lu->den_list, &density_t10kA, 0);\n\tadd_density_support(&lu->den_list, &density_t10kB, 1);\n\tadd_density_support(&lu->den_list, &density_t10kC, 1);\n\n\tadd_drive_media_list(lu, LOAD_RW, \"T10KA\");\n\tadd_drive_media_list(lu, LOAD_RO, \"T10KA Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"T10KB\");\n\tadd_drive_media_list(lu, LOAD_RO, \"T10KB Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"T10KC\");\n\tadd_drive_media_list(lu, LOAD_RO, \"T10KC Clean\");\n}\n"
  },
  {
    "path": "usr/pm/ult3580_pm.c",
    "content": "/*\n * This handles any SCSI OP codes defined in the standards as 'STREAM'\n *\n * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n * See comments in vtltape.c for a more complete version release...\n *\n */\n\n#include <unistd.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <errno.h>\n#include <inttypes.h>\n#include \"be_byteshift.h\"\n#include \"mhvtl_scsi.h\"\n#include \"vtl_common.h\"\n#include \"vtllib.h\"\n#include \"logging.h\"\n#include \"ssc.h\"\n#include \"vtlcart.h\"\n#include \"mode.h\"\n#include \"mhvtl_log.h\"\n\nstatic struct density_info density_lto1 = {\n\t4880, 127, 384, 100000, medium_density_code_lto1,\n\t\"LTO-CVE\", \"U-18\", \"Ultrium 1/8T\"};\nstatic struct density_info density_lto2 = {\n\t4880, 127, 512, 200000, medium_density_code_lto2,\n\t\"LTO-CVE\", \"U-28\", \"Ultrium 2/8T\"};\nstatic struct density_info density_lto3 = {\n\t9638, 127, 704, 381469, medium_density_code_lto3,\n\t\"LTO-CVE\", \"U-316\", \"Ultrium 3/16T\"};\nstatic struct density_info density_lto4 = {\n\t12725, 127, 896, 800000, medium_density_code_lto4,\n\t\"LTO-CVE\", \"U-416\", \"Ultrium 4/16T\"};\nstatic struct density_info density_lto5 = {\n\t15142, 127, 1280, 1500000, medium_density_code_lto5,\n\t\"LTO-CVE\", \"U-516\", \"Ultrium 5/16T\"};\nstatic struct density_info density_lto6 = {\n\t15142, 127, 2176, 2500000, medium_density_code_lto6,\n\t\"LTO-CVE\", \"U-616\", \"Ultrium 6/16T\"};\nstatic struct density_info density_lto7 = {\n\t19107, 127, 3584, 6000000, medium_density_code_lto7,\n\t\"LTO-CVE\", \"U-732\", \"Ultrium 7/32T\"};\nstatic struct density_info density_lto8 = {\n\t20669, 127, 6656, 12000000, medium_density_code_lto8,\n\t\"LTO-CVE\", \"U-832\", \"Ultrium 8/32T\"};\nstatic struct density_info density_lto9 = {\n\t21456, 127, 8960, 18000000, medium_density_code_lto9,\n\t\"LTO-CVE\", \"U-932\", \"Ultrium 9/48T\"};\n\nstatic struct name_to_media_info media_info[] = {\n\t{\"LTO1\", Media_LTO1,\n\t media_type_lto1_data, medium_density_code_lto1},\n\t{\"LTO1 Clean\", Media_LTO1_CLEAN,\n\t media_type_lto1_data, medium_density_code_lto1},\n\t{\"LTO2\", Media_LTO2,\n\t media_type_lto2_data, medium_density_code_lto2},\n\t{\"LTO2 Clean\", Media_LTO2_CLEAN,\n\t media_type_lto2_data, medium_density_code_lto2},\n\t{\"LTO3\", Media_LTO3,\n\t media_type_lto3_data, medium_density_code_lto3},\n\t{\"LTO3 Clean\", Media_LTO3_CLEAN,\n\t media_type_lto3_data, medium_density_code_lto3},\n\t{\"LTO3 WORM\", Media_LTO3_WORM,\n\t media_type_lto3_worm, medium_density_code_lto3},\n\t{\"LTO4\", Media_LTO4,\n\t media_type_lto4_data, medium_density_code_lto4},\n\t{\"LTO4 Clean\", Media_LTO4_CLEAN,\n\t media_type_lto4_data, medium_density_code_lto4},\n\t{\"LTO4 WORM\", Media_LTO4_WORM,\n\t media_type_lto4_worm, medium_density_code_lto4},\n\t{\"LTO5\", Media_LTO5,\n\t media_type_lto5_data, medium_density_code_lto5},\n\t{\"LTO5 Clean\", Media_LTO5_CLEAN,\n\t media_type_lto5_data, medium_density_code_lto5},\n\t{\"LTO5 WORM\", Media_LTO5_WORM,\n\t media_type_lto5_worm, medium_density_code_lto5},\n\t{\"LTO6\", Media_LTO6,\n\t media_type_lto6_data, medium_density_code_lto6},\n\t{\"LTO6 Clean\", Media_LTO6_CLEAN,\n\t media_type_lto6_data, medium_density_code_lto6},\n\t{\"LTO6 WORM\", Media_LTO6_WORM,\n\t media_type_lto6_worm, medium_density_code_lto6},\n\t{\"LTO7\", Media_LTO7,\n\t media_type_lto7_data, medium_density_code_lto7},\n\t{\"LTO7 Clean\", Media_LTO7_CLEAN,\n\t media_type_lto7_data, medium_density_code_lto7},\n\t{\"LTO7 WORM\", Media_LTO7_WORM,\n\t media_type_lto7_worm, medium_density_code_lto7},\n\t{\"LTO8\", Media_LTO8,\n\t media_type_lto8_data, medium_density_code_lto8},\n\t{\"LTO8 Clean\", Media_LTO8_CLEAN,\n\t media_type_lto8_data, medium_density_code_lto8},\n\t{\"LTO8 WORM\", Media_LTO8_WORM,\n\t media_type_lto8_worm, medium_density_code_lto8},\n\t{\"LTO9\", Media_LTO9,\n\t media_type_lto9_data, medium_density_code_lto9},\n\t{\"LTO9 Clean\", Media_LTO9_CLEAN,\n\t media_type_lto9_data, medium_density_code_lto9},\n\t{\"LTO9 WORM\", Media_LTO9_WORM,\n\t media_type_lto9_worm, medium_density_code_lto9},\n\t{\"\", 0, 0, 0},\n};\n\nstatic uint8_t clear_ult_compression(struct list_head *m) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", m);\n\t/* default clear_compression is in libvtlscsi */\n\treturn clear_compression_mode_pg(m);\n}\n\nstatic uint8_t set_ult_compression(struct list_head *m, int lvl) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", m);\n\t/* default set_compression is in libvtlscsi */\n\treturn set_compression_mode_pg(m, lvl);\n}\n\n/* As per IBM LTO5 SCSI Programmers Guide..\n * Filling in compile time/date & dummy 'platform' string\n */\nstatic void update_vpd_ult_c0(struct lu_phy_attr *lu) {\n\tuint8_t\t   *data;\n\tstruct vpd *vpd_p;\n\tint\t\t\th, m, s;\n\tint\t\t\tday, month, year;\n\n\tvpd_p = lu->lu_vpd[PCODE_OFFSET(0xc0)];\n\tdata  = vpd_p->data;\n\n\tymd(&year, &month, &day, &h, &m, &s);\n\n\tdata[1] = 0xc0;\n\tdata[3] = 0x27;\n\n\tsprintf((char *)&data[16], \"%02d%02d%02d\", h, m, s);\n\tsprintf((char *)&data[23], \"%04d%02d%02d\", year, month, day);\n\tsprintf((char *)&data[31], \"mhvtl_fl_f\");\n}\n\nstatic void update_vpd_ult_c1(struct lu_phy_attr *lu, char *sn) {\n\tuint8_t\t   *data;\n\tstruct vpd *vpd_p;\n\n\tvpd_p = lu->lu_vpd[PCODE_OFFSET(0xc1)];\n\tdata  = vpd_p->data;\n\n\tdata[1] = 0xc1;\n\tdata[3] = 0x18;\n\tsnprintf((char *)&data[4], 13, \"%-12.12s\", sn);\n\tsnprintf((char *)&data[16], 13, \"%-12.12s\", sn);\n}\n\nstatic uint8_t set_ult_WORM(struct list_head *lst) {\n\tuint8_t\t\t*mp;\n\tstruct mode *m;\n\n\tset_WORM(lst); /* Default WORM setup */\n\n\t/* Now for the Ultrium unique stuff */\n\n\tm = lookup_mode_pg(lst, MODE_BEHAVIOR_CONFIGURATION, 0);\n\tif (m) {\n\t\tMHVTL_DBG(3, \"l: %p, m: %p, m->pcodePointer: %p\",\n\t\t\t\t  lst, m, m->pcodePointer);\n\n\t\tmp = m->pcodePointer;\n\t\tif (!mp)\n\t\t\treturn SAM_STAT_GOOD;\n\n\t\tmp[4] = 0x01; /* WORM Behavior */\n\t} else {\n\t\tMHVTL_DBG(2, \"MODE BEHAVIOUR CONFIGURATION page not found\");\n\t}\n\n\treturn SAM_STAT_GOOD;\n}\n\nstatic uint8_t clear_ult_WORM(struct list_head *m) {\n\tMHVTL_DBG(3, \"+++ Trace mode pages at %p +++\", m);\n\treturn clear_WORM(m);\n}\n\nstatic uint8_t update_ult_encryption_mode(struct list_head *m, void *p, int value) {\n\tstruct mode *mp;\n\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\n\tmp = lookup_mode_pg(m, MODE_VENDOR_SPECIFIC_24H, 0);\n\tif (mp) {\n\t\tif (value)\n\t\t\tmp->pcodePointer[5] |= ENCR_E;\n\t\telse\n\t\t\tmp->pcodePointer[5] &= ~ENCR_E;\n\t}\n\treturn SAM_STAT_GOOD;\n}\n\nstatic int encr_capabilities_ult(struct scsi_cmd *cmd) {\n\tuint8_t *buf = cmd->dbuf_p->data;\n\n\tput_unaligned_be16(ENCR_CAPABILITIES, &buf[0]);\n\tput_unaligned_be16(40, &buf[2]); /* List length */\n\n\tbuf[20] = 1;\t\t\t\t\t\t/* Algorithm index */\n\tbuf[21] = 0;\t\t\t\t\t\t/* Reserved */\n\tput_unaligned_be16(0x14, &buf[22]); /* Descriptor length */\n\tbuf[24] = 0x3a;\t\t\t\t\t\t/* MAC C/DED_C DECRYPT_C = 2 ENCRYPT_C = 2 */\n\tbuf[25] = 0x10;\t\t\t\t\t\t/* NONCE_C = 1 */\n\t/* Max unauthenticated key data */\n\tput_unaligned_be16(0x20, &buf[26]);\n\t/* Max authenticated  key data */\n\tput_unaligned_be16(0x0c, &buf[28]);\n\t/* Key size */\n\tput_unaligned_be16(0x20, &buf[30]);\n\tbuf[32] = 0x01; /* EAREM */\n\t/* buf 12 - 19 reserved */\n\n\tbuf[40] = 0;\t/* Encryption Algorithm Id */\n\tbuf[41] = 0x01; /* Encryption Algorithm Id */\n\tbuf[42] = 0;\t/* Encryption Algorithm Id */\n\tbuf[43] = 0x14; /* Encryption Algorithm Id */\n\n\t/* adjustments for each emulated drive type */\n\tbuf[4] = 0x1; /* CFG_P == 01b */\n\tif (get_tape_load_status() == TAPE_LOADED) {\n\t\tswitch (mam.MediaType) {\n\t\tcase Media_LTO4:\n\t\t\tMHVTL_DBG(1, \"LTO4 Medium - Setting AVFMV\");\n\t\t\tbuf[24] |= 0x80; /* AVFMV */\n\t\t\tbreak;\n\t\tcase Media_LTO5:\n\t\t\tMHVTL_DBG(1, \"LTO5 Medium - Setting AVFMV\");\n\t\t\tbuf[24] |= 0x80; /* AVFMV */\n\t\t\tbreak;\n\t\tcase Media_LTO6:\n\t\t\tMHVTL_DBG(1, \"LTO6 Medium - Setting AVFMV\");\n\t\t\tbuf[24] |= 0x80; /* AVFMV */\n\t\t\tbreak;\n\t\tcase Media_LTO7:\n\t\t\tMHVTL_DBG(1, \"LTO7 Medium - Setting AVFMV\");\n\t\t\tbuf[24] |= 0x80; /* AVFMV */\n\t\t\tbreak;\n\t\tcase Media_LTO8:\n\t\t\tMHVTL_DBG(1, \"LTO8 Medium - Setting AVFMV\");\n\t\t\tbuf[24] |= 0x80; /* AVFMV */\n\t\t\tbreak;\n\t\tcase Media_LTO9:\n\t\t\tMHVTL_DBG(1, \"LTO9 Medium - Setting AVFMV\");\n\t\t\tbuf[24] |= 0x80; /* AVFMV */\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tMHVTL_DBG(1, \"Unable to set Encryption (AVFMV) bit on mounted media\");\n\t\t\tbreak;\n\t\t}\n\t}\n\tbuf[32] |= 0x08; /* RDMC_C == 4 */\n\treturn 44;\n}\n\nstatic void update_vpd_lbp(struct lu_phy_attr *lu) {\n\tstruct vpd *v;\n\tuint8_t\t   *d;\n\n\tv = lu->lu_vpd[PCODE_OFFSET(0xb5)];\n\td = v->data;\n\n\td[4] = 7;\n\t/* LBP method for LBP disabled */\n\td[5] = 0; /* LBP method */\n\td[6] = 0; /* LBP len */\n\td[7] = 0; /* LBP_W & LBP_R set to 0 */\n\n\t/* LBP method for RS-CRC */\n\td[12] = 7;\n\td[13] = 1;\t  /* LBP method */\n\td[14] = 4;\t  /* LBP len */\n\td[15] = 0xc0; /* LBP_W & LBP_R set to true */\n\n\tif (((struct priv_lu_ssc *)lu->lu_private)->pm->drive_supports_LBP == LBP_CRC32C) {\n\t\td[20] = 7;\n\t\td[21] = 2;\t  /* LBP method */\n\t\td[22] = 4;\t  /* LBP len */\n\t\td[23] = 0xc0; /* LBP_W & LBP_R set to true */\n\t}\n}\n\nstatic void init_ult_inquiry(struct lu_phy_attr *lu) {\n\tint\t\tpg;\n\tuint8_t worm;\n\tuint8_t local_TapeAlert[8] =\n\t\t{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\n\n\tworm = ((struct priv_lu_ssc *)lu->lu_private)->pm->drive_supports_WORM;\n\tlu->inquiry[2] =\n\t\t((struct priv_lu_ssc *)lu->lu_private)->pm->drive_ANSI_VERSION;\n\n\t/* Set Protect bit if 'drive supports Logical Block Protection */\n\tlu->inquiry[5] |= (((struct priv_lu_ssc *)lu->lu_private)->pm->drive_supports_LBP) ? 1 : 0;\n\n\t/* Extended INQUIRY Data VPD page */\n\tpg\t\t\t   = PCODE_OFFSET(0x86);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_86_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_86(lu, ((struct priv_lu_ssc *)lu->lu_private)->pm);\n\n\t/* Sequential Access device capabilities - Ref: 8.4.2 */\n\tpg\t\t\t   = PCODE_OFFSET(0xb0);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_B0_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_b0(lu, &worm);\n\n\t/* Manufacture-assigned serial number - Ref: 8.4.3 */\n\tpg\t\t\t   = PCODE_OFFSET(0xb1);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_B1_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_b1(lu, lu->lu_serial_no);\n\n\t/* TapeAlert supported flags - Ref: 8.4.4 */\n\tpg\t\t\t   = PCODE_OFFSET(0xb2);\n\tlu->lu_vpd[pg] = alloc_vpd(VPD_B2_SZ);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_b2(lu, &local_TapeAlert);\n\n\t/* Logical Block Protection - Ref: 6.3.13.13 (LTO-9 reference guide) */\n\tif (((struct priv_lu_ssc *)lu->lu_private)->pm->drive_supports_LBP) {\n\t\t/* two pages ? - one for CRC32C and one for RS-CRC */\n\t\tint pg_size = (((struct priv_lu_ssc *)lu->lu_private)->pm->drive_supports_LBP == LBP_RSCRC) ? VPD_B5_SZ : VPD_B5_SZ + VPD_B5_SZ;\n\n\t\tpg\t\t\t   = PCODE_OFFSET(0xb5);\n\t\tlu->lu_vpd[pg] = alloc_vpd(pg_size + 12); /* header page, one page for 'disabled' LBP + one or two for RS-CRC / CRC32C */\n\t\tif (!lu->lu_vpd[pg]) {\n\t\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\t\texit(-ENOMEM);\n\t\t}\n\t\tupdate_vpd_lbp(lu);\n\t}\n\n\t/* VPD page 0xC0 */\n\tpg\t\t\t   = PCODE_OFFSET(0xc0);\n\tlu->lu_vpd[pg] = alloc_vpd(43);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_ult_c0(lu);\n\n\t/* VPD page 0xC1 */\n\tpg\t\t\t   = PCODE_OFFSET(0xc1);\n\tlu->lu_vpd[pg] = alloc_vpd(28);\n\tif (!lu->lu_vpd[pg]) {\n\t\tMHVTL_ERR(\"Failed to malloc(): Line %d\", __LINE__);\n\t\texit(-ENOMEM);\n\t}\n\tupdate_vpd_ult_c1(lu, lu->lu_serial_no);\n}\n\nstatic int td4_kad_validation(int encrypt_mode, int ukad, int akad) {\n\tint count = FALSE;\n\tif (ukad > 32 || akad > 12)\n\t\tcount = TRUE;\n\tif (!encrypt_mode && (ukad || akad))\n\t\tcount = TRUE;\n\n\treturn count;\n}\n\n/* Some comments before I forget how this is supose to work..\n - cleaning_media_state is either\n   0 - Not mounted\n   1 - Cleaning media mounted -> return Cleaning cartridge installed\n   2 - Cleaning media mounted -> return Cause not reportable\n   3 - Cleaning media mounted -> return Initializing command required\n\n On cleaning media mount, ult_cleaning() is called which:\n   Sets a pointer from priv_lu_ssc -> cleaning_media_state.\n   Sets cleaning_media_state to 1.\n   Sets a 30 second timer to call inc_cleaning_state()\n\n inc_cleaning_state()\n   Increments cleaning_media_state.\n   If cleaning media_state == 2, set another timer for 90 seconds to again\n   call inc_cleaning_state.\n\n If the application issues a TUR, ssc_tur() will return one of the\n above status codes depending on the current value of cleaning_media_state.\n\n When the cleaning media is unmounted, the pointer in priv_lu_ssc to this\n var will be re-set to NULL so the ssc_tur() will return defautl value.\n\n */\nstatic volatile sig_atomic_t cleaning_media_state;\n\nstatic void inc_cleaning_state(int sig);\n\nstatic void set_cleaning_timer(int t) {\n\tMHVTL_DBG(3, \"+++ Trace +++ Setting alarm for %d\", t);\n\tsignal(SIGALRM, inc_cleaning_state);\n\talarm(t);\n}\n\nstatic void inc_cleaning_state(int sig) {\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\tsignal(sig, inc_cleaning_state);\n\n\tcleaning_media_state++;\n\n\tif (cleaning_media_state == CLEAN_MOUNT_STAGE2)\n\t\tset_cleaning_timer(90);\n}\n\nstatic uint8_t ult_media_load(struct lu_phy_attr *lu, int load) {\n\tstruct priv_lu_ssc *lu_priv = lu->lu_private;\n\n\tMHVTL_DBG(3, \"+++ Trace +++ %s\", (load) ? \"load\" : \"unload\");\n\n\tif (load) {\n\t\tswitch (lu_priv->mamp->MediaType) {\n\t\tcase Media_LTO1:\n\t\t\tlu->mode_media_type = media_type_lto1_data;\n\t\t\tbreak;\n\t\tcase Media_LTO2:\n\t\t\tlu->mode_media_type = media_type_lto2_data;\n\t\t\tbreak;\n\t\tcase Media_LTO3:\n\t\t\tlu->mode_media_type = media_type_lto3_data;\n\t\t\tbreak;\n\t\tcase Media_LTO4:\n\t\t\tlu->mode_media_type = media_type_lto4_data;\n\t\t\tbreak;\n\t\tcase Media_LTO5:\n\t\t\tlu->mode_media_type = media_type_lto5_data;\n\t\t\tbreak;\n\t\tcase Media_LTO6:\n\t\t\tlu->mode_media_type = media_type_lto6_data;\n\t\t\tbreak;\n\t\tcase Media_LTO7:\n\t\t\tlu->mode_media_type = media_type_lto7_data;\n\t\t\tbreak;\n\t\tcase Media_LTO8:\n\t\t\tlu->mode_media_type = media_type_lto8_data;\n\t\t\tbreak;\n\t\tcase Media_LTO9:\n\t\t\tlu->mode_media_type = media_type_lto9_data;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tlu->mode_media_type = 0;\n\t\t}\n\t\tif (lu_priv->mamp->MediumType == MEDIA_TYPE_WORM)\n\t\t\tlu->mode_media_type |= 0x04;\n\t} else {\n\t\tlu->mode_media_type = 0;\n\t}\n\treturn 0;\n}\n\nstatic uint8_t ult_cleaning(void *ssc_priv) {\n\tstruct priv_lu_ssc *ssc;\n\n\tMHVTL_DBG(3, \"+++ Trace +++\");\n\n\tssc = ssc_priv;\n\n\tssc->cleaning_media_state = &cleaning_media_state;\n\tcleaning_media_state\t  = CLEAN_MOUNT_STAGE1;\n\n\tset_cleaning_timer(30);\n\n\treturn 0;\n}\n\nstatic char *pm_name_lto1 = \"LTO-1\";\nstatic char *pm_name_lto2 = \"LTO-2\";\nstatic char *pm_name_lto3 = \"LTO-3\";\nstatic char *pm_name_lto4 = \"LTO-4\";\nstatic char *pm_name_lto5 = \"LTO-5\";\nstatic char *pm_name_lto6 = \"LTO-6\";\nstatic char *pm_name_lto7 = \"LTO-7\";\nstatic char *pm_name_lto8 = \"LTO-8\";\nstatic char *pm_name_lto9 = \"LTO-9\";\n\nstatic struct ssc_personality_template ssc_pm = {\n\t.valid_encryption_blk = valid_encryption_blk, /* default in ssc.c */\n\t.check_restrictions\t  = check_restrictions,\t  /* default in ssc.c */\n\t.clear_compression\t  = clear_ult_compression,\n\t.set_compression\t  = set_ult_compression,\n\t.media_load\t\t\t  = ult_media_load,\n\t.cleaning_media\t\t  = ult_cleaning,\n\t.media_handling\t\t  = media_info,\n};\n\nvoid init_ult3580_td1(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t= pm_name_lto1;\n\tssc_pm.lu\t\t\t\t\t= lu;\n\tssc_pm.native_drive_density = &density_lto1;\n\n\t/* Drive capabilities need to be defined before mode pages */\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = FALSE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = FALSE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_ult_inquiry(lu);\n\n\t/* IBM Ultrium SCSI Reference (5edition - Oct 2001)\n\t * lists these mode pages\n\t */\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_information_exception(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\t/* Capacity units in MBytes */\n\t((struct priv_lu_ssc *)lu->lu_private)->capacity_unit = 1L << 20;\n\n\tadd_density_support(&lu->den_list, &density_lto1, 1);\n\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO1\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO1 Clean\");\n}\n\nvoid init_ult3580_td2(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_lto2;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.native_drive_density\t\t\t\t = &density_lto2;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = FALSE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = FALSE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_ult_inquiry(lu);\n\n\t/* Based on 9th edition of IBM SCSI Reference */\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_control(lu);\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_information_exception(lu);\n\tadd_mode_medium_configuration(lu);\n\tadd_mode_behavior_configuration(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\t/* Capacity units in MBytes */\n\t((struct priv_lu_ssc *)lu->lu_private)->capacity_unit = 1L << 20;\n\n\tadd_density_support(&lu->den_list, &density_lto1, 1);\n\tadd_density_support(&lu->den_list, &density_lto2, 1);\n\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO1\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO1 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO2\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO2 Clean\");\n}\n\nvoid init_ult3580_td3(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_lto3;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.native_drive_density\t\t\t\t = &density_lto3;\n\tssc_pm.clear_WORM\t\t\t\t\t\t = clear_ult_WORM;\n\tssc_pm.set_WORM\t\t\t\t\t\t\t = set_ult_WORM;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = FALSE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_ult_inquiry(lu);\n\n\t/* Based on 9th edition of IBM SCSI Reference */\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_control(lu);\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_device_configuration_extension(lu);\n\tadd_mode_information_exception(lu);\n\tadd_mode_medium_configuration(lu);\n\tadd_mode_behavior_configuration(lu);\n\tadd_mode_vendor_25h_mode_pages(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_device_status(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\t/* Capacity units in MBytes */\n\t((struct priv_lu_ssc *)lu->lu_private)->capacity_unit = 1L << 20;\n\n\tadd_density_support(&lu->den_list, &density_lto1, 0);\n\tadd_density_support(&lu->den_list, &density_lto2, 1);\n\tadd_density_support(&lu->den_list, &density_lto3, 1);\n\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO1\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO1 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO2\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO2 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO3\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO3 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO3 WORM\");\n}\n\nvoid init_ult3580_td4(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_lto4;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.native_drive_density\t\t\t\t = &density_lto4;\n\tssc_pm.update_encryption_mode\t\t\t = update_ult_encryption_mode;\n\tssc_pm.encryption_capabilities\t\t\t = encr_capabilities_ult;\n\tssc_pm.kad_validation\t\t\t\t\t = td4_kad_validation;\n\tssc_pm.clear_WORM\t\t\t\t\t\t = clear_ult_WORM;\n\tssc_pm.set_WORM\t\t\t\t\t\t\t = set_ult_WORM;\n\tssc_pm.drive_supports_append_only_mode\t = FALSE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = FALSE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = TRUE;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_ult_inquiry(lu);\n\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_control(lu);\n\tadd_mode_control_extension(lu);\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_device_configuration_extension(lu);\n\tadd_mode_medium_partition(lu);\n\tadd_mode_power_condition(lu);\n\tadd_mode_information_exception(lu);\n\tadd_mode_medium_configuration(lu);\n\tadd_mode_ult_encr_mode_pages(lu); /* Extra for LTO-4 */\n\tadd_mode_vendor_25h_mode_pages(lu);\n\tadd_mode_behavior_configuration(lu);\n\tadd_mode_encryption_mode_attribute(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_device_status(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\t/* Capacity units in MBytes */\n\t((struct priv_lu_ssc *)lu->lu_private)->capacity_unit = 1L << 20;\n\n\tadd_density_support(&lu->den_list, &density_lto2, 0);\n\tadd_density_support(&lu->den_list, &density_lto3, 1);\n\tadd_density_support(&lu->den_list, &density_lto4, 1);\n\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO2\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO2 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO3\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO3 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO3 WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO4\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO4 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO4 WORM\");\n}\n\nvoid init_ult3580_td5(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_lto5;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.native_drive_density\t\t\t\t = &density_lto5;\n\tssc_pm.update_encryption_mode\t\t\t = update_ult_encryption_mode;\n\tssc_pm.encryption_capabilities\t\t\t = encr_capabilities_ult;\n\tssc_pm.kad_validation\t\t\t\t\t = td4_kad_validation;\n\tssc_pm.clear_WORM\t\t\t\t\t\t = clear_ult_WORM;\n\tssc_pm.set_WORM\t\t\t\t\t\t\t = set_ult_WORM;\n\tssc_pm.drive_supports_append_only_mode\t = TRUE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = TRUE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_LBP\t\t\t\t = LBP_RSCRC;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_ult_inquiry(lu);\n\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_control(lu);\n\tadd_mode_control_extension(lu);\n\t/* LBP appears in LTO5 & 6 IBM SCSI reference Feb 2013 */\n\tadd_mode_control_data_protection(lu); /* LBP 0x0a/0xf0 */\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_device_configuration_extension(lu);\n\tadd_mode_medium_partition(lu);\n\tadd_mode_power_condition(lu);\n\tadd_mode_information_exception(lu);\n\tadd_mode_medium_configuration(lu);\n\tadd_mode_ult_encr_mode_pages(lu); /* Extra for LTO-5 */\n\tadd_mode_vendor_25h_mode_pages(lu);\n\tadd_mode_behavior_configuration(lu);\n\tadd_mode_encryption_mode_attribute(lu);\n\n\t/* Supports non-zero programable early warning */\n\tupdate_prog_early_warning(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_device_status(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\t/* Capacity units in MBytes */\n\t((struct priv_lu_ssc *)lu->lu_private)->capacity_unit = 1L << 20;\n\n\tadd_density_support(&lu->den_list, &density_lto3, 0);\n\tadd_density_support(&lu->den_list, &density_lto4, 1);\n\tadd_density_support(&lu->den_list, &density_lto5, 1);\n\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO3\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO3 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO4\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO4 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO4 WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO4 ENCR\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO5\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO5 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO5 WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO5 ENCR\");\n}\n\nvoid init_ult3580_td6(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_lto6;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.native_drive_density\t\t\t\t = &density_lto6;\n\tssc_pm.update_encryption_mode\t\t\t = update_ult_encryption_mode;\n\tssc_pm.encryption_capabilities\t\t\t = encr_capabilities_ult;\n\tssc_pm.kad_validation\t\t\t\t\t = td4_kad_validation;\n\tssc_pm.clear_WORM\t\t\t\t\t\t = clear_ult_WORM;\n\tssc_pm.set_WORM\t\t\t\t\t\t\t = set_ult_WORM;\n\tssc_pm.drive_supports_append_only_mode\t = TRUE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = TRUE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_LBP\t\t\t\t = LBP_RSCRC;\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_ult_inquiry(lu);\n\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_control(lu);\n\tadd_mode_control_extension(lu);\n\t/* LBP appears in LTO5 & 6 IBM SCSI reference Feb 2013 */\n\tadd_mode_control_data_protection(lu); /* LBP 0x0a/0xf0 */\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_device_configuration_extension(lu);\n\tadd_mode_medium_partition(lu);\n\tadd_mode_power_condition(lu);\n\tadd_mode_information_exception(lu);\n\tadd_mode_medium_configuration(lu);\n\tadd_mode_ult_encr_mode_pages(lu); /* Extra for LTO-6 */\n\tadd_mode_vendor_25h_mode_pages(lu);\n\tadd_mode_behavior_configuration(lu);\n\tadd_mode_encryption_mode_attribute(lu);\n\n\t/* Supports non-zero programable early warning */\n\tupdate_prog_early_warning(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_device_status(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\t/* Capacity units in MBytes */\n\t((struct priv_lu_ssc *)lu->lu_private)->capacity_unit = 1L << 20;\n\n\tadd_density_support(&lu->den_list, &density_lto4, 0);\n\tadd_density_support(&lu->den_list, &density_lto5, 1);\n\tadd_density_support(&lu->den_list, &density_lto6, 1);\n\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO4\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO4 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO4 WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO5\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO5 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO5 WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO5 ENCR\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO6\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO6 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO6 WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO6 ENCR\");\n}\n\nvoid init_ult3580_td7(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_lto7;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.native_drive_density\t\t\t\t = &density_lto7;\n\tssc_pm.update_encryption_mode\t\t\t = update_ult_encryption_mode;\n\tssc_pm.encryption_capabilities\t\t\t = encr_capabilities_ult;\n\tssc_pm.kad_validation\t\t\t\t\t = td4_kad_validation;\n\tssc_pm.clear_WORM\t\t\t\t\t\t = clear_ult_WORM;\n\tssc_pm.set_WORM\t\t\t\t\t\t\t = set_ult_WORM;\n\tssc_pm.drive_supports_append_only_mode\t = TRUE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = TRUE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_LBP\t\t\t\t = LBP_CRC32C; /* both RS-CRC and CRC32C */\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_ult_inquiry(lu);\n\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_control(lu);\n\tadd_mode_control_extension(lu);\n\tadd_mode_control_data_protection(lu); /* LBP 0x0a/0xf0 */\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_device_configuration_extension(lu);\n\tadd_mode_medium_partition(lu);\n\tadd_mode_power_condition(lu);\n\tadd_mode_information_exception(lu);\n\tadd_mode_medium_configuration(lu);\n\tadd_mode_ult_encr_mode_pages(lu); /* Extra for LTO-7 */\n\tadd_mode_vendor_25h_mode_pages(lu);\n\tadd_mode_behavior_configuration(lu);\n\tadd_mode_encryption_mode_attribute(lu);\n\n\t/* Supports non-zero programable early warning */\n\tupdate_prog_early_warning(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_device_status(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\t/* Capacity units in MBytes */\n\t((struct priv_lu_ssc *)lu->lu_private)->capacity_unit = 1L << 20;\n\n\tadd_density_support(&lu->den_list, &density_lto5, 0);\n\tadd_density_support(&lu->den_list, &density_lto6, 1);\n\tadd_density_support(&lu->den_list, &density_lto7, 1);\n\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO5\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO5 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO5 WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO5 ENCR\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO6\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO6 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO6 WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO6 ENCR\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO7\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO7 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO7 WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO7 ENCR\");\n}\n\nvoid init_ult3580_td8(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_lto8;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.native_drive_density\t\t\t\t = &density_lto8;\n\tssc_pm.update_encryption_mode\t\t\t = update_ult_encryption_mode;\n\tssc_pm.encryption_capabilities\t\t\t = encr_capabilities_ult;\n\tssc_pm.kad_validation\t\t\t\t\t = td4_kad_validation;\n\tssc_pm.clear_WORM\t\t\t\t\t\t = clear_ult_WORM;\n\tssc_pm.set_WORM\t\t\t\t\t\t\t = set_ult_WORM;\n\tssc_pm.drive_supports_append_only_mode\t = TRUE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = TRUE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_LBP\t\t\t\t = LBP_CRC32C; /* both RS-CRC and CRC32C */\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_ult_inquiry(lu);\n\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_control(lu);\n\tadd_mode_control_extension(lu);\n\tadd_mode_control_data_protection(lu); /* LBP 0x0a/0xf0 */\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_device_configuration_extension(lu);\n\tadd_mode_medium_partition(lu);\n\tadd_mode_power_condition(lu);\n\tadd_mode_information_exception(lu);\n\tadd_mode_medium_configuration(lu);\n\tadd_mode_ult_encr_mode_pages(lu); /* Extra for LTO-7+ */\n\tadd_mode_vendor_25h_mode_pages(lu);\n\tadd_mode_behavior_configuration(lu);\n\tadd_mode_encryption_mode_attribute(lu);\n\n\t/* Supports non-zero programable early warning */\n\tupdate_prog_early_warning(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_device_status(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\t/* Capacity units in MBytes */\n\t((struct priv_lu_ssc *)lu->lu_private)->capacity_unit = 1L << 20;\n\n\t/* LTO 8 drives cannot read LTO6 cartridges.\n\thttps://www.lto.org/lto-generation-compatibility/\n\t\"LTO drive generations 1-7 are able to read tapes from two generations prior\n\tand are able to write to tapes from the prior generation.\n\n\tLTO-8 drives can read and write to LTO-7 and LTO-8 media*/\n\tadd_density_support(&lu->den_list, &density_lto7, 1);\n\tadd_density_support(&lu->den_list, &density_lto8, 1);\n\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO7\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO7 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO7 WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO7 ENCR\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO8\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO8 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO8 WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO8 ENCR\");\n}\n\nvoid init_ult3580_td9(struct lu_phy_attr *lu) {\n\tssc_pm.name\t\t\t\t\t\t\t\t = pm_name_lto9;\n\tssc_pm.lu\t\t\t\t\t\t\t\t = lu;\n\tssc_pm.native_drive_density\t\t\t\t = &density_lto9;\n\tssc_pm.update_encryption_mode\t\t\t = update_ult_encryption_mode;\n\tssc_pm.encryption_capabilities\t\t\t = encr_capabilities_ult;\n\tssc_pm.kad_validation\t\t\t\t\t = td4_kad_validation;\n\tssc_pm.clear_WORM\t\t\t\t\t\t = clear_ult_WORM;\n\tssc_pm.set_WORM\t\t\t\t\t\t\t = set_ult_WORM;\n\tssc_pm.drive_supports_append_only_mode\t = TRUE;\n\tssc_pm.drive_supports_early_warning\t\t = TRUE;\n\tssc_pm.drive_supports_prog_early_warning = TRUE;\n\tssc_pm.drive_supports_WORM\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SPR\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_SP\t\t\t\t = TRUE;\n\tssc_pm.drive_supports_LBP\t\t\t\t = LBP_CRC32C; /* both RS-CRC and CRC32C */\n\tssc_pm.drive_ANSI_VERSION\t\t\t\t = 5;\n\n\tssc_personality_module_register(&ssc_pm);\n\n\tinit_ult_inquiry(lu);\n\n\tadd_mode_page_rw_err_recovery(lu);\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_control(lu);\n\tadd_mode_control_extension(lu);\n\tadd_mode_control_data_protection(lu); /* LBP 0x0a/0xf0 */\n\tadd_mode_data_compression(lu);\n\tadd_mode_device_configuration(lu);\n\tadd_mode_device_configuration_extension(lu);\n\tadd_mode_medium_partition(lu);\n\tadd_mode_power_condition(lu);\n\tadd_mode_information_exception(lu);\n\tadd_mode_medium_configuration(lu);\n\tadd_mode_ult_encr_mode_pages(lu); /* Extra for LTO-7+ */\n\tadd_mode_vendor_25h_mode_pages(lu);\n\tadd_mode_behavior_configuration(lu);\n\tadd_mode_encryption_mode_attribute(lu);\n\n\t/* Supports non-zero programable early warning */\n\tupdate_prog_early_warning(lu);\n\n\tadd_log_write_err_counter(lu);\n\tadd_log_read_err_counter(lu);\n\tadd_log_sequential_access(lu);\n\tadd_log_temperature_page(lu);\n\tadd_log_selftest_results(lu);\n\tadd_log_device_status(lu);\n\tadd_log_volume_statistics(lu);\n\tadd_log_tape_alert(lu);\n\tadd_log_tape_usage(lu);\n\tadd_log_tape_capacity(lu);\n\tadd_log_data_compression(lu);\n\tadd_log_performance_characteristics(lu);\n\n\t/* Capacity units in MBytes */\n\t((struct priv_lu_ssc *)lu->lu_private)->capacity_unit = 1L << 20;\n\n\t/* LTO 9 drives cannot read LTO7 cartridges.\n\thttps://www.lto.org/lto-generation-compatibility/\n\t\"LTO drive generations 1-7 are able to read tapes from two generations prior\n\tand are able to write to tapes from the prior generation.\n\n\tLTO-9 drives can read and write to LTO-8 and LTO-9 media only*/\n\tadd_density_support(&lu->den_list, &density_lto8, 1);\n\tadd_density_support(&lu->den_list, &density_lto9, 1);\n\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO8\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO8 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO8 WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO8 ENCR\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO9\");\n\tadd_drive_media_list(lu, LOAD_RO, \"LTO9 Clean\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO9 WORM\");\n\tadd_drive_media_list(lu, LOAD_RW, \"LTO9 ENCR\");\n}\n"
  },
  {
    "path": "usr/smc.c",
    "content": "/*\n * This handles any SCSI OP codes defined in the standards as 'MEDIUM CHANGER'\n *\n * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n * See comments in vtltape.c for a more complete version release...\n *\n */\n\n#include <unistd.h>\n#include <sys/msg.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <inttypes.h>\n#include \"be_byteshift.h\"\n#include \"mhvtl_scsi.h\"\n#include \"mhvtl_list.h\"\n#include \"vtl_common.h\"\n#include \"vtllib.h\"\n#include \"logging.h\"\n#include \"smc.h\"\n#include \"q.h\"\n#include \"mhvtl_log.h\"\n#include \"subprocess.h\"\n\nuint8_t smc_allow_removal(struct scsi_cmd *cmd) {\n\tMHVTL_DBG(1, \"%s MEDIUM REMOVAL (%ld) **\",\n\t\t\t  (cmd->scb[4]) ? \"PREVENT\" : \"ALLOW\",\n\t\t\t  (long)cmd->dbuf_p->serialNo);\n\treturn SAM_STAT_GOOD;\n}\n\nuint8_t smc_initialize_element_status(struct scsi_cmd *cmd) {\n\tuint8_t *sam_stat = &cmd->dbuf_p->sam_stat;\n\n\tcurrent_state = MHVTL_STATE_INITIALISE_ELEMENTS;\n\n\tMHVTL_DBG(1, \"%s (%ld) **\", \"INITIALIZE ELEMENT\",\n\t\t\t  (long)cmd->dbuf_p->serialNo);\n\tif (!cmd->lu->online) {\n\t\tsam_not_ready(NO_ADDITIONAL_SENSE, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\tsleep(1);\n\treturn SAM_STAT_GOOD;\n}\n\nuint8_t smc_initialize_element_status_with_range(struct scsi_cmd *cmd) {\n\tuint8_t *sam_stat = &cmd->dbuf_p->sam_stat;\n\n\tcurrent_state = MHVTL_STATE_INITIALISE_ELEMENTS;\n\n\tMHVTL_DBG(1, \"%s (%ld) **\", \"INITIALIZE ELEMENT RANGE\",\n\t\t\t  (long)cmd->dbuf_p->serialNo);\n\n\tif (!cmd->lu->online) {\n\t\tsam_not_ready(NO_ADDITIONAL_SENSE, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\tsleep(1);\n\treturn SAM_STAT_GOOD;\n}\n\n/* Return the element type of a particular element address */\nstatic int slot_type(struct smc_priv *smc_p, int addr) {\n\tif ((addr >= smc_p->pm->start_drive) &&\n\t\t(addr < smc_p->pm->start_drive + smc_p->num_drives))\n\t\treturn DATA_TRANSFER;\n\tif ((addr >= smc_p->pm->start_picker) &&\n\t\t(addr < smc_p->pm->start_picker + smc_p->num_picker))\n\t\treturn MEDIUM_TRANSPORT;\n\tif ((addr >= smc_p->pm->start_map) &&\n\t\t(addr < smc_p->pm->start_map + smc_p->num_map))\n\t\treturn MAP_ELEMENT;\n\tif ((addr >= smc_p->pm->start_storage) &&\n\t\t(addr < smc_p->pm->start_storage + smc_p->num_storage))\n\t\treturn STORAGE_ELEMENT;\n\treturn 0;\n}\n\n/*\n * Returns a 'human frendly' slot number\n * i.e. One with the internal offset removed (start counting at 1).\n */\nstatic int slot_number(struct smc_personality_template *pm, struct s_info *sp) {\n\tswitch (sp->element_type) {\n\tcase MEDIUM_TRANSPORT:\n\t\treturn sp->slot_location - pm->start_picker + 1;\n\tcase STORAGE_ELEMENT:\n\t\treturn sp->slot_location - pm->start_storage + 1;\n\tcase MAP_ELEMENT:\n\t\treturn sp->slot_location - pm->start_map + 1;\n\tcase DATA_TRANSFER:\n\t\treturn sp->slot_location - pm->start_drive + 1;\n\t}\n\treturn 0;\n}\n\n/*\n * Takes a slot number and returns a struct pointer to the slot\n */\nstatic struct s_info *slot2struct(struct smc_priv *smc_p, int addr) {\n\tstruct list_head *slot_head;\n\tstruct s_info\t *sp;\n\n\tslot_head = &smc_p->slot_list;\n\n\tlist_for_each_entry(sp, slot_head, siblings) {\n\t\tif (sp->slot_location == (unsigned int)addr)\n\t\t\treturn sp;\n\t}\n\n\tMHVTL_DBG(1, \"Arrr... Could not find slot %d\", addr);\n\n\treturn NULL;\n}\n\n/*\n * Takes a Drive number and returns a struct pointer to the drive\n */\nstatic struct d_info *drive2struct(struct smc_priv *smc_p, int addr) {\n\tstruct s_info *s;\n\n\ts = slot2struct(smc_p, addr);\n\tif (s)\n\t\treturn s->drive;\n\n\treturn NULL;\n}\n\n/* Query the drive to check if it thinks it is empty */\nstatic int is_drive_empty(struct d_info *drv) {\n\tint\t\t\t   mlen, r_qid;\n\tstruct q_entry q;\n\n\t/* Initialise message queue as necessary */\n\tr_qid = init_queue();\n\tif (r_qid == -1) {\n\t\tprintf(\"Could not initialise message queue\\n\");\n\t\texit(1);\n\t}\n\n\tMHVTL_DBG(1, \"%ld: Sending \\\"%s\\\" to snd_id %ld\",\n\t\t\t  my_id, msg_mount_state, drv->drv_id);\n\tsend_msg(msg_mount_state, drv->drv_id);\n\n\tmlen = msgrcv(r_qid, &q, MAXOBN, my_id, MSG_NOERROR);\n\tif (mlen > 0)\n\t\tMHVTL_DBG(1, \"%ld: Received \\\"%s\\\" from snd_id %ld\",\n\t\t\t\t  my_id,\n\t\t\t\t  q.msg.text,\n\t\t\t\t  q.msg.snd_id);\n\n\t/* string defined in q.h */\n\treturn strncmp(msg_not_occupied, q.msg.text, 12);\n}\n\n/* returns true if medium transport access to slot is OK */\nint slotAccess(struct s_info *s) {\n\treturn s->status & STATUS_Access;\n}\n\n/* Returns true if slot has media in it */\nint slotOccupied(struct s_info *s) {\n\treturn s->status & STATUS_Full;\n}\n\n/* Returns true if drive has media in it */\nstatic int driveOccupied(struct d_info *d) {\n\tint ret;\n\n\tret = slotOccupied(d->slot);\n\tret |= is_drive_empty(d);\n\n\treturn ret;\n}\n\nstatic int check_tape_unload(void) {\n\tint\t\t\t   mlen, r_qid;\n\tstruct q_entry q;\n\n\t/* Initialise message queue as necessary */\n\tr_qid = init_queue();\n\tif (r_qid == -1) {\n\t\tprintf(\"Could not initialise message queue\\n\");\n\t\texit(1);\n\t}\n\n\tmlen = msgrcv(r_qid, &q, MAXOBN, my_id, MSG_NOERROR);\n\tif (mlen > 0)\n\t\tMHVTL_DBG(1, \"%ld: Received \\\"%s\\\" from snd_id %ld\",\n\t\t\t\t  my_id,\n\t\t\t\t  q.msg.text,\n\t\t\t\t  q.msg.snd_id);\n\n\t/* msg defined in q.h */\n\treturn strncmp(msg_unload_ok, q.msg.text, 11);\n}\n\n/*\n * A value of 0 indicates that media movement from the I/O port\n * to the handler is denied; a value of 1 indicates that the movement\n * is permitted.\n */\n/*\nstatic void setInEnableStatus(struct s_info *s, int flg)\n{\n\tif (flg)\n\t\ts->status |= STATUS_InEnab;\n\telse\n\t\ts->status &= ~STATUS_InEnab;\n}\n*/\n/*\n * A value of 0 in the Export Enable field indicates that media movement\n * from the handler to the I/O port is denied. A value of 1 indicates that\n * movement is permitted.\n */\n/*\nstatic void setExEnableStatus(struct s_info *s, int flg)\n{\n\tif (flg)\n\t\ts->status |= STATUS_ExEnab;\n\telse\n\t\ts->status &= ~STATUS_ExEnab;\n}\n*/\n\n/*\n * 1 / 0 Set/Clear the Access bit.\n * Access bit when set, indicates the medium transport can access media\n */\nvoid setAccessStatus(struct s_info *s, int flg) {\n\tif (flg)\n\t\ts->status |= STATUS_Access;\n\telse\n\t\ts->status &= ~STATUS_Access;\n}\n\n/*\n * Reset to 0 indicates it is in normal state, set to 1 indicates an Exception\n * condition exists. An exception indicates the libary is uncertain of an\n * elements status.\n */\n/*\nstatic void setExceptStatus(struct s_info *s, int flg)\n{\n\tif (flg)\n\t\ts->status |= STATUS_Except;\n\telse\n\t\ts->status &= ~STATUS_Except;\n}\n*/\n\n/*\n * If set(1) then cartridge placed by operator\n * If clear(0), placed there by handler.\n */\nvoid setImpExpStatus(struct s_info *s, int flg) {\n\tif (flg)\n\t\ts->status |= STATUS_ImpExp;\n\telse\n\t\ts->status &= ~STATUS_ImpExp;\n}\n\n/*\n * Sets the 'Full' bit true/false in the status field\n */\nvoid setFullStatus(struct s_info *s, int flg) {\n\tif (flg)\n\t\ts->status |= STATUS_Full;\n\telse\n\t\ts->status &= ~STATUS_Full;\n}\n\nvoid setSlotEmpty(struct s_info *s) {\n\tsetFullStatus(s, 0);\n}\n\nstatic void setDriveEmpty(struct d_info *d) {\n\tsetFullStatus(d->slot, 0);\n\tsend_msg(msg_set_empty, d->drv_id);\n\t/* Wait for ack from drive */\n\tcheck_tape_unload();\n}\n\nvoid setSlotFull(struct s_info *s) {\n\tsetFullStatus(s, 1);\n}\n\nvoid setDriveFull(struct d_info *d) {\n\tsetFullStatus(d->slot, 1);\n}\n\n/* Returns 1 (true) if slot is MAP slot */\nstatic int is_map_slot(struct s_info *s) {\n\tMHVTL_DBG(2, \"slot type %d: %s\", s->element_type,\n\t\t\t  (s->element_type == MAP_ELEMENT) ? \"MAP\" : \"NOT A MAP\");\n\treturn s->element_type == MAP_ELEMENT;\n}\n\nstatic int map_access_ok(struct smc_priv *smc_p, struct s_info *s) {\n\tif (is_map_slot(s)) {\n\t\tMHVTL_DBG(3, \"Returning status of %d\", smc_p->cap_closed);\n\t\treturn smc_p->cap_closed;\n\t}\n\tMHVTL_DBG(3, \"Returning 0\");\n\treturn 0;\n}\n\nstatic int dump_element_desc(uint8_t *p, int voltag, int num_elem, int len,\n\t\t\t\t\t\t\t char dvcid_serial_only) {\n\tint i, j, idlen;\n\n\ti = 0;\n\tfor (j = 0; j < num_elem; j++) {\n\t\tMHVTL_DBG(3, \" Debug.... i = %d, len = %d\", i, len);\n\t\tMHVTL_DBG(3, \"  Element Address             : %d\",\n\t\t\t\t  get_unaligned_be16(&p[i]));\n\t\tMHVTL_DBG(3, \"  Status                      : 0x%02x\",\n\t\t\t\t  p[i + 2]);\n\t\tMHVTL_DBG(3, \"  Medium type                 : %d\",\n\t\t\t\t  p[i + 9] & 0x7);\n\t\tif (p[i + 9] & 0x80)\n\t\t\tMHVTL_DBG(3, \"  Source Address              : %d\",\n\t\t\t\t\t  get_unaligned_be16(&p[i + 10]));\n\t\ti += 12;\n\t\tif (voltag) {\n\t\t\ti += VOLTAG_LEN;\n\t\t\tMHVTL_DBG(3, \" Voltag info...\");\n\t\t}\n\n\t\tMHVTL_DBG(3, \" Identification Descriptor\");\n\t\tMHVTL_DBG(3, \"  Code Set                     : 0x%02x\",\n\t\t\t\t  p[i] & 0xf);\n\t\tMHVTL_DBG(3, \"  Identifier type              : 0x%02x\",\n\t\t\t\t  p[i + 1] & 0xf);\n\t\tidlen = p[i + 3];\n\t\tMHVTL_DBG(3, \"  Identifier length            : %d\", idlen);\n\t\tif (idlen) {\n\t\t\tif (dvcid_serial_only) {\n\t\t\t\tMHVTL_DBG(3, \"  ASCII data                   : %.*s\", idlen, &p[i + 4]);\n\t\t\t} else {\n\t\t\t\tMHVTL_DBG(3, \"  ASCII data                   : %.*s\", 8, &p[i + 4]);\n\t\t\t\tMHVTL_DBG(3, \"  ASCII data                   : %.*s\", 16, &p[i + 12]);\n\t\t\t\tMHVTL_DBG(3, \"  ASCII data                   : %.*s\", 10, &p[i + 28]);\n\t\t\t}\n\t\t}\n\t\ti = (j + 1) * len;\n\t}\n\treturn i;\n}\n\nstatic void decode_element_status(struct smc_priv *smc_p, uint8_t *p) {\n\tint voltag;\n\tint elem_len;\n\tint page_elements, page_bytes;\n\tint total_count;\n\tint i;\n\n\ttotal_count = get_unaligned_be24(&p[5]);\n\n\tMHVTL_DBG(3, \"Element Status Data\");\n\tMHVTL_DBG(3, \"  First element reported       : %d\",\n\t\t\t  get_unaligned_be16(&p[0]));\n\tMHVTL_DBG(3, \"  Number of elements available : %d\",\n\t\t\t  get_unaligned_be16(&p[2]));\n\tMHVTL_DBG(3, \"  Byte count of report         : %d\",\n\t\t\t  get_unaligned_be24(&p[5]));\n\n\tp += 8;\n\ttotal_count -= 8;\n\n\twhile (total_count > 0) {\n\t\tMHVTL_DBG(3, \"Element Status Page\");\n\t\tMHVTL_DBG(3, \"  Element Type code            : %d (%s)\",\n\t\t\t\t  p[0], slot_type_str(p[0]));\n\n\t\tvoltag = (p[1] & 0x80) ? 1 : 0;\n\t\tMHVTL_DBG(3, \"  Primary Vol Tag              : %s\",\n\t\t\t\t  voltag ? \"Yes\" : \"No\");\n\t\tMHVTL_DBG(3, \"  Alt Vol Tag                  : %s\",\n\t\t\t\t  (p[1] & 0x40) ? \"Yes\" : \"No\");\n\t\telem_len = get_unaligned_be16(&p[2]);\n\t\tMHVTL_DBG(3, \"  Element descriptor length    : %d\", elem_len);\n\t\tpage_bytes = get_unaligned_be24(&p[5]);\n\t\tMHVTL_DBG(3, \"  Byte count of descriptor data: %d\", page_bytes);\n\t\tpage_elements = page_bytes / elem_len;\n\t\tp += 8;\n\t\ttotal_count -= 8;\n\n\t\tMHVTL_DBG(3, \"Element Descriptor(s) : Num of Elements %d\",\n\t\t\t\t  page_elements);\n\n\t\ti = dump_element_desc(p, voltag, page_elements, elem_len,\n\t\t\t\t\t\t\t  smc_p->pm->dvcid_serial_only);\n\t\tp += i;\n\t\ttotal_count -= i;\n\t}\n\n\tif (debug)\n\t\tfflush(NULL);\n}\n\n/*\n * Calculate length of one element\n */\nstatic int sizeof_element(struct scsi_cmd *cmd, int type) {\n\tstruct smc_priv *smc_p = (struct smc_priv *)cmd->lu->lu_private;\n\tint\t\t\t\t dvcid;\n\tint\t\t\t\t voltag;\n\n\tvoltag = (cmd->scb[1] & 0x10) >> 4;\n\tif (smc_p->pm->no_dvcid_flag)\n\t\tdvcid = 1;\n\telse\n\t\tdvcid = cmd->scb[6] & 0x01; /* Device ID */\n\n\treturn 16 + (voltag ? VOLTAG_LEN : 0) +\n\t\t   (dvcid && (type == DATA_TRANSFER) ? smc_p->pm->dvcid_len : 0);\n}\n\n/*\n * Fill in a single element descriptor\n *\n * Returns number of bytes in element data.\n */\nstatic int fill_ed(struct scsi_cmd *cmd, uint8_t *p, struct s_info *s) {\n\tstruct smc_priv *smc_p = (struct smc_priv *)cmd->lu->lu_private;\n\tstruct d_info\t*d\t   = NULL;\n\tint\t\t\t\t j\t   = 0;\n\tuint8_t\t\t\t voltag;\n\tuint8_t\t\t\t dvcid;\n\n\tvoltag = (cmd->scb[1] & 0x10) >> 4;\n\tif (smc_p->pm->no_dvcid_flag)\n\t\tdvcid = 1;\n\telse\n\t\tdvcid = cmd->scb[6] & 0x01; /* Device ID */\n\n\t/* Should never occur, but better to trap then core */\n\tif (!s) {\n\t\tMHVTL_DBG(1, \"Slot out of range\");\n\t\treturn 0;\n\t}\n\n\tif (s->element_type == DATA_TRANSFER)\n\t\td = s->drive;\n\n\tput_unaligned_be16(s->slot_location, &p[j]);\n\tj += 2;\n\n\tp[j] = s->status;\n\tif (s->element_type == MAP_ELEMENT) {\n\t\tif (smc_p->cap_closed)\n\t\t\tp[j] |= STATUS_Access;\n\t\telse\n\t\t\tp[j] &= ~STATUS_Access;\n\t}\n\tj++;\n\n\tp[j++] = 0; /* Reserved */\n\n\t/* Possible values for ASC/ASCQ for data transfer elements\n\t * 0x30/0x03 Cleaner cartridge present\n\t * 0x83/0x00 Barcode not scanned\n\t * 0x83/0x02 No magazine installed\n\t * 0x83/0x04 Tape drive not installed\n\t * 0x83/0x09 Unable to read bar code\n\t * 0x80/0x5d Drive operating in overheated state\n\t * 0x80/0x5e Drive being shutdown due to overheat condition\n\t * 0x80/0x63 Drive operating with low module fan speed\n\t * 0x80/0x5f Drive being shutdown due to low module fan speed\n\t */\n\tp[j++] = (s->asc_ascq >> 8) & 0xff; /* Additional Sense Code */\n\tp[j++] = s->asc_ascq & 0xff;\t\t/* Additional Sense Code Qualifer */\n\n\tp[j++] = 0; /* Reserved */\n\tif (s->element_type == DATA_TRANSFER)\n\t\tp[j++] = d->SCSI_ID;\n\telse\n\t\tp[j++] = 0; /* Reserved */\n\n\tp[j++] = 0; /* Reserved */\n\n\t/* bit 8 set if Source Storage Element is valid | s->occupied */\n\tif (s->media)\n\t\tp[j] = (s->media->last_location > 0) ? 0x80 : 0;\n\telse\n\t\tp[j] = 0;\n\n\t/* Ref: smc3r12 - Table 28\n\t * 0 - empty,\n\t * 1 - data,\n\t * 2 - cleaning tape,\n\t * 3 - Cleaning,\n\t * 4 - WORM,\n\t * 5 - Microcode image medium\n\t */\n\tif (s->media)\n\t\tp[j] |= s->media->cart_type & 0x0f;\n\n\tj++;\n\n\t/* Source Storage Element Address */\n\tput_unaligned_be16(s->last_location, &p[j]);\n\tj += 2;\n\n\tMHVTL_DBG(2, \"Slot location: %d, DVCID: %d, VOLTAG: %d, status: 0x%02x\",\n\t\t\t  s->slot_location, dvcid, voltag, s->status);\n\n\tif (voltag) {\n\t\t/* Barcode with trailing space(s) */\n\t\tif (s->status & STATUS_Full) {\n\t\t\tif (!(s->media->internal_status & INSTATUS_NO_BARCODE))\n\t\t\t\tblank_fill(&p[j], s->media->barcode, VOLTAG_LEN);\n\t\t\telse\n\t\t\t\tmemset(&p[j], 0, VOLTAG_LEN);\n\t\t} else\n\t\t\tmemset(&p[j], 0, VOLTAG_LEN);\n\n\t\tj += VOLTAG_LEN; /* Account for barcode */\n\t}\n\n\tif (dvcid && s->element_type == DATA_TRANSFER) {\n\t\tp[j++] = 2; /* Code set 2 = ASCII */\n\t\t/* Identifier type - If serial number only - 0, otherwise 1 */\n\t\tp[j++] = smc_p->pm->dvcid_serial_only ? 0 : 1;\n\t\tp[j++] = 0;\t\t\t\t\t   /* Reserved */\n\t\tp[j++] = smc_p->pm->dvcid_len; /* Identifier Length */\n\t\tif (smc_p->pm->dvcid_serial_only) {\n\t\t\tblank_fill(&p[j], d->inq_product_sno,\n\t\t\t\t\t   smc_p->pm->dvcid_len);\n\t\t\tj += smc_p->pm->dvcid_len;\n\t\t} else {\n\t\t\tblank_fill(&p[j], d->inq_vendor_id, 8);\n\t\t\tj += 8;\n\t\t\tblank_fill(&p[j], d->inq_product_id, 16);\n\t\t\tj += 16;\n\t\t\tblank_fill(&p[j], d->inq_product_sno, 10);\n\t\t\tj += 10;\n\t\t}\n\t} else {\n\t\tp[j++] = 0; /* Reserved */\n\t\tp[j++] = 0; /* Reserved */\n\t\tp[j++] = 0; /* Reserved */\n\t\tp[j++] = 0; /* Reserved */\n\t}\n\tMHVTL_DBG(3, \"Element Descriptor - Returning %d (0x%02x) bytes\", j, j);\n\n\treturn j;\n}\n\n/*\n * Fill in element status page Header (8 bytes)\n */\nstatic void fill_element_status_page_hdr(struct scsi_cmd *cmd, uint8_t *p,\n\t\t\t\t\t\t\t\t\t\t uint16_t element_count,\n\t\t\t\t\t\t\t\t\t\t uint8_t  type) {\n\tstruct smc_priv *smc_p;\n\tint\t\t\t\t element_sz;\n\tuint32_t\t\t element_len;\n\tuint8_t\t\t\t voltag;\n\n\tsmc_p  = (struct smc_priv *)cmd->lu->lu_private;\n\tvoltag = (cmd->scb[1] & 0x10) >> 4;\n\n\telement_sz = sizeof_element(cmd, type);\n\n\tp[0] = type; /* Element type Code */\n\n\t/* Primary Volume Tag set - Returning Barcode info */\n\tp[1] = (voltag == 0) ? 0 : 0x80;\n\tif (smc_p->pm->dvcid_serial_only && type == DATA_TRANSFER)\n\t\tp[1] |= 0x40; /* Set AVolTag */\n\n\t/* Number of bytes per element */\n\tput_unaligned_be16(element_sz, &p[2]);\n\n\telement_len = element_sz * element_count;\n\n\t/* Total number of bytes in all element descriptors */\n\tput_unaligned_be24(element_len, &p[5]);\n\n\t/* Reserved */\n\tp[4] = 0; /* Above mask should have already set this to 0... */\n\n\tMHVTL_DBG(2, \"Element Status Page Header: \"\n\t\t\t\t \"%02x %02x %02x %02x %02x %02x %02x %02x\",\n\t\t\t  p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);\n}\n\n/*\n * Build the initial ELEMENT STATUS HEADER\n *\n */\nstatic int fill_element_status_data_hdr(uint8_t *p, int start, int count,\n\t\t\t\t\t\t\t\t\t\tuint32_t byte_count) {\n\tMHVTL_DBG(2, \"Building READ ELEMENT STATUS Header struct\");\n\tMHVTL_DBG(2, \" Starting slot: %d, number of configured slots: %d\",\n\t\t\t  start, count);\n\n\t/* Start of ELEMENT STATUS DATA */\n\tput_unaligned_be16(start, &p[0]);\n\tput_unaligned_be16(count, &p[2]);\n\n\t/* The byte_count should be the length required to return all of\n\t * valid data.\n\t * The 'allocated length' indicates how much data can be returned.\n\t */\n\tput_unaligned_be24(byte_count, &p[5]);\n\n\tMHVTL_DBG(2, \" Element Status Data HEADER: \"\n\t\t\t\t \"%02x %02x %02x %02x %02x %02x %02x %02x\",\n\t\t\t  p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);\n\tMHVTL_DBG(3, \" Decoded:\");\n\tMHVTL_DBG(3, \"  First element Address    : %d (0x%02x)\",\n\t\t\t  get_unaligned_be16(&p[0]),\n\t\t\t  get_unaligned_be16(&p[0]));\n\tMHVTL_DBG(3, \"  Number elements reported : %d (0x%02x)\",\n\t\t\t  get_unaligned_be16(&p[2]),\n\t\t\t  get_unaligned_be16(&p[2]));\n\tMHVTL_DBG(3, \"  Total byte count         : %d (0x%04x)\",\n\t\t\t  get_unaligned_be32(&p[4]),\n\t\t\t  get_unaligned_be32(&p[4]));\n\n\treturn 8; /* Header is 8 bytes in size.. */\n}\n\n/* Returns address of first available elements from starting number */\nstatic uint32_t find_first_matching_element(struct smc_priv *priv,\n\t\t\t\t\t\t\t\t\t\t\tuint32_t\t\t start,\n\t\t\t\t\t\t\t\t\t\t\tuint8_t\t\t\t type) {\n\tstruct list_head *slot_head;\n\tstruct s_info\t *sp;\n\n\tslot_head = &priv->slot_list;\n\n\tlist_for_each_entry(sp, slot_head, siblings) {\n\t\tif (!type) { /* Element type not defined */\n\t\t\tif (sp->slot_location >= start)\n\t\t\t\treturn sp->slot_location;\n\t\t} else if (sp->element_type == type) {\n\t\t\tif (sp->slot_location >= start)\n\t\t\t\treturn sp->slot_location;\n\t\t}\n\t}\n\treturn 0;\n}\n\n/* Returns number of available elements left from starting number */\nstatic uint32_t num_available_elements(struct smc_priv *priv, uint8_t type,\n\t\t\t\t\t\t\t\t\t   uint32_t start, uint32_t max) {\n\tstruct list_head *slot_head;\n\tstruct s_info\t *sp;\n\tunsigned int\t  counted = 0;\n\n\tslot_head = &priv->slot_list;\n\n\tlist_for_each_entry(sp, slot_head, siblings) {\n\t\tif (!type) { /* Element type not defined */\n\t\t\tif (sp->slot_location >= start)\n\t\t\t\tif (counted < max)\n\t\t\t\t\tcounted++;\n\t\t} else if (sp->element_type == type) {\n\t\t\tif (sp->slot_location >= start)\n\t\t\t\tif (counted < max)\n\t\t\t\t\tcounted++;\n\t\t}\n\t}\n\n\tMHVTL_DBG(2, \"Determining %d element%s of type %s starting at %d\"\n\t\t\t\t \", returning %d\",\n\t\t\t  max, max == 1 ? \"\" : \"s\",\n\t\t\t  slot_type_str(type),\n\t\t\t  start, counted);\n\n\treturn counted;\n}\n\n/*\n * Fill in Element status page header + each Element descriptor\n *\n * uint8_t *p -> Pointer to data buffer address\n * uint16_t start -> Starting slot number\n * uint8_t type -> Slot type\n * uint16_t residual -> Sum of slots already reported on\n *\n * Returns number of bytes in element page(s)\n */\nstatic uint32_t fill_element_page(struct scsi_cmd *cmd, uint8_t *p,\n\t\t\t\t\t\t\t\t  uint16_t start, uint8_t type,\n\t\t\t\t\t\t\t\t  uint16_t residual) {\n\tstruct smc_priv *smc_p;\n\tint\t\t\t\t j;\n\tuint8_t\t\t\t*cdb = cmd->scb;\n\tstruct s_info\t*sp;\n\n\tuint16_t max_count; /* Max element count */\n\tuint32_t avail_count;\n\tuint32_t element_sz;\n\tuint16_t begin_element;\n\tint\t\t slot_count;\n\n\tmax_count = get_unaligned_be16(&cdb[4]);\n\tif (max_count == 0)\n\t\tmax_count = ~0;\n\n\tslot_count = max_count - residual;\n\tif (slot_count <= 0)\n\t\treturn 0; /* No more slots to report on */\n\n\t/* Update max_count to reflect 'sum' value */\n\tmax_count = (uint16_t)slot_count;\n\n\tsmc_p = (struct smc_priv *)cmd->lu->lu_private;\n\n\tMHVTL_DBG(2, \"Query %d element%s starting from addr: %d\"\n\t\t\t\t \" of type: (%d) %s\",\n\t\t\t  max_count,\n\t\t\t  (max_count == 1) ? \"\" : \"s\",\n\t\t\t  start,\n\t\t\t  type, slot_type_str(type));\n\n\t/* Find first valid slot. */\n\tbegin_element = find_first_matching_element(smc_p, start, type);\n\tif (begin_element == 0) {\n\t\tMHVTL_DBG(1, \"Start element is still 0, line %d\", __LINE__);\n\t\treturn 0;\n\t}\n\n\tavail_count = num_available_elements(smc_p, type, start, max_count);\n\n\tMHVTL_DBG(3, \"Available count: %d, type: (%d) %s\",\n\t\t\t  avail_count, type, slot_type_str(type));\n\n\t/* Create Element Status Page Header. */\n\tfill_element_status_page_hdr(cmd, p, avail_count, type);\n\n\t/* Account for the 8 bytes in element status page header */\n\tp += 8;\n\tavail_count = 8; /* Reuse avail_count as available byte count */\n\n\t/* Now loop over each slot and fill in details. */\n\tj = 1;\n\tlist_for_each_entry(sp, &smc_p->slot_list, siblings) {\n\t\tif (sp->slot_location < start)\n\t\t\tcontinue;\n\t\tif (type) {\n\t\t\tif (sp->element_type != type)\n\t\t\t\tcontinue; /* Don't report on this one */\n\t\t} else {\n\t\t\t/* Any type.. Need to fill in one type at a time */\n\t\t\tif (sp->slot_location == start)\n\t\t\t\ttype = sp->element_type;\n\t\t}\n\t\telement_sz = fill_ed(cmd, p, sp);\n\t\tavail_count += element_sz; /* inc byte count */\n\t\tMHVTL_DBG(3, \"Count: %d, max_count: %d, slot: %d, \"\n\t\t\t\t\t \"byte_count: 0x%04x (%d)\",\n\t\t\t\t  j, max_count, sp->slot_location,\n\t\t\t\t  avail_count, avail_count);\n\t\tif (debug)\n\t\t\thex_dump(p, element_sz);\n\t\tp += element_sz; /* inc pointer into dest buf */\n\t\tj++;\n\t\tif (j > max_count)\n\t\t\tbreak;\n\t}\n\n\treturn avail_count;\n}\n\n/*\n * Build READ ELEMENT STATUS data.\n *\n * Returns number of bytes to xfer back to host.\n */\n\n#define NUM_SLOT 4 /* 4 Element types */\n\nuint8_t smc_read_element_status(struct scsi_cmd *cmd) {\n\tstruct smc_priv\t\t*smc_p = (struct smc_priv *)cmd->lu->lu_private;\n\tstruct lu_phy_attr\t*lu\t   = cmd->lu;\n\tuint8_t\t\t\t\t*cdb   = cmd->scb;\n\tuint8_t\t\t\t\t*p;\n\tuint8_t\t\t\t\t*sam_stat = &cmd->dbuf_p->sam_stat;\n\tuint8_t\t\t\t\t type\t  = cdb[1] & 0x0f;\n\tuint16_t\t\t\t sum;\n\tuint16_t\t\t\t req_start_elem;\n\tuint16_t\t\t\t req_number; /* Num of elements initiator requested */\n\tuint32_t\t\t\t alloc_len;\t /* Amount of space initiator has pre alloc */\n\tuint16_t\t\t\t start;\t\t /* First valid slot location */\n\tuint16_t\t\t\t start_any;\t /* First valid slot location - temp count */\n\tuint32_t\t\t\t elem_byte_count;\n\tuint32_t\t\t\t byte_count;\n\tuint32_t\t\t\t cur_count;\n\tstruct s_sd\t\t\t sd;\n\tstruct smc_type_slot type_arr[NUM_SLOT]; /* Hold sorted slot type */\n\tchar\t\t\t\t start_slot_type;\n\tint\t\t\t\t\t i;\n\n#ifdef MHVTL_DEBUG\n\tuint8_t voltag = (cdb[1] & 0x10) >> 4;\n\tuint8_t dvcid; /* Device ID */\n\tif (smc_p->pm->no_dvcid_flag)\n\t\tdvcid = 1;\n\telse\n\t\tdvcid = cmd->scb[6] & 0x01; /* Device ID */\n#endif\n\n\tMHVTL_DBG(1, \"READ ELEMENT STATUS (%ld) **\",\n\t\t\t  (long)cmd->dbuf_p->serialNo);\n\n\treq_start_elem = get_unaligned_be16(&cdb[2]);\n\treq_number\t   = get_unaligned_be16(&cdb[4]);\n\talloc_len\t   = get_unaligned_be24(&cdb[7]);\n\n\tMHVTL_DBG(3, \" Element type(%d) => %s\", type, slot_type_str(type));\n\tMHVTL_DBG(3, \"  Starting Element Address: %d\", req_start_elem);\n\tMHVTL_DBG(3, \"  Number of Elements      : %d\", req_number);\n\tMHVTL_DBG(3, \"  Allocation length       : %d (0x%04x)\",\n\t\t\t  alloc_len, alloc_len);\n\tMHVTL_DBG(3, \"  Device ID: %s, voltag: %s\",\n\t\t\t  (dvcid == 0) ? \"No\" : \"Yes\",\n\t\t\t  (voltag == 0) ? \"No\" : \"Yes\");\n\n\tp = (uint8_t *)cmd->dbuf_p->data;\n\n\t/* Set alloc_len to smallest value */\n\talloc_len = min(alloc_len, smc_p->bufsize);\n\n\tcmd->dbuf_p->sz = 0;\n\n\t/* Init buffer */\n\tmemset(p, 0, alloc_len);\n\n\tif (cdb[11] != 0x0) { /* Reserved byte.. */\n\t\tMHVTL_DBG(2, \"cdb[11] : Illegal value of %02x\", cdb[11]);\n\t\tsd.byte0\t\t = SKSV | CD;\n\t\tsd.field_pointer = 11;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\t/* Find first matching slot number which matches the type. */\n\tstart = find_first_matching_element(smc_p, req_start_elem, type);\n\tif (start == 0) { /* Nothing found.. */\n\t\tMHVTL_DBG(1, \"Start element is still 0, line %d\", __LINE__);\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\t/* Leave room for 'Element Status data' header which is filled in\n\t * after we figure out how many elements to report\n\t */\n\tp += 8;\n\n\t/* Byte count of report available all pages, n-7\n\t * Reference: table 44 6.12.2 smc3r15\n\t * i.e. Don't include 8 byte 'Element Status data' header in the count\n\t */\n\telem_byte_count = 0;\n\n\tsum = 0; /* keep track of number of elements already reported */\n\n\tswitch (type) {\n\tcase MEDIUM_TRANSPORT:\n\tcase STORAGE_ELEMENT:\n\tcase MAP_ELEMENT:\n\tcase DATA_TRANSFER:\n\t\telem_byte_count += fill_element_page(cmd, p, start, type, sum);\n\t\tbreak;\n\tcase ANY:\n\t\t/* Don't modify 'start' value as it is needed later */\n\t\tstart_any\t\t= start;\n\t\tstart_slot_type = slot_type(smc_p, start_any);\n\t\tsort_library_slot_type(lu, &type_arr[0]);\n\n\t\t/* Find out where we are up to */\n\t\tfor (i = 0; i < NUM_SLOT; i++) {\n\t\t\tMHVTL_DBG(2, \"Testing type %d with %d\",\n\t\t\t\t\t  type_arr[i].type, start_slot_type);\n\t\t\tif (type_arr[i].type == start_slot_type)\n\t\t\t\tbreak;\n\t\t}\n\t\tif (i >= NUM_SLOT) { /* Not found in above for loop */\n\t\t\tMHVTL_ERR(\"Couldn't find starting slot type !!\");\n\t\t\tsd.byte0\t\t = SKSV | CD;\n\t\t\tsd.field_pointer = 3;\n\t\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd,\n\t\t\t\t\t\t\t\tsam_stat);\n\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t}\n\n\t\tMHVTL_DBG(3, \"All element type: Starting at %d\", start_any);\n\t\tfor (; i < NUM_SLOT; i++) {\n\t\t\tMHVTL_DBG(3, \"i: %d, type_arr[i].type: (%d) %s, \"\n\t\t\t\t\t\t \"type_arr[i].start: %d\",\n\t\t\t\t\t  i, type_arr[i].type,\n\t\t\t\t\t  slot_type_str(type_arr[i].type),\n\t\t\t\t\t  type_arr[i].start);\n\n\t\t\tbyte_count = fill_element_page(cmd, p, start_any,\n\t\t\t\t\t\t\t\t\t\t   type_arr[i].type, sum);\n\t\t\telem_byte_count += byte_count;\n\t\t\tp += byte_count;\n\t\t\tsum += byte_count /\n\t\t\t\t   sizeof_element(cmd, type_arr[i].type);\n\n\t\t\tif (i < NUM_SLOT - 1) /* Next slot type number */\n\t\t\t\tstart_any = type_arr[i + 1].start;\n\t\t}\n\t\tbreak;\n\tdefault: /* Illegal descriptor type. */\n\t\tsd.byte0\t\t = SKSV | CD;\n\t\tsd.field_pointer = 1;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\tbreak;\n\t}\n\n\tcur_count = num_available_elements(smc_p, type, start, req_number);\n\n\t/* Now populate the 'main' header structure with byte count.. */\n\tfill_element_status_data_hdr(cmd->dbuf_p->data, start, cur_count,\n\t\t\t\t\t\t\t\t elem_byte_count);\n\n#ifdef MHVTL_DEBUG\n\tif (debug)\n\t\thex_dump(cmd->dbuf_p->data, elem_byte_count);\n#endif\n\n\tif (verbose > 2)\n\t\tdecode_element_status(smc_p, cmd->dbuf_p->data);\n\n\tcmd->dbuf_p->sz = min(elem_byte_count + 8, alloc_len);\n\n\tMHVTL_DBG(2, \"Element count: %d, Elem byte count: %d (0x%04x),\"\n\t\t\t\t \" alloc_len: %d, returning %d\",\n\t\t\t  cur_count,\n\t\t\t  elem_byte_count, elem_byte_count,\n\t\t\t  alloc_len, cmd->dbuf_p->sz);\n\n\treturn SAM_STAT_GOOD;\n}\n\n/* Expect a response from tape drive on load success/failure\n * Returns 0 on success\n * non-zero on load failure\n\n * FIXME: I really need a timeout here..\n */\nstatic int check_tape_load(void) {\n\tint\t\t\t   mlen, r_qid;\n\tstruct q_entry q;\n\n\t/* Initialise message queue as necessary */\n\tr_qid = init_queue();\n\tif (r_qid == -1) {\n\t\tprintf(\"Could not initialise message queue\\n\");\n\t\texit(1);\n\t}\n\n\tmlen = msgrcv(r_qid, &q, MAXOBN, my_id, MSG_NOERROR);\n\tif (mlen > 0)\n\t\tMHVTL_DBG(1, \"%ld: Received \\\"%s\\\" from snd_id %ld\",\n\t\t\t\t  my_id,\n\t\t\t\t  q.msg.text,\n\t\t\t\t  q.msg.snd_id);\n\n\t/* msg defined in q.h */\n\treturn strncmp(msg_load_ok, q.msg.text, strlen(msg_load_ok));\n}\n\n/*\n * Logically move information from 'src' address to 'dest' address\n */\nstatic void move_cart(struct s_info *src, struct s_info *dest) {\n\n\tdest->media = src->media;\n\n\tdest->last_location\t\t   = src->slot_location;\n\tdest->media->last_location = src->slot_location;\n\n\tsetSlotFull(dest);\n\tif (is_map_slot(dest))\n\t\tsetImpExpStatus(dest, ROBOT_ARM); /* Placed by robot arm */\n\n\tsrc->media\t\t   = NULL;\n\tsrc->last_location = 0; /* Forget where the old media was */\n\tsetSlotEmpty(src);\t\t/* Clear Full bit */\n\tMHVTL_DBG(1, \"Setting src slot access true\");\n\tsetAccessStatus(src, 1); /* Set the access bit now it's empty */\n}\n\nstatic int run_move_command(struct smc_priv *smc_p, struct s_info *src,\n\t\t\t\t\t\t\tstruct s_info *dest, uint8_t *sam_stat) {\n\tchar *movecommand;\n\tchar  barcode[MAX_BARCODE_LEN + 1];\n\tint\t  res = 0;\n\tint\t  cmdlen;\n\n\tif (!smc_p->movecommand) {\n\t\t/* no command: do nothing */\n\t\treturn SAM_STAT_GOOD;\n\t}\n\n\tcmdlen\t\t= strlen(smc_p->movecommand) + MAX_BARCODE_LEN + 4 * 10;\n\tmovecommand = zalloc(cmdlen + 1);\n\n\tif (!movecommand) {\n\t\tMHVTL_ERR(\"malloc failed\");\n\t\tsam_hardware_error(E_MANUAL_INTERVENTION_REQ, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tsprintf(barcode, \"%s\", src->media->barcode);\n\ttruncate_spaces(&barcode[0], MAX_BARCODE_LEN + 1);\n\tsnprintf(movecommand, cmdlen, \"%s %s %d %s %d %s\",\n\t\t\t smc_p->movecommand,\n\t\t\t slot_type_str(src->element_type),\n\t\t\t slot_number(smc_p->pm, src),\n\t\t\t slot_type_str(dest->element_type),\n\t\t\t slot_number(smc_p->pm, dest),\n\t\t\t barcode);\n\tMHVTL_DBG(3, \"Calling external script: %s\", movecommand);\n\tres = run_command(movecommand, smc_p->commandtimeout);\n\tif (res) {\n\t\tMHVTL_ERR(\"move command returned %d\", res);\n\t\tsam_hardware_error(E_MANUAL_INTERVENTION_REQ, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\treturn SAM_STAT_GOOD;\n}\n\nstatic int move_slot2drive(struct smc_priv *smc_p,\n\t\t\t\t\t\t   int src_addr, int dest_addr, uint8_t *sam_stat) {\n\tstruct s_info *src;\n\tstruct d_info *dest;\n\tchar\t\t   cmd[MAX_BARCODE_LEN + 12];\n\tint\t\t\t   retval;\n\n\tcurrent_state = MHVTL_STATE_MOVING_SLOT_2_DRIVE;\n\n\tsrc\t = slot2struct(smc_p, src_addr);\n\tdest = drive2struct(smc_p, dest_addr);\n\n\tif (!slotOccupied(src)) {\n\t\tsam_illegal_request(E_MEDIUM_SRC_EMPTY, NULL, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\tif (driveOccupied(dest)) {\n\t\tsam_illegal_request(E_MEDIUM_DEST_FULL, NULL, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\tif (src->element_type == MAP_ELEMENT) {\n\t\tif (!map_access_ok(smc_p, src)) {\n\t\t\tMHVTL_DBG(2, \"SOURCE MAP port not accessable\");\n\t\t\tsam_not_ready(E_MAP_OPEN, sam_stat);\n\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t}\n\t}\n\n\t/* Call any external cmd first before changing state */\n\tretval = run_move_command(smc_p, src, dest->slot, sam_stat);\n\tif (retval)\n\t\treturn retval;\n\n\tsprintf(cmd, \"lload %s\", src->media->barcode);\n\t/* Remove traling spaces */\n\ttruncate_spaces(&cmd[6], MAX_BARCODE_LEN + 1);\n\n\t/* FIXME: About here would be a good spot to create any 'missing'\n\t *\t  media. That way, the user would not have to pre-create\n\t *\t  media.\n\t */\n\n\tMHVTL_DBG(1, \"About to send cmd: \\'%s\\' to drive %d\",\n\t\t\t  cmd, slot_number(smc_p->pm, dest->slot));\n\n\tsend_msg(cmd, dest->drv_id);\n\n\tif (!smc_p->state_msg)\n\t\tsmc_p->state_msg = (char *)zalloc(DEF_SMC_PRIV_STATE_MSG_LENGTH);\n\tif (smc_p->state_msg) {\n\t\t/* Re-use 'cmd[]' var */\n\t\tsnprintf(cmd, sizeof(cmd), \"%s\", src->media->barcode);\n\t\ttruncate_spaces(&cmd[0], MAX_BARCODE_LEN + 1);\n\n\t\tsnprintf(smc_p->state_msg, DEF_SMC_PRIV_STATE_MSG_LENGTH,\n\t\t\t\t \"Moving %s from %s slot %d to drive %d\",\n\t\t\t\t cmd,\n\t\t\t\t slot_type_str(src->element_type),\n\t\t\t\t slot_number(smc_p->pm, src),\n\t\t\t\t slot_number(smc_p->pm, dest->slot));\n\t}\n\n\tif (check_tape_load()) {\n\t\tMHVTL_ERR(\"Load of %s into drive %d failed\",\n\t\t\t\t  cmd, slot_number(smc_p->pm, dest->slot));\n\t\tsam_hardware_error(E_MANUAL_INTERVENTION_REQ, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tmove_cart(src, dest->slot);\n\tsetDriveFull(dest);\n\t/* Set the 'Access bit' to zero - i.e. the picker arm can't access it */\n\tsetAccessStatus(dest->slot, 0);\n\n\treturn retval;\n}\n\nstatic int move_slot2slot(struct smc_priv *smc_p, int src_addr,\n\t\t\t\t\t\t  int dest_addr, uint8_t *sam_stat) {\n\tstruct s_info *src;\n\tstruct s_info *dest;\n\tchar\t\t   cmd[MAX_BARCODE_LEN + 1];\n\tint\t\t\t   retval;\n\n\tcurrent_state = MHVTL_STATE_MOVING_SLOT_2_SLOT;\n\n\tsrc\t = slot2struct(smc_p, src_addr);\n\tdest = slot2struct(smc_p, dest_addr);\n\n\tMHVTL_DBG(1, \"Moving from %s slot %d to %s slot %d\",\n\t\t\t  slot_type_str(src->element_type),\n\t\t\t  src->slot_location,\n\t\t\t  slot_type_str(dest->element_type),\n\t\t\t  dest->slot_location);\n\n\tif (!slotOccupied(src)) {\n\t\tsam_illegal_request(E_MEDIUM_SRC_EMPTY, NULL, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\tif (slotOccupied(dest)) {\n\t\tsam_illegal_request(E_MEDIUM_DEST_FULL, NULL, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tif (src->element_type == MAP_ELEMENT) {\n\t\tif (!map_access_ok(smc_p, src)) {\n\t\t\tMHVTL_DBG(2, \"SOURCE MAP port not accessable\");\n\t\t\tsam_not_ready(E_MAP_OPEN, sam_stat);\n\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t}\n\t}\n\n\tif (dest->element_type == MAP_ELEMENT) {\n\t\tif (!map_access_ok(smc_p, dest)) {\n\t\t\tMHVTL_DBG(2, \"DESTINATION MAP port not accessable\");\n\t\t\tsam_not_ready(E_MAP_OPEN, sam_stat);\n\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t}\n\t}\n\n\tif (!smc_p->state_msg)\n\t\tsmc_p->state_msg = zalloc(DEF_SMC_PRIV_STATE_MSG_LENGTH);\n\tif (smc_p->state_msg) {\n\t\tsnprintf(cmd, sizeof(cmd), \"%s\", src->media->barcode);\n\t\ttruncate_spaces(&cmd[0], MAX_BARCODE_LEN + 1);\n\t\tsnprintf(smc_p->state_msg, DEF_SMC_PRIV_STATE_MSG_LENGTH,\n\t\t\t\t \"Moving %s from %s slot %d to %s slot %d\",\n\t\t\t\t cmd,\n\t\t\t\t slot_type_str(src->element_type),\n\t\t\t\t slot_number(smc_p->pm, src),\n\t\t\t\t slot_type_str(dest->element_type),\n\t\t\t\t slot_number(smc_p->pm, dest));\n\t}\n\n\tretval = run_move_command(smc_p, src, dest, sam_stat);\n\tif (retval)\n\t\treturn retval;\n\tmove_cart(src, dest);\n\treturn retval;\n}\n\n/* Return OK if 'addr' is within either a MAP, Drive or Storage slot */\nstatic int valid_slot(struct smc_priv *smc_p, int addr) {\n\tstruct s_info *slt;\n\tstruct d_info *drv;\n\n\tMHVTL_DBG(3, \"%s slot %d\", slot_type_str(slot_type(smc_p, addr)), addr);\n\tswitch (slot_type(smc_p, addr)) {\n\tcase STORAGE_ELEMENT:\n\tcase MAP_ELEMENT:\n\t\tslt = slot2struct(smc_p, addr);\n\t\tif (slt)\n\t\t\treturn TRUE; /* slot, return true */\n\t\tbreak;\n\tcase DATA_TRANSFER:\n\t\tdrv = drive2struct(smc_p, addr);\n\t\tif (!drv) {\n\t\t\tMHVTL_DBG(1, \"No target drive %d in device.conf\", addr);\n\t\t\treturn FALSE; /* No drive, return false */\n\t\t}\n\t\tif (drv->drv_id) {\n\t\t\tMHVTL_DBG(3, \"Found drive id: %d\", (int)drv->drv_id);\n\t\t\treturn TRUE; /* Found a drive ID */\n\t\t} else {\n\t\t\tMHVTL_ERR(\"No drive in slot: %d\", addr);\n\t\t}\n\t\tbreak;\n\t}\n\treturn FALSE;\n}\n\nstatic int move_drive2slot(struct smc_priv *smc_p,\n\t\t\t\t\t\t   int src_addr, int dest_addr, uint8_t *sam_stat) {\n\tchar\t\t   cmd[MAX_BARCODE_LEN + 1 + 12]; /* 12 being the longest msg string */\n\tstruct d_info *src;\n\tstruct s_info *dest;\n\tint\t\t\t   retval;\n\n\tcurrent_state = MHVTL_STATE_MOVING_DRIVE_2_SLOT;\n\n\tsrc\t = drive2struct(smc_p, src_addr);\n\tdest = slot2struct(smc_p, dest_addr);\n\n\tif (!driveOccupied(src)) {\n\t\tsam_illegal_request(E_MEDIUM_SRC_EMPTY, NULL, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\tif (slotOccupied(dest)) {\n\t\tsam_illegal_request(E_MEDIUM_DEST_FULL, NULL, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tif (dest->element_type == MAP_ELEMENT) {\n\t\tif (!map_access_ok(smc_p, dest)) {\n\t\t\tsam_not_ready(E_MAP_OPEN, sam_stat);\n\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t}\n\t}\n\n\t/* Send any external command before any changes here */\n\tretval = run_move_command(smc_p, src->slot, dest, sam_stat);\n\tif (retval)\n\t\treturn retval;\n\n\t/* Send 'unload' message to drive b4 the move.. If not already unloaded */\n\tif (!slotAccess(src->slot)) {\n\t\tsprintf(cmd, \"unload %s\", src->slot->media->barcode);\n\t\tsend_msg(cmd, src->drv_id);\n\t\t/* Now we wait for the tape device to respond with status of unload */\n\t\tif (check_tape_unload()) {\n\t\t\tMHVTL_ERR(\"Unload of %s from drive %d failed\",\n\t\t\t\t\t  cmd, slot_number(smc_p->pm, src->slot));\n\t\t\tsam_hardware_error(E_MANUAL_INTERVENTION_REQ, sam_stat);\n\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t}\n\t}\n\n\tif (!smc_p->state_msg)\n\t\tsmc_p->state_msg = zalloc(DEF_SMC_PRIV_STATE_MSG_LENGTH);\n\tif (smc_p->state_msg) {\n\t\tsnprintf(cmd, sizeof(cmd), \"%s\", src->slot->media->barcode);\n\t\ttruncate_spaces(&cmd[0], MAX_BARCODE_LEN + 1);\n\t\tsnprintf(smc_p->state_msg, DEF_SMC_PRIV_STATE_MSG_LENGTH,\n\t\t\t\t \"Moving %s from drive %d to %s slot %d\",\n\t\t\t\t cmd,\n\t\t\t\t slot_number(smc_p->pm, src->slot),\n\t\t\t\t slot_type_str(dest->element_type),\n\t\t\t\t slot_number(smc_p->pm, dest));\n\t}\n\n\tmove_cart(src->slot, dest);\n\tsetDriveEmpty(src);\n\n\treturn retval;\n}\n\n/* Move media in drive 'src_addr' to drive 'dest_addr' */\nstatic int move_drive2drive(struct smc_priv *smc_p,\n\t\t\t\t\t\t\tint src_addr, int dest_addr, uint8_t *sam_stat) {\n\tstruct d_info *src;\n\tstruct d_info *dest;\n\tchar\t\t   cmd[MAX_BARCODE_LEN + 12];\n\tint\t\t\t   retval;\n\n\tcurrent_state = MHVTL_STATE_MOVING_DRIVE_2_DRIVE;\n\n\tsrc\t = drive2struct(smc_p, src_addr);\n\tdest = drive2struct(smc_p, dest_addr);\n\n\tif (src_addr == dest_addr) {\n\t\t/* Did not find documentation for this behavior but feels like it should not fail */\n\t\tMHVTL_DBG(1, \"Same source and destination address : %d : do nothing\", src_addr);\n\t\treturn SAM_STAT_GOOD;\n\t}\n\n\tif (!driveOccupied(src)) {\n\t\tsam_illegal_request(E_MEDIUM_SRC_EMPTY, NULL, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\tif (driveOccupied(dest)) {\n\t\tsam_illegal_request(E_MEDIUM_DEST_FULL, NULL, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\t/* Execute any external commands before changing state */\n\tretval = run_move_command(smc_p, src->slot, dest->slot, sam_stat);\n\tif (retval)\n\t\treturn retval;\n\n\t/* Send 'unload' message to drive b4 the move.. */\n\tMHVTL_DBG(2, \"Unloading %s from drive %d\",\n\t\t\t  src->slot->media->barcode,\n\t\t\t  slot_number(smc_p->pm, src->slot));\n\n\tsprintf(cmd, \"unload %s\", src->slot->media->barcode);\n\tsend_msg(cmd, src->drv_id);\n\t/* Now we wait for the tape device to respond with status of unload */\n\tif (check_tape_unload()) {\n\t\tMHVTL_ERR(\"Failed to unload tape from drive %d\",\n\t\t\t\t  slot_number(smc_p->pm, src->slot));\n\t\tsam_hardware_error(E_MANUAL_INTERVENTION_REQ, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tmove_cart(src->slot, dest->slot);\n\tsetDriveEmpty(src);\n\n\tsprintf(cmd, \"lload %s\", dest->slot->media->barcode);\n\n\ttruncate_spaces(&cmd[6], MAX_BARCODE_LEN + 1);\n\tMHVTL_DBG(2, \"Sending cmd: \\'%s\\' to drive %d\",\n\t\t\t  cmd, slot_number(smc_p->pm, dest->slot));\n\n\tsend_msg(cmd, dest->drv_id);\n\n\tif (check_tape_load()) {\n\t\t/* Failed, so put the tape back where it came from */\n\t\tMHVTL_ERR(\"Failed to move to drive %d, \"\n\t\t\t\t  \"placing back into drive %d\",\n\t\t\t\t  slot_number(smc_p->pm, dest->slot),\n\t\t\t\t  slot_number(smc_p->pm, src->slot));\n\t\tmove_cart(dest->slot, src->slot);\n\t\tsprintf(cmd, \"lload %s\", src->slot->media->barcode);\n\t\ttruncate_spaces(&cmd[6], MAX_BARCODE_LEN + 1);\n\t\tsend_msg(cmd, src->drv_id);\n\t\tcheck_tape_load();\n\t\tsam_hardware_error(E_MANUAL_INTERVENTION_REQ, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tif (!smc_p->state_msg)\n\t\tsmc_p->state_msg = zalloc(DEF_SMC_PRIV_STATE_MSG_LENGTH);\n\tif (smc_p->state_msg) {\n\t\t/* Re-use 'cmd[]' var */\n\t\tsnprintf(cmd, sizeof(cmd), \"%s\", dest->slot->media->barcode);\n\t\ttruncate_spaces(&cmd[0], MAX_BARCODE_LEN + 1);\n\t\tsnprintf(smc_p->state_msg, DEF_SMC_PRIV_STATE_MSG_LENGTH,\n\t\t\t\t \"Moving %s from drive %d to drive %d\",\n\t\t\t\t cmd,\n\t\t\t\t slot_number(smc_p->pm, src->slot),\n\t\t\t\t slot_number(smc_p->pm, dest->slot));\n\t}\n\n\t/* Set the 'Access bit' to zero - i.e. the picker arm can't access it */\n\tsetAccessStatus(dest->slot, 0);\n\n\treturn retval;\n}\n\n/* Move a piece of medium from one slot to another */\nuint8_t smc_move_medium(struct scsi_cmd *cmd) {\n\tuint8_t\t\t\t*cdb\t  = cmd->scb;\n\tuint8_t\t\t\t*sam_stat = &cmd->dbuf_p->sam_stat;\n\tint\t\t\t\t transport_addr;\n\tint\t\t\t\t src_addr, src_type;\n\tint\t\t\t\t dest_addr, dest_type;\n\tint\t\t\t\t retval = SAM_STAT_GOOD;\n\tstruct smc_priv *smc_p\t= cmd->lu->lu_private;\n\tstruct s_sd\t\t sd;\n\n\tMHVTL_DBG(1, \"MOVE MEDIUM (%ld) **\", (long)cmd->dbuf_p->serialNo);\n\n\ttransport_addr = get_unaligned_be16(&cdb[2]);\n\tsrc_addr\t   = get_unaligned_be16(&cdb[4]);\n\tdest_addr\t   = get_unaligned_be16(&cdb[6]);\n\tsrc_type\t   = slot_type(smc_p, src_addr);\n\tdest_type\t   = slot_type(smc_p, dest_addr);\n\n\tif (cdb[11] & 0xc0) {\n\t\tMHVTL_DBG(1, \"%s\",\n\t\t\t\t  (cdb[11] & 0x80) ? \"  Retract I/O port\" : \"  Extend I/O port\");\n\t} else {\n\t\tMHVTL_DBG(1,\n\t\t\t\t  \"Moving from slot %d to slot %d using transport %d, Invert media: %s\",\n\t\t\t\t  src_addr, dest_addr, transport_addr,\n\t\t\t\t  (cdb[10]) ? \"yes\" : \"no\");\n\t}\n\n\tif (cdb[10] != 0) { /* Can not Invert media */\n\t\tMHVTL_ERR(\"Can not invert media\");\n\t\tsd.byte0\t\t = SKSV | CD;\n\t\tsd.field_pointer = 10;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\tif (cdb[11] == 0xc0) { /* Invalid combo of Extend/retract I/O port */\n\t\tMHVTL_ERR(\"Extend/retract I/O port invalid\");\n\t\tsd.byte0\t\t = SKSV | CD;\n\t\tsd.field_pointer = 11;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\tif (cdb[11]) /* Must be an Extend/Retract I/O port cdb.. NO-OP */\n\t\treturn SAM_STAT_GOOD;\n\n\tif (transport_addr == 0)\n\t\ttransport_addr = smc_p->pm->start_picker;\n\tif (slot_type(smc_p, transport_addr) != MEDIUM_TRANSPORT) {\n\t\tMHVTL_ERR(\"Can't move media using slot type %d\",\n\t\t\t\t  slot_type(smc_p, transport_addr));\n\t\tsd.byte0\t\t = SKSV | CD;\n\t\tsd.field_pointer = 2;\n\t\tsam_illegal_request(E_INVALID_ELEMENT_ADDR, &sd, sam_stat);\n\t\tretval = SAM_STAT_CHECK_CONDITION;\n\t}\n\tif (!valid_slot(smc_p, src_addr)) {\n\t\tMHVTL_ERR(\"Invalid source slot: %d\", src_addr);\n\t\tsd.byte0\t\t = SKSV | CD;\n\t\tsd.field_pointer = 4;\n\t\tsam_illegal_request(E_INVALID_ELEMENT_ADDR, &sd, sam_stat);\n\t\tretval = SAM_STAT_CHECK_CONDITION;\n\t}\n\tif (!valid_slot(smc_p, dest_addr)) {\n\t\tMHVTL_ERR(\"Invalid dest slot: %d\", dest_addr);\n\t\tsd.byte0\t\t = SKSV | CD;\n\t\tsd.field_pointer = 6;\n\t\tsam_illegal_request(E_INVALID_ELEMENT_ADDR, &sd, sam_stat);\n\t\tretval = SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tif (retval == SAM_STAT_GOOD) {\n\t\tif (src_type == DATA_TRANSFER && dest_type == DATA_TRANSFER) {\n\t\t\t/* Move between drives */\n\t\t\tretval = move_drive2drive(smc_p, src_addr, dest_addr,\n\t\t\t\t\t\t\t\t\t  sam_stat);\n\t\t} else if (src_type == DATA_TRANSFER) {\n\t\t\tretval = move_drive2slot(smc_p, src_addr, dest_addr,\n\t\t\t\t\t\t\t\t\t sam_stat);\n\t\t} else if (dest_type == DATA_TRANSFER) {\n\t\t\tretval = move_slot2drive(smc_p, src_addr, dest_addr,\n\t\t\t\t\t\t\t\t\t sam_stat);\n\t\t} else { /* Move between (non-drive) slots */\n\t\t\tretval = move_slot2slot(smc_p, src_addr, dest_addr,\n\t\t\t\t\t\t\t\t\tsam_stat);\n\t\t}\n\t}\n\n\treturn retval;\n}\n\nuint8_t smc_rezero(struct scsi_cmd *cmd) {\n\tMHVTL_DBG(1, \"REZERO (%ld) **\", (long)cmd->dbuf_p->serialNo);\n\n\tif (!cmd->lu->online) {\n\t\tsam_not_ready(NO_ADDITIONAL_SENSE, &cmd->dbuf_p->sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\tsleep(1);\n\treturn SAM_STAT_GOOD;\n}\n\nuint8_t smc_open_close_import_export_element(struct scsi_cmd *cmd) {\n\tuint8_t\t\t\t*cdb\t  = cmd->scb;\n\tstruct smc_priv *smc_p\t  = cmd->lu->lu_private;\n\tuint8_t\t\t\t*sam_stat = &cmd->dbuf_p->sam_stat;\n\tint\t\t\t\t addr;\n\tint\t\t\t\t action_code;\n\tstruct s_sd\t\t sd;\n\n\tMHVTL_DBG(1, \"OPEN/CLOSE IMPORT/EXPORT ELEMENT (%ld) **\",\n\t\t\t  (long)cmd->dbuf_p->serialNo);\n\n\taddr\t\t= get_unaligned_be16(&cdb[2]);\n\taction_code = cdb[4] & 0x1f;\n\tMHVTL_DBG(2, \"addr: %d action_code: %d\", addr, action_code);\n\n\tif (slot_type(smc_p, addr) != MAP_ELEMENT) {\n\t\tsam_illegal_request(E_INVALID_ELEMENT_ADDR, NULL, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\tswitch (action_code) {\n\tcase 0: /* open */\n\t\tif (smc_p->cap_closed == CAP_CLOSED) {\n\t\t\tMHVTL_DBG(2, \"opening CAP\");\n\t\t\tsmc_p->cap_closed = CAP_OPEN;\n\t\t}\n\t\tbreak;\n\tcase 1: /* close */\n\t\tif (smc_p->cap_closed == CAP_OPEN) {\n\t\t\tMHVTL_DBG(2, \"closing CAP\");\n\t\t\tsmc_p->cap_closed = CAP_CLOSED;\n\t\t}\n\t\tbreak;\n\tdefault:\n\t\tMHVTL_DBG(1, \"unknown action code: %d\", action_code);\n\t\tsd.byte0\t\t = SKSV | CD;\n\t\tsd.field_pointer = 4;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\tbreak;\n\t}\n\n\treturn SAM_STAT_GOOD;\n}\n\nuint8_t smc_log_sense(struct scsi_cmd *cmd) {\n\tstruct lu_phy_attr *lu;\n\tuint8_t\t\t\t   *b\t= cmd->dbuf_p->data;\n\tuint8_t\t\t\t   *cdb = cmd->scb;\n\tuint8_t\t\t\t   *sam_stat;\n\tint\t\t\t\t\tretval;\n\tint\t\t\t\t\ti;\n\tuint16_t\t\t\talloc_len;\n\tstruct list_head   *l_head;\n\tstruct log_pg_list *l;\n\tstruct s_sd\t\t\tsd;\n\n\tMHVTL_DBG(1, \"LOG SENSE (%ld) **\", (long)cmd->dbuf_p->serialNo);\n\n\talloc_len\t\t= get_unaligned_be16(&cdb[7]);\n\tcmd->dbuf_p->sz = alloc_len;\n\n\tlu\t\t = cmd->lu;\n\tsam_stat = &cmd->dbuf_p->sam_stat;\n\tl_head\t = &lu->log_pg;\n\tretval\t = 0;\n\n\tswitch (cdb[2] & 0x3f) {\n\tcase 0: /* Send supported pages */\n\t\tMHVTL_DBG(1, \"LOG SENSE: Sending supported pages\");\n\t\tmemset(b, 0, 4); /* Clear first few (4) bytes */\n\t\ti\t   = 4;\n\t\tb[i++] = 0; /* b[0] is log page '0' (this one) */\n\t\tlist_for_each_entry(l, l_head, siblings) {\n\t\t\tMHVTL_DBG(3, \"found page 0x%02x\", l->log_page_num);\n\t\t\tb[i] = l->log_page_num;\n\t\t\ti++;\n\t\t}\n\t\tput_unaligned_be16(i - 4, &b[2]);\n\t\tretval = i;\n\t\tbreak;\n\tcase TEMPERATURE_PAGE: /* Temperature page */\n\t\tMHVTL_DBG(1, \"LOG SENSE: Temperature page\");\n\t\tl = lookup_log_pg(&lu->log_pg, TEMPERATURE_PAGE, NO_SUBPAGE);\n\t\tif (!l)\n\t\t\tgoto log_page_not_found;\n\n\t\tb\t   = memcpy(b, l->p, l->size);\n\t\tretval = l->size;\n\t\tbreak;\n\tcase TAPE_ALERT: /* TapeAlert page */\n\t\tMHVTL_DBG(1, \"LOG SENSE: TapeAlert page\");\n\t\t/*\t\tMHVTL_DBG(2, \" Returning TapeAlert flags: 0x%\" PRIx64,\n\t\t\t\t\t\tget_unaligned_be64(&SequentialAccessDevice_pg.TapeAlert));\n\t\t*/\n\n\t\tl = lookup_log_pg(&lu->log_pg, TAPE_ALERT, NO_SUBPAGE);\n\t\tif (!l)\n\t\t\tgoto log_page_not_found;\n\n\t\tb\t   = memcpy(b, l->p, l->size);\n\t\tretval = l->size;\n\n\t\t/* Clear flags after value read. */\n\t\tif (alloc_len > 4)\n\t\t\tupdate_TapeAlert(TA_NONE);\n\t\telse\n\t\t\tMHVTL_DBG(1, \"TapeAlert : Alloc len short -\"\n\t\t\t\t\t\t \" Not clearing TapeAlert flags.\");\n\t\tbreak;\n\tdefault:\n\t\tMHVTL_DBG(1, \"LOG SENSE: Unknown code: 0x%x\", cdb[2] & 0x3f);\n\t\tgoto log_page_not_found;\n\t\tbreak;\n\t}\n\tcmd->dbuf_p->sz = retval;\n\n\treturn SAM_STAT_GOOD;\n\nlog_page_not_found:\n\tcmd->dbuf_p->sz\t = 0;\n\tsd.byte0\t\t = SKSV | CD;\n\tsd.field_pointer = 2;\n\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\treturn SAM_STAT_CHECK_CONDITION;\n}\n\nvoid unload_drive_on_shutdown(struct s_info *src, struct s_info *dest) {\n\tif (!dest)\n\t\treturn;\n\n\tMHVTL_DBG(1, \"Force unload of media %s to slot %d\",\n\t\t\t  src->media->barcode, dest->slot_location);\n\tmove_cart(src, dest);\n}\n"
  },
  {
    "path": "usr/spc.c",
    "content": "/*\n * This handles any SCSI OP codes defined in the standards as 'PRIMARY'\n *\n * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n * See comments in vtltape.c for a more complete version release...\n *\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <inttypes.h>\n#include <assert.h>\n#include \"be_byteshift.h\"\n#include \"mhvtl_scsi.h\"\n#include \"vtl_common.h\"\n#include \"vtllib.h\"\n#include \"logging.h\"\n#include \"ssc.h\"\n\nextern unsigned char sense[];\n\nuint32_t SPR_Reservation_Generation;\nuint8_t\t SPR_Reservation_Type;\nuint64_t SPR_Reservation_Key;\n\nstruct vpd *alloc_vpd(uint16_t sz) {\n\tstruct vpd *vpd_pg;\n\n\tvpd_pg = zalloc(sizeof(struct vpd));\n\tif (!vpd_pg) {\n\t\tMHVTL_ERR(\"Could not malloc %d bytes of mem\",\n\t\t\t\t  (int)sizeof(struct vpd));\n\t\treturn NULL;\n\t}\n\tvpd_pg->data = zalloc(sz);\n\tif (!vpd_pg->data) {\n\t\tMHVTL_ERR(\"Could not malloc %d bytes of mem\", sz);\n\t\tfree(vpd_pg);\n\t\treturn NULL;\n\t}\n\tvpd_pg->sz = sz;\n\n\treturn vpd_pg;\n}\n\nvoid dealloc_vpd(struct vpd *pg) {\n\tfree(pg->data);\n\tfree(pg);\n}\n\nuint8_t spc_inquiry(struct scsi_cmd *cmd) {\n\tint\t\t\t\t\tlen = 0;\n\tstruct vpd\t\t   *vpd_pg;\n\tuint8_t\t\t\t   *data\t = (uint8_t *)cmd->dbuf_p->data;\n\tuint8_t\t\t\t   *cdb\t\t = cmd->scb;\n\tuint8_t\t\t\t   *sam_stat = &cmd->dbuf_p->sam_stat;\n\tstruct lu_phy_attr *lu\t\t = cmd->lu;\n\tstruct s_sd\t\t\tsd;\n\n\tMHVTL_DBG(1, \"INQUIRY ** (%ld)\", (long)cmd->dbuf_p->serialNo);\n\n\tif (((cdb[1] & 0x3) == 0x3) || (!(cdb[1] & 0x3) && cdb[2])) {\n\t\tsd.byte0\t\t = SKSV | CD;\n\t\tsd.field_pointer = 1;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tif (cdb[1] & 0x3) { /* VPD bit set - clear memory */\n\t\tmemset(data, 0, MAX_INQUIRY_SZ);\n\t} else { /* Standard inquiry - copy in-mem data struct */\n\t\tmemcpy(cmd->dbuf_p->data, lu->inquiry, MAX_INQUIRY_SZ);\n\t\tlen = lu->inquiry[4] + 5;\n\t}\n\tif (cdb[1] & 0x2) {\n\t\t/* CmdDt bit is set */\n\t\t/* We do not support it now. */\n\t\tdata[1] = 0x1;\n\t\tdata[5] = 0;\n\t\tlen\t\t= 6;\n\n\t} else if (cdb[1] & 0x1) { /* VPD */\n\t\tuint8_t pcode = cdb[2];\n\n\t\tMHVTL_DBG(2, \"VPD Page code 0x%02x\", pcode);\n\n\t\tif (pcode == 0x00) {\n\t\t\tuint8_t\t\t*p;\n\t\t\tunsigned int i, cnt;\n\n\t\t\tdata[0] = lu->ptype;\n\t\t\tdata[1] = 0;\n\t\t\tdata[2] = 0;\n\n\t\t\tcnt = 1;\n\t\t\tp\t= data + 5;\n\t\t\tfor (i = 0; i < ARRAY_SIZE(lu->lu_vpd); i++) {\n\t\t\t\tif (lu->lu_vpd[i]) {\n\t\t\t\t\t*p++ = i | 0x80;\n\t\t\t\t\tcnt++;\n\t\t\t\t}\n\t\t\t}\n\t\t\tdata[3] = cnt;\n\t\t\tdata[4] = 0x0;\n\t\t\tlen\t\t= cnt + 4;\n\t\t\thex_dump(data, len);\n\t\t} else if (lu->lu_vpd[PCODE_OFFSET(pcode)]) {\n\t\t\tvpd_pg = lu->lu_vpd[PCODE_OFFSET(pcode)];\n\n\t\t\tMHVTL_DBG(2, \"VPD Found page 0x%x\", pcode);\n\n\t\t\tdata[0] = lu->ptype;\n\t\t\tdata[1] = pcode;\n\t\t\tdata[2] = (vpd_pg->sz >> 8);\n\t\t\tdata[3] = vpd_pg->sz & 0xff;\n\t\t\tmemcpy(&data[4], vpd_pg->data, vpd_pg->sz);\n\t\t\tlen = vpd_pg->sz + 4;\n\t\t\thex_dump(data, len);\n\t\t}\n\t}\n\tcmd->dbuf_p->sz = len;\n\treturn SAM_STAT_GOOD;\n}\n\n#ifdef MHVTL_DEBUG\n/*\n * Process PERSITENT RESERVE OUT scsi command\n * Returns 0 if OK\n *         or -1 on failure.\n */\nstatic char *type_str[] = {\n\t\"Obsolete\",\n\t\"Write exclusive\",\n\t\"Obsolete\",\n\t\"Exclusive access\",\n\t\"Obsolete\",\n};\n\nstatic char *type_unknown = \"Undefined\";\n\nstatic char *lookup_type(uint8_t type) {\n\tif (type > 4)\n\t\treturn type_unknown;\n\telse\n\t\treturn type_str[type];\n}\n\nstatic char *serv_action_str[] = {\n\t\"Register\",\n\t\"Reserve\",\n\t\"Release\",\n\t\"Clear\",\n\t\"Preempt\",\n\t\"Preempt & abort\",\n\t\"Register & ignore existing key\",\n\t\"Register & move\",\n};\nstatic char *sa_unknown = \"Undefined\";\n\nstatic char *lookup_sa(uint8_t sa) {\n\tif (sa > 7)\n\t\treturn sa_unknown;\n\telse\n\t\treturn serv_action_str[sa];\n}\n#endif\n\n#define SPR_EXCLUSIVE_ACCESS 3\nuint8_t resp_spc_pro(uint8_t *cdb, struct mhvtl_ds *dbuf_p) {\n\tuint64_t\tRK;\n\tuint64_t\tSARK;\n\tuint16_t\tSA;\n\tuint8_t\t\tTYPE;\n\tuint8_t\t   *sam_stat = &dbuf_p->sam_stat;\n\tuint8_t\t   *buf\t\t = (uint8_t *)dbuf_p->data;\n\tstruct s_sd sd;\n\n\tif (dbuf_p->sz != 24) {\n\t\tsd.byte0\t\t = SKSV | CD;\n\t\tsd.field_pointer = 5;\n\t\tsam_illegal_request(E_PARAMETER_LIST_LENGTH_ERR, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\t*sam_stat = SAM_STAT_GOOD;\n\n\tSA\t = cdb[1] & 0x1f;\n\tTYPE = cdb[2] & 0x0f;\n\n\tRK\t = get_unaligned_be64(&buf[0]);\n\tSARK = get_unaligned_be64(&buf[8]);\n\n\tMHVTL_DBG(2, \"Key 0x%.8x %.8x SA Key 0x%.8x %.8x \"\n\t\t\t\t \"Service Action: %s, Type: %s\",\n\t\t\t  (uint32_t)(RK >> 32) & 0xffffffff,\n\t\t\t  (uint32_t)RK & 0xffffffff,\n\t\t\t  (uint32_t)(SARK >> 32) & 0xffffffff,\n\t\t\t  (uint32_t)SARK & 0xffffffff,\n\t\t\t  lookup_sa(SA), lookup_type(TYPE));\n\tMHVTL_DBG(2, \"Reservation key was: 0x%.8x 0x%.8x\",\n\t\t\t  (uint32_t)(SPR_Reservation_Key >> 32) & 0xffffffff,\n\t\t\t  (uint32_t)(SPR_Reservation_Key & 0xffffffff));\n\n\tswitch (SA) {\n\tcase 0: /* REGISTER */\n\t\tif (SPR_Reservation_Key) {\n\t\t\tif (RK == SPR_Reservation_Key) {\n\t\t\t\tif (SARK) {\n\t\t\t\t\tSPR_Reservation_Key = SARK;\n\t\t\t\t} else {\n\t\t\t\t\tSPR_Reservation_Key\t = 0UL;\n\t\t\t\t\tSPR_Reservation_Type = 0;\n\t\t\t\t}\n\t\t\t\tSPR_Reservation_Generation++;\n\t\t\t} else {\n\t\t\t\t*sam_stat = SAM_STAT_RESERVATION_CONFLICT;\n\t\t\t}\n\t\t} else {\n\t\t\tif (RK) {\n\t\t\t\t*sam_stat = SAM_STAT_RESERVATION_CONFLICT;\n\t\t\t} else {\n\t\t\t\tSPR_Reservation_Key = SARK;\n\t\t\t\tSPR_Reservation_Generation++;\n\t\t\t}\n\t\t}\n\t\tbreak;\n\tcase 1: /* RESERVE */\n\t\tif (SPR_Reservation_Key)\n\t\t\tif (RK == SPR_Reservation_Key)\n\t\t\t\tif (TYPE == SPR_EXCLUSIVE_ACCESS) {\n\t\t\t\t\tSPR_Reservation_Type = TYPE;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t*sam_stat = SAM_STAT_RESERVATION_CONFLICT;\n\t\tbreak;\n\tcase 2: /* RELEASE */\n\t\tif (SPR_Reservation_Key)\n\t\t\tif (RK == SPR_Reservation_Key)\n\t\t\t\tif (TYPE == SPR_EXCLUSIVE_ACCESS) {\n\t\t\t\t\tSPR_Reservation_Type = 0;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t*sam_stat = SAM_STAT_RESERVATION_CONFLICT;\n\t\tbreak;\n\tcase 3: /* CLEAR */\n\t\tif (!SPR_Reservation_Key && !SPR_Reservation_Key) {\n\t\t\t*sam_stat = SAM_STAT_RESERVATION_CONFLICT;\n\t\t} else {\n\t\t\tif (RK == SPR_Reservation_Key) {\n\t\t\t\tSPR_Reservation_Key\t = 0UL;\n\t\t\t\tSPR_Reservation_Type = 0;\n\t\t\t\tSPR_Reservation_Generation++;\n\t\t\t} else {\n\t\t\t\t*sam_stat = SAM_STAT_RESERVATION_CONFLICT;\n\t\t\t}\n\t\t}\n\t\tbreak;\n\tcase 4: /* PREEMT */\n\tcase 5: /* PREEMPT AND ABORT */\n\t\t/* this is pretty weird,\n\t\t * in that we can only have a single key registered,\n\t\t * so preempt is pretty simplified */\n\t\tif ((!SPR_Reservation_Key) && (!RK) && (!SARK)) {\n\t\t\t*sam_stat = SAM_STAT_RESERVATION_CONFLICT;\n\t\t} else {\n\t\t\tif (SPR_Reservation_Type) {\n\t\t\t\tif (SARK == SPR_Reservation_Key) {\n\t\t\t\t\tSPR_Reservation_Key\t = RK;\n\t\t\t\t\tSPR_Reservation_Type = TYPE;\n\t\t\t\t\tSPR_Reservation_Generation++;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (SARK == SPR_Reservation_Key) {\n\t\t\t\t\tSPR_Reservation_Key = 0UL;\n\t\t\t\t\tSPR_Reservation_Generation++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tbreak;\n\tcase 6: /* REGISTER AND IGNORE EXISTING KEY */\n\t\tif (SPR_Reservation_Key) {\n\t\t\tif (SARK) {\n\t\t\t\tSPR_Reservation_Key = SARK;\n\t\t\t} else {\n\t\t\t\tSPR_Reservation_Key\t = 0UL;\n\t\t\t\tSPR_Reservation_Type = 0;\n\t\t\t}\n\t\t} else {\n\t\t\tSPR_Reservation_Key = SARK;\n\t\t}\n\t\tSPR_Reservation_Generation++;\n\t\tbreak;\n\tcase 7: /* REGISTER AND MOVE */\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, NULL, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\tbreak;\n\tdefault:\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, NULL, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\tbreak;\n\t}\n\tMHVTL_DBG(2, \"Reservation key now: 0x%.8x 0x%.8x\",\n\t\t\t  (uint32_t)(SPR_Reservation_Key >> 32) & 0xffffffff,\n\t\t\t  (uint32_t)(SPR_Reservation_Key & 0xffffffff));\n\treturn *sam_stat;\n}\n\n/*\n * Process PERSITENT RESERVE IN scsi command\n */\nuint8_t resp_spc_pri(uint8_t *cdb, struct mhvtl_ds *dbuf_p) {\n\tuint16_t\talloc_len;\n\tuint16_t\tSA;\n\tuint8_t\t   *buf\t\t = (uint8_t *)dbuf_p->data;\n\tuint8_t\t   *sam_stat = &dbuf_p->sam_stat;\n\tuint8_t\t\tsam_status;\n\tstruct s_sd sd;\n\n\tSA = cdb[1] & 0x1f;\n\n\talloc_len = get_unaligned_be16(&cdb[7]);\n\n\tmemset(buf, 0, alloc_len); /* Clear memory */\n\n\tMHVTL_DBG(1, \"service action: %d\", SA);\n\n\tsam_status = SAM_STAT_GOOD;\n\tswitch (SA) {\n\tcase 0: /* READ KEYS */\n\t\tput_unaligned_be32(SPR_Reservation_Generation, &buf[0]);\n\t\tif (!SPR_Reservation_Key) {\n\t\t\tdbuf_p->sz = 8;\n\t\t\tbreak;\n\t\t}\n\t\tbuf[7] = 8;\n\t\tput_unaligned_be64(SPR_Reservation_Key, &buf[8]);\n\t\tdbuf_p->sz = 16;\n\t\tbreak;\n\tcase 1: /* READ RESERVATON */\n\t\tput_unaligned_be32(SPR_Reservation_Generation, &buf[0]);\n\t\tif (!SPR_Reservation_Type) {\n\t\t\tdbuf_p->sz = 8;\n\t\t\tbreak;\n\t\t}\n\t\tbuf[7] = 16;\n\t\tput_unaligned_be64(SPR_Reservation_Key, &buf[8]);\n\t\tbuf[21]\t   = SPR_Reservation_Type;\n\t\tdbuf_p->sz = 24;\n\t\tbreak;\n\tcase 2: /* REPORT CAPABILITIES */\n\t\tbuf[1]\t   = 8;\n\t\tbuf[2]\t   = 0x10;\n\t\tbuf[3]\t   = 0x80;\n\t\tbuf[4]\t   = 0x08;\n\t\tdbuf_p->sz = 8;\n\t\tbreak;\n\tcase 3: /* READ FULL STATUS */\n\tdefault:\n\t\tsd.byte0\t\t = SKSV | CD;\n\t\tsd.field_pointer = 1;\n\t\tdbuf_p->sz\t\t = 0;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\tsam_status = SAM_STAT_CHECK_CONDITION;\n\t\tbreak;\n\t}\n\treturn sam_status;\n}\n\nuint8_t spc_tur(struct scsi_cmd *cmd) {\n\tMHVTL_DBG(1, \"** %s (%ld) %s **\", \"TEST UNIT READY : Returning => \",\n\t\t\t  (long)cmd->dbuf_p->serialNo,\n\t\t\t  (cmd->lu->online) ? \"Online\" : \"Offline\");\n\tif (cmd->lu->online)\n\t\treturn SAM_STAT_GOOD;\n\n\tsam_not_ready(NO_ADDITIONAL_SENSE, &cmd->dbuf_p->sam_stat);\n\treturn SAM_STAT_CHECK_CONDITION;\n}\n\nuint8_t spc_illegal_op(struct scsi_cmd *cmd) {\n\tuint8_t\t   *sam_stat = &cmd->dbuf_p->sam_stat;\n\tstruct s_sd sd;\n\n\tMHVTL_DBG(1, \"UNSUPPORTED OP CODE **\");\n\n\tsd.byte0\t\t = SKSV | CD;\n\tsd.field_pointer = 0; /* byte 0 in cdb is invalid (the op code) */\n\n\tsam_illegal_request(E_INVALID_OP_CODE, &sd, sam_stat);\n\n\treturn SAM_STAT_CHECK_CONDITION;\n}\n\nuint8_t spc_request_sense(struct scsi_cmd *cmd) {\n\tuint8_t *sense_buf = (uint8_t *)cmd->dbuf_p->sense_buf;\n\tuint8_t *cdb\t   = cmd->scb;\n\n\tMHVTL_DBG(1, \"REQUEST SENSE (%ld) : KEY/ASC/ASCQ \"\n\t\t\t\t \"[0x%02x 0x%02x 0x%02x]\"\n\t\t\t\t \" Filemark: %s, EOM: %s, ILI: %s\",\n\t\t\t  (long)cmd->dbuf_p->serialNo,\n\t\t\t  sense_buf[2] & 0x0f,\n\t\t\t  sense_buf[12],\n\t\t\t  sense_buf[13],\n\t\t\t  (sense_buf[2] & SD_FILEMARK) ? \"yes\" : \"no\",\n\t\t\t  (sense_buf[2] & SD_EOM) ? \"yes\" : \"no\",\n\t\t\t  (sense_buf[2] & SD_ILI) ? \"yes\" : \"no\");\n\n\tassert(cmd->dbuf_p->data);\n\t/* Clear out the request sense flag */\n\tcmd->dbuf_p->sam_stat = 0;\n\n\t/* set buf size */\n\tcmd->dbuf_p->sz = min(cdb[4], (uint8_t)SENSE_BUF_SIZE);\n\tmemcpy(cmd->dbuf_p->data, sense_buf, cmd->dbuf_p->sz);\n\tmemset(sense_buf, 0, 18); /* First 18bytes contain usual suspect */\n\tsense_buf[0] = SD_CURRENT_INFORMATION_FIXED;\n\treturn SAM_STAT_GOOD;\n}\n\n/*\n * Log Select\n *\n * Set the logs to a known state.\n *\n * Currently a no-op\n */\nstatic char LOG_SELECT_00[] = \"Current threshold values\";\nstatic char LOG_SELECT_01[] = \"Current cumulative values\";\nstatic char LOG_SELECT_10[] = \"Default threshold values\";\nstatic char LOG_SELECT_11[] = \"Default cumulative values\";\n\nuint8_t spc_log_select(struct scsi_cmd *cmd) {\n\tuint8_t\t   *cdb\t\t = cmd->scb;\n\tuint8_t\t   *sam_stat = &cmd->dbuf_p->sam_stat;\n\tchar\t\tsp\t\t = cdb[1] & 0x1; /* Save Parameters */\n\tchar\t\tpcr\t\t = cdb[1] & 0x2; /* Parameter Code Reset */\n\tuint16_t\tparmList;\n\tchar\t   *parmString = \"Undefined\";\n\tstruct s_sd sd;\n\n\tparmList = get_unaligned_be16(&cdb[7]); /* bytes 7 & 8 are parm list. */\n\n\tMHVTL_DBG(1, \"LOG SELECT (%ld)%s **\",\n\t\t\t  (long)cmd->dbuf_p->serialNo,\n\t\t\t  (pcr) ? \" : Parameter Code Reset \" : \"\");\n\tif (sp) {\n\t\tMHVTL_DBG(1, \" Log Select - Save Parameters not supported\");\n\t\tsd.byte0\t\t = SKSV | CD | BPV | 1; /* bit 1 */\n\t\tsd.field_pointer = 1;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tif (pcr) {\t\t\t/* Check for Parameter code reset */\n\t\tif (parmList) { /* If non-zero, error */\n\t\t\tsd.byte0\t\t = SKSV | CD;\n\t\t\tsd.field_pointer = 7;\n\t\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd,\n\t\t\t\t\t\t\t\tsam_stat);\n\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t}\n\t\tswitch ((cdb[2] & 0xc0) >> 6) {\n\t\tcase 0:\n\t\t\tparmString = LOG_SELECT_00;\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tparmString = LOG_SELECT_01;\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tparmString = LOG_SELECT_10;\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\tparmString = LOG_SELECT_11;\n\t\t\tbreak;\n\t\t}\n\t\tMHVTL_DBG(1, \"  %s\", parmString);\n\t}\n\treturn SAM_STAT_GOOD;\n}\n\n/*\n * Process the MODE_SELECT command\n */\nuint8_t spc_mode_select(struct scsi_cmd *cmd) {\n\tMHVTL_DBG(1, \"MODE SELECT (%ld) **\", (long)cmd->dbuf_p->serialNo);\n\n\tcmd->dbuf_p->sz = 0;\n\treturn SAM_STAT_GOOD;\n}\n\n/*\n * Add data for pcode to buffer pointed to by p\n * Return: Number of chars moved.\n */\nstatic int add_pcode(struct mode *m, uint8_t pc, uint8_t *p) {\n\tif (pc == 1) /* Report Changeable bitmap */\n\t\tmemcpy(p, m->pcodePointerBitMap, m->pcodeSize);\n\telse\n\t\tmemcpy(p, m->pcodePointer, m->pcodeSize);\n\treturn m->pcodeSize;\n}\n\n/*\n * Build mode sense data into *buf\n * Return SAM STATUS\n */\nuint8_t spc_mode_sense(struct scsi_cmd *cmd) {\n\tint\t\t\t\t\tpc, pcode, subpcode;\n\tint\t\t\t\t\talloc_len, msense_6;\n\tint\t\t\t\t\tlen\t   = 0;\n\tint\t\t\t\t\toffset = 0;\n\tuint8_t\t\t\t   *ap;\n\tstruct mode\t\t   *smp; /* Struct mode pointer... */\n\tstruct priv_lu_ssc *ssc;\n\tint\t\t\t\t\ti, j;\n\tint\t\t\t\t\tWriteProtect = 0;\n\tstruct s_sd\t\t\tsd;\n\n\tuint8_t\t\t\t *buf\t   = (uint8_t *)cmd->dbuf_p->data;\n\tuint8_t\t\t\t *scb\t   = cmd->scb;\n\tuint8_t\t\t\t *sam_stat = &cmd->dbuf_p->sam_stat;\n\tstruct list_head *m\t\t   = &cmd->lu->mode_pg;\n\n\tif (cmd->lu->ptype == TYPE_TAPE) {\n\t\tssc\t\t\t = cmd->lu->lu_private;\n\t\tWriteProtect = ssc->MediaWriteProtect;\n\t}\n\n#ifdef MHVTL_DEBUG\n\tchar *pcString[] = {\n\t\t\"Current values\",\n\t\t\"Changeable values\",\n\t\t\"Default values\",\n\t\t\"Saved values\",\n\t};\n#endif\n\n\t/* Disable Block Descriptors */\n\tuint8_t blockDescriptorLen = (scb[1] & 0x8) ? 0 : 8;\n\n\t/*\n\t pc => page control\n\t\t00 -> 0: Report Current values\n\t\t01 -> 1: Report Changeable values\n\t\t10 -> 2: Report Default values\n\t\t11 -> 3: Report Saved values\n\t*/\n\tpc = (scb[2] & 0xc0) >> 6;\n\t/* pcode -> Page Code */\n\tpcode\t = scb[2] & 0x3f;\n\tsubpcode = scb[3];\n\tmsense_6 = (MODE_SENSE == scb[0]);\n\n\talloc_len = msense_6 ? scb[4] : ((scb[7] << 8) | scb[8]);\n\toffset\t  = msense_6 ? 4 : 8;\n\n\tMHVTL_DBG(1, \"MODE SENSE %d (%ld) **\",\n\t\t\t  (msense_6) ? 6 : 10,\n\t\t\t  (long)cmd->dbuf_p->serialNo);\n\tMHVTL_DBG(2, \" Page Control     : %s(0x%02x)\",\n\t\t\t  pcString[pc], pc);\n\tMHVTL_DBG(2, \" Page/Subpage Code: 0x%02x/0x%02x\", pcode, subpcode);\n\tMHVTL_DBG(2, \" %s Block Descriptor\",\n\t\t\t  (blockDescriptorLen) ? \"Report\" : \"Disable\");\n\tMHVTL_DBG(2, \" Allocation len   : %d\", alloc_len);\n\n\tif (0x3 == pc) { /* Saving values not supported */\n\t\tMHVTL_DBG(2, \"Reporting on Saved Values not supported\");\n\t\tsam_illegal_request(E_SAVING_PARMS_UNSUP, NULL, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tif (pcode == 0x3f && (subpcode != 0x0 && subpcode != 0xff)) {\n\t\tsd.byte0\t\t = SKSV | CD;\n\t\tsd.field_pointer = 3;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tmemset(buf, 0, alloc_len); /* Set return data to null */\n\n\toffset += blockDescriptorLen;\n\tap = buf + offset;\n\n\tswitch (pcode) {\n\tcase 0:\n\t\tlen = 0;\n\t\tbreak;\n\tcase 0x3f:\n\t\t/* Walk thru all possibilities */\n\t\tif (subpcode == 0) {\n\t\t\tfor (i = 1; i < 0x3f; i++) {\n\t\t\t\tsmp = lookup_mode_pg(m, i, subpcode);\n\t\t\t\tif (smp)\n\t\t\t\t\tlen += add_pcode(smp, pc,\n\t\t\t\t\t\t\t\t\t (uint8_t *)ap + len);\n\t\t\t}\n\t\t} else { /* 0x01 - 0xfe are reserved. Should only be 0xff */\n\t\t\tfor (i = 1; i < 0x3f; i++) {\n\t\t\t\tfor (j = 0; j < 0xff; j++) {\n\t\t\t\t\tsmp = lookup_mode_pg(m, i, j);\n\t\t\t\t\tif (smp)\n\t\t\t\t\t\tlen += add_pcode(smp, pc,\n\t\t\t\t\t\t\t\t\t\t (uint8_t *)ap + len);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tbreak;\n\tdefault:\n\t\tif (subpcode == 0xff) { /* All sub-pcodes for this pcode */\n\t\t\tfor (i = 0; i < 0xff; i++) {\n\t\t\t\tsmp = lookup_mode_pg(m, pcode, i);\n\t\t\t\tif (smp)\n\t\t\t\t\tlen += add_pcode(smp, pc,\n\t\t\t\t\t\t\t\t\t (uint8_t *)ap + len);\n\t\t\t}\n\t\t} else {\n\t\t\tsmp = lookup_mode_pg(m, pcode, subpcode);\n\t\t\tif (smp)\n\t\t\t\tlen = add_pcode(smp, pc, (uint8_t *)ap);\n\t\t}\n\t\tbreak;\n\t}\n\n\toffset += len;\n\n\tif (pcode != 0)\t\t/* 0 = No page code requested */\n\t\tif (0 == len) { /* Page not found.. */\n\t\t\tMHVTL_DBG(2, \"Unknown mode page: 0x%02x sub-page code: 0x%02x\",\n\t\t\t\t\t  pcode, subpcode);\n\t\t\tsd.byte0\t\t = SKSV | CD;\n\t\t\tsd.field_pointer = 2; /* Byte 2 page code */\n\t\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t}\n\n\t/* Fill in header.. */\n\tif (msense_6) {\n\t\tbuf[0] = offset - 1; /* size - sizeof(buf[0]) field */\n\t\tbuf[1] = cmd->lu->mode_media_type;\n\t\tbuf[2] = (WriteProtect ? 0x80 : 0x00) | 0x10;\n\t\tbuf[3] = blockDescriptorLen;\n\t\t/* If the length > 0, copy Block Desc. */\n\t\tif (blockDescriptorLen) {\n\t\t\tswitch (pc) {\n\t\t\tcase 0:\n\t\t\tcase 2:\n\t\t\t\tmemcpy(&buf[4], modeBlockDescriptor,\n\t\t\t\t\t   blockDescriptorLen);\n\t\t\t\tbreak;\n\t\t\tcase 1:\n\t\t\t\tbuf[9]\t= 0xff;\n\t\t\t\tbuf[10] = 0xff;\n\t\t\t\tbuf[11] = 0xff;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t} else {\n\t\tput_unaligned_be16(offset - 2, &buf[0]);\n\t\tbuf[2] = cmd->lu->mode_media_type;\n\t\tbuf[3] = (WriteProtect ? 0x80 : 0x00) | 0x10;\n\t\tput_unaligned_be16(blockDescriptorLen, &buf[6]);\n\t\t/* If the length > 0, copy Block Desc. */\n\t\tif (blockDescriptorLen) {\n\t\t\tswitch (pc) {\n\t\t\tcase 0:\n\t\t\tcase 2:\n\t\t\t\tmemcpy(&buf[8], modeBlockDescriptor,\n\t\t\t\t\t   blockDescriptorLen);\n\t\t\t\tbreak;\n\t\t\tcase 1:\n\t\t\t\tbuf[13] = 0xff;\n\t\t\t\tbuf[14] = 0xff;\n\t\t\t\tbuf[15] = 0xff;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n#ifdef MHVTL_DEBUG\n\tif (debug) {\n\t\tprintf(\"mode sense: Returning %d bytes\\n\", offset);\n\t\thex_dump(buf, offset);\n\t}\n#endif\n\n\tcmd->dbuf_p->sz = offset;\n\n\treturn SAM_STAT_GOOD;\n}\n\nuint8_t spc_release(struct scsi_cmd *cmd) {\n\tMHVTL_DBG(1, \"RELEASE UNIT (%ld) **\", (long)cmd->dbuf_p->serialNo);\n\treturn SAM_STAT_GOOD;\n}\n\nuint8_t spc_reserve(struct scsi_cmd *cmd) {\n\tMHVTL_DBG(1, \"RESERVE UNIT (%ld) **\", (long)cmd->dbuf_p->serialNo);\n\treturn SAM_STAT_GOOD;\n}\n\nuint8_t spc_send_diagnostics(struct scsi_cmd *cmd) {\n\tMHVTL_DBG(1, \"SEND DIAGNOSTICS (%ld) **\", (long)cmd->dbuf_p->serialNo);\n\treturn SAM_STAT_GOOD;\n}\n\nuint8_t spc_recv_diagnostics(struct scsi_cmd *cmd) {\n\tuint8_t\t   *data;\n\tuint8_t\t\tpc;\n\tuint8_t\t   *sam_stat = &cmd->dbuf_p->sam_stat;\n\tstruct s_sd sd;\n\n\tMHVTL_DBG(1, \"RECEIVE DIAGNOSTIC (%ld) **\",\n\t\t\t  (long)cmd->dbuf_p->serialNo);\n\n\tif (cmd->scb[1] & 0x01) { /* Page Code Valid bit */\n\t\tpc = cmd->scb[2];\n\n\t\tMHVTL_DBG(3, \"Page code: %d\", pc);\n\t\tif (pc == 0) {\n\t\t\tdata = cmd->dbuf_p->data;\n\n\t\t\tmemset(data, 0, 10); /* Clear any junk */\n\t\t\tput_unaligned_be16(1, &data[2]);\n\t\t\tcmd->dbuf_p->sz = 5;\n\n\t\t\treturn SAM_STAT_GOOD;\n\t\t}\n\t}\n\n\tsd.byte0\t\t = SKSV | CD;\n\tsd.field_pointer = 1;\n\tcmd->dbuf_p->sz\t = 0;\n\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\treturn SAM_STAT_CHECK_CONDITION;\n}\n\nuint8_t spc_read_buffer(struct scsi_cmd *cmd) {\n\t/* \tuint8_t *cdb = cmd->scb;\n\t\tuint8_t *sam_stat = &cmd->dbuf_p->sam_stat;\n\n\t\tuint8_t mode = cdb[1] & 0x11111;\n\t\tuint8_t buf_id = cdb[2];\n\t\tuint16_t buf_offset = get_unaligned_be16(&cdb[3]);\n\t\tuint16_t alloc_length = get_unaligned_be16(&cdb[6]); */\n\n\treturn SAM_STAT_GOOD;\n}"
  },
  {
    "path": "usr/ssc.c",
    "content": "/*\n * This handles any SCSI OP codes defined in the standards as 'STREAM'\n *\n * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n * See comments in vtltape.c for a more complete version release...\n *\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <inttypes.h>\n#include <sys/time.h>\n#include \"be_byteshift.h\"\n#include \"mhvtl_scsi.h\"\n#include \"mhvtl_list.h\"\n#include \"vtl_common.h\"\n#include \"logging.h\"\n#include \"vtllib.h\"\n#include \"spc.h\"\n#include \"ssc.h\"\n#include \"vtlcart.h\"\n#include \"mhvtl_log.h\"\n#include \"mode.h\"\n\n#ifdef MHVTL_DEBUG\nstatic struct allow_overwrite_state {\n\tchar *desc;\n} allow_overwrite_desc[] = {\n\t{\n\t\t\"Disabled\",\n\t},\n\t{\n\t\t\"Current Position\",\n\t},\n\t{\n\t\t\"Format\",\n\t},\n\t{\n\t\t\"Opps, Invalid field in CDB\",\n\t},\n};\n#endif\n\n#define declare_ssc_vars                                                            \\\n\tstruct lu_phy_attr *lu __attribute__((unused))\t\t = cmd->lu;                 \\\n\tstruct priv_lu_ssc *lu_priv __attribute__((unused))\t = lu->lu_private;          \\\n\tstruct encryption  *encr __attribute__((unused))\t = lu_priv->app_encr_info;  \\\n\tuint8_t\t\t\t   *cdb __attribute__((unused))\t\t = cmd->scb;                \\\n\tstruct mhvtl_ds\t   *dbuf_p __attribute__((unused))\t = cmd->dbuf_p;             \\\n\tuint8_t\t\t\t   *buf __attribute__((unused))\t\t = (uint8_t *)dbuf_p->data; \\\n\tuint8_t\t\t\t   *sam_stat __attribute__((unused)) = &dbuf_p->sam_stat;       \\\n\t*sam_stat\t\t\t\t\t\t\t\t\t\t\t = SAM_STAT_GOOD;\n\nvoid memset_ssc_buf(struct scsi_cmd *cmd, uint64_t alloc_len) {\n\tdeclare_ssc_vars;\n\n\tmemset(buf, 0, min((int)alloc_len, lu_priv->bufsize));\n}\n\nuint8_t ssc_allow_overwrite(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tstruct s_sd sd;\n\tuint64_t\tallow_overwrite_block;\n\tuint8_t\t\tallow_overwrite = cdb[2] & 0x0f;\n\tuint8_t\t\tpartition\t\t= cdb[3];\n\n\tif (allow_overwrite > 2) /* Truncate bad values 3 to 15 -> '3' */\n\t\tallow_overwrite = 3;\n\n\tMHVTL_DBG(1, \"ALLOW OVERWRITE (%ld) : %s **\",\n\t\t\t  (long)dbuf_p->serialNo,\n\t\t\t  allow_overwrite_desc[allow_overwrite].desc);\n\n\tlu_priv->allow_overwrite = FALSE;\n\n\tswitch (allow_overwrite) {\n\tcase 0:\n\t\tbreak;\n\tcase 1:\t\t\t\t /* current position */\n\t\tif (partition) { /* Partitions not supported at this stage */\n\t\t\tMHVTL_LOG(\"Partitions not implemented at this time\");\n\t\t\tsd.byte0\t\t = SKSV | CD;\n\t\t\tsd.field_pointer = 3;\n\t\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB,\n\t\t\t\t\t\t\t\t&sd, sam_stat);\n\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t}\n\t\tallow_overwrite_block = get_unaligned_be64(&cdb[4]);\n\t\tMHVTL_DBG(1, \"Allow overwrite block: %lld\",\n\t\t\t\t  (long long)allow_overwrite_block);\n\t\tif (allow_overwrite_block == current_tape_block()) {\n\t\t\tlu_priv->allow_overwrite_block = allow_overwrite_block;\n\t\t\tlu_priv->allow_overwrite\t   = TRUE;\n\t\t} else {\n\t\t\t/* Set allow_overwrite position to an invalid number */\n\t\t\tlu_priv->allow_overwrite_block = 0;\n\t\t\tlu_priv->allow_overwrite_block--;\n\t\t\tsam_illegal_request(E_SEQUENTIAL_POSITIONING_ERROR,\n\t\t\t\t\t\t\t\tNULL, sam_stat);\n\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t}\n\t\tbreak;\n\tcase 2:\n\t\tlu_priv->allow_overwrite = 2;\n\t\tbreak;\n\tdefault:\n\t\tsd.byte0\t\t = SKSV | CD;\n\t\tsd.field_pointer = 2;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\tbreak;\n\t}\n\n\treturn SAM_STAT_GOOD;\n}\n\nuint8_t ssc_log_select(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\tuint8_t pcr = cdb[1] & 0x2; /* Parameter code reset */\n\n\t*sam_stat = spc_log_select(cmd);\n\tif (*sam_stat) /* spc_log_select() failed - return */\n\t\treturn *sam_stat;\n\n\tif (pcr) {\n\t\tswitch ((cdb[2] & 0xc0) >> 6) {\n\t\tcase 3:\n\t\t\tlu_priv->bytesRead_I\t= 0;\n\t\t\tlu_priv->bytesRead_M\t= 0;\n\t\t\tlu_priv->bytesWritten_I = 0;\n\t\t\tlu_priv->bytesWritten_M = 0;\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn SAM_STAT_GOOD;\n}\n\nuint8_t complete_read_6(struct scsi_cmd *cmd, int sz, int count) {\n\tdeclare_ssc_vars;\n\n\tint lbp_method;\n\tint k;\n\tint retval = 0;\n\tint fixed  = cdb[1] & FIXED_BLOCK;\n\n\tswitch (get_tape_load_status()) {\n\tcase TAPE_LOADING:\n\t\tsam_not_ready(E_BECOMING_READY, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\tbreak;\n\tcase TAPE_LOADED:\n\t\tif (mam.MediumType == MEDIA_TYPE_CLEAN) {\n\t\t\tMHVTL_DBG(3, \"Cleaning cart loaded\");\n\t\t\tsam_not_ready(E_CLEANING_CART_INSTALLED,\n\t\t\t\t\t\t  sam_stat);\n\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t}\n\t\tbreak;\n\tcase TAPE_UNLOADED:\n\t\tMHVTL_DBG(3, \"No media loaded\");\n\t\tsam_not_ready(E_MEDIUM_NOT_PRESENT, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\tbreak;\n\tdefault:\n\t\tMHVTL_DBG(1, \"Media format corrupt\");\n\t\tsam_not_ready(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\tbreak;\n\t}\n\n\tfor (k = 0; k < count; k++) {\n\t\tif (!lu_priv->pm->valid_encryption_blk(cmd))\n\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t/* If LBP Read bit is set, pass through the LBP_method 0: off, 1 RS-CRC, 2 CRC32C */\n\t\tlbp_method = (lu_priv->LBP_R) ? lu_priv->LBP_method : 0;\n\t\tretval\t   = readBlock(buf, sz, cdb[1] & SILI, lbp_method, sam_stat);\n\t\tif (!retval && fixed) {\n\t\t\t/* Fixed block read hack:\n\t\t\t *\n\t\t\t * Overwrite INFORMATION field with:\n\t\t\t *\n\t\t\t * SSC4r01e states:\n\t\t\t * The INFORMATION field shall be set to the requested\n\t\t\t * transfer length minus the actual number of logical\n\t\t\t * blocks read (not including the incorrect-length\n\t\t\t * logical block).\n\n\t\t\t * NOTE 35 - In the above case with the FIXED bit of\n\t\t\t * one, only the position of the incorrect-length\n\t\t\t * logical block may be determined from the sense\n\t\t\t * data. The actual length of the incorrect logical\n\t\t\t * block is not reported. Other means may be used to\n\t\t\t * determine its actual length (e.g., read it again\n\t\t\t * with the fixed bit set to zero).\n\t\t\t */\n\t\t\tMHVTL_DBG(2, \"Fixed block read short by %d blocks\",\n\t\t\t\t\t  count - k);\n\t\t\tput_unaligned_be32(count - k, &sense[3]);\n\t\t\tbreak;\n\t\t}\n\t\tbuf += retval;\n\t\tdbuf_p->sz += retval;\n\t}\n\tif (retval > (sz * count))\n\t\tretval = sz * count;\n\n\treturn *sam_stat;\n}\n\n/* VERIFY_6:\n *\n * Here is what the IBM_LTO SCSI Reference (18Aug2021) says about the op code.\n * GA32-0928-04 18 August 2021\n *\n * The following parameters apply:\n *\n * • VTE (verify to end-of-data): If the VTE bit is set to zero, then a verify to EOD is not requested.\n *  If the VTE bit is set to one, then the expected verification sequence termination condition is met\n *  when EOD is encountered. If a filemark is encountered during the sequence, processing continues.\n *  If the verify command fails, then the VALID bit and the INFORMATION field of sense data are set\n *  to zero. The VBF bit shall be set to zero. The VERIFICATION LENGTH field is ignored.\n *\n * • VLBPM (verify logical block protection method): This bit has no effect. The result is the same for either setting.\n *\n * • VBF (verify by filemarks): If the VBF bit is set to zero, then a verify of n filemarks is not requested.\n *  If the VBF bit is set to one, then the expected verification sequence termination condition is met\n *  if the number of filemarks specified by the VERIFICATION LENGTH field have been traversed. If a\n *  filemark is encountered during the sequence, processing continues. If EOD is encountered, the\n *  sense key is set to BLANK CHECK, the EOM bit is set to one if the logical position is at or\n *  after early warning, and the additional sense code is set to END-OF-DATA DETECTED. If a verify\n *  operation fails, then the verification sequence terminates and the VALID bit is set to one and\n *  the INFORMATION FIELD is set to the requested verification length minus the actual number of\n *  filemarks successfully traversed. The VTE bit shall be set to zero.\n *  NOTE 30 - Following the completion of a verify with the VBF bit set to one, the application\n *  client should issue a READ POSITION command to determine the logical object identifier associated\n *  with the current logical position.\n *\n * • IMMED (immediate) : An IMMED bit set to zero specifies the command shall not return status until\n *  the verify sequence has completed.\n *  An IMMED bit set to one specifies status shall be returned as soon as the command descriptor block\n *  has been validated. Verification sequences that complete unsuccessfully generate deferred sense data\n *  indicating the reason for termination (e.g., .an incorrect length logical block is encountered and\n *  the sense data is set to indicate an incorrect length block was encountered).\n *  NOTE 31 - In order to ensure that no errors are lost, the application client should set the IMMED\n *  bit to zero on the last VERIFY (6) command of a series of VERIFY (6) commands.\n *\n * • BYTCMP (byte compare): Byte compare is not supported by this device. The BYTCMP bit shall be set to\n *  zero to specify the verification shall be a verification of logical blocks on the medium (e.g., CRC, ECC).\n *   No data shall be transferred from the application client to the device server.\n *\n * • FIXED: If the VTE bit and the VBF bit are set to zero and the FIXED bit is set to one, then the\n *  expected verification sequence termination condition is met when the number of logical blocks\n *  specified in the VERIFICATION LENGTH field have been traversed. If the VERIFICATION LENGTH field\n *  is set to zero, then no logical objects are verified and the current logical position is not changed.\n *  This condition is not an error. If a file-mark is encountered during the sequence, processing\n *  terminates with filemark encountered as specified in the READ(6) command (see 5.2.15).\n *  If EOD is encountered, the sense key is set to BLANK CHECK, the EOM bit is set to one if the logical\n *  position is at or after early warning, and the additional sense code is set to END-OF-DATA DETECTED.\n *  If a verify operation fails, then the verification sequence terminates and the VALID bit is set to\n *  one and the INFORMATION FIELD is set to the requested verification length minus the actual number\n *  of logical blocks successfully traversed.\n *  If the VTE bit and the VBF bit are set to zero and the FIXED bit is set to zero, then the expected\n *  verification sequence termination condition is met when one logical block has been traversed.\n *  The length of the verified logical block is equal to the value specified in the VERIFICATION LENGTH field.\n *  If the VERIFICATION LENGTH field is set to zero, then no logical objects are verified and the\n *  current logical position is not changed. This condition is not considered an error. If a filemark\n *  is encountered during the sequence, pro- cessing terminates with filemark encountered as specified in the\n *  READ(6) command (see 5.2.15). If EOD is encountered, the sense key is set to BLANK CHECK, the EOM bit is\n *  set to one if the logical position is at or after early warning, and the additional sense code is set to\n *  END-OF-DATA DETECTED. If a verify oper- ation fails, then the verification sequence terminates and the\n *  VALID bit is set to one and the INFORMATION FIELD is set to the requested verification length minus\n *  the actual number of bytes successfully traversed.\n *  A FIXED bit set to zero and either the VTE bit set to one or the VBF bit set to one specifies that the\n *  block length shall not be checked.\n *  A FIXED bit set to one specifies that the length of verified logical blocks shall be equal to the the\n *  current block length reported in the mode parameters block descriptor. Refer to the READ(6) command\n *  (see 5.2.15) for a description of the FIXED bit and any error conditions that may result from incorrect usage.\n *\n * • VERIFICATION LENGTH: The VERIFICATION LENGTH field specifies the number of bytes, logical blocks,\n *  or file-marks to traverse during verification, as specified by the VBF bit and the FIXED bit.\n *  If the VTE bit is set to one, then the VERIFICATION LENGTH field is ignored.\n *  If the VERIFICATION LENGTH field is set to zero and the VTE bit is set to zero, then no logical objects\n *  are verified and the current logical position is not changed. This condition is not considered an error.\n */\nuint8_t ssc_verify_6(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tint\t\t\t\t\t  blocks;\n\tint\t\t\t\t\t  sz;\n\tstruct s_sd\t\t\t  sd;\n\tstruct verify_6_bits *cdb1 = (struct verify_6_bits *)&cdb[1];\n\n\tset_current_state(MHVTL_STATE_VERIFY);\n\n\tdbuf_p->sz = 0; /* zero data xfer between application and target */\n\n\topcode_6_params(cmd, &blocks, &sz);\n\tMHVTL_DBG(1, \"VERIFY 6 : %s: %d, fixed: %d, bytcmp: %d, immed: %d, vbf: %d, vlbpm: %d, vte: %d, cdb[1]: 0x%02x (%ld) **\",\n\t\t\t  (cdb1->FIXED) ? \"Num blks\" : \"byte count\",\n\t\t\t  (cdb1->FIXED) ? blocks : sz,\n\t\t\t  cdb1->FIXED, cdb1->BYTCMP, cdb1->IMMED, cdb1->VBF, cdb1->VLBPM, cdb1->VTE, cdb[1],\n\t\t\t  (long)dbuf_p->serialNo);\n\n\tif (cdb1->VTE) { /* To be implemented */\n\t\tMHVTL_DBG(1, \"Verify to end of data is currently not implemented\");\n\t\tsd.byte0\t\t = SKSV | CD | BPV | 0x6;\n\t\tsd.field_pointer = 1;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\tif (cdb1->VBF) {\n\t\tint count;\n\n\t\tcount = (cdb1->FIXED) ? blocks : sz;\n\t\tMHVTL_DBG(1, \"Verify %d filemarks\", count);\n\t\tresp_space(count, 1, sam_stat); /* Lets try and move 'count' number of filemarks */\n\t\treturn *sam_stat;\n\t}\n\n\treturn complete_read_6(cmd, sz, blocks);\n}\n\nuint8_t ssc_read_6(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tint\t\t\tcount;\n\tint\t\t\tsz;\n\tstruct s_sd sd;\n\n\tset_current_state(MHVTL_STATE_READING);\n\n\topcode_6_params(cmd, &count, &sz);\n\tMHVTL_DBG(3, \"READ 6 (%ld) ** %d block%s of %d bytes \",\n\t\t\t  (long)dbuf_p->serialNo,\n\t\t\t  count, count == 1 ? \"\" : \"s\",\n\t\t\t  sz);\n\n\t/* If both FIXED & SILI bits set, invalid combo.. */\n\tif ((cdb[1] & (SILI | FIXED_BLOCK)) == (SILI | FIXED_BLOCK)) {\n\t\tMHVTL_DBG(1, \"Suppress ILI and Fixed block \"\n\t\t\t\t\t \"read not allowed by SSC3\");\n\t\tsd.byte0\t\t = SKSV | CD;\n\t\tsd.field_pointer = 1;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\treturn complete_read_6(cmd, sz, count);\n}\n\nuint8_t ssc_write_6(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tint retval = 0;\n\tint count;\n\tint sz;\n\tint k;\n\n\tset_current_state(MHVTL_STATE_WRITING);\n\n\topcode_6_params(cmd, &count, &sz);\n\tMHVTL_DBG(3, \"WRITE 6 : %d block%s of %d bytes (%ld) **\",\n\t\t\t  count, count == 1 ? \"\" : \"s\",\n\t\t\t  sz,\n\t\t\t  (long)dbuf_p->serialNo);\n\n\t/* FIXME: Should handle this instead of 'check & warn' */\n\tif ((sz * count) > lu_priv->bufsize)\n\t\tMHVTL_DBG(1,\n\t\t\t\t  \"Fatal: bufsize %d, requested write of %d bytes\",\n\t\t\t\t  lu_priv->bufsize, sz);\n\n\tdbuf_p->sz = sz * count;\n\n\t/* Retrieve data from kernel - unless media type is 'null' */\n\tif (likely(mam.MediumType != MEDIA_TYPE_NULL))\n\t\tretrieve_CDB_data(cmd->cdev, dbuf_p);\n\n\tif (!lu_priv->pm->check_restrictions(cmd))\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\n\tif (OK_to_write) {\n\t\tfor (k = 0; k < count; k++) {\n\t\t\tretval = writeBlock(cmd, sz);\n\t\t\tbuf += retval;\n\n\t\t\tif (*sam_stat)\n\t\t\t\treturn *sam_stat;\n\t\t}\n\t}\n\treturn SAM_STAT_GOOD;\n}\n\n/*\n * Check for any write restrictions - e.g. WORM, or Clean Cartridge mounted.\n * Return 1 = OK to write, zero -> Can't write.\n */\nuint8_t check_restrictions(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\t/* Check that there is a piece of media loaded.. */\n\tswitch (get_tape_load_status()) {\n\tcase TAPE_LOADING:\n\t\tsam_not_ready(E_BECOMING_READY, sam_stat);\n\t\t*lu_priv->OK_2_write = 0;\n\t\treturn *lu_priv->OK_2_write;\n\t\tbreak;\n\tcase TAPE_LOADED: /* Do nothing */\n\t\tbreak;\n\tcase TAPE_UNLOADED:\n\t\tsam_not_ready(E_MEDIUM_NOT_PRESENT, sam_stat);\n\t\t*lu_priv->OK_2_write = 0;\n\t\treturn *lu_priv->OK_2_write;\n\t\tbreak;\n\tdefault:\n\t\tsam_not_ready(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\t*lu_priv->OK_2_write = 0;\n\t\treturn *lu_priv->OK_2_write;\n\t\tbreak;\n\t}\n\n\tswitch (mam.MediumType) {\n\tcase MEDIA_TYPE_CLEAN:\n\t\tsam_not_ready(E_CLEANING_CART_INSTALLED, sam_stat);\n\t\tMHVTL_DBG(2, \"Can not write - Cleaning cart\");\n\t\t*lu_priv->OK_2_write = 0;\n\t\tbreak;\n\tcase MEDIA_TYPE_WORM:\n\t\t/* If we are not at end of data for a write\n\t\t * and media is defined as WORM, fail...\n\t\t */\n\n\t\t/* OK to append to end of 'tape' */\n\t\tif (c_pos->blk_type == B_EOD)\n\t\t\t*lu_priv->OK_2_write = 1;\n\n\t\tif (!*lu_priv->OK_2_write) {\n\t\t\tMHVTL_DBG(1, \"Failed attempt to overwrite WORM data\");\n\t\t\tsam_data_protect(E_MEDIUM_OVERWRITE_ATTEMPT, sam_stat);\n\t\t}\n\t\tbreak;\n\tcase MEDIA_TYPE_DATA:\n\t\t*lu_priv->OK_2_write = 1;\n\t\tbreak;\n\tcase MEDIA_TYPE_NULL:\n\t\t*lu_priv->OK_2_write = 1;\n\t\t/* Special case - no need for more checks */\n\t\treturn *lu_priv->OK_2_write;\n\t\tbreak;\n\tdefault:\n\t\t*lu_priv->OK_2_write = 0;\n\t\tsam_illegal_request(E_MEDIUM_INCOMPATIBLE, NULL, sam_stat);\n\t}\n\n\t/* over-ride the above IF the virtual write protect switch is on */\n\tif (*lu_priv->OK_2_write && lu_priv->MediaWriteProtect) {\n\t\t*lu_priv->OK_2_write = 0;\n\t\tsam_data_protect(E_WRITE_PROTECT, sam_stat);\n\t}\n\n\t/* over-ride the above IF running in append_only mode and this write\n\t * isn't authorized.\n\t * Some writes would be OK, like the first write to an empty tape or\n\t * WORM media overwriting a filemark that is next to EOD\n\t */\n\tif (*lu_priv->OK_2_write && lu_priv->append_only_mode) {\n\t\tif ((c_pos->blk_number != lu_priv->allow_overwrite_block) &&\n\t\t\t(c_pos->blk_type != B_EOD)) {\n\n\t\t\tuint64_t TAflag;\n\n\t\t\tlu_priv->OK_2_write\t\t = 0;\n\t\t\tlu_priv->allow_overwrite = FALSE;\n\t\t\tsam_data_protect(E_MEDIUM_OVERWRITE_ATTEMPT, sam_stat);\n\t\t\t/* And set TapeAlert flg 09 -> WRITE PROTECT */\n\t\t\tTAflag = TA_WRITE_PROTECT;\n\t\t\tupdate_TapeAlert(TAflag);\n\t\t}\n\t}\n\n\tMHVTL_DBG(2, \"returning:%s writable\",\n\t\t\t  (*lu_priv->OK_2_write) ? \"\" : \" not\");\n\treturn *lu_priv->OK_2_write;\n}\n\n/*\n * Returns true if blk header has correct encryption key data\n */\n#define UKAD_LENGTH (encr->ukad_length)\n#define AKAD_LENGTH (encr->akad_length)\n#define KEY_LENGTH\t(encr->key_length)\n#define UKAD\t\t(encr->ukad)\n#define AKAD\t\t(encr->akad)\n#define KEY\t\t\t(encr->key)\nuint8_t valid_encryption_blk(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tuint8_t correct_key;\n\tint\t\ti;\n\n\t/* decryption logic */\n\tcorrect_key = TRUE;\n\n\tif (c_pos->blk_flags & BLKHDR_FLG_ENCRYPTED) {\n\t\t/* compare the keys */\n\t\tif (lu_priv->DECRYPT_MODE > 1) {\n\t\t\tif (c_pos->blk_encryption_info.key_length != KEY_LENGTH) {\n\t\t\t\tsam_data_protect(E_INCORRECT_KEY, sam_stat);\n\t\t\t\tcorrect_key = FALSE;\n\t\t\t}\n\t\t\tfor (i = 0; i < c_pos->blk_encryption_info.key_length; ++i) {\n\t\t\t\tif (c_pos->blk_encryption_info.key[i] != KEY[i]) {\n\t\t\t\t\tsam_data_protect(E_INCORRECT_KEY, sam_stat);\n\t\t\t\t\tcorrect_key = FALSE;\n\t\t\t\t\treturn correct_key;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tsam_data_protect(E_UNABLE_TO_DECRYPT, sam_stat);\n\t\t\tcorrect_key = FALSE;\n\t\t}\n\t} else if (lu_priv->DECRYPT_MODE == 2) {\n\t\tsam_data_protect(E_UNENCRYPTED_DATA, sam_stat);\n\t\tcorrect_key = FALSE;\n\t}\n\treturn correct_key;\n}\n\nuint8_t valid_encryption_media(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tif (c_pos->blk_number == 0) {\n\t\tmodeBlockDescriptor[0]\t = lu_priv->pm->native_drive_density->density;\n\t\tmam.MediumDensityCode\t = modeBlockDescriptor[0];\n\t\tmam.FormattedDensityCode = modeBlockDescriptor[0];\n\t\trewriteMAM(sam_stat);\n\t} else {\n\t\tif (mam.MediumDensityCode !=\n\t\t\tlu_priv->pm->native_drive_density->density) {\n\t\t\tsam_data_protect(E_WRITE_PROTECT, sam_stat);\n\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t}\n\t}\n\n\treturn SAM_STAT_GOOD;\n}\n\nuint8_t ssc_allow_prevent_removal(struct scsi_cmd *cmd) {\n\t/* FIXME: Currently does nothing... */\n\tMHVTL_DBG(1, \"%s MEDIA REMOVAL (%ld) **\",\n\t\t\t  (cmd->scb[4]) ? \"PREVENT\" : \"ALLOW\",\n\t\t\t  (long)cmd->dbuf_p->serialNo);\n\treturn SAM_STAT_GOOD;\n}\n\nuint8_t ssc_format_medium(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tMHVTL_DBG(1, \"FORMAT MEDIUM (%ld) **\", (long)dbuf_p->serialNo);\n\n\tif (!lu_priv->pm->check_restrictions(cmd))\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\n\tif (c_pos->blk_number != 0) {\n\t\tMHVTL_DBG(2, \"Failed - Not at beginning\");\n\t\tsam_illegal_request(E_POSITION_PAST_BOM, NULL, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\t/* 0h = format the volume to a single partition */\n\t/* 1h = use medium partition mode page to format the partitions */\n\t/* 2h = do 0h then 1h */\n\tswitch (cmd->scb[2] & 0x0F) /* Format */\n\t{\n\tcase 0x00:\n\t\tmam.num_partitions = 1;\n\t\tformat_tape(sam_stat);\n\t\tbreak;\n\tcase 0x01: /* TODO : take MODE_MEDIUM_PARTITION into account */\n\t\tformat_tape(sam_stat);\n\t\tbreak;\n\tcase 0x02: /* TODO : do 0x00 then 0x01 */\n\t\tformat_tape(sam_stat);\n\t\tbreak;\n\tdefault:\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, NULL, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\treturn SAM_STAT_GOOD;\n}\n\nuint8_t ssc_locate(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tuint64_t blk_no;\n\tuint8_t\t partition_no = c_pos->partition_id;\n\n\tset_current_state(MHVTL_STATE_LOCATE);\n\n\tMHVTL_DBG(1, \"LOCATE %d (%ld) **\", (cdb[0] == LOCATE_16) ? 16 : 10,\n\t\t\t  (long)dbuf_p->serialNo);\n\n\tswitch (cdb[0]) {\n\tcase LOCATE_10:\n\t\tif (cdb[1] & 0b00000010) /* CP - Change Partition */\n\t\t\tpartition_no = cdb[8];\n\t\tblk_no = (uint64_t)get_unaligned_be32(&cdb[3]);\n\t\tbreak;\n\tcase LOCATE_16:\n\t\tif (cdb[1] & 0b00000010)\n\t\t\tpartition_no = cdb[3];\n\t\tswitch (cdb[1] & 0b00011000) { /* Destination Type */\n\t\tcase 0b00:\t\t\t\t\t   /* with logical object identifier */\n\t\t\tblk_no = get_unaligned_be64(&cdb[4]);\n\t\t\t/* mhvtl only supports u32 blk_numbers so blk_no will be truncated */\n\t\t\tbreak;\n\t\tcase 0b01: /* with logical file identifier */\n\t\t\tblk_no = block_from_filemark(partition_no, get_unaligned_be64(&cdb[4]));\n\t\t\tbreak;\n\t\tcase 0b11: /* finish with EOD */\n\t\t\tblk_no = last_block(partition_no);\n\t\tdefault:\n\t\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, NULL, sam_stat);\n\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t}\n\t\tbreak;\n\tdefault:\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tif ((cdb[1] & 0b00000010) && partition_no > mam.num_partitions) {\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB,\n\t\t\t\t\t\t\tNULL, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\t/* If we want to seek closer to beginning of file than\n\t * we currently are, rewind and seek from there\n\t */\n\tMHVTL_DBG(2, \"Current partition/blk: %u/%u, seek: %u/%u\",\n\t\t\t  c_pos->partition_id, c_pos->blk_number, partition_no, (uint32_t)blk_no);\n\tchange_partition(partition_no);\n\tposition_to_block((uint32_t)blk_no, sam_stat);\n\n\treturn *sam_stat;\n}\n\nuint8_t ssc_load_display(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tchar str1[9];\n\tchar str2[9];\n\n\tMHVTL_DBG(1, \"LOAD DISPLAY (%ld) - T10000 specific **\",\n\t\t\t  (long)dbuf_p->serialNo);\n\n\tdbuf_p->sz = cdb[4];\n\tretrieve_CDB_data(cmd->cdev, dbuf_p);\n\tmemcpy(str1, &buf[1], 8);\n\tstr1[8] = 0;\n\tmemcpy(str2, &buf[9], 8);\n\tstr2[8] = 0;\n\n\tMHVTL_DBG(3, \"Raw data: %02x  \"\n\t\t\t\t \"%02x %02x %02x %02x %02x %02x %02x %02x  \"\n\t\t\t\t \"%02x %02x %02x %02x %02x %02x %02x %02x\",\n\t\t\t  buf[0], buf[1], buf[2], buf[3], buf[4],\n\t\t\t  buf[5], buf[6], buf[7], buf[8],\n\t\t\t  buf[9], buf[10], buf[11], buf[12],\n\t\t\t  buf[13], buf[14], buf[15], buf[16]);\n\n\tswitch (buf[0] >> 5) { /* Bits 5, 6 & 7 are overlay */\n\tcase 0:\n\t\tMHVTL_DBG(1, \"Display \\'%s\\' until next\"\n\t\t\t\t\t \" command that initiates tape motion\",\n\t\t\t\t  /* Low/High bit */ (buf[0] & 2) ? str2 : str1);\n\t\tbreak;\n\tcase 1:\n\t\tMHVTL_DBG(1, \"Maintain \\'%s\\' until the\"\n\t\t\t\t\t \" cartridge is unloaded\",\n\t\t\t\t  /* Low/High bit */ (buf[0] & 2) ? str2 : str1);\n\t\tbreak;\n\tcase 2:\n\t\tMHVTL_DBG(1, \"Maintain \\'%s\\' until the drive\"\n\t\t\t\t\t \" is next loaded\",\n\t\t\t\t  str1);\n\t\tbreak;\n\tcase 3:\n\t\tMHVTL_DBG(1, \"Physically access tape drive with\"\n\t\t\t\t\t \"out changing the msg\");\n\t\tbreak;\n\tcase 7:\n\t\tMHVTL_DBG(1, \"Display \\'%s\\' until the tape\"\n\t\t\t\t\t \" drive is unloaded then \\'%s\\'\",\n\t\t\t\t  str1, str2);\n\t\tbreak;\n\t}\n\tMHVTL_DBG(2, \"Load display: msg1: %s msg2: %s\",\n\t\t\t  str1, str2);\n\n\tdbuf_p->sz = 0;\n\treturn SAM_STAT_GOOD;\n}\n\n#define REPORT_TIMESTAMP_DATA_LEN 0x0a\n\n/* If timestamp_source == 0 : timestamp is num of uS at logical unit initialization - get_timestamp will return delta of mS between init and now\n * If timestamp_source == 2 : timestamp is set to that provided by initiator - get_timestamp will return delta + timestamp\n */\n\nstatic uint64_t timestamp;\t\t  /* Used for device clock - number uS since initialization */\nstatic int64_t\ttimestamp_offset; /* Used for device clock - offset of local clock and initiator 'set timestamp' value */\nstatic uint8_t\ttimestamp_source;\n\nvoid set_timestamp(uint8_t source, uint64_t ts) {\n\tstruct timeval tv;\n\tuint64_t\t   now;\n\n\ttimestamp_source = source;\n\tgettimeofday(&tv, NULL);\n\tnow = 1000000 * tv.tv_sec + tv.tv_usec;\n\tif (source) {\n\t\ttimestamp\t\t = ts * 1000; /* save as uSec */\n\t\ttimestamp_offset = now - timestamp;\n\t} else {\n\t\ttimestamp\t\t = now;\n\t\ttimestamp_offset = 0;\n\t}\n\tMHVTL_DBG(1, \"SET timestamp: source %u, timestamp is %lu, offset is %ld\", source, timestamp, timestamp_offset);\n}\n\nstatic uint64_t get_timestamp() {\n\tstruct timeval tv;\n\tuint64_t\t   now;\n\n\tgettimeofday(&tv, NULL);\n\tnow = 1000000 * tv.tv_sec + tv.tv_usec;\n\n\tif (timestamp_source) {\n\t\tMHVTL_DBG(1, \"now: %lx, offset: %ld, ret val:  0x%lx\", now, timestamp_offset, (now - timestamp_offset) / 1000);\n\t\treturn (now - timestamp_offset) / 1000; /* Account for any offset between local time and initiator set time */\n\t} else {\n\t\tMHVTL_DBG(1, \"now: %lx, timestamp: %lx, ret val: 0x%lx\", now, timestamp, (now - timestamp) / 1000);\n\t\treturn (now - timestamp) / 1000; /* Num of mS since init */\n\t}\n}\n\nstatic uint8_t report_timestamp(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tmemset(buf, 0, REPORT_TIMESTAMP_DATA_LEN + 2);\n\n\tput_unaligned_be16(REPORT_TIMESTAMP_DATA_LEN, &buf[0]);\n\tbuf[2] = timestamp_source; /* Timestamp origin - Timestamp initialised to zero at power-on */\n\tput_unaligned_be48(get_timestamp() & 0xffffffffffff, &buf[4]);\n\n\tMHVTL_DBG(1, \"Returning timestamp 0x%08lx (%lu)\", get_unaligned_be48(&buf[4]), get_unaligned_be48(&buf[4]));\n\tdbuf_p->sz = REPORT_TIMESTAMP_DATA_LEN + 2;\n\t*sam_stat  = SAM_STAT_GOOD;\n\treturn SAM_STAT_GOOD;\n}\n\nstatic uint8_t configure_timestamp(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tstruct s_sd sd;\n\n\tdbuf_p->sz = get_unaligned_be32(&cdb[6]);\n\tif (dbuf_p->sz == 0)\n\t\treturn SAM_STAT_GOOD;\n\tif (dbuf_p->sz != 0x0c) {\n\t\tdbuf_p->sz\t\t = 0;\n\t\tsd.byte0\t\t = SKSV;\n\t\tsd.field_pointer = 6;\n\t\tMHVTL_LOG(\"Unexpected timestamp parameter length..\");\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_PARMS, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tretrieve_CDB_data(cmd->cdev, cmd->dbuf_p);\n\n\tif (buf[4] > 0xf0) { /* overflow - Illegal request */\n\t\tdbuf_p->sz\t\t = 0;\n\t\tsd.byte0\t\t = SKSV;\n\t\tsd.field_pointer = 4;\n\t\tMHVTL_LOG(\"Unexpected set timestamp value.. Value too large\");\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_PARMS, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tset_timestamp(2, get_unaligned_be48(&buf[4]));\n\n\tdbuf_p->sz = 0;\n\t*sam_stat  = SAM_STAT_GOOD;\n\treturn SAM_STAT_GOOD;\n}\n\nuint8_t ssc_a3_service_action(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tswitch (cdb[1]) {\n\tcase MANAGEMENT_PROTOCOL_IN:\n\t\tlog_opcode(\"MANAGEMENT PROTOCOL IN **\", cmd);\n\t\tbreak;\n\tcase REPORT_ALIASES:\n\t\tlog_opcode(\"REPORT ALIASES **\", cmd);\n\t\tbreak;\n\tcase REPORT_SUPPORTED_OPCODES:\n\t\tlog_opcode(\"REPORT SUPPORTED OPCODES **\", cmd);\n\t\tbreak;\n\tcase REPORT_TIMESTAMP:\n\t\tMHVTL_DBG(1, \"REPORT TIMESTAMP (%ld) **\", (long)dbuf_p->serialNo);\n\t\treturn report_timestamp(cmd);\n\t\tbreak;\n\tdefault:\n\t\tlog_opcode(\"UNKNOWN SERVICE ACTION A3 **\", cmd);\n\t\tbreak;\n\t}\n\treturn *sam_stat;\n}\n\nuint8_t ssc_a4_service_action(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tswitch (cdb[1]) {\n\tcase MANAGEMENT_PROTOCOL_OUT:\n\t\tlog_opcode(\"MANAGEMENT PROTOCOL OUT **\", cmd);\n\t\tbreak;\n\tcase CHANGE_ALIASES:\n\t\tlog_opcode(\"CHANGE ALIASES **\", cmd);\n\t\tbreak;\n\tcase FORCED_EJECT:\n\t\tlog_opcode(\"FORCED EJECT **\", cmd);\n\t\tbreak;\n\tcase SET_TIMESTAMP:\n\t\tMHVTL_DBG(1, \"SET TIMESTAMP (%ld) **\", (long)dbuf_p->serialNo);\n\t\treturn configure_timestamp(cmd);\n\t\tbreak;\n\tdefault:\n\t\tlog_opcode(\"UNKNOWN SERVICE ACTION A4 **\", cmd);\n\t\tbreak;\n\t}\n\treturn *sam_stat;\n}\n\nuint8_t ssc_spout(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tMHVTL_DBG(1, \"SECURITY PROTOCOL OUT (%ld) **\",\n\t\t\t  (long)dbuf_p->serialNo);\n\n\tdbuf_p->sz = get_unaligned_be32(&cdb[6]);\n\t/* Check for '512 increment' bit & multiply sz by 512 if set */\n\tdbuf_p->sz *= (cdb[4] & 0x80) ? 512 : 1;\n\n\tretrieve_CDB_data(cmd->cdev, dbuf_p);\n\n\treturn resp_spout(cmd);\n}\n\nuint8_t ssc_spin(struct scsi_cmd *cmd) {\n\tMHVTL_DBG(1, \"SECURITY PROTOCOL IN (%ld) **\",\n\t\t\t  (long)cmd->dbuf_p->serialNo);\n\n\treturn resp_spin(cmd);\n}\n\nuint8_t ssc_pr_out(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tMHVTL_DBG(1, \"PERSISTENT RESERVE OUT (%ld) **\",\n\t\t\t  (long)dbuf_p->serialNo);\n\tif (lu_priv->I_am_SPC_2_Reserved) {\n\t\tMHVTL_DBG(1, \"SPC 2 reserved\");\n\t\t*sam_stat = SAM_STAT_RESERVATION_CONFLICT;\n\t\treturn SAM_STAT_RESERVATION_CONFLICT;\n\t}\n\tdbuf_p->sz = get_unaligned_be32(&cdb[5]);\n\tretrieve_CDB_data(cmd->cdev, dbuf_p);\n\treturn resp_spc_pro(cdb, dbuf_p);\n}\n\n/*\n * Process the MODE_SELECT command\n */\nuint8_t ssc_mode_select(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tuint8_t\t   *bdb\t\t\t\t= NULL;\n\tint\t\t\tpage_len\t\t= 0;\n\tint\t\t\tmode_param_h_sz = 0;\n\tint\t\t\ti, j;\n\tint\t\t\tcount;\n\tint\t\t\tsave_pages;\n\tint\t\t\tpage_format;\n\tint\t\t\tmselect_6 = 0;\n\tint\t\t\tpage;\n\tint\t\t\toffset;\n\tint\t\t\tmode_medium_type;\n\tint\t\t\tmode_dev_spec_param;\n\tint\t\t\tmode_block_descriptor_len;\n\tstruct s_sd sd;\n\n\tsave_pages\t= cdb[1] & 0x01;\n\tpage_format = (cdb[1] & (1 << 4)) ? 1 : 0;\n\n\tswitch (cdb[0]) {\n\tcase MODE_SELECT:\n\t\tmselect_6\t\t= 1;\n\t\tdbuf_p->sz\t\t= cdb[4];\n\t\tmode_param_h_sz = 4;\n\t\tbreak;\n\tcase MODE_SELECT_10:\n\t\tdbuf_p->sz\t\t= get_unaligned_be16(&cdb[7]);\n\t\tmode_param_h_sz = 8;\n\t\tbreak;\n\tdefault:\n\t\tdbuf_p->sz = 0;\n\t}\n\n\tMHVTL_DBG(1, \"MODE SELECT %d (%ld) **\",\n\t\t\t  (mselect_6) ? 6 : 10, (long)dbuf_p->serialNo);\n\tMHVTL_DBG(1, \" Save Pages: %d, Page Format conforms to %s standard\",\n\t\t\t  save_pages, (page_format) ? \"T10\" : \"Vendor uniq\");\n\n\tcount = retrieve_CDB_data(cmd->cdev, dbuf_p);\n\n\tswitch (cmd->scb[0]) {\n\tcase MODE_SELECT:\n\t\tpage_len = buf[5];\n\t\tbreak;\n\tcase MODE_SELECT_10:\n\t\tpage_len = get_unaligned_be16(&buf[9]);\n\t\tbreak;\n\t}\n\n\t/*\n\t * As per t10.org SPC4r31 (6.9)\n\t *\n\t * A page format (PF) bit set to zero specifies that all parameters after\n\t * the block descriptors are vendor specific. A PF bit set to one specifies\n\t * that the MODE SELECT parameters following the header and block\n\t * descriptor(s) are structured as pages of related parameters and are\n\t * as defined in this standard.\n\t */\n\tif (!page_format && page_len) {\n\t\tMHVTL_DBG(1, \"PF bit cleared, yet page data supplied. Len: %d\",\n\t\t\t\t  page_len);\n\t\tsd.byte0\t\t = SKSV | CD | BPV | 4; /* bit 4 is invalid */\n\t\tsd.field_pointer = 1;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n#ifdef MHVTL_DEBUG\n\tif (debug)\n\t\thex_dump(buf, cmd->dbuf_p->sz);\n#endif\n\n\t/* T10 spec => MODE DATA LEN is reserved for MODE SELECT */\n\tMHVTL_DBG(3, \"count: %d, param header len: %d\", count, mode_param_h_sz);\n\tswitch (mode_param_h_sz) {\n\tcase 4: /* MODE SELECT 6 */\n\t\tmode_medium_type\t\t  = buf[1];\n\t\tmode_dev_spec_param\t\t  = buf[2];\n\t\tmode_block_descriptor_len = buf[3];\n\t\tbdb\t\t\t\t\t\t  = &buf[4];\n\t\tbreak;\n\tcase 8: /* MODE SELECT 10 */\n\t\tmode_medium_type\t\t  = buf[2];\n\t\tmode_dev_spec_param\t\t  = buf[3];\n\t\tmode_block_descriptor_len = get_unaligned_be16(&buf[6]);\n\t\tbdb\t\t\t\t\t\t  = &buf[8];\n\t\tbreak;\n\tdefault: /* Shouldn't be possible */\n\t\tMHVTL_LOG(\"Should never see this: line %d\", __LINE__);\n\t\tmode_medium_type\t\t  = 0;\n\t\tmode_dev_spec_param\t\t  = 0;\n\t\tmode_block_descriptor_len = 0;\n\t}\n\n\ti = j = 0;\n\tMHVTL_DBG(3, \" %02d: %02x %02x %02x %02x\"\n\t\t\t\t \"  %02x %02x %02x %02x\"\n\t\t\t\t \"  %02x %02x %02x %02x\"\n\t\t\t\t \"  %02x %02x %02x %02x\",\n\t\t\t  j,\n\t\t\t  buf[i + 0], buf[i + 1], buf[i + 2], buf[i + 3],\n\t\t\t  buf[i + 4], buf[i + 5], buf[i + 6], buf[i + 7],\n\t\t\t  buf[i + 8], buf[i + 9], buf[i + 10], buf[i + 11],\n\t\t\t  buf[i + 12], buf[i + 13], buf[i + 14], buf[i + 15]);\n\n\tMHVTL_DBG(3, \"Mode Param header: Medium type 0x%02x, \"\n\t\t\t\t \"Device spec param 0x%02x, \"\n\t\t\t\t \"Blk Descr Len 0x%02x, \"\n\t\t\t\t \"Buff mode %d, Speed %d\",\n\t\t\t  mode_medium_type,\n\t\t\t  mode_dev_spec_param,\n\t\t\t  mode_block_descriptor_len,\n\t\t\t  (mode_dev_spec_param & 0x70) >> 4,\n\t\t\t  (mode_dev_spec_param & 0x0f));\n\n\ti = mode_param_h_sz;\n\tif (mode_block_descriptor_len) {\n\t\tmemcpy(modeBlockDescriptor, bdb, mode_block_descriptor_len);\n\t\tMHVTL_DBG(3, \"Descriptor block: density code 0x%02x, \"\n\t\t\t\t\t \"No. of blocks 0x%02x, \"\n\t\t\t\t\t \"Block length 0x%02x\",\n\t\t\t\t  buf[i],\n\t\t\t\t  get_unaligned_be24(&buf[i + 1]),\n\t\t\t\t  get_unaligned_be24(&buf[i + 5]));\n\t}\n\n\t/*\n\t * As per t10.org SPC4r31 (6.9)\n\t *\n\t * A save pages (SP) bit set to zero specifies that the device server\n\t * shall perform the specified MODE SELECT operation, and shall not\n\t * save any mode pages. If the logical unit implements no distinction\n\t * between current and saved mode pages and the SP bit is set to zero,\n\t * the command shall be terminated with CHECK CONDITION status,\n\t * with the sense key set to ILLEGAL REQUEST, and the additional\n\t * sense code set to INVALID FIELD IN CDB.\n\t * An SP bit set to one specifies that the device server shall perform\n\t * the specified MODE SELECT operation, and shall save to a nonvolatile\n\t * vendor specific location all the saveable mode pages including any\n\t * sent in the Data-Out Buffer.\n\t * Mode pages that are saved are specified by the parameter saveable\n\t * (PS) bit that is returned in the first byte of each mode page by\n\t * the MODE SENSE command (see 7.5). If the PS bit is set to one in\n\t * the MODE SENSE data, then the mode page shall be saveable by\n\t * issuing a MODE SELECT command with the SP bit set to one. If the\n\t * logical unit does not implement saved mode pages and the SP bit is\n\t * set to one, then the command shall be terminated with CHECK CONDITION\n\t * status, with the sense key set to ILLEGAL REQUEST, and the additional\n\t * sense code set to INVALID FIELD IN CDB.\n\t */\n\tif (save_pages) {\n\t\tMHVTL_DBG(1, \" Save pages bit set. Not supported\");\n\t\tsd.byte0\t\t = SKSV | CD | BPV | 1; /* bit 1 is invalid */\n\t\tsd.field_pointer = 1;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\ti += mode_block_descriptor_len;\n\tj = 0;\n\twhile (i < count) {\n\t\toffset\t = 2;\n\t\tpage\t = buf[i];\n\t\tpage_len = buf[i + 1];\n\n\t\tMHVTL_DBG(2, \" Page: 0x%02x, Page Len: 0x%02x\", page, page_len);\n\n\t\tif (page_len) {\n\t\t\tMHVTL_DBG(3, \" %02d: %02x %02x %02x %02x\"\n\t\t\t\t\t\t \"  %02x %02x %02x %02x\",\n\t\t\t\t\t  j,\n\t\t\t\t\t  buf[i + 0], buf[i + 1], buf[i + 2], buf[i + 3],\n\t\t\t\t\t  buf[i + 4], buf[i + 5], buf[i + 6], buf[i + 7]);\n\t\t}\n\t\tif (page_len > 8) {\n\t\t\tif (page_len == 0x0e) { /* Common page len */\n\t\t\t\tMHVTL_DBG(3, \" %02d: %02x %02x %02x %02x\"\n\t\t\t\t\t\t\t \"  %02x %02x\",\n\t\t\t\t\t\t  j + 8,\n\t\t\t\t\t\t  buf[i + 8], buf[i + 9], buf[i + 10], buf[i + 11],\n\t\t\t\t\t\t  buf[i + 12], buf[i + 13]);\n\t\t\t} else {\n\t\t\t\tMHVTL_DBG(3, \" %02d: %02x %02x %02x %02x\"\n\t\t\t\t\t\t\t \"  %02x %02x %02x %02x\",\n\t\t\t\t\t\t  j + 8,\n\t\t\t\t\t\t  buf[i + 8], buf[i + 9], buf[i + 10], buf[i + 11],\n\t\t\t\t\t\t  buf[i + 12], buf[i + 13], buf[i + 14], buf[i + 15]);\n\t\t\t}\n\t\t}\n\t\tif (page_len > 16) {\n\t\t\tMHVTL_DBG(3, \" %02d: %02x %02x %02x %02x\"\n\t\t\t\t\t\t \"  %02x %02x %02x %02x\",\n\t\t\t\t\t  j + 16,\n\t\t\t\t\t  buf[i + 16], buf[i + 17], buf[i + 18], buf[i + 19],\n\t\t\t\t\t  buf[i + 20], buf[i + 21], buf[i + 22], buf[i + 23]);\n\t\t}\n\t\tif (page_len > 24) {\n\t\t\tMHVTL_DBG(3, \" %02d: %02x %02x %02x %02x\"\n\t\t\t\t\t\t \"  %02x %02x %02x %02x\",\n\t\t\t\t\t  j + 24,\n\t\t\t\t\t  buf[i + 24], buf[i + 25], buf[i + 26], buf[i + 27],\n\t\t\t\t\t  buf[i + 28], buf[i + 29], buf[i + 30], buf[i + 31]);\n\t\t}\n\n\t\tswitch (page) {\n\t\tcase MODE_DATA_COMPRESSION:\n\t\t\tif (page_len == 0x0e)\n\t\t\t\tset_mode_compression(cmd, &buf[i]);\n\t\t\tbreak;\n\n\t\tcase MODE_DEVICE_CONFIGURATION:\n\t\t\t/* If this is '01' it's a subpage value\n\t\t\t *     i.e. DEVICE CONFIGURATION EXTENSION\n\t\t\t * If it's 0x0e, it indicates a page length\n\t\t\t * for MODE DEVICE CONFIGURATION\n\t\t\t */\n\t\t\tif (page_len == 0x01) {\n\t\t\t\tif (set_device_configuration_extension(cmd, &buf[i]))\n\t\t\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t\t\t/* Subpage 1 - override default page length */\n\t\t\t\tpage_len = get_unaligned_be16(&buf[i + 2]);\n\t\t\t\toffset\t = 4;\n\t\t\t} else if (page_len >= 0x0e) {\n\t\t\t\tset_device_configuration(cmd, &buf[i]);\n\t\t\t} else {\n\t\t\t\tMHVTL_DBG(2, \"Invalid page len: 0x%02x\",\n\t\t\t\t\t\t  page_len);\n\t\t\t\tsd.byte0\t\t = SKSV;\n\t\t\t\tsd.field_pointer = i + 1;\n\t\t\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase MODE_CONTROL:\n\t\t\tif (page_len == 0x0a) {\t\t\t\t\t  /* Control mode page - byte[1] is page len */\n\t\t\t\tMHVTL_DBG(3, \"Setting Mode Control\"); /* Silently accept this worked, but really did not change anything */\n\t\t\t} else {\n\t\t\t\t/* Otherwise, subpage handling - where page len is byte[2] & byte[3] */\n\t\t\t\tpage_len = get_unaligned_be16(&buf[i + 2]);\n\t\t\t\tif (buf[1 + i] == 0xf0) {\n\t\t\t\t\t/* Logical Block Protection */\n\t\t\t\t\tMHVTL_DBG(2, \"Setting LBP method: %d, LBP length: %d, LBP_W: %s, LBP_R: %s\",\n\t\t\t\t\t\t\t  buf[4 + i], buf[5 + i],\n\t\t\t\t\t\t\t  (buf[6 + i] & 0x80) ? \"True\" : \"False\",\n\t\t\t\t\t\t\t  (buf[6 + i] & 0x40) ? \"True\" : \"False\");\n\t\t\t\t\tif (set_lbp(cmd, &buf[i], page_len))\n\t\t\t\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t\t\t} else {\n\t\t\t\t\tMHVTL_DBG(2, \"Mode Control - Subpage: 0x%02x not supported\", buf[i + 1]);\n\t\t\t\t\tsd.byte0\t\t = SKSV;\n\t\t\t\t\tsd.field_pointer = i;\n\t\t\t\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\t\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn SAM_STAT_GOOD;\n\t\t\tbreak;\n\n\t\tcase MODE_MEDIUM_PARTITION:\n\t\t\tset_medium_partition(cmd, &buf[i]);\n\t\t\treturn SAM_STAT_GOOD;\n\n\t\tdefault:\n\t\t\tMHVTL_DBG_PRT_CDB(1, cmd);\n\t\t\tMHVTL_LOG(\"Mode page 0x%02x not handled\", page);\n\t\t\tsd.byte0\t\t = SKSV;\n\t\t\tsd.field_pointer = i;\n\t\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t\tbreak;\n\t\t}\n\t\tif (page_len == 0) { /* Something wrong with data structure */\n\t\t\tpage_len = dbuf_p->sz;\n\t\t\tMHVTL_LOG(\"Problem with mode select data structure\");\n\t\t\tsd.byte0\t\t = SKSV;\n\t\t\tsd.field_pointer = i + 1;\n\t\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t}\n\t\ti += page_len + offset; /* Next mode page */\n\t\tj += page_len;\n\t}\n\n\treturn SAM_STAT_GOOD;\n}\n\nuint8_t ssc_write_attributes(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tint sz;\n\n\tMHVTL_DBG(1, \"WRITE ATTRIBUTES (%ld) **\", (long)dbuf_p->serialNo);\n\n\tswitch (get_tape_load_status()) {\n\tcase TAPE_UNLOADED:\n\t\tsam_not_ready(E_MEDIUM_NOT_PRESENT, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\tbreak;\n\tcase TAPE_LOADED:\n\t\tdbuf_p->sz = get_unaligned_be32(&cdb[10]);\n\t\tsz\t\t   = retrieve_CDB_data(cmd->cdev, dbuf_p);\n\t\tMHVTL_DBG(1, \"  --> Expected to read %d bytes\"\n\t\t\t\t\t \", read %d\",\n\t\t\t\t  dbuf_p->sz, sz);\n\t\tif (resp_write_attribute(cmd) > 0)\n\t\t\trewriteMAM(sam_stat);\n\t\tbreak;\n\tdefault:\n\t\tsam_not_ready(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\tbreak;\n\t}\n\treturn SAM_STAT_GOOD;\n}\n\nuint8_t ssc_tur(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tchar\t\t str[128];\n\tconst char\t*suffix;\n\tsize_t\t\t prefix_len;\n\n\t/* Large serial numbers + longest suffix (\"No, Media format\n\t * corrupt\") can exceed the original 64-byte buffer. Use a 128-byte\n\t * buffer with snprintf for both the prefix and the suffix append.\n\t */\n\tprefix_len = snprintf(str, sizeof(str), \"TEST UNIT READY (%ld) ** : \",\n\t\t\t\t\t\t  (long)dbuf_p->serialNo);\n\tif (prefix_len >= sizeof(str))\n\t\tprefix_len = sizeof(str) - 1;\n\n\tsuffix = NULL;\n\tswitch (get_tape_load_status()) {\n\tcase TAPE_UNLOADED:\n\t\tsuffix = \"No, No tape loaded\";\n\t\tsam_not_ready(E_MEDIUM_NOT_PRESENT, sam_stat);\n\t\tbreak;\n\tcase TAPE_LOADING:\n\t\tsuffix = \"No, Tape loading\";\n\t\tsam_not_ready(E_BECOMING_READY, sam_stat);\n\t\tbreak;\n\tcase TAPE_LOADED:\n\t\tif (mam.MediumType == MEDIA_TYPE_CLEAN) {\n\t\t\tint state;\n\n\t\t\tsuffix = \"No, Cleaning cart loaded\";\n\n\t\t\tif (lu_priv->cleaning_media_state)\n\t\t\t\tstate = *lu_priv->cleaning_media_state;\n\t\t\telse\n\t\t\t\tstate = 0;\n\n\t\t\tswitch (state) {\n\t\t\tcase CLEAN_MOUNT_STAGE1:\n\t\t\t\tsam_not_ready(E_CLEANING_CART_INSTALLED, sam_stat);\n\t\t\t\tbreak;\n\t\t\tcase CLEAN_MOUNT_STAGE2:\n\t\t\t\tsam_not_ready(E_CAUSE_NOT_REPORTABLE, sam_stat);\n\t\t\t\tbreak;\n\t\t\tcase CLEAN_MOUNT_STAGE3:\n\t\t\t\tsam_not_ready(E_INITIALIZING_REQUIRED, sam_stat);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tMHVTL_ERR(\"Unknown cleaning media mount state\");\n\t\t\t\tsam_not_ready(E_CLEANING_CART_INSTALLED, sam_stat);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} else\n\t\t\tsuffix = \"Yes\";\n\t\tbreak;\n\tdefault:\n\t\tsuffix = \"No, Media format corrupt\";\n\t\tsam_not_ready(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\tbreak;\n\t}\n\n\tif (suffix)\n\t\tsnprintf(str + prefix_len, sizeof(str) - prefix_len, \"%s\", suffix);\n\n\tMHVTL_DBG(1, \"%s\", str);\n\n\treturn *sam_stat;\n}\n\nuint8_t ssc_rewind(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tint retval;\n\n\tMHVTL_DBG(1, \"REWINDING (%ld) **\", (long)dbuf_p->serialNo);\n\n\tset_current_state(MHVTL_STATE_REWIND);\n\n\tswitch (get_tape_load_status()) {\n\tcase TAPE_UNLOADED:\n\t\tsam_not_ready(E_MEDIUM_NOT_PRESENT, sam_stat);\n\t\tbreak;\n\tcase TAPE_LOADED:\n\t\tretval = rewind_tape(sam_stat);\n\t\tdelay_opcode(DELAY_REWIND, lu_priv->delay_rewind);\n\t\tif (retval < 0) {\n\t\t\tsam_not_ready(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\t}\n\t\tbreak;\n\tdefault:\n\t\tsam_not_ready(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\tbreak;\n\t}\n\n\treturn *sam_stat;\n}\n\nuint8_t ssc_read_attributes(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tuint8_t\t\tservice_action = cmd->scb[1] & 0b00011111;\n\tstruct s_sd sd;\n\n\tMHVTL_DBG(1, \"READ ATTRIBUTE (%ld) ** %s\",\n\t\t\t  (long)cmd->dbuf_p->serialNo,\n\t\t\t  (service_action == 0)\t  ? \"Attribute Values\"\n\t\t\t  : (service_action == 1) ? \"Attribute List\"\n\t\t\t  : (service_action == 2) ? \"Logical Volume List\"\n\t\t\t  : (service_action == 3) ? \"Partition List\"\n\t\t\t  : (service_action == 5) ? \"Supported Attributes\"\n\t\t\t\t\t\t\t\t\t  : \"Unknown service action\");\n\n\tswitch (get_tape_load_status()) {\n\tcase TAPE_UNLOADED:\n\t\tMHVTL_DBG(1, \"Failed due to \\\"no media loaded\\\"\");\n\t\tsam_not_ready(E_MEDIUM_NOT_PRESENT, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\tbreak;\n\tcase TAPE_LOADED:\n\t\tbreak;\n\tdefault:\n\t\tMHVTL_DBG(1, \"Failed due to \\\"media corrupt\\\"\");\n\t\tsam_not_ready(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\tbreak;\n\t}\n\n\tif (cdb[7] > mam.num_partitions) {\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, NULL, sam_stat);\n\t\tMHVTL_DBG(1, \"Not enough partitions : requested partition %d over %d \", cdb[7], mam.num_partitions);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tswitch (service_action) {\n\tcase 0x00: /* Attribute values */\n\tcase 0x01: /* Attribute list */\n\t\tdbuf_p->sz = resp_read_attribute(cmd);\n\t\tbreak;\n\tcase 0x03:\t\t\t\t\t\t\t\t /* Partition list */\n\t\tput_unaligned_be16(0x0002, &buf[0]); /* Available data */\n\t\tbuf[1]\t   = 0;\t\t\t\t\t\t /* First partition number */\n\t\tbuf[2]\t   = mam.num_partitions;\t /* Number of partitions available */\n\t\tdbuf_p->sz = buf[0];\n\t\tbreak;\n\tdefault:\n\t\tsd.byte0\t\t = SKSV | CD;\n\t\tsd.field_pointer = 1;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t}\n\n\treturn *sam_stat;\n}\n\nuint8_t ssc_read_block_limits(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tMHVTL_DBG(1, \"READ BLOCK LIMITS (%ld) **\",\n\t\t\t  (long)dbuf_p->serialNo);\n\n\tswitch (get_tape_load_status()) {\n\tcase TAPE_LOADED:\n\tcase TAPE_UNLOADED:\n\t\tdbuf_p->sz = resp_read_block_limits(dbuf_p, lu_priv->bufsize);\n\t\tbreak;\n\tcase TAPE_LOADING:\n\t\tsam_not_ready(E_BECOMING_READY, sam_stat);\n\t\tbreak;\n\tdefault:\n\t\tsam_not_ready(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\tbreak;\n\t}\n\n\treturn *sam_stat;\n}\n\n/* SPC 6.17 - READ MEDIA SERIAL NUMBER */\nuint8_t ssc_read_media_sn(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tuint32_t\talloc_len = get_unaligned_be32(&cdb[6]);\n\tstruct s_sd sd;\n\n\tMHVTL_DBG(1, \"READ MEDIUM SERIAL NO. (%ld) **\",\n\t\t\t  (long)dbuf_p->serialNo);\n\n\tif (cdb[1] != 1) { /* Service Action 1 only */\n\t\tsd.byte0\t\t = SKSV | CD;\n\t\tsd.field_pointer = 1;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tmemset_ssc_buf(cmd, alloc_len);\n\n\tswitch (get_tape_load_status()) {\n\tcase TAPE_LOADED:\n\t\tdbuf_p->sz = resp_read_media_serial(lu_priv->mediaSerialNo,\n\t\t\t\t\t\t\t\t\t\t\tbuf,\n\t\t\t\t\t\t\t\t\t\t\tsam_stat);\n\t\tbreak;\n\tcase TAPE_UNLOADED:\n\t\tsam_not_ready(E_MEDIUM_NOT_PRESENT, sam_stat);\n\t\tbreak;\n\tdefault:\n\t\tsam_not_ready(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\tbreak;\n\t}\n\treturn *sam_stat;\n}\n\n#define READ_POSITION_SERVICE_ACTION 0b000111111\n#define READ_POSITION_SHORT_LEN\t\t 20\n#define READ_POSITION_LONG_LEN\t\t 32\n#define READ_POSITION_EXTENDED_LEN\t 32\n\n#define SET_BOP(ptr, blk_number)                                  \\\n\tdo {                                                          \\\n\t\tif ((blk_number) < 2) {                                   \\\n\t\t\t(ptr)->BOP = 1;                                       \\\n\t\t\tMHVTL_DBG(3, \"Setting Beginning of Partition (BOP)\"); \\\n\t\t}                                                         \\\n\t} while (0)\n\n#define SET_BPEW(ptr, offset, lu_priv)                                                                                  \\\n\tdo {                                                                                                                \\\n\t\tif ((lu_priv->pm->drive_supports_prog_early_warning) && ((offset) >= (lu_priv->prog_early_warning_position))) { \\\n\t\t\t(ptr)->BPEW = 1;                                                                                            \\\n\t\t\tMHVTL_DBG(3, \"Drive supports prog early warning : Setting prog_early_warning of Partition\");                \\\n\t\t} else {                                                                                                        \\\n\t\t\t(ptr)->BPEW = 0;                                                                                            \\\n\t\t}                                                                                                               \\\n\t} while (0)\n\n#define SET_EOP(ptr, offset, eop_pos)                       \\\n\tdo {                                                    \\\n\t\tif ((offset) > (eop_pos)) {                         \\\n\t\t\t(ptr)->EOP = 1;                                 \\\n\t\t\tMHVTL_DBG(3, \"Setting End of Partition (EOP)\"); \\\n\t\t} else {                                            \\\n\t\t\t(ptr)->EOP = 0;                                 \\\n\t\t}                                                   \\\n\t} while (0)\n\n#define SET_PERR(ptr, blk_number)                                                                  \\\n\tdo {                                                                                           \\\n\t\tif ((blk_number) > 0xFFFFFFFF) {                                                           \\\n\t\t\t(ptr)->PERR = 1;                                                                       \\\n\t\t\tMHVTL_DBG(1, \"More than supported number of blocks - Setting Logical Block overflow\"); \\\n\t\t}                                                                                          \\\n\t} while (0)\n\nuint8_t ssc_read_position(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tuint8_t\t\t\t\t\t\t\t\t\t   service_action = cdb[1] & READ_POSITION_SERVICE_ACTION;\n\tstruct s_sd\t\t\t\t\t\t\t\t   sd;\n\tuint64_t\t\t\t\t\t\t\t\t   filemarks = 0;\n\tstruct read_position_information_short\t  *sp;\n\tstruct read_position_information_long\t  *lp;\n\tstruct read_position_information_extended *ep;\n\n\tMHVTL_DBG(1, \"READ POSITION (%ld) ** %s form\",\n\t\t\t  (long)cmd->dbuf_p->serialNo,\n\t\t\t  (service_action == 0)\t  ? \"Short\"\n\t\t\t  : (service_action == 6) ? \"Long\"\n\t\t\t  : (service_action == 8) ? \"Extended\"\n\t\t\t\t\t\t\t\t\t  : \"Unknown\");\n\n\tswitch (get_tape_load_status()) {\n\tcase TAPE_LOADED:\n\t\tswitch (service_action) {\n\t\tcase 0:\n\t\tcase 1:\n\t\tsp = (struct read_position_information_short *)&buf[0];\n\n\t\t\tmemset(buf, 0, READ_POSITION_SHORT_LEN); /* Clear 'array' */\n\n\t\t\tSET_BOP(sp, c_pos->blk_number);\t /* Beginning of partition */\n\t\t\tsp->LOCU = 0;\t\t\t\t\t /* Logical object count unknown - 0: Block count is exact */\n\t\t\tsp->BYCU = 1;\t\t\t\t\t /* Logical byte count unknown - 1: Byte count is estimate */\n\t\t\tsp->LOLU = 0;\t\t\t\t\t /* Logical Object Location Unknown - 0: Count is exact */\n\t\t\tSET_PERR(sp, c_pos->blk_number); /* logical block address overflow - currently not possible as blk_number is a uint32_t */\n\t\t\tif (sp->LOLU == 0)\n\t\t\t\tSET_BPEW(sp, current_tape_offset(), lu_priv);\n\t\t\tSET_EOP(sp, current_tape_offset(), lu_priv->early_warning_position);\n\n\t\t\tbuf[1] = c_pos->partition_id;\n\t\t\tput_unaligned_be32(c_pos->blk_number, &buf[4]); /* First Logical Object Location - (current location) */\n\t\t\tput_unaligned_be32(c_pos->blk_number, &buf[8]); /* After a write, Logical Object Location of the new write - If buffer empty: == first logical objecct */\n\t\t\t// &buf[13] nb logical objects in object buffer\n\t\t\t// &buf[16] nb bytes in object buffer\n\n\t\t\tMHVTL_DBG(1, \"Positioned at partition/block %u/%u\", c_pos->partition_id, c_pos->blk_number);\n\t\t\tdbuf_p->sz = READ_POSITION_SHORT_LEN;\n\t\t\tbreak;\n\n\t\tcase 6:\n\t\t\tlp = (struct read_position_information_long *)&buf[0];\n\n\t\t\tmemset(buf, 0, READ_POSITION_LONG_LEN); /* Clear 'array' */\n\n\t\t\tSET_BOP(lp, c_pos->blk_number); /* Beginning of partition */\n\t\t\tlp->LONU = 0;\t\t\t\t\t/* Set 'Logical Object Number Unknown' bit valid (block location info is valid) */\n\t\t\tlp->MPU\t = 0;\t\t\t\t\t/* Mark Position Unknown : 0 = num filemarks is known */\n\t\t\tSET_BPEW(lp, current_tape_offset(), lu_priv);\n\t\t\tSET_EOP(lp, current_tape_offset(), lu_priv->early_warning_position);\n\n\t\t\tfilemarks = count_filemarks(c_pos->blk_number);\n\n\t\t\tput_unaligned_be32(c_pos->partition_id, &buf[4]);\n\t\t\tput_unaligned_be64(c_pos->blk_number, &buf[8]);\n\t\t\tput_unaligned_be64(filemarks, &buf[16]);\n\t\t\t// &buf[24] Logical Set Identifier - Obsolete...\n\n\t\t\tMHVTL_DBG(1, \"Positioned at partition/block %u/%u, %lu filemarks after BOP\",\n\t\t\t\t\t  c_pos->partition_id, c_pos->blk_number, filemarks);\n\t\t\tdbuf_p->sz = READ_POSITION_LONG_LEN;\n\t\t\tbreak;\n\n\t\tcase 8:\n\t\t\tep = (struct read_position_information_extended *)&buf[0];\n\n\t\t\tmemset(buf, 0, READ_POSITION_EXTENDED_LEN); /* Clear 'array' */\n\n\t\t\tSET_BOP(ep, c_pos->blk_number); /* Beginning of partition */\n\t\t\tep->BYCU = 1;\t\t\t\t\t/* Logical byte count unknown - 1: Byte count is estimate */\n\t\t\tep->LOLU = 0;\t\t\t\t\t/* Logical Object Location Unknown - 0: Count is exact */\n\t\t\tif (ep->LOLU == 0)\n\t\t\t\tSET_BPEW(ep, current_tape_offset(), lu_priv);\n\t\t\tSET_EOP(ep, current_tape_offset(), lu_priv->early_warning_position);\n\n\t\t\tbuf[1] = (uint8_t)c_pos->partition_id;\n\t\t\tput_unaligned_be16(0x1C, &buf[2]); /* Additional length */\n\t\t\t// &buf[5] nb logical objects in object buffer\n\t\t\tput_unaligned_be64(c_pos->blk_number, &buf[8]);\t /* First Logical Object Location - (current location) */\n\t\t\tput_unaligned_be64(c_pos->blk_number, &buf[16]); /* After a write, Logical Object Location of the new write - If buffer empty: == first logical objecct */\n\t\t\t// &buf[24] nb bytes in object buffer\n\n\t\t\tMHVTL_DBG(1, \"Positioned at partition/block %u/%u\", c_pos->partition_id, c_pos->blk_number);\n\t\t\tcmd->dbuf_p->sz = READ_POSITION_EXTENDED_LEN;\n\n\t\tdefault:\n\t\t\tMHVTL_DBG(1, \"service_action not supported\");\n\t\t\tsd.byte0\t\t = SKSV | CD;\n\t\t\tsd.field_pointer = 1;\n\t\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd,\n\t\t\t\t\t\t\t\tsam_stat);\n\t\t}\n\t\tbreak;\n\tcase TAPE_UNLOADED:\n\t\tsam_not_ready(E_MEDIUM_NOT_PRESENT, sam_stat);\n\t\tbreak;\n\tdefault:\n\t\tsam_not_ready(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\tbreak;\n\t}\n\treturn *sam_stat;\n}\n\nuint8_t ssc_release(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tMHVTL_DBG(1, \"RELEASE (%ld) **\", (long)dbuf_p->serialNo);\n\n\tif (!SPR_Reservation_Type && SPR_Reservation_Key)\n\t\treturn SAM_STAT_RESERVATION_CONFLICT;\n\n\tlu_priv->I_am_SPC_2_Reserved = 0;\n\treturn SAM_STAT_GOOD;\n}\n\nuint8_t ssc_report_density_support(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tstruct s_sd sd;\n\tuint8_t\t\tmedia = cdb[1] & 0x01;\n\n\tdbuf_p->sz = 0;\n\n\tMHVTL_DBG(1, \"REPORT %s DENSITY SUPPORT (%ld) **\",\n\t\t\t  (media) ? \"MOUNTED MEDIA\" : \"DRIVE\",\n\t\t\t  (long)dbuf_p->serialNo);\n\n\tif (cdb[1] & 0x02) { /* Don't support Medium Type (yet) */\n\t\tMHVTL_DBG(1, \"Medium Type - not currently supported\");\n\t\tsd.byte0\t\t = SKSV | CD;\n\t\tsd.field_pointer = 1;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tif (media == 1 && get_tape_load_status() != TAPE_LOADED) {\n\t\tMHVTL_DBG(1, \"Media has to be mounted to return media density\");\n\t\tsam_not_ready(E_MEDIUM_NOT_PRESENT, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tmemset_ssc_buf(cmd, get_unaligned_be16(&cdb[7]));\n\n\tdbuf_p->sz = resp_report_density(lu_priv, media, dbuf_p);\n\n\treturn SAM_STAT_GOOD;\n}\n\nuint8_t ssc_reserve(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tMHVTL_DBG(1, \"RESERVE (%ld) **\", (long)dbuf_p->serialNo);\n\n\tif (!SPR_Reservation_Type && !SPR_Reservation_Key)\n\t\tlu_priv->I_am_SPC_2_Reserved = 1;\n\tif (!SPR_Reservation_Type && SPR_Reservation_Key)\n\t\treturn SAM_STAT_RESERVATION_CONFLICT;\n\treturn SAM_STAT_GOOD;\n}\n\nuint8_t ssc_erase(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tMHVTL_DBG(1, \"ERASING (%ld) **\", (long)dbuf_p->serialNo);\n\n\tset_current_state(MHVTL_STATE_ERASE);\n\n\tif (!lu_priv->pm->check_restrictions(cmd))\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\n\tif (c_pos->blk_number != 0) {\n\t\tMHVTL_LOG(\"Not at BOT.. Can't erase unless at BOT\");\n\t\tsam_not_ready(E_INVALID_FIELD_IN_CDB, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tif (OK_to_write)\n\t\tformat_partition(sam_stat);\n\telse {\n\t\tMHVTL_LOG(\"Attempt to erase Write-protected media\");\n\t\tsam_not_ready(E_MEDIUM_OVERWRITE_ATTEMPT, sam_stat);\n\t}\n\treturn *sam_stat;\n}\n\nuint8_t ssc_space_6(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tuint32_t\tcount;\n\tint32_t\t\ticount;\n\tuint8_t\t\tcode;\n\tstruct s_sd sd;\n\n\tset_current_state(MHVTL_STATE_POSITIONING);\n\n\tcount = get_unaligned_be24(&cdb[2]);\n\tcode  = cdb[1] & 0x07;\n\n\t/* 'count' is only a 24-bit value.  If the top bit is set, it\n\t   should be treated as a twos-complement negative number.\n\t*/\n\n\tif (cdb[2] >= 0x80) /* MSB of the count field */\n\t\ticount = -(0xffffff - count + 1);\n\telse\n\t\ticount = (int32_t)count;\n\n\tswitch (code) {\n\tcase 0: /* Logical blocks - supported */\n\tcase 1: /* filemarks - supported */\n\t\tMHVTL_DBG(1, \"SPACE 6 (%ld) ** %s %d %s%s\",\n\t\t\t\t  (long)dbuf_p->serialNo,\n\t\t\t\t  (icount >= 0) ? \"forward \" : \"back \", abs(icount),\n\t\t\t\t  (code == 0) ? \"block\" : \"filemark\",\n\t\t\t\t  (abs(icount) != 1) ? \"s\" : \"\");\n\t\tbreak;\n\tcase 3: /* End of Data - supported */\n\t\tMHVTL_DBG(1, \"SPACE 6 (%ld) ** %s \",\n\t\t\t\t  (long)dbuf_p->serialNo, \"to End-of-data\");\n\t\tbreak;\n\tcase 2:\t /* Sequential filemarks currently not supported */\n\tdefault: /* Unsupported or reserved option */\n\t\tMHVTL_DBG(1, \"SPACE 6 (%ld) ** - Unsupported option %d\",\n\t\t\t\t  (long)dbuf_p->serialNo, code);\n\t\tsd.byte0\t\t = SKSV | CD | BPV | code;\n\t\tsd.field_pointer = 1;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_PARMS, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\tbreak;\n\t}\n\n\tif (icount != 0 || code == 3)\n\t\tresp_space(icount, code, sam_stat);\n\n\treturn *sam_stat;\n}\n\nuint8_t ssc_space_16(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tuint8_t\t\tcode = cdb[1] & 0x0f;\n\tstruct s_sd sd;\n\tint64_t\t\ticount = get_unaligned_be64(&cmd->scb[4]);\n\n\tset_current_state(MHVTL_STATE_POSITIONING);\n\n\tswitch (code) {\n\tcase 0: /* Logical blocks - supported */\n\tcase 1: /* filemarks - supported */\n\t\tMHVTL_DBG(1, \"SPACE 16 (%ld) ** %s %d %s%s\",\n\t\t\t\t  (long)dbuf_p->serialNo,\n\t\t\t\t  (icount >= 0) ? \"forward \" : \"back \", abs(icount),\n\t\t\t\t  (code == 0) ? \"block\" : \"filemark\",\n\t\t\t\t  (abs(icount) != 1) ? \"s\" : \"\");\n\t\tbreak;\n\tcase 3: /* End of Data - supported */\n\t\tMHVTL_DBG(1, \"SPACE 16 (%ld) ** %s \",\n\t\t\t\t  (long)dbuf_p->serialNo, \"to End-of-data\");\n\t\tbreak;\n\tcase 2:\t /* Sequential filemarks currently not supported */\n\tdefault: /* Unsupported or reserved option */\n\t\tMHVTL_DBG(1, \"SPACE 16 (%ld) ** - Unsupported option %d\",\n\t\t\t\t  (long)dbuf_p->serialNo, code);\n\t\tsd.byte0\t\t = SKSV | CD | BPV | code;\n\t\tsd.field_pointer = 1;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_PARMS, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\tbreak;\n\t}\n\n\tif (icount != 0 || code == 3)\n\t\tresp_space(icount, code, sam_stat);\n\n\treturn *sam_stat;\n}\n\nuint8_t ssc_load_unload(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tstruct s_sd sd;\n\tint\t\t\tload_request = cdb[4] & 0x01;\n\tint\t\t\tmedia_state;\n\n\tset_current_state((load_request) ? MHVTL_STATE_LOADING : MHVTL_STATE_UNLOADING);\n\n\tif (cdb[4] & 0x04) { /* EOT bit */\n\t\tMHVTL_ERR(\"EOT bit set on load. Not supported\");\n\t\tsd.byte0\t\t = SKSV | CD | BPV | 4;\n\t\tsd.field_pointer = 4;\n\t\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tMHVTL_DBG(1, \"TAPE %s (%ld) **\",\n\t\t\t  (load_request) ? \"LOADING\" : \"UNLOADING\", (long)cmd->dbuf_p->serialNo);\n\n\tchange_partition(0);\n\tmedia_state = rewind_tape(sam_stat);\n\tswitch (get_tape_load_status()) {\n\tcase TAPE_UNLOADED:\n\t\tif (load_request) {\n\t\t\tint load_state;\n\t\t\t/*\n\t\t\t * media_state = 0 - Load OK -> Nothing to do\n\t\t\t * media_state = 1 - Already loaded -> Nothing to do\n\t\t\t */\n\t\t\tswitch (media_state) {\n\t\t\tcase 0:\n\t\t\t\t/*\n\t\t\t\t * lu_priv->barcode indicates there is a tape in mouth\n\t\t\t\t * media not mounted, and receive a mount request - attempt\n\t\t\t\t * to load media\n\t\t\t\t */\n\t\t\t\tif (!lu_priv->barcode) {\n\t\t\t\t\tsam_not_ready(E_MEDIUM_NOT_PRESENT, sam_stat);\n\t\t\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t\t\t}\n\t\t\t\tload_state = loadTape(lu_priv->barcode, sam_stat);\n\t\t\t\tif (load_state == 2) {\n\t\t\t\t\tsam_not_ready(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\t\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t\t\t} else if (load_state == 3) {\n\t\t\t\t\tsam_not_ready(E_MEDIUM_NOT_PRESENT, sam_stat);\n\t\t\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 1:\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tsam_not_ready(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} else {\n\t\t\tsam_not_ready(E_MEDIUM_NOT_PRESENT, sam_stat);\n\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t\t}\n\t\tset_lp11_medium_present(1);\n\t\tbreak;\n\n\tcase TAPE_LOADED:\n\t\tif (!load_request) {\n\t\t\t/* Send library an update status 'true' */\n\t\t\tunloadTape(TRUE, sam_stat);\n\t\t\tset_lp11_medium_present(0);\n\t\t} else {\n\t\t\tset_lp11_medium_present(1);\n\t\t}\n\t\tbreak;\n\n\tdefault:\n\t\tsam_not_ready(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\tbreak;\n\t}\n\treturn *sam_stat;\n}\n\nuint8_t ssc_write_filemarks(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tuint32_t count = get_unaligned_be24(&cdb[2]);\n\n\tMHVTL_DBG(1, \"WRITE %d FILEMARKS (%ld) **\",\n\t\t\t  count, (long)cmd->dbuf_p->serialNo);\n\n\tif (!lu_priv->pm->check_restrictions(cmd)) {\n\t\t/* If restrictions & WORM media at block 0.. OK\n\t\t * Otherwise return CHECK_CONDITION.\n\t\t *\tcheck_restrictions()\n\t\t *\twas nice enough to set correct sense status for us.\n\t\t */\n\t\tif ((mam.MediumType == MEDIA_TYPE_WORM) &&\n\t\t\t(c_pos->blk_number == 0)) {\n\t\t\tMHVTL_DBG(1, \"Erasing WORM media\");\n\t\t} else\n\t\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\twrite_filemarks(count, sam_stat);\n\tif (count) {\n\t\tif (current_tape_offset() >=\n\t\t\tget_unaligned_be64(&mam.max_capacity)) {\n\t\t\tmam.remaining_capacity = 0L;\n\t\t\tMHVTL_DBG(2, \"Setting EOM flag\");\n\t\t\tsam_no_sense(SD_EOM, NO_ADDITIONAL_SENSE, sam_stat);\n\t\t}\n\t}\n\n\treturn *sam_stat;\n}\n\nuint8_t ssc_pr_in(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tMHVTL_DBG(1, \"PERSISTENT RESERVE IN (%ld) **\",\n\t\t\t  (long)dbuf_p->serialNo);\n\n\tif (lu_priv->I_am_SPC_2_Reserved)\n\t\treturn SAM_STAT_RESERVATION_CONFLICT;\n\telse\n\t\treturn resp_spc_pri(cdb, dbuf_p);\n}\n\nuint8_t ssc_log_sense(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tuint8_t\t\t\t\tpage = cdb[2] & 0x3f;\n\tstruct log_pg_list *l;\n\tstruct s_sd\t\t\tsd;\n\n\tMHVTL_DBG(1, \"LOG SENSE (%ld) ** %s\",\n\t\t\t  (long)dbuf_p->serialNo, log_page_desc[page]);\n\n\tif (page == SUPPORTED_LOG_PAGES) { /* Send supported pages */\n\t\tint i = 4;\n\t\tmemset(buf, 0, 4); /* Clear first few (4) bytes */\n\t\tbuf[i++] = 0;\t   /* b[0] is log page '0' (this one) */\n\t\tlist_for_each_entry(l, &lu->log_pg, siblings) {\n\t\t\tMHVTL_DBG(3, \"found page 0x%02x : %s\", l->log_page_num, log_page_desc[l->log_page_num]);\n\t\t\tbuf[i] = l->log_page_num;\n\t\t\ti++;\n\t\t}\n\t\tput_unaligned_be16(i - 4, &buf[2]); /* number of entries stored in b*/\n\t\tdbuf_p->sz = i;\n\t} else {\n\t\tl = lookup_log_pg(&lu->log_pg, page, NO_SUBPAGE);\n\t\tif (!l)\n\t\t\tgoto log_page_not_found;\n\t\tdbuf_p->sz = l->size;\n\t\tbuf\t\t   = memcpy(buf, l->p, l->size);\n\t}\n\n\tswitch (page) {\n\tcase SUPPORTED_LOG_PAGES:\n\tcase WRITE_ERROR_COUNTER:\n\tcase READ_ERROR_COUNTER:\n\t\tbreak;\n\n\tcase SEQUENTIAL_ACCESS_DEVICE:\n\t\tupdate_SequentialAccessDevice((struct SequentialAccessDevice_pg *)buf);\n\t\tbreak;\n\n\tcase TEMPERATURE_PAGE:\n\tcase SELFTEST_RESULTS:\n\tcase DEVICE_STATUS:\n\t\tbreak;\n\n\tcase VOLUME_STATISTICS:\n\t\tupdate_VolumeStatistics((struct VolumeStatistics_pg *)buf, lu_priv);\n\t\tbreak;\n\n\tcase TAPE_ALERT:\n\t\tif (get_unaligned_be16(&cdb[7]) > 4) /* Checking Allocation Length */\n\t\t\tset_TapeAlert(TA_NONE);\n\t\telse\n\t\t\tMHVTL_DBG(1, \"TapeAlert : Alloc len short -\"\n\t\t\t\t\t\t \" Not clearing TapeAlert flags.\");\n\t\tbreak;\n\n\tcase TAPE_USAGE:\n\t\tupdate_TapeUsage((struct TapeUsage_pg *)buf);\n\t\tbreak;\n\n\tcase TAPE_CAPACITY:\n\tcase DATA_COMPRESSION:\n\t\tbreak;\n\n\tcase PERFORMANCE_CHARACTERISTICS:\n\t\tbreak;\n\n\tdefault:\n\t\tMHVTL_DBG(1, \"Unknown/Unimplemented log page : 0x%02x\", page);\n\t\tgoto log_page_not_found;\n\t\tbreak;\n\t}\n\n\treturn SAM_STAT_GOOD;\n\nlog_page_not_found:\n\tdbuf_p->sz\t\t = 0;\n\tsd.byte0\t\t = SKSV | CD;\n\tsd.field_pointer = 2;\n\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\treturn SAM_STAT_CHECK_CONDITION;\n}\n\nuint8_t ssc_recv_diagnostics(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\tstruct s_sd sd;\n\n\tMHVTL_DBG(1, \"SSC RECEIVE DIAGNOSTICS (%ld) **\", (long)dbuf_p->serialNo);\n\n\tdbuf_p->sz\t\t = 0;\n\tsd.byte0\t\t = SKSV | CD;\n\tsd.field_pointer = 2;\n\tsam_illegal_request(E_INVALID_FIELD_IN_CDB, &sd, sam_stat);\n\treturn SAM_STAT_CHECK_CONDITION;\n}\n\nuint32_t GenerateRSCRC(uint32_t seed, int sz, const uint8_t *buf);\nuint32_t crc32c(uint32_t seed, const uint8_t *buf, size_t sz);\n\nuint8_t ssc_send_diagnostics(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\tuint32_t\t  computedCRC1;\n\tuint32_t\t  computedCRC2;\n\tuint32_t\t  computedCRC3;\n\tint\t\t\t  crc_check_failed = 0;\n\tconst uint8_t block1[]\t\t   = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,\n\t\t\t\t\t\t\t\t\t  47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127,\n\t\t\t\t\t\t\t\t\t  131, 137, 139, 149, 151, 157};\n\n\tconst uint8_t block2[] = {163, 167, 173, 179, 181, 191, 193, 197, 199, 211,\n\t\t\t\t\t\t\t  223, 227, 229, 233, 239, 241, 251};\n\n\tMHVTL_DBG(1, \"SSC SEND DIAGNOSTICS (%ld) **\", (long)cmd->dbuf_p->serialNo);\n\n\t/* Now check the CRC32C routines pass basic sanity check */\n\tcomputedCRC1 = crc32c(0, block1, sizeof(block1));\n\tcomputedCRC2 = crc32c(~computedCRC1, block2, sizeof(block2));\n\tcomputedCRC3 = crc32c(~crc32c(0, block1, sizeof(block1)), block2, sizeof(block2));\n\n\tif (computedCRC1 != 0xE8174F48) {\n\t\tMHVTL_ERR(\"CRC32C #1 error\");\n\t\tcrc_check_failed = 1;\n\t}\n\tif (computedCRC2 != 0x56DAB0A6) {\n\t\tMHVTL_ERR(\"CRC32C #2 error\");\n\t\tcrc_check_failed = 1;\n\t}\n\tif (computedCRC3 != 0x56DAB0A6) {\n\t\tMHVTL_ERR(\"CRC32C #3 error\");\n\t\tcrc_check_failed = 1;\n\t}\n\n\t/* Now check the Reed/Solomon CRC routines pass basic sanity check */\n\tcomputedCRC1 = GenerateRSCRC(0, sizeof(block1), block1);\n\tcomputedCRC2 = GenerateRSCRC(computedCRC1, sizeof(block2), block2);\n\tcomputedCRC3 = GenerateRSCRC(GenerateRSCRC(0, sizeof(block1), block1), sizeof(block2), block2);\n\n\tif (computedCRC1 != 0x733D4DCA) {\n\t\tMHVTL_ERR(\"RS-CRC #1 error\");\n\t\tcrc_check_failed = 1;\n\t}\n\tif (computedCRC2 != 0x754ED37E) {\n\t\tMHVTL_ERR(\"RS-CRC #2 error\");\n\t\tcrc_check_failed = 1;\n\t}\n\tif (computedCRC3 != 0x754ED37E) {\n\t\tMHVTL_ERR(\"RS-CRC #3 error\");\n\t\tcrc_check_failed = 1;\n\t}\n\n\tif (crc_check_failed) {\n\t\tsam_hardware_error(E_INTERNAL_TARGET_FAILURE, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\treturn SAM_STAT_GOOD;\n}\n\nuint8_t ssc_set_capacity(struct scsi_cmd *cmd) {\n\tdeclare_ssc_vars;\n\n\t/* TODO : implement medium_for_use_proportion_value */\n\t/* uint16_t medium_for_use_proportion_value = get_unaligned_be16(&cmd->scb[3]); */\n\n\tif (c_pos->blk_number != 0) { /* not at Beginnning Of Partition (BOP) */\n\t\tsam_illegal_request(E_POSITION_PAST_BOM, NULL, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\t/* Check that there is a piece of media loaded.. */\n\tswitch (get_tape_load_status(lu_priv)) {\n\tcase TAPE_LOADED:\n\t\tbreak;\n\tcase TAPE_LOADING:\n\t\tsam_not_ready(E_BECOMING_READY, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\tcase TAPE_UNLOADED:\n\t\tsam_not_ready(E_MEDIUM_NOT_PRESENT, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\tdefault:\n\t\tsam_not_ready(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\treturn SAM_STAT_CHECK_CONDITION;\n\t}\n\n\tmam.num_partitions = 1;\n\tformat_tape(sam_stat);\n\n\treturn SAM_STAT_GOOD;\n}"
  },
  {
    "path": "usr/utils/README.LZO",
    "content": "\n ============================================================================\n miniLZO -- mini subset of the LZO real-time data compression library\n ============================================================================\n\n Author  : Markus Franz Xaver Johannes Oberhumer\n           <markus@oberhumer.com>\n           http://www.oberhumer.com/opensource/lzo/\n Version : 2.09\n Date    : 04 Feb 2015\n\n I've created miniLZO for projects where it is inconvenient to\n include (or require) the full LZO source code just because you\n want to add a little bit of data compression to your application.\n\n miniLZO implements the LZO1X-1 compressor and both the standard and\n safe LZO1X decompressor. Apart from fast compression it also useful\n for situations where you want to use pre-compressed data files (which\n must have been compressed with LZO1X-999).\n\n miniLZO consists of one C source file and three header files:\n    minilzo.c\n    minilzo.h, lzoconf.h, lzodefs.h\n\n To use miniLZO just copy these files into your source directory, add\n minilzo.c to your Makefile and #include minilzo.h from your program.\n Note: you also must distribute this file ('README.LZO') with your project.\n\n minilzo.o compiles to about 6 KiB (using gcc or Visual C on an i386), and\n the sources are about 30 KiB when packed with zip - so there's no more\n excuse that your application doesn't support data compression :-)\n\n For more information, documentation, example programs and other support\n files (like Makefiles and build scripts) please download the full LZO\n package from\n    http://www.oberhumer.com/opensource/lzo/\n\n Have fun,\n  Markus\n\n\n P.S. minilzo.c is generated automatically from the LZO sources and\n      therefore functionality is completely identical\n\n\n Appendix A: building miniLZO\n ----------------------------\n miniLZO is written such a way that it should compile and run\n out-of-the-box on most machines.\n\n If you are running on a very unusual architecture and lzo_init() fails then\n you should first recompile with '-DLZO_DEBUG' to see what causes the failure.\n The most probable case is something like 'sizeof(void *) != sizeof(size_t)'.\n After identifying the problem you can compile by adding some defines\n like '-DSIZEOF_VOID_P=8' to your Makefile.\n\n The best solution is (of course) using Autoconf - if your project uses\n Autoconf anyway just add '-DMINILZO_HAVE_CONFIG_H' to your compiler\n flags when compiling minilzo.c. See the LZO distribution for an example\n how to set up configure.ac.\n\n\n Appendix B: list of public functions available in miniLZO\n ---------------------------------------------------------\n Library initialization\n    lzo_init()\n\n Compression\n    lzo1x_1_compress()\n\n Decompression\n    lzo1x_decompress()\n    lzo1x_decompress_safe()\n\n Checksum functions\n    lzo_adler32()\n\n Version functions\n    lzo_version()\n    lzo_version_string()\n    lzo_version_date()\n\n Portable (but slow) string functions\n    lzo_memcmp()\n    lzo_memcpy()\n    lzo_memmove()\n    lzo_memset()\n\n\n Appendix C: suggested macros for 'configure.ac' when using Autoconf\n -------------------------------------------------------------------\n Checks for typedefs and structures\n    AC_CHECK_TYPE(ptrdiff_t,long)\n    AC_TYPE_SIZE_T\n    AC_CHECK_SIZEOF(short)\n    AC_CHECK_SIZEOF(int)\n    AC_CHECK_SIZEOF(long)\n    AC_CHECK_SIZEOF(long long)\n    AC_CHECK_SIZEOF(__int64)\n    AC_CHECK_SIZEOF(void *)\n    AC_CHECK_SIZEOF(size_t)\n    AC_CHECK_SIZEOF(ptrdiff_t)\n\n Checks for compiler characteristics\n    AC_C_CONST\n\n Checks for library functions\n    AC_CHECK_FUNCS(memcmp memcpy memmove memset)\n\n\n Appendix D: Copyright\n ---------------------\n LZO and miniLZO are Copyright (C) 1996-2015 Markus Franz Xaver Oberhumer\n All Rights Reserved.\n\n LZO and miniLZO are distributed under the terms of the GNU General\n Public License (GPL).  See the file COPYING.\n\n Special licenses for commercial and other applications which\n are not willing to accept the GNU General Public License\n are available by contacting the author.\n\n\n"
  },
  {
    "path": "usr/utils/crc32c.c",
    "content": "/* MIT (BSD) license - see LICENSE file for details */\n/* crc32c.c -- compute CRC-32C using the Intel crc32 instruction\n * Copyright (C) 2013, 2015 Mark Adler\n * Version 1.3  31 Dec 2015  Mark Adler\n */\n\n/*\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the author be held liable for any damages\n  arising from the use of this software.\n\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n\n  1. The origin of this software must not be misrepresented; you must not\n\t claim that you wrote the original software. If you use this software\n\t in a product, an acknowledgment in the product documentation would be\n\t appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n\t misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n\n  Mark Adler\n  madler@alumni.caltech.edu\n */\n\n/* Use hardware CRC instruction on Intel SSE 4.2 processors.  This computes a\n   CRC-32C, *not* the CRC-32 used by Ethernet and zip, gzip, etc.  A software\n   version is provided as a fall-back, as well as for speed comparisons. */\n\n/* Version history:\n   1.0  10 Feb 2013  First version\n   1.1   1 Aug 2013  Correct comments on why three crc instructions in parallel\n   1.2   1 Nov 2015  Add const qualifier to avoid compiler warning\n\t\t\t\t\t Load entire input into memory (test code)\n\t\t\t\t\t Argument gives number of times to repeat (test code)\n\t\t\t\t\t Argument < 0 forces software implementation (test code)\n   1.3  31 Dec 2015  Check for Intel architecture using compiler macro\n\t\t\t\t\t Support big-endian processors in software calculation\n\t\t\t\t\t Add header for external use\n */\n\n#include \"ccan/crc32c/crc32c.h\"\n#include <stdbool.h>\n\nstatic uint32_t crc32c_sw(uint32_t crc, void const *buf, size_t len);\n\n/* CRC-32C (iSCSI) polynomial in reversed bit order. */\n#define POLY 0x82f63b78\n\n#ifdef __x86_64__\n\n/* Hardware CRC-32C for Intel and compatible processors. */\n\n/* Multiply a matrix times a vector over the Galois field of two elements,\n   GF(2).  Each element is a bit in an unsigned integer.  mat must have at\n   least as many entries as the power of two for most significant one bit in\n   vec. */\nstatic inline uint32_t gf2_matrix_times(uint32_t *mat, uint32_t vec) {\n\tuint32_t sum = 0;\n\twhile (vec) {\n\t\tif (vec & 1)\n\t\t\tsum ^= *mat;\n\t\tvec >>= 1;\n\t\tmat++;\n\t}\n\treturn sum;\n}\n\n/* Multiply a matrix by itself over GF(2).  Both mat and square must have 32\n   rows. */\nstatic inline void gf2_matrix_square(uint32_t *square, uint32_t *mat) {\n\tfor (unsigned n = 0; n < 32; n++)\n\t\tsquare[n] = gf2_matrix_times(mat, mat[n]);\n}\n\n/* Construct an operator to apply len zeros to a crc.  len must be a power of\n   two.  If len is not a power of two, then the result is the same as for the\n   largest power of two less than len.  The result for len == 0 is the same as\n   for len == 1.  A version of this routine could be easily written for any\n   len, but that is not needed for this application. */\nstatic void crc32c_zeros_op(uint32_t *even, size_t len) {\n\tuint32_t odd[32]; /* odd-power-of-two zeros operator */\n\n\t/* put operator for one zero bit in odd */\n\todd[0]\t\t = POLY; /* CRC-32C polynomial */\n\tuint32_t row = 1;\n\tfor (unsigned n = 1; n < 32; n++) {\n\t\todd[n] = row;\n\t\trow <<= 1;\n\t}\n\n\t/* put operator for two zero bits in even */\n\tgf2_matrix_square(even, odd);\n\n\t/* put operator for four zero bits in odd */\n\tgf2_matrix_square(odd, even);\n\n\t/* first square will put the operator for one zero byte (eight zero bits),\n\t   in even -- next square puts operator for two zero bytes in odd, and so\n\t   on, until len has been rotated down to zero */\n\tdo {\n\t\tgf2_matrix_square(even, odd);\n\t\tlen >>= 1;\n\t\tif (len == 0)\n\t\t\treturn;\n\t\tgf2_matrix_square(odd, even);\n\t\tlen >>= 1;\n\t} while (len);\n\n\t/* answer ended up in odd -- copy to even */\n\tfor (unsigned n = 0; n < 32; n++)\n\t\teven[n] = odd[n];\n}\n\n/* Take a length and build four lookup tables for applying the zeros operator\n   for that length, byte-by-byte on the operand. */\nstatic void crc32c_zeros(uint32_t zeros[][256], size_t len) {\n\tuint32_t op[32];\n\n\tcrc32c_zeros_op(op, len);\n\tfor (unsigned n = 0; n < 256; n++) {\n\t\tzeros[0][n] = gf2_matrix_times(op, n);\n\t\tzeros[1][n] = gf2_matrix_times(op, n << 8);\n\t\tzeros[2][n] = gf2_matrix_times(op, n << 16);\n\t\tzeros[3][n] = gf2_matrix_times(op, n << 24);\n\t}\n}\n\n/* Apply the zeros operator table to crc. */\nstatic inline uint32_t crc32c_shift(uint32_t zeros[][256], uint32_t crc) {\n\treturn zeros[0][crc & 0xff] ^ zeros[1][(crc >> 8) & 0xff] ^\n\t\t   zeros[2][(crc >> 16) & 0xff] ^ zeros[3][crc >> 24];\n}\n\n/* Block sizes for three-way parallel crc computation.  LONG and SHORT must\n   both be powers of two.  The associated string constants must be set\n   accordingly, for use in constructing the assembler instructions. */\n#define LONG\t8192\n#define LONGx1\t\"8192\"\n#define LONGx2\t\"16384\"\n#define SHORT\t256\n#define SHORTx1 \"256\"\n#define SHORTx2 \"512\"\n\n/* Tables for hardware crc that shift a crc by LONG and SHORT zeros. */\nstatic bool\t\tcrc32c_once_hw;\nstatic uint32_t crc32c_long[4][256];\nstatic uint32_t crc32c_short[4][256];\n\n/* Initialize tables for shifting crcs. */\nstatic void crc32c_init_hw(void) {\n\tcrc32c_once_hw = true;\n\tcrc32c_zeros(crc32c_long, LONG);\n\tcrc32c_zeros(crc32c_short, SHORT);\n}\n\n/* Compute CRC-32C using the Intel hardware instruction. */\nstatic uint32_t crc32c_hw(uint32_t crc, void const *buf, size_t len) {\n\t/* populate shift tables the first time through */\n\tif (!crc32c_once_hw)\n\t\tcrc32c_init_hw();\n\n\t/* pre-process the crc */\n\tcrc\t\t\t  = ~crc;\n\tuint64_t crc0 = crc; /* 64-bits for crc32q instruction */\n\n\t/* compute the crc for up to seven leading bytes to bring the data pointer\n\t   to an eight-byte boundary */\n\tunsigned char const *next = buf;\n\twhile (len && ((uintptr_t)next & 7) != 0) {\n\t\t__asm__(\"crc32b\\t\"\n\t\t\t\t\"(%1), %0\"\n\t\t\t\t: \"=r\"(crc0)\n\t\t\t\t: \"r\"(next), \"0\"(crc0));\n\t\tnext++;\n\t\tlen--;\n\t}\n\n\t/* compute the crc on sets of LONG*3 bytes, executing three independent crc\n\t   instructions, each on LONG bytes -- this is optimized for the Nehalem,\n\t   Westmere, Sandy Bridge, and Ivy Bridge architectures, which have a\n\t   throughput of one crc per cycle, but a latency of three cycles */\n\twhile (len >= LONG * 3) {\n\t\tuint64_t\t\t\t\t   crc1 = 0;\n\t\tuint64_t\t\t\t\t   crc2 = 0;\n\t\tunsigned char const *const end\t= next + LONG;\n\t\tdo {\n\t\t\t__asm__(\"crc32q\\t\"\n\t\t\t\t\t\"(%3), %0\\n\\t\"\n\t\t\t\t\t\"crc32q\\t\" LONGx1 \"(%3), %1\\n\\t\"\n\t\t\t\t\t\"crc32q\\t\" LONGx2 \"(%3), %2\"\n\t\t\t\t\t: \"=r\"(crc0), \"=r\"(crc1), \"=r\"(crc2)\n\t\t\t\t\t: \"r\"(next), \"0\"(crc0), \"1\"(crc1), \"2\"(crc2));\n\t\t\tnext += 8;\n\t\t} while (next < end);\n\t\tcrc0 = crc32c_shift(crc32c_long, crc0) ^ crc1;\n\t\tcrc0 = crc32c_shift(crc32c_long, crc0) ^ crc2;\n\t\tnext += LONG * 2;\n\t\tlen -= LONG * 3;\n\t}\n\n\t/* do the same thing, but now on SHORT*3 blocks for the remaining data less\n\t   than a LONG*3 block */\n\twhile (len >= SHORT * 3) {\n\t\tuint64_t\t\t\t\t   crc1 = 0;\n\t\tuint64_t\t\t\t\t   crc2 = 0;\n\t\tunsigned char const *const end\t= next + SHORT;\n\t\tdo {\n\t\t\t__asm__(\"crc32q\\t\"\n\t\t\t\t\t\"(%3), %0\\n\\t\"\n\t\t\t\t\t\"crc32q\\t\" SHORTx1 \"(%3), %1\\n\\t\"\n\t\t\t\t\t\"crc32q\\t\" SHORTx2 \"(%3), %2\"\n\t\t\t\t\t: \"=r\"(crc0), \"=r\"(crc1), \"=r\"(crc2)\n\t\t\t\t\t: \"r\"(next), \"0\"(crc0), \"1\"(crc1), \"2\"(crc2));\n\t\t\tnext += 8;\n\t\t} while (next < end);\n\t\tcrc0 = crc32c_shift(crc32c_short, crc0) ^ crc1;\n\t\tcrc0 = crc32c_shift(crc32c_short, crc0) ^ crc2;\n\t\tnext += SHORT * 2;\n\t\tlen -= SHORT * 3;\n\t}\n\n\t/* compute the crc on the remaining eight-byte units less than a SHORT*3\n\t   block */\n\t{\n\t\tunsigned char const *const end = next + (len - (len & 7));\n\t\twhile (next < end) {\n\t\t\t__asm__(\"crc32q\\t\"\n\t\t\t\t\t\"(%1), %0\"\n\t\t\t\t\t: \"=r\"(crc0)\n\t\t\t\t\t: \"r\"(next), \"0\"(crc0));\n\t\t\tnext += 8;\n\t\t}\n\t\tlen &= 7;\n\t}\n\n\t/* compute the crc for up to seven trailing bytes */\n\twhile (len) {\n\t\t__asm__(\"crc32b\\t\"\n\t\t\t\t\"(%1), %0\"\n\t\t\t\t: \"=r\"(crc0)\n\t\t\t\t: \"r\"(next), \"0\"(crc0));\n\t\tnext++;\n\t\tlen--;\n\t}\n\n\t/* return a post-processed crc */\n\treturn ~crc0;\n}\n\n/* Compute a CRC-32C.  If the crc32 instruction is available, use the hardware\n   version.  Otherwise, use the software version. */\nuint32_t crc32c(uint32_t crc, void const *buf, size_t len) {\n\n\treturn __builtin_cpu_supports(\"sse4.2\") ? crc32c_hw(crc, buf, len) : crc32c_sw(crc, buf, len);\n}\n\n#else /* !__x86_64__ */\n\nuint32_t crc32c(uint32_t crc, void const *buf, size_t len) {\n\treturn crc32c_sw(crc, buf, len);\n}\n\n#endif\n\n/* Construct table for software CRC-32C little-endian calculation. */\nstatic bool\t\tcrc32c_once_little;\nstatic uint32_t crc32c_table_little[8][256];\nstatic void\t\tcrc32c_init_sw_little(void) {\n\tfor (unsigned n = 0; n < 256; n++) {\n\t\tuint32_t crc\t\t\t  = n;\n\t\tcrc\t\t\t\t\t\t  = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n\t\tcrc\t\t\t\t\t\t  = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n\t\tcrc\t\t\t\t\t\t  = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n\t\tcrc\t\t\t\t\t\t  = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n\t\tcrc\t\t\t\t\t\t  = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n\t\tcrc\t\t\t\t\t\t  = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n\t\tcrc\t\t\t\t\t\t  = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n\t\tcrc\t\t\t\t\t\t  = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n\t\tcrc32c_table_little[0][n] = crc;\n\t}\n\tfor (unsigned n = 0; n < 256; n++) {\n\t\tuint32_t crc = crc32c_table_little[0][n];\n\t\tfor (unsigned k = 1; k < 8; k++) {\n\t\t\tcrc\t\t\t\t\t\t  = crc32c_table_little[0][crc & 0xff] ^ (crc >> 8);\n\t\t\tcrc32c_table_little[k][n] = crc;\n\t\t}\n\t}\n\tcrc32c_once_little = true;\n}\n\n/* Compute a CRC-32C in software assuming a little-endian architecture,\n   constructing the required table if that hasn't already been done. */\nstatic uint32_t crc32c_sw_little(uint32_t crc, void const *buf, size_t len) {\n\tunsigned char const *next = buf;\n\n\tif (!crc32c_once_little)\n\t\tcrc32c_init_sw_little();\n\tcrc = ~crc;\n\twhile (len && ((uintptr_t)next & 7) != 0) {\n\t\tcrc = crc32c_table_little[0][(crc ^ *next++) & 0xff] ^ (crc >> 8);\n\t\tlen--;\n\t}\n\tif (len >= 8) {\n\t\tuint64_t crcw = crc;\n\t\tdo {\n\t\t\tcrcw ^= *(uint64_t const *)next;\n\t\t\tcrcw = crc32c_table_little[7][crcw & 0xff] ^\n\t\t\t\t   crc32c_table_little[6][(crcw >> 8) & 0xff] ^\n\t\t\t\t   crc32c_table_little[5][(crcw >> 16) & 0xff] ^\n\t\t\t\t   crc32c_table_little[4][(crcw >> 24) & 0xff] ^\n\t\t\t\t   crc32c_table_little[3][(crcw >> 32) & 0xff] ^\n\t\t\t\t   crc32c_table_little[2][(crcw >> 40) & 0xff] ^\n\t\t\t\t   crc32c_table_little[1][(crcw >> 48) & 0xff] ^\n\t\t\t\t   crc32c_table_little[0][crcw >> 56];\n\t\t\tnext += 8;\n\t\t\tlen -= 8;\n\t\t} while (len >= 8);\n\t\tcrc = crcw;\n\t}\n\twhile (len) {\n\t\tcrc = crc32c_table_little[0][(crc ^ *next++) & 0xff] ^ (crc >> 8);\n\t\tlen--;\n\t}\n\treturn ~crc;\n}\n\n/* Swap the bytes in a uint64_t.  (Only for big-endian.) */\n#if defined(__has_builtin) || (defined(__GNUC__) && \\\n\t\t\t\t\t\t\t   (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))\n#define swap __builtin_bswap64\n#else\nstatic inline uint64_t swap(uint64_t x) {\n\tx = ((x << 8) & 0xff00ff00ff00ff00) | ((x >> 8) & 0xff00ff00ff00ff);\n\tx = ((x << 16) & 0xffff0000ffff0000) | ((x >> 16) & 0xffff0000ffff);\n\treturn (x << 32) | (x >> 32);\n}\n#endif\n\n/* Construct tables for software CRC-32C big-endian calculation. */\nstatic bool\t\tcrc32c_once_big;\nstatic uint32_t crc32c_table_big_byte[256];\nstatic uint64_t crc32c_table_big[8][256];\nstatic void\t\tcrc32c_init_sw_big(void) {\n\tfor (unsigned n = 0; n < 256; n++) {\n\t\tuint32_t crc\t\t\t = n;\n\t\tcrc\t\t\t\t\t\t = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n\t\tcrc\t\t\t\t\t\t = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n\t\tcrc\t\t\t\t\t\t = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n\t\tcrc\t\t\t\t\t\t = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n\t\tcrc\t\t\t\t\t\t = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n\t\tcrc\t\t\t\t\t\t = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n\t\tcrc\t\t\t\t\t\t = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n\t\tcrc\t\t\t\t\t\t = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;\n\t\tcrc32c_table_big_byte[n] = crc;\n\t}\n\tfor (unsigned n = 0; n < 256; n++) {\n\t\tuint32_t crc\t\t   = crc32c_table_big_byte[n];\n\t\tcrc32c_table_big[0][n] = swap(crc);\n\t\tfor (unsigned k = 1; k < 8; k++) {\n\t\t\tcrc\t\t\t\t\t   = crc32c_table_big_byte[crc & 0xff] ^ (crc >> 8);\n\t\t\tcrc32c_table_big[k][n] = swap(crc);\n\t\t}\n\t}\n\tcrc32c_once_big = true;\n}\n\n/* Compute a CRC-32C in software assuming a big-endian architecture,\n   constructing the required tables if that hasn't already been done. */\nstatic uint32_t crc32c_sw_big(uint32_t crc, void const *buf, size_t len) {\n\tunsigned char const *next = buf;\n\n\tif (!crc32c_once_big)\n\t\tcrc32c_init_sw_big();\n\tcrc = ~crc;\n\twhile (len && ((uintptr_t)next & 7) != 0) {\n\t\tcrc = crc32c_table_big_byte[(crc ^ *next++) & 0xff] ^ (crc >> 8);\n\t\tlen--;\n\t}\n\tif (len >= 8) {\n\t\tuint64_t crcw = swap(crc);\n\t\tdo {\n\t\t\tcrcw ^= *(uint64_t const *)next;\n\t\t\tcrcw = crc32c_table_big[0][crcw & 0xff] ^\n\t\t\t\t   crc32c_table_big[1][(crcw >> 8) & 0xff] ^\n\t\t\t\t   crc32c_table_big[2][(crcw >> 16) & 0xff] ^\n\t\t\t\t   crc32c_table_big[3][(crcw >> 24) & 0xff] ^\n\t\t\t\t   crc32c_table_big[4][(crcw >> 32) & 0xff] ^\n\t\t\t\t   crc32c_table_big[5][(crcw >> 40) & 0xff] ^\n\t\t\t\t   crc32c_table_big[6][(crcw >> 48) & 0xff] ^\n\t\t\t\t   crc32c_table_big[7][(crcw >> 56)];\n\t\t\tnext += 8;\n\t\t\tlen -= 8;\n\t\t} while (len >= 8);\n\t\tcrc = swap(crcw);\n\t}\n\twhile (len) {\n\t\tcrc = crc32c_table_big_byte[(crc ^ *next++) & 0xff] ^ (crc >> 8);\n\t\tlen--;\n\t}\n\treturn ~crc;\n}\n\n/* Table-driven software CRC-32C.  This is about 15 times slower than using the\n   hardware instructions.  Determine the endianess of the processor and proceed\n   accordingly.  Ideally the endianess will be determined at compile time, in\n   which case the unused functions and tables for the other endianess will be\n   removed by the optimizer.  If not, then the proper routines and tables will\n   be used, even if the endianess is changed mid-stream.  (Yes, there are\n   processors that permit that -- go figure.) */\nstatic uint32_t crc32c_sw(uint32_t crc, void const *buf, size_t len) {\n\tstatic int const little = 1;\n\tif (*(char const *)&little)\n\t\treturn crc32c_sw_little(crc, buf, len);\n\telse\n\t\treturn crc32c_sw_big(crc, buf, len);\n}\n"
  },
  {
    "path": "usr/utils/mhvtl_update.c",
    "content": "/*\n * Functions to update the tape format and mam format to new versions\n *\n * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n */\n\n#define _FILE_OFFSET_BITS 64\n\n#include <fcntl.h>\n#include <string.h>\n#include <errno.h>\n#include \"logging.h\"\n#include \"vtlcart.h\"\n#include \"mhvtl_update.h\"\n#include \"vtllib.h\"\n\nstruct MAM_tapeFmtV3 {\n\tuint32_t tape_fmt_version;\n\tuint32_t mam_fmt_version;\n\n\tuint64_t remaining_capacity;\n\tuint64_t max_capacity;\n\tuint64_t TapeAlert;\n\tuint64_t LoadCount;\n\tuint64_t MAMSpaceRemaining;\n\tuint8_t\t AssigningOrganization_1[8];\n\tuint8_t\t InitializationCount[2];\n\tuint8_t\t DevMakeSerialLastLoad[40];\n\tuint8_t\t DevMakeSerialLastLoad1[40];\n\tuint8_t\t DevMakeSerialLastLoad2[40];\n\tuint8_t\t DevMakeSerialLastLoad3[40];\n\tuint64_t WrittenInMediumLife;\n\tuint64_t ReadInMediumLife;\n\tuint64_t WrittenInLastLoad;\n\tuint64_t ReadInLastLoad;\n\n\tuint8_t\t MediumManufacturer[8];\n\tuint8_t\t MediumSerialNumber[32];\n\tuint32_t MediumLength;\n\tuint32_t MediumWidth;\n\tuint8_t\t AssigningOrganization_2[8];\n\tuint8_t\t MediumManufactureDate[12];\n\tuint8_t\t FormattedDensityCode;\n\tuint8_t\t MediumDensityCode;\n\tuint8_t\t MediumType; /* 0 -> Data, 1 -> WORM, 6 -> Clean */\n\tuint8_t\t MediaType;\t /* LTO1, LTO2, AIT etc (Media_Type_list) */\n\tuint64_t MAMCapacity;\n\tuint16_t MediumTypeInformation; /* If Clean, max mount */\n\n\tuint8_t ApplicationVendor[8];\n\tuint8_t ApplicationName[32];\n\tuint8_t ApplicationVersion[8];\n\tuint8_t UserMediumTextLabel[160];\n\tuint8_t DateTimeLastWritten[12];\n\tuint8_t LocalizationIdentifier;\n\tuint8_t Barcode[32];\n\tuint8_t OwningHostTextualName[80];\n\tuint8_t MediaPool[160];\n\n\tuint8_t\t record_dirty; /* 0 = Record clean, non-zero umount failed. */\n\tuint16_t Flags;\n\n\tstruct uniq_media_info_tapeFmtV3 {\n\t\tuint32_t bits_per_mm;\n\t\tuint16_t tracks;\n\t\tchar\t density_name[8];\n\t\tchar\t description[32];\n\t} media_info;\n\tuint8_t max_partitions;\n\tuint8_t num_partitions;\n\n\t/* Pad to keep MAM to 1024 bytes */\n\tuint8_t pad[1024 - 878];\n} __attribute__((packed));\n\n/*\n * Assuming mam.tape_fmt_version == 3,\n * extract mam from \"meta\" and create separate \"mam\" file\n * Sets mam.tape_fmt_version to 4\n *\n * Returns:\n * == 0 -> Successfully extracted mam\n * == 1 -> Failed to extract mam from meta file\n * == 2 -> could not find meta file : format corrupt\n */\nint try_extract_mam(char *currentPCL) {\n\tstruct MAM_tapeFmtV3 mam_v3;\n\tchar\t\t\t\t meta_path[1024];\n\tchar\t\t\t\t mam_path[1024];\n\tchar\t\t\t\t tmp_path[1024];\n\tint\t\t\t\t\t metafile = -1;\n\tint\t\t\t\t\t mamfile  = -1;\n\tint\t\t\t\t\t tmpfile  = -1;\n\tint\t\t\t\t\t rc\t\t  = 1; /* default: failed to extract */\n\n\tsnprintf(meta_path, sizeof(meta_path), \"%s/meta\", currentPCL);\n\tsnprintf(mam_path, sizeof(mam_path), \"%s/mam\", currentPCL);\n\tsnprintf(tmp_path, sizeof(tmp_path), \"%s/meta.new\", currentPCL);\n\n\tmetafile = open(meta_path, O_RDWR | O_LARGEFILE);\n\tif (metafile < 0) {\n\t\tMHVTL_ERR(\"open of file %s failed: %s\", meta_path, strerror(errno));\n\t\treturn 2;\n\t}\n\n\tif (read(metafile, &mam_v3, sizeof(struct MAM_tapeFmtV3)) != sizeof(struct MAM_tapeFmtV3)) {\n\t\tMHVTL_ERR(\"Error reading pcl %s MAM from meta file: %s\",\n\t\t\t\t  currentPCL, strerror(errno));\n\t\tgoto cleanup;\n\t}\n\n\t/* Checking Tape Format Version */\n\tif (mam_v3.tape_fmt_version != 3) {\n\t\tMHVTL_ERR(\"Error : Tape Format Version : %d , expected 3.\\\n\t\t\t\t\t\\nCannot handle conversion of %s tape format to version 4\",\n\t\t\t\t  mam_v3.tape_fmt_version, currentPCL);\n\t\tgoto cleanup;\n\t}\n\n\t/* create mam file */\n\tmamfile = open(mam_path, O_CREAT | O_EXCL | O_WRONLY,\n\t\t\t\t   S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);\n\tif (mamfile < 0) {\n\t\tMHVTL_ERR(\"Failed to create file %s: %s\", mam_path, strerror(errno));\n\t\tgoto cleanup;\n\t}\n\n\t/* Update Tape Format Version and write mam in \"mam\" file */\n\tmam_v3.tape_fmt_version = 4;\n\tif (write(mamfile, &mam_v3, sizeof(struct MAM_tapeFmtV3)) != sizeof(struct MAM_tapeFmtV3)) {\n\t\tMHVTL_ERR(\"Failed to initialize file %s: %s\", mam_path,\n\t\t\t\t  strerror(errno));\n\t\tgoto cleanup;\n\t}\n\n\t/* Rewrite meta without mam : writing content to meta.tmp, then renaming to meta */\n\t{\n\t\tsize_t remaining_meta;\n\t\tchar   buf[4096];\n\n\t\tremaining_meta = lseek(metafile, 0, SEEK_END) - sizeof(struct MAM_tapeFmtV3);\n\t\tif (remaining_meta < 0) {\n\t\t\tMHVTL_ERR(\"Error : lseek failed on %s: %s\", meta_path, strerror(errno));\n\t\t\tgoto cleanup;\n\t\t}\n\n\t\t/* Positioning at the beginning of the meta data */\n\t\tif (lseek(metafile, sizeof(struct MAM_tapeFmtV3), SEEK_SET) < 0) {\n\t\t\tMHVTL_ERR(\"Error : lseek failed on %s: %s\", meta_path, strerror(errno));\n\t\t\tgoto cleanup;\n\t\t}\n\n\t\ttmpfile = open(tmp_path, O_CREAT | O_TRUNC | O_WRONLY,\n\t\t\t\t\t   S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);\n\t\tif (tmpfile < 0) {\n\t\t\tMHVTL_ERR(\"Failed to create temp meta file %s: %s\",\n\t\t\t\t\t  tmp_path, strerror(errno));\n\t\t\tgoto cleanup;\n\t\t}\n\n\t\twhile (remaining_meta > 0) {\n\t\t\tssize_t nread = read(metafile, buf,\n\t\t\t\t\t\t\t\t remaining_meta > sizeof(buf) ? sizeof(buf) : remaining_meta);\n\t\t\tif (nread <= 0) {\n\t\t\t\tMHVTL_ERR(\"Error reading meta file %s: %s\",\n\t\t\t\t\t\t  meta_path, strerror(errno));\n\t\t\t\tgoto cleanup;\n\t\t\t}\n\t\t\tif (write(tmpfile, buf, nread) != nread) {\n\t\t\t\tMHVTL_ERR(\"Error writing temp meta file %s: %s\",\n\t\t\t\t\t\t  tmp_path, strerror(errno));\n\t\t\t\tgoto cleanup;\n\t\t\t}\n\t\t\tremaining_meta -= nread;\n\t\t}\n\n\t\tif (fsync(tmpfile) < 0) {\n\t\t\tMHVTL_ERR(\"Error doing fsync of temp meta file %s: %s\", tmp_path, strerror(errno));\n\t\t\tgoto cleanup;\n\t\t}\n\n\t\tif (rename(tmp_path, meta_path) < 0) {\n\t\t\tMHVTL_ERR(\"rename %s -> %s failed: %s\",\n\t\t\t\t\t  tmp_path, meta_path, strerror(errno));\n\t\t\tgoto cleanup;\n\t\t}\n\t}\n\n\trc = 0; /* success */\n\ncleanup:\n\tif (mamfile >= 0) close(mamfile);\n\tif (metafile >= 0) close(metafile);\n\tif (tmpfile >= 0) close(tmpfile);\n\n\tif (rc != 0) {\n\t\tunlink(mam_path);\n\t\tunlink(tmp_path);\n\t}\n\n\treturn rc;\n}\n\n/*\n * Assuming mam.mam_fmt_version == 3,\n * Update mam from mam_fmt_version 3 to 4\n * Splitting mam into mam/mhvtl_data : updating tape_fmt_version from version 4 to 5\n * turning mam into an auto-descriptive format\n *\n * Returns:\n * == 0 -> Successfully updated mam\n * == 1 -> Failed to update mam\n * == 2 -> could not find mam file : format corrupt\n */\nint try_update_mam(char *currentPCL) {\n\tstruct MAM_tapeFmtV3 mam_v3;\n\tchar\t\t\t\t mam_path[1024];\n\tchar\t\t\t\t mhvtl_data_path[1024];\n\tchar\t\t\t\t tmp_path[1024];\n\tint\t\t\t\t\t mamfile   = -1;\n\tint\t\t\t\t\t mhvtlfile = -1;\n\tint\t\t\t\t\t tmpfile   = -1;\n\tssize_t\t\t\t\t nread;\n\tint\t\t\t\t\t rc = 1;\n\n\tsnprintf(mam_path, sizeof(mam_path), \"%s/mam\", currentPCL);\n\tsnprintf(mhvtl_data_path, sizeof(mhvtl_data_path), \"%s/mhvtl_data\", currentPCL);\n\tsnprintf(tmp_path, sizeof(tmp_path), \"%s/mam.tmp\", currentPCL);\n\n\tmamfile = open(mam_path, O_RDWR | O_LARGEFILE);\n\tif (mamfile < 0) {\n\t\tMHVTL_ERR(\"open of file %s failed: %s\", mam_path, strerror(errno));\n\t\treturn 2;\n\t}\n\n\tnread = read(mamfile, &mam_v3, sizeof(struct MAM_tapeFmtV3));\n\tif (nread != sizeof(struct MAM_tapeFmtV3)) {\n\t\tMHVTL_ERR(\"Error reading pcl %s MAM from mam file: %s\",\n\t\t\t\t  currentPCL, strerror(errno));\n\t\tgoto cleanup;\n\t}\n\n\t/* Checking MAM Format Version */\n\tif (mam_v3.mam_fmt_version != 3) {\n\t\tMHVTL_ERR(\"Error : MAM Format Version : %d , expected 3.\\\n\t\t\t\t\t\\nCannot handle conversion of %s MAM format to version 4\",\n\t\t\t\t  mam_v3.mam_fmt_version, currentPCL);\n\t\tgoto cleanup;\n\t}\n\n\tmam.mam_fmt_version\t = MAM_VERSION;\n\tmam.tape_fmt_version = 5;\n\n\t/* Copying attributes to new format */\n\n\tmam.remaining_capacity = mam_v3.remaining_capacity;\n\tmam.max_capacity\t   = mam_v3.max_capacity;\n\tmam.TapeAlert\t\t   = mam_v3.TapeAlert;\n\tmam.LoadCount\t\t   = mam_v3.LoadCount;\n\tmam.MAMSpaceRemaining  = mam_v3.MAMSpaceRemaining;\n\tmemcpy(mam.AssigningOrganization_1, mam_v3.AssigningOrganization_1, sizeof(mam.AssigningOrganization_1));\n\tmemcpy(mam.InitializationCount, mam_v3.InitializationCount, sizeof(mam.InitializationCount));\n\tmemcpy(mam.DevMakeSerialLastLoad, mam_v3.DevMakeSerialLastLoad, sizeof(mam.DevMakeSerialLastLoad));\n\tmemcpy(mam.DevMakeSerialLastLoad1, mam_v3.DevMakeSerialLastLoad1, sizeof(mam.DevMakeSerialLastLoad1));\n\tmemcpy(mam.DevMakeSerialLastLoad2, mam_v3.DevMakeSerialLastLoad2, sizeof(mam.DevMakeSerialLastLoad2));\n\tmemcpy(mam.DevMakeSerialLastLoad3, mam_v3.DevMakeSerialLastLoad3, sizeof(mam.DevMakeSerialLastLoad3));\n\tmam.WrittenInMediumLife = mam_v3.WrittenInMediumLife;\n\tmam.ReadInMediumLife\t= mam_v3.ReadInMediumLife;\n\tmam.WrittenInLastLoad\t= mam_v3.WrittenInLastLoad;\n\tmam.ReadInLastLoad\t\t= mam_v3.ReadInLastLoad;\n\n\tmemcpy(mam.MediumManufacturer, mam_v3.MediumManufacturer, sizeof(mam.MediumManufacturer));\n\tmemcpy(mam.MediumSerialNumber, mam_v3.MediumSerialNumber, sizeof(mam.MediumSerialNumber));\n\tmam.MediumLength = mam_v3.MediumLength;\n\tmam.MediumWidth\t = mam_v3.MediumWidth;\n\tmemcpy(mam.AssigningOrganization_2, mam_v3.AssigningOrganization_2, sizeof(mam.AssigningOrganization_2));\n\tmemcpy(mam.MediumManufactureDate, mam_v3.MediumManufactureDate, sizeof(mam.MediumManufactureDate));\n\tmam.FormattedDensityCode  = mam_v3.FormattedDensityCode;\n\tmam.MediumDensityCode\t  = mam_v3.MediumDensityCode;\n\tmam.MediumType\t\t\t  = mam_v3.MediumType;\n\tmam.MediaType\t\t\t  = mam_v3.MediaType;\n\tmam.MAMCapacity\t\t\t  = mam_v3.MAMCapacity;\n\tmam.MediumTypeInformation = mam_v3.MediumTypeInformation;\n\n\tmemcpy(mam.ApplicationVendor, mam_v3.ApplicationVendor, sizeof(mam.ApplicationVendor));\n\tmemcpy(mam.ApplicationName, mam_v3.ApplicationName, sizeof(mam.ApplicationName));\n\tmemcpy(mam.ApplicationVersion, mam_v3.ApplicationVersion, sizeof(mam.ApplicationVersion));\n\tmemcpy(mam.UserMediumTextLabel, mam_v3.UserMediumTextLabel, sizeof(mam.UserMediumTextLabel));\n\tmemcpy(mam.DateTimeLastWritten, mam_v3.DateTimeLastWritten, sizeof(mam.DateTimeLastWritten));\n\tmam.LocalizationIdentifier = mam_v3.LocalizationIdentifier;\n\tmemcpy(mam.Barcode, mam_v3.Barcode, sizeof(mam.Barcode));\n\tmemcpy(mam.OwningHostTextualName, mam_v3.OwningHostTextualName, sizeof(mam.OwningHostTextualName));\n\tmemcpy(mam.MediaPool, mam_v3.MediaPool, sizeof(mam.MediaPool));\n\n\tmam.record_dirty = mam_v3.record_dirty;\n\tmam.Flags\t\t = mam_v3.Flags;\n\n\tmam.media_info.bits_per_mm = mam_v3.media_info.bits_per_mm;\n\tmam.media_info.tracks\t   = mam_v3.media_info.tracks;\n\tmemcpy(mam.media_info.density_name, mam_v3.media_info.density_name, sizeof(mam.media_info.density_name));\n\tmemcpy(mam.media_info.description, mam_v3.media_info.description, sizeof(mam.media_info.description));\n\n\tmam.max_partitions = mam_v3.max_partitions;\n\tmam.num_partitions = mam_v3.num_partitions;\n\n\t/* create mhvtl_data file */\n\tmhvtlfile = open(mhvtl_data_path, O_CREAT | O_EXCL | O_WRONLY,\n\t\t\t\t\t S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);\n\tif (mhvtlfile < 0) {\n\t\tMHVTL_ERR(\"Failed to create mhvtl_data file %s: %s\", mhvtl_data_path, strerror(errno));\n\t\tgoto cleanup;\n\t}\n\n\t/* Updating mam :\n\t * - writing content to mam.tmp, then renaming to mam\n\t * - filling mhvtl_data */\n\t{\n\t\ttmpfile = open(tmp_path, O_CREAT | O_TRUNC | O_WRONLY,\n\t\t\t\t\t   S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);\n\t\tif (tmpfile < 0) {\n\t\t\tMHVTL_ERR(\"Failed to create temp mam file %s: %s\",\n\t\t\t\t\t  tmp_path, strerror(errno));\n\t\t\tgoto cleanup;\n\t\t}\n\n\t\twrite_mam(tmpfile, mhvtlfile);\n\n\t\tif (fsync(tmpfile) < 0) {\n\t\t\tMHVTL_ERR(\"Error doing fsync of temp mhvtl_data file %s: %s\", mhvtl_data_path, strerror(errno));\n\t\t\tgoto cleanup;\n\t\t}\n\n\t\tif (fsync(tmpfile) < 0) {\n\t\t\tMHVTL_ERR(\"Error doing fsync of temp mam file %s: %s\", tmp_path, strerror(errno));\n\t\t\tgoto cleanup;\n\t\t}\n\n\t\tif (rename(tmp_path, mam_path) < 0) {\n\t\t\tMHVTL_ERR(\"rename %s -> %s failed: %s\",\n\t\t\t\t\t  tmp_path, mam_path, strerror(errno));\n\t\t\tgoto cleanup;\n\t\t}\n\t}\n\n\trc = 0; /* success */\n\ncleanup:\n\tif (mamfile >= 0) close(mamfile);\n\tif (mhvtlfile >= 0) close(mhvtlfile);\n\tif (tmpfile >= 0) close(tmpfile);\n\n\tif (rc != 0) {\n\t\tunlink(tmp_path);\n\t\tunlink(mhvtl_data_path);\n\t}\n\n\treturn rc;\n}\n\n/*\n * Assuming mam.tape_fmt_version == 5,\n * Update from tape_fmt_version 5 to 6\n * Renaming {data, indx, meta} to {data, indx, meta}.0 as they correspond\n * to partition 0 instead of the whole tape\n *\n * Returns:\n * == 0 -> Successfully updated tape\n * == 1 -> Failed to update tape\n */\n\nint try_update_tape(char *currentPCL) {\n\tchar\t\toldpath[1024];\n\tchar\t\tpath[1024 + 2];\n\tconst char *file_name[] = {\"data\", \"indx\", \"meta\"};\n\n\t/* Checking Tape Format Version */\n\tif (mam.tape_fmt_version != 5) {\n\t\tMHVTL_ERR(\"Error : Tape Format Version : %d , expected 5.\\\n\t\t\t\t\t\\nCannot handle conversion of %s tape format to version 6\",\n\t\t\t\t  mam.tape_fmt_version, currentPCL);\n\t\treturn 1;\n\t}\n\n\t/* renaming <file> to <file>.0 */\n\tfor (int k = 0; k < 3; k++) {\n\t\tsnprintf(oldpath, sizeof(oldpath), \"%s/%s\", currentPCL, file_name[k]);\n\t\tsnprintf(path, sizeof(path), \"%s.0\", oldpath);\n\t\tif (rename(oldpath, path) < 0) {\n\t\t\tMHVTL_ERR(\"rename %s -> %s failed: %s\",\n\t\t\t\t\t  oldpath, path, strerror(errno));\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\tmam.tape_fmt_version = 6;\n\n\treturn 0;\n}"
  },
  {
    "path": "usr/utils/minilzo.c",
    "content": "/* minilzo.c -- mini subset of the LZO real-time data compression library\n\n   This file is part of the LZO real-time data compression library.\n\n   Copyright (C) 1996-2015 Markus Franz Xaver Johannes Oberhumer\n   All Rights Reserved.\n\n   The LZO library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU General Public License as\n   published by the Free Software Foundation; either version 2 of\n   the License, or (at your option) any later version.\n\n   The LZO library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n\n   You should have received a copy of the GNU General Public License\n   along with the LZO library; see the file COPYING.\n   If not, write to the Free Software Foundation, Inc.,\n   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n\n   Markus F.X.J. Oberhumer\n   <markus@oberhumer.com>\n   http://www.oberhumer.com/opensource/lzo/\n */\n\n/*\n * NOTE:\n *   the full LZO package can be found at\n *   http://www.oberhumer.com/opensource/lzo/\n */\n\n#define __LZO_IN_MINILZO 1\n\n#if defined(LZO_CFG_FREESTANDING)\n#  undef MINILZO_HAVE_CONFIG_H\n#  define LZO_LIBC_FREESTANDING 1\n#  define LZO_OS_FREESTANDING 1\n#endif\n\n#ifdef MINILZO_HAVE_CONFIG_H\n#  include <config.h>\n#endif\n#include <limits.h>\n#include <stddef.h>\n#if defined(MINILZO_CFG_USE_INTERNAL_LZODEFS)\n\n#ifndef __LZODEFS_H_INCLUDED\n#define __LZODEFS_H_INCLUDED 1\n\n#if defined(__CYGWIN32__) && !defined(__CYGWIN__)\n#  define __CYGWIN__ __CYGWIN32__\n#endif\n#if 1 && defined(__INTERIX) && defined(__GNUC__) && !defined(_ALL_SOURCE)\n#  define _ALL_SOURCE 1\n#endif\n#if defined(__mips__) && defined(__R5900__)\n#  if !defined(__LONG_MAX__)\n#    define __LONG_MAX__ 9223372036854775807L\n#  endif\n#endif\n#if !defined(LZO_CFG_NO_DISABLE_WUNDEF)\n#if defined(__ARMCC_VERSION)\n#  pragma diag_suppress 193\n#elif defined(__clang__) && defined(__clang_minor__)\n#  pragma clang diagnostic ignored \"-Wundef\"\n#elif defined(__INTEL_COMPILER)\n#  pragma warning(disable: 193)\n#elif defined(__KEIL__) && defined(__C166__)\n#  pragma warning disable = 322\n#elif defined(__GNUC__) && defined(__GNUC_MINOR__) && !defined(__PATHSCALE__)\n#  if ((__GNUC__-0) >= 5 || ((__GNUC__-0) == 4 && (__GNUC_MINOR__-0) >= 2))\n#    pragma GCC diagnostic ignored \"-Wundef\"\n#  endif\n#elif defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__MWERKS__)\n#  if ((_MSC_VER-0) >= 1300)\n#    pragma warning(disable: 4668)\n#  endif\n#endif\n#endif\n#if 0 && defined(__POCC__) && defined(_WIN32)\n#  if (__POCC__ >= 400)\n#    pragma warn(disable: 2216)\n#  endif\n#endif\n#if 0 && defined(__WATCOMC__)\n#  if (__WATCOMC__ >= 1050) && (__WATCOMC__ < 1060)\n#    pragma warning 203 9\n#  endif\n#endif\n#if defined(__BORLANDC__) && defined(__MSDOS__) && !defined(__FLAT__)\n#  pragma option -h\n#endif\n#if !(LZO_CFG_NO_DISABLE_WCRTNONSTDC)\n#ifndef _CRT_NONSTDC_NO_DEPRECATE\n#define _CRT_NONSTDC_NO_DEPRECATE 1\n#endif\n#ifndef _CRT_NONSTDC_NO_WARNINGS\n#define _CRT_NONSTDC_NO_WARNINGS 1\n#endif\n#ifndef _CRT_SECURE_NO_DEPRECATE\n#define _CRT_SECURE_NO_DEPRECATE 1\n#endif\n#ifndef _CRT_SECURE_NO_WARNINGS\n#define _CRT_SECURE_NO_WARNINGS 1\n#endif\n#endif\n#if 0\n#define LZO_0xffffUL            0xfffful\n#define LZO_0xffffffffUL        0xfffffffful\n#else\n#define LZO_0xffffUL            65535ul\n#define LZO_0xffffffffUL        4294967295ul\n#endif\n#define LZO_0xffffL             LZO_0xffffUL\n#define LZO_0xffffffffL         LZO_0xffffffffUL\n#if (LZO_0xffffL == LZO_0xffffffffL)\n#  error \"your preprocessor is broken 1\"\n#endif\n#if (16ul * 16384ul != 262144ul)\n#  error \"your preprocessor is broken 2\"\n#endif\n#if 0\n#if (32767 >= 4294967295ul)\n#  error \"your preprocessor is broken 3\"\n#endif\n#if (65535u >= 4294967295ul)\n#  error \"your preprocessor is broken 4\"\n#endif\n#endif\n#if defined(__COUNTER__)\n#  ifndef LZO_CFG_USE_COUNTER\n#  define LZO_CFG_USE_COUNTER 1\n#  endif\n#else\n#  undef LZO_CFG_USE_COUNTER\n#endif\n#if (UINT_MAX == LZO_0xffffL)\n#if defined(__ZTC__) && defined(__I86__) && !defined(__OS2__)\n#  if !defined(MSDOS)\n#    define MSDOS 1\n#  endif\n#  if !defined(_MSDOS)\n#    define _MSDOS 1\n#  endif\n#elif 0 && defined(__VERSION) && defined(MB_LEN_MAX)\n#  if (__VERSION == 520) && (MB_LEN_MAX == 1)\n#    if !defined(__AZTEC_C__)\n#      define __AZTEC_C__ __VERSION\n#    endif\n#    if !defined(__DOS__)\n#      define __DOS__ 1\n#    endif\n#  endif\n#endif\n#endif\n#if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL)\n#  define ptrdiff_t long\n#  define _PTRDIFF_T_DEFINED 1\n#endif\n#if (UINT_MAX == LZO_0xffffL)\n#  undef __LZO_RENAME_A\n#  undef __LZO_RENAME_B\n#  if defined(__AZTEC_C__) && defined(__DOS__)\n#    define __LZO_RENAME_A 1\n#  elif defined(_MSC_VER) && defined(MSDOS)\n#    if (_MSC_VER < 600)\n#      define __LZO_RENAME_A 1\n#    elif (_MSC_VER < 700)\n#      define __LZO_RENAME_B 1\n#    endif\n#  elif defined(__TSC__) && defined(__OS2__)\n#    define __LZO_RENAME_A 1\n#  elif defined(__MSDOS__) && defined(__TURBOC__) && (__TURBOC__ < 0x0410)\n#    define __LZO_RENAME_A 1\n#  elif defined(__PACIFIC__) && defined(DOS)\n#    if !defined(__far)\n#      define __far far\n#    endif\n#    if !defined(__near)\n#      define __near near\n#    endif\n#  endif\n#  if defined(__LZO_RENAME_A)\n#    if !defined(__cdecl)\n#      define __cdecl cdecl\n#    endif\n#    if !defined(__far)\n#      define __far far\n#    endif\n#    if !defined(__huge)\n#      define __huge huge\n#    endif\n#    if !defined(__near)\n#      define __near near\n#    endif\n#    if !defined(__pascal)\n#      define __pascal pascal\n#    endif\n#    if !defined(__huge)\n#      define __huge huge\n#    endif\n#  elif defined(__LZO_RENAME_B)\n#    if !defined(__cdecl)\n#      define __cdecl _cdecl\n#    endif\n#    if !defined(__far)\n#      define __far _far\n#    endif\n#    if !defined(__huge)\n#      define __huge _huge\n#    endif\n#    if !defined(__near)\n#      define __near _near\n#    endif\n#    if !defined(__pascal)\n#      define __pascal _pascal\n#    endif\n#  elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__)\n#    if !defined(__cdecl)\n#      define __cdecl cdecl\n#    endif\n#    if !defined(__pascal)\n#      define __pascal pascal\n#    endif\n#  endif\n#  undef __LZO_RENAME_A\n#  undef __LZO_RENAME_B\n#endif\n#if (UINT_MAX == LZO_0xffffL)\n#if defined(__AZTEC_C__) && defined(__DOS__)\n#  define LZO_BROKEN_CDECL_ALT_SYNTAX 1\n#elif defined(_MSC_VER) && defined(MSDOS)\n#  if (_MSC_VER < 600)\n#    define LZO_BROKEN_INTEGRAL_CONSTANTS 1\n#  endif\n#  if (_MSC_VER < 700)\n#    define LZO_BROKEN_INTEGRAL_PROMOTION 1\n#    define LZO_BROKEN_SIZEOF 1\n#  endif\n#elif defined(__PACIFIC__) && defined(DOS)\n#  define LZO_BROKEN_INTEGRAL_CONSTANTS 1\n#elif defined(__TURBOC__) && defined(__MSDOS__)\n#  if (__TURBOC__ < 0x0150)\n#    define LZO_BROKEN_CDECL_ALT_SYNTAX 1\n#    define LZO_BROKEN_INTEGRAL_CONSTANTS 1\n#    define LZO_BROKEN_INTEGRAL_PROMOTION 1\n#  endif\n#  if (__TURBOC__ < 0x0200)\n#    define LZO_BROKEN_SIZEOF 1\n#  endif\n#  if (__TURBOC__ < 0x0400) && defined(__cplusplus)\n#    define LZO_BROKEN_CDECL_ALT_SYNTAX 1\n#  endif\n#elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__)\n#  define LZO_BROKEN_CDECL_ALT_SYNTAX 1\n#  define LZO_BROKEN_SIZEOF 1\n#endif\n#endif\n#if defined(__WATCOMC__) && (__WATCOMC__ < 900)\n#  define LZO_BROKEN_INTEGRAL_CONSTANTS 1\n#endif\n#if defined(_CRAY) && defined(_CRAY1)\n#  define LZO_BROKEN_SIGNED_RIGHT_SHIFT 1\n#endif\n#define LZO_PP_STRINGIZE(x)             #x\n#define LZO_PP_MACRO_EXPAND(x)          LZO_PP_STRINGIZE(x)\n#define LZO_PP_CONCAT0()                /*empty*/\n#define LZO_PP_CONCAT1(a)               a\n#define LZO_PP_CONCAT2(a,b)             a ## b\n#define LZO_PP_CONCAT3(a,b,c)           a ## b ## c\n#define LZO_PP_CONCAT4(a,b,c,d)         a ## b ## c ## d\n#define LZO_PP_CONCAT5(a,b,c,d,e)       a ## b ## c ## d ## e\n#define LZO_PP_CONCAT6(a,b,c,d,e,f)     a ## b ## c ## d ## e ## f\n#define LZO_PP_CONCAT7(a,b,c,d,e,f,g)   a ## b ## c ## d ## e ## f ## g\n#define LZO_PP_ECONCAT0()               LZO_PP_CONCAT0()\n#define LZO_PP_ECONCAT1(a)              LZO_PP_CONCAT1(a)\n#define LZO_PP_ECONCAT2(a,b)            LZO_PP_CONCAT2(a,b)\n#define LZO_PP_ECONCAT3(a,b,c)          LZO_PP_CONCAT3(a,b,c)\n#define LZO_PP_ECONCAT4(a,b,c,d)        LZO_PP_CONCAT4(a,b,c,d)\n#define LZO_PP_ECONCAT5(a,b,c,d,e)      LZO_PP_CONCAT5(a,b,c,d,e)\n#define LZO_PP_ECONCAT6(a,b,c,d,e,f)    LZO_PP_CONCAT6(a,b,c,d,e,f)\n#define LZO_PP_ECONCAT7(a,b,c,d,e,f,g)  LZO_PP_CONCAT7(a,b,c,d,e,f,g)\n#define LZO_PP_EMPTY                    /*empty*/\n#define LZO_PP_EMPTY0()                 /*empty*/\n#define LZO_PP_EMPTY1(a)                /*empty*/\n#define LZO_PP_EMPTY2(a,b)              /*empty*/\n#define LZO_PP_EMPTY3(a,b,c)            /*empty*/\n#define LZO_PP_EMPTY4(a,b,c,d)          /*empty*/\n#define LZO_PP_EMPTY5(a,b,c,d,e)        /*empty*/\n#define LZO_PP_EMPTY6(a,b,c,d,e,f)      /*empty*/\n#define LZO_PP_EMPTY7(a,b,c,d,e,f,g)    /*empty*/\n#if 1\n#define LZO_CPP_STRINGIZE(x)            #x\n#define LZO_CPP_MACRO_EXPAND(x)         LZO_CPP_STRINGIZE(x)\n#define LZO_CPP_CONCAT2(a,b)            a ## b\n#define LZO_CPP_CONCAT3(a,b,c)          a ## b ## c\n#define LZO_CPP_CONCAT4(a,b,c,d)        a ## b ## c ## d\n#define LZO_CPP_CONCAT5(a,b,c,d,e)      a ## b ## c ## d ## e\n#define LZO_CPP_CONCAT6(a,b,c,d,e,f)    a ## b ## c ## d ## e ## f\n#define LZO_CPP_CONCAT7(a,b,c,d,e,f,g)  a ## b ## c ## d ## e ## f ## g\n#define LZO_CPP_ECONCAT2(a,b)           LZO_CPP_CONCAT2(a,b)\n#define LZO_CPP_ECONCAT3(a,b,c)         LZO_CPP_CONCAT3(a,b,c)\n#define LZO_CPP_ECONCAT4(a,b,c,d)       LZO_CPP_CONCAT4(a,b,c,d)\n#define LZO_CPP_ECONCAT5(a,b,c,d,e)     LZO_CPP_CONCAT5(a,b,c,d,e)\n#define LZO_CPP_ECONCAT6(a,b,c,d,e,f)   LZO_CPP_CONCAT6(a,b,c,d,e,f)\n#define LZO_CPP_ECONCAT7(a,b,c,d,e,f,g) LZO_CPP_CONCAT7(a,b,c,d,e,f,g)\n#endif\n#define __LZO_MASK_GEN(o,b)     (((((o) << ((b)-!!(b))) - (o)) << 1) + (o)*!!(b))\n#if 1 && defined(__cplusplus)\n#  if !defined(__STDC_CONSTANT_MACROS)\n#    define __STDC_CONSTANT_MACROS 1\n#  endif\n#  if !defined(__STDC_LIMIT_MACROS)\n#    define __STDC_LIMIT_MACROS 1\n#  endif\n#endif\n#if defined(__cplusplus)\n#  define LZO_EXTERN_C          extern \"C\"\n#  define LZO_EXTERN_C_BEGIN    extern \"C\" {\n#  define LZO_EXTERN_C_END      }\n#else\n#  define LZO_EXTERN_C          extern\n#  define LZO_EXTERN_C_BEGIN    /*empty*/\n#  define LZO_EXTERN_C_END      /*empty*/\n#endif\n#if !defined(__LZO_OS_OVERRIDE)\n#if (LZO_OS_FREESTANDING)\n#  define LZO_INFO_OS           \"freestanding\"\n#elif (LZO_OS_EMBEDDED)\n#  define LZO_INFO_OS           \"embedded\"\n#elif 1 && defined(__IAR_SYSTEMS_ICC__)\n#  define LZO_OS_EMBEDDED       1\n#  define LZO_INFO_OS           \"embedded\"\n#elif defined(__CYGWIN__) && defined(__GNUC__)\n#  define LZO_OS_CYGWIN         1\n#  define LZO_INFO_OS           \"cygwin\"\n#elif defined(__EMX__) && defined(__GNUC__)\n#  define LZO_OS_EMX            1\n#  define LZO_INFO_OS           \"emx\"\n#elif defined(__BEOS__)\n#  define LZO_OS_BEOS           1\n#  define LZO_INFO_OS           \"beos\"\n#elif defined(__Lynx__)\n#  define LZO_OS_LYNXOS         1\n#  define LZO_INFO_OS           \"lynxos\"\n#elif defined(__OS400__)\n#  define LZO_OS_OS400          1\n#  define LZO_INFO_OS           \"os400\"\n#elif defined(__QNX__)\n#  define LZO_OS_QNX            1\n#  define LZO_INFO_OS           \"qnx\"\n#elif defined(__BORLANDC__) && defined(__DPMI32__) && (__BORLANDC__ >= 0x0460)\n#  define LZO_OS_DOS32          1\n#  define LZO_INFO_OS           \"dos32\"\n#elif defined(__BORLANDC__) && defined(__DPMI16__)\n#  define LZO_OS_DOS16          1\n#  define LZO_INFO_OS           \"dos16\"\n#elif defined(__ZTC__) && defined(DOS386)\n#  define LZO_OS_DOS32          1\n#  define LZO_INFO_OS           \"dos32\"\n#elif defined(__OS2__) || defined(__OS2V2__)\n#  if (UINT_MAX == LZO_0xffffL)\n#    define LZO_OS_OS216        1\n#    define LZO_INFO_OS         \"os216\"\n#  elif (UINT_MAX == LZO_0xffffffffL)\n#    define LZO_OS_OS2          1\n#    define LZO_INFO_OS         \"os2\"\n#  else\n#    error \"check your limits.h header\"\n#  endif\n#elif defined(__WIN64__) || defined(_WIN64) || defined(WIN64)\n#  define LZO_OS_WIN64          1\n#  define LZO_INFO_OS           \"win64\"\n#elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WINDOWS_386__)\n#  define LZO_OS_WIN32          1\n#  define LZO_INFO_OS           \"win32\"\n#elif defined(__MWERKS__) && defined(__INTEL__)\n#  define LZO_OS_WIN32          1\n#  define LZO_INFO_OS           \"win32\"\n#elif defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows)\n#  if (UINT_MAX == LZO_0xffffL)\n#    define LZO_OS_WIN16        1\n#    define LZO_INFO_OS         \"win16\"\n#  elif (UINT_MAX == LZO_0xffffffffL)\n#    define LZO_OS_WIN32        1\n#    define LZO_INFO_OS         \"win32\"\n#  else\n#    error \"check your limits.h header\"\n#  endif\n#elif defined(__DOS__) || defined(__MSDOS__) || defined(_MSDOS) || defined(MSDOS) || (defined(__PACIFIC__) && defined(DOS))\n#  if (UINT_MAX == LZO_0xffffL)\n#    define LZO_OS_DOS16        1\n#    define LZO_INFO_OS         \"dos16\"\n#  elif (UINT_MAX == LZO_0xffffffffL)\n#    define LZO_OS_DOS32        1\n#    define LZO_INFO_OS         \"dos32\"\n#  else\n#    error \"check your limits.h header\"\n#  endif\n#elif defined(__WATCOMC__)\n#  if defined(__NT__) && (UINT_MAX == LZO_0xffffL)\n#    define LZO_OS_DOS16        1\n#    define LZO_INFO_OS         \"dos16\"\n#  elif defined(__NT__) && (__WATCOMC__ < 1100)\n#    define LZO_OS_WIN32        1\n#    define LZO_INFO_OS         \"win32\"\n#  elif defined(__linux__) || defined(__LINUX__)\n#    define LZO_OS_POSIX        1\n#    define LZO_INFO_OS         \"posix\"\n#  else\n#    error \"please specify a target using the -bt compiler option\"\n#  endif\n#elif defined(__palmos__)\n#  define LZO_OS_PALMOS         1\n#  define LZO_INFO_OS           \"palmos\"\n#elif defined(__TOS__) || defined(__atarist__)\n#  define LZO_OS_TOS            1\n#  define LZO_INFO_OS           \"tos\"\n#elif defined(macintosh) && !defined(__arm__) && !defined(__i386__) && !defined(__ppc__) && !defined(__x64_64__)\n#  define LZO_OS_MACCLASSIC     1\n#  define LZO_INFO_OS           \"macclassic\"\n#elif defined(__VMS)\n#  define LZO_OS_VMS            1\n#  define LZO_INFO_OS           \"vms\"\n#elif (defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)\n#  define LZO_OS_CONSOLE        1\n#  define LZO_OS_CONSOLE_PS2    1\n#  define LZO_INFO_OS           \"console\"\n#  define LZO_INFO_OS_CONSOLE   \"ps2\"\n#elif defined(__mips__) && defined(__psp__)\n#  define LZO_OS_CONSOLE        1\n#  define LZO_OS_CONSOLE_PSP    1\n#  define LZO_INFO_OS           \"console\"\n#  define LZO_INFO_OS_CONSOLE   \"psp\"\n#else\n#  define LZO_OS_POSIX          1\n#  define LZO_INFO_OS           \"posix\"\n#endif\n#if (LZO_OS_POSIX)\n#  if defined(_AIX) || defined(__AIX__) || defined(__aix__)\n#    define LZO_OS_POSIX_AIX        1\n#    define LZO_INFO_OS_POSIX       \"aix\"\n#  elif defined(__FreeBSD__)\n#    define LZO_OS_POSIX_FREEBSD    1\n#    define LZO_INFO_OS_POSIX       \"freebsd\"\n#  elif defined(__hpux__) || defined(__hpux)\n#    define LZO_OS_POSIX_HPUX       1\n#    define LZO_INFO_OS_POSIX       \"hpux\"\n#  elif defined(__INTERIX)\n#    define LZO_OS_POSIX_INTERIX    1\n#    define LZO_INFO_OS_POSIX       \"interix\"\n#  elif defined(__IRIX__) || defined(__irix__)\n#    define LZO_OS_POSIX_IRIX       1\n#    define LZO_INFO_OS_POSIX       \"irix\"\n#  elif defined(__linux__) || defined(__linux) || defined(__LINUX__)\n#    define LZO_OS_POSIX_LINUX      1\n#    define LZO_INFO_OS_POSIX       \"linux\"\n#  elif defined(__APPLE__) && defined(__MACH__)\n#    if ((__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__-0) >= 20000)\n#      define LZO_OS_POSIX_DARWIN     1040\n#      define LZO_INFO_OS_POSIX       \"darwin_iphone\"\n#    elif ((__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__-0) >= 1040)\n#      define LZO_OS_POSIX_DARWIN     __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__\n#      define LZO_INFO_OS_POSIX       \"darwin\"\n#    else\n#      define LZO_OS_POSIX_DARWIN     1\n#      define LZO_INFO_OS_POSIX       \"darwin\"\n#    endif\n#    define LZO_OS_POSIX_MACOSX     LZO_OS_POSIX_DARWIN\n#  elif defined(__minix__) || defined(__minix)\n#    define LZO_OS_POSIX_MINIX      1\n#    define LZO_INFO_OS_POSIX       \"minix\"\n#  elif defined(__NetBSD__)\n#    define LZO_OS_POSIX_NETBSD     1\n#    define LZO_INFO_OS_POSIX       \"netbsd\"\n#  elif defined(__OpenBSD__)\n#    define LZO_OS_POSIX_OPENBSD    1\n#    define LZO_INFO_OS_POSIX       \"openbsd\"\n#  elif defined(__osf__)\n#    define LZO_OS_POSIX_OSF        1\n#    define LZO_INFO_OS_POSIX       \"osf\"\n#  elif defined(__solaris__) || defined(__sun)\n#    if defined(__SVR4) || defined(__svr4__)\n#      define LZO_OS_POSIX_SOLARIS  1\n#      define LZO_INFO_OS_POSIX     \"solaris\"\n#    else\n#      define LZO_OS_POSIX_SUNOS    1\n#      define LZO_INFO_OS_POSIX     \"sunos\"\n#    endif\n#  elif defined(__ultrix__) || defined(__ultrix)\n#    define LZO_OS_POSIX_ULTRIX     1\n#    define LZO_INFO_OS_POSIX       \"ultrix\"\n#  elif defined(_UNICOS)\n#    define LZO_OS_POSIX_UNICOS     1\n#    define LZO_INFO_OS_POSIX       \"unicos\"\n#  else\n#    define LZO_OS_POSIX_UNKNOWN    1\n#    define LZO_INFO_OS_POSIX       \"unknown\"\n#  endif\n#endif\n#endif\n#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)\n#  if (UINT_MAX != LZO_0xffffL)\n#    error \"unexpected configuration - check your compiler defines\"\n#  endif\n#  if (ULONG_MAX != LZO_0xffffffffL)\n#    error \"unexpected configuration - check your compiler defines\"\n#  endif\n#endif\n#if (LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_WIN32 || LZO_OS_WIN64)\n#  if (UINT_MAX != LZO_0xffffffffL)\n#    error \"unexpected configuration - check your compiler defines\"\n#  endif\n#  if (ULONG_MAX != LZO_0xffffffffL)\n#    error \"unexpected configuration - check your compiler defines\"\n#  endif\n#endif\n#if defined(CIL) && defined(_GNUCC) && defined(__GNUC__)\n#  define LZO_CC_CILLY          1\n#  define LZO_INFO_CC           \"Cilly\"\n#  if defined(__CILLY__)\n#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__CILLY__)\n#  else\n#    define LZO_INFO_CCVER      \"unknown\"\n#  endif\n#elif 0 && defined(SDCC) && defined(__VERSION__) && !defined(__GNUC__)\n#  define LZO_CC_SDCC           1\n#  define LZO_INFO_CC           \"sdcc\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(SDCC)\n#elif defined(__PATHSCALE__) && defined(__PATHCC_PATCHLEVEL__)\n#  define LZO_CC_PATHSCALE      (__PATHCC__ * 0x10000L + (__PATHCC_MINOR__-0) * 0x100 + (__PATHCC_PATCHLEVEL__-0))\n#  define LZO_INFO_CC           \"Pathscale C\"\n#  define LZO_INFO_CCVER        __PATHSCALE__\n#  if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)\n#    define LZO_CC_PATHSCALE_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))\n#  endif\n#elif defined(__INTEL_COMPILER) && ((__INTEL_COMPILER-0) > 0)\n#  define LZO_CC_INTELC         __INTEL_COMPILER\n#  define LZO_INFO_CC           \"Intel C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__INTEL_COMPILER)\n#  if defined(_MSC_VER) && ((_MSC_VER-0) > 0)\n#    define LZO_CC_INTELC_MSC   _MSC_VER\n#  elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)\n#    define LZO_CC_INTELC_GNUC   (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))\n#  endif\n#elif defined(__POCC__) && defined(_WIN32)\n#  define LZO_CC_PELLESC        1\n#  define LZO_INFO_CC           \"Pelles C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__POCC__)\n#elif defined(__ARMCC_VERSION) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)\n#  if defined(__GNUC_PATCHLEVEL__)\n#    define LZO_CC_ARMCC_GNUC   (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))\n#  else\n#    define LZO_CC_ARMCC_GNUC   (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100)\n#  endif\n#  define LZO_CC_ARMCC          __ARMCC_VERSION\n#  define LZO_INFO_CC           \"ARM C Compiler\"\n#  define LZO_INFO_CCVER        __VERSION__\n#elif defined(__clang__) && defined(__llvm__) && defined(__VERSION__)\n#  if defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__)\n#    define LZO_CC_CLANG        (__clang_major__ * 0x10000L + (__clang_minor__-0) * 0x100 + (__clang_patchlevel__-0))\n#  else\n#    define LZO_CC_CLANG        0x010000L\n#  endif\n#  if defined(_MSC_VER) && ((_MSC_VER-0) > 0)\n#    define LZO_CC_CLANG_MSC    _MSC_VER\n#  elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)\n#    define LZO_CC_CLANG_GNUC   (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))\n#  endif\n#  define LZO_INFO_CC           \"clang\"\n#  define LZO_INFO_CCVER        __VERSION__\n#elif defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)\n#  if defined(__GNUC_PATCHLEVEL__)\n#    define LZO_CC_LLVM_GNUC    (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))\n#  else\n#    define LZO_CC_LLVM_GNUC    (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100)\n#  endif\n#  define LZO_CC_LLVM           LZO_CC_LLVM_GNUC\n#  define LZO_INFO_CC           \"llvm-gcc\"\n#  define LZO_INFO_CCVER        __VERSION__\n#elif defined(__ACK__) && defined(_ACK)\n#  define LZO_CC_ACK            1\n#  define LZO_INFO_CC           \"Amsterdam Compiler Kit C\"\n#  define LZO_INFO_CCVER        \"unknown\"\n#elif defined(__ARMCC_VERSION) && !defined(__GNUC__)\n#  define LZO_CC_ARMCC          __ARMCC_VERSION\n#  define LZO_CC_ARMCC_ARMCC    __ARMCC_VERSION\n#  define LZO_INFO_CC           \"ARM C Compiler\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__ARMCC_VERSION)\n#elif defined(__AZTEC_C__)\n#  define LZO_CC_AZTECC         1\n#  define LZO_INFO_CC           \"Aztec C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__AZTEC_C__)\n#elif defined(__CODEGEARC__)\n#  define LZO_CC_CODEGEARC      1\n#  define LZO_INFO_CC           \"CodeGear C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__CODEGEARC__)\n#elif defined(__BORLANDC__)\n#  define LZO_CC_BORLANDC       1\n#  define LZO_INFO_CC           \"Borland C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__BORLANDC__)\n#elif defined(_CRAYC) && defined(_RELEASE)\n#  define LZO_CC_CRAYC          1\n#  define LZO_INFO_CC           \"Cray C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(_RELEASE)\n#elif defined(__DMC__) && defined(__SC__)\n#  define LZO_CC_DMC            1\n#  define LZO_INFO_CC           \"Digital Mars C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__DMC__)\n#elif defined(__DECC)\n#  define LZO_CC_DECC           1\n#  define LZO_INFO_CC           \"DEC C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__DECC)\n#elif (defined(__ghs) || defined(__ghs__)) && defined(__GHS_VERSION_NUMBER) && ((__GHS_VERSION_NUMBER-0) > 0)\n#  define LZO_CC_GHS            1\n#  define LZO_INFO_CC           \"Green Hills C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__GHS_VERSION_NUMBER)\n#  if defined(_MSC_VER) && ((_MSC_VER-0) > 0)\n#    define LZO_CC_GHS_MSC      _MSC_VER\n#  elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)\n#    define LZO_CC_GHS_GNUC     (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))\n#  endif\n#elif defined(__HIGHC__)\n#  define LZO_CC_HIGHC          1\n#  define LZO_INFO_CC           \"MetaWare High C\"\n#  define LZO_INFO_CCVER        \"unknown\"\n#elif defined(__HP_aCC) && ((__HP_aCC-0) > 0)\n#  define LZO_CC_HPACC          __HP_aCC\n#  define LZO_INFO_CC           \"HP aCC\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__HP_aCC)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#  define LZO_CC_IARC           1\n#  define LZO_INFO_CC           \"IAR C\"\n#  if defined(__VER__)\n#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__VER__)\n#  else\n#    define LZO_INFO_CCVER      \"unknown\"\n#  endif\n#elif defined(__IBMC__) && ((__IBMC__-0) > 0)\n#  define LZO_CC_IBMC           __IBMC__\n#  define LZO_INFO_CC           \"IBM C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__IBMC__)\n#elif defined(__IBMCPP__) && ((__IBMCPP__-0) > 0)\n#  define LZO_CC_IBMC           __IBMCPP__\n#  define LZO_INFO_CC           \"IBM C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__IBMCPP__)\n#elif defined(__KEIL__) && defined(__C166__)\n#  define LZO_CC_KEILC          1\n#  define LZO_INFO_CC           \"Keil C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__C166__)\n#elif defined(__LCC__) && defined(_WIN32) && defined(__LCCOPTIMLEVEL)\n#  define LZO_CC_LCCWIN32       1\n#  define LZO_INFO_CC           \"lcc-win32\"\n#  define LZO_INFO_CCVER        \"unknown\"\n#elif defined(__LCC__)\n#  define LZO_CC_LCC            1\n#  define LZO_INFO_CC           \"lcc\"\n#  if defined(__LCC_VERSION__)\n#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__LCC_VERSION__)\n#  else\n#    define LZO_INFO_CCVER      \"unknown\"\n#  endif\n#elif defined(__MWERKS__) && ((__MWERKS__-0) > 0)\n#  define LZO_CC_MWERKS         __MWERKS__\n#  define LZO_INFO_CC           \"Metrowerks C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__MWERKS__)\n#elif (defined(__NDPC__) || defined(__NDPX__)) && defined(__i386)\n#  define LZO_CC_NDPC           1\n#  define LZO_INFO_CC           \"Microway NDP C\"\n#  define LZO_INFO_CCVER        \"unknown\"\n#elif defined(__PACIFIC__)\n#  define LZO_CC_PACIFICC       1\n#  define LZO_INFO_CC           \"Pacific C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__PACIFIC__)\n#elif defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__)\n#  if defined(__PGIC_PATCHLEVEL__)\n#    define LZO_CC_PGI          (__PGIC__ * 0x10000L + (__PGIC_MINOR__-0) * 0x100 + (__PGIC_PATCHLEVEL__-0))\n#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__PGIC__) \".\" LZO_PP_MACRO_EXPAND(__PGIC_MINOR__) \".\" LZO_PP_MACRO_EXPAND(__PGIC_PATCHLEVEL__)\n#  else\n#    define LZO_CC_PGI          (__PGIC__ * 0x10000L + (__PGIC_MINOR__-0) * 0x100)\n#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__PGIC__) \".\" LZO_PP_MACRO_EXPAND(__PGIC_MINOR__) \".0\"\n#  endif\n#  define LZO_INFO_CC           \"Portland Group PGI C\"\n#elif defined(__PGI) && (defined(__linux__) || defined(__WIN32__))\n#  define LZO_CC_PGI            1\n#  define LZO_INFO_CC           \"Portland Group PGI C\"\n#  define LZO_INFO_CCVER        \"unknown\"\n#elif defined(__PUREC__) && defined(__TOS__)\n#  define LZO_CC_PUREC          1\n#  define LZO_INFO_CC           \"Pure C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__PUREC__)\n#elif defined(__SC__) && defined(__ZTC__)\n#  define LZO_CC_SYMANTECC      1\n#  define LZO_INFO_CC           \"Symantec C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__SC__)\n#elif defined(__SUNPRO_C)\n#  define LZO_INFO_CC           \"SunPro C\"\n#  if ((__SUNPRO_C-0) > 0)\n#    define LZO_CC_SUNPROC      __SUNPRO_C\n#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__SUNPRO_C)\n#  else\n#    define LZO_CC_SUNPROC      1\n#    define LZO_INFO_CCVER      \"unknown\"\n#  endif\n#elif defined(__SUNPRO_CC)\n#  define LZO_INFO_CC           \"SunPro C\"\n#  if ((__SUNPRO_CC-0) > 0)\n#    define LZO_CC_SUNPROC      __SUNPRO_CC\n#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__SUNPRO_CC)\n#  else\n#    define LZO_CC_SUNPROC      1\n#    define LZO_INFO_CCVER      \"unknown\"\n#  endif\n#elif defined(__TINYC__)\n#  define LZO_CC_TINYC          1\n#  define LZO_INFO_CC           \"Tiny C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__TINYC__)\n#elif defined(__TSC__)\n#  define LZO_CC_TOPSPEEDC      1\n#  define LZO_INFO_CC           \"TopSpeed C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__TSC__)\n#elif defined(__WATCOMC__)\n#  define LZO_CC_WATCOMC        1\n#  define LZO_INFO_CC           \"Watcom C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__WATCOMC__)\n#elif defined(__TURBOC__)\n#  define LZO_CC_TURBOC         1\n#  define LZO_INFO_CC           \"Turbo C\"\n#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__TURBOC__)\n#elif defined(__ZTC__)\n#  define LZO_CC_ZORTECHC       1\n#  define LZO_INFO_CC           \"Zortech C\"\n#  if ((__ZTC__-0) == 0x310)\n#    define LZO_INFO_CCVER      \"0x310\"\n#  else\n#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__ZTC__)\n#  endif\n#elif defined(__GNUC__) && defined(__VERSION__)\n#  if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)\n#    define LZO_CC_GNUC         (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))\n#  elif defined(__GNUC_MINOR__)\n#    define LZO_CC_GNUC         (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100)\n#  else\n#    define LZO_CC_GNUC         (__GNUC__ * 0x10000L)\n#  endif\n#  define LZO_INFO_CC           \"gcc\"\n#  define LZO_INFO_CCVER        __VERSION__\n#elif defined(_MSC_VER) && ((_MSC_VER-0) > 0)\n#  define LZO_CC_MSC            _MSC_VER\n#  define LZO_INFO_CC           \"Microsoft C\"\n#  if defined(_MSC_FULL_VER)\n#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(_MSC_VER) \".\" LZO_PP_MACRO_EXPAND(_MSC_FULL_VER)\n#  else\n#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(_MSC_VER)\n#  endif\n#else\n#  define LZO_CC_UNKNOWN        1\n#  define LZO_INFO_CC           \"unknown\"\n#  define LZO_INFO_CCVER        \"unknown\"\n#endif\n#if (LZO_CC_GNUC) && defined(__OPEN64__)\n#  if defined(__OPENCC__) && defined(__OPENCC_MINOR__) && defined(__OPENCC_PATCHLEVEL__)\n#    define LZO_CC_OPEN64       (__OPENCC__ * 0x10000L + (__OPENCC_MINOR__-0) * 0x100 + (__OPENCC_PATCHLEVEL__-0))\n#    define LZO_CC_OPEN64_GNUC  LZO_CC_GNUC\n#  endif\n#endif\n#if (LZO_CC_GNUC) && defined(__PCC__)\n#  if defined(__PCC__) && defined(__PCC_MINOR__) && defined(__PCC_MINORMINOR__)\n#    define LZO_CC_PCC          (__PCC__ * 0x10000L + (__PCC_MINOR__-0) * 0x100 + (__PCC_MINORMINOR__-0))\n#    define LZO_CC_PCC_GNUC     LZO_CC_GNUC\n#  endif\n#endif\n#if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER)\n#  error \"LZO_CC_MSC: _MSC_FULL_VER is not defined\"\n#endif\n#if !defined(__LZO_ARCH_OVERRIDE) && !(LZO_ARCH_GENERIC) && defined(_CRAY)\n#  if (UINT_MAX > LZO_0xffffffffL) && defined(_CRAY)\n#    if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E)\n#      define LZO_ARCH_CRAY_MPP     1\n#    elif defined(_CRAY1)\n#      define LZO_ARCH_CRAY_PVP     1\n#    endif\n#  endif\n#endif\n#if !defined(__LZO_ARCH_OVERRIDE)\n#if (LZO_ARCH_GENERIC)\n#  define LZO_INFO_ARCH             \"generic\"\n#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)\n#  define LZO_ARCH_I086             1\n#  define LZO_INFO_ARCH             \"i086\"\n#elif defined(__aarch64__)\n#  define LZO_ARCH_ARM64            1\n#  define LZO_INFO_ARCH             \"arm64\"\n#elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA)\n#  define LZO_ARCH_ALPHA            1\n#  define LZO_INFO_ARCH             \"alpha\"\n#elif (LZO_ARCH_CRAY_MPP) && (defined(_CRAYT3D) || defined(_CRAYT3E))\n#  define LZO_ARCH_ALPHA            1\n#  define LZO_INFO_ARCH             \"alpha\"\n#elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64)\n#  define LZO_ARCH_AMD64            1\n#  define LZO_INFO_ARCH             \"amd64\"\n#elif defined(__arm__) || defined(_M_ARM)\n#  define LZO_ARCH_ARM              1\n#  define LZO_INFO_ARCH             \"arm\"\n#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__)\n#  define LZO_ARCH_ARM              1\n#  define LZO_INFO_ARCH             \"arm\"\n#elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__)\n#  define LZO_ARCH_AVR              1\n#  define LZO_INFO_ARCH             \"avr\"\n#elif defined(__avr32__) || defined(__AVR32__)\n#  define LZO_ARCH_AVR32            1\n#  define LZO_INFO_ARCH             \"avr32\"\n#elif defined(__bfin__)\n#  define LZO_ARCH_BLACKFIN         1\n#  define LZO_INFO_ARCH             \"blackfin\"\n#elif (UINT_MAX == LZO_0xffffL) && defined(__C166__)\n#  define LZO_ARCH_C166             1\n#  define LZO_INFO_ARCH             \"c166\"\n#elif defined(__cris__)\n#  define LZO_ARCH_CRIS             1\n#  define LZO_INFO_ARCH             \"cris\"\n#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCEZ80__)\n#  define LZO_ARCH_EZ80             1\n#  define LZO_INFO_ARCH             \"ez80\"\n#elif defined(__H8300__) || defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)\n#  define LZO_ARCH_H8300            1\n#  define LZO_INFO_ARCH             \"h8300\"\n#elif defined(__hppa__) || defined(__hppa)\n#  define LZO_ARCH_HPPA             1\n#  define LZO_INFO_ARCH             \"hppa\"\n#elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386)\n#  define LZO_ARCH_I386             1\n#  define LZO_ARCH_IA32             1\n#  define LZO_INFO_ARCH             \"i386\"\n#elif (LZO_CC_ZORTECHC && defined(__I86__))\n#  define LZO_ARCH_I386             1\n#  define LZO_ARCH_IA32             1\n#  define LZO_INFO_ARCH             \"i386\"\n#elif (LZO_OS_DOS32 && LZO_CC_HIGHC) && defined(_I386)\n#  define LZO_ARCH_I386             1\n#  define LZO_ARCH_IA32             1\n#  define LZO_INFO_ARCH             \"i386\"\n#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64)\n#  define LZO_ARCH_IA64             1\n#  define LZO_INFO_ARCH             \"ia64\"\n#elif (UINT_MAX == LZO_0xffffL) && defined(__m32c__)\n#  define LZO_ARCH_M16C             1\n#  define LZO_INFO_ARCH             \"m16c\"\n#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCM16C__)\n#  define LZO_ARCH_M16C             1\n#  define LZO_INFO_ARCH             \"m16c\"\n#elif defined(__m32r__)\n#  define LZO_ARCH_M32R             1\n#  define LZO_INFO_ARCH             \"m32r\"\n#elif (LZO_OS_TOS) || defined(__m68k__) || defined(__m68000__) || defined(__mc68000__) || defined(__mc68020__) || defined(_M_M68K)\n#  define LZO_ARCH_M68K             1\n#  define LZO_INFO_ARCH             \"m68k\"\n#elif (UINT_MAX == LZO_0xffffL) && defined(__C251__)\n#  define LZO_ARCH_MCS251           1\n#  define LZO_INFO_ARCH             \"mcs251\"\n#elif (UINT_MAX == LZO_0xffffL) && defined(__C51__)\n#  define LZO_ARCH_MCS51            1\n#  define LZO_INFO_ARCH             \"mcs51\"\n#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC8051__)\n#  define LZO_ARCH_MCS51            1\n#  define LZO_INFO_ARCH             \"mcs51\"\n#elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000)\n#  define LZO_ARCH_MIPS             1\n#  define LZO_INFO_ARCH             \"mips\"\n#elif (UINT_MAX == LZO_0xffffL) && defined(__MSP430__)\n#  define LZO_ARCH_MSP430           1\n#  define LZO_INFO_ARCH             \"msp430\"\n#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC430__)\n#  define LZO_ARCH_MSP430           1\n#  define LZO_INFO_ARCH             \"msp430\"\n#elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR)\n#  define LZO_ARCH_POWERPC          1\n#  define LZO_INFO_ARCH             \"powerpc\"\n#elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x)\n#  define LZO_ARCH_S390             1\n#  define LZO_INFO_ARCH             \"s390\"\n#elif defined(__sh__) || defined(_M_SH)\n#  define LZO_ARCH_SH               1\n#  define LZO_INFO_ARCH             \"sh\"\n#elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8)\n#  define LZO_ARCH_SPARC            1\n#  define LZO_INFO_ARCH             \"sparc\"\n#elif defined(__SPU__)\n#  define LZO_ARCH_SPU              1\n#  define LZO_INFO_ARCH             \"spu\"\n#elif (UINT_MAX == LZO_0xffffL) && defined(__z80)\n#  define LZO_ARCH_Z80              1\n#  define LZO_INFO_ARCH             \"z80\"\n#elif (LZO_ARCH_CRAY_PVP)\n#  if defined(_CRAYSV1)\n#    define LZO_ARCH_CRAY_SV1       1\n#    define LZO_INFO_ARCH           \"cray_sv1\"\n#  elif (_ADDR64)\n#    define LZO_ARCH_CRAY_T90       1\n#    define LZO_INFO_ARCH           \"cray_t90\"\n#  elif (_ADDR32)\n#    define LZO_ARCH_CRAY_YMP       1\n#    define LZO_INFO_ARCH           \"cray_ymp\"\n#  else\n#    define LZO_ARCH_CRAY_XMP       1\n#    define LZO_INFO_ARCH           \"cray_xmp\"\n#  endif\n#else\n#  define LZO_ARCH_UNKNOWN          1\n#  define LZO_INFO_ARCH             \"unknown\"\n#endif\n#endif\n#if !defined(LZO_ARCH_ARM_THUMB2)\n#if (LZO_ARCH_ARM)\n#  if defined(__ARM_ARCH_ISA_THUMB)\n#   if ((__ARM_ARCH_ISA_THUMB)+0 >= 2)\n#    define LZO_ARCH_ARM_THUMB2     1\n#   endif\n#  elif 1 && defined(__thumb2__)\n#    define LZO_ARCH_ARM_THUMB2     1\n#  elif 1 && defined(__TARGET_ARCH_THUMB) && ((__TARGET_ARCH_THUMB)+0 >= 4)\n#    define LZO_ARCH_ARM_THUMB2     1\n#  endif\n#endif\n#endif\n#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_DOS32 || LZO_OS_OS2)\n#  error \"FIXME - missing define for CPU architecture\"\n#endif\n#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN32)\n#  error \"FIXME - missing LZO_OS_WIN32 define for CPU architecture\"\n#endif\n#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN64)\n#  error \"FIXME - missing LZO_OS_WIN64 define for CPU architecture\"\n#endif\n#if (LZO_OS_OS216 || LZO_OS_WIN16)\n#  define LZO_ARCH_I086PM           1\n#elif 1 && (LZO_OS_DOS16 && defined(BLX286))\n#  define LZO_ARCH_I086PM           1\n#elif 1 && (LZO_OS_DOS16 && defined(DOSX286))\n#  define LZO_ARCH_I086PM           1\n#elif 1 && (LZO_OS_DOS16 && LZO_CC_BORLANDC && defined(__DPMI16__))\n#  define LZO_ARCH_I086PM           1\n#endif\n#if (LZO_ARCH_AMD64 && !LZO_ARCH_X64)\n#  define LZO_ARCH_X64              1\n#elif (!LZO_ARCH_AMD64 && LZO_ARCH_X64) && defined(__LZO_ARCH_OVERRIDE)\n#  define LZO_ARCH_AMD64            1\n#endif\n#if (LZO_ARCH_ARM64 && !LZO_ARCH_AARCH64)\n#  define LZO_ARCH_AARCH64          1\n#elif (!LZO_ARCH_ARM64 && LZO_ARCH_AARCH64) && defined(__LZO_ARCH_OVERRIDE)\n#  define LZO_ARCH_ARM64            1\n#endif\n#if (LZO_ARCH_I386 && !LZO_ARCH_X86)\n#  define LZO_ARCH_X86              1\n#elif (!LZO_ARCH_I386 && LZO_ARCH_X86) && defined(__LZO_ARCH_OVERRIDE)\n#  define LZO_ARCH_I386            1\n#endif\n#if (LZO_ARCH_AMD64 && !LZO_ARCH_X64) || (!LZO_ARCH_AMD64 && LZO_ARCH_X64)\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if (LZO_ARCH_ARM64 && !LZO_ARCH_AARCH64) || (!LZO_ARCH_ARM64 && LZO_ARCH_AARCH64)\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if (LZO_ARCH_I386 && !LZO_ARCH_X86) || (!LZO_ARCH_I386 && LZO_ARCH_X86)\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if (LZO_ARCH_ARM_THUMB1 && !LZO_ARCH_ARM)\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if (LZO_ARCH_ARM_THUMB2 && !LZO_ARCH_ARM)\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if (LZO_ARCH_ARM_THUMB1 && LZO_ARCH_ARM_THUMB2)\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if (LZO_ARCH_I086PM && !LZO_ARCH_I086)\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if (LZO_ARCH_I086)\n#  if (UINT_MAX != LZO_0xffffL)\n#    error \"unexpected configuration - check your compiler defines\"\n#  endif\n#  if (ULONG_MAX != LZO_0xffffffffL)\n#    error \"unexpected configuration - check your compiler defines\"\n#  endif\n#endif\n#if (LZO_ARCH_I386)\n#  if (UINT_MAX != LZO_0xffffL) && defined(__i386_int16__)\n#    error \"unexpected configuration - check your compiler defines\"\n#  endif\n#  if (UINT_MAX != LZO_0xffffffffL) && !defined(__i386_int16__)\n#    error \"unexpected configuration - check your compiler defines\"\n#  endif\n#  if (ULONG_MAX != LZO_0xffffffffL)\n#    error \"unexpected configuration - check your compiler defines\"\n#  endif\n#endif\n#if (LZO_ARCH_AMD64 || LZO_ARCH_I386)\n#  if !defined(LZO_TARGET_FEATURE_SSE2)\n#    if defined(__SSE2__)\n#      define LZO_TARGET_FEATURE_SSE2       1\n#    elif defined(_MSC_VER) && (defined(_M_IX86_FP) && ((_M_IX86_FP)+0 >= 2))\n#      define LZO_TARGET_FEATURE_SSE2       1\n#    elif (LZO_CC_INTELC_MSC || LZO_CC_MSC) && defined(_M_AMD64)\n#      define LZO_TARGET_FEATURE_SSE2       1\n#    endif\n#  endif\n#  if !defined(LZO_TARGET_FEATURE_SSSE3)\n#  if (LZO_TARGET_FEATURE_SSE2)\n#    if defined(__SSSE3__)\n#      define LZO_TARGET_FEATURE_SSSE3      1\n#    elif defined(_MSC_VER) && defined(__AVX__)\n#      define LZO_TARGET_FEATURE_SSSE3      1\n#    endif\n#  endif\n#  endif\n#  if !defined(LZO_TARGET_FEATURE_SSE4_2)\n#  if (LZO_TARGET_FEATURE_SSSE3)\n#    if defined(__SSE4_2__)\n#      define LZO_TARGET_FEATURE_SSE4_2     1\n#    endif\n#  endif\n#  endif\n#  if !defined(LZO_TARGET_FEATURE_AVX)\n#  if (LZO_TARGET_FEATURE_SSSE3)\n#    if defined(__AVX__)\n#      define LZO_TARGET_FEATURE_AVX        1\n#    endif\n#  endif\n#  endif\n#  if !defined(LZO_TARGET_FEATURE_AVX2)\n#  if (LZO_TARGET_FEATURE_AVX)\n#    if defined(__AVX2__)\n#      define LZO_TARGET_FEATURE_AVX2       1\n#    endif\n#  endif\n#  endif\n#endif\n#if (LZO_TARGET_FEATURE_SSSE3 && !(LZO_TARGET_FEATURE_SSE2))\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if (LZO_TARGET_FEATURE_SSE4_2 && !(LZO_TARGET_FEATURE_SSSE3))\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if (LZO_TARGET_FEATURE_AVX && !(LZO_TARGET_FEATURE_SSSE3))\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if (LZO_TARGET_FEATURE_AVX2 && !(LZO_TARGET_FEATURE_AVX))\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if (LZO_ARCH_ARM)\n#  if !defined(LZO_TARGET_FEATURE_NEON)\n#    if defined(__ARM_NEON) && ((__ARM_NEON)+0)\n#      define LZO_TARGET_FEATURE_NEON       1\n#    elif 1 && defined(__ARM_NEON__) && ((__ARM_NEON__)+0)\n#      define LZO_TARGET_FEATURE_NEON       1\n#    elif 1 && defined(__TARGET_FEATURE_NEON) && ((__TARGET_FEATURE_NEON)+0)\n#      define LZO_TARGET_FEATURE_NEON       1\n#    endif\n#  endif\n#elif (LZO_ARCH_ARM64)\n#  if !defined(LZO_TARGET_FEATURE_NEON)\n#    if 1\n#      define LZO_TARGET_FEATURE_NEON       1\n#    endif\n#  endif\n#endif\n#if 0\n#elif !defined(__LZO_MM_OVERRIDE)\n#if (LZO_ARCH_I086)\n#if (UINT_MAX != LZO_0xffffL)\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if defined(__TINY__) || defined(M_I86TM) || defined(_M_I86TM)\n#  define LZO_MM_TINY           1\n#elif defined(__HUGE__) || defined(_HUGE_) || defined(M_I86HM) || defined(_M_I86HM)\n#  define LZO_MM_HUGE           1\n#elif defined(__SMALL__) || defined(M_I86SM) || defined(_M_I86SM) || defined(SMALL_MODEL)\n#  define LZO_MM_SMALL          1\n#elif defined(__MEDIUM__) || defined(M_I86MM) || defined(_M_I86MM)\n#  define LZO_MM_MEDIUM         1\n#elif defined(__COMPACT__) || defined(M_I86CM) || defined(_M_I86CM)\n#  define LZO_MM_COMPACT        1\n#elif defined(__LARGE__) || defined(M_I86LM) || defined(_M_I86LM) || defined(LARGE_MODEL)\n#  define LZO_MM_LARGE          1\n#elif (LZO_CC_AZTECC)\n#  if defined(_LARGE_CODE) && defined(_LARGE_DATA)\n#    define LZO_MM_LARGE        1\n#  elif defined(_LARGE_CODE)\n#    define LZO_MM_MEDIUM       1\n#  elif defined(_LARGE_DATA)\n#    define LZO_MM_COMPACT      1\n#  else\n#    define LZO_MM_SMALL        1\n#  endif\n#elif (LZO_CC_ZORTECHC && defined(__VCM__))\n#  define LZO_MM_LARGE          1\n#else\n#  error \"unknown LZO_ARCH_I086 memory model\"\n#endif\n#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)\n#define LZO_HAVE_MM_HUGE_PTR        1\n#define LZO_HAVE_MM_HUGE_ARRAY      1\n#if (LZO_MM_TINY)\n#  undef LZO_HAVE_MM_HUGE_ARRAY\n#endif\n#if (LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_ZORTECHC)\n#  undef LZO_HAVE_MM_HUGE_PTR\n#  undef LZO_HAVE_MM_HUGE_ARRAY\n#elif (LZO_CC_DMC || LZO_CC_SYMANTECC)\n#  undef LZO_HAVE_MM_HUGE_ARRAY\n#elif (LZO_CC_MSC && defined(_QC))\n#  undef LZO_HAVE_MM_HUGE_ARRAY\n#  if (_MSC_VER < 600)\n#    undef LZO_HAVE_MM_HUGE_PTR\n#  endif\n#elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295))\n#  undef LZO_HAVE_MM_HUGE_ARRAY\n#endif\n#if (LZO_ARCH_I086PM) && !(LZO_HAVE_MM_HUGE_PTR)\n#  if (LZO_OS_DOS16)\n#    error \"unexpected configuration - check your compiler defines\"\n#  elif (LZO_CC_ZORTECHC)\n#  else\n#    error \"unexpected configuration - check your compiler defines\"\n#  endif\n#endif\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n#if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0200))\n   extern void __near __cdecl _AHSHIFT(void);\n#  define LZO_MM_AHSHIFT      ((unsigned) _AHSHIFT)\n#elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)\n   extern void __near __cdecl _AHSHIFT(void);\n#  define LZO_MM_AHSHIFT      ((unsigned) _AHSHIFT)\n#elif (LZO_CC_MSC || LZO_CC_TOPSPEEDC)\n   extern void __near __cdecl _AHSHIFT(void);\n#  define LZO_MM_AHSHIFT      ((unsigned) _AHSHIFT)\n#elif (LZO_CC_TURBOC && (__TURBOC__ >= 0x0295))\n   extern void __near __cdecl _AHSHIFT(void);\n#  define LZO_MM_AHSHIFT      ((unsigned) _AHSHIFT)\n#elif ((LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_TURBOC) && LZO_OS_DOS16)\n#  define LZO_MM_AHSHIFT      12\n#elif (LZO_CC_WATCOMC)\n   extern unsigned char _HShift;\n#  define LZO_MM_AHSHIFT      ((unsigned) _HShift)\n#else\n#  error \"FIXME - implement LZO_MM_AHSHIFT\"\n#endif\n#ifdef __cplusplus\n}\n#endif\n#endif\n#elif (LZO_ARCH_C166)\n#if !defined(__MODEL__)\n#  error \"FIXME - LZO_ARCH_C166 __MODEL__\"\n#elif ((__MODEL__) == 0)\n#  define LZO_MM_SMALL          1\n#elif ((__MODEL__) == 1)\n#  define LZO_MM_SMALL          1\n#elif ((__MODEL__) == 2)\n#  define LZO_MM_LARGE          1\n#elif ((__MODEL__) == 3)\n#  define LZO_MM_TINY           1\n#elif ((__MODEL__) == 4)\n#  define LZO_MM_XTINY          1\n#elif ((__MODEL__) == 5)\n#  define LZO_MM_XSMALL         1\n#else\n#  error \"FIXME - LZO_ARCH_C166 __MODEL__\"\n#endif\n#elif (LZO_ARCH_MCS251)\n#if !defined(__MODEL__)\n#  error \"FIXME - LZO_ARCH_MCS251 __MODEL__\"\n#elif ((__MODEL__) == 0)\n#  define LZO_MM_SMALL          1\n#elif ((__MODEL__) == 2)\n#  define LZO_MM_LARGE          1\n#elif ((__MODEL__) == 3)\n#  define LZO_MM_TINY           1\n#elif ((__MODEL__) == 4)\n#  define LZO_MM_XTINY          1\n#elif ((__MODEL__) == 5)\n#  define LZO_MM_XSMALL         1\n#else\n#  error \"FIXME - LZO_ARCH_MCS251 __MODEL__\"\n#endif\n#elif (LZO_ARCH_MCS51)\n#if !defined(__MODEL__)\n#  error \"FIXME - LZO_ARCH_MCS51 __MODEL__\"\n#elif ((__MODEL__) == 1)\n#  define LZO_MM_SMALL          1\n#elif ((__MODEL__) == 2)\n#  define LZO_MM_LARGE          1\n#elif ((__MODEL__) == 3)\n#  define LZO_MM_TINY           1\n#elif ((__MODEL__) == 4)\n#  define LZO_MM_XTINY          1\n#elif ((__MODEL__) == 5)\n#  define LZO_MM_XSMALL         1\n#else\n#  error \"FIXME - LZO_ARCH_MCS51 __MODEL__\"\n#endif\n#elif (LZO_ARCH_CRAY_PVP)\n#  define LZO_MM_PVP            1\n#else\n#  define LZO_MM_FLAT           1\n#endif\n#if (LZO_MM_COMPACT)\n#  define LZO_INFO_MM           \"compact\"\n#elif (LZO_MM_FLAT)\n#  define LZO_INFO_MM           \"flat\"\n#elif (LZO_MM_HUGE)\n#  define LZO_INFO_MM           \"huge\"\n#elif (LZO_MM_LARGE)\n#  define LZO_INFO_MM           \"large\"\n#elif (LZO_MM_MEDIUM)\n#  define LZO_INFO_MM           \"medium\"\n#elif (LZO_MM_PVP)\n#  define LZO_INFO_MM           \"pvp\"\n#elif (LZO_MM_SMALL)\n#  define LZO_INFO_MM           \"small\"\n#elif (LZO_MM_TINY)\n#  define LZO_INFO_MM           \"tiny\"\n#else\n#  error \"unknown memory model\"\n#endif\n#endif\n#if !defined(__lzo_gnuc_extension__)\n#if (LZO_CC_GNUC >= 0x020800ul)\n#  define __lzo_gnuc_extension__    __extension__\n#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#  define __lzo_gnuc_extension__    __extension__\n#elif (LZO_CC_IBMC >= 600)\n#  define __lzo_gnuc_extension__    __extension__\n#else\n#endif\n#endif\n#if !defined(__lzo_gnuc_extension__)\n#  define __lzo_gnuc_extension__    /*empty*/\n#endif\n#if !defined(lzo_has_builtin)\n#if (LZO_CC_CLANG) && defined(__has_builtin)\n#  define lzo_has_builtin           __has_builtin\n#endif\n#endif\n#if !defined(lzo_has_builtin)\n#  define lzo_has_builtin(x)        0\n#endif\n#if !defined(lzo_has_attribute)\n#if (LZO_CC_CLANG) && defined(__has_attribute)\n#  define lzo_has_attribute         __has_attribute\n#endif\n#endif\n#if !defined(lzo_has_attribute)\n#  define lzo_has_attribute(x)      0\n#endif\n#if !defined(lzo_has_declspec_attribute)\n#if (LZO_CC_CLANG) && defined(__has_declspec_attribute)\n#  define lzo_has_declspec_attribute        __has_declspec_attribute\n#endif\n#endif\n#if !defined(lzo_has_declspec_attribute)\n#  define lzo_has_declspec_attribute(x)     0\n#endif\n#if !defined(lzo_has_feature)\n#if (LZO_CC_CLANG) && defined(__has_feature)\n#  define lzo_has_feature         __has_feature\n#endif\n#endif\n#if !defined(lzo_has_feature)\n#  define lzo_has_feature(x)        0\n#endif\n#if !defined(lzo_has_extension)\n#if (LZO_CC_CLANG) && defined(__has_extension)\n#  define lzo_has_extension         __has_extension\n#elif (LZO_CC_CLANG) && defined(__has_feature)\n#  define lzo_has_extension         __has_feature\n#endif\n#endif\n#if !defined(lzo_has_extension)\n#  define lzo_has_extension         0\n#endif\n#if !defined(LZO_CFG_USE_NEW_STYLE_CASTS) && defined(__cplusplus) && 0\n#  if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020800ul))\n#    define LZO_CFG_USE_NEW_STYLE_CASTS 0\n#  elif (LZO_CC_INTELC && (__INTEL_COMPILER < 1200))\n#    define LZO_CFG_USE_NEW_STYLE_CASTS 0\n#  else\n#    define LZO_CFG_USE_NEW_STYLE_CASTS 1\n#  endif\n#endif\n#if !defined(LZO_CFG_USE_NEW_STYLE_CASTS)\n#  define LZO_CFG_USE_NEW_STYLE_CASTS 0\n#endif\n#if !defined(__cplusplus)\n#  if defined(LZO_CFG_USE_NEW_STYLE_CASTS)\n#    undef LZO_CFG_USE_NEW_STYLE_CASTS\n#  endif\n#  define LZO_CFG_USE_NEW_STYLE_CASTS 0\n#endif\n#if !defined(LZO_REINTERPRET_CAST)\n#  if (LZO_CFG_USE_NEW_STYLE_CASTS)\n#    define LZO_REINTERPRET_CAST(t,e)       (reinterpret_cast<t> (e))\n#  endif\n#endif\n#if !defined(LZO_REINTERPRET_CAST)\n#  define LZO_REINTERPRET_CAST(t,e)         ((t) (e))\n#endif\n#if !defined(LZO_STATIC_CAST)\n#  if (LZO_CFG_USE_NEW_STYLE_CASTS)\n#    define LZO_STATIC_CAST(t,e)            (static_cast<t> (e))\n#  endif\n#endif\n#if !defined(LZO_STATIC_CAST)\n#  define LZO_STATIC_CAST(t,e)              ((t) (e))\n#endif\n#if !defined(LZO_STATIC_CAST2)\n#  define LZO_STATIC_CAST2(t1,t2,e)         LZO_STATIC_CAST(t1, LZO_STATIC_CAST(t2, e))\n#endif\n#if !defined(LZO_UNCONST_CAST)\n#  if (LZO_CFG_USE_NEW_STYLE_CASTS)\n#    define LZO_UNCONST_CAST(t,e)           (const_cast<t> (e))\n#  elif (LZO_HAVE_MM_HUGE_PTR)\n#    define LZO_UNCONST_CAST(t,e)           ((t) (e))\n#  elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#    define LZO_UNCONST_CAST(t,e)           ((t) ((void *) ((lzo_uintptr_t) ((const void *) (e)))))\n#  endif\n#endif\n#if !defined(LZO_UNCONST_CAST)\n#  define LZO_UNCONST_CAST(t,e)             ((t) ((void *) ((const void *) (e))))\n#endif\n#if !defined(LZO_UNCONST_VOLATILE_CAST)\n#  if (LZO_CFG_USE_NEW_STYLE_CASTS)\n#    define LZO_UNCONST_VOLATILE_CAST(t,e)  (const_cast<t> (e))\n#  elif (LZO_HAVE_MM_HUGE_PTR)\n#    define LZO_UNCONST_VOLATILE_CAST(t,e)  ((t) (e))\n#  elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#    define LZO_UNCONST_VOLATILE_CAST(t,e)  ((t) ((volatile void *) ((lzo_uintptr_t) ((volatile const void *) (e)))))\n#  endif\n#endif\n#if !defined(LZO_UNCONST_VOLATILE_CAST)\n#  define LZO_UNCONST_VOLATILE_CAST(t,e)    ((t) ((volatile void *) ((volatile const void *) (e))))\n#endif\n#if !defined(LZO_UNVOLATILE_CAST)\n#  if (LZO_CFG_USE_NEW_STYLE_CASTS)\n#    define LZO_UNVOLATILE_CAST(t,e)        (const_cast<t> (e))\n#  elif (LZO_HAVE_MM_HUGE_PTR)\n#    define LZO_UNVOLATILE_CAST(t,e)        ((t) (e))\n#  elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#    define LZO_UNVOLATILE_CAST(t,e)        ((t) ((void *) ((lzo_uintptr_t) ((volatile void *) (e)))))\n#  endif\n#endif\n#if !defined(LZO_UNVOLATILE_CAST)\n#  define LZO_UNVOLATILE_CAST(t,e)          ((t) ((void *) ((volatile void *) (e))))\n#endif\n#if !defined(LZO_UNVOLATILE_CONST_CAST)\n#  if (LZO_CFG_USE_NEW_STYLE_CASTS)\n#    define LZO_UNVOLATILE_CONST_CAST(t,e)  (const_cast<t> (e))\n#  elif (LZO_HAVE_MM_HUGE_PTR)\n#    define LZO_UNVOLATILE_CONST_CAST(t,e)  ((t) (e))\n#  elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#    define LZO_UNVOLATILE_CONST_CAST(t,e)  ((t) ((const void *) ((lzo_uintptr_t) ((volatile const void *) (e)))))\n#  endif\n#endif\n#if !defined(LZO_UNVOLATILE_CONST_CAST)\n#  define LZO_UNVOLATILE_CONST_CAST(t,e)    ((t) ((const void *) ((volatile const void *) (e))))\n#endif\n#if !defined(LZO_PCAST)\n#  if (LZO_HAVE_MM_HUGE_PTR)\n#    define LZO_PCAST(t,e)                  ((t) (e))\n#  endif\n#endif\n#if !defined(LZO_PCAST)\n#  define LZO_PCAST(t,e)                    LZO_STATIC_CAST(t, LZO_STATIC_CAST(void *, e))\n#endif\n#if !defined(LZO_CCAST)\n#  if (LZO_HAVE_MM_HUGE_PTR)\n#    define LZO_CCAST(t,e)                  ((t) (e))\n#  endif\n#endif\n#if !defined(LZO_CCAST)\n#  define LZO_CCAST(t,e)                    LZO_STATIC_CAST(t, LZO_STATIC_CAST(const void *, e))\n#endif\n#if !defined(LZO_ICONV)\n#  define LZO_ICONV(t,e)                    LZO_STATIC_CAST(t, e)\n#endif\n#if !defined(LZO_ICAST)\n#  define LZO_ICAST(t,e)                    LZO_STATIC_CAST(t, e)\n#endif\n#if !defined(LZO_ITRUNC)\n#  define LZO_ITRUNC(t,e)                   LZO_STATIC_CAST(t, e)\n#endif\n#if !defined(__lzo_cte)\n#  if (LZO_CC_MSC || LZO_CC_WATCOMC)\n#    define __lzo_cte(e)            ((void)0,(e))\n#  elif 1\n#    define __lzo_cte(e)            ((void)0,(e))\n#  endif\n#endif\n#if !defined(__lzo_cte)\n#  define __lzo_cte(e)              (e)\n#endif\n#if !defined(LZO_BLOCK_BEGIN)\n#  define LZO_BLOCK_BEGIN           do {\n#  define LZO_BLOCK_END             } while __lzo_cte(0)\n#endif\n#if !defined(LZO_UNUSED)\n#  if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600))\n#    define LZO_UNUSED(var)         ((void) &var)\n#  elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC)\n#    define LZO_UNUSED(var)         if (&var) ; else\n#  elif (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x030200ul))\n#    define LZO_UNUSED(var)         ((void) &var)\n#  elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#    define LZO_UNUSED(var)         ((void) var)\n#  elif (LZO_CC_MSC && (_MSC_VER < 900))\n#    define LZO_UNUSED(var)         if (&var) ; else\n#  elif (LZO_CC_KEILC)\n#    define LZO_UNUSED(var)         {extern int lzo_unused__[1-2*!(sizeof(var)>0)]; (void)lzo_unused__;}\n#  elif (LZO_CC_PACIFICC)\n#    define LZO_UNUSED(var)         ((void) sizeof(var))\n#  elif (LZO_CC_WATCOMC) && defined(__cplusplus)\n#    define LZO_UNUSED(var)         ((void) var)\n#  else\n#    define LZO_UNUSED(var)         ((void) &var)\n#  endif\n#endif\n#if !defined(LZO_UNUSED_FUNC)\n#  if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600))\n#    define LZO_UNUSED_FUNC(func)   ((void) func)\n#  elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC)\n#    define LZO_UNUSED_FUNC(func)   if (func) ; else\n#  elif (LZO_CC_CLANG || LZO_CC_LLVM)\n#    define LZO_UNUSED_FUNC(func)   ((void) &func)\n#  elif (LZO_CC_MSC && (_MSC_VER < 900))\n#    define LZO_UNUSED_FUNC(func)   if (func) ; else\n#  elif (LZO_CC_MSC)\n#    define LZO_UNUSED_FUNC(func)   ((void) &func)\n#  elif (LZO_CC_KEILC || LZO_CC_PELLESC)\n#    define LZO_UNUSED_FUNC(func)   {extern int lzo_unused__[1-2*!(sizeof((int)func)>0)]; (void)lzo_unused__;}\n#  else\n#    define LZO_UNUSED_FUNC(func)   ((void) func)\n#  endif\n#endif\n#if !defined(LZO_UNUSED_LABEL)\n#  if (LZO_CC_CLANG >= 0x020800ul)\n#    define LZO_UNUSED_LABEL(l)     (__lzo_gnuc_extension__ ((void) ((const void *) &&l)))\n#  elif (LZO_CC_ARMCC || LZO_CC_CLANG || LZO_CC_INTELC || LZO_CC_WATCOMC)\n#    define LZO_UNUSED_LABEL(l)     if __lzo_cte(0) goto l\n#  else\n#    define LZO_UNUSED_LABEL(l)     switch (0) case 1:goto l\n#  endif\n#endif\n#if !defined(LZO_DEFINE_UNINITIALIZED_VAR)\n#  if 0\n#    define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init)  type var\n#  elif 0 && (LZO_CC_GNUC)\n#    define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init)  type var = var\n#  else\n#    define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init)  type var = init\n#  endif\n#endif\n#if !defined(__lzo_inline)\n#if (LZO_CC_TURBOC && (__TURBOC__ <= 0x0295))\n#elif defined(__cplusplus)\n#  define __lzo_inline          inline\n#elif defined(__STDC_VERSION__) && (__STDC_VERSION__-0 >= 199901L)\n#  define __lzo_inline          inline\n#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550))\n#  define __lzo_inline          __inline\n#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)\n#  define __lzo_inline          __inline__\n#elif (LZO_CC_DMC)\n#  define __lzo_inline          __inline\n#elif (LZO_CC_GHS)\n#  define __lzo_inline          __inline__\n#elif (LZO_CC_IBMC >= 600)\n#  define __lzo_inline          __inline__\n#elif (LZO_CC_INTELC)\n#  define __lzo_inline          __inline\n#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x2405))\n#  define __lzo_inline          __inline\n#elif (LZO_CC_MSC && (_MSC_VER >= 900))\n#  define __lzo_inline          __inline\n#elif (LZO_CC_SUNPROC >= 0x5100)\n#  define __lzo_inline          __inline__\n#endif\n#endif\n#if defined(__lzo_inline)\n#  ifndef __lzo_HAVE_inline\n#  define __lzo_HAVE_inline 1\n#  endif\n#else\n#  define __lzo_inline          /*empty*/\n#endif\n#if !defined(__lzo_forceinline)\n#if (LZO_CC_GNUC >= 0x030200ul)\n#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))\n#elif (LZO_CC_IBMC >= 700)\n#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))\n#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 450))\n#  define __lzo_forceinline     __forceinline\n#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 800))\n#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))\n#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))\n#elif (LZO_CC_MSC && (_MSC_VER >= 1200))\n#  define __lzo_forceinline     __forceinline\n#elif (LZO_CC_PGI >= 0x0d0a00ul)\n#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))\n#elif (LZO_CC_SUNPROC >= 0x5100)\n#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))\n#endif\n#endif\n#if defined(__lzo_forceinline)\n#  ifndef __lzo_HAVE_forceinline\n#  define __lzo_HAVE_forceinline 1\n#  endif\n#else\n#  define __lzo_forceinline     __lzo_inline\n#endif\n#if !defined(__lzo_noinline)\n#if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul)\n#  define __lzo_noinline        __attribute__((__noinline__,__used__))\n#elif (LZO_CC_GNUC >= 0x030200ul)\n#  define __lzo_noinline        __attribute__((__noinline__))\n#elif (LZO_CC_IBMC >= 700)\n#  define __lzo_noinline        __attribute__((__noinline__))\n#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 600))\n#  define __lzo_noinline        __declspec(noinline)\n#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 800))\n#  define __lzo_noinline        __attribute__((__noinline__))\n#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#  define __lzo_noinline        __attribute__((__noinline__))\n#elif (LZO_CC_MSC && (_MSC_VER >= 1300))\n#  define __lzo_noinline        __declspec(noinline)\n#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x3200) && (LZO_OS_WIN32 || LZO_OS_WIN64))\n#  if defined(__cplusplus)\n#  else\n#    define __lzo_noinline      __declspec(noinline)\n#  endif\n#elif (LZO_CC_PGI >= 0x0d0a00ul)\n#  define __lzo_noinline        __attribute__((__noinline__))\n#elif (LZO_CC_SUNPROC >= 0x5100)\n#  define __lzo_noinline        __attribute__((__noinline__))\n#endif\n#endif\n#if defined(__lzo_noinline)\n#  ifndef __lzo_HAVE_noinline\n#  define __lzo_HAVE_noinline 1\n#  endif\n#else\n#  define __lzo_noinline        /*empty*/\n#endif\n#if (__lzo_HAVE_forceinline || __lzo_HAVE_noinline) && !(__lzo_HAVE_inline)\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if !defined(__lzo_static_inline)\n#if (LZO_CC_IBMC)\n#  define __lzo_static_inline       __lzo_gnuc_extension__ static __lzo_inline\n#endif\n#endif\n#if !defined(__lzo_static_inline)\n#  define __lzo_static_inline       static __lzo_inline\n#endif\n#if !defined(__lzo_static_forceinline)\n#if (LZO_CC_IBMC)\n#  define __lzo_static_forceinline  __lzo_gnuc_extension__ static __lzo_forceinline\n#endif\n#endif\n#if !defined(__lzo_static_forceinline)\n#  define __lzo_static_forceinline  static __lzo_forceinline\n#endif\n#if !defined(__lzo_static_noinline)\n#if (LZO_CC_IBMC)\n#  define __lzo_static_noinline     __lzo_gnuc_extension__ static __lzo_noinline\n#endif\n#endif\n#if !defined(__lzo_static_noinline)\n#  define __lzo_static_noinline     static __lzo_noinline\n#endif\n#if !defined(__lzo_c99_extern_inline)\n#if defined(__GNUC_GNU_INLINE__)\n#  define __lzo_c99_extern_inline   __lzo_inline\n#elif defined(__GNUC_STDC_INLINE__)\n#  define __lzo_c99_extern_inline   extern __lzo_inline\n#elif defined(__STDC_VERSION__) && (__STDC_VERSION__-0 >= 199901L)\n#  define __lzo_c99_extern_inline   extern __lzo_inline\n#endif\n#if !defined(__lzo_c99_extern_inline) && (__lzo_HAVE_inline)\n#  define __lzo_c99_extern_inline   __lzo_inline\n#endif\n#endif\n#if defined(__lzo_c99_extern_inline)\n#  ifndef __lzo_HAVE_c99_extern_inline\n#  define __lzo_HAVE_c99_extern_inline 1\n#  endif\n#else\n#  define __lzo_c99_extern_inline   /*empty*/\n#endif\n#if !defined(__lzo_may_alias)\n#if (LZO_CC_GNUC >= 0x030400ul)\n#  define __lzo_may_alias       __attribute__((__may_alias__))\n#elif (LZO_CC_CLANG >= 0x020900ul)\n#  define __lzo_may_alias       __attribute__((__may_alias__))\n#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 1210)) && 0\n#  define __lzo_may_alias       __attribute__((__may_alias__))\n#elif (LZO_CC_PGI >= 0x0d0a00ul) && 0\n#  define __lzo_may_alias       __attribute__((__may_alias__))\n#endif\n#endif\n#if defined(__lzo_may_alias)\n#  ifndef __lzo_HAVE_may_alias\n#  define __lzo_HAVE_may_alias 1\n#  endif\n#else\n#  define __lzo_may_alias       /*empty*/\n#endif\n#if !defined(__lzo_noreturn)\n#if (LZO_CC_GNUC >= 0x020700ul)\n#  define __lzo_noreturn        __attribute__((__noreturn__))\n#elif (LZO_CC_IBMC >= 700)\n#  define __lzo_noreturn        __attribute__((__noreturn__))\n#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 450))\n#  define __lzo_noreturn        __declspec(noreturn)\n#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 600))\n#  define __lzo_noreturn        __attribute__((__noreturn__))\n#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#  define __lzo_noreturn        __attribute__((__noreturn__))\n#elif (LZO_CC_MSC && (_MSC_VER >= 1200))\n#  define __lzo_noreturn        __declspec(noreturn)\n#elif (LZO_CC_PGI >= 0x0d0a00ul)\n#  define __lzo_noreturn        __attribute__((__noreturn__))\n#endif\n#endif\n#if defined(__lzo_noreturn)\n#  ifndef __lzo_HAVE_noreturn\n#  define __lzo_HAVE_noreturn 1\n#  endif\n#else\n#  define __lzo_noreturn        /*empty*/\n#endif\n#if !defined(__lzo_nothrow)\n#if (LZO_CC_GNUC >= 0x030300ul)\n#  define __lzo_nothrow         __attribute__((__nothrow__))\n#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 450)) && defined(__cplusplus)\n#  define __lzo_nothrow         __declspec(nothrow)\n#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 900))\n#  define __lzo_nothrow         __attribute__((__nothrow__))\n#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#  define __lzo_nothrow         __attribute__((__nothrow__))\n#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus)\n#  define __lzo_nothrow         __declspec(nothrow)\n#endif\n#endif\n#if defined(__lzo_nothrow)\n#  ifndef __lzo_HAVE_nothrow\n#  define __lzo_HAVE_nothrow 1\n#  endif\n#else\n#  define __lzo_nothrow         /*empty*/\n#endif\n#if !defined(__lzo_restrict)\n#if (LZO_CC_GNUC >= 0x030400ul)\n#  define __lzo_restrict        __restrict__\n#elif (LZO_CC_IBMC >= 800) && !defined(__cplusplus)\n#  define __lzo_restrict        __restrict__\n#elif (LZO_CC_IBMC >= 1210)\n#  define __lzo_restrict        __restrict__\n#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 600))\n#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 600))\n#  define __lzo_restrict        __restrict__\n#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM)\n#  define __lzo_restrict        __restrict__\n#elif (LZO_CC_MSC && (_MSC_VER >= 1400))\n#  define __lzo_restrict        __restrict\n#elif (LZO_CC_PGI >= 0x0d0a00ul)\n#  define __lzo_restrict        __restrict__\n#endif\n#endif\n#if defined(__lzo_restrict)\n#  ifndef __lzo_HAVE_restrict\n#  define __lzo_HAVE_restrict 1\n#  endif\n#else\n#  define __lzo_restrict        /*empty*/\n#endif\n#if !defined(__lzo_alignof)\n#if (LZO_CC_ARMCC || LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)\n#  define __lzo_alignof(e)      __alignof__(e)\n#elif (LZO_CC_GHS) && !defined(__cplusplus)\n#  define __lzo_alignof(e)      __alignof__(e)\n#elif (LZO_CC_IBMC >= 600)\n#  define __lzo_alignof(e)      (__lzo_gnuc_extension__ __alignof__(e))\n#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700))\n#  define __lzo_alignof(e)      __alignof__(e)\n#elif (LZO_CC_MSC && (_MSC_VER >= 1300))\n#  define __lzo_alignof(e)      __alignof(e)\n#elif (LZO_CC_SUNPROC >= 0x5100)\n#  define __lzo_alignof(e)      __alignof__(e)\n#endif\n#endif\n#if defined(__lzo_alignof)\n#  ifndef __lzo_HAVE_alignof\n#  define __lzo_HAVE_alignof 1\n#  endif\n#endif\n#if !defined(__lzo_struct_packed)\n#if   (LZO_CC_CLANG && (LZO_CC_CLANG < 0x020800ul)) && defined(__cplusplus)\n#elif (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020700ul))\n#elif (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020800ul)) && defined(__cplusplus)\n#elif (LZO_CC_PCC && (LZO_CC_PCC < 0x010100ul))\n#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC < 0x5110)) && !defined(__cplusplus)\n#elif (LZO_CC_GNUC >= 0x030400ul) && !(LZO_CC_PCC_GNUC) && (LZO_ARCH_AMD64 || LZO_ARCH_I386)\n#  define __lzo_struct_packed(s)        struct s {\n#  define __lzo_struct_packed_end()     } __attribute__((__gcc_struct__,__packed__));\n#  define __lzo_struct_packed_ma_end()  } __lzo_may_alias __attribute__((__gcc_struct__,__packed__));\n#elif (LZO_CC_ARMCC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || (LZO_CC_PGI >= 0x0d0a00ul) || (LZO_CC_SUNPROC >= 0x5100))\n#  define __lzo_struct_packed(s)        struct s {\n#  define __lzo_struct_packed_end()     } __attribute__((__packed__));\n#  define __lzo_struct_packed_ma_end()  } __lzo_may_alias __attribute__((__packed__));\n#elif (LZO_CC_IBMC >= 700)\n#  define __lzo_struct_packed(s)        __lzo_gnuc_extension__ struct s {\n#  define __lzo_struct_packed_end()     } __attribute__((__packed__));\n#  define __lzo_struct_packed_ma_end()  } __lzo_may_alias __attribute__((__packed__));\n#elif (LZO_CC_INTELC_MSC) || (LZO_CC_MSC && (_MSC_VER >= 1300))\n#  define __lzo_struct_packed(s)        __pragma(pack(push,1)) struct s {\n#  define __lzo_struct_packed_end()     } __pragma(pack(pop));\n#elif (LZO_CC_WATCOMC && (__WATCOMC__ >= 900))\n#  define __lzo_struct_packed(s)        _Packed struct s {\n#  define __lzo_struct_packed_end()     };\n#endif\n#endif\n#if defined(__lzo_struct_packed) && !defined(__lzo_struct_packed_ma)\n#  define __lzo_struct_packed_ma(s)     __lzo_struct_packed(s)\n#endif\n#if defined(__lzo_struct_packed_end) && !defined(__lzo_struct_packed_ma_end)\n#  define __lzo_struct_packed_ma_end()  __lzo_struct_packed_end()\n#endif\n#if !defined(__lzo_byte_struct)\n#if defined(__lzo_struct_packed)\n#  define __lzo_byte_struct(s,n)        __lzo_struct_packed(s) unsigned char a[n]; __lzo_struct_packed_end()\n#  define __lzo_byte_struct_ma(s,n)     __lzo_struct_packed_ma(s) unsigned char a[n]; __lzo_struct_packed_ma_end()\n#elif (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_PGI || (LZO_CC_SUNPROC >= 0x5100))\n#  define __lzo_byte_struct(s,n)        struct s { unsigned char a[n]; } __attribute__((__packed__));\n#  define __lzo_byte_struct_ma(s,n)     struct s { unsigned char a[n]; } __lzo_may_alias __attribute__((__packed__));\n#endif\n#endif\n#if defined(__lzo_byte_struct) &&  !defined(__lzo_byte_struct_ma)\n#  define __lzo_byte_struct_ma(s,n)     __lzo_byte_struct(s,n)\n#endif\n#if !defined(__lzo_struct_align16) && (__lzo_HAVE_alignof)\n#if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x030000ul))\n#elif (LZO_CC_CLANG && (LZO_CC_CLANG < 0x020800ul)) && defined(__cplusplus)\n#elif (LZO_CC_CILLY || LZO_CC_PCC)\n#elif (LZO_CC_INTELC_MSC) || (LZO_CC_MSC && (_MSC_VER >= 1300))\n#  define __lzo_struct_align16(s)       struct __declspec(align(16)) s {\n#  define __lzo_struct_align16_end()    };\n#  define __lzo_struct_align32(s)       struct __declspec(align(32)) s {\n#  define __lzo_struct_align32_end()    };\n#  define __lzo_struct_align64(s)       struct __declspec(align(64)) s {\n#  define __lzo_struct_align64_end()    };\n#elif (LZO_CC_ARMCC || LZO_CC_CLANG || LZO_CC_GNUC || (LZO_CC_IBMC >= 700) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#  define __lzo_struct_align16(s)       struct s {\n#  define __lzo_struct_align16_end()    } __attribute__((__aligned__(16)));\n#  define __lzo_struct_align32(s)       struct s {\n#  define __lzo_struct_align32_end()    } __attribute__((__aligned__(32)));\n#  define __lzo_struct_align64(s)       struct s {\n#  define __lzo_struct_align64_end()    } __attribute__((__aligned__(64)));\n#endif\n#endif\n#if !defined(__lzo_union_um)\n#if   (LZO_CC_CLANG && (LZO_CC_CLANG < 0x020800ul)) && defined(__cplusplus)\n#elif (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020700ul))\n#elif (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020800ul)) && defined(__cplusplus)\n#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER < 810))\n#elif (LZO_CC_PCC && (LZO_CC_PCC < 0x010100ul))\n#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC < 0x5110)) && !defined(__cplusplus)\n#elif (LZO_CC_ARMCC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || (LZO_CC_PGI >= 0x0d0a00ul) || (LZO_CC_SUNPROC >= 0x5100))\n#  define __lzo_union_am(s)             union s {\n#  define __lzo_union_am_end()          } __lzo_may_alias;\n#  define __lzo_union_um(s)             union s {\n#  define __lzo_union_um_end()          } __lzo_may_alias __attribute__((__packed__));\n#elif (LZO_CC_IBMC >= 700)\n#  define __lzo_union_am(s)             __lzo_gnuc_extension__ union s {\n#  define __lzo_union_am_end()          } __lzo_may_alias;\n#  define __lzo_union_um(s)             __lzo_gnuc_extension__ union s {\n#  define __lzo_union_um_end()          } __lzo_may_alias __attribute__((__packed__));\n#elif (LZO_CC_INTELC_MSC) || (LZO_CC_MSC && (_MSC_VER >= 1300))\n#  define __lzo_union_um(s)             __pragma(pack(push,1)) union s {\n#  define __lzo_union_um_end()          } __pragma(pack(pop));\n#elif (LZO_CC_WATCOMC && (__WATCOMC__ >= 900))\n#  define __lzo_union_um(s)             _Packed union s {\n#  define __lzo_union_um_end()          };\n#endif\n#endif\n#if !defined(__lzo_union_am)\n#  define __lzo_union_am(s)             union s {\n#  define __lzo_union_am_end()          };\n#endif\n#if !defined(__lzo_constructor)\n#if (LZO_CC_GNUC >= 0x030400ul)\n#  define __lzo_constructor     __attribute__((__constructor__,__used__))\n#elif (LZO_CC_GNUC >= 0x020700ul)\n#  define __lzo_constructor     __attribute__((__constructor__))\n#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 800))\n#  define __lzo_constructor     __attribute__((__constructor__,__used__))\n#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#  define __lzo_constructor     __attribute__((__constructor__))\n#endif\n#endif\n#if defined(__lzo_constructor)\n#  ifndef __lzo_HAVE_constructor\n#  define __lzo_HAVE_constructor 1\n#  endif\n#endif\n#if !defined(__lzo_destructor)\n#if (LZO_CC_GNUC >= 0x030400ul)\n#  define __lzo_destructor      __attribute__((__destructor__,__used__))\n#elif (LZO_CC_GNUC >= 0x020700ul)\n#  define __lzo_destructor      __attribute__((__destructor__))\n#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 800))\n#  define __lzo_destructor      __attribute__((__destructor__,__used__))\n#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#  define __lzo_destructor      __attribute__((__destructor__))\n#endif\n#endif\n#if defined(__lzo_destructor)\n#  ifndef __lzo_HAVE_destructor\n#  define __lzo_HAVE_destructor 1\n#  endif\n#endif\n#if (__lzo_HAVE_destructor) && !(__lzo_HAVE_constructor)\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if !defined(__lzo_likely) && !defined(__lzo_unlikely)\n#if (LZO_CC_GNUC >= 0x030200ul)\n#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))\n#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))\n#elif (LZO_CC_IBMC >= 1010)\n#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))\n#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))\n#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800))\n#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))\n#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))\n#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))\n#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))\n#endif\n#endif\n#if defined(__lzo_likely)\n#  ifndef __lzo_HAVE_likely\n#  define __lzo_HAVE_likely 1\n#  endif\n#else\n#  define __lzo_likely(e)           (e)\n#endif\n#if defined(__lzo_very_likely)\n#  ifndef __lzo_HAVE_very_likely\n#  define __lzo_HAVE_very_likely 1\n#  endif\n#else\n#  define __lzo_very_likely(e)      __lzo_likely(e)\n#endif\n#if defined(__lzo_unlikely)\n#  ifndef __lzo_HAVE_unlikely\n#  define __lzo_HAVE_unlikely 1\n#  endif\n#else\n#  define __lzo_unlikely(e)         (e)\n#endif\n#if defined(__lzo_very_unlikely)\n#  ifndef __lzo_HAVE_very_unlikely\n#  define __lzo_HAVE_very_unlikely 1\n#  endif\n#else\n#  define __lzo_very_unlikely(e)    __lzo_unlikely(e)\n#endif\n#if !defined(__lzo_loop_forever)\n#  if (LZO_CC_IBMC)\n#    define __lzo_loop_forever()    LZO_BLOCK_BEGIN for (;;) { ; } LZO_BLOCK_END\n#  else\n#    define __lzo_loop_forever()    do { ; } while __lzo_cte(1)\n#  endif\n#endif\n#if !defined(__lzo_unreachable)\n#if (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x020800ul)) && lzo_has_builtin(__builtin_unreachable)\n#  define __lzo_unreachable()       __builtin_unreachable();\n#elif (LZO_CC_GNUC >= 0x040500ul)\n#  define __lzo_unreachable()       __builtin_unreachable();\n#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 1300)) && 1\n#  define __lzo_unreachable()       __builtin_unreachable();\n#endif\n#endif\n#if defined(__lzo_unreachable)\n#  ifndef __lzo_HAVE_unreachable\n#  define __lzo_HAVE_unreachable 1\n#  endif\n#else\n#  if 0\n#  define __lzo_unreachable()       ((void)0);\n#  else\n#  define __lzo_unreachable()       __lzo_loop_forever();\n#  endif\n#endif\n#if !defined(lzo_unused_funcs_impl)\n#  if 1 && (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)\n#    define lzo_unused_funcs_impl(r,f)  static r __attribute__((__unused__)) f\n#  elif 1 && (LZO_CC_BORLANDC || LZO_CC_GNUC)\n#    define lzo_unused_funcs_impl(r,f)  static r f\n#  else\n#    define lzo_unused_funcs_impl(r,f)  __lzo_static_forceinline r f\n#  endif\n#endif\n#ifndef __LZO_CTA_NAME\n#if (LZO_CFG_USE_COUNTER)\n#  define __LZO_CTA_NAME(a)         LZO_PP_ECONCAT2(a,__COUNTER__)\n#else\n#  define __LZO_CTA_NAME(a)         LZO_PP_ECONCAT2(a,__LINE__)\n#endif\n#endif\n#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER)\n#  if (LZO_CC_AZTECC || LZO_CC_ZORTECHC)\n#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  LZO_EXTERN_C_BEGIN extern int __LZO_CTA_NAME(lzo_cta__)[1-!(e)]; LZO_EXTERN_C_END\n#  elif (LZO_CC_DMC || LZO_CC_SYMANTECC)\n#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  LZO_EXTERN_C_BEGIN extern int __LZO_CTA_NAME(lzo_cta__)[1u-2*!(e)]; LZO_EXTERN_C_END\n#  elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295))\n#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  LZO_EXTERN_C_BEGIN extern int __LZO_CTA_NAME(lzo_cta__)[1-!(e)]; LZO_EXTERN_C_END\n#  elif (LZO_CC_CLANG && (LZO_CC_CLANG < 0x020900ul)) && defined(__cplusplus)\n#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  LZO_EXTERN_C_BEGIN int __LZO_CTA_NAME(lzo_cta_f__)(int [1-2*!(e)]); LZO_EXTERN_C_END\n#  elif (LZO_CC_GNUC) && defined(__CHECKER__) && defined(__SPARSE_CHECKER__)\n#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  LZO_EXTERN_C_BEGIN enum {__LZO_CTA_NAME(lzo_cta_e__)=1/!!(e)} __attribute__((__unused__)); LZO_EXTERN_C_END\n#  else\n#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  LZO_EXTERN_C_BEGIN extern int __LZO_CTA_NAME(lzo_cta__)[1-2*!(e)]; LZO_EXTERN_C_END\n#  endif\n#endif\n#if !defined(LZO_COMPILE_TIME_ASSERT)\n#  if (LZO_CC_AZTECC)\n#    define LZO_COMPILE_TIME_ASSERT(e)  {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-!(e)];}\n#  elif (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x030000ul))\n#    define LZO_COMPILE_TIME_ASSERT(e)  {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-2*!(e)] __attribute__((__unused__));}\n#  elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)\n#    define LZO_COMPILE_TIME_ASSERT(e)  switch(0) case 1:case !(e):break;\n#  elif (LZO_CC_GNUC) && defined(__CHECKER__) && defined(__SPARSE_CHECKER__)\n#    define LZO_COMPILE_TIME_ASSERT(e)  {(void) (0/!!(e));}\n#  elif (LZO_CC_GNUC >= 0x040700ul) && (LZO_CFG_USE_COUNTER) && defined(__cplusplus)\n#    define LZO_COMPILE_TIME_ASSERT(e)  {enum {__LZO_CTA_NAME(lzo_cta_e__)=1/!!(e)} __attribute__((__unused__));}\n#  elif (LZO_CC_GNUC >= 0x040700ul)\n#    define LZO_COMPILE_TIME_ASSERT(e)  {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-2*!(e)] __attribute__((__unused__));}\n#  elif (LZO_CC_MSC && (_MSC_VER < 900))\n#    define LZO_COMPILE_TIME_ASSERT(e)  switch(0) case 1:case !(e):break;\n#  elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295))\n#    define LZO_COMPILE_TIME_ASSERT(e)  switch(0) case 1:case !(e):break;\n#  else\n#    define LZO_COMPILE_TIME_ASSERT(e)  {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-2*!(e)];}\n#  endif\n#endif\nLZO_COMPILE_TIME_ASSERT_HEADER(1 == 1)\n#if defined(__cplusplus)\nextern \"C\" { LZO_COMPILE_TIME_ASSERT_HEADER(2 == 2) }\n#endif\nLZO_COMPILE_TIME_ASSERT_HEADER(3 == 3)\n#if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64)\n#  if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC)\n#  elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)\n#    define __lzo_cdecl                 __cdecl\n#    define __lzo_cdecl_atexit          /*empty*/\n#    define __lzo_cdecl_main            __cdecl\n#    if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC))\n#      define __lzo_cdecl_qsort         __pascal\n#    elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC))\n#      define __lzo_cdecl_qsort         _stdcall\n#    else\n#      define __lzo_cdecl_qsort         __cdecl\n#    endif\n#  elif (LZO_CC_WATCOMC)\n#    define __lzo_cdecl                 __cdecl\n#  else\n#    define __lzo_cdecl                 __cdecl\n#    define __lzo_cdecl_atexit          __cdecl\n#    define __lzo_cdecl_main            __cdecl\n#    define __lzo_cdecl_qsort           __cdecl\n#  endif\n#  if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC || LZO_CC_WATCOMC)\n#  elif (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC))\n#    define __lzo_cdecl_sighandler      __pascal\n#  elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC))\n#    define __lzo_cdecl_sighandler      _stdcall\n#  elif (LZO_CC_MSC && (_MSC_VER >= 1400)) && defined(_M_CEE_PURE)\n#    define __lzo_cdecl_sighandler      __clrcall\n#  elif (LZO_CC_MSC && (_MSC_VER >= 600 && _MSC_VER < 700))\n#    if defined(_DLL)\n#      define __lzo_cdecl_sighandler    _far _cdecl _loadds\n#    elif defined(_MT)\n#      define __lzo_cdecl_sighandler    _far _cdecl\n#    else\n#      define __lzo_cdecl_sighandler    _cdecl\n#    endif\n#  else\n#    define __lzo_cdecl_sighandler      __cdecl\n#  endif\n#elif (LZO_ARCH_I386) && (LZO_CC_WATCOMC)\n#  define __lzo_cdecl                   __cdecl\n#elif (LZO_ARCH_M68K && LZO_OS_TOS && (LZO_CC_PUREC || LZO_CC_TURBOC))\n#  define __lzo_cdecl                   cdecl\n#endif\n#if !defined(__lzo_cdecl)\n#  define __lzo_cdecl                   /*empty*/\n#endif\n#if !defined(__lzo_cdecl_atexit)\n#  define __lzo_cdecl_atexit            /*empty*/\n#endif\n#if !defined(__lzo_cdecl_main)\n#  define __lzo_cdecl_main              /*empty*/\n#endif\n#if !defined(__lzo_cdecl_qsort)\n#  define __lzo_cdecl_qsort             /*empty*/\n#endif\n#if !defined(__lzo_cdecl_sighandler)\n#  define __lzo_cdecl_sighandler        /*empty*/\n#endif\n#if !defined(__lzo_cdecl_va)\n#  define __lzo_cdecl_va                __lzo_cdecl\n#endif\n#if !(LZO_CFG_NO_WINDOWS_H)\n#if !defined(LZO_HAVE_WINDOWS_H)\n#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64)\n#  if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000))\n#  elif ((LZO_OS_WIN32 && defined(__PW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x030000ul)))\n#  elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul)))\n#  else\n#    define LZO_HAVE_WINDOWS_H 1\n#  endif\n#endif\n#endif\n#endif\n#ifndef LZO_SIZEOF_SHORT\n#if defined(SIZEOF_SHORT)\n#  define LZO_SIZEOF_SHORT          (SIZEOF_SHORT)\n#elif defined(__SIZEOF_SHORT__)\n#  define LZO_SIZEOF_SHORT          (__SIZEOF_SHORT__)\n#endif\n#endif\n#ifndef LZO_SIZEOF_INT\n#if defined(SIZEOF_INT)\n#  define LZO_SIZEOF_INT            (SIZEOF_INT)\n#elif defined(__SIZEOF_INT__)\n#  define LZO_SIZEOF_INT            (__SIZEOF_INT__)\n#endif\n#endif\n#ifndef LZO_SIZEOF_LONG\n#if defined(SIZEOF_LONG)\n#  define LZO_SIZEOF_LONG           (SIZEOF_LONG)\n#elif defined(__SIZEOF_LONG__)\n#  define LZO_SIZEOF_LONG           (__SIZEOF_LONG__)\n#endif\n#endif\n#ifndef LZO_SIZEOF_LONG_LONG\n#if defined(SIZEOF_LONG_LONG)\n#  define LZO_SIZEOF_LONG_LONG      (SIZEOF_LONG_LONG)\n#elif defined(__SIZEOF_LONG_LONG__)\n#  define LZO_SIZEOF_LONG_LONG      (__SIZEOF_LONG_LONG__)\n#endif\n#endif\n#ifndef LZO_SIZEOF___INT16\n#if defined(SIZEOF___INT16)\n#  define LZO_SIZEOF___INT16        (SIZEOF___INT16)\n#endif\n#endif\n#ifndef LZO_SIZEOF___INT32\n#if defined(SIZEOF___INT32)\n#  define LZO_SIZEOF___INT32        (SIZEOF___INT32)\n#endif\n#endif\n#ifndef LZO_SIZEOF___INT64\n#if defined(SIZEOF___INT64)\n#  define LZO_SIZEOF___INT64        (SIZEOF___INT64)\n#endif\n#endif\n#ifndef LZO_SIZEOF_VOID_P\n#if defined(SIZEOF_VOID_P)\n#  define LZO_SIZEOF_VOID_P         (SIZEOF_VOID_P)\n#elif defined(__SIZEOF_POINTER__)\n#  define LZO_SIZEOF_VOID_P         (__SIZEOF_POINTER__)\n#endif\n#endif\n#ifndef LZO_SIZEOF_SIZE_T\n#if defined(SIZEOF_SIZE_T)\n#  define LZO_SIZEOF_SIZE_T         (SIZEOF_SIZE_T)\n#elif defined(__SIZEOF_SIZE_T__)\n#  define LZO_SIZEOF_SIZE_T         (__SIZEOF_SIZE_T__)\n#endif\n#endif\n#ifndef LZO_SIZEOF_PTRDIFF_T\n#if defined(SIZEOF_PTRDIFF_T)\n#  define LZO_SIZEOF_PTRDIFF_T      (SIZEOF_PTRDIFF_T)\n#elif defined(__SIZEOF_PTRDIFF_T__)\n#  define LZO_SIZEOF_PTRDIFF_T      (__SIZEOF_PTRDIFF_T__)\n#endif\n#endif\n#define __LZO_LSR(x,b)    (((x)+0ul) >> (b))\n#if !defined(LZO_SIZEOF_SHORT)\n#  if (LZO_ARCH_CRAY_PVP)\n#    define LZO_SIZEOF_SHORT        8\n#  elif (USHRT_MAX == LZO_0xffffL)\n#    define LZO_SIZEOF_SHORT        2\n#  elif (__LZO_LSR(USHRT_MAX,7) == 1)\n#    define LZO_SIZEOF_SHORT        1\n#  elif (__LZO_LSR(USHRT_MAX,15) == 1)\n#    define LZO_SIZEOF_SHORT        2\n#  elif (__LZO_LSR(USHRT_MAX,31) == 1)\n#    define LZO_SIZEOF_SHORT        4\n#  elif (__LZO_LSR(USHRT_MAX,63) == 1)\n#    define LZO_SIZEOF_SHORT        8\n#  elif (__LZO_LSR(USHRT_MAX,127) == 1)\n#    define LZO_SIZEOF_SHORT        16\n#  else\n#    error \"LZO_SIZEOF_SHORT\"\n#  endif\n#endif\nLZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_SHORT == sizeof(short))\n#if !defined(LZO_SIZEOF_INT)\n#  if (LZO_ARCH_CRAY_PVP)\n#    define LZO_SIZEOF_INT          8\n#  elif (UINT_MAX == LZO_0xffffL)\n#    define LZO_SIZEOF_INT          2\n#  elif (UINT_MAX == LZO_0xffffffffL)\n#    define LZO_SIZEOF_INT          4\n#  elif (__LZO_LSR(UINT_MAX,7) == 1)\n#    define LZO_SIZEOF_INT          1\n#  elif (__LZO_LSR(UINT_MAX,15) == 1)\n#    define LZO_SIZEOF_INT          2\n#  elif (__LZO_LSR(UINT_MAX,31) == 1)\n#    define LZO_SIZEOF_INT          4\n#  elif (__LZO_LSR(UINT_MAX,63) == 1)\n#    define LZO_SIZEOF_INT          8\n#  elif (__LZO_LSR(UINT_MAX,127) == 1)\n#    define LZO_SIZEOF_INT          16\n#  else\n#    error \"LZO_SIZEOF_INT\"\n#  endif\n#endif\nLZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_INT == sizeof(int))\n#if !defined(LZO_SIZEOF_LONG)\n#  if (ULONG_MAX == LZO_0xffffffffL)\n#    define LZO_SIZEOF_LONG         4\n#  elif (__LZO_LSR(ULONG_MAX,7) == 1)\n#    define LZO_SIZEOF_LONG         1\n#  elif (__LZO_LSR(ULONG_MAX,15) == 1)\n#    define LZO_SIZEOF_LONG         2\n#  elif (__LZO_LSR(ULONG_MAX,31) == 1)\n#    define LZO_SIZEOF_LONG         4\n#  elif (__LZO_LSR(ULONG_MAX,39) == 1)\n#    define LZO_SIZEOF_LONG         5\n#  elif (__LZO_LSR(ULONG_MAX,63) == 1)\n#    define LZO_SIZEOF_LONG         8\n#  elif (__LZO_LSR(ULONG_MAX,127) == 1)\n#    define LZO_SIZEOF_LONG         16\n#  else\n#    error \"LZO_SIZEOF_LONG\"\n#  endif\n#endif\nLZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_LONG == sizeof(long))\n#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64)\n#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8)\n#  if defined(__LONG_MAX__) && defined(__LONG_LONG_MAX__)\n#    if (LZO_CC_GNUC >= 0x030300ul)\n#      if ((__LONG_MAX__-0) == (__LONG_LONG_MAX__-0))\n#        define LZO_SIZEOF_LONG_LONG      LZO_SIZEOF_LONG\n#      elif (__LZO_LSR(__LONG_LONG_MAX__,30) == 1)\n#        define LZO_SIZEOF_LONG_LONG      4\n#      endif\n#    endif\n#  endif\n#endif\n#endif\n#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64)\n#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8)\n#if (LZO_ARCH_I086 && LZO_CC_DMC)\n#elif (LZO_CC_CILLY) && defined(__GNUC__)\n#  define LZO_SIZEOF_LONG_LONG      8\n#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)\n#  define LZO_SIZEOF_LONG_LONG      8\n#elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400))\n#  define LZO_SIZEOF_LONG_LONG      8\n#elif (LZO_OS_WIN64 || defined(_WIN64))\n#  define LZO_SIZEOF___INT64        8\n#elif (LZO_ARCH_I386 && (LZO_CC_DMC))\n#  define LZO_SIZEOF_LONG_LONG      8\n#elif (LZO_ARCH_I386 && (LZO_CC_SYMANTECC && (__SC__ >= 0x700)))\n#  define LZO_SIZEOF_LONG_LONG      8\n#elif (LZO_ARCH_I386 && (LZO_CC_INTELC && defined(__linux__)))\n#  define LZO_SIZEOF_LONG_LONG      8\n#elif (LZO_ARCH_I386 && (LZO_CC_MWERKS || LZO_CC_PELLESC || LZO_CC_PGI || LZO_CC_SUNPROC))\n#  define LZO_SIZEOF_LONG_LONG      8\n#elif (LZO_ARCH_I386 && (LZO_CC_INTELC || LZO_CC_MSC))\n#  define LZO_SIZEOF___INT64        8\n#elif ((LZO_OS_WIN32 || defined(_WIN32)) && (LZO_CC_MSC))\n#  define LZO_SIZEOF___INT64        8\n#elif (LZO_ARCH_I386 && (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0520)))\n#  define LZO_SIZEOF___INT64        8\n#elif (LZO_ARCH_I386 && (LZO_CC_WATCOMC && (__WATCOMC__ >= 1100)))\n#  define LZO_SIZEOF___INT64        8\n#elif (LZO_CC_GHS && defined(__LLONG_BIT) && ((__LLONG_BIT-0) == 64))\n#  define LZO_SIZEOF_LONG_LONG      8\n#elif (LZO_CC_WATCOMC && defined(_INTEGRAL_MAX_BITS) && ((_INTEGRAL_MAX_BITS-0) == 64))\n#  define LZO_SIZEOF___INT64        8\n#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__)\n#  define LZO_SIZEOF_LONG_LONG      8\n#elif (defined(__vms) || defined(__VMS)) && ((__INITIAL_POINTER_SIZE-0) == 64)\n#  define LZO_SIZEOF_LONG_LONG      8\n#elif (LZO_CC_SDCC) && (LZO_SIZEOF_INT == 2)\n#elif 1 && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)\n#  define LZO_SIZEOF_LONG_LONG      8\n#endif\n#endif\n#endif\n#if defined(__cplusplus) && (LZO_CC_GNUC)\n#  if (LZO_CC_GNUC < 0x020800ul)\n#    undef LZO_SIZEOF_LONG_LONG\n#  endif\n#endif\n#if (LZO_CFG_NO_LONG_LONG)\n#  undef LZO_SIZEOF_LONG_LONG\n#elif defined(__NO_LONG_LONG)\n#  undef LZO_SIZEOF_LONG_LONG\n#elif defined(_NO_LONGLONG)\n#  undef LZO_SIZEOF_LONG_LONG\n#endif\n#if !defined(LZO_WORDSIZE)\n#if (LZO_ARCH_ALPHA)\n#  define LZO_WORDSIZE              8\n#elif (LZO_ARCH_AMD64)\n#  define LZO_WORDSIZE              8\n#elif (LZO_ARCH_AVR)\n#  define LZO_WORDSIZE              1\n#elif (LZO_ARCH_H8300)\n#  if defined(__NORMAL_MODE__)\n#    define LZO_WORDSIZE            4\n#  elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)\n#    define LZO_WORDSIZE            4\n#  else\n#    define LZO_WORDSIZE            2\n#  endif\n#elif (LZO_ARCH_I086)\n#  define LZO_WORDSIZE              2\n#elif (LZO_ARCH_IA64)\n#  define LZO_WORDSIZE              8\n#elif (LZO_ARCH_M16C)\n#  define LZO_WORDSIZE              2\n#elif (LZO_ARCH_SPU)\n#  define LZO_WORDSIZE              4\n#elif (LZO_ARCH_Z80)\n#  define LZO_WORDSIZE              1\n#elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__))\n#  define LZO_WORDSIZE              8\n#elif (LZO_OS_OS400 || defined(__OS400__))\n#  define LZO_WORDSIZE              8\n#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64)\n#  define LZO_WORDSIZE              8\n#endif\n#endif\n#if !defined(LZO_SIZEOF_VOID_P)\n#if defined(__ILP32__) || defined(__ILP32) || defined(_ILP32)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(int)  == 4)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 4)\n#  define LZO_SIZEOF_VOID_P         4\n#elif defined(__ILP64__) || defined(__ILP64) || defined(_ILP64)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(int)  == 8)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 8)\n#  define LZO_SIZEOF_VOID_P         8\n#elif defined(__LLP64__) || defined(__LLP64) || defined(_LLP64) || defined(_WIN64)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 4)\n#  define LZO_SIZEOF_VOID_P         8\n#elif defined(__LP64__) || defined(__LP64) || defined(_LP64)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 8)\n#  define LZO_SIZEOF_VOID_P         8\n#elif (LZO_ARCH_AVR)\n#  define LZO_SIZEOF_VOID_P         2\n#elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430)\n#  define LZO_SIZEOF_VOID_P         2\n#elif (LZO_ARCH_H8300)\n#  if defined(__NORMAL_MODE__)\n#    define LZO_SIZEOF_VOID_P       2\n#  elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)\n#    define LZO_SIZEOF_VOID_P       4\n#  else\n#    define LZO_SIZEOF_VOID_P       2\n#  endif\n#  if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4)\n#    define LZO_SIZEOF_SIZE_T       LZO_SIZEOF_INT\n#    define LZO_SIZEOF_PTRDIFF_T    LZO_SIZEOF_INT\n#  endif\n#elif (LZO_ARCH_I086)\n#  if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM)\n#    define LZO_SIZEOF_VOID_P       2\n#  elif (LZO_MM_COMPACT || LZO_MM_LARGE || LZO_MM_HUGE)\n#    define LZO_SIZEOF_VOID_P       4\n#  else\n#    error \"invalid LZO_ARCH_I086 memory model\"\n#  endif\n#elif (LZO_ARCH_M16C)\n#  if defined(__m32c_cpu__) || defined(__m32cm_cpu__)\n#    define LZO_SIZEOF_VOID_P       4\n#  else\n#    define LZO_SIZEOF_VOID_P       2\n#  endif\n#elif (LZO_ARCH_SPU)\n#  define LZO_SIZEOF_VOID_P         4\n#elif (LZO_ARCH_Z80)\n#  define LZO_SIZEOF_VOID_P         2\n#elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__))\n#  define LZO_SIZEOF_VOID_P         4\n#elif (LZO_OS_OS400 || defined(__OS400__))\n#  if defined(__LLP64_IFC__)\n#    define LZO_SIZEOF_VOID_P       8\n#    define LZO_SIZEOF_SIZE_T       LZO_SIZEOF_LONG\n#    define LZO_SIZEOF_PTRDIFF_T    LZO_SIZEOF_LONG\n#  else\n#    define LZO_SIZEOF_VOID_P       16\n#    define LZO_SIZEOF_SIZE_T       LZO_SIZEOF_LONG\n#    define LZO_SIZEOF_PTRDIFF_T    LZO_SIZEOF_LONG\n#  endif\n#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64)\n#  define LZO_SIZEOF_VOID_P         8\n#  define LZO_SIZEOF_SIZE_T         LZO_SIZEOF_LONG\n#  define LZO_SIZEOF_PTRDIFF_T      LZO_SIZEOF_LONG\n#endif\n#endif\n#if !defined(LZO_SIZEOF_VOID_P)\n#  define LZO_SIZEOF_VOID_P         LZO_SIZEOF_LONG\n#endif\nLZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_VOID_P == sizeof(void *))\n#if !defined(LZO_SIZEOF_SIZE_T)\n#if (LZO_ARCH_I086 || LZO_ARCH_M16C)\n#  define LZO_SIZEOF_SIZE_T         2\n#endif\n#endif\n#if !defined(LZO_SIZEOF_SIZE_T)\n#  define LZO_SIZEOF_SIZE_T         LZO_SIZEOF_VOID_P\n#endif\n#if defined(offsetof)\nLZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_SIZE_T == sizeof(size_t))\n#endif\n#if !defined(LZO_SIZEOF_PTRDIFF_T)\n#if (LZO_ARCH_I086)\n#  if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM || LZO_MM_HUGE)\n#    define LZO_SIZEOF_PTRDIFF_T    LZO_SIZEOF_VOID_P\n#  elif (LZO_MM_COMPACT || LZO_MM_LARGE)\n#    if (LZO_CC_BORLANDC || LZO_CC_TURBOC)\n#      define LZO_SIZEOF_PTRDIFF_T  4\n#    else\n#      define LZO_SIZEOF_PTRDIFF_T  2\n#    endif\n#  else\n#    error \"invalid LZO_ARCH_I086 memory model\"\n#  endif\n#endif\n#endif\n#if !defined(LZO_SIZEOF_PTRDIFF_T)\n#  define LZO_SIZEOF_PTRDIFF_T      LZO_SIZEOF_SIZE_T\n#endif\n#if defined(offsetof)\nLZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))\n#endif\n#if !defined(LZO_WORDSIZE)\n#  define LZO_WORDSIZE              LZO_SIZEOF_VOID_P\n#endif\n#if (LZO_ABI_NEUTRAL_ENDIAN)\n#  undef LZO_ABI_BIG_ENDIAN\n#  undef LZO_ABI_LITTLE_ENDIAN\n#elif !(LZO_ABI_BIG_ENDIAN) && !(LZO_ABI_LITTLE_ENDIAN)\n#if (LZO_ARCH_ALPHA) && (LZO_ARCH_CRAY_MPP)\n#  define LZO_ABI_BIG_ENDIAN        1\n#elif (LZO_ARCH_IA64) && (LZO_OS_POSIX_LINUX || LZO_OS_WIN64)\n#  define LZO_ABI_LITTLE_ENDIAN     1\n#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430)\n#  define LZO_ABI_LITTLE_ENDIAN     1\n#elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390 || LZO_ARCH_SPU)\n#  define LZO_ABI_BIG_ENDIAN        1\n#elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__)\n#  if (__LITTLE_ENDIAN__ == 1)\n#    define LZO_ABI_LITTLE_ENDIAN   1\n#  else\n#    define LZO_ABI_BIG_ENDIAN      1\n#  endif\n#elif 1 && defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)\n#  define LZO_ABI_BIG_ENDIAN        1\n#elif 1 && defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)\n#  define LZO_ABI_LITTLE_ENDIAN     1\n#elif 1 && (LZO_ARCH_ARM) && defined(__ARM_BIG_ENDIAN) && ((__ARM_BIG_ENDIAN)+0)\n#  define LZO_ABI_BIG_ENDIAN        1\n#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEB__) && !defined(__ARMEL__)\n#  define LZO_ABI_BIG_ENDIAN        1\n#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__)\n#  define LZO_ABI_LITTLE_ENDIAN     1\n#elif 1 && (LZO_ARCH_ARM && LZO_CC_ARMCC_ARMCC)\n#  if defined(__BIG_ENDIAN) && defined(__LITTLE_ENDIAN)\n#    error \"unexpected configuration - check your compiler defines\"\n#  elif defined(__BIG_ENDIAN)\n#    define LZO_ABI_BIG_ENDIAN      1\n#  else\n#    define LZO_ABI_LITTLE_ENDIAN   1\n#  endif\n#  define LZO_ABI_LITTLE_ENDIAN     1\n#elif 1 && (LZO_ARCH_ARM64) && defined(__ARM_BIG_ENDIAN) && ((__ARM_BIG_ENDIAN)+0)\n#  define LZO_ABI_BIG_ENDIAN        1\n#elif 1 && (LZO_ARCH_ARM64) && defined(__AARCH64EB__) && !defined(__AARCH64EL__)\n#  define LZO_ABI_BIG_ENDIAN        1\n#elif 1 && (LZO_ARCH_ARM64) && defined(__AARCH64EL__) && !defined(__AARCH64EB__)\n#  define LZO_ABI_LITTLE_ENDIAN     1\n#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__)\n#  define LZO_ABI_BIG_ENDIAN        1\n#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__)\n#  define LZO_ABI_LITTLE_ENDIAN     1\n#endif\n#endif\n#if (LZO_ABI_BIG_ENDIAN) && (LZO_ABI_LITTLE_ENDIAN)\n#  error \"unexpected configuration - check your compiler defines\"\n#endif\n#if (LZO_ABI_BIG_ENDIAN)\n#  define LZO_INFO_ABI_ENDIAN       \"be\"\n#elif (LZO_ABI_LITTLE_ENDIAN)\n#  define LZO_INFO_ABI_ENDIAN       \"le\"\n#elif (LZO_ABI_NEUTRAL_ENDIAN)\n#  define LZO_INFO_ABI_ENDIAN       \"neutral\"\n#endif\n#if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2)\n#  define LZO_ABI_I8LP16         1\n#  define LZO_INFO_ABI_PM       \"i8lp16\"\n#elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2)\n#  define LZO_ABI_ILP16         1\n#  define LZO_INFO_ABI_PM       \"ilp16\"\n#elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4)\n#  define LZO_ABI_LP32          1\n#  define LZO_INFO_ABI_PM       \"lp32\"\n#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4)\n#  define LZO_ABI_ILP32         1\n#  define LZO_INFO_ABI_PM       \"ilp32\"\n#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 8 && LZO_SIZEOF_SIZE_T == 8)\n#  define LZO_ABI_LLP64         1\n#  define LZO_INFO_ABI_PM       \"llp64\"\n#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8)\n#  define LZO_ABI_LP64          1\n#  define LZO_INFO_ABI_PM       \"lp64\"\n#elif (LZO_SIZEOF_INT == 8 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8)\n#  define LZO_ABI_ILP64         1\n#  define LZO_INFO_ABI_PM       \"ilp64\"\n#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 4)\n#  define LZO_ABI_IP32L64       1\n#  define LZO_INFO_ABI_PM       \"ip32l64\"\n#endif\n#if 0\n#elif !defined(__LZO_LIBC_OVERRIDE)\n#if (LZO_LIBC_NAKED)\n#  define LZO_INFO_LIBC         \"naked\"\n#elif (LZO_LIBC_FREESTANDING)\n#  define LZO_INFO_LIBC         \"freestanding\"\n#elif (LZO_LIBC_MOSTLY_FREESTANDING)\n#  define LZO_INFO_LIBC         \"mfreestanding\"\n#elif (LZO_LIBC_ISOC90)\n#  define LZO_INFO_LIBC         \"isoc90\"\n#elif (LZO_LIBC_ISOC99)\n#  define LZO_INFO_LIBC         \"isoc99\"\n#elif (LZO_CC_ARMCC_ARMCC) && defined(__ARMCLIB_VERSION)\n#  define LZO_LIBC_ISOC90       1\n#  define LZO_INFO_LIBC         \"isoc90\"\n#elif defined(__dietlibc__)\n#  define LZO_LIBC_DIETLIBC     1\n#  define LZO_INFO_LIBC         \"dietlibc\"\n#elif defined(_NEWLIB_VERSION)\n#  define LZO_LIBC_NEWLIB       1\n#  define LZO_INFO_LIBC         \"newlib\"\n#elif defined(__UCLIBC__) && defined(__UCLIBC_MAJOR__) && defined(__UCLIBC_MINOR__)\n#  if defined(__UCLIBC_SUBLEVEL__)\n#    define LZO_LIBC_UCLIBC     (__UCLIBC_MAJOR__ * 0x10000L + (__UCLIBC_MINOR__-0) * 0x100 + (__UCLIBC_SUBLEVEL__-0))\n#  else\n#    define LZO_LIBC_UCLIBC     0x00090bL\n#  endif\n#  define LZO_INFO_LIBC         \"uc\" \"libc\"\n#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__)\n#  define LZO_LIBC_GLIBC        (__GLIBC__ * 0x10000L + (__GLIBC_MINOR__-0) * 0x100)\n#  define LZO_INFO_LIBC         \"glibc\"\n#elif (LZO_CC_MWERKS) && defined(__MSL__)\n#  define LZO_LIBC_MSL          __MSL__\n#  define LZO_INFO_LIBC         \"msl\"\n#elif 1 && defined(__IAR_SYSTEMS_ICC__)\n#  define LZO_LIBC_ISOC90       1\n#  define LZO_INFO_LIBC         \"isoc90\"\n#else\n#  define LZO_LIBC_DEFAULT      1\n#  define LZO_INFO_LIBC         \"default\"\n#endif\n#endif\n#if (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))\n#  define LZO_ASM_SYNTAX_MSC 1\n#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))\n#elif (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC == 0x011f00ul))\n#elif (LZO_ARCH_I386 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))\n#  define LZO_ASM_SYNTAX_GNUC 1\n#elif (LZO_ARCH_AMD64 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))\n#  define LZO_ASM_SYNTAX_GNUC 1\n#elif (LZO_CC_GNUC)\n#  define LZO_ASM_SYNTAX_GNUC 1\n#endif\n#if (LZO_ASM_SYNTAX_GNUC)\n#if (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC < 0x020000ul))\n#  define __LZO_ASM_CLOBBER                     \"ax\"\n#  define __LZO_ASM_CLOBBER_LIST_CC             /*empty*/\n#  define __LZO_ASM_CLOBBER_LIST_CC_MEMORY      /*empty*/\n#  define __LZO_ASM_CLOBBER_LIST_EMPTY          /*empty*/\n#elif (LZO_CC_INTELC && (__INTEL_COMPILER < 1000))\n#  define __LZO_ASM_CLOBBER                     \"memory\"\n#  define __LZO_ASM_CLOBBER_LIST_CC             /*empty*/\n#  define __LZO_ASM_CLOBBER_LIST_CC_MEMORY      : \"memory\"\n#  define __LZO_ASM_CLOBBER_LIST_EMPTY          /*empty*/\n#else\n#  define __LZO_ASM_CLOBBER                     \"cc\", \"memory\"\n#  define __LZO_ASM_CLOBBER_LIST_CC             : \"cc\"\n#  define __LZO_ASM_CLOBBER_LIST_CC_MEMORY      : \"cc\", \"memory\"\n#  define __LZO_ASM_CLOBBER_LIST_EMPTY          /*empty*/\n#endif\n#endif\n#if (LZO_ARCH_ALPHA)\n#  define LZO_OPT_AVOID_UINT_INDEX          1\n#elif (LZO_ARCH_AMD64)\n#  define LZO_OPT_AVOID_INT_INDEX           1\n#  define LZO_OPT_AVOID_UINT_INDEX          1\n#  ifndef LZO_OPT_UNALIGNED16\n#  define LZO_OPT_UNALIGNED16               1\n#  endif\n#  ifndef LZO_OPT_UNALIGNED32\n#  define LZO_OPT_UNALIGNED32               1\n#  endif\n#  ifndef LZO_OPT_UNALIGNED64\n#  define LZO_OPT_UNALIGNED64               1\n#  endif\n#elif (LZO_ARCH_ARM)\n#  if defined(__ARM_FEATURE_UNALIGNED)\n#   if ((__ARM_FEATURE_UNALIGNED)+0)\n#    ifndef LZO_OPT_UNALIGNED16\n#    define LZO_OPT_UNALIGNED16             1\n#    endif\n#    ifndef LZO_OPT_UNALIGNED32\n#    define LZO_OPT_UNALIGNED32             1\n#    endif\n#   endif\n#  elif 1 && (LZO_ARCH_ARM_THUMB2)\n#    ifndef LZO_OPT_UNALIGNED16\n#    define LZO_OPT_UNALIGNED16             1\n#    endif\n#    ifndef LZO_OPT_UNALIGNED32\n#    define LZO_OPT_UNALIGNED32             1\n#    endif\n#  elif 1 && defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM)+0 >= 7)\n#    ifndef LZO_OPT_UNALIGNED16\n#    define LZO_OPT_UNALIGNED16             1\n#    endif\n#    ifndef LZO_OPT_UNALIGNED32\n#    define LZO_OPT_UNALIGNED32             1\n#    endif\n#  elif 1 && defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM)+0 >= 6) && (defined(__TARGET_PROFILE_A) || defined(__TARGET_PROFILE_R))\n#    ifndef LZO_OPT_UNALIGNED16\n#    define LZO_OPT_UNALIGNED16             1\n#    endif\n#    ifndef LZO_OPT_UNALIGNED32\n#    define LZO_OPT_UNALIGNED32             1\n#    endif\n#  endif\n#elif (LZO_ARCH_ARM64)\n#  ifndef LZO_OPT_UNALIGNED16\n#  define LZO_OPT_UNALIGNED16               1\n#  endif\n#  ifndef LZO_OPT_UNALIGNED32\n#  define LZO_OPT_UNALIGNED32               1\n#  endif\n#  ifndef LZO_OPT_UNALIGNED64\n#  define LZO_OPT_UNALIGNED64               1\n#  endif\n#elif (LZO_ARCH_CRIS)\n#  ifndef LZO_OPT_UNALIGNED16\n#  define LZO_OPT_UNALIGNED16               1\n#  endif\n#  ifndef LZO_OPT_UNALIGNED32\n#  define LZO_OPT_UNALIGNED32               1\n#  endif\n#elif (LZO_ARCH_I386)\n#  ifndef LZO_OPT_UNALIGNED16\n#  define LZO_OPT_UNALIGNED16               1\n#  endif\n#  ifndef LZO_OPT_UNALIGNED32\n#  define LZO_OPT_UNALIGNED32               1\n#  endif\n#elif (LZO_ARCH_IA64)\n#  define LZO_OPT_AVOID_INT_INDEX           1\n#  define LZO_OPT_AVOID_UINT_INDEX          1\n#  define LZO_OPT_PREFER_POSTINC            1\n#elif (LZO_ARCH_M68K)\n#  define LZO_OPT_PREFER_POSTINC            1\n#  define LZO_OPT_PREFER_PREDEC             1\n#  if defined(__mc68020__) && !defined(__mcoldfire__)\n#    ifndef LZO_OPT_UNALIGNED16\n#    define LZO_OPT_UNALIGNED16             1\n#    endif\n#    ifndef LZO_OPT_UNALIGNED32\n#    define LZO_OPT_UNALIGNED32             1\n#    endif\n#  endif\n#elif (LZO_ARCH_MIPS)\n#  define LZO_OPT_AVOID_UINT_INDEX          1\n#elif (LZO_ARCH_POWERPC)\n#  define LZO_OPT_PREFER_PREINC             1\n#  define LZO_OPT_PREFER_PREDEC             1\n#  if (LZO_ABI_BIG_ENDIAN)\n#    ifndef LZO_OPT_UNALIGNED16\n#    define LZO_OPT_UNALIGNED16             1\n#    endif\n#    ifndef LZO_OPT_UNALIGNED32\n#    define LZO_OPT_UNALIGNED32             1\n#    endif\n#    if (LZO_WORDSIZE == 8)\n#      ifndef LZO_OPT_UNALIGNED64\n#      define LZO_OPT_UNALIGNED64           1\n#      endif\n#    endif\n#  endif\n#elif (LZO_ARCH_S390)\n#  ifndef LZO_OPT_UNALIGNED16\n#  define LZO_OPT_UNALIGNED16               1\n#  endif\n#  ifndef LZO_OPT_UNALIGNED32\n#  define LZO_OPT_UNALIGNED32               1\n#  endif\n#  if (LZO_WORDSIZE == 8)\n#    ifndef LZO_OPT_UNALIGNED64\n#    define LZO_OPT_UNALIGNED64             1\n#    endif\n#  endif\n#elif (LZO_ARCH_SH)\n#  define LZO_OPT_PREFER_POSTINC            1\n#  define LZO_OPT_PREFER_PREDEC             1\n#endif\n#ifndef LZO_CFG_NO_INLINE_ASM\n#if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC)\n#  define LZO_CFG_NO_INLINE_ASM 1\n#elif (LZO_CC_LLVM)\n#  define LZO_CFG_NO_INLINE_ASM 1\n#endif\n#endif\n#if (LZO_CFG_NO_INLINE_ASM)\n#  undef LZO_ASM_SYNTAX_MSC\n#  undef LZO_ASM_SYNTAX_GNUC\n#  undef __LZO_ASM_CLOBBER\n#  undef __LZO_ASM_CLOBBER_LIST_CC\n#  undef __LZO_ASM_CLOBBER_LIST_CC_MEMORY\n#  undef __LZO_ASM_CLOBBER_LIST_EMPTY\n#endif\n#ifndef LZO_CFG_NO_UNALIGNED\n#if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC)\n#  define LZO_CFG_NO_UNALIGNED 1\n#endif\n#endif\n#if (LZO_CFG_NO_UNALIGNED)\n#  undef LZO_OPT_UNALIGNED16\n#  undef LZO_OPT_UNALIGNED32\n#  undef LZO_OPT_UNALIGNED64\n#endif\n#if defined(__LZO_INFOSTR_MM)\n#elif (LZO_MM_FLAT) && (defined(__LZO_INFOSTR_PM) || defined(LZO_INFO_ABI_PM))\n#  define __LZO_INFOSTR_MM          \"\"\n#elif defined(LZO_INFO_MM)\n#  define __LZO_INFOSTR_MM          \".\" LZO_INFO_MM\n#else\n#  define __LZO_INFOSTR_MM          \"\"\n#endif\n#if defined(__LZO_INFOSTR_PM)\n#elif defined(LZO_INFO_ABI_PM)\n#  define __LZO_INFOSTR_PM          \".\" LZO_INFO_ABI_PM\n#else\n#  define __LZO_INFOSTR_PM          \"\"\n#endif\n#if defined(__LZO_INFOSTR_ENDIAN)\n#elif defined(LZO_INFO_ABI_ENDIAN)\n#  define __LZO_INFOSTR_ENDIAN      \".\" LZO_INFO_ABI_ENDIAN\n#else\n#  define __LZO_INFOSTR_ENDIAN      \"\"\n#endif\n#if defined(__LZO_INFOSTR_OSNAME)\n#elif defined(LZO_INFO_OS_CONSOLE)\n#  define __LZO_INFOSTR_OSNAME      LZO_INFO_OS \".\" LZO_INFO_OS_CONSOLE\n#elif defined(LZO_INFO_OS_POSIX)\n#  define __LZO_INFOSTR_OSNAME      LZO_INFO_OS \".\" LZO_INFO_OS_POSIX\n#else\n#  define __LZO_INFOSTR_OSNAME      LZO_INFO_OS\n#endif\n#if defined(__LZO_INFOSTR_LIBC)\n#elif defined(LZO_INFO_LIBC)\n#  define __LZO_INFOSTR_LIBC        \".\" LZO_INFO_LIBC\n#else\n#  define __LZO_INFOSTR_LIBC        \"\"\n#endif\n#if defined(__LZO_INFOSTR_CCVER)\n#elif defined(LZO_INFO_CCVER)\n#  define __LZO_INFOSTR_CCVER       \" \" LZO_INFO_CCVER\n#else\n#  define __LZO_INFOSTR_CCVER       \"\"\n#endif\n#define LZO_INFO_STRING \\\n    LZO_INFO_ARCH __LZO_INFOSTR_MM __LZO_INFOSTR_PM __LZO_INFOSTR_ENDIAN \\\n    \" \" __LZO_INFOSTR_OSNAME __LZO_INFOSTR_LIBC \" \" LZO_INFO_CC __LZO_INFOSTR_CCVER\n#if !(LZO_CFG_SKIP_LZO_TYPES)\n#if (!(LZO_SIZEOF_SHORT+0 > 0 && LZO_SIZEOF_INT+0 > 0 && LZO_SIZEOF_LONG+0 > 0))\n#  error \"missing defines for sizes\"\n#endif\n#if (!(LZO_SIZEOF_PTRDIFF_T+0 > 0 && LZO_SIZEOF_SIZE_T+0 > 0 && LZO_SIZEOF_VOID_P+0 > 0))\n#  error \"missing defines for sizes\"\n#endif\n#define LZO_TYPEOF_CHAR             1u\n#define LZO_TYPEOF_SHORT            2u\n#define LZO_TYPEOF_INT              3u\n#define LZO_TYPEOF_LONG             4u\n#define LZO_TYPEOF_LONG_LONG        5u\n#define LZO_TYPEOF___INT8           17u\n#define LZO_TYPEOF___INT16          18u\n#define LZO_TYPEOF___INT32          19u\n#define LZO_TYPEOF___INT64          20u\n#define LZO_TYPEOF___INT128         21u\n#define LZO_TYPEOF___INT256         22u\n#define LZO_TYPEOF___MODE_QI        33u\n#define LZO_TYPEOF___MODE_HI        34u\n#define LZO_TYPEOF___MODE_SI        35u\n#define LZO_TYPEOF___MODE_DI        36u\n#define LZO_TYPEOF___MODE_TI        37u\n#define LZO_TYPEOF_CHAR_P           129u\n#if !defined(lzo_llong_t)\n#if (LZO_SIZEOF_LONG_LONG+0 > 0)\n__lzo_gnuc_extension__ typedef long long lzo_llong_t__;\n__lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;\n#  define lzo_llong_t               lzo_llong_t__\n#  define lzo_ullong_t              lzo_ullong_t__\n#endif\n#endif\n#if !defined(lzo_int16e_t)\n#if (LZO_SIZEOF_LONG == 2)\n#  define lzo_int16e_t              long\n#  define lzo_uint16e_t             unsigned long\n#  define LZO_TYPEOF_LZO_INT16E_T   LZO_TYPEOF_LONG\n#elif (LZO_SIZEOF_INT == 2)\n#  define lzo_int16e_t              int\n#  define lzo_uint16e_t             unsigned int\n#  define LZO_TYPEOF_LZO_INT16E_T   LZO_TYPEOF_INT\n#elif (LZO_SIZEOF_SHORT == 2)\n#  define lzo_int16e_t              short int\n#  define lzo_uint16e_t             unsigned short int\n#  define LZO_TYPEOF_LZO_INT16E_T   LZO_TYPEOF_SHORT\n#elif 1 && !(LZO_CFG_TYPE_NO_MODE_HI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM)\n   typedef int lzo_int16e_hi_t__ __attribute__((__mode__(__HI__)));\n   typedef unsigned int lzo_uint16e_hi_t__ __attribute__((__mode__(__HI__)));\n#  define lzo_int16e_t              lzo_int16e_hi_t__\n#  define lzo_uint16e_t             lzo_uint16e_hi_t__\n#  define LZO_TYPEOF_LZO_INT16E_T   LZO_TYPEOF___MODE_HI\n#elif (LZO_SIZEOF___INT16 == 2)\n#  define lzo_int16e_t              __int16\n#  define lzo_uint16e_t             unsigned __int16\n#  define LZO_TYPEOF_LZO_INT16E_T   LZO_TYPEOF___INT16\n#else\n#endif\n#endif\n#if defined(lzo_int16e_t)\n#  define LZO_SIZEOF_LZO_INT16E_T   2\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16e_t) == 2)\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16e_t) == LZO_SIZEOF_LZO_INT16E_T)\n#endif\n#if !defined(lzo_int32e_t)\n#if (LZO_SIZEOF_LONG == 4)\n#  define lzo_int32e_t              long int\n#  define lzo_uint32e_t             unsigned long int\n#  define LZO_TYPEOF_LZO_INT32E_T   LZO_TYPEOF_LONG\n#elif (LZO_SIZEOF_INT == 4)\n#  define lzo_int32e_t              int\n#  define lzo_uint32e_t             unsigned int\n#  define LZO_TYPEOF_LZO_INT32E_T   LZO_TYPEOF_INT\n#elif (LZO_SIZEOF_SHORT == 4)\n#  define lzo_int32e_t              short int\n#  define lzo_uint32e_t             unsigned short int\n#  define LZO_TYPEOF_LZO_INT32E_T   LZO_TYPEOF_SHORT\n#elif (LZO_SIZEOF_LONG_LONG == 4)\n#  define lzo_int32e_t              lzo_llong_t\n#  define lzo_uint32e_t             lzo_ullong_t\n#  define LZO_TYPEOF_LZO_INT32E_T   LZO_TYPEOF_LONG_LONG\n#elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM) && (__INT_MAX__+0 > 2147483647L)\n   typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__)));\n   typedef unsigned int lzo_uint32e_si_t__ __attribute__((__mode__(__SI__)));\n#  define lzo_int32e_t              lzo_int32e_si_t__\n#  define lzo_uint32e_t             lzo_uint32e_si_t__\n#  define LZO_TYPEOF_LZO_INT32E_T   LZO_TYPEOF___MODE_SI\n#elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_GNUC >= 0x025f00ul) && defined(__AVR__) && (__LONG_MAX__+0 == 32767L)\n   typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__)));\n   typedef unsigned int lzo_uint32e_si_t__ __attribute__((__mode__(__SI__)));\n#  define lzo_int32e_t              lzo_int32e_si_t__\n#  define lzo_uint32e_t             lzo_uint32e_si_t__\n#  define LZO_INT32_C(c)            (c##LL)\n#  define LZO_UINT32_C(c)           (c##ULL)\n#  define LZO_TYPEOF_LZO_INT32E_T   LZO_TYPEOF___MODE_SI\n#elif (LZO_SIZEOF___INT32 == 4)\n#  define lzo_int32e_t              __int32\n#  define lzo_uint32e_t             unsigned __int32\n#  define LZO_TYPEOF_LZO_INT32E_T   LZO_TYPEOF___INT32\n#else\n#endif\n#endif\n#if defined(lzo_int32e_t)\n#  define LZO_SIZEOF_LZO_INT32E_T   4\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32e_t) == 4)\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32e_t) == LZO_SIZEOF_LZO_INT32E_T)\n#endif\n#if !defined(lzo_int64e_t)\n#if (LZO_SIZEOF___INT64 == 8)\n#  if (LZO_CC_BORLANDC) && !(LZO_CFG_TYPE_PREFER___INT64)\n#    define LZO_CFG_TYPE_PREFER___INT64 1\n#  endif\n#endif\n#if (LZO_SIZEOF_INT == 8) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)\n#  define lzo_int64e_t              int\n#  define lzo_uint64e_t             unsigned int\n#  define LZO_TYPEOF_LZO_INT64E_T   LZO_TYPEOF_INT\n#elif (LZO_SIZEOF_LONG == 8)\n#  define lzo_int64e_t              long int\n#  define lzo_uint64e_t             unsigned long int\n#  define LZO_TYPEOF_LZO_INT64E_T   LZO_TYPEOF_LONG\n#elif (LZO_SIZEOF_LONG_LONG == 8) && !(LZO_CFG_TYPE_PREFER___INT64)\n#  define lzo_int64e_t              lzo_llong_t\n#  define lzo_uint64e_t             lzo_ullong_t\n#  define LZO_TYPEOF_LZO_INT64E_T   LZO_TYPEOF_LONG_LONG\n#  if (LZO_CC_BORLANDC)\n#    define LZO_INT64_C(c)          ((c) + 0ll)\n#    define LZO_UINT64_C(c)         ((c) + 0ull)\n#  elif 0\n#    define LZO_INT64_C(c)          (__lzo_gnuc_extension__ (c##LL))\n#    define LZO_UINT64_C(c)         (__lzo_gnuc_extension__ (c##ULL))\n#  else\n#    define LZO_INT64_C(c)          (c##LL)\n#    define LZO_UINT64_C(c)         (c##ULL)\n#  endif\n#elif (LZO_SIZEOF___INT64 == 8)\n#  define lzo_int64e_t              __int64\n#  define lzo_uint64e_t             unsigned __int64\n#  define LZO_TYPEOF_LZO_INT64E_T   LZO_TYPEOF___INT64\n#  if (LZO_CC_BORLANDC)\n#    define LZO_INT64_C(c)          ((c) + 0i64)\n#    define LZO_UINT64_C(c)         ((c) + 0ui64)\n#  else\n#    define LZO_INT64_C(c)          (c##i64)\n#    define LZO_UINT64_C(c)         (c##ui64)\n#  endif\n#else\n#endif\n#endif\n#if defined(lzo_int64e_t)\n#  define LZO_SIZEOF_LZO_INT64E_T   8\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64e_t) == 8)\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64e_t) == LZO_SIZEOF_LZO_INT64E_T)\n#endif\n#if !defined(lzo_int32l_t)\n#if defined(lzo_int32e_t)\n#  define lzo_int32l_t              lzo_int32e_t\n#  define lzo_uint32l_t             lzo_uint32e_t\n#  define LZO_SIZEOF_LZO_INT32L_T   LZO_SIZEOF_LZO_INT32E_T\n#  define LZO_TYPEOF_LZO_INT32L_T   LZO_TYPEOF_LZO_INT32E_T\n#elif (LZO_SIZEOF_INT >= 4) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)\n#  define lzo_int32l_t              int\n#  define lzo_uint32l_t             unsigned int\n#  define LZO_SIZEOF_LZO_INT32L_T   LZO_SIZEOF_INT\n#  define LZO_TYPEOF_LZO_INT32L_T   LZO_SIZEOF_INT\n#elif (LZO_SIZEOF_LONG >= 4)\n#  define lzo_int32l_t              long int\n#  define lzo_uint32l_t             unsigned long int\n#  define LZO_SIZEOF_LZO_INT32L_T   LZO_SIZEOF_LONG\n#  define LZO_TYPEOF_LZO_INT32L_T   LZO_SIZEOF_LONG\n#else\n#  error \"lzo_int32l_t\"\n#endif\n#endif\n#if 1\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32l_t) >= 4)\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32l_t) == LZO_SIZEOF_LZO_INT32L_T)\n#endif\n#if !defined(lzo_int64l_t)\n#if defined(lzo_int64e_t)\n#  define lzo_int64l_t              lzo_int64e_t\n#  define lzo_uint64l_t             lzo_uint64e_t\n#  define LZO_SIZEOF_LZO_INT64L_T   LZO_SIZEOF_LZO_INT64E_T\n#  define LZO_TYPEOF_LZO_INT64L_T   LZO_TYPEOF_LZO_INT64E_T\n#else\n#endif\n#endif\n#if defined(lzo_int64l_t)\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64l_t) >= 8)\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64l_t) == LZO_SIZEOF_LZO_INT64L_T)\n#endif\n#if !defined(lzo_int32f_t)\n#if (LZO_SIZEOF_SIZE_T >= 8)\n#  define lzo_int32f_t              lzo_int64l_t\n#  define lzo_uint32f_t             lzo_uint64l_t\n#  define LZO_SIZEOF_LZO_INT32F_T   LZO_SIZEOF_LZO_INT64L_T\n#  define LZO_TYPEOF_LZO_INT32F_T   LZO_TYPEOF_LZO_INT64L_T\n#else\n#  define lzo_int32f_t              lzo_int32l_t\n#  define lzo_uint32f_t             lzo_uint32l_t\n#  define LZO_SIZEOF_LZO_INT32F_T   LZO_SIZEOF_LZO_INT32L_T\n#  define LZO_TYPEOF_LZO_INT32F_T   LZO_TYPEOF_LZO_INT32L_T\n#endif\n#endif\n#if 1\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32f_t) >= 4)\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32f_t) == LZO_SIZEOF_LZO_INT32F_T)\n#endif\n#if !defined(lzo_int64f_t)\n#if defined(lzo_int64l_t)\n#  define lzo_int64f_t              lzo_int64l_t\n#  define lzo_uint64f_t             lzo_uint64l_t\n#  define LZO_SIZEOF_LZO_INT64F_T   LZO_SIZEOF_LZO_INT64L_T\n#  define LZO_TYPEOF_LZO_INT64F_T   LZO_TYPEOF_LZO_INT64L_T\n#else\n#endif\n#endif\n#if defined(lzo_int64f_t)\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64f_t) >= 8)\n   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64f_t) == LZO_SIZEOF_LZO_INT64F_T)\n#endif\n#if !defined(lzo_intptr_t)\n#if 1 && (LZO_OS_OS400 && (LZO_SIZEOF_VOID_P == 16))\n#  define __LZO_INTPTR_T_IS_POINTER 1\n   typedef char *                   lzo_intptr_t;\n   typedef char *                   lzo_uintptr_t;\n#  define lzo_intptr_t              lzo_intptr_t\n#  define lzo_uintptr_t             lzo_uintptr_t\n#  define LZO_SIZEOF_LZO_INTPTR_T   LZO_SIZEOF_VOID_P\n#  define LZO_TYPEOF_LZO_INTPTR_T   LZO_TYPEOF_CHAR_P\n#elif (LZO_CC_MSC && (_MSC_VER >= 1300) && (LZO_SIZEOF_VOID_P == 4) && (LZO_SIZEOF_INT == 4))\n   typedef __w64 int                lzo_intptr_t;\n   typedef __w64 unsigned int       lzo_uintptr_t;\n#  define lzo_intptr_t              lzo_intptr_t\n#  define lzo_uintptr_t             lzo_uintptr_t\n#  define LZO_SIZEOF_LZO_INTPTR_T   LZO_SIZEOF_INT\n#  define LZO_TYPEOF_LZO_INTPTR_T   LZO_TYPEOF_INT\n#elif (LZO_SIZEOF_SHORT == LZO_SIZEOF_VOID_P) && (LZO_SIZEOF_INT > LZO_SIZEOF_VOID_P)\n#  define lzo_intptr_t              short\n#  define lzo_uintptr_t             unsigned short\n#  define LZO_SIZEOF_LZO_INTPTR_T   LZO_SIZEOF_SHORT\n#  define LZO_TYPEOF_LZO_INTPTR_T   LZO_TYPEOF_SHORT\n#elif (LZO_SIZEOF_INT >= LZO_SIZEOF_VOID_P) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)\n#  define lzo_intptr_t              int\n#  define lzo_uintptr_t             unsigned int\n#  define LZO_SIZEOF_LZO_INTPTR_T   LZO_SIZEOF_INT\n#  define LZO_TYPEOF_LZO_INTPTR_T   LZO_TYPEOF_INT\n#elif (LZO_SIZEOF_LONG >= LZO_SIZEOF_VOID_P)\n#  define lzo_intptr_t              long\n#  define lzo_uintptr_t             unsigned long\n#  define LZO_SIZEOF_LZO_INTPTR_T   LZO_SIZEOF_LONG\n#  define LZO_TYPEOF_LZO_INTPTR_T   LZO_TYPEOF_LONG\n#elif (LZO_SIZEOF_LZO_INT64L_T >= LZO_SIZEOF_VOID_P)\n#  define lzo_intptr_t              lzo_int64l_t\n#  define lzo_uintptr_t             lzo_uint64l_t\n#  define LZO_SIZEOF_LZO_INTPTR_T   LZO_SIZEOF_LZO_INT64L_T\n#  define LZO_TYPEOF_LZO_INTPTR_T   LZO_TYPEOF_LZO_INT64L_T\n#else\n#  error \"lzo_intptr_t\"\n#endif\n#endif\n#if 1\n    LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_intptr_t) >= sizeof(void *))\n    LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_intptr_t) == sizeof(lzo_uintptr_t))\n#endif\n#if !defined(lzo_word_t)\n#if defined(LZO_WORDSIZE) && (LZO_WORDSIZE+0 > 0)\n#if (LZO_WORDSIZE == LZO_SIZEOF_LZO_INTPTR_T) && !(__LZO_INTPTR_T_IS_POINTER)\n#  define lzo_word_t                lzo_uintptr_t\n#  define lzo_sword_t               lzo_intptr_t\n#  define LZO_SIZEOF_LZO_WORD_T     LZO_SIZEOF_LZO_INTPTR_T\n#  define LZO_TYPEOF_LZO_WORD_T     LZO_TYPEOF_LZO_INTPTR_T\n#elif (LZO_WORDSIZE == LZO_SIZEOF_LONG)\n#  define lzo_word_t                unsigned long\n#  define lzo_sword_t               long\n#  define LZO_SIZEOF_LZO_WORD_T     LZO_SIZEOF_LONG\n#  define LZO_TYPEOF_LZO_WORD_T     LZO_TYPEOF_LONG\n#elif (LZO_WORDSIZE == LZO_SIZEOF_INT)\n#  define lzo_word_t                unsigned int\n#  define lzo_sword_t               int\n#  define LZO_SIZEOF_LZO_WORD_T     LZO_SIZEOF_INT\n#  define LZO_TYPEOF_LZO_WORD_T     LZO_TYPEOF_INT\n#elif (LZO_WORDSIZE == LZO_SIZEOF_SHORT)\n#  define lzo_word_t                unsigned short\n#  define lzo_sword_t               short\n#  define LZO_SIZEOF_LZO_WORD_T     LZO_SIZEOF_SHORT\n#  define LZO_TYPEOF_LZO_WORD_T     LZO_TYPEOF_SHORT\n#elif (LZO_WORDSIZE == 1)\n#  define lzo_word_t                unsigned char\n#  define lzo_sword_t               signed char\n#  define LZO_SIZEOF_LZO_WORD_T     1\n#  define LZO_TYPEOF_LZO_WORD_T     LZO_TYPEOF_CHAR\n#elif (LZO_WORDSIZE == LZO_SIZEOF_LZO_INT64L_T)\n#  define lzo_word_t                lzo_uint64l_t\n#  define lzo_sword_t               lzo_int64l_t\n#  define LZO_SIZEOF_LZO_WORD_T     LZO_SIZEOF_LZO_INT64L_T\n#  define LZO_TYPEOF_LZO_WORD_T     LZO_SIZEOF_LZO_INT64L_T\n#elif (LZO_ARCH_SPU) && (LZO_CC_GNUC)\n#if 0\n   typedef unsigned lzo_word_t  __attribute__((__mode__(__V16QI__)));\n   typedef int      lzo_sword_t __attribute__((__mode__(__V16QI__)));\n#  define lzo_word_t                lzo_word_t\n#  define lzo_sword_t               lzo_sword_t\n#  define LZO_SIZEOF_LZO_WORD_T     16\n#  define LZO_TYPEOF_LZO_WORD_T     LZO_TYPEOF___MODE_V16QI\n#endif\n#else\n#  error \"lzo_word_t\"\n#endif\n#endif\n#endif\n#if 1 && defined(lzo_word_t)\n    LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_word_t)  == LZO_WORDSIZE)\n    LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_sword_t) == LZO_WORDSIZE)\n#endif\n#if 1\n#define lzo_int8_t                  signed char\n#define lzo_uint8_t                 unsigned char\n#define LZO_SIZEOF_LZO_INT8_T       1\n#define LZO_TYPEOF_LZO_INT8_T       LZO_TYPEOF_CHAR\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == 1)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == sizeof(lzo_uint8_t))\n#endif\n#if defined(lzo_int16e_t)\n#define lzo_int16_t                 lzo_int16e_t\n#define lzo_uint16_t                lzo_uint16e_t\n#define LZO_SIZEOF_LZO_INT16_T      LZO_SIZEOF_LZO_INT16E_T\n#define LZO_TYPEOF_LZO_INT16_T      LZO_TYPEOF_LZO_INT16E_T\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == 2)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == sizeof(lzo_uint16_t))\n#endif\n#if defined(lzo_int32e_t)\n#define lzo_int32_t                 lzo_int32e_t\n#define lzo_uint32_t                lzo_uint32e_t\n#define LZO_SIZEOF_LZO_INT32_T      LZO_SIZEOF_LZO_INT32E_T\n#define LZO_TYPEOF_LZO_INT32_T      LZO_TYPEOF_LZO_INT32E_T\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == 4)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == sizeof(lzo_uint32_t))\n#endif\n#if defined(lzo_int64e_t)\n#define lzo_int64_t                 lzo_int64e_t\n#define lzo_uint64_t                lzo_uint64e_t\n#define LZO_SIZEOF_LZO_INT64_T      LZO_SIZEOF_LZO_INT64E_T\n#define LZO_TYPEOF_LZO_INT64_T      LZO_TYPEOF_LZO_INT64E_T\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == 8)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == sizeof(lzo_uint64_t))\n#endif\n#if 1\n#define lzo_int_least32_t           lzo_int32l_t\n#define lzo_uint_least32_t          lzo_uint32l_t\n#define LZO_SIZEOF_LZO_INT_LEAST32_T LZO_SIZEOF_LZO_INT32L_T\n#define LZO_TYPEOF_LZO_INT_LEAST32_T LZO_TYPEOF_LZO_INT32L_T\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least32_t) >= 4)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least32_t) == sizeof(lzo_uint_least32_t))\n#endif\n#if defined(lzo_int64l_t)\n#define lzo_int_least64_t           lzo_int64l_t\n#define lzo_uint_least64_t          lzo_uint64l_t\n#define LZO_SIZEOF_LZO_INT_LEAST64_T LZO_SIZEOF_LZO_INT64L_T\n#define LZO_TYPEOF_LZO_INT_LEAST64_T LZO_TYPEOF_LZO_INT64L_T\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least64_t) >= 8)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least64_t) == sizeof(lzo_uint_least64_t))\n#endif\n#if 1\n#define lzo_int_fast32_t           lzo_int32f_t\n#define lzo_uint_fast32_t          lzo_uint32f_t\n#define LZO_SIZEOF_LZO_INT_FAST32_T LZO_SIZEOF_LZO_INT32F_T\n#define LZO_TYPEOF_LZO_INT_FAST32_T LZO_TYPEOF_LZO_INT32F_T\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast32_t) >= 4)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast32_t) == sizeof(lzo_uint_fast32_t))\n#endif\n#if defined(lzo_int64f_t)\n#define lzo_int_fast64_t           lzo_int64f_t\n#define lzo_uint_fast64_t          lzo_uint64f_t\n#define LZO_SIZEOF_LZO_INT_FAST64_T LZO_SIZEOF_LZO_INT64F_T\n#define LZO_TYPEOF_LZO_INT_FAST64_T LZO_TYPEOF_LZO_INT64F_T\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) >= 8)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) == sizeof(lzo_uint_fast64_t))\n#endif\n#if !defined(LZO_INT16_C)\n#  if (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_INT >= 2)\n#    define LZO_INT16_C(c)          ((c) + 0)\n#    define LZO_UINT16_C(c)         ((c) + 0U)\n#  elif (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_LONG >= 2)\n#    define LZO_INT16_C(c)          ((c) + 0L)\n#    define LZO_UINT16_C(c)         ((c) + 0UL)\n#  elif (LZO_SIZEOF_INT >= 2)\n#    define LZO_INT16_C(c)          (c)\n#    define LZO_UINT16_C(c)         (c##U)\n#  elif (LZO_SIZEOF_LONG >= 2)\n#    define LZO_INT16_C(c)          (c##L)\n#    define LZO_UINT16_C(c)         (c##UL)\n#  else\n#    error \"LZO_INT16_C\"\n#  endif\n#endif\n#if !defined(LZO_INT32_C)\n#  if (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_INT >= 4)\n#    define LZO_INT32_C(c)          ((c) + 0)\n#    define LZO_UINT32_C(c)         ((c) + 0U)\n#  elif (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_LONG >= 4)\n#    define LZO_INT32_C(c)          ((c) + 0L)\n#    define LZO_UINT32_C(c)         ((c) + 0UL)\n#  elif (LZO_SIZEOF_INT >= 4)\n#    define LZO_INT32_C(c)          (c)\n#    define LZO_UINT32_C(c)         (c##U)\n#  elif (LZO_SIZEOF_LONG >= 4)\n#    define LZO_INT32_C(c)          (c##L)\n#    define LZO_UINT32_C(c)         (c##UL)\n#  elif (LZO_SIZEOF_LONG_LONG >= 4)\n#    define LZO_INT32_C(c)          (c##LL)\n#    define LZO_UINT32_C(c)         (c##ULL)\n#  else\n#    error \"LZO_INT32_C\"\n#  endif\n#endif\n#if !defined(LZO_INT64_C) && defined(lzo_int64l_t)\n#  if (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_INT >= 8)\n#    define LZO_INT64_C(c)          ((c) + 0)\n#    define LZO_UINT64_C(c)         ((c) + 0U)\n#  elif (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_LONG >= 8)\n#    define LZO_INT64_C(c)          ((c) + 0L)\n#    define LZO_UINT64_C(c)         ((c) + 0UL)\n#  elif (LZO_SIZEOF_INT >= 8)\n#    define LZO_INT64_C(c)          (c)\n#    define LZO_UINT64_C(c)         (c##U)\n#  elif (LZO_SIZEOF_LONG >= 8)\n#    define LZO_INT64_C(c)          (c##L)\n#    define LZO_UINT64_C(c)         (c##UL)\n#  else\n#    error \"LZO_INT64_C\"\n#  endif\n#endif\n#endif\n\n#endif\n\n#endif\n\n#undef LZO_HAVE_CONFIG_H\n#include \"minilzo.h\"\n\n#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x2090)\n#  error \"version mismatch in miniLZO source files\"\n#endif\n\n#ifdef MINILZO_HAVE_CONFIG_H\n#  define LZO_HAVE_CONFIG_H 1\n#endif\n\n#ifndef __LZO_CONF_H\n#define __LZO_CONF_H 1\n\n#if !defined(__LZO_IN_MINILZO)\n#if defined(LZO_CFG_FREESTANDING) && (LZO_CFG_FREESTANDING)\n#  define LZO_LIBC_FREESTANDING 1\n#  define LZO_OS_FREESTANDING 1\n#endif\n#if defined(LZO_CFG_EXTRA_CONFIG_HEADER)\n#  include LZO_CFG_EXTRA_CONFIG_HEADER\n#endif\n#if defined(__LZOCONF_H) || defined(__LZOCONF_H_INCLUDED)\n#  error \"include this file first\"\n#endif\n#if defined(LZO_CFG_BUILD_DLL) && (LZO_CFG_BUILD_DLL+0) && !defined(__LZO_EXPORT1) && !defined(__LZO_EXPORT2) && 0\n#ifndef __LZODEFS_H_INCLUDED\n#if defined(LZO_HAVE_CONFIG_H)\n#  include <config.h>\n#endif\n#include <limits.h>\n#include <stddef.h>\n#include <lzo/lzodefs.h>\n#endif\n#endif\n#include <lzo/lzoconf.h>\n#if defined(LZO_CFG_EXTRA_CONFIG_HEADER2)\n#  include LZO_CFG_EXTRA_CONFIG_HEADER2\n#endif\n#endif\n\n#if !defined(__LZOCONF_H_INCLUDED) || (LZO_VERSION+0 != 0x2090)\n#  error \"version mismatch\"\n#endif\n\n#if (LZO_CC_MSC && (_MSC_VER >= 1000 && _MSC_VER < 1100))\n#  pragma warning(disable: 4702)\n#endif\n#if (LZO_CC_MSC && (_MSC_VER >= 1000))\n#  pragma warning(disable: 4127 4701)\n#  pragma warning(disable: 4514 4710 4711)\n#endif\n#if (LZO_CC_MSC && (_MSC_VER >= 1300))\n#  pragma warning(disable: 4820)\n#endif\n#if (LZO_CC_MSC && (_MSC_VER >= 1800))\n#  pragma warning(disable: 4746)\n#endif\n#if (LZO_CC_INTELC && (__INTEL_COMPILER >= 900))\n#  pragma warning(disable: 1684)\n#endif\n\n#if (LZO_CC_SUNPROC)\n#if !defined(__cplusplus)\n#  pragma error_messages(off,E_END_OF_LOOP_CODE_NOT_REACHED)\n#  pragma error_messages(off,E_LOOP_NOT_ENTERED_AT_TOP)\n#  pragma error_messages(off,E_STATEMENT_NOT_REACHED)\n#endif\n#endif\n\n#if !defined(__LZO_NOEXPORT1)\n#  define __LZO_NOEXPORT1       /*empty*/\n#endif\n#if !defined(__LZO_NOEXPORT2)\n#  define __LZO_NOEXPORT2       /*empty*/\n#endif\n\n#if 1\n#  define LZO_PUBLIC_DECL(r)    LZO_EXTERN(r)\n#endif\n#if 1\n#  define LZO_PUBLIC_IMPL(r)    LZO_PUBLIC(r)\n#endif\n#if !defined(LZO_LOCAL_DECL)\n#  define LZO_LOCAL_DECL(r)     __LZO_EXTERN_C LZO_LOCAL_IMPL(r)\n#endif\n#if !defined(LZO_LOCAL_IMPL)\n#  define LZO_LOCAL_IMPL(r)     __LZO_NOEXPORT1 r __LZO_NOEXPORT2 __LZO_CDECL\n#endif\n#if 1\n#  define LZO_STATIC_DECL(r)    LZO_PRIVATE(r)\n#endif\n#if 1\n#  define LZO_STATIC_IMPL(r)    LZO_PRIVATE(r)\n#endif\n\n#if defined(__LZO_IN_MINILZO) || (LZO_CFG_FREESTANDING)\n#elif 1\n#  include <string.h>\n#else\n#  define LZO_WANT_ACC_INCD_H 1\n#endif\n#if defined(LZO_HAVE_CONFIG_H)\n#  define LZO_CFG_NO_CONFIG_HEADER 1\n#endif\n\n#if 1 && !defined(LZO_CFG_FREESTANDING)\n#if 1 && !defined(HAVE_STRING_H)\n#define HAVE_STRING_H 1\n#endif\n#if 1 && !defined(HAVE_MEMCMP)\n#define HAVE_MEMCMP 1\n#endif\n#if 1 && !defined(HAVE_MEMCPY)\n#define HAVE_MEMCPY 1\n#endif\n#if 1 && !defined(HAVE_MEMMOVE)\n#define HAVE_MEMMOVE 1\n#endif\n#if 1 && !defined(HAVE_MEMSET)\n#define HAVE_MEMSET 1\n#endif\n#endif\n\n#if 1 && defined(HAVE_STRING_H)\n#include <string.h>\n#endif\n\n#if 1 || defined(lzo_int8_t) || defined(lzo_uint8_t)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t)  == 1)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint8_t) == 1)\n#endif\n#if 1 || defined(lzo_int16_t) || defined(lzo_uint16_t)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t)  == 2)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint16_t) == 2)\n#endif\n#if 1 || defined(lzo_int32_t) || defined(lzo_uint32_t)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t)  == 4)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint32_t) == 4)\n#endif\n#if defined(lzo_int64_t) || defined(lzo_uint64_t)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t)  == 8)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint64_t) == 8)\n#endif\n\n#if (LZO_CFG_FREESTANDING)\n#  undef HAVE_MEMCMP\n#  undef HAVE_MEMCPY\n#  undef HAVE_MEMMOVE\n#  undef HAVE_MEMSET\n#endif\n\n#if !(HAVE_MEMCMP)\n#  undef memcmp\n#  define memcmp(a,b,c)         lzo_memcmp(a,b,c)\n#else\n#  undef lzo_memcmp\n#  define lzo_memcmp(a,b,c)     memcmp(a,b,c)\n#endif\n#if !(HAVE_MEMCPY)\n#  undef memcpy\n#  define memcpy(a,b,c)         lzo_memcpy(a,b,c)\n#else\n#  undef lzo_memcpy\n#  define lzo_memcpy(a,b,c)     memcpy(a,b,c)\n#endif\n#if !(HAVE_MEMMOVE)\n#  undef memmove\n#  define memmove(a,b,c)        lzo_memmove(a,b,c)\n#else\n#  undef lzo_memmove\n#  define lzo_memmove(a,b,c)    memmove(a,b,c)\n#endif\n#if !(HAVE_MEMSET)\n#  undef memset\n#  define memset(a,b,c)         lzo_memset(a,b,c)\n#else\n#  undef lzo_memset\n#  define lzo_memset(a,b,c)     memset(a,b,c)\n#endif\n\n#undef NDEBUG\n#if (LZO_CFG_FREESTANDING)\n#  undef LZO_DEBUG\n#  define NDEBUG 1\n#  undef assert\n#  define assert(e) ((void)0)\n#else\n#  if !defined(LZO_DEBUG)\n#    define NDEBUG 1\n#  endif\n#  include <assert.h>\n#endif\n\n#if 0 && defined(__BOUNDS_CHECKING_ON)\n#  include <unchecked.h>\n#else\n#  define BOUNDS_CHECKING_OFF_DURING(stmt)      stmt\n#  define BOUNDS_CHECKING_OFF_IN_EXPR(expr)     (expr)\n#endif\n\n#if (LZO_CFG_PGO)\n#  undef __lzo_likely\n#  undef __lzo_unlikely\n#  define __lzo_likely(e)       (e)\n#  define __lzo_unlikely(e)     (e)\n#endif\n\n#undef _\n#undef __\n#undef ___\n#undef ____\n#undef _p0\n#undef _p1\n#undef _p2\n#undef _p3\n#undef _p4\n#undef _s0\n#undef _s1\n#undef _s2\n#undef _s3\n#undef _s4\n#undef _ww\n\n#if 1\n#  define LZO_BYTE(x)       ((unsigned char) (x))\n#else\n#  define LZO_BYTE(x)       ((unsigned char) ((x) & 0xff))\n#endif\n\n#define LZO_MAX(a,b)        ((a) >= (b) ? (a) : (b))\n#define LZO_MIN(a,b)        ((a) <= (b) ? (a) : (b))\n#define LZO_MAX3(a,b,c)     ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c))\n#define LZO_MIN3(a,b,c)     ((a) <= (b) ? LZO_MIN(a,c) : LZO_MIN(b,c))\n\n#define lzo_sizeof(type)    ((lzo_uint) (sizeof(type)))\n\n#define LZO_HIGH(array)     ((lzo_uint) (sizeof(array)/sizeof(*(array))))\n\n#define LZO_SIZE(bits)      (1u << (bits))\n#define LZO_MASK(bits)      (LZO_SIZE(bits) - 1)\n\n#define LZO_USIZE(bits)     ((lzo_uint) 1 << (bits))\n#define LZO_UMASK(bits)     (LZO_USIZE(bits) - 1)\n\n#if !defined(DMUL)\n#if 0\n\n#  define DMUL(a,b) ((lzo_xint) ((lzo_uint32_t)(a) * (lzo_uint32_t)(b)))\n#else\n#  define DMUL(a,b) ((lzo_xint) ((a) * (b)))\n#endif\n#endif\n\n#ifndef __LZO_FUNC_H\n#define __LZO_FUNC_H 1\n\n#if !defined(LZO_BITOPS_USE_ASM_BITSCAN) && !defined(LZO_BITOPS_USE_GNUC_BITSCAN) && !defined(LZO_BITOPS_USE_MSC_BITSCAN)\n#if 1 && (LZO_ARCH_AMD64) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_ASM_SYNTAX_GNUC)\n#define LZO_BITOPS_USE_ASM_BITSCAN 1\n#elif (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x030400ul) || (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_LLVM && (!defined(__llvm_tools_version__) || (__llvm_tools_version__+0 >= 0x010500ul))))\n#define LZO_BITOPS_USE_GNUC_BITSCAN 1\n#elif (LZO_OS_WIN32 || LZO_OS_WIN64) && ((LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 1010)) || (LZO_CC_MSC && (_MSC_VER >= 1400)))\n#define LZO_BITOPS_USE_MSC_BITSCAN 1\n#if (LZO_CC_MSC) && (LZO_ARCH_AMD64 || LZO_ARCH_I386)\n#include <intrin.h>\n#endif\n#if (LZO_CC_MSC) && (LZO_ARCH_AMD64 || LZO_ARCH_I386)\n#pragma intrinsic(_BitScanReverse)\n#pragma intrinsic(_BitScanForward)\n#endif\n#if (LZO_CC_MSC) && (LZO_ARCH_AMD64)\n#pragma intrinsic(_BitScanReverse64)\n#pragma intrinsic(_BitScanForward64)\n#endif\n#endif\n#endif\n\n__lzo_static_forceinline unsigned lzo_bitops_ctlz32_func(lzo_uint32_t v)\n{\n#if (LZO_BITOPS_USE_MSC_BITSCAN) && (LZO_ARCH_AMD64 || LZO_ARCH_I386)\n    unsigned long r; (void) _BitScanReverse(&r, v); return (unsigned) r ^ 31;\n#define lzo_bitops_ctlz32(v)    lzo_bitops_ctlz32_func(v)\n#elif (LZO_BITOPS_USE_ASM_BITSCAN) && (LZO_ARCH_AMD64 || LZO_ARCH_I386) && (LZO_ASM_SYNTAX_GNUC)\n    lzo_uint32_t r;\n    __asm__(\"bsr %1,%0\" : \"=r\" (r) : \"rm\" (v) __LZO_ASM_CLOBBER_LIST_CC);\n    return (unsigned) r ^ 31;\n#define lzo_bitops_ctlz32(v)    lzo_bitops_ctlz32_func(v)\n#elif (LZO_BITOPS_USE_GNUC_BITSCAN) && (LZO_SIZEOF_INT == 4)\n    unsigned r; r = (unsigned) __builtin_clz(v); return r;\n#define lzo_bitops_ctlz32(v)    ((unsigned) __builtin_clz(v))\n#elif (LZO_BITOPS_USE_GNUC_BITSCAN) && (LZO_SIZEOF_LONG == 8) && (LZO_WORDSIZE >= 8)\n    unsigned r; r = (unsigned) __builtin_clzl(v); return r ^ 32;\n#define lzo_bitops_ctlz32(v)    (((unsigned) __builtin_clzl(v)) ^ 32)\n#else\n    LZO_UNUSED(v); return 0;\n#endif\n}\n\n#if defined(lzo_uint64_t)\n__lzo_static_forceinline unsigned lzo_bitops_ctlz64_func(lzo_uint64_t v)\n{\n#if (LZO_BITOPS_USE_MSC_BITSCAN) && (LZO_ARCH_AMD64)\n    unsigned long r; (void) _BitScanReverse64(&r, v); return (unsigned) r ^ 63;\n#define lzo_bitops_ctlz64(v)    lzo_bitops_ctlz64_func(v)\n#elif (LZO_BITOPS_USE_ASM_BITSCAN) && (LZO_ARCH_AMD64) && (LZO_ASM_SYNTAX_GNUC)\n    lzo_uint64_t r;\n    __asm__(\"bsr %1,%0\" : \"=r\" (r) : \"rm\" (v) __LZO_ASM_CLOBBER_LIST_CC);\n    return (unsigned) r ^ 63;\n#define lzo_bitops_ctlz64(v)    lzo_bitops_ctlz64_func(v)\n#elif (LZO_BITOPS_USE_GNUC_BITSCAN) && (LZO_SIZEOF_LONG == 8) && (LZO_WORDSIZE >= 8)\n    unsigned r; r = (unsigned) __builtin_clzl(v); return r;\n#define lzo_bitops_ctlz64(v)    ((unsigned) __builtin_clzl(v))\n#elif (LZO_BITOPS_USE_GNUC_BITSCAN) && (LZO_SIZEOF_LONG_LONG == 8) && (LZO_WORDSIZE >= 8)\n    unsigned r; r = (unsigned) __builtin_clzll(v); return r;\n#define lzo_bitops_ctlz64(v)    ((unsigned) __builtin_clzll(v))\n#else\n    LZO_UNUSED(v); return 0;\n#endif\n}\n#endif\n\n__lzo_static_forceinline unsigned lzo_bitops_cttz32_func(lzo_uint32_t v)\n{\n#if (LZO_BITOPS_USE_MSC_BITSCAN) && (LZO_ARCH_AMD64 || LZO_ARCH_I386)\n    unsigned long r; (void) _BitScanForward(&r, v); return (unsigned) r;\n#define lzo_bitops_cttz32(v)    lzo_bitops_cttz32_func(v)\n#elif (LZO_BITOPS_USE_ASM_BITSCAN) && (LZO_ARCH_AMD64 || LZO_ARCH_I386) && (LZO_ASM_SYNTAX_GNUC)\n    lzo_uint32_t r;\n    __asm__(\"bsf %1,%0\" : \"=r\" (r) : \"rm\" (v) __LZO_ASM_CLOBBER_LIST_CC);\n    return (unsigned) r;\n#define lzo_bitops_cttz32(v)    lzo_bitops_cttz32_func(v)\n#elif (LZO_BITOPS_USE_GNUC_BITSCAN) && (LZO_SIZEOF_INT >= 4)\n    unsigned r; r = (unsigned) __builtin_ctz(v); return r;\n#define lzo_bitops_cttz32(v)    ((unsigned) __builtin_ctz(v))\n#else\n    LZO_UNUSED(v); return 0;\n#endif\n}\n\n#if defined(lzo_uint64_t)\n__lzo_static_forceinline unsigned lzo_bitops_cttz64_func(lzo_uint64_t v)\n{\n#if (LZO_BITOPS_USE_MSC_BITSCAN) && (LZO_ARCH_AMD64)\n    unsigned long r; (void) _BitScanForward64(&r, v); return (unsigned) r;\n#define lzo_bitops_cttz64(v)    lzo_bitops_cttz64_func(v)\n#elif (LZO_BITOPS_USE_ASM_BITSCAN) && (LZO_ARCH_AMD64) && (LZO_ASM_SYNTAX_GNUC)\n    lzo_uint64_t r;\n    __asm__(\"bsf %1,%0\" : \"=r\" (r) : \"rm\" (v) __LZO_ASM_CLOBBER_LIST_CC);\n    return (unsigned) r;\n#define lzo_bitops_cttz64(v)    lzo_bitops_cttz64_func(v)\n#elif (LZO_BITOPS_USE_GNUC_BITSCAN) && (LZO_SIZEOF_LONG >= 8) && (LZO_WORDSIZE >= 8)\n    unsigned r; r = (unsigned) __builtin_ctzl(v); return r;\n#define lzo_bitops_cttz64(v)    ((unsigned) __builtin_ctzl(v))\n#elif (LZO_BITOPS_USE_GNUC_BITSCAN) && (LZO_SIZEOF_LONG_LONG >= 8) && (LZO_WORDSIZE >= 8)\n    unsigned r; r = (unsigned) __builtin_ctzll(v); return r;\n#define lzo_bitops_cttz64(v)    ((unsigned) __builtin_ctzll(v))\n#else\n    LZO_UNUSED(v); return 0;\n#endif\n}\n#endif\n\nlzo_unused_funcs_impl(void, lzo_bitops_unused_funcs)(void)\n{\n    LZO_UNUSED_FUNC(lzo_bitops_unused_funcs);\n    LZO_UNUSED_FUNC(lzo_bitops_ctlz32_func);\n    LZO_UNUSED_FUNC(lzo_bitops_cttz32_func);\n#if defined(lzo_uint64_t)\n    LZO_UNUSED_FUNC(lzo_bitops_ctlz64_func);\n    LZO_UNUSED_FUNC(lzo_bitops_cttz64_func);\n#endif\n}\n\n#if defined(__lzo_alignof) && !(LZO_CFG_NO_UNALIGNED)\n#if !defined(lzo_memops_tcheck__) && 0\n#define lzo_memops_tcheck__(t,a,b) ((void)0, sizeof(t) == (a) && __lzo_alignof(t) == (b))\n#endif\n#endif\n#ifndef lzo_memops_TU0p\n#define lzo_memops_TU0p void __LZO_MMODEL *\n#endif\n#ifndef lzo_memops_TU1p\n#define lzo_memops_TU1p unsigned char __LZO_MMODEL *\n#endif\n#ifndef lzo_memops_TU2p\n#if (LZO_OPT_UNALIGNED16)\ntypedef lzo_uint16_t __lzo_may_alias lzo_memops_TU2;\n#define lzo_memops_TU2p volatile lzo_memops_TU2 *\n#elif defined(__lzo_byte_struct)\n__lzo_byte_struct(lzo_memops_TU2_struct,2)\ntypedef struct lzo_memops_TU2_struct lzo_memops_TU2;\n#else\nstruct lzo_memops_TU2_struct { unsigned char a[2]; } __lzo_may_alias;\ntypedef struct lzo_memops_TU2_struct lzo_memops_TU2;\n#endif\n#ifndef lzo_memops_TU2p\n#define lzo_memops_TU2p lzo_memops_TU2 *\n#endif\n#endif\n#ifndef lzo_memops_TU4p\n#if (LZO_OPT_UNALIGNED32)\ntypedef lzo_uint32_t __lzo_may_alias lzo_memops_TU4;\n#define lzo_memops_TU4p volatile lzo_memops_TU4 __LZO_MMODEL *\n#elif defined(__lzo_byte_struct)\n__lzo_byte_struct(lzo_memops_TU4_struct,4)\ntypedef struct lzo_memops_TU4_struct lzo_memops_TU4;\n#else\nstruct lzo_memops_TU4_struct { unsigned char a[4]; } __lzo_may_alias;\ntypedef struct lzo_memops_TU4_struct lzo_memops_TU4;\n#endif\n#ifndef lzo_memops_TU4p\n#define lzo_memops_TU4p lzo_memops_TU4 __LZO_MMODEL *\n#endif\n#endif\n#ifndef lzo_memops_TU8p\n#if (LZO_OPT_UNALIGNED64)\ntypedef lzo_uint64_t __lzo_may_alias lzo_memops_TU8;\n#define lzo_memops_TU8p volatile lzo_memops_TU8 __LZO_MMODEL *\n#elif defined(__lzo_byte_struct)\n__lzo_byte_struct(lzo_memops_TU8_struct,8)\ntypedef struct lzo_memops_TU8_struct lzo_memops_TU8;\n#else\nstruct lzo_memops_TU8_struct { unsigned char a[8]; } __lzo_may_alias;\ntypedef struct lzo_memops_TU8_struct lzo_memops_TU8;\n#endif\n#ifndef lzo_memops_TU8p\n#define lzo_memops_TU8p lzo_memops_TU8 __LZO_MMODEL *\n#endif\n#endif\n#ifndef lzo_memops_set_TU1p\n#define lzo_memops_set_TU1p     volatile lzo_memops_TU1p\n#endif\n#ifndef lzo_memops_move_TU1p\n#define lzo_memops_move_TU1p    lzo_memops_TU1p\n#endif\n#define LZO_MEMOPS_SET1(dd,cc) \\\n    LZO_BLOCK_BEGIN \\\n    lzo_memops_set_TU1p d__1 = (lzo_memops_set_TU1p) (lzo_memops_TU0p) (dd); \\\n    d__1[0] = LZO_BYTE(cc); \\\n    LZO_BLOCK_END\n#define LZO_MEMOPS_SET2(dd,cc) \\\n    LZO_BLOCK_BEGIN \\\n    lzo_memops_set_TU1p d__2 = (lzo_memops_set_TU1p) (lzo_memops_TU0p) (dd); \\\n    d__2[0] = LZO_BYTE(cc); d__2[1] = LZO_BYTE(cc); \\\n    LZO_BLOCK_END\n#define LZO_MEMOPS_SET3(dd,cc) \\\n    LZO_BLOCK_BEGIN \\\n    lzo_memops_set_TU1p d__3 = (lzo_memops_set_TU1p) (lzo_memops_TU0p) (dd); \\\n    d__3[0] = LZO_BYTE(cc); d__3[1] = LZO_BYTE(cc); d__3[2] = LZO_BYTE(cc); \\\n    LZO_BLOCK_END\n#define LZO_MEMOPS_SET4(dd,cc) \\\n    LZO_BLOCK_BEGIN \\\n    lzo_memops_set_TU1p d__4 = (lzo_memops_set_TU1p) (lzo_memops_TU0p) (dd); \\\n    d__4[0] = LZO_BYTE(cc); d__4[1] = LZO_BYTE(cc); d__4[2] = LZO_BYTE(cc); d__4[3] = LZO_BYTE(cc); \\\n    LZO_BLOCK_END\n#define LZO_MEMOPS_MOVE1(dd,ss) \\\n    LZO_BLOCK_BEGIN \\\n    lzo_memops_move_TU1p d__1 = (lzo_memops_move_TU1p) (lzo_memops_TU0p) (dd); \\\n    const lzo_memops_move_TU1p s__1 = (const lzo_memops_move_TU1p) (const lzo_memops_TU0p) (ss); \\\n    d__1[0] = s__1[0]; \\\n    LZO_BLOCK_END\n#define LZO_MEMOPS_MOVE2(dd,ss) \\\n    LZO_BLOCK_BEGIN \\\n    lzo_memops_move_TU1p d__2 = (lzo_memops_move_TU1p) (lzo_memops_TU0p) (dd); \\\n    const lzo_memops_move_TU1p s__2 = (const lzo_memops_move_TU1p) (const lzo_memops_TU0p) (ss); \\\n    d__2[0] = s__2[0]; d__2[1] = s__2[1]; \\\n    LZO_BLOCK_END\n#define LZO_MEMOPS_MOVE3(dd,ss) \\\n    LZO_BLOCK_BEGIN \\\n    lzo_memops_move_TU1p d__3 = (lzo_memops_move_TU1p) (lzo_memops_TU0p) (dd); \\\n    const lzo_memops_move_TU1p s__3 = (const lzo_memops_move_TU1p) (const lzo_memops_TU0p) (ss); \\\n    d__3[0] = s__3[0]; d__3[1] = s__3[1]; d__3[2] = s__3[2]; \\\n    LZO_BLOCK_END\n#define LZO_MEMOPS_MOVE4(dd,ss) \\\n    LZO_BLOCK_BEGIN \\\n    lzo_memops_move_TU1p d__4 = (lzo_memops_move_TU1p) (lzo_memops_TU0p) (dd); \\\n    const lzo_memops_move_TU1p s__4 = (const lzo_memops_move_TU1p) (const lzo_memops_TU0p) (ss); \\\n    d__4[0] = s__4[0]; d__4[1] = s__4[1]; d__4[2] = s__4[2]; d__4[3] = s__4[3]; \\\n    LZO_BLOCK_END\n#define LZO_MEMOPS_MOVE8(dd,ss) \\\n    LZO_BLOCK_BEGIN \\\n    lzo_memops_move_TU1p d__8 = (lzo_memops_move_TU1p) (lzo_memops_TU0p) (dd); \\\n    const lzo_memops_move_TU1p s__8 = (const lzo_memops_move_TU1p) (const lzo_memops_TU0p) (ss); \\\n    d__8[0] = s__8[0]; d__8[1] = s__8[1]; d__8[2] = s__8[2]; d__8[3] = s__8[3]; \\\n    d__8[4] = s__8[4]; d__8[5] = s__8[5]; d__8[6] = s__8[6]; d__8[7] = s__8[7]; \\\n    LZO_BLOCK_END\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU1p)0)==1)\n#define LZO_MEMOPS_COPY1(dd,ss) LZO_MEMOPS_MOVE1(dd,ss)\n#if (LZO_OPT_UNALIGNED16)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU2p)0)==2)\n#define LZO_MEMOPS_COPY2(dd,ss) \\\n    * (lzo_memops_TU2p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss)\n#elif defined(lzo_memops_tcheck__)\n#define LZO_MEMOPS_COPY2(dd,ss) \\\n    LZO_BLOCK_BEGIN if (lzo_memops_tcheck__(lzo_memops_TU2,2,1)) { \\\n        * (lzo_memops_TU2p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss); \\\n    } else { LZO_MEMOPS_MOVE2(dd,ss); } LZO_BLOCK_END\n#else\n#define LZO_MEMOPS_COPY2(dd,ss) LZO_MEMOPS_MOVE2(dd,ss)\n#endif\n#if (LZO_OPT_UNALIGNED32)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU4p)0)==4)\n#define LZO_MEMOPS_COPY4(dd,ss) \\\n    * (lzo_memops_TU4p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU4p) (const lzo_memops_TU0p) (ss)\n#elif defined(lzo_memops_tcheck__)\n#define LZO_MEMOPS_COPY4(dd,ss) \\\n    LZO_BLOCK_BEGIN if (lzo_memops_tcheck__(lzo_memops_TU4,4,1)) { \\\n        * (lzo_memops_TU4p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU4p) (const lzo_memops_TU0p) (ss); \\\n    } else { LZO_MEMOPS_MOVE4(dd,ss); } LZO_BLOCK_END\n#else\n#define LZO_MEMOPS_COPY4(dd,ss) LZO_MEMOPS_MOVE4(dd,ss)\n#endif\n#if (LZO_WORDSIZE != 8)\n#define LZO_MEMOPS_COPY8(dd,ss) \\\n    LZO_BLOCK_BEGIN LZO_MEMOPS_COPY4(dd,ss); LZO_MEMOPS_COPY4((lzo_memops_TU1p)(lzo_memops_TU0p)(dd)+4,(const lzo_memops_TU1p)(const lzo_memops_TU0p)(ss)+4); LZO_BLOCK_END\n#else\n#if (LZO_OPT_UNALIGNED64)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU8p)0)==8)\n#define LZO_MEMOPS_COPY8(dd,ss) \\\n    * (lzo_memops_TU8p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU8p) (const lzo_memops_TU0p) (ss)\n#elif (LZO_OPT_UNALIGNED32)\n#define LZO_MEMOPS_COPY8(dd,ss) \\\n    LZO_BLOCK_BEGIN LZO_MEMOPS_COPY4(dd,ss); LZO_MEMOPS_COPY4((lzo_memops_TU1p)(lzo_memops_TU0p)(dd)+4,(const lzo_memops_TU1p)(const lzo_memops_TU0p)(ss)+4); LZO_BLOCK_END\n#elif defined(lzo_memops_tcheck__)\n#define LZO_MEMOPS_COPY8(dd,ss) \\\n    LZO_BLOCK_BEGIN if (lzo_memops_tcheck__(lzo_memops_TU8,8,1)) { \\\n        * (lzo_memops_TU8p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU8p) (const lzo_memops_TU0p) (ss); \\\n    } else { LZO_MEMOPS_MOVE8(dd,ss); } LZO_BLOCK_END\n#else\n#define LZO_MEMOPS_COPY8(dd,ss) LZO_MEMOPS_MOVE8(dd,ss)\n#endif\n#endif\n#define LZO_MEMOPS_COPYN(dd,ss,nn) \\\n    LZO_BLOCK_BEGIN \\\n    lzo_memops_TU1p d__n = (lzo_memops_TU1p) (lzo_memops_TU0p) (dd); \\\n    const lzo_memops_TU1p s__n = (const lzo_memops_TU1p) (const lzo_memops_TU0p) (ss); \\\n    lzo_uint n__n = (nn); \\\n    while ((void)0, n__n >= 8) { LZO_MEMOPS_COPY8(d__n, s__n); d__n += 8; s__n += 8; n__n -= 8; } \\\n    if ((void)0, n__n >= 4) { LZO_MEMOPS_COPY4(d__n, s__n); d__n += 4; s__n += 4; n__n -= 4; } \\\n    if ((void)0, n__n > 0) do { *d__n++ = *s__n++; } while (--n__n > 0); \\\n    LZO_BLOCK_END\n\n__lzo_static_forceinline lzo_uint16_t lzo_memops_get_le16(const lzo_voidp ss)\n{\n    lzo_uint16_t v;\n#if (LZO_ABI_LITTLE_ENDIAN)\n    LZO_MEMOPS_COPY2(&v, ss);\n#elif (LZO_OPT_UNALIGNED16 && LZO_ARCH_POWERPC && LZO_ABI_BIG_ENDIAN) && (LZO_ASM_SYNTAX_GNUC)\n    const lzo_memops_TU2p s = (const lzo_memops_TU2p) ss;\n    unsigned long vv;\n    __asm__(\"lhbrx %0,0,%1\" : \"=r\" (vv) : \"r\" (s), \"m\" (*s));\n    v = (lzo_uint16_t) vv;\n#else\n    const lzo_memops_TU1p s = (const lzo_memops_TU1p) ss;\n    v = (lzo_uint16_t) (((lzo_uint16_t)s[0]) | ((lzo_uint16_t)s[1] << 8));\n#endif\n    return v;\n}\n#if (LZO_OPT_UNALIGNED16) && (LZO_ABI_LITTLE_ENDIAN)\n#define LZO_MEMOPS_GET_LE16(ss)    (* (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss))\n#else\n#define LZO_MEMOPS_GET_LE16(ss)    lzo_memops_get_le16(ss)\n#endif\n\n__lzo_static_forceinline lzo_uint32_t lzo_memops_get_le32(const lzo_voidp ss)\n{\n    lzo_uint32_t v;\n#if (LZO_ABI_LITTLE_ENDIAN)\n    LZO_MEMOPS_COPY4(&v, ss);\n#elif (LZO_OPT_UNALIGNED32 && LZO_ARCH_POWERPC && LZO_ABI_BIG_ENDIAN) && (LZO_ASM_SYNTAX_GNUC)\n    const lzo_memops_TU4p s = (const lzo_memops_TU4p) ss;\n    unsigned long vv;\n    __asm__(\"lwbrx %0,0,%1\" : \"=r\" (vv) : \"r\" (s), \"m\" (*s));\n    v = (lzo_uint32_t) vv;\n#else\n    const lzo_memops_TU1p s = (const lzo_memops_TU1p) ss;\n    v = (lzo_uint32_t) (((lzo_uint32_t)s[0]) | ((lzo_uint32_t)s[1] << 8) | ((lzo_uint32_t)s[2] << 16) | ((lzo_uint32_t)s[3] << 24));\n#endif\n    return v;\n}\n#if (LZO_OPT_UNALIGNED32) && (LZO_ABI_LITTLE_ENDIAN)\n#define LZO_MEMOPS_GET_LE32(ss)    (* (const lzo_memops_TU4p) (const lzo_memops_TU0p) (ss))\n#else\n#define LZO_MEMOPS_GET_LE32(ss)    lzo_memops_get_le32(ss)\n#endif\n\n#if (LZO_OPT_UNALIGNED64) && (LZO_ABI_LITTLE_ENDIAN)\n#define LZO_MEMOPS_GET_LE64(ss)    (* (const lzo_memops_TU8p) (const lzo_memops_TU0p) (ss))\n#endif\n\n__lzo_static_forceinline lzo_uint16_t lzo_memops_get_ne16(const lzo_voidp ss)\n{\n    lzo_uint16_t v;\n    LZO_MEMOPS_COPY2(&v, ss);\n    return v;\n}\n#if (LZO_OPT_UNALIGNED16)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU2p)0)==2)\n#define LZO_MEMOPS_GET_NE16(ss)    (* (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss))\n#else\n#define LZO_MEMOPS_GET_NE16(ss)    lzo_memops_get_ne16(ss)\n#endif\n\n__lzo_static_forceinline lzo_uint32_t lzo_memops_get_ne32(const lzo_voidp ss)\n{\n    lzo_uint32_t v;\n    LZO_MEMOPS_COPY4(&v, ss);\n    return v;\n}\n#if (LZO_OPT_UNALIGNED32)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU4p)0)==4)\n#define LZO_MEMOPS_GET_NE32(ss)    (* (const lzo_memops_TU4p) (const lzo_memops_TU0p) (ss))\n#else\n#define LZO_MEMOPS_GET_NE32(ss)    lzo_memops_get_ne32(ss)\n#endif\n\n#if (LZO_OPT_UNALIGNED64)\nLZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU8p)0)==8)\n#define LZO_MEMOPS_GET_NE64(ss)    (* (const lzo_memops_TU8p) (const lzo_memops_TU0p) (ss))\n#endif\n\n__lzo_static_forceinline void lzo_memops_put_le16(lzo_voidp dd, lzo_uint16_t vv)\n{\n#if (LZO_ABI_LITTLE_ENDIAN)\n    LZO_MEMOPS_COPY2(dd, &vv);\n#elif (LZO_OPT_UNALIGNED16 && LZO_ARCH_POWERPC && LZO_ABI_BIG_ENDIAN) && (LZO_ASM_SYNTAX_GNUC)\n    lzo_memops_TU2p d = (lzo_memops_TU2p) dd;\n    unsigned long v = vv;\n    __asm__(\"sthbrx %2,0,%1\" : \"=m\" (*d) : \"r\" (d), \"r\" (v));\n#else\n    lzo_memops_TU1p d = (lzo_memops_TU1p) dd;\n    d[0] = LZO_BYTE((vv      ) & 0xff);\n    d[1] = LZO_BYTE((vv >>  8) & 0xff);\n#endif\n}\n#if (LZO_OPT_UNALIGNED16) && (LZO_ABI_LITTLE_ENDIAN)\n#define LZO_MEMOPS_PUT_LE16(dd,vv) (* (lzo_memops_TU2p) (lzo_memops_TU0p) (dd) = (vv))\n#else\n#define LZO_MEMOPS_PUT_LE16(dd,vv) lzo_memops_put_le16(dd,vv)\n#endif\n\n__lzo_static_forceinline void lzo_memops_put_le32(lzo_voidp dd, lzo_uint32_t vv)\n{\n#if (LZO_ABI_LITTLE_ENDIAN)\n    LZO_MEMOPS_COPY4(dd, &vv);\n#elif (LZO_OPT_UNALIGNED32 && LZO_ARCH_POWERPC && LZO_ABI_BIG_ENDIAN) && (LZO_ASM_SYNTAX_GNUC)\n    lzo_memops_TU4p d = (lzo_memops_TU4p) dd;\n    unsigned long v = vv;\n    __asm__(\"stwbrx %2,0,%1\" : \"=m\" (*d) : \"r\" (d), \"r\" (v));\n#else\n    lzo_memops_TU1p d = (lzo_memops_TU1p) dd;\n    d[0] = LZO_BYTE((vv      ) & 0xff);\n    d[1] = LZO_BYTE((vv >>  8) & 0xff);\n    d[2] = LZO_BYTE((vv >> 16) & 0xff);\n    d[3] = LZO_BYTE((vv >> 24) & 0xff);\n#endif\n}\n#if (LZO_OPT_UNALIGNED32) && (LZO_ABI_LITTLE_ENDIAN)\n#define LZO_MEMOPS_PUT_LE32(dd,vv) (* (lzo_memops_TU4p) (lzo_memops_TU0p) (dd) = (vv))\n#else\n#define LZO_MEMOPS_PUT_LE32(dd,vv) lzo_memops_put_le32(dd,vv)\n#endif\n\n__lzo_static_forceinline void lzo_memops_put_ne16(lzo_voidp dd, lzo_uint16_t vv)\n{\n    LZO_MEMOPS_COPY2(dd, &vv);\n}\n#if (LZO_OPT_UNALIGNED16)\n#define LZO_MEMOPS_PUT_NE16(dd,vv) (* (lzo_memops_TU2p) (lzo_memops_TU0p) (dd) = (vv))\n#else\n#define LZO_MEMOPS_PUT_NE16(dd,vv) lzo_memops_put_ne16(dd,vv)\n#endif\n\n__lzo_static_forceinline void lzo_memops_put_ne32(lzo_voidp dd, lzo_uint32_t vv)\n{\n    LZO_MEMOPS_COPY4(dd, &vv);\n}\n#if (LZO_OPT_UNALIGNED32)\n#define LZO_MEMOPS_PUT_NE32(dd,vv) (* (lzo_memops_TU4p) (lzo_memops_TU0p) (dd) = (vv))\n#else\n#define LZO_MEMOPS_PUT_NE32(dd,vv) lzo_memops_put_ne32(dd,vv)\n#endif\n\nlzo_unused_funcs_impl(void, lzo_memops_unused_funcs)(void)\n{\n    LZO_UNUSED_FUNC(lzo_memops_unused_funcs);\n    LZO_UNUSED_FUNC(lzo_memops_get_le16);\n    LZO_UNUSED_FUNC(lzo_memops_get_le32);\n    LZO_UNUSED_FUNC(lzo_memops_get_ne16);\n    LZO_UNUSED_FUNC(lzo_memops_get_ne32);\n    LZO_UNUSED_FUNC(lzo_memops_put_le16);\n    LZO_UNUSED_FUNC(lzo_memops_put_le32);\n    LZO_UNUSED_FUNC(lzo_memops_put_ne16);\n    LZO_UNUSED_FUNC(lzo_memops_put_ne32);\n}\n\n#endif\n\n#ifndef UA_SET1\n#define UA_SET1             LZO_MEMOPS_SET1\n#endif\n#ifndef UA_SET2\n#define UA_SET2             LZO_MEMOPS_SET2\n#endif\n#ifndef UA_SET3\n#define UA_SET3             LZO_MEMOPS_SET3\n#endif\n#ifndef UA_SET4\n#define UA_SET4             LZO_MEMOPS_SET4\n#endif\n#ifndef UA_MOVE1\n#define UA_MOVE1            LZO_MEMOPS_MOVE1\n#endif\n#ifndef UA_MOVE2\n#define UA_MOVE2            LZO_MEMOPS_MOVE2\n#endif\n#ifndef UA_MOVE3\n#define UA_MOVE3            LZO_MEMOPS_MOVE3\n#endif\n#ifndef UA_MOVE4\n#define UA_MOVE4            LZO_MEMOPS_MOVE4\n#endif\n#ifndef UA_MOVE8\n#define UA_MOVE8            LZO_MEMOPS_MOVE8\n#endif\n#ifndef UA_COPY1\n#define UA_COPY1            LZO_MEMOPS_COPY1\n#endif\n#ifndef UA_COPY2\n#define UA_COPY2            LZO_MEMOPS_COPY2\n#endif\n#ifndef UA_COPY3\n#define UA_COPY3            LZO_MEMOPS_COPY3\n#endif\n#ifndef UA_COPY4\n#define UA_COPY4            LZO_MEMOPS_COPY4\n#endif\n#ifndef UA_COPY8\n#define UA_COPY8            LZO_MEMOPS_COPY8\n#endif\n#ifndef UA_COPYN\n#define UA_COPYN            LZO_MEMOPS_COPYN\n#endif\n#ifndef UA_COPYN_X\n#define UA_COPYN_X          LZO_MEMOPS_COPYN\n#endif\n#ifndef UA_GET_LE16\n#define UA_GET_LE16         LZO_MEMOPS_GET_LE16\n#endif\n#ifndef UA_GET_LE32\n#define UA_GET_LE32         LZO_MEMOPS_GET_LE32\n#endif\n#ifdef LZO_MEMOPS_GET_LE64\n#ifndef UA_GET_LE64\n#define UA_GET_LE64         LZO_MEMOPS_GET_LE64\n#endif\n#endif\n#ifndef UA_GET_NE16\n#define UA_GET_NE16         LZO_MEMOPS_GET_NE16\n#endif\n#ifndef UA_GET_NE32\n#define UA_GET_NE32         LZO_MEMOPS_GET_NE32\n#endif\n#ifdef LZO_MEMOPS_GET_NE64\n#ifndef UA_GET_NE64\n#define UA_GET_NE64         LZO_MEMOPS_GET_NE64\n#endif\n#endif\n#ifndef UA_PUT_LE16\n#define UA_PUT_LE16         LZO_MEMOPS_PUT_LE16\n#endif\n#ifndef UA_PUT_LE32\n#define UA_PUT_LE32         LZO_MEMOPS_PUT_LE32\n#endif\n#ifndef UA_PUT_NE16\n#define UA_PUT_NE16         LZO_MEMOPS_PUT_NE16\n#endif\n#ifndef UA_PUT_NE32\n#define UA_PUT_NE32         LZO_MEMOPS_PUT_NE32\n#endif\n\n#define MEMCPY8_DS(dest,src,len) \\\n    lzo_memcpy(dest,src,len); dest += len; src += len\n\n#define BZERO8_PTR(s,l,n) \\\n    lzo_memset((lzo_voidp)(s),0,(lzo_uint)(l)*(n))\n\n#define MEMCPY_DS(dest,src,len) \\\n    do *dest++ = *src++; while (--len > 0)\n\nLZO_EXTERN(const lzo_bytep) lzo_copyright(void);\n\n#ifndef __LZO_PTR_H\n#define __LZO_PTR_H 1\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if (LZO_ARCH_I086)\n#error \"LZO_ARCH_I086 is unsupported\"\n#elif (LZO_MM_PVP)\n#error \"LZO_MM_PVP is unsupported\"\n#else\n#define PTR(a)              ((lzo_uintptr_t) (a))\n#define PTR_LINEAR(a)       PTR(a)\n#define PTR_ALIGNED_4(a)    ((PTR_LINEAR(a) & 3) == 0)\n#define PTR_ALIGNED_8(a)    ((PTR_LINEAR(a) & 7) == 0)\n#define PTR_ALIGNED2_4(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 3) == 0)\n#define PTR_ALIGNED2_8(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 7) == 0)\n#endif\n\n#define PTR_LT(a,b)         (PTR(a) < PTR(b))\n#define PTR_GE(a,b)         (PTR(a) >= PTR(b))\n#define PTR_DIFF(a,b)       (PTR(a) - PTR(b))\n#define pd(a,b)             ((lzo_uint) ((a)-(b)))\n\nLZO_EXTERN(lzo_uintptr_t)\n__lzo_ptr_linear(const lzo_voidp ptr);\n\ntypedef union\n{\n    char            a_char;\n    unsigned char   a_uchar;\n    short           a_short;\n    unsigned short  a_ushort;\n    int             a_int;\n    unsigned int    a_uint;\n    long            a_long;\n    unsigned long   a_ulong;\n    lzo_int         a_lzo_int;\n    lzo_uint        a_lzo_uint;\n    lzo_xint        a_lzo_xint;\n    lzo_int16_t     a_lzo_int16_t;\n    lzo_uint16_t    a_lzo_uint16_t;\n    lzo_int32_t     a_lzo_int32_t;\n    lzo_uint32_t    a_lzo_uint32_t;\n#if defined(lzo_uint64_t)\n    lzo_int64_t     a_lzo_int64_t;\n    lzo_uint64_t    a_lzo_uint64_t;\n#endif\n    size_t          a_size_t;\n    ptrdiff_t       a_ptrdiff_t;\n    lzo_uintptr_t   a_lzo_uintptr_t;\n    void *          a_void_p;\n    char *          a_char_p;\n    unsigned char * a_uchar_p;\n    const void *          a_c_void_p;\n    const char *          a_c_char_p;\n    const unsigned char * a_c_uchar_p;\n    lzo_voidp       a_lzo_voidp;\n    lzo_bytep       a_lzo_bytep;\n    const lzo_voidp a_c_lzo_voidp;\n    const lzo_bytep a_c_lzo_bytep;\n}\nlzo_full_align_t;\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n\n#ifndef LZO_DETERMINISTIC\n#define LZO_DETERMINISTIC 1\n#endif\n\n#ifndef LZO_DICT_USE_PTR\n#define LZO_DICT_USE_PTR 1\n#endif\n\n#if (LZO_DICT_USE_PTR)\n#  define lzo_dict_t    const lzo_bytep\n#  define lzo_dict_p    lzo_dict_t *\n#else\n#  define lzo_dict_t    lzo_uint\n#  define lzo_dict_p    lzo_dict_t *\n#endif\n\n#endif\n\n#if !defined(MINILZO_CFG_SKIP_LZO_PTR)\n\nLZO_PUBLIC(lzo_uintptr_t)\n__lzo_ptr_linear(const lzo_voidp ptr)\n{\n    lzo_uintptr_t p;\n\n#if (LZO_ARCH_I086)\n#error \"LZO_ARCH_I086 is unsupported\"\n#elif (LZO_MM_PVP)\n#error \"LZO_MM_PVP is unsupported\"\n#else\n    p = (lzo_uintptr_t) PTR_LINEAR(ptr);\n#endif\n\n    return p;\n}\n\nLZO_PUBLIC(unsigned)\n__lzo_align_gap(const lzo_voidp ptr, lzo_uint size)\n{\n#if (__LZO_UINTPTR_T_IS_POINTER)\n#error \"__LZO_UINTPTR_T_IS_POINTER is unsupported\"\n#else\n    lzo_uintptr_t p, n;\n    if (size < 2) return 0;\n    p = __lzo_ptr_linear(ptr);\n#if 0\n    n = (((p + size - 1) / size) * size) - p;\n#else\n    if ((size & (size - 1)) != 0)\n        return 0;\n    n = size; n = ((p + n - 1) & ~(n - 1)) - p;\n#endif\n#endif\n    assert((long)n >= 0);\n    assert(n <= size);\n    return (unsigned)n;\n}\n\n#endif\n#if !defined(MINILZO_CFG_SKIP_LZO_UTIL)\n\n/* If you use the LZO library in a product, I would appreciate that you\n * keep this copyright string in the executable of your product.\n */\n\nstatic const char lzo_copyright_[] =\n#if !defined(__LZO_IN_MINLZO)\n    LZO_VERSION_STRING;\n#else\n    \"\\r\\n\\n\"\n    \"LZO data compression library.\\n\"\n    \"$Copyright: LZO Copyright (C) 1996-2015 Markus Franz Xaver Johannes Oberhumer\\n\"\n    \"<markus@oberhumer.com>\\n\"\n    \"http://www.oberhumer.com $\\n\\n\"\n    \"$Id: LZO version: v\" LZO_VERSION_STRING \", \" LZO_VERSION_DATE \" $\\n\"\n    \"$Info: \" LZO_INFO_STRING \" $\\n\";\n#endif\nstatic const char lzo_version_string_[] = LZO_VERSION_STRING;\nstatic const char lzo_version_date_[] = LZO_VERSION_DATE;\n\nLZO_PUBLIC(const lzo_bytep)\nlzo_copyright(void)\n{\n    return (const lzo_bytep) lzo_copyright_;\n}\n\nLZO_PUBLIC(unsigned)\nlzo_version(void)\n{\n    return LZO_VERSION;\n}\n\nLZO_PUBLIC(const char *)\nlzo_version_string(void)\n{\n    return lzo_version_string_;\n}\n\nLZO_PUBLIC(const char *)\nlzo_version_date(void)\n{\n    return lzo_version_date_;\n}\n\nLZO_PUBLIC(const lzo_charp)\n_lzo_version_string(void)\n{\n    return lzo_version_string_;\n}\n\nLZO_PUBLIC(const lzo_charp)\n_lzo_version_date(void)\n{\n    return lzo_version_date_;\n}\n\n#define LZO_BASE 65521u\n#define LZO_NMAX 5552\n\n#define LZO_DO1(buf,i)  s1 += buf[i]; s2 += s1\n#define LZO_DO2(buf,i)  LZO_DO1(buf,i); LZO_DO1(buf,i+1)\n#define LZO_DO4(buf,i)  LZO_DO2(buf,i); LZO_DO2(buf,i+2)\n#define LZO_DO8(buf,i)  LZO_DO4(buf,i); LZO_DO4(buf,i+4)\n#define LZO_DO16(buf,i) LZO_DO8(buf,i); LZO_DO8(buf,i+8)\n\nLZO_PUBLIC(lzo_uint32_t)\nlzo_adler32(lzo_uint32_t adler, const lzo_bytep buf, lzo_uint len)\n{\n    lzo_uint32_t s1 = adler & 0xffff;\n    lzo_uint32_t s2 = (adler >> 16) & 0xffff;\n    unsigned k;\n\n    if (buf == NULL)\n        return 1;\n\n    while (len > 0)\n    {\n        k = len < LZO_NMAX ? (unsigned) len : LZO_NMAX;\n        len -= k;\n        if (k >= 16) do\n        {\n            LZO_DO16(buf,0);\n            buf += 16;\n            k -= 16;\n        } while (k >= 16);\n        if (k != 0) do\n        {\n            s1 += *buf++;\n            s2 += s1;\n        } while (--k > 0);\n        s1 %= LZO_BASE;\n        s2 %= LZO_BASE;\n    }\n    return (s2 << 16) | s1;\n}\n\n#undef LZO_DO1\n#undef LZO_DO2\n#undef LZO_DO4\n#undef LZO_DO8\n#undef LZO_DO16\n\n#endif\n#if !defined(MINILZO_CFG_SKIP_LZO_STRING)\n#undef lzo_memcmp\n#undef lzo_memcpy\n#undef lzo_memmove\n#undef lzo_memset\n#if !defined(__LZO_MMODEL_HUGE)\n#  undef LZO_HAVE_MM_HUGE_PTR\n#endif\n#define lzo_hsize_t             lzo_uint\n#define lzo_hvoid_p             lzo_voidp\n#define lzo_hbyte_p             lzo_bytep\n#define LZOLIB_PUBLIC(r,f)      LZO_PUBLIC(r) f\n#define lzo_hmemcmp             lzo_memcmp\n#define lzo_hmemcpy             lzo_memcpy\n#define lzo_hmemmove            lzo_memmove\n#define lzo_hmemset             lzo_memset\n#define __LZOLIB_HMEMCPY_CH_INCLUDED 1\n#if !defined(LZOLIB_PUBLIC)\n#  define LZOLIB_PUBLIC(r,f)    r __LZOLIB_FUNCNAME(f)\n#endif\nLZOLIB_PUBLIC(int, lzo_hmemcmp) (const lzo_hvoid_p s1, const lzo_hvoid_p s2, lzo_hsize_t len)\n{\n#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMCMP)\n    const lzo_hbyte_p p1 = LZO_STATIC_CAST(const lzo_hbyte_p, s1);\n    const lzo_hbyte_p p2 = LZO_STATIC_CAST(const lzo_hbyte_p, s2);\n    if __lzo_likely(len > 0) do\n    {\n        int d = *p1 - *p2;\n        if (d != 0)\n            return d;\n        p1++; p2++;\n    } while __lzo_likely(--len > 0);\n    return 0;\n#else\n    return memcmp(s1, s2, len);\n#endif\n}\nLZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemcpy) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len)\n{\n#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMCPY)\n    lzo_hbyte_p p1 = LZO_STATIC_CAST(lzo_hbyte_p, dest);\n    const lzo_hbyte_p p2 = LZO_STATIC_CAST(const lzo_hbyte_p, src);\n    if (!(len > 0) || p1 == p2)\n        return dest;\n    do\n        *p1++ = *p2++;\n    while __lzo_likely(--len > 0);\n    return dest;\n#else\n    return memcpy(dest, src, len);\n#endif\n}\nLZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemmove) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len)\n{\n#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMMOVE)\n    lzo_hbyte_p p1 = LZO_STATIC_CAST(lzo_hbyte_p, dest);\n    const lzo_hbyte_p p2 = LZO_STATIC_CAST(const lzo_hbyte_p, src);\n    if (!(len > 0) || p1 == p2)\n        return dest;\n    if (p1 < p2)\n    {\n        do\n            *p1++ = *p2++;\n        while __lzo_likely(--len > 0);\n    }\n    else\n    {\n        p1 += len;\n        p2 += len;\n        do\n            *--p1 = *--p2;\n        while __lzo_likely(--len > 0);\n    }\n    return dest;\n#else\n    return memmove(dest, src, len);\n#endif\n}\nLZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemset) (lzo_hvoid_p s, int cc, lzo_hsize_t len)\n{\n#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMSET)\n    lzo_hbyte_p p = LZO_STATIC_CAST(lzo_hbyte_p, s);\n    unsigned char c = LZO_ITRUNC(unsigned char, cc);\n    if __lzo_likely(len > 0) do\n        *p++ = c;\n    while __lzo_likely(--len > 0);\n    return s;\n#else\n    return memset(s, cc, len);\n#endif\n}\n#undef LZOLIB_PUBLIC\n#endif\n#if !defined(MINILZO_CFG_SKIP_LZO_INIT)\n\n#if !defined(__LZO_IN_MINILZO)\n\n#define LZO_WANT_ACC_CHK_CH 1\n#undef LZOCHK_ASSERT\n\n    LZOCHK_ASSERT((LZO_UINT32_C(1) << (int)(8*sizeof(LZO_UINT32_C(1))-1)) > 0)\n    LZOCHK_ASSERT_IS_SIGNED_T(lzo_int)\n    LZOCHK_ASSERT_IS_UNSIGNED_T(lzo_uint)\n#if !(__LZO_UINTPTR_T_IS_POINTER)\n    LZOCHK_ASSERT_IS_UNSIGNED_T(lzo_uintptr_t)\n#endif\n    LZOCHK_ASSERT(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp))\n    LZOCHK_ASSERT_IS_UNSIGNED_T(lzo_xint)\n\n#endif\n#undef LZOCHK_ASSERT\n\nunion lzo_config_check_union {\n    lzo_uint a[2];\n    unsigned char b[2*LZO_MAX(8,sizeof(lzo_uint))];\n#if defined(lzo_uint64_t)\n    lzo_uint64_t c[2];\n#endif\n};\n\n#if 0\n#define u2p(ptr,off) ((lzo_voidp) (((lzo_bytep)(lzo_voidp)(ptr)) + (off)))\n#else\nstatic __lzo_noinline lzo_voidp u2p(lzo_voidp ptr, lzo_uint off)\n{\n    return (lzo_voidp) ((lzo_bytep) ptr + off);\n}\n#endif\n\nLZO_PUBLIC(int)\n_lzo_config_check(void)\n{\n#if (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x030100ul && LZO_CC_CLANG < 0x030300ul))\n# if 0\n    volatile\n# endif\n#endif\n    union lzo_config_check_union u;\n    lzo_voidp p;\n    unsigned r = 1;\n\n    u.a[0] = u.a[1] = 0;\n    p = u2p(&u, 0);\n    r &= ((* (lzo_bytep) p) == 0);\n#if !(LZO_CFG_NO_CONFIG_CHECK)\n#if (LZO_ABI_BIG_ENDIAN)\n    u.a[0] = u.a[1] = 0; u.b[sizeof(lzo_uint) - 1] = 128;\n    p = u2p(&u, 0);\n    r &= ((* (lzo_uintp) p) == 128);\n#endif\n#if (LZO_ABI_LITTLE_ENDIAN)\n    u.a[0] = u.a[1] = 0; u.b[0] = 128;\n    p = u2p(&u, 0);\n    r &= ((* (lzo_uintp) p) == 128);\n#endif\n    u.a[0] = u.a[1] = 0;\n    u.b[0] = 1; u.b[3] = 2;\n    p = u2p(&u, 1);\n    r &= UA_GET_NE16(p) == 0;\n    r &= UA_GET_LE16(p) == 0;\n    u.b[1] = 128;\n    r &= UA_GET_LE16(p) == 128;\n    u.b[2] = 129;\n    r &= UA_GET_LE16(p) == LZO_UINT16_C(0x8180);\n#if (LZO_ABI_BIG_ENDIAN)\n    r &= UA_GET_NE16(p) == LZO_UINT16_C(0x8081);\n#endif\n#if (LZO_ABI_LITTLE_ENDIAN)\n    r &= UA_GET_NE16(p) == LZO_UINT16_C(0x8180);\n#endif\n    u.a[0] = u.a[1] = 0;\n    u.b[0] = 3; u.b[5] = 4;\n    p = u2p(&u, 1);\n    r &= UA_GET_NE32(p) == 0;\n    r &= UA_GET_LE32(p) == 0;\n    u.b[1] = 128;\n    r &= UA_GET_LE32(p) == 128;\n    u.b[2] = 129; u.b[3] = 130; u.b[4] = 131;\n    r &= UA_GET_LE32(p) == LZO_UINT32_C(0x83828180);\n#if (LZO_ABI_BIG_ENDIAN)\n    r &= UA_GET_NE32(p) == LZO_UINT32_C(0x80818283);\n#endif\n#if (LZO_ABI_LITTLE_ENDIAN)\n    r &= UA_GET_NE32(p) == LZO_UINT32_C(0x83828180);\n#endif\n#if defined(UA_GET_NE64)\n    u.c[0] = u.c[1] = 0;\n    u.b[0] = 5; u.b[9] = 6;\n    p = u2p(&u, 1);\n    u.c[0] = u.c[1] = 0;\n    r &= UA_GET_NE64(p) == 0;\n#if defined(UA_GET_LE64)\n    r &= UA_GET_LE64(p) == 0;\n    u.b[1] = 128;\n    r &= UA_GET_LE64(p) == 128;\n#endif\n#endif\n#if defined(lzo_bitops_ctlz32)\n    { unsigned i = 0; lzo_uint32_t v;\n    for (v = 1; v != 0 && r == 1; v <<= 1, i++) {\n        r &= lzo_bitops_ctlz32(v) == 31 - i;\n        r &= lzo_bitops_ctlz32_func(v) == 31 - i;\n    }}\n#endif\n#if defined(lzo_bitops_ctlz64)\n    { unsigned i = 0; lzo_uint64_t v;\n    for (v = 1; v != 0 && r == 1; v <<= 1, i++) {\n        r &= lzo_bitops_ctlz64(v) == 63 - i;\n        r &= lzo_bitops_ctlz64_func(v) == 63 - i;\n    }}\n#endif\n#if defined(lzo_bitops_cttz32)\n    { unsigned i = 0; lzo_uint32_t v;\n    for (v = 1; v != 0 && r == 1; v <<= 1, i++) {\n        r &= lzo_bitops_cttz32(v) == i;\n        r &= lzo_bitops_cttz32_func(v) == i;\n    }}\n#endif\n#if defined(lzo_bitops_cttz64)\n    { unsigned i = 0; lzo_uint64_t v;\n    for (v = 1; v != 0 && r == 1; v <<= 1, i++) {\n        r &= lzo_bitops_cttz64(v) == i;\n        r &= lzo_bitops_cttz64_func(v) == i;\n    }}\n#endif\n#endif\n    LZO_UNUSED_FUNC(lzo_bitops_unused_funcs);\n\n    return r == 1 ? LZO_E_OK : LZO_E_ERROR;\n}\n\nLZO_PUBLIC(int)\n__lzo_init_v2(unsigned v, int s1, int s2, int s3, int s4, int s5,\n                          int s6, int s7, int s8, int s9)\n{\n    int r;\n\n#if defined(__LZO_IN_MINILZO)\n#elif (LZO_CC_MSC && ((_MSC_VER) < 700))\n#else\n#define LZO_WANT_ACC_CHK_CH 1\n#undef LZOCHK_ASSERT\n#define LZOCHK_ASSERT(expr)  LZO_COMPILE_TIME_ASSERT(expr)\n#endif\n#undef LZOCHK_ASSERT\n\n    if (v == 0)\n        return LZO_E_ERROR;\n\n    r = (s1 == -1 || s1 == (int) sizeof(short)) &&\n        (s2 == -1 || s2 == (int) sizeof(int)) &&\n        (s3 == -1 || s3 == (int) sizeof(long)) &&\n        (s4 == -1 || s4 == (int) sizeof(lzo_uint32_t)) &&\n        (s5 == -1 || s5 == (int) sizeof(lzo_uint)) &&\n        (s6 == -1 || s6 == (int) lzo_sizeof_dict_t) &&\n        (s7 == -1 || s7 == (int) sizeof(char *)) &&\n        (s8 == -1 || s8 == (int) sizeof(lzo_voidp)) &&\n        (s9 == -1 || s9 == (int) sizeof(lzo_callback_t));\n    if (!r)\n        return LZO_E_ERROR;\n\n    r = _lzo_config_check();\n    if (r != LZO_E_OK)\n        return r;\n\n    return r;\n}\n\n#if !defined(__LZO_IN_MINILZO)\n\n#if (LZO_OS_WIN16 && LZO_CC_WATCOMC) && defined(__SW_BD)\n\n#if 0\nBOOL FAR PASCAL LibMain ( HANDLE hInstance, WORD wDataSegment,\n                          WORD wHeapSize, LPSTR lpszCmdLine )\n#else\nint __far __pascal LibMain ( int a, short b, short c, long d )\n#endif\n{\n    LZO_UNUSED(a); LZO_UNUSED(b); LZO_UNUSED(c); LZO_UNUSED(d);\n    return 1;\n}\n\n#endif\n\n#endif\n\n#endif\n\n#define LZO1X           1\n#define LZO_EOF_CODE    1\n#define M2_MAX_OFFSET   0x0800\n\n#if !defined(MINILZO_CFG_SKIP_LZO1X_1_COMPRESS)\n\n#if 1 && defined(UA_GET_LE32)\n#undef  LZO_DICT_USE_PTR\n#define LZO_DICT_USE_PTR 0\n#undef  lzo_dict_t\n#define lzo_dict_t lzo_uint16_t\n#endif\n\n#define LZO_NEED_DICT_H 1\n#ifndef D_BITS\n#define D_BITS          14\n#endif\n#define D_INDEX1(d,p)       d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5)\n#define D_INDEX2(d,p)       d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f)\n#if 1\n#define DINDEX(dv,p)        DM(((DMUL(0x1824429d,dv)) >> (32-D_BITS)))\n#else\n#define DINDEX(dv,p)        DM((dv) + ((dv) >> (32-D_BITS)))\n#endif\n\n#ifndef __LZO_CONFIG1X_H\n#define __LZO_CONFIG1X_H 1\n\n#if !defined(LZO1X) && !defined(LZO1Y) && !defined(LZO1Z)\n#  define LZO1X 1\n#endif\n\n#if !defined(__LZO_IN_MINILZO)\n#include <lzo/lzo1x.h>\n#endif\n\n#ifndef LZO_EOF_CODE\n#define LZO_EOF_CODE 1\n#endif\n#undef LZO_DETERMINISTIC\n\n#define M1_MAX_OFFSET   0x0400\n#ifndef M2_MAX_OFFSET\n#define M2_MAX_OFFSET   0x0800\n#endif\n#define M3_MAX_OFFSET   0x4000\n#define M4_MAX_OFFSET   0xbfff\n\n#define MX_MAX_OFFSET   (M1_MAX_OFFSET + M2_MAX_OFFSET)\n\n#define M1_MIN_LEN      2\n#define M1_MAX_LEN      2\n#define M2_MIN_LEN      3\n#ifndef M2_MAX_LEN\n#define M2_MAX_LEN      8\n#endif\n#define M3_MIN_LEN      3\n#define M3_MAX_LEN      33\n#define M4_MIN_LEN      3\n#define M4_MAX_LEN      9\n\n#define M1_MARKER       0\n#define M2_MARKER       64\n#define M3_MARKER       32\n#define M4_MARKER       16\n\n#ifndef MIN_LOOKAHEAD\n#define MIN_LOOKAHEAD       (M2_MAX_LEN + 1)\n#endif\n\n#if defined(LZO_NEED_DICT_H)\n\n#ifndef LZO_HASH\n#define LZO_HASH            LZO_HASH_LZO_INCREMENTAL_B\n#endif\n#define DL_MIN_LEN          M2_MIN_LEN\n\n#ifndef __LZO_DICT_H\n#define __LZO_DICT_H 1\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if !defined(D_BITS) && defined(DBITS)\n#  define D_BITS        DBITS\n#endif\n#if !defined(D_BITS)\n#  error \"D_BITS is not defined\"\n#endif\n#if (D_BITS < 16)\n#  define D_SIZE        LZO_SIZE(D_BITS)\n#  define D_MASK        LZO_MASK(D_BITS)\n#else\n#  define D_SIZE        LZO_USIZE(D_BITS)\n#  define D_MASK        LZO_UMASK(D_BITS)\n#endif\n#define D_HIGH          ((D_MASK >> 1) + 1)\n\n#if !defined(DD_BITS)\n#  define DD_BITS       0\n#endif\n#define DD_SIZE         LZO_SIZE(DD_BITS)\n#define DD_MASK         LZO_MASK(DD_BITS)\n\n#if !defined(DL_BITS)\n#  define DL_BITS       (D_BITS - DD_BITS)\n#endif\n#if (DL_BITS < 16)\n#  define DL_SIZE       LZO_SIZE(DL_BITS)\n#  define DL_MASK       LZO_MASK(DL_BITS)\n#else\n#  define DL_SIZE       LZO_USIZE(DL_BITS)\n#  define DL_MASK       LZO_UMASK(DL_BITS)\n#endif\n\n#if (D_BITS != DL_BITS + DD_BITS)\n#  error \"D_BITS does not match\"\n#endif\n#if (D_BITS < 6 || D_BITS > 18)\n#  error \"invalid D_BITS\"\n#endif\n#if (DL_BITS < 6 || DL_BITS > 20)\n#  error \"invalid DL_BITS\"\n#endif\n#if (DD_BITS < 0 || DD_BITS > 6)\n#  error \"invalid DD_BITS\"\n#endif\n\n#if !defined(DL_MIN_LEN)\n#  define DL_MIN_LEN    3\n#endif\n#if !defined(DL_SHIFT)\n#  define DL_SHIFT      ((DL_BITS + (DL_MIN_LEN - 1)) / DL_MIN_LEN)\n#endif\n\n#define LZO_HASH_GZIP                   1\n#define LZO_HASH_GZIP_INCREMENTAL       2\n#define LZO_HASH_LZO_INCREMENTAL_A      3\n#define LZO_HASH_LZO_INCREMENTAL_B      4\n\n#if !defined(LZO_HASH)\n#  error \"choose a hashing strategy\"\n#endif\n\n#undef DM\n#undef DX\n\n#if (DL_MIN_LEN == 3)\n#  define _DV2_A(p,shift1,shift2) \\\n        (((( (lzo_xint)((p)[0]) << shift1) ^ (p)[1]) << shift2) ^ (p)[2])\n#  define _DV2_B(p,shift1,shift2) \\\n        (((( (lzo_xint)((p)[2]) << shift1) ^ (p)[1]) << shift2) ^ (p)[0])\n#  define _DV3_B(p,shift1,shift2,shift3) \\\n        ((_DV2_B((p)+1,shift1,shift2) << (shift3)) ^ (p)[0])\n#elif (DL_MIN_LEN == 2)\n#  define _DV2_A(p,shift1,shift2) \\\n        (( (lzo_xint)(p[0]) << shift1) ^ p[1])\n#  define _DV2_B(p,shift1,shift2) \\\n        (( (lzo_xint)(p[1]) << shift1) ^ p[2])\n#else\n#  error \"invalid DL_MIN_LEN\"\n#endif\n#define _DV_A(p,shift)      _DV2_A(p,shift,shift)\n#define _DV_B(p,shift)      _DV2_B(p,shift,shift)\n#define DA2(p,s1,s2) \\\n        (((((lzo_xint)((p)[2]) << (s2)) + (p)[1]) << (s1)) + (p)[0])\n#define DS2(p,s1,s2) \\\n        (((((lzo_xint)((p)[2]) << (s2)) - (p)[1]) << (s1)) - (p)[0])\n#define DX2(p,s1,s2) \\\n        (((((lzo_xint)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0])\n#define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0])\n#define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0])\n#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0])\n#define DMS(v,s)        ((lzo_uint) (((v) & (D_MASK >> (s))) << (s)))\n#define DM(v)           DMS(v,0)\n\n#if (LZO_HASH == LZO_HASH_GZIP)\n#  define _DINDEX(dv,p)     (_DV_A((p),DL_SHIFT))\n\n#elif (LZO_HASH == LZO_HASH_GZIP_INCREMENTAL)\n#  define __LZO_HASH_INCREMENTAL 1\n#  define DVAL_FIRST(dv,p)  dv = _DV_A((p),DL_SHIFT)\n#  define DVAL_NEXT(dv,p)   dv = (((dv) << DL_SHIFT) ^ p[2])\n#  define _DINDEX(dv,p)     (dv)\n#  define DVAL_LOOKAHEAD    DL_MIN_LEN\n\n#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_A)\n#  define __LZO_HASH_INCREMENTAL 1\n#  define DVAL_FIRST(dv,p)  dv = _DV_A((p),5)\n#  define DVAL_NEXT(dv,p) \\\n                dv ^= (lzo_xint)(p[-1]) << (2*5); dv = (((dv) << 5) ^ p[2])\n#  define _DINDEX(dv,p)     ((DMUL(0x9f5f,dv)) >> 5)\n#  define DVAL_LOOKAHEAD    DL_MIN_LEN\n\n#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_B)\n#  define __LZO_HASH_INCREMENTAL 1\n#  define DVAL_FIRST(dv,p)  dv = _DV_B((p),5)\n#  define DVAL_NEXT(dv,p) \\\n                dv ^= p[-1]; dv = (((dv) >> 5) ^ ((lzo_xint)(p[2]) << (2*5)))\n#  define _DINDEX(dv,p)     ((DMUL(0x9f5f,dv)) >> 5)\n#  define DVAL_LOOKAHEAD    DL_MIN_LEN\n\n#else\n#  error \"choose a hashing strategy\"\n#endif\n\n#ifndef DINDEX\n#define DINDEX(dv,p)        ((lzo_uint)((_DINDEX(dv,p)) & DL_MASK) << DD_BITS)\n#endif\n#if !defined(DINDEX1) && defined(D_INDEX1)\n#define DINDEX1             D_INDEX1\n#endif\n#if !defined(DINDEX2) && defined(D_INDEX2)\n#define DINDEX2             D_INDEX2\n#endif\n\n#if !defined(__LZO_HASH_INCREMENTAL)\n#  define DVAL_FIRST(dv,p)  ((void) 0)\n#  define DVAL_NEXT(dv,p)   ((void) 0)\n#  define DVAL_LOOKAHEAD    0\n#endif\n\n#if !defined(DVAL_ASSERT)\n#if defined(__LZO_HASH_INCREMENTAL) && !defined(NDEBUG)\n#if 1 && (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)\nstatic void __attribute__((__unused__))\n#else\nstatic void\n#endif\nDVAL_ASSERT(lzo_xint dv, const lzo_bytep p)\n{\n    lzo_xint df;\n    DVAL_FIRST(df,(p));\n    assert(DINDEX(dv,p) == DINDEX(df,p));\n}\n#else\n#  define DVAL_ASSERT(dv,p) ((void) 0)\n#endif\n#endif\n\n#if (LZO_DICT_USE_PTR)\n#  define DENTRY(p,in)                          (p)\n#  define GINDEX(m_pos,m_off,dict,dindex,in)    m_pos = dict[dindex]\n#else\n#  define DENTRY(p,in)                          ((lzo_dict_t) pd(p, in))\n#  define GINDEX(m_pos,m_off,dict,dindex,in)    m_off = dict[dindex]\n#endif\n\n#if (DD_BITS == 0)\n\n#  define UPDATE_D(dict,drun,dv,p,in)       dict[ DINDEX(dv,p) ] = DENTRY(p,in)\n#  define UPDATE_I(dict,drun,index,p,in)    dict[index] = DENTRY(p,in)\n#  define UPDATE_P(ptr,drun,p,in)           (ptr)[0] = DENTRY(p,in)\n\n#else\n\n#  define UPDATE_D(dict,drun,dv,p,in)   \\\n        dict[ DINDEX(dv,p) + drun++ ] = DENTRY(p,in); drun &= DD_MASK\n#  define UPDATE_I(dict,drun,index,p,in)    \\\n        dict[ (index) + drun++ ] = DENTRY(p,in); drun &= DD_MASK\n#  define UPDATE_P(ptr,drun,p,in)   \\\n        (ptr) [ drun++ ] = DENTRY(p,in); drun &= DD_MASK\n\n#endif\n\n#if (LZO_DICT_USE_PTR)\n\n#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \\\n        (m_pos == NULL || (m_off = pd(ip, m_pos)) > max_offset)\n\n#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \\\n    (BOUNDS_CHECKING_OFF_IN_EXPR(( \\\n        m_pos = ip - (lzo_uint) PTR_DIFF(ip,m_pos), \\\n        PTR_LT(m_pos,in) || \\\n        (m_off = (lzo_uint) PTR_DIFF(ip,m_pos)) == 0 || \\\n         m_off > max_offset )))\n\n#else\n\n#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \\\n        (m_off == 0 || \\\n         ((m_off = pd(ip, in) - m_off) > max_offset) || \\\n         (m_pos = (ip) - (m_off), 0) )\n\n#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \\\n        (pd(ip, in) <= m_off || \\\n         ((m_off = pd(ip, in) - m_off) > max_offset) || \\\n         (m_pos = (ip) - (m_off), 0) )\n\n#endif\n\n#if (LZO_DETERMINISTIC)\n#  define LZO_CHECK_MPOS    LZO_CHECK_MPOS_DET\n#else\n#  define LZO_CHECK_MPOS    LZO_CHECK_MPOS_NON_DET\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n\n#endif\n\n#endif\n\n#define LZO_DETERMINISTIC !(LZO_DICT_USE_PTR)\n\n#ifndef DO_COMPRESS\n#define DO_COMPRESS     lzo1x_1_compress\n#endif\n\n#if 1 && defined(DO_COMPRESS) && !defined(do_compress)\n#  define do_compress       LZO_PP_ECONCAT2(DO_COMPRESS,_core)\n#endif\n\nstatic __lzo_noinline lzo_uint\ndo_compress ( const lzo_bytep in , lzo_uint  in_len,\n                    lzo_bytep out, lzo_uintp out_len,\n                    lzo_uint  ti,  lzo_voidp wrkmem)\n{\n    const lzo_bytep ip;\n    lzo_bytep op;\n    const lzo_bytep const in_end = in + in_len;\n    const lzo_bytep const ip_end = in + in_len - 20;\n    const lzo_bytep ii;\n    lzo_dict_p const dict = (lzo_dict_p) wrkmem;\n\n    op = out;\n    ip = in;\n    ii = ip;\n\n    ip += ti < 4 ? 4 - ti : 0;\n    for (;;)\n    {\n        const lzo_bytep m_pos;\n#if !(LZO_DETERMINISTIC)\n        LZO_DEFINE_UNINITIALIZED_VAR(lzo_uint, m_off, 0);\n        lzo_uint m_len;\n        lzo_uint dindex;\nnext:\n        if __lzo_unlikely(ip >= ip_end)\n            break;\n        DINDEX1(dindex,ip);\n        GINDEX(m_pos,m_off,dict,dindex,in);\n        if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))\n            goto literal;\n#if 1\n        if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])\n            goto try_match;\n        DINDEX2(dindex,ip);\n#endif\n        GINDEX(m_pos,m_off,dict,dindex,in);\n        if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))\n            goto literal;\n        if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])\n            goto try_match;\n        goto literal;\n\ntry_match:\n#if (LZO_OPT_UNALIGNED32)\n        if (UA_GET_NE32(m_pos) != UA_GET_NE32(ip))\n#else\n        if (m_pos[0] != ip[0] || m_pos[1] != ip[1] || m_pos[2] != ip[2] || m_pos[3] != ip[3])\n#endif\n        {\nliteral:\n            UPDATE_I(dict,0,dindex,ip,in);\n            ip += 1 + ((ip - ii) >> 5);\n            continue;\n        }\n        UPDATE_I(dict,0,dindex,ip,in);\n#else\n        lzo_uint m_off;\n        lzo_uint m_len;\n        {\n        lzo_uint32_t dv;\n        lzo_uint dindex;\nliteral:\n        ip += 1 + ((ip - ii) >> 5);\nnext:\n        if __lzo_unlikely(ip >= ip_end)\n            break;\n        dv = UA_GET_LE32(ip);\n        dindex = DINDEX(dv,ip);\n        GINDEX(m_off,m_pos,in+dict,dindex,in);\n        UPDATE_I(dict,0,dindex,ip,in);\n        if __lzo_unlikely(dv != UA_GET_LE32(m_pos))\n            goto literal;\n        }\n#endif\n\n        ii -= ti; ti = 0;\n        {\n        lzo_uint t = pd(ip,ii);\n        if (t != 0)\n        {\n            if (t <= 3)\n            {\n                op[-2] = LZO_BYTE(op[-2] | t);\n#if (LZO_OPT_UNALIGNED32)\n                UA_COPY4(op, ii);\n                op += t;\n#else\n                { do *op++ = *ii++; while (--t > 0); }\n#endif\n            }\n#if (LZO_OPT_UNALIGNED32) || (LZO_OPT_UNALIGNED64)\n            else if (t <= 16)\n            {\n                *op++ = LZO_BYTE(t - 3);\n                UA_COPY8(op, ii);\n                UA_COPY8(op+8, ii+8);\n                op += t;\n            }\n#endif\n            else\n            {\n                if (t <= 18)\n                    *op++ = LZO_BYTE(t - 3);\n                else\n                {\n                    lzo_uint tt = t - 18;\n                    *op++ = 0;\n                    while __lzo_unlikely(tt > 255)\n                    {\n                        tt -= 255;\n                        UA_SET1(op, 0);\n                        op++;\n                    }\n                    assert(tt > 0);\n                    *op++ = LZO_BYTE(tt);\n                }\n#if (LZO_OPT_UNALIGNED32) || (LZO_OPT_UNALIGNED64)\n                do {\n                    UA_COPY8(op, ii);\n                    UA_COPY8(op+8, ii+8);\n                    op += 16; ii += 16; t -= 16;\n                } while (t >= 16); if (t > 0)\n#endif\n                { do *op++ = *ii++; while (--t > 0); }\n            }\n        }\n        }\n        m_len = 4;\n        {\n#if (LZO_OPT_UNALIGNED64)\n        lzo_uint64_t v;\n        v = UA_GET_NE64(ip + m_len) ^ UA_GET_NE64(m_pos + m_len);\n        if __lzo_unlikely(v == 0) {\n            do {\n                m_len += 8;\n                v = UA_GET_NE64(ip + m_len) ^ UA_GET_NE64(m_pos + m_len);\n                if __lzo_unlikely(ip + m_len >= ip_end)\n                    goto m_len_done;\n            } while (v == 0);\n        }\n#if (LZO_ABI_BIG_ENDIAN) && defined(lzo_bitops_ctlz64)\n        m_len += lzo_bitops_ctlz64(v) / CHAR_BIT;\n#elif (LZO_ABI_BIG_ENDIAN)\n        if ((v >> (64 - CHAR_BIT)) == 0) do {\n            v <<= CHAR_BIT;\n            m_len += 1;\n        } while ((v >> (64 - CHAR_BIT)) == 0);\n#elif (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_cttz64)\n        m_len += lzo_bitops_cttz64(v) / CHAR_BIT;\n#elif (LZO_ABI_LITTLE_ENDIAN)\n        if ((v & UCHAR_MAX) == 0) do {\n            v >>= CHAR_BIT;\n            m_len += 1;\n        } while ((v & UCHAR_MAX) == 0);\n#else\n        if (ip[m_len] == m_pos[m_len]) do {\n            m_len += 1;\n        } while (ip[m_len] == m_pos[m_len]);\n#endif\n#elif (LZO_OPT_UNALIGNED32)\n        lzo_uint32_t v;\n        v = UA_GET_NE32(ip + m_len) ^ UA_GET_NE32(m_pos + m_len);\n        if __lzo_unlikely(v == 0) {\n            do {\n                m_len += 4;\n                v = UA_GET_NE32(ip + m_len) ^ UA_GET_NE32(m_pos + m_len);\n                if (v != 0)\n                    break;\n                m_len += 4;\n                v = UA_GET_NE32(ip + m_len) ^ UA_GET_NE32(m_pos + m_len);\n                if __lzo_unlikely(ip + m_len >= ip_end)\n                    goto m_len_done;\n            } while (v == 0);\n        }\n#if (LZO_ABI_BIG_ENDIAN) && defined(lzo_bitops_ctlz32)\n        m_len += lzo_bitops_ctlz32(v) / CHAR_BIT;\n#elif (LZO_ABI_BIG_ENDIAN)\n        if ((v >> (32 - CHAR_BIT)) == 0) do {\n            v <<= CHAR_BIT;\n            m_len += 1;\n        } while ((v >> (32 - CHAR_BIT)) == 0);\n#elif (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_cttz32)\n        m_len += lzo_bitops_cttz32(v) / CHAR_BIT;\n#elif (LZO_ABI_LITTLE_ENDIAN)\n        if ((v & UCHAR_MAX) == 0) do {\n            v >>= CHAR_BIT;\n            m_len += 1;\n        } while ((v & UCHAR_MAX) == 0);\n#else\n        if (ip[m_len] == m_pos[m_len]) do {\n            m_len += 1;\n        } while (ip[m_len] == m_pos[m_len]);\n#endif\n#else\n        if __lzo_unlikely(ip[m_len] == m_pos[m_len]) {\n            do {\n                m_len += 1;\n                if (ip[m_len] != m_pos[m_len])\n                    break;\n                m_len += 1;\n                if (ip[m_len] != m_pos[m_len])\n                    break;\n                m_len += 1;\n                if (ip[m_len] != m_pos[m_len])\n                    break;\n                m_len += 1;\n                if (ip[m_len] != m_pos[m_len])\n                    break;\n                m_len += 1;\n                if (ip[m_len] != m_pos[m_len])\n                    break;\n                m_len += 1;\n                if (ip[m_len] != m_pos[m_len])\n                    break;\n                m_len += 1;\n                if (ip[m_len] != m_pos[m_len])\n                    break;\n                m_len += 1;\n                if __lzo_unlikely(ip + m_len >= ip_end)\n                    goto m_len_done;\n            } while (ip[m_len] == m_pos[m_len]);\n        }\n#endif\n        }\nm_len_done:\n        m_off = pd(ip,m_pos);\n        ip += m_len;\n        ii = ip;\n        if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET)\n        {\n            m_off -= 1;\n#if defined(LZO1X)\n            *op++ = LZO_BYTE(((m_len - 1) << 5) | ((m_off & 7) << 2));\n            *op++ = LZO_BYTE(m_off >> 3);\n#elif defined(LZO1Y)\n            *op++ = LZO_BYTE(((m_len + 1) << 4) | ((m_off & 3) << 2));\n            *op++ = LZO_BYTE(m_off >> 2);\n#endif\n        }\n        else if (m_off <= M3_MAX_OFFSET)\n        {\n            m_off -= 1;\n            if (m_len <= M3_MAX_LEN)\n                *op++ = LZO_BYTE(M3_MARKER | (m_len - 2));\n            else\n            {\n                m_len -= M3_MAX_LEN;\n                *op++ = M3_MARKER | 0;\n                while __lzo_unlikely(m_len > 255)\n                {\n                    m_len -= 255;\n                    UA_SET1(op, 0);\n                    op++;\n                }\n                *op++ = LZO_BYTE(m_len);\n            }\n            *op++ = LZO_BYTE(m_off << 2);\n            *op++ = LZO_BYTE(m_off >> 6);\n        }\n        else\n        {\n            m_off -= 0x4000;\n            if (m_len <= M4_MAX_LEN)\n                *op++ = LZO_BYTE(M4_MARKER | ((m_off >> 11) & 8) | (m_len - 2));\n            else\n            {\n                m_len -= M4_MAX_LEN;\n                *op++ = LZO_BYTE(M4_MARKER | ((m_off >> 11) & 8));\n                while __lzo_unlikely(m_len > 255)\n                {\n                    m_len -= 255;\n                    UA_SET1(op, 0);\n                    op++;\n                }\n                *op++ = LZO_BYTE(m_len);\n            }\n            *op++ = LZO_BYTE(m_off << 2);\n            *op++ = LZO_BYTE(m_off >> 6);\n        }\n        goto next;\n    }\n\n    *out_len = pd(op, out);\n    return pd(in_end,ii-ti);\n}\n\nLZO_PUBLIC(int)\nDO_COMPRESS      ( const lzo_bytep in , lzo_uint  in_len,\n                         lzo_bytep out, lzo_uintp out_len,\n                         lzo_voidp wrkmem )\n{\n    const lzo_bytep ip = in;\n    lzo_bytep op = out;\n    lzo_uint l = in_len;\n    lzo_uint t = 0;\n\n    while (l > 20)\n    {\n        lzo_uint ll = l;\n        lzo_uintptr_t ll_end;\n#if 0 || (LZO_DETERMINISTIC)\n        ll = LZO_MIN(ll, 49152);\n#endif\n        ll_end = (lzo_uintptr_t)ip + ll;\n        if ((ll_end + ((t + ll) >> 5)) <= ll_end || (const lzo_bytep)(ll_end + ((t + ll) >> 5)) <= ip + ll)\n            break;\n#if (LZO_DETERMINISTIC)\n        lzo_memset(wrkmem, 0, ((lzo_uint)1 << D_BITS) * sizeof(lzo_dict_t));\n#endif\n        t = do_compress(ip,ll,op,out_len,t,wrkmem);\n        ip += ll;\n        op += *out_len;\n        l  -= ll;\n    }\n    t += l;\n\n    if (t > 0)\n    {\n        const lzo_bytep ii = in + in_len - t;\n\n        if (op == out && t <= 238)\n            *op++ = LZO_BYTE(17 + t);\n        else if (t <= 3)\n            op[-2] = LZO_BYTE(op[-2] | t);\n        else if (t <= 18)\n            *op++ = LZO_BYTE(t - 3);\n        else\n        {\n            lzo_uint tt = t - 18;\n\n            *op++ = 0;\n            while (tt > 255)\n            {\n                tt -= 255;\n                UA_SET1(op, 0);\n                op++;\n            }\n            assert(tt > 0);\n            *op++ = LZO_BYTE(tt);\n        }\n        UA_COPYN(op, ii, t);\n        op += t;\n    }\n\n    *op++ = M4_MARKER | 1;\n    *op++ = 0;\n    *op++ = 0;\n\n    *out_len = pd(op, out);\n    return LZO_E_OK;\n}\n\n#endif\n\n#undef do_compress\n#undef DO_COMPRESS\n#undef LZO_HASH\n\n#undef LZO_TEST_OVERRUN\n#undef DO_DECOMPRESS\n#define DO_DECOMPRESS       lzo1x_decompress\n\n#if !defined(MINILZO_CFG_SKIP_LZO1X_DECOMPRESS)\n\n#if defined(LZO_TEST_OVERRUN)\n#  if !defined(LZO_TEST_OVERRUN_INPUT)\n#    define LZO_TEST_OVERRUN_INPUT       2\n#  endif\n#  if !defined(LZO_TEST_OVERRUN_OUTPUT)\n#    define LZO_TEST_OVERRUN_OUTPUT      2\n#  endif\n#  if !defined(LZO_TEST_OVERRUN_LOOKBEHIND)\n#    define LZO_TEST_OVERRUN_LOOKBEHIND  1\n#  endif\n#endif\n\n#undef TEST_IP\n#undef TEST_OP\n#undef TEST_IP_AND_TEST_OP\n#undef TEST_LB\n#undef TEST_LBO\n#undef NEED_IP\n#undef NEED_OP\n#undef TEST_IV\n#undef TEST_OV\n#undef HAVE_TEST_IP\n#undef HAVE_TEST_OP\n#undef HAVE_NEED_IP\n#undef HAVE_NEED_OP\n#undef HAVE_ANY_IP\n#undef HAVE_ANY_OP\n\n#if defined(LZO_TEST_OVERRUN_INPUT)\n#  if (LZO_TEST_OVERRUN_INPUT >= 1)\n#    define TEST_IP             (ip < ip_end)\n#  endif\n#  if (LZO_TEST_OVERRUN_INPUT >= 2)\n#    define NEED_IP(x) \\\n            if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x))  goto input_overrun\n#    define TEST_IV(x)          if ((x) >  (lzo_uint)0 - (511)) goto input_overrun\n#  endif\n#endif\n\n#if defined(LZO_TEST_OVERRUN_OUTPUT)\n#  if (LZO_TEST_OVERRUN_OUTPUT >= 1)\n#    define TEST_OP             (op <= op_end)\n#  endif\n#  if (LZO_TEST_OVERRUN_OUTPUT >= 2)\n#    undef TEST_OP\n#    define NEED_OP(x) \\\n            if ((lzo_uint)(op_end - op) < (lzo_uint)(x))  goto output_overrun\n#    define TEST_OV(x)          if ((x) >  (lzo_uint)0 - (511)) goto output_overrun\n#  endif\n#endif\n\n#if defined(LZO_TEST_OVERRUN_LOOKBEHIND)\n#  define TEST_LB(m_pos)        if (PTR_LT(m_pos,out) || PTR_GE(m_pos,op)) goto lookbehind_overrun\n#  define TEST_LBO(m_pos,o)     if (PTR_LT(m_pos,out) || PTR_GE(m_pos,op-(o))) goto lookbehind_overrun\n#else\n#  define TEST_LB(m_pos)        ((void) 0)\n#  define TEST_LBO(m_pos,o)     ((void) 0)\n#endif\n\n#if !defined(LZO_EOF_CODE) && !defined(TEST_IP)\n#  define TEST_IP               (ip < ip_end)\n#endif\n\n#if defined(TEST_IP)\n#  define HAVE_TEST_IP 1\n#else\n#  define TEST_IP               1\n#endif\n#if defined(TEST_OP)\n#  define HAVE_TEST_OP 1\n#else\n#  define TEST_OP               1\n#endif\n\n#if defined(HAVE_TEST_IP) && defined(HAVE_TEST_OP)\n#  define TEST_IP_AND_TEST_OP   (TEST_IP && TEST_OP)\n#elif defined(HAVE_TEST_IP)\n#  define TEST_IP_AND_TEST_OP   TEST_IP\n#elif defined(HAVE_TEST_OP)\n#  define TEST_IP_AND_TEST_OP   TEST_OP\n#else\n#  define TEST_IP_AND_TEST_OP   1\n#endif\n\n#if defined(NEED_IP)\n#  define HAVE_NEED_IP 1\n#else\n#  define NEED_IP(x)            ((void) 0)\n#  define TEST_IV(x)            ((void) 0)\n#endif\n#if defined(NEED_OP)\n#  define HAVE_NEED_OP 1\n#else\n#  define NEED_OP(x)            ((void) 0)\n#  define TEST_OV(x)            ((void) 0)\n#endif\n\n#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP)\n#  define HAVE_ANY_IP 1\n#endif\n#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP)\n#  define HAVE_ANY_OP 1\n#endif\n\n#if defined(DO_DECOMPRESS)\nLZO_PUBLIC(int)\nDO_DECOMPRESS  ( const lzo_bytep in , lzo_uint  in_len,\n                       lzo_bytep out, lzo_uintp out_len,\n                       lzo_voidp wrkmem )\n#endif\n{\n    lzo_bytep op;\n    const lzo_bytep ip;\n    lzo_uint t;\n#if defined(COPY_DICT)\n    lzo_uint m_off;\n    const lzo_bytep dict_end;\n#else\n    const lzo_bytep m_pos;\n#endif\n\n    const lzo_bytep const ip_end = in + in_len;\n#if defined(HAVE_ANY_OP)\n    lzo_bytep const op_end = out + *out_len;\n#endif\n#if defined(LZO1Z)\n    lzo_uint last_m_off = 0;\n#endif\n\n    LZO_UNUSED(wrkmem);\n\n#if defined(COPY_DICT)\n    if (dict)\n    {\n        if (dict_len > M4_MAX_OFFSET)\n        {\n            dict += dict_len - M4_MAX_OFFSET;\n            dict_len = M4_MAX_OFFSET;\n        }\n        dict_end = dict + dict_len;\n    }\n    else\n    {\n        dict_len = 0;\n        dict_end = NULL;\n    }\n#endif\n\n    *out_len = 0;\n\n    op = out;\n    ip = in;\n\n    NEED_IP(1);\n    if (*ip > 17)\n    {\n        t = *ip++ - 17;\n        if (t < 4)\n            goto match_next;\n        assert(t > 0); NEED_OP(t); NEED_IP(t+3);\n        do *op++ = *ip++; while (--t > 0);\n        goto first_literal_run;\n    }\n\n    for (;;)\n    {\n        NEED_IP(3);\n        t = *ip++;\n        if (t >= 16)\n            goto match;\n        if (t == 0)\n        {\n            while (*ip == 0)\n            {\n                t += 255;\n                ip++;\n                TEST_IV(t);\n                NEED_IP(1);\n            }\n            t += 15 + *ip++;\n        }\n        assert(t > 0); NEED_OP(t+3); NEED_IP(t+6);\n#if (LZO_OPT_UNALIGNED64) && (LZO_OPT_UNALIGNED32)\n        t += 3;\n        if (t >= 8) do\n        {\n            UA_COPY8(op,ip);\n            op += 8; ip += 8; t -= 8;\n        } while (t >= 8);\n        if (t >= 4)\n        {\n            UA_COPY4(op,ip);\n            op += 4; ip += 4; t -= 4;\n        }\n        if (t > 0)\n        {\n            *op++ = *ip++;\n            if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }\n        }\n#elif (LZO_OPT_UNALIGNED32) || (LZO_ALIGNED_OK_4)\n#if !(LZO_OPT_UNALIGNED32)\n        if (PTR_ALIGNED2_4(op,ip))\n        {\n#endif\n        UA_COPY4(op,ip);\n        op += 4; ip += 4;\n        if (--t > 0)\n        {\n            if (t >= 4)\n            {\n                do {\n                    UA_COPY4(op,ip);\n                    op += 4; ip += 4; t -= 4;\n                } while (t >= 4);\n                if (t > 0) do *op++ = *ip++; while (--t > 0);\n            }\n            else\n                do *op++ = *ip++; while (--t > 0);\n        }\n#if !(LZO_OPT_UNALIGNED32)\n        }\n        else\n#endif\n#endif\n#if !(LZO_OPT_UNALIGNED32)\n        {\n            *op++ = *ip++; *op++ = *ip++; *op++ = *ip++;\n            do *op++ = *ip++; while (--t > 0);\n        }\n#endif\n\nfirst_literal_run:\n\n        t = *ip++;\n        if (t >= 16)\n            goto match;\n#if defined(COPY_DICT)\n#if defined(LZO1Z)\n        m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);\n        last_m_off = m_off;\n#else\n        m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2);\n#endif\n        NEED_OP(3);\n        t = 3; COPY_DICT(t,m_off)\n#else\n#if defined(LZO1Z)\n        t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);\n        m_pos = op - t;\n        last_m_off = t;\n#else\n        m_pos = op - (1 + M2_MAX_OFFSET);\n        m_pos -= t >> 2;\n        m_pos -= *ip++ << 2;\n#endif\n        TEST_LB(m_pos); NEED_OP(3);\n        *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos;\n#endif\n        goto match_done;\n\n        for (;;) {\nmatch:\n            if (t >= 64)\n            {\n#if defined(COPY_DICT)\n#if defined(LZO1X)\n                m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3);\n                t = (t >> 5) - 1;\n#elif defined(LZO1Y)\n                m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2);\n                t = (t >> 4) - 3;\n#elif defined(LZO1Z)\n                m_off = t & 0x1f;\n                if (m_off >= 0x1c)\n                    m_off = last_m_off;\n                else\n                {\n                    m_off = 1 + (m_off << 6) + (*ip++ >> 2);\n                    last_m_off = m_off;\n                }\n                t = (t >> 5) - 1;\n#endif\n#else\n#if defined(LZO1X)\n                m_pos = op - 1;\n                m_pos -= (t >> 2) & 7;\n                m_pos -= *ip++ << 3;\n                t = (t >> 5) - 1;\n#elif defined(LZO1Y)\n                m_pos = op - 1;\n                m_pos -= (t >> 2) & 3;\n                m_pos -= *ip++ << 2;\n                t = (t >> 4) - 3;\n#elif defined(LZO1Z)\n                {\n                    lzo_uint off = t & 0x1f;\n                    m_pos = op;\n                    if (off >= 0x1c)\n                    {\n                        assert(last_m_off > 0);\n                        m_pos -= last_m_off;\n                    }\n                    else\n                    {\n                        off = 1 + (off << 6) + (*ip++ >> 2);\n                        m_pos -= off;\n                        last_m_off = off;\n                    }\n                }\n                t = (t >> 5) - 1;\n#endif\n                TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);\n                goto copy_match;\n#endif\n            }\n            else if (t >= 32)\n            {\n                t &= 31;\n                if (t == 0)\n                {\n                    while (*ip == 0)\n                    {\n                        t += 255;\n                        ip++;\n                        TEST_OV(t);\n                        NEED_IP(1);\n                    }\n                    t += 31 + *ip++;\n                    NEED_IP(2);\n                }\n#if defined(COPY_DICT)\n#if defined(LZO1Z)\n                m_off = 1 + (ip[0] << 6) + (ip[1] >> 2);\n                last_m_off = m_off;\n#else\n                m_off = 1 + (ip[0] >> 2) + (ip[1] << 6);\n#endif\n#else\n#if defined(LZO1Z)\n                {\n                    lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2);\n                    m_pos = op - off;\n                    last_m_off = off;\n                }\n#elif (LZO_OPT_UNALIGNED16) && (LZO_ABI_LITTLE_ENDIAN)\n                m_pos = op - 1;\n                m_pos -= UA_GET_LE16(ip) >> 2;\n#else\n                m_pos = op - 1;\n                m_pos -= (ip[0] >> 2) + (ip[1] << 6);\n#endif\n#endif\n                ip += 2;\n            }\n            else if (t >= 16)\n            {\n#if defined(COPY_DICT)\n                m_off = (t & 8) << 11;\n#else\n                m_pos = op;\n                m_pos -= (t & 8) << 11;\n#endif\n                t &= 7;\n                if (t == 0)\n                {\n                    while (*ip == 0)\n                    {\n                        t += 255;\n                        ip++;\n                        TEST_OV(t);\n                        NEED_IP(1);\n                    }\n                    t += 7 + *ip++;\n                    NEED_IP(2);\n                }\n#if defined(COPY_DICT)\n#if defined(LZO1Z)\n                m_off += (ip[0] << 6) + (ip[1] >> 2);\n#else\n                m_off += (ip[0] >> 2) + (ip[1] << 6);\n#endif\n                ip += 2;\n                if (m_off == 0)\n                    goto eof_found;\n                m_off += 0x4000;\n#if defined(LZO1Z)\n                last_m_off = m_off;\n#endif\n#else\n#if defined(LZO1Z)\n                m_pos -= (ip[0] << 6) + (ip[1] >> 2);\n#elif (LZO_OPT_UNALIGNED16) && (LZO_ABI_LITTLE_ENDIAN)\n                m_pos -= UA_GET_LE16(ip) >> 2;\n#else\n                m_pos -= (ip[0] >> 2) + (ip[1] << 6);\n#endif\n                ip += 2;\n                if (m_pos == op)\n                    goto eof_found;\n                m_pos -= 0x4000;\n#if defined(LZO1Z)\n                last_m_off = pd((const lzo_bytep)op, m_pos);\n#endif\n#endif\n            }\n            else\n            {\n#if defined(COPY_DICT)\n#if defined(LZO1Z)\n                m_off = 1 + (t << 6) + (*ip++ >> 2);\n                last_m_off = m_off;\n#else\n                m_off = 1 + (t >> 2) + (*ip++ << 2);\n#endif\n                NEED_OP(2);\n                t = 2; COPY_DICT(t,m_off)\n#else\n#if defined(LZO1Z)\n                t = 1 + (t << 6) + (*ip++ >> 2);\n                m_pos = op - t;\n                last_m_off = t;\n#else\n                m_pos = op - 1;\n                m_pos -= t >> 2;\n                m_pos -= *ip++ << 2;\n#endif\n                TEST_LB(m_pos); NEED_OP(2);\n                *op++ = *m_pos++; *op++ = *m_pos;\n#endif\n                goto match_done;\n            }\n\n#if defined(COPY_DICT)\n\n            NEED_OP(t+3-1);\n            t += 3-1; COPY_DICT(t,m_off)\n\n#else\n\n            TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);\n#if (LZO_OPT_UNALIGNED64) && (LZO_OPT_UNALIGNED32)\n            if (op - m_pos >= 8)\n            {\n                t += (3 - 1);\n                if (t >= 8) do\n                {\n                    UA_COPY8(op,m_pos);\n                    op += 8; m_pos += 8; t -= 8;\n                } while (t >= 8);\n                if (t >= 4)\n                {\n                    UA_COPY4(op,m_pos);\n                    op += 4; m_pos += 4; t -= 4;\n                }\n                if (t > 0)\n                {\n                    *op++ = m_pos[0];\n                    if (t > 1) { *op++ = m_pos[1]; if (t > 2) { *op++ = m_pos[2]; } }\n                }\n            }\n            else\n#elif (LZO_OPT_UNALIGNED32) || (LZO_ALIGNED_OK_4)\n#if !(LZO_OPT_UNALIGNED32)\n            if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos))\n            {\n                assert((op - m_pos) >= 4);\n#else\n            if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4)\n            {\n#endif\n                UA_COPY4(op,m_pos);\n                op += 4; m_pos += 4; t -= 4 - (3 - 1);\n                do {\n                    UA_COPY4(op,m_pos);\n                    op += 4; m_pos += 4; t -= 4;\n                } while (t >= 4);\n                if (t > 0) do *op++ = *m_pos++; while (--t > 0);\n            }\n            else\n#endif\n            {\ncopy_match:\n                *op++ = *m_pos++; *op++ = *m_pos++;\n                do *op++ = *m_pos++; while (--t > 0);\n            }\n\n#endif\n\nmatch_done:\n#if defined(LZO1Z)\n            t = ip[-1] & 3;\n#else\n            t = ip[-2] & 3;\n#endif\n            if (t == 0)\n                break;\n\nmatch_next:\n            assert(t > 0); assert(t < 4); NEED_OP(t); NEED_IP(t+3);\n#if 0\n            do *op++ = *ip++; while (--t > 0);\n#else\n            *op++ = *ip++;\n            if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }\n#endif\n            t = *ip++;\n        }\n    }\n\neof_found:\n    *out_len = pd(op, out);\n    return (ip == ip_end ? LZO_E_OK :\n           (ip < ip_end  ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));\n\n#if defined(HAVE_NEED_IP)\ninput_overrun:\n    *out_len = pd(op, out);\n    return LZO_E_INPUT_OVERRUN;\n#endif\n\n#if defined(HAVE_NEED_OP)\noutput_overrun:\n    *out_len = pd(op, out);\n    return LZO_E_OUTPUT_OVERRUN;\n#endif\n\n#if defined(LZO_TEST_OVERRUN_LOOKBEHIND)\nlookbehind_overrun:\n    *out_len = pd(op, out);\n    return LZO_E_LOOKBEHIND_OVERRUN;\n#endif\n}\n\n#endif\n\n#define LZO_TEST_OVERRUN 1\n#undef DO_DECOMPRESS\n#define DO_DECOMPRESS       lzo1x_decompress_safe\n\n#if !defined(MINILZO_CFG_SKIP_LZO1X_DECOMPRESS_SAFE)\n\n#if defined(LZO_TEST_OVERRUN)\n#  if !defined(LZO_TEST_OVERRUN_INPUT)\n#    define LZO_TEST_OVERRUN_INPUT       2\n#  endif\n#  if !defined(LZO_TEST_OVERRUN_OUTPUT)\n#    define LZO_TEST_OVERRUN_OUTPUT      2\n#  endif\n#  if !defined(LZO_TEST_OVERRUN_LOOKBEHIND)\n#    define LZO_TEST_OVERRUN_LOOKBEHIND  1\n#  endif\n#endif\n\n#undef TEST_IP\n#undef TEST_OP\n#undef TEST_IP_AND_TEST_OP\n#undef TEST_LB\n#undef TEST_LBO\n#undef NEED_IP\n#undef NEED_OP\n#undef TEST_IV\n#undef TEST_OV\n#undef HAVE_TEST_IP\n#undef HAVE_TEST_OP\n#undef HAVE_NEED_IP\n#undef HAVE_NEED_OP\n#undef HAVE_ANY_IP\n#undef HAVE_ANY_OP\n\n#if defined(LZO_TEST_OVERRUN_INPUT)\n#  if (LZO_TEST_OVERRUN_INPUT >= 1)\n#    define TEST_IP             (ip < ip_end)\n#  endif\n#  if (LZO_TEST_OVERRUN_INPUT >= 2)\n#    define NEED_IP(x) \\\n            if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x))  goto input_overrun\n#    define TEST_IV(x)          if ((x) >  (lzo_uint)0 - (511)) goto input_overrun\n#  endif\n#endif\n\n#if defined(LZO_TEST_OVERRUN_OUTPUT)\n#  if (LZO_TEST_OVERRUN_OUTPUT >= 1)\n#    define TEST_OP             (op <= op_end)\n#  endif\n#  if (LZO_TEST_OVERRUN_OUTPUT >= 2)\n#    undef TEST_OP\n#    define NEED_OP(x) \\\n            if ((lzo_uint)(op_end - op) < (lzo_uint)(x))  goto output_overrun\n#    define TEST_OV(x)          if ((x) >  (lzo_uint)0 - (511)) goto output_overrun\n#  endif\n#endif\n\n#if defined(LZO_TEST_OVERRUN_LOOKBEHIND)\n#  define TEST_LB(m_pos)        if (PTR_LT(m_pos,out) || PTR_GE(m_pos,op)) goto lookbehind_overrun\n#  define TEST_LBO(m_pos,o)     if (PTR_LT(m_pos,out) || PTR_GE(m_pos,op-(o))) goto lookbehind_overrun\n#else\n#  define TEST_LB(m_pos)        ((void) 0)\n#  define TEST_LBO(m_pos,o)     ((void) 0)\n#endif\n\n#if !defined(LZO_EOF_CODE) && !defined(TEST_IP)\n#  define TEST_IP               (ip < ip_end)\n#endif\n\n#if defined(TEST_IP)\n#  define HAVE_TEST_IP 1\n#else\n#  define TEST_IP               1\n#endif\n#if defined(TEST_OP)\n#  define HAVE_TEST_OP 1\n#else\n#  define TEST_OP               1\n#endif\n\n#if defined(HAVE_TEST_IP) && defined(HAVE_TEST_OP)\n#  define TEST_IP_AND_TEST_OP   (TEST_IP && TEST_OP)\n#elif defined(HAVE_TEST_IP)\n#  define TEST_IP_AND_TEST_OP   TEST_IP\n#elif defined(HAVE_TEST_OP)\n#  define TEST_IP_AND_TEST_OP   TEST_OP\n#else\n#  define TEST_IP_AND_TEST_OP   1\n#endif\n\n#if defined(NEED_IP)\n#  define HAVE_NEED_IP 1\n#else\n#  define NEED_IP(x)            ((void) 0)\n#  define TEST_IV(x)            ((void) 0)\n#endif\n#if defined(NEED_OP)\n#  define HAVE_NEED_OP 1\n#else\n#  define NEED_OP(x)            ((void) 0)\n#  define TEST_OV(x)            ((void) 0)\n#endif\n\n#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP)\n#  define HAVE_ANY_IP 1\n#endif\n#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP)\n#  define HAVE_ANY_OP 1\n#endif\n\n#if defined(DO_DECOMPRESS)\nLZO_PUBLIC(int)\nDO_DECOMPRESS  ( const lzo_bytep in , lzo_uint  in_len,\n                       lzo_bytep out, lzo_uintp out_len,\n                       lzo_voidp wrkmem )\n#endif\n{\n    lzo_bytep op;\n    const lzo_bytep ip;\n    lzo_uint t;\n#if defined(COPY_DICT)\n    lzo_uint m_off;\n    const lzo_bytep dict_end;\n#else\n    const lzo_bytep m_pos;\n#endif\n\n    const lzo_bytep const ip_end = in + in_len;\n#if defined(HAVE_ANY_OP)\n    lzo_bytep const op_end = out + *out_len;\n#endif\n#if defined(LZO1Z)\n    lzo_uint last_m_off = 0;\n#endif\n\n    LZO_UNUSED(wrkmem);\n\n#if defined(COPY_DICT)\n    if (dict)\n    {\n        if (dict_len > M4_MAX_OFFSET)\n        {\n            dict += dict_len - M4_MAX_OFFSET;\n            dict_len = M4_MAX_OFFSET;\n        }\n        dict_end = dict + dict_len;\n    }\n    else\n    {\n        dict_len = 0;\n        dict_end = NULL;\n    }\n#endif\n\n    *out_len = 0;\n\n    op = out;\n    ip = in;\n\n    NEED_IP(1);\n    if (*ip > 17)\n    {\n        t = *ip++ - 17;\n        if (t < 4)\n            goto match_next;\n        assert(t > 0); NEED_OP(t); NEED_IP(t+3);\n        do *op++ = *ip++; while (--t > 0);\n        goto first_literal_run;\n    }\n\n    for (;;)\n    {\n        NEED_IP(3);\n        t = *ip++;\n        if (t >= 16)\n            goto match;\n        if (t == 0)\n        {\n            while (*ip == 0)\n            {\n                t += 255;\n                ip++;\n                TEST_IV(t);\n                NEED_IP(1);\n            }\n            t += 15 + *ip++;\n        }\n        assert(t > 0); NEED_OP(t+3); NEED_IP(t+6);\n#if (LZO_OPT_UNALIGNED64) && (LZO_OPT_UNALIGNED32)\n        t += 3;\n        if (t >= 8) do\n        {\n            UA_COPY8(op,ip);\n            op += 8; ip += 8; t -= 8;\n        } while (t >= 8);\n        if (t >= 4)\n        {\n            UA_COPY4(op,ip);\n            op += 4; ip += 4; t -= 4;\n        }\n        if (t > 0)\n        {\n            *op++ = *ip++;\n            if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }\n        }\n#elif (LZO_OPT_UNALIGNED32) || (LZO_ALIGNED_OK_4)\n#if !(LZO_OPT_UNALIGNED32)\n        if (PTR_ALIGNED2_4(op,ip))\n        {\n#endif\n        UA_COPY4(op,ip);\n        op += 4; ip += 4;\n        if (--t > 0)\n        {\n            if (t >= 4)\n            {\n                do {\n                    UA_COPY4(op,ip);\n                    op += 4; ip += 4; t -= 4;\n                } while (t >= 4);\n                if (t > 0) do *op++ = *ip++; while (--t > 0);\n            }\n            else\n                do *op++ = *ip++; while (--t > 0);\n        }\n#if !(LZO_OPT_UNALIGNED32)\n        }\n        else\n#endif\n#endif\n#if !(LZO_OPT_UNALIGNED32)\n        {\n            *op++ = *ip++; *op++ = *ip++; *op++ = *ip++;\n            do *op++ = *ip++; while (--t > 0);\n        }\n#endif\n\nfirst_literal_run:\n\n        t = *ip++;\n        if (t >= 16)\n            goto match;\n#if defined(COPY_DICT)\n#if defined(LZO1Z)\n        m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);\n        last_m_off = m_off;\n#else\n        m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2);\n#endif\n        NEED_OP(3);\n        t = 3; COPY_DICT(t,m_off)\n#else\n#if defined(LZO1Z)\n        t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);\n        m_pos = op - t;\n        last_m_off = t;\n#else\n        m_pos = op - (1 + M2_MAX_OFFSET);\n        m_pos -= t >> 2;\n        m_pos -= *ip++ << 2;\n#endif\n        TEST_LB(m_pos); NEED_OP(3);\n        *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos;\n#endif\n        goto match_done;\n\n        for (;;) {\nmatch:\n            if (t >= 64)\n            {\n#if defined(COPY_DICT)\n#if defined(LZO1X)\n                m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3);\n                t = (t >> 5) - 1;\n#elif defined(LZO1Y)\n                m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2);\n                t = (t >> 4) - 3;\n#elif defined(LZO1Z)\n                m_off = t & 0x1f;\n                if (m_off >= 0x1c)\n                    m_off = last_m_off;\n                else\n                {\n                    m_off = 1 + (m_off << 6) + (*ip++ >> 2);\n                    last_m_off = m_off;\n                }\n                t = (t >> 5) - 1;\n#endif\n#else\n#if defined(LZO1X)\n                m_pos = op - 1;\n                m_pos -= (t >> 2) & 7;\n                m_pos -= *ip++ << 3;\n                t = (t >> 5) - 1;\n#elif defined(LZO1Y)\n                m_pos = op - 1;\n                m_pos -= (t >> 2) & 3;\n                m_pos -= *ip++ << 2;\n                t = (t >> 4) - 3;\n#elif defined(LZO1Z)\n                {\n                    lzo_uint off = t & 0x1f;\n                    m_pos = op;\n                    if (off >= 0x1c)\n                    {\n                        assert(last_m_off > 0);\n                        m_pos -= last_m_off;\n                    }\n                    else\n                    {\n                        off = 1 + (off << 6) + (*ip++ >> 2);\n                        m_pos -= off;\n                        last_m_off = off;\n                    }\n                }\n                t = (t >> 5) - 1;\n#endif\n                TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);\n                goto copy_match;\n#endif\n            }\n            else if (t >= 32)\n            {\n                t &= 31;\n                if (t == 0)\n                {\n                    while (*ip == 0)\n                    {\n                        t += 255;\n                        ip++;\n                        TEST_OV(t);\n                        NEED_IP(1);\n                    }\n                    t += 31 + *ip++;\n                    NEED_IP(2);\n                }\n#if defined(COPY_DICT)\n#if defined(LZO1Z)\n                m_off = 1 + (ip[0] << 6) + (ip[1] >> 2);\n                last_m_off = m_off;\n#else\n                m_off = 1 + (ip[0] >> 2) + (ip[1] << 6);\n#endif\n#else\n#if defined(LZO1Z)\n                {\n                    lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2);\n                    m_pos = op - off;\n                    last_m_off = off;\n                }\n#elif (LZO_OPT_UNALIGNED16) && (LZO_ABI_LITTLE_ENDIAN)\n                m_pos = op - 1;\n                m_pos -= UA_GET_LE16(ip) >> 2;\n#else\n                m_pos = op - 1;\n                m_pos -= (ip[0] >> 2) + (ip[1] << 6);\n#endif\n#endif\n                ip += 2;\n            }\n            else if (t >= 16)\n            {\n#if defined(COPY_DICT)\n                m_off = (t & 8) << 11;\n#else\n                m_pos = op;\n                m_pos -= (t & 8) << 11;\n#endif\n                t &= 7;\n                if (t == 0)\n                {\n                    while (*ip == 0)\n                    {\n                        t += 255;\n                        ip++;\n                        TEST_OV(t);\n                        NEED_IP(1);\n                    }\n                    t += 7 + *ip++;\n                    NEED_IP(2);\n                }\n#if defined(COPY_DICT)\n#if defined(LZO1Z)\n                m_off += (ip[0] << 6) + (ip[1] >> 2);\n#else\n                m_off += (ip[0] >> 2) + (ip[1] << 6);\n#endif\n                ip += 2;\n                if (m_off == 0)\n                    goto eof_found;\n                m_off += 0x4000;\n#if defined(LZO1Z)\n                last_m_off = m_off;\n#endif\n#else\n#if defined(LZO1Z)\n                m_pos -= (ip[0] << 6) + (ip[1] >> 2);\n#elif (LZO_OPT_UNALIGNED16) && (LZO_ABI_LITTLE_ENDIAN)\n                m_pos -= UA_GET_LE16(ip) >> 2;\n#else\n                m_pos -= (ip[0] >> 2) + (ip[1] << 6);\n#endif\n                ip += 2;\n                if (m_pos == op)\n                    goto eof_found;\n                m_pos -= 0x4000;\n#if defined(LZO1Z)\n                last_m_off = pd((const lzo_bytep)op, m_pos);\n#endif\n#endif\n            }\n            else\n            {\n#if defined(COPY_DICT)\n#if defined(LZO1Z)\n                m_off = 1 + (t << 6) + (*ip++ >> 2);\n                last_m_off = m_off;\n#else\n                m_off = 1 + (t >> 2) + (*ip++ << 2);\n#endif\n                NEED_OP(2);\n                t = 2; COPY_DICT(t,m_off)\n#else\n#if defined(LZO1Z)\n                t = 1 + (t << 6) + (*ip++ >> 2);\n                m_pos = op - t;\n                last_m_off = t;\n#else\n                m_pos = op - 1;\n                m_pos -= t >> 2;\n                m_pos -= *ip++ << 2;\n#endif\n                TEST_LB(m_pos); NEED_OP(2);\n                *op++ = *m_pos++; *op++ = *m_pos;\n#endif\n                goto match_done;\n            }\n\n#if defined(COPY_DICT)\n\n            NEED_OP(t+3-1);\n            t += 3-1; COPY_DICT(t,m_off)\n\n#else\n\n            TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);\n#if (LZO_OPT_UNALIGNED64) && (LZO_OPT_UNALIGNED32)\n            if (op - m_pos >= 8)\n            {\n                t += (3 - 1);\n                if (t >= 8) do\n                {\n                    UA_COPY8(op,m_pos);\n                    op += 8; m_pos += 8; t -= 8;\n                } while (t >= 8);\n                if (t >= 4)\n                {\n                    UA_COPY4(op,m_pos);\n                    op += 4; m_pos += 4; t -= 4;\n                }\n                if (t > 0)\n                {\n                    *op++ = m_pos[0];\n                    if (t > 1) { *op++ = m_pos[1]; if (t > 2) { *op++ = m_pos[2]; } }\n                }\n            }\n            else\n#elif (LZO_OPT_UNALIGNED32) || (LZO_ALIGNED_OK_4)\n#if !(LZO_OPT_UNALIGNED32)\n            if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos))\n            {\n                assert((op - m_pos) >= 4);\n#else\n            if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4)\n            {\n#endif\n                UA_COPY4(op,m_pos);\n                op += 4; m_pos += 4; t -= 4 - (3 - 1);\n                do {\n                    UA_COPY4(op,m_pos);\n                    op += 4; m_pos += 4; t -= 4;\n                } while (t >= 4);\n                if (t > 0) do *op++ = *m_pos++; while (--t > 0);\n            }\n            else\n#endif\n            {\ncopy_match:\n                *op++ = *m_pos++; *op++ = *m_pos++;\n                do *op++ = *m_pos++; while (--t > 0);\n            }\n\n#endif\n\nmatch_done:\n#if defined(LZO1Z)\n            t = ip[-1] & 3;\n#else\n            t = ip[-2] & 3;\n#endif\n            if (t == 0)\n                break;\n\nmatch_next:\n            assert(t > 0); assert(t < 4); NEED_OP(t); NEED_IP(t+3);\n#if 0\n            do *op++ = *ip++; while (--t > 0);\n#else\n            *op++ = *ip++;\n            if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }\n#endif\n            t = *ip++;\n        }\n    }\n\neof_found:\n    *out_len = pd(op, out);\n    return (ip == ip_end ? LZO_E_OK :\n           (ip < ip_end  ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));\n\n#if defined(HAVE_NEED_IP)\ninput_overrun:\n    *out_len = pd(op, out);\n    return LZO_E_INPUT_OVERRUN;\n#endif\n\n#if defined(HAVE_NEED_OP)\noutput_overrun:\n    *out_len = pd(op, out);\n    return LZO_E_OUTPUT_OVERRUN;\n#endif\n\n#if defined(LZO_TEST_OVERRUN_LOOKBEHIND)\nlookbehind_overrun:\n    *out_len = pd(op, out);\n    return LZO_E_LOOKBEHIND_OVERRUN;\n#endif\n}\n\n#endif\n\n/***** End of minilzo.c *****/\n"
  },
  {
    "path": "usr/utils/q.c",
    "content": "/*\n * From Unix System Programming -\n * Starting from Pg 195\n *\n * Advanced inter-process communications\n */\n\n#include <stddef.h>\n#include <stdio.h>\n#include <syslog.h>\n#include <sys/msg.h>\n#include <errno.h>\n#include <string.h>\n#include \"q.h\"\n\nextern int\tdebug;\nextern char mhvtl_driver_name[];\n\n#define MHVTL_ERR(format, arg...)                             \\\n\t{                                                         \\\n\t\tif (debug)                                            \\\n\t\t\tprintf(\"%s: ERROR %s: \" format \"\\n\",              \\\n\t\t\t\t   mhvtl_driver_name, __func__, ##arg);       \\\n\t\telse                                                  \\\n\t\t\tsyslog(LOG_DAEMON | LOG_ERR, \"ERROR %s: \" format, \\\n\t\t\t\t   __func__, ##arg);                          \\\n\t}\n\nstatic void warn(char *s) {\n\tfprintf(stderr, \"Warning: %s\\n\", s);\n}\n\nint init_queue(void) {\n\tint queue_id;\n\n\t/* Attempt to create or open message queue */\n\tqueue_id = msgget(QKEY, IPC_CREAT | QPERM);\n\tif (queue_id == -1) {\n\t\tchar s[245];\n\t\tswitch (errno) {\n\t\tcase EACCES:\n\t\t\tstrcpy(s, \"Operation not permitted\");\n\t\t\tbreak;\n\t\tcase EEXIST:\n\t\t\tstrcpy(s, \"Message Q already exists\");\n\t\t\tbreak;\n\t\tcase ENOENT:\n\t\t\tstrcpy(s, \"Message Q does not exist\");\n\t\t\tbreak;\n\t\tcase ENOSPC:\n\t\t\tstrcpy(s, \"Exceeded max num of message queues\");\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tstrcpy(s, \"errno not valid\");\n\t\t\tbreak;\n\t\t}\n\t\tMHVTL_ERR(\"msgget(%d) failed %s, %s\",\n\t\t\t\t  QKEY, strerror(errno), s);\n\t}\n\n\treturn queue_id;\n}\n\nint send_msg(char *cmd, long rcv_id) {\n\tint\t\t\t   len, s_qid;\n\tstruct q_entry s_entry;\n\n\t/* Match enter()'s length guard: refuse messages that would not\n\t * fit into s_entry.msg.text[MAXTEXTLEN + 1] and prevent an\n\t * unbounded strcpy into the fixed-size queue message slot.\n\t */\n\tif (strlen(cmd) > MAXTEXTLEN) {\n\t\tMHVTL_ERR(\"send_msg: command too long (%zu > %d)\",\n\t\t\t\t  strlen(cmd), MAXTEXTLEN);\n\t\treturn -1;\n\t}\n\n\tmemset(&s_entry, 0, sizeof(struct q_entry));\n\n\ts_qid = init_queue();\n\tif (s_qid == -1)\n\t\treturn -1;\n\n\ts_entry.rcv_id\t   = rcv_id;\n\ts_entry.msg.snd_id = my_id;\n\tstrncpy(s_entry.msg.text, cmd, MAXTEXTLEN);\n\ts_entry.msg.text[MAXTEXTLEN] = '\\0';\n\tlen = strlen(s_entry.msg.text) + 1 + offsetof(struct q_entry, msg.text);\n\n\tif (msgsnd(s_qid, &s_entry, len, 0) == -1) {\n\t\tMHVTL_ERR(\"msgsnd failed: %s\", strerror(errno));\n\t\treturn -1;\n\t}\n\n\treturn 0;\n}\n\nstatic void proc_obj(struct q_entry *q_entry) {\n\tprintf(\"rcv_id: %ld, snd_id: %ld, text: %s\\n\",\n\t\t   q_entry->rcv_id, q_entry->msg.snd_id, q_entry->msg.text);\n}\n\nint enter(char *objname, long rcv_id) {\n\tint\t\t\t   len, s_qid;\n\tstruct q_entry s_entry; /* Structure to hold message */\n\n\t/* Validate name length, rcv_id */\n\tif (strlen(objname) > MAXTEXTLEN) {\n\t\twarn(\"Name too long\");\n\t\treturn -1;\n\t}\n\n\tif (rcv_id > 32764 || rcv_id < 0) {\n\t\twarn(\"Invalid rcv_id\");\n\t\treturn -1;\n\t}\n\n\t/* Initialize message queue as nessary */\n\ts_qid = init_queue();\n\tif (s_qid == -1)\n\t\treturn -1;\n\n\t/* Initialize s_entry */\n\ts_entry.rcv_id\t   = rcv_id;\n\ts_entry.msg.snd_id = my_id;\n\tstrcpy(s_entry.msg.text, objname);\n\tlen = strlen(s_entry.msg.text) + 1 + offsetof(struct q_msg, text);\n\n\t/* Send message, waiting if nessary */\n\tif (msgsnd(s_qid, &s_entry, len, 0) == -1) {\n\t\tMHVTL_ERR(\"msgsnd failed: %s\", strerror(errno));\n\t\treturn -1;\n\t}\n\n\treturn 0;\n}\n\nint serve(void) {\n\tint\t\t\t   mlen, r_qid;\n\tstruct q_entry r_entry;\n\n\t/* Initialise message queue as necessary */\n\tr_qid = init_queue();\n\tif (r_qid == -1)\n\t\treturn -1;\n\n\t/* Get and process next message, waiting if necessary */\n\tfor (;;) {\n\t\tmlen = msgrcv(r_qid, &r_entry, MAXOBN,\n\t\t\t\t\t  (-1 * MAXPRIOR), MSG_NOERROR);\n\t\tif (mlen == -1) {\n\t\t\tMHVTL_ERR(\"msgsnd failed: %s\", strerror(errno));\n\t\t\treturn -1;\n\t\t} else {\n\t\t\t/* Process object name */\n\t\t\tproc_obj(&r_entry);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "usr/utils/reed-solomon.c",
    "content": "/*\n * Reed-Solomon CRC defined in ECMA-319\n *\n * Lifted (copied) from IBM LTO reference guide Appendix D.\n */\n\n#include <inttypes.h>\n#include <byteswap.h>\n\n/*----------------------------------------------------------------------------\n** ABSTRACT: function to compute interim LBP CRC\n** INPUTS:\tcrc - initial crc (0 for fresh) (i.e., seed)\n**\t\tcnt - the number of data bytes to compute CRC for\n**\t\tstart - the starting address of the data bytes (e.g., data buffer)\n** OUTPUTS: uint32_t - crc in big endian (MSB is first byte)\n*/\nuint32_t GenerateRSCRC(uint32_t crc, uint32_t cnt, const void *start) {\n\tstatic const uint32_t crcTable[256] =\n\t\t{\n\t\t\t0x00000000, 0x38CF3801, 0x70837002, 0x484C4803, 0xE01BE004, 0xD8D4D805,\n\t\t\t0x90989006, 0xA857A807, 0xDD36DD08, 0xE5F9E509, 0xADB5AD0A, 0x957A950B,\n\t\t\t0x3D2D3D0C, 0x05E2050D, 0x4DAE4D0E, 0x7561750F, 0xA76CA710, 0x9FA39F11,\n\t\t\t0xD7EFD712, 0xEF20EF13, 0x47774714, 0x7FB87F15, 0x37F43716, 0x0F3B0F17,\n\t\t\t0x7A5A7A18, 0x42954219, 0x0AD90A1A, 0x3216321B, 0x9A419A1C, 0xA28EA21D,\n\t\t\t0xEAC2EA1E, 0xD20DD21F, 0x53D85320, 0x6B176B21, 0x235B2322, 0x1B941B23,\n\t\t\t0xB3C3B324, 0x8B0C8B25, 0xC340C326, 0xFB8FFB27, 0x8EEE8E28, 0xB621B629,\n\t\t\t0xFE6DFE2A, 0xC6A2C62B, 0x6EF56E2C, 0x563A562D, 0x1E761E2E, 0x26B9262F,\n\t\t\t0xF4B4F430, 0xCC7BCC31, 0x84378432, 0xBCF8BC33, 0x14AF1434, 0x2C602C35,\n\t\t\t0x642C6436, 0x5CE35C37, 0x29822938, 0x114D1139, 0x5901593A, 0x61CE613B,\n\t\t\t0xC999C93C, 0xF156F13D, 0xB91AB93E, 0x81D5813F, 0xA6ADA640, 0x9E629E41,\n\t\t\t0xD62ED642, 0xEEE1EE43, 0x46B64644, 0x7E797E45, 0x36353646, 0x0EFA0E47,\n\t\t\t0x7B9B7B48, 0x43544349, 0x0B180B4A, 0x33D7334B, 0x9B809B4C, 0xA34FA34D,\n\t\t\t0xEB03EB4E, 0xD3CCD34F, 0x01C10150, 0x390E3951, 0x71427152, 0x498D4953,\n\t\t\t0xE1DAE154, 0xD915D955, 0x91599156, 0xA996A957, 0xDCF7DC58, 0xE438E459,\n\t\t\t0xAC74AC5A, 0x94BB945B, 0x3CEC3C5C, 0x0423045D, 0x4C6F4C5E, 0x74A0745F,\n\t\t\t0xF575F560, 0xCDBACD61, 0x85F68562, 0xBD39BD63, 0x156E1564, 0x2DA12D65,\n\t\t\t0x65ED6566, 0x5D225D67, 0x28432868, 0x108C1069, 0x58C0586A, 0x600F606B,\n\t\t\t0xC858C86C, 0xF097F06D, 0xB8DBB86E, 0x8014806F, 0x52195270, 0x6AD66A71,\n\t\t\t0x229A2272, 0x1A551A73, 0xB202B274, 0x8ACD8A75, 0xC281C276, 0xFA4EFA77,\n\t\t\t0x8F2F8F78, 0xB7E0B779, 0xFFACFF7A, 0xC763C77B, 0x6F346F7C, 0x57FB577D,\n\t\t\t0x1FB71F7E, 0x2778277F, 0x51475180, 0x69886981, 0x21C42182, 0x190B1983,\n\t\t\t0xB15CB184, 0x89938985, 0xC1DFC186, 0xF910F987, 0x8C718C88, 0xB4BEB489,\n\t\t\t0xFCF2FC8A, 0xC43DC48B, 0x6C6A6C8C, 0x54A5548D, 0x1CE91C8E, 0x2426248F,\n\t\t\t0xF62BF690, 0xCEE4CE91, 0x86A88692, 0xBE67BE93, 0x16301694, 0x2EFF2E95,\n\t\t\t0x66B36696, 0x5E7C5E97, 0x2B1D2B98, 0x13D21399, 0x5B9E5B9A, 0x6351639B,\n\t\t\t0xCB06CB9C, 0xF3C9F39D, 0xBB85BB9E, 0x834A839F, 0x029F02A0, 0x3A503AA1,\n\t\t\t0x721C72A2, 0x4AD34AA3, 0xE284E2A4, 0xDA4BDAA5, 0x920792A6, 0xAAC8AAA7,\n\t\t\t0xDFA9DFA8, 0xE766E7A9, 0xAF2AAFAA, 0x97E597AB, 0x3FB23FAC, 0x077D07AD,\n\t\t\t0x4F314FAE, 0x77FE77AF, 0xA5F3A5B0, 0x9D3C9DB1, 0xD570D5B2, 0xEDBFEDB3,\n\t\t\t0x45E845B4, 0x7D277DB5, 0x356B35B6, 0x0DA40DB7, 0x78C578B8, 0x400A40B9,\n\t\t\t0x084608BA, 0x308930BB, 0x98DE98BC, 0xA011A0BD, 0xE85DE8BE, 0xD092D0BF,\n\t\t\t0xF7EAF7C0, 0xCF25CFC1, 0x876987C2, 0xBFA6BFC3, 0x17F117C4, 0x2F3E2FC5,\n\t\t\t0x677267C6, 0x5FBD5FC7, 0x2ADC2AC8, 0x121312C9, 0x5A5F5ACA, 0x629062CB,\n\t\t\t0xCAC7CACC, 0xF208F2CD, 0xBA44BACE, 0x828B82CF, 0x508650D0, 0x684968D1,\n\t\t\t0x200520D2, 0x18CA18D3, 0xB09DB0D4, 0x885288D5, 0xC01EC0D6, 0xF8D1F8D7,\n\t\t\t0x8DB08DD8, 0xB57FB5D9, 0xFD33FDDA, 0xC5FCC5DB, 0x6DAB6DDC, 0x556455DD,\n\t\t\t0x1D281DDE, 0x25E725DF, 0xA432A4E0, 0x9CFD9CE1, 0xD4B1D4E2, 0xEC7EECE3,\n\t\t\t0x442944E4, 0x7CE67CE5, 0x34AA34E6, 0x0C650CE7, 0x790479E8, 0x41CB41E9,\n\t\t\t0x098709EA, 0x314831EB, 0x991F99EC, 0xA1D0A1ED, 0xE99CE9EE, 0xD153D1EF,\n\t\t\t0x035E03F0, 0x3B913BF1, 0x73DD73F2, 0x4B124BF3, 0xE345E3F4, 0xDB8ADBF5,\n\t\t\t0x93C693F6, 0xAB09ABF7, 0xDE68DEF8, 0xE6A7E6F9, 0xAEEBAEFA, 0x962496FB,\n\t\t\t0x3E733EFC, 0x06BC06FD, 0x4EF04EFE, 0x763F76FF};\n\n\tint\t\t\t   i;\n\tconst uint8_t *d = start;\n\n\tfor (i = 0; i < cnt; i++) {\n\t\tcrc = (crc << 8) ^ crcTable[*d ^ (crc >> 24)];\n\t\td++;\n\t}\n\treturn crc;\n}\n\n/*----------------------------------------------------------------------------\n**  ABSTRACT: function to compute and append LBP CRC to a data block\n**  INPUTS:\tblkbuf  - starting address of the data block to protect\n**\t\tblklen  - length of block to protect (NOT including CRC)\n**\t\tbigendian - Check CRC in big/little endian\n**  OUTPUTS:\tuint32_t - length of protected block (to write) including LBP CRC\n*/\nuint32_t BlockProtectRSCRC(uint8_t *blkbuf, uint32_t blklen, int32_t bigendian) {\n\tuint32_t crc = GenerateRSCRC(0x00000000, blklen, blkbuf);\n\tif (blklen == 0)\n\t\treturn 0; /* no such thing as a zero length block in SSC (write NOP) */\n\n\tif (bigendian) {\n\t\t/* append CRC in proper byte order (regardless of system endian-ness) */\n\t\tblkbuf[blklen + 0] = (crc >> 24) & 0xFF;\n\t\tblkbuf[blklen + 1] = (crc >> 16) & 0xFF;\n\t\tblkbuf[blklen + 2] = (crc >> 8) & 0xFF;\n\t\tblkbuf[blklen + 3] = (crc >> 0) & 0xFF;\n\t} else {\n\t\tblkbuf[blklen + 0] = (crc >> 0) & 0xFF;\n\t\tblkbuf[blklen + 1] = (crc >> 8) & 0xFF;\n\t\tblkbuf[blklen + 2] = (crc >> 16) & 0xFF;\n\t\tblkbuf[blklen + 3] = (crc >> 24) & 0xFF;\n\t}\n\treturn (blklen + 4); /* size of block to be written includes CRC */\n}\n\n/*----------------------------------------------------------------------------\n**  ABSTRACT: function to verify block with LBP CRC\n**  INPUTS:\tblkbuf  - starting address of the data block to protect\n**\t\tblklen  - length of block to verify (INCLUDING CRC)\n**\t\tbigendian - Check CRC in big/little endian\n**  OUTPUTS:\tuint32_t - length of block w/o CRC (0 if verify failed)\n*/\nuint32_t BlockVerifyRSCRC(const uint8_t *blkbuf, uint32_t blklen, int32_t bigendian) {\n\tif (blklen <= 4)\n\t\treturn 0; /* block is too small to be valid, cannot check CRC */\n\tblklen -= 4;  /* user data portion does not include CRC */\n\n\tuint32_t crccmp;\n\tuint32_t crcblk;\n\n\t/* this matches the append method in the function above */\n\tcrcblk = (blkbuf[blklen + 0] << 24) |\n\t\t\t (blkbuf[blklen + 1] << 16) |\n\t\t\t (blkbuf[blklen + 2] << 8) |\n\t\t\t (blkbuf[blklen + 3] << 0);\n\tif (bigendian) {\n\t\tcrccmp = GenerateRSCRC(0x00000000, blklen, blkbuf);\n\t} else {\n\t\tcrccmp = __bswap_32(GenerateRSCRC(0x00000000, blklen, blkbuf));\n\t}\n\tif (crccmp != crcblk)\n\t\treturn 0; /* block CRC is incorrect */\n\treturn (blklen);\n\n#if 2 /* method 2: calculate including CRC and check magic constant */\n\t{\n\t\tif (GenerateRSCRC(0x00000000, blklen + 4, blkbuf) != 0x00000000)\n\t\t\treturn 0; /* block CRC is incorrect (CRC did not neutralize) */\n\t\treturn (blklen);\n\t}\n#endif\n}\n"
  },
  {
    "path": "usr/utils/subprocess.c",
    "content": "/*\n * Run subprocess\n *\n * Copyright (C) 2012 Ivo De Decker ivo.dedecker@ugent.be\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n */\n\n#include <unistd.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <sys/types.h>\n#include <sys/wait.h>\n#include <signal.h>\n#include \"logging.h\"\n\nstatic pid_t pid;\nstatic int\t timedout;\n\nvoid alarm_timeout(int sig) {\n\talarm(0);\n\ttimedout = 1;\n\tif (pid)\n\t\tkill(pid, 9);\n}\n\nint run_command(char *command, int timeout) {\n\tpid = fork();\n\tif (!pid) {\n\t\t/* child */\n\t\texeclp(\"/bin/sh\", \"/bin/sh\", \"-c\", command, (char *)NULL);\n\t} else if (pid < 0) {\n\t\t/* TODO error handling */\n\t\treturn -1;\n\t} else {\n\t\tsignal(SIGALRM, alarm_timeout);\n\t\ttimedout = 0;\n\t\talarm(timeout);\n\t\tint status;\n\n\t\twhile (waitpid(pid, &status, 0) <= 0)\n\t\t\tusleep(1);\n\n\t\talarm(0);\n\n\t\tif (WIFEXITED(status)) {\n\t\t\tint res = WEXITSTATUS(status);\n\t\t\treturn res;\n\t\t} else if (WIFSIGNALED(status)) {\n\t\t\tint sig = WTERMSIG(status);\n\t\t\tMHVTL_DBG(1, \"command died with signal: %d \"\n\t\t\t\t\t\t \"(timedout: %d)\\n\",\n\t\t\t\t\t  sig, timedout);\n\t\t\treturn -sig;\n\t\t}\n\t}\n\n\treturn -1;\n}\n"
  },
  {
    "path": "usr/utils/validate_crc.c",
    "content": "\n/*\n * Validate Reed-Solomon CRC and CRC32C routines pass\n * basic sanity check at compile time\n *\n * Shamelessly lifted/copied from CASTOR utils/CRCtest.cpp\n *\n * Designed to abort if CRC32C or RS-CRC fails basic sanity check\n */\n\n#include <stdio.h>\n#include <assert.h>\n#include <inttypes.h>\n\nuint32_t crc32c(uint32_t seed, const uint8_t *buf, size_t sz);\nuint32_t GenerateRSCRC(uint32_t seed, int sz, const uint8_t *buf);\n\nint main(int argc, char *argv[]) {\n\tconst uint8_t block1[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,\n\t\t\t\t\t\t\t  47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127,\n\t\t\t\t\t\t\t  131, 137, 139, 149, 151, 157};\n\n\tconst uint8_t block2[] = {163, 167, 173, 179, 181, 191, 193, 197, 199, 211,\n\t\t\t\t\t\t\t  223, 227, 229, 233, 239, 241, 251};\n\n\tuint32_t computedCRC1 = crc32c(0, block1, sizeof(block1));\n\tuint32_t computedCRC2 = crc32c(~computedCRC1, block2, sizeof(block2));\n\tuint32_t computedCRC3 = crc32c(~crc32c(0, block1, sizeof(block1)), block2, sizeof(block2));\n\n\tassert(computedCRC1 == 0xE8174F48);\n\tassert(computedCRC2 == 0x56DAB0A6);\n\tassert(computedCRC3 == 0x56DAB0A6);\n\n\tcomputedCRC1 = GenerateRSCRC(0, sizeof(block1), block1);\n\tcomputedCRC2 = GenerateRSCRC(computedCRC1, sizeof(block2), block2);\n\tcomputedCRC3 = GenerateRSCRC(GenerateRSCRC(0, sizeof(block1), block1), sizeof(block2), block2);\n\n\tassert(computedCRC1 == 0x733D4DCA);\n\tassert(computedCRC2 == 0x754ED37E);\n\tassert(computedCRC3 == 0x754ED37E);\n\n\treturn 0;\n}\n"
  },
  {
    "path": "usr/vtl_cart_type.c",
    "content": "/*\n * Version 2 of tape format.\n *\n * Each media contains 3 files.\n *  - The .data file contains each block of data written to the media\n *  - The .indx file consists of an array of one raw_header structure per\n *    written tape block or filemark.\n *  - The .meta file consists of a MAM structure followed by a meta_header\n *    structure, followed by a variable-length array of filemark block numbers.\n *\n * Copyright (C) 2009 - 2010 Kevan Rehm\n *\n * This is a vtllibrary 'helper'. This contains a function to open the media\n * metadata file and return the media type (Data, WORM, Cleaning etc)\n * Required to fill in details of READ ELEMENT STATUS - instead of just guessing\n * based on barcode, open the actual media metadata and read 'from the horses\n * mouth'\n\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n */\n\n#define _FILE_OFFSET_BITS 64\n\n#define __STDC_FORMAT_MACROS /* for PRId64 */\n\n/* for unistd.h pread/pwrite and fcntl.h posix_fadvise */\n#define _XOPEN_SOURCE 600\n\n#include <sys/stat.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include \"logging.h\"\n#include \"vtllib.h\"\n#include \"vtlcart.h\"\n\nstatic char currentPCL[HOME_DIR_PATH_SZ + MAX_BARCODE_LEN + 3]; /* make room for home_dir plus some */\n\n/*\n * Attempt to open PCL metadata and read cart type\n *\n * Returns valid SMC media type values (READ ELEMENT STATUS):\n * == 0 -> open failed or unknown cart type\n * == 1 -> Data Cart type\n * == 2 -> Cleaning\n * == 3 -> Diagnostics\n * == 4 -> WORM\n *\n * == 5 -> NULL media type (SMC specifies values > 4 as 'reserved')\n */\n\nvoid update_home_dir(long lib_id) {\n\tif (strlen(home_directory) < 2) {\n\t\tfind_media_home_directory(NULL, lib_id);\n\t\tMHVTL_DBG(3, \"Setting home dir to %s\", home_directory);\n\t}\n}\n\nint get_cart_type(const char *barcode) {\n\tchar\t   pcl[MAX_BARCODE_LEN + 1];\n\tchar\t   path[HOME_DIR_PATH_SZ + MAX_BARCODE_LEN + 4 + 10];\n\tint\t\t   rc\t   = 0;\n\tint\t\t   mamfile = -1;\n\tstruct MAM tmp_mam;\n\n\t/* init tmp_mam */\n\tinit_mam(&tmp_mam);\n\n\t/* copy barcode to &pcl and terminate at either ' ' or '\\0' */\n\tfor (int i = 0; i < MAX_BARCODE_LEN; i++) {\n\t\tpcl[i] = barcode[i];\n\t\tif (pcl[i] == ' ' || pcl[i] == '\\0') {\n\t\t\tpcl[i] = '\\0';\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tsnprintf(currentPCL, ARRAY_SIZE(currentPCL), \"%s/%s\",\n\t\t\t strlen(home_directory) ? home_directory : MHVTL_HOME_PATH,\n\t\t\t pcl);\n\n\t/* Open mam file */\n\tsnprintf(path, ARRAY_SIZE(path), \"%s/mam\", currentPCL);\n\tmamfile = open(path, O_RDWR | O_LARGEFILE);\n\tif (mamfile == -1) {\n\t\tMHVTL_ERR(\"open of file %s failed: %s\", path, strerror(errno));\n\t\trc = 0;\n\t\tgoto failed;\n\t}\n\n\t/* Read in the MAM */\n\tread_mam(mamfile, -1, &tmp_mam);\n\n\tswitch (tmp_mam.MediumType) {\n\tcase MEDIA_TYPE_NULL:\n\t\trc = 5; /* Reserved */\n\t\tbreak;\n\tcase MEDIA_TYPE_DATA:\n\t\trc = 1;\n\t\tbreak;\n\tcase MEDIA_TYPE_CLEAN:\n\t\trc = 2;\n\t\tbreak;\n\tcase MEDIA_TYPE_DIAGNOSTIC:\n\t\trc = 3;\n\t\tbreak;\n\tcase MEDIA_TYPE_WORM:\n\t\trc = 4;\n\t\tbreak;\n\tdefault:\n\t\trc = 0;\n\t\tbreak;\n\t}\n\nfailed:\n\tif (mamfile >= 0)\n\t\tclose(mamfile);\n\n\tMHVTL_DBG(3, \"Opening media: %s (barcode %s), returning type %d\",\n\t\t\t  currentPCL, barcode, rc);\n\treturn rc;\n}\n"
  },
  {
    "path": "usr/vtlcart.c",
    "content": "/*\n * Version 2 of tape format.\n *\n * Each media contains 3 files.\n *  - The .data file contains each block of data written to the media\n *  - The .indx file consists of an array of one raw_header structure per\n *    written tape block or filemark.\n *  - The .meta file consists of a MAM structure followed by a meta_header\n *    structure, followed by a variable-length array of filemark block numbers.\n *\n * Copyright (C) 2009 - 2010 Kevan Rehm\n\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n */\n\n#define _FILE_OFFSET_BITS 64\n\n#define __STDC_FORMAT_MACROS /* for PRId64 */\n\n/* for unistd.h pread/pwrite and fcntl.h posix_fadvise */\n#define _XOPEN_SOURCE 600\n\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include \"logging.h\"\n#include \"mhvtl_scsi.h\"\n#include \"vtlcart.h\"\n#include \"vtllib.h\"\n#include \"mhvtl_update.h\"\n#include \"be_byteshift.h\"\n\n/* The .indx file consists of an array of one raw_header structure per\n   written tape block or filemark.  There is no separate raw_header\n   structure required for BOT or EOM.  The raw_header structure is padded\n   out to 512 bytes to allow for the addition of fields in the future without\n   breaking backwards compatibility with existing PCL indx files.\n*/\n\nstruct raw_header {\n\tloff_t\t\t\t  data_offset;\n\tstruct blk_header hdr;\n\tchar\t\t\t  pad[512 - sizeof(loff_t) - sizeof(struct blk_header)];\n};\n\n/* The .meta file consists of a meta_header\n   structure, followed by a variable-length array of filemark block numbers.\n   Both the MAM and meta_header structures also contain padding to allow\n   for future expansion with backwards compatibility.\n*/\n\nstruct meta_header {\n\tuint32_t filemark_count;\n\tchar\t pad[512 - sizeof(uint32_t)];\n};\n\nstatic char *currentPCL = NULL;\n\nstatic int datafile[MAX_PARTITIONS] = {[0 ... MAX_PARTITIONS - 1] = -1};\nstatic int indxfile[MAX_PARTITIONS] = {[0 ... MAX_PARTITIONS - 1] = -1};\nstatic int metafile[MAX_PARTITIONS] = {[0 ... MAX_PARTITIONS - 1] = -1};\nstatic int mamfile\t\t\t\t\t= -1;\nstatic int mhvtlfile\t\t\t\t= -1;\n\nstatic struct raw_header  raw_pos;\nstatic struct meta_header meta[MAX_PARTITIONS];\nstatic uint64_t\t\t\t  eod_data_offset[MAX_PARTITIONS];\nstatic uint32_t\t\t\t  eod_blk_number[MAX_PARTITIONS];\n\n#define FM_DELTA 500\nstatic int\t\t filemark_alloc[MAX_PARTITIONS] = {[0 ... MAX_PARTITIONS - 1] = 0};\nstatic uint32_t *filemarks[MAX_PARTITIONS]\t\t= {[0 ... MAX_PARTITIONS - 1] = NULL};\n\n/* Initialisation of current position (global blk_header) */\nstruct blk_header *c_pos = &raw_pos.hdr;\n\n#ifdef MHVTL_DEBUG\nstatic char *mhvtl_block_type_desc(int blk_type) {\n\tunsigned int i;\n\n\tstatic const struct {\n\t\tint\t  blk_type;\n\t\tchar *desc;\n\t} block_type_desc[] = {\n\t\t{B_FILEMARK, \"FILEMARK\"},\n\t\t{B_EOD, \"END OF DATA\"},\n\t\t{B_NOOP, \"NO OP\"},\n\t\t{B_DATA, \"DATA\"},\n\t};\n\tfor (i = 0; i < ARRAY_SIZE(block_type_desc); i++)\n\t\tif (block_type_desc[i].blk_type == blk_type)\n\t\t\treturn block_type_desc[i].desc;\n\treturn NULL;\n}\n#endif\n\n/*\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nstatic int mkEODHeader(uint32_t blk_number, uint64_t data_offset) {\n\tuint32_t partition_id = c_pos->partition_id;\n\tmemset(&raw_pos, 0, sizeof(raw_pos));\n\n\traw_pos.data_offset = data_offset;\n\n\tc_pos->blk_type\t\t= B_EOD;\n\tc_pos->blk_number\t= blk_number;\n\tc_pos->partition_id = partition_id;\n\n\teod_blk_number[c_pos->partition_id]\t = blk_number;\n\teod_data_offset[c_pos->partition_id] = data_offset;\n\n\tOK_to_write = 1;\n\n\treturn 0;\n}\n\n/*\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nstatic int read_header(uint32_t blk_number, uint8_t *sam_stat) {\n\tloff_t nread;\n\n\tMHVTL_DBG(3, \"Reading header partition/block %d/%d\", c_pos->partition_id, blk_number);\n\n\tif (blk_number > eod_blk_number[c_pos->partition_id]) {\n\t\tMHVTL_ERR(\"Attempt to seek [%d] beyond EOD [%d]\",\n\t\t\t\t  blk_number, eod_blk_number[c_pos->partition_id]);\n\t} else if (blk_number == eod_blk_number[c_pos->partition_id])\n\t\tmkEODHeader(eod_blk_number[c_pos->partition_id], eod_data_offset[c_pos->partition_id]);\n\telse {\n\t\tnread = pread(indxfile[c_pos->partition_id], &raw_pos, sizeof(raw_pos),\n\t\t\t\t\t  blk_number * sizeof(raw_pos));\n\t\tif (nread < 0) {\n\t\t\tMHVTL_ERR(\"Medium format corrupt\");\n\t\t\tsam_medium_error(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\t\treturn -1;\n\t\t} else if (nread != sizeof(raw_pos)) {\n\t\t\tMHVTL_ERR(\"Failed to read next header\");\n\t\t\tsam_medium_error(E_END_OF_DATA, sam_stat);\n\t\t\treturn -1;\n\t\t}\n\t}\n\n\tMHVTL_DBG(3, \"Reading header partition/block %u/%u at disk offset %ld, type: %s, size: %d\",\n\t\t\t  c_pos->partition_id,\n\t\t\t  raw_pos.hdr.blk_number,\n\t\t\t  (unsigned long)raw_pos.data_offset,\n\t\t\t  mhvtl_block_type_desc(raw_pos.hdr.blk_type),\n\t\t\t  raw_pos.hdr.blk_size);\n\treturn 0;\n}\n\nstatic int tape_loaded(uint8_t *sam_stat) {\n\tif (datafile[c_pos->partition_id] != -1)\n\t\treturn 1;\n\n\tsam_not_ready(E_MEDIUM_NOT_PRESENT, sam_stat);\n\treturn 0;\n}\n\nstatic int rewrite_meta_file(void) {\n\tssize_t io_size, nwrite;\n\tsize_t\tio_offset;\n\n\tio_size = sizeof(struct meta_header);\n\tnwrite\t= pwrite(metafile[c_pos->partition_id], &meta[c_pos->partition_id], io_size, 0);\n\tif (nwrite < 0) {\n\t\tMHVTL_ERR(\"Error writing meta_header to metafile: %s\",\n\t\t\t\t  strerror(errno));\n\t\treturn -1;\n\t}\n\tif (nwrite != io_size) {\n\t\tMHVTL_ERR(\"Error writing meta_header map to metafile.\"\n\t\t\t\t  \" Expected to write %d bytes\",\n\t\t\t\t  (int)io_size);\n\t\treturn -1;\n\t}\n\n\tio_size\t  = meta[c_pos->partition_id].filemark_count * sizeof(*filemarks[c_pos->partition_id]);\n\tio_offset = sizeof(struct meta_header);\n\n\tif (io_size) {\n\t\tnwrite = pwrite(metafile[c_pos->partition_id], filemarks[c_pos->partition_id], io_size, io_offset);\n\t\tif (nwrite < 0) {\n\t\t\tMHVTL_ERR(\"Error writing filemark map to metafile: %s\",\n\t\t\t\t\t  strerror(errno));\n\t\t\treturn -1;\n\t\t}\n\t\tif (nwrite != io_size) {\n\t\t\tMHVTL_ERR(\"Error writing filemark map to metafile.\"\n\t\t\t\t\t  \" Expected to write %d bytes\",\n\t\t\t\t\t  (int)io_size);\n\t\t\treturn -1;\n\t\t}\n\t}\n\n\t/* If filemarks were overwritten, the meta file may need to be shorter\n\t   than before.\n\t*/\n\n\tif (ftruncate(metafile[c_pos->partition_id], io_offset + io_size) < 0) {\n\t\tMHVTL_ERR(\"Error truncating metafile: %s\", strerror(errno));\n\t\treturn -1;\n\t}\n\n\treturn 0;\n}\n\nstatic int check_for_overwrite(uint8_t *sam_stat) {\n\tuint32_t\t blk_number;\n\tuint64_t\t data_offset;\n\tunsigned int i;\n\n\tif (c_pos->blk_type == B_EOD)\n\t\treturn 0;\n\n\tMHVTL_DBG(2, \"At block %ld\", (unsigned long)c_pos->blk_number);\n\n\t/* We aren't at EOD so we are performing a rewrite.  Truncate\n\t   the data and index files back to the current length.\n\t*/\n\n\tblk_number\t= c_pos->blk_number;\n\tdata_offset = raw_pos.data_offset;\n\n\tif (ftruncate(indxfile[c_pos->partition_id], blk_number * sizeof(raw_pos))) {\n\t\tsam_medium_error(E_WRITE_ERROR, sam_stat);\n\t\tMHVTL_ERR(\"Index file ftruncate failure, pos: \"\n\t\t\t\t  \"%\" PRId64 \": %s\",\n\t\t\t\t  (uint64_t)blk_number * sizeof(raw_pos),\n\t\t\t\t  strerror(errno));\n\t\treturn -1;\n\t}\n\tif (ftruncate(datafile[c_pos->partition_id], data_offset)) {\n\t\tsam_medium_error(E_WRITE_ERROR, sam_stat);\n\t\tMHVTL_ERR(\"Data file ftruncate failure, pos: \"\n\t\t\t\t  \"%\" PRId64 \": %s\",\n\t\t\t\t  data_offset,\n\t\t\t\t  strerror(errno));\n\t\treturn -1;\n\t}\n\n\t/* Update the filemark map removing any filemarks which will be\n\t   overwritten.  Rewrite the filemark map so that the on-disk image\n\t   of the map is consistent with the new sizes of the other two files.\n\t*/\n\n\tfor (i = 0; i < meta[c_pos->partition_id].filemark_count; i++) {\n\t\tMHVTL_DBG(2, \"filemarks[c_pos->partition_id][%d] %d\", i, filemarks[c_pos->partition_id][i]);\n\t\tif (filemarks[c_pos->partition_id][i] >= blk_number) {\n\t\t\tMHVTL_DBG(2, \"Setting filemark_count from %d to %d\",\n\t\t\t\t\t  meta[c_pos->partition_id].filemark_count, i);\n\t\t\tmeta[c_pos->partition_id].filemark_count = i;\n\t\t\treturn rewrite_meta_file();\n\t\t}\n\t}\n\n\treturn 0;\n}\n\nstatic int check_filemarks_alloc(uint32_t count) {\n\tuint32_t new_size;\n\n\t/* See if we have enough space allocated to hold 'count' filemarks.\n\t   If not, realloc now.\n\t*/\n\n\tif (count > (uint32_t)filemark_alloc[c_pos->partition_id]) {\n\t\tnew_size = ((count + FM_DELTA - 1) / FM_DELTA) * FM_DELTA;\n\n\t\tfilemarks[c_pos->partition_id] = (uint32_t *)realloc(filemarks[c_pos->partition_id],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t new_size * sizeof(*filemarks[c_pos->partition_id]));\n\t\tif (filemarks[c_pos->partition_id] == NULL) {\n\t\t\tMHVTL_ERR(\"filemark map realloc failed, %s\",\n\t\t\t\t\t  strerror(errno));\n\t\t\treturn -1;\n\t\t}\n\t\tfilemark_alloc[c_pos->partition_id] = new_size;\n\t}\n\treturn 0;\n}\n\nstatic int add_filemark(uint32_t blk_number) {\n\t/* See if we have enough space remaining to add the new filemark.  If\n\t   not, realloc now.\n\t*/\n\n\tif (check_filemarks_alloc(meta[c_pos->partition_id].filemark_count + 1))\n\t\treturn -1;\n\n\tfilemarks[c_pos->partition_id][meta[c_pos->partition_id].filemark_count++] = blk_number;\n\n\t/* Now rewrite the meta_header structure and the filemark map. */\n\n\treturn rewrite_meta_file();\n}\n\n/*\n * Return 0 -> Not loaded.\n *        1 -> Load OK\n *        2 -> format corrupt.\n */\n\nint rewind_tape(uint8_t *sam_stat) {\n\tif (!tape_loaded(sam_stat))\n\t\treturn -1;\n\n\tif (read_header(0, sam_stat))\n\t\treturn -1;\n\n\tswitch (mam.MediumType) {\n\tcase MEDIA_TYPE_CLEAN:\n\t\tOK_to_write = 0;\n\t\tbreak;\n\tcase MEDIA_TYPE_WORM:\n\t\t/* Check if this header is a filemark and the next header\n\t\t *  is End of Data. If it is, we are OK to write\n\t\t */\n\n\t\tif (c_pos->blk_type == B_EOD ||\n\t\t\t(c_pos->blk_type == B_FILEMARK && eod_blk_number[c_pos->partition_id] == 1))\n\t\t\tOK_to_write = 1;\n\t\telse\n\t\t\tOK_to_write = 0;\n\t\tbreak;\n\tcase MEDIA_TYPE_DATA:\n\t\tOK_to_write = 1; /* Reset flag to OK. */\n\t\tbreak;\n\t}\n\n\tMHVTL_DBG(1, \"Media is%s writable\", (OK_to_write) ? \"\" : \" not\");\n\n\treturn 1;\n}\n\n/*\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nint position_to_eod(uint8_t *sam_stat) {\n\tif (!tape_loaded(sam_stat))\n\t\treturn -1;\n\n\tif (read_header(eod_blk_number[c_pos->partition_id], sam_stat))\n\t\treturn -1;\n\n\tif (mam.MediumType == MEDIA_TYPE_WORM)\n\t\tOK_to_write = 1;\n\n\treturn 0;\n}\n\n/*\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nint position_to_block(uint32_t blk_number, uint8_t *sam_stat) {\n\tif (!tape_loaded(sam_stat))\n\t\treturn -1;\n\n\tMHVTL_DBG(2, \"Position to partition/block %u/%u\", c_pos->partition_id, blk_number);\n\n\tif (mam.MediumType == MEDIA_TYPE_WORM)\n\t\tOK_to_write = 0;\n\n\tif (blk_number > eod_blk_number[c_pos->partition_id]) {\n\t\tsam_blank_check(E_END_OF_DATA, sam_stat);\n\t\tMHVTL_DBG(1, \"End of data detected while positioning\");\n\t\treturn position_to_eod(sam_stat);\n\t}\n\n\t/* Treat a position to block zero specially, as it has different\n\t   semantics than other blocks when the tape is WORM.\n\t*/\n\n\tif (blk_number == 0)\n\t\treturn rewind_tape(sam_stat);\n\telse\n\t\treturn read_header(blk_number, sam_stat);\n}\n\n/*\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nint position_blocks_forw(uint64_t count, uint8_t *sam_stat) {\n\tuint32_t\t residual;\n\tuint32_t\t blk_target;\n\tunsigned int i;\n\n\tif (!tape_loaded(sam_stat))\n\t\treturn -1;\n\n\tMHVTL_DBG(3, \"Moving %lu blocks forward from block %u/%u\", count, c_pos->partition_id, c_pos->blk_number);\n\n\tif (mam.MediumType == MEDIA_TYPE_WORM)\n\t\tOK_to_write = 0;\n\n\tblk_target = c_pos->blk_number + count;\n\n\t/* Find the first filemark forward from our current position, if any. */\n\n\tfor (i = 0; i < meta[c_pos->partition_id].filemark_count; i++) {\n\t\tMHVTL_DBG(3, \"filemark at %ld\", (unsigned long)filemarks[c_pos->partition_id][i]);\n\t\tif (filemarks[c_pos->partition_id][i] >= c_pos->blk_number)\n\t\t\tbreak;\n\t}\n\n\t/* If there is one, see if it is between our current position and our\n\t   desired destination.\n\t*/\n\n\tif (i < meta[c_pos->partition_id].filemark_count) {\n\t\tif (filemarks[c_pos->partition_id][i] >= blk_target)\n\t\t\treturn position_to_block(blk_target, sam_stat);\n\n\t\tresidual = blk_target - c_pos->blk_number + 1;\n\t\tif (read_header(filemarks[c_pos->partition_id][i] + 1, sam_stat))\n\t\t\treturn -1;\n\n\t\tMHVTL_DBG(1, \"Filemark encountered: block %d\", filemarks[c_pos->partition_id][i]);\n\t\tsam_no_sense(SD_FILEMARK, E_MARK, sam_stat);\n\t\tput_unaligned_be32(residual, &sense[3]);\n\t\treturn -1;\n\t}\n\n\tif (blk_target > eod_blk_number[c_pos->partition_id]) {\n\t\tresidual = blk_target - eod_blk_number[c_pos->partition_id];\n\t\tif (read_header(eod_blk_number[c_pos->partition_id], sam_stat))\n\t\t\treturn -1;\n\n\t\tMHVTL_DBG(1, \"Moving to EOD encountered at block %u\", eod_blk_number[c_pos->partition_id]);\n\t\tsam_blank_check(E_END_OF_DATA, sam_stat);\n\t\tput_unaligned_be32(residual, &sense[3]);\n\t\treturn -1;\n\t}\n\n\treturn position_to_block(blk_target, sam_stat);\n}\n\n/*\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nint position_blocks_back(uint64_t count, uint8_t *sam_stat) {\n\tuint32_t residual;\n\tuint32_t blk_target;\n\tint\t\t i;\n\n\tif (!tape_loaded(sam_stat))\n\t\treturn -1;\n\n\tMHVTL_DBG(2, \"Moving %lu blocks backward from block %u/%u\", count, c_pos->partition_id, c_pos->blk_number);\n\n\tif (mam.MediumType == MEDIA_TYPE_WORM)\n\t\tOK_to_write = 0;\n\n\tblk_target = c_pos->blk_number - count;\n\n\t/* Find the first filemark prior to our current position, if any. */\n\n\tfor (i = meta[c_pos->partition_id].filemark_count - 1; i >= 0; i--) {\n\t\tif (filemarks[c_pos->partition_id][i] < c_pos->blk_number)\n\t\t\tbreak;\n\t}\n\n\t/* If there is one, see if it is between our current position and our\n\t   desired destination.\n\t*/\n\tif (i >= 0) {\n\t\tif (filemarks[c_pos->partition_id][i] < blk_target)\n\t\t\treturn position_to_block(blk_target, sam_stat);\n\n\t\tresidual = c_pos->blk_number - blk_target;\n\t\tif (read_header(filemarks[c_pos->partition_id][i], sam_stat))\n\t\t\treturn -1;\n\n\t\tMHVTL_DBG(2, \"Filemark encountered: block %d\", filemarks[c_pos->partition_id][i]);\n\t\tsam_no_sense(SD_FILEMARK, E_MARK, sam_stat);\n\t\tput_unaligned_be32(residual, &sense[3]);\n\t\treturn -1;\n\t}\n\n\tif (blk_target < 0) {\n\t\tresidual = count - c_pos->blk_number;\n\t\tif (read_header(0, sam_stat))\n\t\t\treturn -1;\n\n\t\tMHVTL_DBG(1, \"Moving to BOP encountered at block 0\");\n\t\tsam_no_sense(SD_EOM, E_BOM, sam_stat);\n\t\tput_unaligned_be32(residual, &sense[3]);\n\t\treturn -1;\n\t}\n\n\treturn position_to_block(blk_target, sam_stat);\n}\n\n/*\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nint position_filemarks_forw(uint64_t count, uint8_t *sam_stat) {\n\tuint32_t\t residual;\n\tunsigned int i;\n\n\tif (!tape_loaded(sam_stat))\n\t\treturn -1;\n\n\tif (mam.MediumType == MEDIA_TYPE_WORM)\n\t\tOK_to_write = 0;\n\n\t/* Find the block number of the first filemark greater than our\n\t   current position.\n\t*/\n\n\tfor (i = 0; i < meta[c_pos->partition_id].filemark_count; i++)\n\t\tif (filemarks[c_pos->partition_id][i] >= c_pos->blk_number)\n\t\t\tbreak;\n\n\tif (i + count - 1 < meta[c_pos->partition_id].filemark_count)\n\t\treturn position_to_block(filemarks[c_pos->partition_id][i + count - 1] + 1, sam_stat);\n\telse {\n\t\tresidual = i + count - meta[c_pos->partition_id].filemark_count;\n\t\tif (read_header(eod_blk_number[c_pos->partition_id], sam_stat))\n\t\t\treturn -1;\n\n\t\tsam_blank_check(E_END_OF_DATA, sam_stat);\n\t\tput_unaligned_be32(residual, &sense[3]);\n\t\treturn -1;\n\t}\n}\n\n/*\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nint position_filemarks_back(uint64_t count, uint8_t *sam_stat) {\n\tuint32_t residual;\n\tint\t\t i;\n\n\tif (!tape_loaded(sam_stat))\n\t\treturn -1;\n\n\tif (mam.MediumType == MEDIA_TYPE_WORM)\n\t\tOK_to_write = 0;\n\n\t/* Find the block number of the first filemark less than our\n\t   current position.\n\t*/\n\n\tfor (i = meta[c_pos->partition_id].filemark_count - 1; i >= 0; i--)\n\t\tif (filemarks[c_pos->partition_id][i] < c_pos->blk_number)\n\t\t\tbreak;\n\n\tif (i + 1 >= count)\n\t\treturn position_to_block(filemarks[c_pos->partition_id][i - count + 1], sam_stat);\n\telse {\n\t\tresidual = count - i - 1;\n\t\tif (read_header(0, sam_stat))\n\t\t\treturn -1;\n\n\t\tsam_no_sense(SD_EOM, E_BOM, sam_stat);\n\t\tput_unaligned_be32(residual, &sense[3]);\n\t\treturn -1;\n\t}\n}\n\n/*\n * Reads data in mam file to the given mam pointer\n * if a fd is closed, the file is not read and no error is raised\n * Returns 0 if successful or -1 on error\n */\nint read_mam(int mam_fd, int mhvtl_fd, struct MAM *mamp) {\n\n\tif (mam_fd >= 0) {\n\t\tstruct MAM_attr attr;\n\n\t\tif (lseek(mam_fd, 0, SEEK_SET) != 0) {\n\t\t\tperror(\"fseek\");\n\t\t\treturn -1;\n\t\t}\n\n\t\t/* versions */\n\t\tif (read(mam_fd, &mamp->tape_fmt_version, sizeof(mamp->tape_fmt_version)) != sizeof(mamp->tape_fmt_version))\n\t\t\treturn -1;\n\n\t\tif (read(mam_fd, &mamp->mam_fmt_version, sizeof(mamp->mam_fmt_version)) != sizeof(mamp->tape_fmt_version))\n\t\t\treturn -1;\n\n\t\t/* mam attributes */\n\t\twhile (read(mam_fd, &attr.attribute_id, sizeof(uint16_t)) == sizeof(uint16_t)) {\n\t\t\tint idx = -1;\n\n\t\t\tif (read(mam_fd, &attr.length, sizeof(uint16_t)) != sizeof(uint16_t)) {\n\t\t\t\tMHVTL_ERR(\"Error reading attribute %04x length : %s\",\n\t\t\t\t\t\t  attr.attribute_id, strerror(errno));\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\tfor (int i = 0; i <= MAM_ATTRIBUTE_END; i++) {\n\t\t\t\tif (mamp->attributes[i].attribute_id == attr.attribute_id) {\n\t\t\t\t\tidx = i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* attribute not known: skip value */\n\t\t\tif (idx < 0) {\n\t\t\t\tif (attr.length) lseek(mam_fd, attr.length, SEEK_CUR);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (read(mam_fd, mamp->attributes[idx].value, attr.length) != attr.length) {\n\t\t\t\tMHVTL_ERR(\"Error reading mam attribute %04x value : %s\",\n\t\t\t\t\t\t  attr.attribute_id, strerror(errno));\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\n\t/* mhvtl attributes */\n\tif (mhvtl_fd >= 0) {\n\t\tstruct MHVTL_attr attr;\n\n\t\tif (lseek(mhvtl_fd, 0, SEEK_SET) != 0) {\n\t\t\tperror(\"fseek\");\n\t\t\treturn -1;\n\t\t}\n\n\t\twhile (read(mhvtl_fd, &attr.attribute_id, sizeof(uint16_t)) == sizeof(uint16_t)) {\n\t\t\tint idx = -1;\n\n\t\t\tif (read(mhvtl_fd, &attr.length, sizeof(uint16_t)) != sizeof(uint16_t)) {\n\t\t\t\tMHVTL_ERR(\"Error reading mhvtl attribute %04x length : %s\",\n\t\t\t\t\t\t  attr.attribute_id, strerror(errno));\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\tfor (int i = 0; i <= MAM_MHVTL_ATTRIBUTE_END; i++) {\n\t\t\t\tif (mamp->mhvtl_attr[i].attribute_id == attr.attribute_id) {\n\t\t\t\t\tidx = i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* attribute not known: skip value */\n\t\t\tif (idx < 0) {\n\t\t\t\tif (attr.length) lseek(mhvtl_fd, attr.length, SEEK_CUR);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (read(mhvtl_fd, mamp->mhvtl_attr[idx].value, attr.length) != attr.length) {\n\t\t\t\tMHVTL_ERR(\"Error reading mhvtl attribute %04x value : %s\",\n\t\t\t\t\t\t  attr.attribute_id, strerror(errno));\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn 0;\n}\n\n/*\n * Writes data in global struct MAM in mam/mhvtl_data files\n * Using a Type-Length-Value format to keep mam auto-descriptive\n * Returns 0 if nothing written or -1 on error\n */\nint write_mam(int mam_fd, int mhvtl_fd) {\n\n\tif ((lseek(mam_fd, 0, SEEK_SET) != 0) || (lseek(mhvtl_fd, 0, SEEK_SET) != 0)) {\n\t\tperror(\"fseek\");\n\t\treturn -1;\n\t}\n\n\t/* versions */\n\tif (write(mam_fd, &mam.tape_fmt_version, sizeof(mam.tape_fmt_version)) != sizeof(mam.tape_fmt_version))\n\t\treturn -1;\n\n\tif (write(mam_fd, &mam.mam_fmt_version, sizeof(mam.mam_fmt_version)) != sizeof(mam.tape_fmt_version))\n\t\treturn -1;\n\n\t/* mam attributes */\n\tfor (int i = 0; i < MAM_ATTRIBUTE_END; i++) {\n\t\tconst struct MAM_attr *attr = &mam.attributes[i];\n\n\t\tif (write(mam_fd, &attr->attribute_id, sizeof(uint16_t)) != sizeof(uint16_t))\n\t\t\treturn -1;\n\n\t\tif (write(mam_fd, &attr->length, sizeof(uint16_t)) != sizeof(uint16_t))\n\t\t\treturn -1;\n\n\t\tif (write(mam_fd, attr->value, attr->length) != attr->length)\n\t\t\treturn -1;\n\t}\n\n\t/* mhvtl attributes */\n\tfor (int i = 0; i < MAM_MHVTL_ATTRIBUTE_END; i++) {\n\t\tconst struct MHVTL_attr *attr = &mam.mhvtl_attr[i];\n\n\t\tif (write(mhvtl_fd, &attr->attribute_id, sizeof(uint16_t)) != sizeof(uint16_t))\n\t\t\treturn -1;\n\n\t\tif (write(mhvtl_fd, &attr->length, sizeof(uint16_t)) != sizeof(uint16_t))\n\t\t\treturn -1;\n\n\t\tif (attr->length == 0)\n\t\t\tcontinue;\n\n\t\tif (write(mhvtl_fd, attr->value, attr->length) != attr->length)\n\t\t\treturn -1;\n\t}\n\n\treturn 0;\n}\n\n/*\n * Writes data in struct MAM in mam and mhvtl_data files if tape is loaded\n * Returns 0 if nothing written or -1 on error\n */\nint rewriteMAM(uint8_t *sam_stat) {\n\tchar mam_path[1024];\n\tchar mhvtl_data_path[1024];\n\n\tif (!tape_loaded(sam_stat))\n\t\treturn -1;\n\n\t/* Rewrite MAM data */\n\tsnprintf(mam_path, sizeof(mam_path), \"%s/mam\", currentPCL);\n\tsnprintf(mhvtl_data_path, sizeof(mhvtl_data_path), \"%s/mhvtl_data\", currentPCL);\n\tif (write_mam(mamfile, mhvtlfile) < 0) {\n\t\tsam_medium_error(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\treturn -1;\n\t};\n\n\treturn 0;\n}\n\nstatic void unlink_partition(int partition_number) {\n\tchar path[1024];\n\n\tif (datafile >= 0) {\n\t\tsnprintf(path, sizeof(path), \"%s/data.%d\", currentPCL, partition_number);\n\t\tunlink(path);\n\t}\n\tif (indxfile >= 0) {\n\t\tsnprintf(path, sizeof(path), \"%s/indx.%d\", currentPCL, partition_number);\n\t\tunlink(path);\n\t}\n\tif (metafile >= 0) {\n\t\tsnprintf(path, sizeof(path), \"%s/meta.%d\", currentPCL, partition_number);\n\t\tunlink(path);\n\t}\n}\n\nstatic int open_partition(uint8_t partition_number) {\n\tint\t\t\t rc = 0;\n\tchar\t\t pcl_data[1024], pcl_indx[1024], pcl_meta[1024];\n\tconst char\t*pcl_files[3] = {pcl_data, pcl_indx, pcl_meta};\n\tstruct stat\t data_stat, indx_stat, meta_stat;\n\tstruct stat *stats[3]\t= {&data_stat, &indx_stat, &meta_stat};\n\tint\t\t\t*fd_open[3] = {&datafile[partition_number],\n\t\t\t\t\t\t\t   &indxfile[partition_number],\n\t\t\t\t\t\t\t   &metafile[partition_number]};\n\n\tsnprintf(pcl_data, ARRAY_SIZE(pcl_data), \"%s/data.%d\", currentPCL, partition_number);\n\tsnprintf(pcl_indx, ARRAY_SIZE(pcl_indx), \"%s/indx.%d\", currentPCL, partition_number);\n\tsnprintf(pcl_meta, ARRAY_SIZE(pcl_meta), \"%s/meta.%d\", currentPCL, partition_number);\n\n\tfor (int i = 0; i < 3; i++) {\n\t\t*fd_open[i] = open(pcl_files[i], O_RDWR | O_LARGEFILE);\n\t\tif (*fd_open[i] == -1) {\n\t\t\tMHVTL_ERR(\"open of file %s failed: %s\", pcl_files[i], strerror(errno));\n\t\t\trc = 3;\n\t\t}\n\t\tif (fstat(*fd_open[i], stats[i]) < 0) {\n\t\t\tMHVTL_ERR(\"stat of pcl %s file %s failed: %s\", currentPCL, pcl_files[i], strerror(errno));\n\t\t\trc = 3;\n\t\t}\n\t}\n\n\treturn rc;\n}\n\nstatic void close_partition(uint8_t partition_number) {\n\tint *fd_close[3] = {&datafile[partition_number],\n\t\t\t\t\t\t&indxfile[partition_number],\n\t\t\t\t\t\t&metafile[partition_number]};\n\tfor (int i = 0; i < 3; i++) {\n\t\tif (*fd_close[i] >= 0) {\n\t\t\tclose(*fd_close[i]);\n\t\t\t*fd_close[i] = -1;\n\t\t}\n\t}\n}\n\nint change_partition(uint8_t partition_number) {\n\tuint8_t *sam_stat = SAM_STAT_GOOD;\n\tint\t\t rc\t\t  = 0;\n\n\tclose_partition(c_pos->partition_id);\n\tc_pos->partition_id = partition_number;\n\trc\t\t\t\t\t= open_partition(partition_number);\n\tread_header(0, sam_stat);\n\treturn rc;\n}\n\nstatic void erase_partition(uint8_t *sam_stat) {\n\n\t/* Erasing all data instead of (ideally) putting Data Set Separator (DSS) from EOD */\n\tc_pos->blk_number\t= 0;\n\traw_pos.data_offset = 0;\n\tformat_partition(sam_stat);\n\tclose_partition(c_pos->partition_id);\n\tunlink_partition(c_pos->partition_id);\n}\n\n/*\n * Returns:\n * == 0, the new partition was successfully created.\n * == 2, could not create some file(s)\n * == 1, an error occurred.\n */\nstatic int create_partition(int partition_number) {\n\tchar\t\tpath[1024];\n\tint\t\t   *fd[3]\t\t= {&datafile[partition_number],\n\t\t\t\t\t\t\t   &indxfile[partition_number],\n\t\t\t\t\t\t\t   &metafile[partition_number]};\n\tconst char *file_name[] = {\"data\", \"indx\", \"meta\"};\n\n\tfor (int k = 0; k < 3; k++) {\n\t\tsnprintf(path, ARRAY_SIZE(path), \"%s/%s.%d\", currentPCL, file_name[k], partition_number);\n\t\tif (verbose)\n\t\t\tprintf(\"Creating new media %s file: %s\\n\", file_name[k], path);\n\t\t*fd[k] = open(path, O_CREAT | O_TRUNC | O_WRONLY,\n\t\t\t\t\t  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);\n\t\tif (*fd[k] == -1) {\n\t\t\tMHVTL_ERR(\"Failed to create file %s: %s\", path, strerror(errno));\n\t\t\tclose_partition(partition_number);\n\t\t\tunlink_partition(partition_number);\n\t\t\treturn 2;\n\t\t}\n\t}\n\n\tMHVTL_LOG(\"%s files created\", currentPCL);\n\n\t/* Write the meta file consisting of the meta_header\n\t   structure with the filemark count initialized to zero.\n\t*/\n\tmemset(&meta[partition_number], 0, sizeof(struct meta_header));\n\tmeta[partition_number].filemark_count = 0;\n\tif (write(metafile[partition_number], &meta[partition_number],\n\t\t\t  sizeof(struct meta_header)) != sizeof(struct meta_header)) {\n\t\tsnprintf(path, ARRAY_SIZE(path), \"%s/meta.%d\", currentPCL, partition_number);\n\t\tMHVTL_ERR(\"Failed to initialize file %s: %s\", path,\n\t\t\t\t  strerror(errno));\n\t\tclose_partition(partition_number);\n\t\tunlink_partition(partition_number);\n\t\treturn 1;\n\t}\n\n\tclose_partition(partition_number);\n\n\treturn 0;\n}\n\n/*\n * Returns:\n * == 0, the new PCL was successfully created.\n * == 2, could not create the directory or some file(s)\n * == 1, an error occurred.\n */\nint create_tape(const char *pcl, uint8_t *sam_stat) {\n\tstruct stat data_stat;\n\tchar\t\tpath[1024];\n\tchar\t\tmhvtl_data_path[1024];\n\n\t/* Attempt to create the new PCL.  This will fail if the PCL's directory\n\t   or any of the PCL's three files already exist, leaving any existing\n\t   files as they were.\n\t*/\n\n\tif (asprintf(&currentPCL, \"%s/%s\", home_directory, pcl) < 0) {\n\t\tperror(\"Could not allocate memory\");\n\t\texit(1);\n\t}\n\n\t/* Check if data file already exists, nothing to create */\n\tsnprintf(path, ARRAY_SIZE(path), \"%s/data.0\", currentPCL);\n\tif (stat(path, &data_stat) != -1) {\n\t\tif (verbose)\n\t\t\tprintf(\"error: Data file already exists for new media\\n\");\n\t\treturn 0;\n\t}\n\n\tif (verbose) printf(\"Creating new media directory: %s\\n\", currentPCL);\n\n\tif (mkdir(currentPCL, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_ISGID)) {\n\t\t/* No need to fail just because the parent dir exists */\n\t\tif (errno != EEXIST) {\n\t\t\tMHVTL_ERR(\"Failed to create directory %s: %s\",\n\t\t\t\t\t  currentPCL, strerror(errno));\n\t\t\tfree(currentPCL);\n\t\t\treturn 2;\n\t\t}\n\t}\n\n\t/* create mam/mhvtl_data files and fill them */\n\tsnprintf(path, ARRAY_SIZE(path), \"%s/mam\", currentPCL);\n\tsnprintf(mhvtl_data_path, ARRAY_SIZE(mhvtl_data_path), \"%s/mhvtl_data\", currentPCL);\n\tif (verbose) printf(\"Creating new media mam files: %s and %s\\n\", path, mhvtl_data_path);\n\tmamfile = open(path, O_CREAT | O_TRUNC | O_WRONLY,\n\t\t\t\t   S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);\n\tif (mamfile == -1) {\n\t\tMHVTL_ERR(\"Failed to create file %s: %s\", path, strerror(errno));\n\t\treturn 2;\n\t}\n\tmhvtlfile = open(mhvtl_data_path, O_CREAT | O_TRUNC | O_WRONLY,\n\t\t\t\t\t S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);\n\tif (mhvtlfile == -1) {\n\t\tMHVTL_ERR(\"Failed to create file %s: %s\", mhvtl_data_path, strerror(errno));\n\t\treturn 2;\n\t}\n\n\tif (write_mam(mamfile, mhvtlfile) < 0) {\n\t\tMHVTL_ERR(\"Failed to initialize mam/mhvtl_data files\");\n\t};\n\n\tclose(mamfile);\n\tmamfile = -1;\n\tclose(mhvtlfile);\n\tmhvtlfile = -1;\n\n\treturn create_partition(0);\n}\n\nint load_partition(const char *pcl, uint8_t *sam_stat, uint8_t error_check, uint8_t partition_number) {\n\tint\t\t\t rc = 0;\n\tchar\t\t pcl_data[1024], pcl_meta[1024];\n\tstruct stat\t data_stat, indx_stat, meta_stat;\n\tstruct stat *stats[3] = {&data_stat, &indx_stat, &meta_stat};\n\tint\t\t\t*fd[3]\t  = {&datafile[partition_number],\n\t\t\t\t\t\t\t &indxfile[partition_number],\n\t\t\t\t\t\t\t &metafile[partition_number]};\n\n\tuint64_t exp_size;\n\tsize_t\t io_size;\n\tloff_t\t nread;\n\n\t/* Open all three files and stat them to get their current sizes. */\n\n\tsnprintf(pcl_data, ARRAY_SIZE(pcl_data), \"%s/data.%d\", currentPCL, partition_number);\n\tif (stat(pcl_data, &data_stat) == -1) {\n\t\tMHVTL_DBG(2, \"Couldn't find %s, trying previous default: %s/%s\",\n\t\t\t\t  pcl_data, MHVTL_HOME_PATH, pcl);\n\t\tfree(currentPCL);\n\t\tif (asprintf(&currentPCL, \"%s/%s\", MHVTL_HOME_PATH, pcl) < 0) {\n\t\t\tperror(\"Could not allocate memory\");\n\t\t\texit(1);\n\t\t}\n\t}\n\n\t/* Opening files */\n\n\tif (open_partition(partition_number) == 3)\n\t\tgoto cleanup;\n\tfor (int i = 0; i < 3; i++) { fstat(*fd[i], stats[i]); }\n\n\t/* Verify that the metafile size is at least reasonable. */\n\texp_size = sizeof(struct meta_header);\n\tif ((uint32_t)meta_stat.st_size < exp_size) {\n\t\tMHVTL_ERR(\"sizeof(struct meta_header) - \"\n\t\t\t\t  \"pcl %s file %s is not the correct length, \"\n\t\t\t\t  \"expected at least %\" PRId64 \", actual %\" PRId64,\n\t\t\t\t  pcl, pcl_meta, exp_size, meta_stat.st_size);\n\t\tif (error_check) {\n\t\t\trc = 2;\n\t\t\tgoto cleanup;\n\t\t}\n\t}\n\n\t/* Read in the meta_header structure and sanity-check it. */\n\tnread = read(metafile[partition_number], &meta[partition_number], sizeof(struct meta_header));\n\tif (nread < 0) {\n\t\tMHVTL_ERR(\"Error reading pcl %s meta_header from \"\n\t\t\t\t  \"metafile: %s\",\n\t\t\t\t  pcl, strerror(errno));\n\t\trc = 2;\n\t\tgoto cleanup;\n\t} else if (nread != sizeof(struct meta_header)) {\n\t\tMHVTL_ERR(\"Error reading pcl %s meta header from \"\n\t\t\t\t  \"metafile: unexpected read length\",\n\t\t\t\t  pcl);\n\t\trc = 2;\n\t\tgoto cleanup;\n\t}\n\n\t/* Now recompute the correct size of the meta file. */\n\texp_size += meta[partition_number].filemark_count * sizeof(*filemarks[partition_number]);\n\tif ((uint32_t)meta_stat.st_size != exp_size) {\n\t\tMHVTL_ERR(\"sizeof(struct MAM) + sizeof(struct_meta_header) + sizeof(*filemarks[c_pos->partition_id]) - \"\n\t\t\t\t  \"pcl %s file %s is not the correct length, \"\n\t\t\t\t  \"expected %\" PRId64 \", actual %\" PRId64,\n\t\t\t\t  pcl,\n\t\t\t\t  pcl_meta, exp_size, meta_stat.st_size);\n\t\tif (error_check) {\n\t\t\trc = 2;\n\t\t\tgoto cleanup;\n\t\t}\n\t}\n\n\t/* See if we have allocated enough space for the actual number of\n\t   filemarks on the tape.  If not, realloc now.\n\t*/\n\tif (check_filemarks_alloc(meta[partition_number].filemark_count)) {\n\t\tif (error_check) {\n\t\t\trc = 3;\n\t\t\tgoto cleanup;\n\t\t}\n\t}\n\n\t/* Now read in the filemark map. */\n\tio_size = meta[partition_number].filemark_count * sizeof(*filemarks[partition_number]);\n\tif (io_size) {\n\t\tnread = read(metafile[partition_number], filemarks[partition_number], io_size);\n\t\tif (nread < 0) {\n\t\t\tMHVTL_ERR(\"Error reading pcl %s filemark map from \"\n\t\t\t\t\t  \"metafile: %s\",\n\t\t\t\t\t  pcl, strerror(errno));\n\t\t\trc = 2;\n\t\t\tgoto cleanup;\n\t\t} else if ((size_t)nread != io_size) {\n\t\t\tMHVTL_ERR(\"Error reading pcl %s filemark map from \"\n\t\t\t\t\t  \"metafile: unexpected read length\",\n\t\t\t\t\t  pcl);\n\t\t\tif (error_check) {\n\t\t\t\trc = 2;\n\t\t\t\tgoto cleanup;\n\t\t\t}\n\t\t}\n\t}\n\n\t/* Use the size of the indx file to work out where the virtual\n\t   B_EOD block resides.\n\t*/\n\n\tif ((indx_stat.st_size % sizeof(struct raw_header)) != 0) {\n\t\tMHVTL_ERR(\"pcl %s indx file has improper length, indicating \"\n\t\t\t\t  \"possible file corruption\",\n\t\t\t\t  pcl);\n\t\trc = 2;\n\t\tgoto cleanup;\n\t}\n\teod_blk_number[partition_number] = indx_stat.st_size / sizeof(struct raw_header);\n\n\t/* Make sure that the filemark map is consistent with the size of the\n\t   indx file.\n\t*/\n\tif (meta[partition_number].filemark_count && eod_blk_number[partition_number] &&\n\t\tfilemarks[partition_number][meta[partition_number].filemark_count - 1] >= eod_blk_number[partition_number]) {\n\t\tMHVTL_ERR(\"pcl %s indx file has improper length as compared \"\n\t\t\t\t  \"to the meta file, indicating possible file corruption\",\n\t\t\t\t  pcl);\n\t\tMHVTL_ERR(\"Filemark count: %u eod_blk_number: %u\",\n\t\t\t\t  meta[partition_number].filemark_count, eod_blk_number[partition_number]);\n\t\trc = 2;\n\t\tgoto cleanup;\n\t}\n\n\t/* Read in the last raw_header struct from the indx file and use that\n\t   to validate the correct size of the data file.\n\t*/\n\n\tif (eod_blk_number[partition_number] == 0)\n\t\teod_data_offset[partition_number] = 0;\n\telse {\n\t\tMHVTL_DBG(3, \"Media format sanity check - Reading block before EOD: %u\",\n\t\t\t\t  eod_blk_number[partition_number] - 1);\n\t\tif (read_header(eod_blk_number[partition_number] - 1, sam_stat)) {\n\t\t\trc = 3;\n\t\t\tgoto cleanup;\n\t\t}\n\t\teod_data_offset[partition_number] = raw_pos.data_offset +\n\t\t\t\t\t\t\t\t\t\t\traw_pos.hdr.disk_blk_size;\n\t}\n\n\tif (mam.MediumType == MEDIA_TYPE_NULL) {\n\t\tMHVTL_LOG(\"Loaded NULL media type\"); /* Skip check */\n\t} else if ((uint64_t)data_stat.st_size != eod_data_offset[partition_number]) {\n\t\tMHVTL_ERR(\"st_size != eod_data_offset - \"\n\t\t\t\t  \"pcl %s file %s is not the correct length, \"\n\t\t\t\t  \"expected %\" PRId64 \", actual %\" PRId64,\n\t\t\t\t  pcl,\n\t\t\t\t  pcl_data, eod_data_offset[partition_number], data_stat.st_size);\n\t\tif (error_check) {\n\t\t\trc = 2;\n\t\t\tgoto cleanup;\n\t\t}\n\t}\n\n\t/* Give a hint to the kernel that data, once written, tends not to be\n\t   accessed again immediately.\n\t*/\n\n\tposix_fadvise(indxfile[partition_number], 0, 0, POSIX_FADV_DONTNEED);\n\tposix_fadvise(datafile[partition_number], 0, 0, POSIX_FADV_DONTNEED);\n\ncleanup:\n\tclose_partition(partition_number);\n\treturn rc;\n}\n\n/*\n * Attempt to load PCL - i.e. Open datafile and read in BOT header & MAM\n *\n * Returns:\n * == 0 -> Load OK\n * == 1 -> Another tape already loaded.\n * == 2 -> format corrupt.\n * == 3 -> cartridge does not exist or cannot be opened.\n */\n\nint load_tape(const char *pcl, uint8_t *sam_stat) {\n\tchar\t\tpath[1024];\n\tchar\t\ttouch_file[128];\n\tuint8_t\t\terror_check;\n\tstruct stat data_stat;\n\tloff_t\t\tnread;\n\n\tsnprintf(touch_file, 127, \"%s/bypass_error_check\", MHVTL_HOME_PATH);\n\terror_check = (stat(touch_file, &data_stat) == -1) ? FALSE : TRUE;\n\n\tif (error_check) {\n\t\tMHVTL_LOG(\"WARNING - touch file %s found - bypassing sanity checks on open\", touch_file);\n\t}\n\n\t/* KFRDEBUG - sam_stat needs updates in lots of places here. */\n\n\t/* If some other PCL is already open, return. */\n\tif (datafile[c_pos->partition_id] >= 0) {\n\t\tMHVTL_DBG(1, \"Drive already full, cannot open %s\", pcl);\n\t\treturn 1;\n\t}\n\n\tMHVTL_DBG(1, \"Opening media: %s\", pcl);\n\n\t/* Determining pcl filepaths */\n\tif (!((strlen(home_directory) && asprintf(&currentPCL, \"%s/%s\", home_directory, pcl) >= 0) || asprintf(&currentPCL, \"%s/%s\", MHVTL_HOME_PATH, pcl) >= 0)) {\n\t\tperror(\"Could not allocate memory\");\n\t\texit(1);\n\t}\n\n\t/* initialize global mam */\n\tinit_mam(&mam);\n\n\t/* load MAM and sanity-check it. */\n\tsnprintf(path, ARRAY_SIZE(path), \"%s/mam\", currentPCL);\n\tprintf(\"mam from %s\\n\", path);\n\tmamfile = open(path, O_RDWR | O_LARGEFILE);\n\n\tif (mamfile == -1) { /* Check for MAM location update */\n\t\tMHVTL_ERR(\"open of file %s failed: %s\", path, strerror(errno));\n\t\tMHVTL_LOG(\"Trying to find mam in the meta file and update tape format...\");\n\n\t\tif (try_extract_mam(currentPCL)) {\n\t\t\tMHVTL_ERR(\"Could not find or extract mam file : medium corrupted\");\n\t\t\treturn 3;\n\t\t};\n\t\tmamfile = open(path, O_RDWR | O_LARGEFILE);\n\t}\n\n\t/* Reading tape/mam versions by reading tape_fmt_version and mam_fmt_version  */\n\tnread = read(mamfile, &mam.tape_fmt_version, sizeof(uint32_t));\n\tif (nread < 0) {\n\t\tMHVTL_ERR(\"Error reading pcl %s Tape Format Version from mam file: %s\",\n\t\t\t\t  pcl, strerror(errno));\n\t\tif (error_check) return 2;\n\t}\n\tnread = read(mamfile, &mam.mam_fmt_version, sizeof(uint32_t));\n\tif (nread < 0) {\n\t\tMHVTL_ERR(\"Error reading pcl %s MAM Format Version from mam file: %s\",\n\t\t\t\t  pcl, strerror(errno));\n\t\tif (error_check) return 2;\n\t}\n\n\tif (mam.mam_fmt_version != MAM_VERSION) { /* Check for MAM Format Update */\n\t\tMHVTL_ERR(\"pcl %s MAM contains incorrect media format\", pcl);\n\t\tMHVTL_LOG(\"Trying to update mam format...\");\n\t\tif (try_update_mam(currentPCL)) {\n\t\t\tMHVTL_ERR(\"Error : MAM update failed\");\n\t\t\tsam_medium_error(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\t\tif (error_check) return 2;\n\t\t}\n\t}\n\n\tsnprintf(path, ARRAY_SIZE(path), \"%s/mhvtl_data\", currentPCL);\n\tmhvtlfile = open(path, O_RDWR | O_LARGEFILE);\n\tread_mam(mamfile, mhvtlfile, &mam);\n\n\tif (mam.tape_fmt_version != TAPE_FMT_VERSION) { /* Check for Tape Format Update */\n\t\tMHVTL_ERR(\"pcl %s contains incorrect media format\", pcl);\n\t\tMHVTL_LOG(\"Trying to update tape format...\");\n\t\tif (try_update_tape(currentPCL)) {\n\t\t\tMHVTL_ERR(\"Error : Tape update failed\");\n\t\t\tsam_medium_error(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\t\tif (error_check) return 2;\n\t\t}\n\t}\n\n\t/* load all partitions */\n\tmam.num_partitions = 0;\n\tsnprintf(path, ARRAY_SIZE(path), \"%s/data.%d\", currentPCL, mam.num_partitions);\n\twhile (access(path, F_OK) == 0) {\n\t\tc_pos->partition_id = mam.num_partitions;\n\t\tload_partition(pcl, sam_stat, error_check, mam.num_partitions);\n\t\tsnprintf(path, ARRAY_SIZE(path), \"%s/data.%d\", currentPCL, ++mam.num_partitions);\n\t}\n\n\tchange_partition(0);\n\n\t/* Initialise SAM STATUS */\n\t*sam_stat = SAM_STAT_GOOD;\n\n\t/* Now initialize raw_pos by reading in the first header, if any. */\n\tif (read_header(0, sam_stat)) {\n\t\tclose_partition(c_pos->partition_id);\n\t\treturn 3;\n\t}\n\n\treturn 0;\n}\n\nvoid zero_filemark_count(void) {\n\tfree(filemarks[c_pos->partition_id]);\n\tfilemark_alloc[c_pos->partition_id] = 0;\n\tfilemarks[c_pos->partition_id]\t\t= NULL;\n\n\tmeta[c_pos->partition_id].filemark_count = 0;\n\trewrite_meta_file();\n}\n\nint format_partition(uint8_t *sam_stat) {\n\tif (!tape_loaded(sam_stat))\n\t\treturn -1;\n\n\tif (check_for_overwrite(sam_stat))\n\t\treturn -1;\n\n\tzero_filemark_count();\n\n\treturn mkEODHeader(c_pos->blk_number, raw_pos.data_offset);\n}\n\nint format_tape(uint8_t *sam_stat) {\n\tchar path[1024];\n\tint\t partition_number = 0;\n\n\t/* Erase all partitions */\n\tsnprintf(path, ARRAY_SIZE(path), \"%s/data.%d\", currentPCL, partition_number);\n\twhile (access(path, F_OK) == 0) {\n\t\tMHVTL_DBG(1, \"Erasing partition %d\", partition_number);\n\t\tchange_partition(partition_number);\n\t\terase_partition(sam_stat);\n\t\tsnprintf(path, ARRAY_SIZE(path), \"%s/data.%d\", currentPCL, ++partition_number);\n\t}\n\n\t/* Create <mam.num_partitions> partitions */\n\tfor (int j = 0; j < mam.num_partitions; ++j) {\n\t\tcreate_partition(j);\n\t}\n\n\tchange_partition(0);\n\n\treturn 0;\n}\n\n/*\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nint write_filemarks(uint32_t count, uint8_t *sam_stat) {\n\tuint32_t blk_number;\n\tuint32_t partition_id;\n\tuint64_t data_offset;\n\tssize_t\t nwrite;\n\n\tif (!tape_loaded(sam_stat))\n\t\treturn -1;\n\n\t/* Applications assume that writing a filemark (even writing zero\n\t   filemarks) will force-flush any data buffered in the drive to media\n\t   so that after the write-filemarks call returns there is no\n\t   possibility that any data previously written could be lost due\n\t   to a power hit.  Provide a similar guarantee here.\n\t*/\n\n\tif (count == 0) {\n\t\tMHVTL_DBG(2, \"Flushing data - 0 filemarks written\");\n\t\tfsync(datafile[c_pos->partition_id]);\n\t\tfsync(indxfile[c_pos->partition_id]);\n\t\tfsync(metafile[c_pos->partition_id]);\n\n\t\treturn 0;\n\t}\n\n\tif (check_for_overwrite(sam_stat))\n\t\treturn -1;\n\n\t/* Preserve existing raw_pos data we need, then clear raw_pos and\n\t   fill it in with new data.\n\t*/\n\n\tblk_number\t = c_pos->blk_number;\n\tpartition_id = c_pos->partition_id;\n\tdata_offset\t = raw_pos.data_offset;\n\n\tmemset(&raw_pos, 0, sizeof(raw_pos));\n\n\traw_pos.data_offset = data_offset;\n\n\tc_pos->blk_type\t\t = B_FILEMARK; /* Header type */\n\tc_pos->blk_flags\t = 0;\n\tc_pos->blk_number\t = blk_number;\n\tc_pos->blk_size\t\t = 0;\n\tc_pos->disk_blk_size = 0;\n\tc_pos->partition_id\t = partition_id;\n\n\t/* Now write out one header per filemark. */\n\n\tfor (; count > 0; count--, blk_number++) {\n\t\tc_pos->blk_number = blk_number;\n\n\t\tMHVTL_DBG(3, \"Writing filemark: partition/block %u/%u\", partition_id, blk_number);\n\n\t\tnwrite = pwrite(indxfile[c_pos->partition_id], &raw_pos, sizeof(raw_pos),\n\t\t\t\t\t\tblk_number * sizeof(raw_pos));\n\t\tif (nwrite != sizeof(raw_pos)) {\n\t\t\tsam_medium_error(E_WRITE_ERROR, sam_stat);\n\t\t\tMHVTL_ERR(\"Index file write failure,\"\n\t\t\t\t\t  \" pos: %\" PRId64 \": %s\",\n\t\t\t\t\t  (uint64_t)blk_number * sizeof(raw_pos),\n\t\t\t\t\t  strerror(errno));\n\t\t\treturn -1;\n\t\t}\n\t\tadd_filemark(blk_number);\n\t}\n\n\t/* Provide the force-flush guarantee. */\n\n\tfsync(datafile[c_pos->partition_id]);\n\tfsync(indxfile[c_pos->partition_id]);\n\tfsync(metafile[c_pos->partition_id]);\n\n\treturn mkEODHeader(blk_number, data_offset);\n}\n\nint write_tape_block(const uint8_t *buffer, uint32_t blk_size,\n\t\t\t\t\t uint32_t comp_size, const struct encryption *encryptp,\n\t\t\t\t\t uint8_t comp_type, uint8_t null_media_type, uint32_t crc, uint8_t *sam_stat) {\n\tuint32_t blk_number, disk_blk_size, partition_id;\n\tuint32_t max_blk_number;\n\tuint64_t data_offset;\n\tssize_t\t nwrite;\n\n\t/* Medium format limits to unsigned 32bit blks */\n\tmax_blk_number = 0xfffffff0;\n\n\tif (!tape_loaded(sam_stat))\n\t\treturn -1;\n\n\tif (check_for_overwrite(sam_stat))\n\t\treturn -1;\n\n\t/* Preserve existing raw_pos data we need, then clear out raw_pos and\n\t   fill it in with new data.\n\t*/\n\n\tblk_number\t = c_pos->blk_number;\n\tpartition_id = c_pos->partition_id;\n\tdata_offset\t = raw_pos.data_offset;\n\n\tif (blk_number > max_blk_number) {\n\t\tMHVTL_ERR(\"Too many tape blocks - 32bit overflow\");\n\t\treturn -1;\n\t}\n\n\tmemset(&raw_pos, 0, sizeof(raw_pos));\n\n\traw_pos.data_offset = data_offset;\n\n\tc_pos->blk_type\t\t= B_DATA; /* Header type */\n\tc_pos->blk_flags\t= 0;\n\tc_pos->blk_number\t= blk_number;\n\tc_pos->partition_id = partition_id;\n\tc_pos->blk_size\t\t= blk_size; /* Size of uncompressed data */\n\n\tc_pos->uncomp_crc = crc;\n\tc_pos->blk_flags |= BLKHDR_FLG_CRC; /* Logical Block Protection */\n\n\tMHVTL_DBG(2, \"CRC is 0x%08x\", crc);\n\n\tif (comp_size) {\n\t\tif (comp_type == LZO)\n\t\t\tc_pos->blk_flags |= BLKHDR_FLG_LZO_COMPRESSED;\n\t\telse\n\t\t\tc_pos->blk_flags |= BLKHDR_FLG_ZLIB_COMPRESSED;\n\t\tc_pos->disk_blk_size = disk_blk_size = comp_size;\n\t} else\n\t\tc_pos->disk_blk_size = disk_blk_size = blk_size;\n\n\tif (encryptp != NULL) {\n\t\tunsigned int i;\n\n\t\tc_pos->blk_flags |= BLKHDR_FLG_ENCRYPTED;\n\t\tc_pos->blk_encryption_info.ukad_length = encryptp->ukad_length;\n\t\tfor (i = 0; i < encryptp->ukad_length; ++i)\n\t\t\tc_pos->blk_encryption_info.ukad[i] = encryptp->ukad[i];\n\n\t\tc_pos->blk_encryption_info.akad_length = encryptp->akad_length;\n\t\tfor (i = 0; i < encryptp->akad_length; ++i)\n\t\t\tc_pos->blk_encryption_info.akad[i] = encryptp->akad[i];\n\n\t\tc_pos->blk_encryption_info.key_length = encryptp->key_length;\n\t\tfor (i = 0; i < encryptp->key_length; ++i)\n\t\t\tc_pos->blk_encryption_info.key[i] = encryptp->key[i];\n\t}\n\n\t/* Now write out both the data and the header. */\n\tif (null_media_type) {\n\t\tnwrite = disk_blk_size;\n\t} else\n\t\tnwrite = pwrite(datafile[c_pos->partition_id], buffer, disk_blk_size, data_offset);\n\tif (nwrite != disk_blk_size) {\n\t\tsam_medium_error(E_WRITE_ERROR, sam_stat);\n\n\t\tMHVTL_ERR(\"Data file write failure, pos: %\" PRId64 \": %s\",\n\t\t\t\t  data_offset, strerror(errno));\n\n\t\t/* Truncate last partital write */\n\t\tMHVTL_DBG(1, \"Truncating data file size: %\" PRId64, data_offset);\n\t\tif (ftruncate(datafile[c_pos->partition_id], data_offset) < 0) {\n\t\t\tMHVTL_ERR(\"Error truncating data: %s\", strerror(errno));\n\t\t}\n\n\t\tmkEODHeader(blk_number, data_offset);\n\t\treturn -1;\n\t}\n\n\tMHVTL_DBG(3, \"writing partition/header %d/%u at offset %lu, type: %s, size: %u\",\n\t\t\t  c_pos->partition_id,\n\t\t\t  c_pos->blk_number,\n\t\t\t  (unsigned long)raw_pos.data_offset,\n\t\t\t  mhvtl_block_type_desc(c_pos->blk_type),\n\t\t\t  c_pos->blk_size);\n\n\tnwrite = pwrite(indxfile[c_pos->partition_id], &raw_pos, sizeof(raw_pos),\n\t\t\t\t\tblk_number * sizeof(raw_pos));\n\tif (nwrite != sizeof(raw_pos)) {\n\t\tlong indxsz = (blk_number - 1) * sizeof(raw_pos);\n\n\t\tsam_medium_error(E_WRITE_ERROR, sam_stat);\n\n\t\tMHVTL_ERR(\"Index file write failure, pos: %\" PRId64 \": %s\",\n\t\t\t\t  (uint64_t)blk_number * sizeof(raw_pos),\n\t\t\t\t  strerror(errno));\n\n\t\tMHVTL_DBG(1, \"Truncating index file size to: %ld\", indxsz);\n\t\tif (ftruncate(indxfile[c_pos->partition_id], indxsz) < 0) {\n\t\t\tMHVTL_ERR(\"Error truncating indx: %s\", strerror(errno));\n\t\t}\n\n\t\tif (!null_media_type) {\n\t\t\tMHVTL_DBG(1, \"Truncating data file size: %\" PRId64,\n\t\t\t\t\t  data_offset);\n\t\t\tif (ftruncate(datafile[c_pos->partition_id], data_offset) < 0) {\n\t\t\t\tMHVTL_ERR(\"Error truncating data: %s\",\n\t\t\t\t\t\t  strerror(errno));\n\t\t\t}\n\t\t}\n\n\t\tmkEODHeader(blk_number, data_offset);\n\t\treturn -1;\n\t}\n\n\tMHVTL_DBG(3, \"Successfully wrote block: %u\", blk_number);\n\n\treturn mkEODHeader(blk_number + 1, data_offset + disk_blk_size);\n}\n\nvoid unload_tape(uint8_t *sam_stat) {\n\tfor (int j = 0; j < mam.num_partitions; ++j) {\n\t\tMHVTL_DBG(3, \"Unloading tape : partition %d\", j);\n\t\tchange_partition(j);\n\t\trewrite_meta_file();\n\t\tclose_partition(j);\n\t\tif (filemarks[j]) {\n\t\t\tfree(filemarks[j]);\n\t\t\tfilemarks[j] = NULL;\n\t\t}\n\t}\n\n\tmemset(filemark_alloc, 0, sizeof(filemark_alloc));\n\tmemset(eod_blk_number, 0, sizeof(eod_blk_number));\n\tmemset(eod_data_offset, 0, sizeof(eod_data_offset));\n\n\tif (mamfile >= 0) {\n\t\tclose(mamfile);\n\t\tmamfile = -1;\n\t}\n\n\tif (mhvtlfile >= 0) {\n\t\tclose(mhvtlfile);\n\t\tmhvtlfile = -1;\n\t}\n\n\tfree(currentPCL);\n}\n\nuint32_t read_tape_block(uint8_t *buf, uint32_t buf_size, uint8_t *sam_stat) {\n\tloff_t\t nread;\n\tuint32_t iosize;\n\n\tif (!tape_loaded(sam_stat))\n\t\treturn -1;\n\n\tMHVTL_DBG(3, \"Reading data partition/block %u/%u, size: %d\",\n\t\t\t  c_pos->partition_id, c_pos->blk_number, buf_size);\n\n\t/* The caller should have already verified that this is a\n\t   B_DATA block before issuing this read, so we shouldn't have to\n\t   worry about B_EOD or B_FILEMARK here.\n\t*/\n\n\tif (c_pos->blk_type == B_EOD) {\n\t\tsam_blank_check(E_END_OF_DATA, sam_stat);\n\t\tMHVTL_ERR(\"End of data detected while reading\");\n\t\treturn -1;\n\t}\n\n\tiosize = c_pos->disk_blk_size;\n\tif (iosize > buf_size)\n\t\tiosize = buf_size;\n\n\tnread = pread(datafile[c_pos->partition_id], buf, iosize, raw_pos.data_offset);\n\tif (nread != iosize) {\n\t\tMHVTL_ERR(\"Failed to read %d bytes\", iosize);\n\t\treturn -1;\n\t}\n\n\t/* Now position to the following block. */\n\tMHVTL_DBG(3, \"Reading data succeeded, now positioning to next header\");\n\tif (read_header(c_pos->blk_number + 1, sam_stat)) {\n\t\tMHVTL_ERR(\"Failed to read next partition/block header %u/%u\",\n\t\t\t\t  c_pos->partition_id, c_pos->blk_number + 1);\n\t\treturn -1;\n\t}\n\n\treturn nread;\n}\n\nuint64_t current_tape_offset(void) {\n\tif (datafile[c_pos->partition_id] != -1)\n\t\treturn raw_pos.data_offset;\n\n\treturn 0;\n}\n\nuint64_t current_tape_block(void) {\n\tif (datafile[c_pos->partition_id] != -1)\n\t\treturn (uint64_t)c_pos->blk_number;\n\treturn 0;\n}\n\nuint64_t last_block(uint8_t partition_number) {\n\treturn eod_blk_number[c_pos->partition_id];\n}\n\nuint64_t block_from_filemark(uint8_t partition_number, uint32_t filemark) {\n\treturn filemarks[partition_number][filemark];\n}\n\n/* Return number of filemarks up to 'block' : -1 for all */\nuint64_t count_filemarks(int64_t block) {\n\tuint64_t count;\n\n\tMHVTL_DBG(3, \"counting filemarks till partition/block %d/%ld (total = %d)\",\n\t\t\t  c_pos->partition_id, (unsigned long)block, meta[c_pos->partition_id].filemark_count);\n\n\tif (block == -1)\n\t\treturn (uint64_t)meta[c_pos->partition_id].filemark_count;\n\n\tfor (count = 0; count < meta[c_pos->partition_id].filemark_count; count++) {\n\t\tif (filemarks[c_pos->partition_id][count] >= block)\n\t\t\treturn count;\n\t}\n\treturn (uint64_t)meta[c_pos->partition_id].filemark_count;\n}\n\nstatic void enc_key_to_string(char *dst, uint8_t *key, int len) {\n\tchar b[16];\n\tint\t i;\n\n\tdst[0] = '\\0';\n\n\tfor (i = 0; i < len; i++) {\n\t\tsprintf(b, \"%02x\", key[i]);\n\t\tstrncat(dst, b, 16);\n\t}\n\tkey[i] = '\\0';\n}\n\nvoid print_raw_header(void) {\n\tchar *f\t  = NULL;\n\tchar *enc = NULL;\n\n\tenc = malloc(256);\n\tif (!enc) {\n\t\tprintf(\"Unable to malloc 256 bytes of memory to produce dump_tape report\");\n\t\tMHVTL_ERR(\"Unable to malloc 256 bytes of memory to produce dump_tape report\");\n\t\treturn;\n\t}\n\tf = malloc(256);\n\tif (!f) {\n\t\tprintf(\"Unable to malloc 256 bytes of memory to produce dump_tape report\");\n\t\tMHVTL_ERR(\"Unable to malloc 256 bytes of memory to produce dump_tape report\");\n\t\tfree(enc);\n\t\treturn;\n\t}\n\n\tsprintf(f, \"%s\", \"Hdr:\");\n\n\tswitch (c_pos->blk_type) {\n\tcase B_DATA:\n\t\tif (c_pos->blk_flags & BLKHDR_FLG_ENCRYPTED) {\n\t\t\tstrncat(f, \"Encrypt/\", 9);\n\t\t}\n\t\tif (c_pos->blk_flags & BLKHDR_FLG_ZLIB_COMPRESSED) {\n\t\t\tstrncat(f, \"zlibCompressed\", 15);\n\t\t} else if (c_pos->blk_flags & BLKHDR_FLG_LZO_COMPRESSED) {\n\t\t\tstrncat(f, \"lzoCompressed\", 14);\n\t\t} else {\n\t\t\tstrncat(f, \"non-compressed\", 15);\n\t\t}\n\n\t\tif (c_pos->blk_flags & BLKHDR_FLG_CRC) {\n\t\t\tstrncat(f, \" with crc\", 10);\n\t\t} else {\n\t\t\tstrncat(f, \" no crc\", 10);\n\t\t}\n\t\tbreak;\n\tcase B_FILEMARK:\n\t\tstrncat(f, \"Filemark\", 9);\n\t\tbreak;\n\tcase B_EOD:\n\t\tstrncat(f, \"End of Data\", 12);\n\t\tbreak;\n\tcase B_NOOP:\n\t\tstrncat(f, \"No Operation\", 13);\n\t\tbreak;\n\tdefault:\n\t\tstrncat(f, \"Unknown type\", 13);\n\t\tbreak;\n\t}\n\tprintf(\"%-35s (0x%02x/0x%02x), sz: %6d/%-6d, Blk No.: %7u, data_offset: %10\" PRId64 \", CRC: %08x\\n\",\n\t\t   f,\n\t\t   c_pos->blk_type,\n\t\t   c_pos->blk_flags,\n\t\t   c_pos->disk_blk_size,\n\t\t   c_pos->blk_size,\n\t\t   c_pos->blk_number,\n\t\t   raw_pos.data_offset,\n\t\t   c_pos->uncomp_crc);\n\tif ((c_pos->blk_type == B_DATA) && (c_pos->blk_flags & BLKHDR_FLG_ENCRYPTED)) {\n\n\t\tprintf(\"   => Encr key length %d, ukad length %d, \"\n\t\t\t   \"akad length %d\\n\",\n\t\t\t   c_pos->blk_encryption_info.key_length,\n\t\t\t   c_pos->blk_encryption_info.ukad_length,\n\t\t\t   c_pos->blk_encryption_info.akad_length);\n\n\t\tif (c_pos->blk_encryption_info.key_length > 0) {\n\t\t\tenc_key_to_string(enc, c_pos->blk_encryption_info.key, c_pos->blk_encryption_info.key_length);\n\t\t\tprintf(\"%12s : %32s\\n\", \"Key\", enc);\n\t\t}\n\t\tif (c_pos->blk_encryption_info.ukad_length > 0) {\n\t\t\tenc_key_to_string(enc, c_pos->blk_encryption_info.ukad, c_pos->blk_encryption_info.ukad_length);\n\t\t\tprintf(\"%12s : %32s\\n\", \"Ukad\", enc);\n\t\t}\n\t\tif (c_pos->blk_encryption_info.akad_length > 0) {\n\t\t\tenc_key_to_string(enc, c_pos->blk_encryption_info.akad, c_pos->blk_encryption_info.akad_length);\n\t\t\tprintf(\"%12s : %32s\\n\", \"Akad\", enc);\n\t\t}\n\t}\n\n\tfree(enc);\n\tfree(f);\n}\n\nvoid print_filemark_count(void) {\n\tprintf(\"Total num of filemarks: %d\\n\", meta[c_pos->partition_id].filemark_count);\n}\n\nvoid print_metadata(void) {\n\tunsigned int a;\n\n\tfor (a = 0; a < meta[c_pos->partition_id].filemark_count; a++)\n\t\tprintf(\"Filemark: %d\\n\", filemarks[c_pos->partition_id][a]);\n}\n\n/*\n * Cleanup entry point\n */\nvoid cart_deinit(void) {\n\tfor (int j = 0; j < mam.num_partitions; j++) {\n\t\tfree(filemarks[j]);\n\t\tfilemarks[j] = NULL;\n\t}\n}\n"
  },
  {
    "path": "usr/vtlcart_v1.c",
    "content": "/*\n * Original tape format.\n *\n * Basically a double-linked-list headers followed by the block of data.\n * Each header describes the header type (data, filemark, EOD etc\n * along with pointer to previous and next block\n *\n * Copyright (C) 2005 - 2025 Mark Harvey       markh794@gmail.com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n */\n\n/* for unistd.h pread() and pwrite() prototypes */\n#define _XOPEN_SOURCE 500\n\n#include <sys/syslog.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <string.h>\n#include <unistd.h>\n#include <zlib.h>\n\n#include \"mhvtl_scsi.h\"\n#include \"vtlcart.h\"\n#include \"be_byteshift.h\"\n\n#define B_BOT 14 /* Beginning of Tape TAPE_FMT_VERSION 2 */\n\nstruct raw_header {\n\tloff_t\t\t\t  prev_blk;\n\tloff_t\t\t\t  curr_blk;\n\tloff_t\t\t\t  next_blk;\n\tstruct blk_header hdr;\n\tchar\t\t\t  pad[512 - (3 * sizeof(loff_t)) - sizeof(struct blk_header)];\n};\n\nstatic struct raw_header raw_pos;\nstatic int\t\t\t\t datafile = -1;\nstatic uint8_t\t\t\t MediumType;\nstatic char\t\t\t\t currentMedia[1024];\n\n/* GLobally visible variables. */\n\nint OK_to_write;\n\n/*\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nstatic int read_header(struct raw_header *h, uint8_t *sam_stat) {\n\tloff_t nread;\n\n\tnread = read(datafile, h, sizeof(*h));\n\tif (nread < 0) {\n\t\tsam_medium_error(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\treturn -1;\n\t} else if (nread != sizeof(*h)) {\n\t\tsam_medium_error(E_END_OF_DATA, sam_stat);\n\t\treturn -1;\n\t}\n\treturn 0;\n}\n\nstatic loff_t position_to_curr_header(uint8_t *sam_stat) {\n\treturn (lseek64(datafile, raw_pos.curr_blk, SEEK_SET));\n}\n\nstatic int skip_to_next_header(uint8_t *sam_stat) {\n\tif (raw_pos.hdr.blk_type == B_EOD) {\n\t\tsam_blank_check(E_END_OF_DATA, sam_stat);\n\t\tMHVTL_DBG(1, \"End of data detected while forward SPACEing!!\");\n\t\treturn -1;\n\t}\n\n\tif (raw_pos.next_blk != lseek64(datafile, raw_pos.next_blk, SEEK_SET)) {\n\t\tsam_medium_error(E_SEQUENTIAL_POSITION_ERR, sam_stat);\n\t\tMHVTL_DBG(1, \"Unable to seek to next block header\");\n\t\treturn -1;\n\t}\n\tif (read_header(&raw_pos, sam_stat)) {\n\t\tsam_medium_error(E_SEQUENTIAL_POSITION_ERR, sam_stat);\n\t\tMHVTL_DBG(1, \"Unable to read next block header\");\n\t\treturn -1;\n\t}\n\t// Position to start of header (rewind over header)\n\tif (raw_pos.curr_blk != position_to_curr_header(sam_stat)) {\n\t\tsam_medium_error(E_SEQUENTIAL_POSITION_ERR, sam_stat);\n\t\tMHVTL_DBG(1, \"Error position in datafile. Offset: %\" PRId64,\n\t\t\t\t  raw_pos.curr_blk);\n\t\treturn -1;\n\t}\n\treturn 0;\n}\n\nstatic int skip_to_prev_header(uint8_t *sam_stat) {\n\t// Position to previous header\n\tMHVTL_DBG(3, \"Positioning to raw_pos.prev_blk: %\" PRId64,\n\t\t\t  raw_pos.prev_blk);\n\tif (raw_pos.prev_blk != lseek64(datafile, raw_pos.prev_blk, SEEK_SET)) {\n\t\tsam_medium_error(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\tMHVTL_DBG(1, \"Error position in datafile !!\");\n\t\treturn -1;\n\t}\n\t// Read in header\n\tMHVTL_DBG(3, \"Reading in header: %d bytes\", (int)sizeof(raw_pos));\n\n\tif (read_header(&raw_pos, sam_stat)) {\n\t\tMHVTL_DBG(1, \"Error reading datafile while reverse SPACEing\");\n\t\treturn -1;\n\t}\n\tif (raw_pos.hdr.blk_type == B_BOT) {\n\t\tMHVTL_DBG(3, \"Found Beginning Of Tape, \"\n\t\t\t\t\t \"Skipping to next header..\");\n\t\tskip_to_next_header(sam_stat);\n\t\tsam_medium_error(E_BOM, sam_stat);\n\t\tMHVTL_DBG(3, \"Found BOT!!\");\n\t\treturn -1;\n\t}\n\n\t// Position to start of header (rewind over header)\n\tif (raw_pos.curr_blk != position_to_curr_header(sam_stat)) {\n\t\tsam_medium_error(E_SEQUENTIAL_POSITION_ERR, sam_stat);\n\t\tMHVTL_DBG(1, \"Error position in datafile !!\");\n\t\treturn -1;\n\t}\n\tMHVTL_DBG(3, \"Rewinding over header just read in: \"\n\t\t\t\t \"curr_position: %\" PRId64,\n\t\t\t  raw_pos.curr_blk);\n\treturn 0;\n}\n\n/*\n * Create & write a new block header\n *\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nstatic int mkNewHeader(uint32_t type, int blk_size, int comp_size,\n\t\t\t\t\t   const struct encryption *cp, uint8_t *sam_stat) {\n\tstruct raw_header h;\n\n\tmemset(&h, 0, sizeof(h));\n\n\th.hdr.blk_type\t = type; /* Header type */\n\th.hdr.blk_flags\t = 0;\n\th.hdr.blk_number = raw_pos.hdr.blk_number;\n\n\tif (type != B_DATA) {\n\t\th.hdr.blk_size\t\t= 0;\n\t\th.hdr.disk_blk_size = 0;\n\t} else {\n\t\th.hdr.blk_size = blk_size; /* Size of uncompressed data */\n\n\t\tif (comp_size) {\n\t\t\th.hdr.blk_flags |= BLKHDR_FLG_COMPRESSED;\n\t\t\th.hdr.disk_blk_size = comp_size;\n\t\t} else {\n\t\t\th.hdr.disk_blk_size = blk_size;\n\t\t}\n\n\t\tif (cp != NULL) {\n\t\t\tint i;\n\n\t\t\th.hdr.blk_flags |= BLKHDR_FLG_ENCRYPTED;\n\t\t\th.hdr.encryption.ukad_length = cp->ukad_length;\n\t\t\tfor (i = 0; i < cp->ukad_length; ++i) {\n\t\t\t\th.hdr.encryption.ukad[i] = cp->ukad[i];\n\t\t\t}\n\n\t\t\th.hdr.encryption.akad_length = cp->akad_length;\n\t\t\tfor (i = 0; i < cp->akad_length; ++i) {\n\t\t\t\th.hdr.encryption.akad[i] = cp->akad[i];\n\t\t\t}\n\n\t\t\th.hdr.encryption.key_length = cp->key_length;\n\t\t\tfor (i = 0; i < cp->key_length; ++i) {\n\t\t\t\th.hdr.encryption.key[i] = cp->key[i];\n\t\t\t}\n\t\t}\n\t}\n\n\th.curr_blk = lseek64(datafile, 0, SEEK_CUR); // Update current position\n\n\t/* If we are writing a new EOD marker,\n\t *  - then set next pointer to itself\n\t * else\n\t *  - Set pointer to next header (header size + size of data)\n\t */\n\tif (type == B_EOD)\n\t\th.next_blk = h.curr_blk;\n\telse\n\t\th.next_blk = h.curr_blk + h.hdr.disk_blk_size + sizeof(h);\n\n\tif (h.curr_blk == raw_pos.curr_blk) {\n\t\t/* If current pos == last header read in we are about to overwrite the\n\t\t * current header block\n\t\t */\n\t\th.prev_blk\t\t = raw_pos.prev_blk;\n\t\th.hdr.blk_number = raw_pos.hdr.blk_number;\n\t} else if (h.curr_blk == raw_pos.next_blk) {\n\t\t/* New header block at end of data file.. */\n\t\th.prev_blk\t\t = raw_pos.curr_blk;\n\t\th.hdr.blk_number = raw_pos.hdr.blk_number + 1;\n\t} else {\n\t\tMHVTL_DBG(1, \"Position error blk No: %d, Pos: %\" PRId64 \", Exp: %\" PRId64,\n\t\t\t\t  h.hdr.blk_number, h.curr_blk, raw_pos.curr_blk);\n\t\tsam_medium_error(E_SEQUENTIAL_POSITION_ERR, sam_stat);\n\t\treturn -1;\n\t}\n\n\tif (write(datafile, &h, sizeof(h)) != sizeof(h)) {\n\t\tsam_medium_error(E_WRITE_ERROR, sam_stat);\n\t\tMHVTL_DBG(1, \"Write failure, pos: %\" PRId64 \": %s\",\n\t\t\t\t  h.curr_blk, strerror(errno));\n\t\treturn -1;\n\t}\n\n\t/*\n\t * Write was successful, update raw_pos with this header block.\n\t */\n\n\tmemcpy(&raw_pos, &h, sizeof(h)); // Update where we think we are..\n\n\treturn 0;\n}\n\n/*\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nstatic int\nmkEODHeader(uint8_t *sam_stat) {\n\tif (mkNewHeader(B_EOD, 0, 0, NULL, sam_stat))\n\t\treturn -1;\n\n\tif (MediumType == MEDIA_TYPE_WORM)\n\t\tOK_to_write = 1;\n\n\t/* If we have just written a END OF DATA marker,\n\t * rewind to just before it. */\n\t// Position to start of header (rewind over header)\n\tif (raw_pos.curr_blk != position_to_curr_header(sam_stat)) {\n\t\tsam_medium_error(E_SEQUENTIAL_POSITION_ERR, sam_stat);\n\t\tMHVTL_DBG(1, \"Failed to write EOD header\");\n\t\treturn -1;\n\t}\n\treturn 0;\n}\n\n/*\n *\n */\n\nstatic int\nskip_prev_filemark(uint8_t *sam_stat) {\n\n\tif (raw_pos.hdr.blk_type == B_FILEMARK)\n\t\traw_pos.hdr.blk_type = B_NOOP;\n\twhile (raw_pos.hdr.blk_type != B_FILEMARK) {\n\t\tif (raw_pos.hdr.blk_type == B_BOT) {\n\t\t\tsam_no_sense(0, E_BOM, sam_stat);\n\t\t\tMHVTL_DBG(2, \"Found Beginning of tape\");\n\t\t\treturn -1;\n\t\t}\n\t\tif (skip_to_prev_header(sam_stat))\n\t\t\treturn -1;\n\t}\n\treturn 0;\n}\n\n/*\n *\n */\nstatic int\nskip_next_filemark(uint8_t *sam_stat) {\n\t// While blk header is NOT a filemark, keep skipping to next header\n\twhile (raw_pos.hdr.blk_type != B_FILEMARK) {\n\t\t// END-OF-DATA -> Treat this as an error - return..\n\t\tif (raw_pos.hdr.blk_type == B_EOD) {\n\t\t\tsam_blank_check(E_END_OF_DATA, sam_stat);\n\t\t\tMHVTL_DBG(2, \"%s\", \"Found end of media\");\n\t\t\tif (MediumType == MEDIA_TYPE_WORM)\n\t\t\t\tOK_to_write = 1;\n\t\t\treturn -1;\n\t\t}\n\t\tif (skip_to_next_header(sam_stat))\n\t\t\treturn -1; // On error\n\t}\n\t// Position to header AFTER the FILEMARK..\n\tif (skip_to_next_header(sam_stat))\n\t\treturn -1;\n\n\treturn 0;\n}\n\nstatic int\ntape_loaded(uint8_t *sam_stat) {\n\tswitch (datafile != -1) {\n\t\treturn 1;\n\t}\n\tsam_not_ready(E_MEDIUM_NOT_PRESENT, sam_stat);\n\treturn 0;\n}\n\n/*\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nint position_to_eod(uint8_t *sam_stat) {\n\tif (!tape_loaded(sam_stat)) {\n\t\treturn -1;\n\t}\n\n\twhile (raw_pos.hdr.blk_type != B_EOD) {\n\t\tif (skip_to_next_header(sam_stat)) {\n\t\t\treturn -1;\n\t\t}\n\t}\n\n\tif (MediumType == MEDIA_TYPE_WORM)\n\t\tOK_to_write = 1;\n\treturn 0;\n}\n\n/*\n * Rewind 'tape'.\n */\nstatic int\nrawRewind(uint8_t *sam_stat) {\n\toff64_t retval;\n\n\t// Start at beginning of datafile..\n\tretval = lseek64(datafile, 0L, SEEK_SET);\n\tif (retval < 0) {\n\t\tMHVTL_DBG(1, \"Can't seek to beginning of file: %s\",\n\t\t\t\t  strerror(errno));\n\t\treturn -1;\n\t}\n\n\t/*\n\t * Read header..\n\t * If this is not the BOT header we are in trouble\n\t */\n\tif (read_header(&raw_pos, sam_stat)) {\n\t\treturn -1;\n\t}\n\n\treturn 0;\n}\n\n/*\n * Rewind to beginning of data file and the position to first data header.\n *\n * Return 0 -> Not loaded.\n *        1 -> Load OK\n *        2 -> format corrupt.\n */\nint rewind_tape(uint8_t *sam_stat) {\n\tif (rawRewind(sam_stat)) {\n\t\tsam_medium_error(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\treturn 2;\n\t}\n\n\tif (raw_pos.hdr.blk_type != B_BOT) {\n\t\tsam_medium_error(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\treturn 2;\n\t}\n\n\tif (skip_to_next_header(sam_stat))\n\t\treturn 2;\n\n\tswitch (MediumType) {\n\tcase MEDIA_TYPE_CLEAN:\n\t\tOK_to_write = 0;\n\t\tbreak;\n\tcase MEDIA_TYPE_WORM:\n\t\t/* Special condition...\n\t\t * If we\n\t\t * - rewind,\n\t\t * - write filemark\n\t\t * - EOD\n\t\t * We set this as writable media as the tape is blank.\n\t\t */\n\t\tif (raw_pos.hdr.blk_type != B_EOD)\n\t\t\tOK_to_write = 0;\n\n\t\t// Check that this header is a filemark and the next header\n\t\t//  is End of Data. If it is, we are OK to write\n\t\tif (raw_pos.hdr.blk_type == B_FILEMARK) {\n\t\t\tskip_to_next_header(sam_stat);\n\t\t\tif (raw_pos.hdr.blk_type == B_EOD)\n\t\t\t\tOK_to_write = 1;\n\t\t}\n\t\t// Now we have to go thru thru the rewind again..\n\t\tif (rawRewind(sam_stat)) {\n\t\t\tsam_medium_error(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\t\treturn 2;\n\t\t}\n\n\t\t// No need to do all previous error checking...\n\t\tskip_to_next_header(sam_stat);\n\t\tbreak;\n\tcase MEDIA_TYPE_DATA:\n\t\tOK_to_write = 1; // Reset flag to OK.\n\t\tbreak;\n\t}\n\n\tMHVTL_DBG(1, \"Media is %s\",\n\t\t\t  (OK_to_write) ? \"writable\" : \"not writable\");\n\n\treturn 1;\n}\n\n/*\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nint position_to_block(uint32_t blk_no, uint8_t *sam_stat) {\n\tif (!tape_loaded(sam_stat)) {\n\t\treturn -1;\n\t}\n\n\tif (MediumType == MEDIA_TYPE_WORM)\n\t\tOK_to_write = 0;\n\n\tif (blk_no < raw_pos.hdr.blk_number && raw_pos.hdr.blk_number - blk_no > blk_no) {\n\t\tif (rewind_tape(sam_stat))\n\t\t\treturn -1;\n\t}\n\twhile (raw_pos.hdr.blk_number != blk_no) {\n\t\tif (raw_pos.hdr.blk_number > blk_no) {\n\t\t\tif (skip_to_prev_header(sam_stat) == -1)\n\t\t\t\treturn -1;\n\t\t} else {\n\t\t\tif (skip_to_next_header(sam_stat) == -1)\n\t\t\t\treturn -1;\n\t\t}\n\t}\n\treturn 0;\n}\n\n/*\n * 'count' is in the range 0xff000001 to 0x00ffffff\n *\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nint position_blocks(int32_t count, uint8_t *sam_stat) {\n\tif (!tape_loaded(sam_stat)) {\n\t\treturn -1;\n\t}\n\n\tif (MediumType == MEDIA_TYPE_WORM)\n\t\tOK_to_write = 0;\n\n\tif (count < 0) {\n\t\tfor (; count < 0; count++) {\n\t\t\tif (skip_to_prev_header(sam_stat))\n\t\t\t\treturn -1;\n\t\t\tif (raw_pos.hdr.blk_type == B_FILEMARK) {\n\t\t\t\tsam_no_sense(SD_FILEMARK, E_MARK, sam_stat);\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor (; count > 0; count--) {\n\t\t\tif (skip_to_next_header(sam_stat))\n\t\t\t\treturn -1;\n\t\t\tif (raw_pos.hdr.blk_type == B_FILEMARK) {\n\t\t\t\tsam_no_sense(SD_FILEMARK, E_MARK, sam_stat);\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\treturn 0;\n}\n\n/*\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nint position_filemarks(int32_t count, uint8_t *sam_stat) {\n\tif (!tape_loaded(sam_stat)) {\n\t\treturn -1;\n\t}\n\n\tif (MediumType == MEDIA_TYPE_WORM)\n\t\tOK_to_write = 0;\n\n\tif (count < 0) {\n\t\tfor (; count < 0; count++)\n\t\t\tif (skip_prev_filemark(sam_stat))\n\t\t\t\treturn -1;\n\t} else {\n\t\tfor (; count > 0; count--)\n\t\t\tif (skip_next_filemark(sam_stat))\n\t\t\t\treturn -1;\n\t}\n\treturn 0;\n}\n\n/*\n * Writes data in struct MAM back to beginning of datafile..\n * Returns 0 if nothing written or -1 on error\n */\nint rewriteMAM(uint8_t *sam_stat) {\n\tloff_t nwrite = 0;\n\n\t// Rewrite MAM data\n\tnwrite = pwrite(datafile, &mam, sizeof(mam), sizeof(struct blk_header));\n\tif (nwrite != sizeof(mam)) {\n\t\tsam_medium_error(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\treturn -1;\n\t}\n\tMediumType = mam.MediumType;\n\n\treturn 0;\n}\n\n/*\n * Returns:\n * == 0, the new PCL was successfully created.\n * == 2, the PCL (probably) already existed.\n * == 1, an error occurred.\n */\n\nint create_tape(const char *pcl, const struct MAM *mamp, uint8_t *sam_stat) {\n\tchar\t\t\t  newMedia[1024];\n\tstruct raw_header h;\n\n\t/* Attempt to create the new PCL.  It will fail if the PCL already exists. */\n\n\tsprintf((char *)newMedia, \"%s/%s\", MHVTL_HOME_PATH, pcl);\n\tsyslog(LOG_DAEMON | LOG_INFO, \"%s being created\", newMedia);\n\tdatafile = open((char *)newMedia, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);\n\tif (datafile == -1) {\n\t\tperror(\"Failed creating file\");\n\t\treturn 2;\n\t}\n\n\t/* Write a B_BOT record consisting of the B_BOT header plus the MAM. */\n\n\tmemset(&h, 0, sizeof(h));\n\th.next_blk\t   = sizeof(*mamp) + sizeof(h);\n\th.hdr.blk_type = B_BOT;\n\th.hdr.blk_size = ntohll(mamp->max_capacity) / 1048576;\n\n\tif (write(datafile, &h, sizeof(h)) != sizeof(h)) {\n\t\tperror(\"Unable to write header\");\n\t\tunlink(newMedia);\n\t\treturn 1;\n\t}\n\n\tif (write(datafile, mamp, sizeof(*mamp)) != sizeof(*mamp)) {\n\t\tperror(\"Unable to write MAM\");\n\t\tunlink(newMedia);\n\t\treturn 1;\n\t}\n\n\t/* Write a B_EOD record. */\n\n\tmemset(&h, 0, sizeof(h));\n\th.curr_blk\t   = lseek64(datafile, 0, SEEK_CUR);\n\th.next_blk\t   = h.curr_blk;\n\th.hdr.blk_type = B_EOD;\n\n\tif (write(datafile, &h, sizeof(h)) != sizeof(h)) {\n\t\tperror(\"Unable to write header\");\n\t\tunlink(newMedia);\n\t\treturn 1;\n\t}\n\n\tclose(datafile);\n\tdatafile = -1;\n\treturn 0;\n}\n\n/*\n * Attempt to load PCL - i.e. Open datafile and read in BOT header & MAM\n *\n * Returns:\n * == 0 -> Load OK\n * == 1 -> Tape already loaded.\n * == 2 -> format corrupt.\n * == 3 -> cartridge does not exist or cannot be opened.\n */\n\nint load_tape(const char *pcl, uint8_t *sam_stat) {\n\tloff_t nread;\n\n\t/* KFRDEBUG - sam_stat needs updates in lots of places here. */\n\n\tif (datafile == -1)\n\t\treturn 1;\n\n\tsprintf(currentMedia, \"%s/%s\", MHVTL_HOME_PATH, pcl);\n\tMHVTL_DBG(2, \"Opening file/media %s\", currentMedia);\n\tif ((datafile = open(currentMedia, O_RDWR | O_LARGEFILE)) == -1) {\n\t\tMHVTL_DBG(1, \"%s: open file/media failed, %s\", currentMedia,\n\t\t\t\t  strerror(errno));\n\t\treturn 3; // Unsuccessful load\n\t}\n\n\t// Now read in header information from just opened datafile\n\tnread = read(datafile, &raw_pos, sizeof(raw_pos));\n\tif (nread < 0) {\n\t\tMHVTL_DBG(1, \"%s: %s\",\n\t\t\t\t  \"Error reading header in datafile, load failed\",\n\t\t\t\t  strerror(errno));\n\t\tclose(datafile);\n\t\tdatafile = -1;\n\t\treturn 2;\t\t\t\t\t\t  // Unsuccessful load\n\t} else if (nread < sizeof(raw_pos)) { // Did not read anything...\n\t\tMHVTL_DBG(1, \"%s: %s\",\n\t\t\t\t  \"Error: Not a tape format, load failed\",\n\t\t\t\t  strerror(errno));\n\t\tclose(datafile);\n\t\tdatafile = -1;\n\t\treturn 2;\n\t}\n\tif (raw_pos.hdr.blk_type != B_BOT) {\n\t\tMHVTL_DBG(1, \"Header type: %d not valid, load failed\",\n\t\t\t\t  raw_pos.hdr.blk_type);\n\t\tclose(datafile);\n\t\tdatafile = -1;\n\t\treturn 2;\n\t}\n\t// FIXME: Need better validation checking here !!\n\tif (raw_pos.next_blk != (sizeof(raw_pos) + sizeof(mam))) {\n\t\tMHVTL_DBG(1, \"MAM size incorrect, load failed\"\n\t\t\t\t\t \" - Expected size: %d, size found: %\" PRId64,\n\t\t\t\t  (int)(sizeof(raw_pos) + sizeof(mam)),\n\t\t\t\t  raw_pos.next_blk);\n\t\tclose(datafile);\n\t\tdatafile = -1;\n\t\treturn 2; // Unsuccessful load\n\t}\n\tnread = read(datafile, &mam, sizeof(mam));\n\tif (nread < 0) {\n\t\tMHVTL_DBG(1, \"Can not read MAM from mounted media, %s\", strerror(errno));\n\t\tclose(datafile);\n\t\tdatafile = -1;\n\t\treturn 2; // Unsuccessful load\n\t}\n\tif (nread != sizeof(mam)) {\n\t\tMHVTL_DBG(1, \"Can not read MAM from mounted media, insufficient data\");\n\t\tclose(datafile);\n\t\tdatafile = -1;\n\t\treturn 2; // Unsuccessful load\n\t}\n\n\tif (mam.tape_fmt_version != TAPE_FMT_VERSION) {\n\t\tMHVTL_DBG(1, \"Incorrect media format\");\n\t\tsam_medium_error(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\tclose(datafile);\n\t\tdatafile = -1;\n\t\treturn 2;\n\t}\n\n\tMediumType = mam.MediumType;\n\tc_pos\t   = &raw_pos.hdr;\n\treturn 0;\n}\n\n/*\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nint write_filemarks(uint32_t count, uint8_t *sam_stat) {\n\tif (!tape_loaded(sam_stat)) {\n\t\treturn -1;\n\t}\n\n\tif (count > 0) {\n\t\twhile (count > 0) {\n\t\t\tcount--;\n\t\t\tif (mkNewHeader(B_FILEMARK, 0, 0, NULL, sam_stat))\n\t\t\t\treturn -1;\n\t\t}\n\t\tmkEODHeader(sam_stat);\n\t}\n\treturn 0;\n}\n\nint write_tape_block(const uint8_t *buf, uint32_t blk_size,\n\t\t\t\t\t uint32_t comp_size, const struct encryption *cp, uint8_t *sam_stat) {\n\tloff_t\t nwrite;\n\tuint32_t iosize;\n\n\tif (!tape_loaded(sam_stat)) {\n\t\treturn -1;\n\t}\n\n\t/* If comp_size is non-zero then the data is compressed, so use\n\t   comp_size for the I/O size.  If comp_size is zero, the data is\n\t   non-compressed, so use the blk_size as the I/O size.\n\t*/\n\n\tiosize = comp_size ? comp_size : blk_size;\n\n\tif (mkNewHeader(B_DATA, blk_size, comp_size, cp, sam_stat)) {\n\t\tMHVTL_DBG(1, \"Failed to write header\");\n\t\tsam_medium_error(E_WRITE_ERROR, sam_stat);\n\t\treturn -1;\n\t}\n\n\t// now write the block of data..\n\tnwrite = write(datafile, buf, iosize);\n\tif (nwrite <= 0) {\n\t\tMHVTL_DBG(1, \"failed to write %d bytes, %s\", iosize,\n\t\t\t\t  strerror(errno));\n\t\tsam_medium_error(E_WRITE_ERROR, sam_stat);\n\t\treturn -1;\n\t} else if (nwrite != iosize) {\n\t\tMHVTL_DBG(1, \"Did not write all data\");\n\t\tsam_medium_error(E_WRITE_ERROR, sam_stat);\n\t\treturn -1;\n\t}\n\n\t/* Write END-OF-DATA marker */\n\tif (mkEODHeader(sam_stat)) {\n\t\tMHVTL_DBG(1, \"Did not write EOD\");\n\t\tsam_medium_error(E_WRITE_ERROR, sam_stat);\n\t\treturn -1;\n\t}\n\treturn 0;\n}\n\nvoid unload_tape(uint8_t *sam_stat) {\n\tif (datafile >= 0) {\n\t\tclose(datafile);\n\t\tdatafile = -1;\n\t}\n}\n\nuint32_t read_tape_block(uint8_t *buf, uint32_t buf_size, uint8_t *sam_stat) {\n\tloff_t\t nread;\n\tuint32_t size;\n\n\tif (!tape_loaded(sam_stat)) {\n\t\treturn -1;\n\t}\n\tsize = raw_pos.hdr.disk_blk_size;\n\tif (size > buf_size)\n\t\tsize = buf_size;\n\n\tnread = read(datafile, buf, size);\n\n\t// Now read in subsequent header\n\tskip_to_next_header(sam_stat);\n\n\treturn nread;\n}\n\nuint64_t\ncurrent_tape_offset(void) {\n\tif (datafile != -1) {\n\t\treturn raw_pos.curr_blk;\n\t}\n\treturn 0;\n}\n\nvoid print_raw_header(void) {\n\tprintf(\"Hdr:\");\n\tswitch (raw_pos.hdr.blk_type) {\n\tcase B_DATA:\n\t\tif ((raw_pos.hdr.blk_flags &&\n\t\t\t (BLKHDR_FLG_COMPRESSED | BLKHDR_FLG_ENCRYPTED)) ==\n\t\t\t(BLKHDR_FLG_COMPRESSED | BLKHDR_FLG_ENCRYPTED))\n\t\t\tprintf(\" Encrypt/Comp data\");\n\t\telse if (raw_pos.hdr.blk_flags & BLKHDR_FLG_ENCRYPTED)\n\t\t\tprintf(\"    Encrypted data\");\n\t\telse if (raw_pos.hdr.blk_flags & BLKHDR_FLG_COMPRESSED)\n\t\t\tprintf(\"   Compressed data\");\n\t\telse\n\t\t\tprintf(\"             data\");\n\n\t\tprintf(\"(%02x), sz %6d/%-6d, Blk No.: %u, prev %\" PRId64\n\t\t\t   \", cur %\" PRId64 \", next %\" PRId64 \"\\n\",\n\t\t\t   raw_pos.hdr.blk_type,\n\t\t\t   raw_pos.hdr.disk_blk_size,\n\t\t\t   raw_pos.hdr.blk_size,\n\t\t\t   raw_pos.hdr.blk_number,\n\t\t\t   raw_pos.prev_blk,\n\t\t\t   raw_pos.curr_blk,\n\t\t\t   raw_pos.next_blk);\n\t\tif (raw_pos.hdr.blk_flags & BLKHDR_FLG_ENCRYPTED)\n\t\t\tprintf(\"   => Encr key length %d, ukad length %d, \"\n\t\t\t\t   \"akad length %d\\n\",\n\t\t\t\t   raw_pos.hdr.encryption.key_length,\n\t\t\t\t   raw_pos.hdr.encryption.ukad_length,\n\t\t\t\t   raw_pos.hdr.encryption.akad_length);\n\t\tbreak;\n\tcase B_FILEMARK:\n\t\tprintf(\"          Filemark\");\n\t\tprintf(\"(%02x), sz %13d, Blk No.: %u, prev %\" PRId64\n\t\t\t   \", cur %\" PRId64 \", next %\" PRId64 \"\\n\",\n\t\t\t   raw_pos.hdr.blk_type,\n\t\t\t   raw_pos.hdr.blk_size,\n\t\t\t   raw_pos.hdr.blk_number,\n\t\t\t   raw_pos.prev_blk,\n\t\t\t   raw_pos.curr_blk,\n\t\t\t   raw_pos.next_blk);\n\t\tbreak;\n\tcase B_BOT:\n\t\tprintf(\" Beginning of Tape\");\n\t\tprintf(\"(%02x), Capacity %6d Mbytes\"\n\t\t\t   \", prev %\" PRId64\n\t\t\t   \", cur %\" PRId64\n\t\t\t   \", next %\" PRId64 \"\\n\",\n\t\t\t   raw_pos.hdr.blk_type,\n\t\t\t   raw_pos.hdr.blk_size,\n\t\t\t   raw_pos.prev_blk,\n\t\t\t   raw_pos.curr_blk,\n\t\t\t   raw_pos.next_blk);\n\t\treturn;\n\t\tbreak;\n\tcase B_EOD:\n\t\tprintf(\"       End of Data\");\n\t\tprintf(\"(%02x), sz %13d, Blk No.: %u, prev %\" PRId64\n\t\t\t   \", cur %\" PRId64 \", next %\" PRId64 \"\\n\",\n\t\t\t   raw_pos.hdr.blk_type,\n\t\t\t   raw_pos.hdr.blk_size,\n\t\t\t   raw_pos.hdr.blk_number,\n\t\t\t   raw_pos.prev_blk,\n\t\t\t   raw_pos.curr_blk,\n\t\t\t   raw_pos.next_blk);\n\t\tbreak;\n\tcase B_NOOP:\n\t\tprintf(\"      No Operation\");\n\t\tbreak;\n\tdefault:\n\t\tprintf(\"      Unknown type\");\n\t\tprintf(\"(%02x), %6d/%-6d, Blk No.: %u, prev %\" PRId64\n\t\t\t   \", cur %\" PRId64 \", next %\" PRId64 \"\\n\",\n\t\t\t   raw_pos.hdr.blk_type,\n\t\t\t   raw_pos.hdr.disk_blk_size,\n\t\t\t   raw_pos.hdr.blk_size,\n\t\t\t   raw_pos.hdr.blk_number,\n\t\t\t   raw_pos.prev_blk,\n\t\t\t   raw_pos.curr_blk,\n\t\t\t   raw_pos.next_blk);\n\t\tbreak;\n\t}\n}\n"
  },
  {
    "path": "usr/vtlcart_v1_mtr.c",
    "content": "/*\n * Original tape format.\n *\n * Basically a double-linked-list headers followed by the block of data.\n * Each header describes the header type (data, filemark, EOD etc\n * along with pointer to previous and next block\n *\n * Copyright (C) 2005 - 2025 Mark Harvey       markh794@gmail.com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n */\n\n/* for unistd.h pread() and pwrite() prototypes */\n#define _XOPEN_SOURCE 500\n\n#include <sys/syslog.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <string.h>\n#include <unistd.h>\n#include <zlib.h>\n\n#include \"mhvtl_scsi.h\"\n#include \"mhvtl_list.h\"\n#include \"vtlcart.h\"\n#include \"be_byteshift.h\"\n\n#define B_BOT 14 /* Beginning of Tape TAPE_FMT_VERSION 2 */\n\n#ifndef MHVTL_DEBUG\n#error DEBUG use only !\n#endif\n\nstruct raw_header {\n\tloff_t\t\t\t  prev_blk;\n\tloff_t\t\t\t  curr_blk;\n\tloff_t\t\t\t  next_blk;\n\tstruct blk_header hdr;\n\tchar\t\t\t  pad[512 - (3 * sizeof(loff_t)) -\n\t\t\t  sizeof(struct blk_header)];\n};\n\nstatic struct raw_header raw_pos;\nstatic int\t\t\t\t datafile = -1;\nstatic uint8_t\t\t\t MediumType;\nstatic char\t\t\t\t currentMedia[1024];\n\n/* GLobally visible variables. */\n\nstruct MAM\t\t   mam;\nstruct blk_header *c_pos = &raw_pos.hdr;\n\nint OK_to_write;\n\n/*\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nstatic int read_header(struct raw_header *h, uint8_t *sam_stat) {\n\tMHVTL_DBG(1, \"read_header\");\n\n\tloff_t nread;\n\n\tnread = read(datafile, h, sizeof(*h));\n\tif (nread < 0) {\n\t\tsam_medium_error(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\treturn -1;\n\t} else if (nread != sizeof(*h)) {\n\t\tsam_medium_error(E_END_OF_DATA, sam_stat);\n\t\treturn -1;\n\t}\n\treturn 0;\n}\n\nstatic loff_t position_to_curr_header(uint8_t *sam_stat) {\n\tMHVTL_DBG(1, \"position_to_curr_header\");\n\treturn (lseek64(datafile, raw_pos.curr_blk, SEEK_SET));\n}\n\nstatic int skip_to_next_header(uint8_t *sam_stat) {\n\tMHVTL_DBG(1, \"skip_to_next_header\");\n\tif (raw_pos.hdr.blk_type == B_EOD) {\n\t\tsam_blank_check(E_END_OF_DATA, sam_stat);\n\t\tMHVTL_DBG(1, \"End of data detected while forward SPACEing!!\");\n\t\treturn -1;\n\t}\n\n\tif (raw_pos.next_blk != lseek64(datafile, raw_pos.next_blk, SEEK_SET)) {\n\t\tsam_medium_error(E_SEQUENTIAL_POSITION_ERR, sam_stat);\n\t\tMHVTL_DBG(1, \"Unable to seek to next block header\");\n\t\treturn -1;\n\t}\n\tif (read_header(&raw_pos, sam_stat)) {\n\t\tsam_medium_error(E_SEQUENTIAL_POSITION_ERR, sam_stat);\n\t\tMHVTL_DBG(1, \"Unable to read next block header\");\n\t\treturn -1;\n\t}\n\t/* Position to start of header (rewind over header) */\n\tif (raw_pos.curr_blk != position_to_curr_header(sam_stat)) {\n\t\tsam_medium_error(E_SEQUENTIAL_POSITION_ERR, sam_stat);\n\t\tMHVTL_DBG(1, \"Error position in datafile. Offset: %\" PRId64,\n\t\t\t\t  raw_pos.curr_blk);\n\t\treturn -1;\n\t}\n\treturn 0;\n}\n\nstatic int skip_to_prev_header(uint8_t *sam_stat) {\n\tMHVTL_DBG(1, \"skip_to_prev_header\");\n\t/* Position to previous header */\n\tMHVTL_DBG(3, \"Positioning to raw_pos.prev_blk: %\" PRId64,\n\t\t\t  raw_pos.prev_blk);\n\tif (raw_pos.prev_blk != lseek64(datafile, raw_pos.prev_blk, SEEK_SET)) {\n\t\tsam_medium_error(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\tMHVTL_DBG(1, \"Error position in datafile !!\");\n\t\treturn -1;\n\t}\n\t/* Read in header */\n\tMHVTL_DBG(3, \"Reading in header: %d bytes\", (int)sizeof(raw_pos));\n\n\tif (read_header(&raw_pos, sam_stat)) {\n\t\tMHVTL_DBG(1, \"Error reading datafile while reverse SPACEing\");\n\t\treturn -1;\n\t}\n\tif (raw_pos.hdr.blk_type == B_BOT) {\n\t\tMHVTL_DBG(3, \"Found Beginning Of Tape, \"\n\t\t\t\t\t \"Skipping to next header..\");\n\t\tskip_to_next_header(sam_stat);\n\t\tsam_medium_error(E_BOM, sam_stat);\n\t\tMHVTL_DBG(3, \"Found BOT!!\");\n\t\treturn -1;\n\t}\n\n\t/* Position to start of header (rewind over header) */\n\tif (raw_pos.curr_blk != position_to_curr_header(sam_stat)) {\n\t\tsam_medium_error(E_SEQUENTIAL_POSITION_ERR, sam_stat);\n\t\tMHVTL_DBG(1, \"Error position in datafile !!\");\n\t\treturn -1;\n\t}\n\tMHVTL_DBG(3, \"Rewinding over header just read in: \"\n\t\t\t\t \"curr_position: %\" PRId64,\n\t\t\t  raw_pos.curr_blk);\n\treturn 0;\n}\n\n/*\n * Create & write a new block header\n *\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nstatic int mkNewHeader(uint32_t type, int blk_size, int comp_size,\n\t\t\t\t\t   const struct encryption *cp, uint8_t *sam_stat) {\n\tstruct raw_header h;\n\tMHVTL_DBG(1, \"mkNewHeader\");\n\n\tmemset(&h, 0, sizeof(h));\n\n\th.hdr.blk_type\t = type; /* Header type */\n\th.hdr.blk_flags\t = 0;\n\th.hdr.blk_number = raw_pos.hdr.blk_number;\n\n\tif (type != B_DATA) {\n\t\th.hdr.blk_size\t\t= 0;\n\t\th.hdr.disk_blk_size = 0;\n\t} else {\n\t\th.hdr.blk_size = blk_size; /* Size of uncompressed data */\n\n\t\tif (comp_size) {\n\t\t\th.hdr.blk_flags |= BLKHDR_FLG_COMPRESSED;\n\t\t\th.hdr.disk_blk_size = comp_size;\n\t\t} else {\n\t\t\th.hdr.disk_blk_size = blk_size;\n\t\t}\n\n\t\tif (cp != NULL) {\n\t\t\tint i;\n\n\t\t\th.hdr.blk_flags |= BLKHDR_FLG_ENCRYPTED;\n\t\t\th.hdr.encryption.ukad_length = cp->ukad_length;\n\t\t\tfor (i = 0; i < cp->ukad_length; ++i)\n\t\t\t\th.hdr.encryption.ukad[i] = cp->ukad[i];\n\n\t\t\th.hdr.encryption.akad_length = cp->akad_length;\n\t\t\tfor (i = 0; i < cp->akad_length; ++i)\n\t\t\t\th.hdr.encryption.akad[i] = cp->akad[i];\n\n\t\t\th.hdr.encryption.key_length = cp->key_length;\n\t\t\tfor (i = 0; i < cp->key_length; ++i)\n\t\t\t\th.hdr.encryption.key[i] = cp->key[i];\n\t\t}\n\t}\n\n\t/* Update current position */\n\th.curr_blk = lseek64(datafile, 0, SEEK_CUR);\n\n\t/* If we are writing a new EOD marker,\n\t *  - then set next pointer to itself\n\t * else\n\t *  - Set pointer to next header (header size + size of data)\n\t */\n\tif (type == B_EOD)\n\t\th.next_blk = h.curr_blk;\n\telse\n\t\th.next_blk = h.curr_blk + h.hdr.disk_blk_size + sizeof(h);\n\n\tif (h.curr_blk == raw_pos.curr_blk) {\n\t\t/* If current pos == last header read in we are about to overwrite the\n\t\t * current header block\n\t\t */\n\t\th.prev_blk\t\t = raw_pos.prev_blk;\n\t\th.hdr.blk_number = raw_pos.hdr.blk_number;\n\t} else if (h.curr_blk == raw_pos.next_blk) {\n\t\t/* New header block at end of data file.. */\n\t\th.prev_blk\t\t = raw_pos.curr_blk;\n\t\th.hdr.blk_number = raw_pos.hdr.blk_number + 1;\n\t} else {\n\t\tMHVTL_DBG(1, \"Position error blk No: %d, Pos: %\" PRId64 \", Exp: %\" PRId64,\n\t\t\t\t  h.hdr.blk_number, h.curr_blk, raw_pos.curr_blk);\n\t\tsam_medium_error(E_SEQUENTIAL_POSITION_ERR, sam_stat);\n\t\treturn -1;\n\t}\n\n\tif (write(datafile, &h, sizeof(h)) != sizeof(h)) {\n\t\tsam_medium_error(E_WRITE_ERROR, sam_stat);\n\t\tMHVTL_DBG(1, \"Write failure, pos: %\" PRId64 \": %s\",\n\t\t\t\t  h.curr_blk, strerror(errno));\n\t\treturn -1;\n\t}\n\n\t/*\n\t * Write was successful, update raw_pos with this header block.\n\t */\n\n\tmemcpy(&raw_pos, &h, sizeof(h)); /* Update where we think we are.. */\n\n\treturn 0;\n}\n\n/*\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nstatic int mkEODHeader(uint8_t *sam_stat) {\n\tMHVTL_DBG(1, \"mkEODHeader\");\n\tif (mkNewHeader(B_EOD, 0, 0, NULL, sam_stat))\n\t\treturn -1;\n\n\tif (MediumType == MEDIA_TYPE_WORM)\n\t\tOK_to_write = 1;\n\n\t/* If we have just written a END OF DATA marker,\n\t * rewind to just before it. */\n\t/* Position to start of header (rewind over header) */\n\tif (raw_pos.curr_blk != position_to_curr_header(sam_stat)) {\n\t\tsam_medium_error(E_SEQUENTIAL_POSITION_ERR, sam_stat);\n\t\tMHVTL_DBG(1, \"Failed to write EOD header\");\n\t\treturn -1;\n\t}\n\treturn 0;\n}\n\n/*\n *\n */\n\nstatic int skip_prev_filemark(uint8_t *sam_stat) {\n\tMHVTL_DBG(1, \"skip_prev_filemark\");\n\n\tif (raw_pos.hdr.blk_type == B_FILEMARK)\n\t\traw_pos.hdr.blk_type = B_NOOP;\n\twhile (raw_pos.hdr.blk_type != B_FILEMARK) {\n\t\tif (raw_pos.hdr.blk_type == B_BOT) {\n\t\t\tsam_no_sense(NO_SENSE, E_BOM, sam_stat);\n\t\t\tMHVTL_DBG(2, \"Found Beginning of tape\");\n\t\t\treturn -1;\n\t\t}\n\t\tif (skip_to_prev_header(sam_stat))\n\t\t\treturn -1;\n\t}\n\treturn 0;\n}\n\n/*\n *\n */\nstatic int skip_next_filemark(uint8_t *sam_stat) {\n\tMHVTL_DBG(1, \"skip_next_filemark\");\n\t/* While blk header is NOT a filemark, keep skipping to next header */\n\twhile (raw_pos.hdr.blk_type != B_FILEMARK) {\n\t\t/* END-OF-DATA -> Treat this as an error - return.. */\n\t\tif (raw_pos.hdr.blk_type == B_EOD) {\n\t\t\tsam_blank_check(E_END_OF_DATA, sam_stat);\n\t\t\tMHVTL_DBG(2, \"%s\", \"Found end of media\");\n\t\t\tif (MediumType == MEDIA_TYPE_WORM)\n\t\t\t\tOK_to_write = 1;\n\t\t\treturn -1;\n\t\t}\n\t\tif (skip_to_next_header(sam_stat))\n\t\t\treturn -1; /* On error */\n\t}\n\t/* Position to header AFTER the FILEMARK.. */\n\tif (skip_to_next_header(sam_stat))\n\t\treturn -1;\n\n\treturn 0;\n}\n\nstatic int tape_loaded(uint8_t *sam_stat) {\n\tMHVTL_DBG(1, \"tape_loaded\");\n\tswitch (datafile != -1) {\n\t\treturn 1;\n\t}\n\tsam_not_ready(E_MEDIUM_NOT_PRESENT, sam_stat);\n\treturn 0;\n}\n\n/*\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nint position_to_eod(uint8_t *sam_stat) {\n\tMHVTL_DBG(1, \"position_to_eod\");\n\tif (!tape_loaded(sam_stat))\n\t\treturn -1;\n\n\twhile (raw_pos.hdr.blk_type != B_EOD) {\n\t\tif (skip_to_next_header(sam_stat))\n\t\t\treturn -1;\n\t}\n\n\tif (MediumType == MEDIA_TYPE_WORM)\n\t\tOK_to_write = 1;\n\treturn 0;\n}\n\n/*\n * Rewind 'tape'.\n */\nstatic int rawRewind(uint8_t *sam_stat) {\n\toff64_t retval;\n\n\tMHVTL_DBG(1, \"rawRewind\");\n\t/* Start at beginning of datafile.. */\n\tretval = lseek64(datafile, 0L, SEEK_SET);\n\tif (retval < 0) {\n\t\tMHVTL_DBG(1, \"Can't seek to beginning of file: %s\",\n\t\t\t\t  strerror(errno));\n\t\treturn -1;\n\t}\n\n\t/*\n\t * Read header..\n\t * If this is not the BOT header we are in trouble\n\t */\n\tif (read_header(&raw_pos, sam_stat))\n\t\treturn -1;\n\n\treturn 0;\n}\n\n/*\n * Rewind to beginning of data file and the position to first data header.\n *\n * Return 0 -> Not loaded.\n *        1 -> Load OK\n *        2 -> format corrupt.\n */\nint rewind_tape(uint8_t *sam_stat) {\n\tMHVTL_DBG(1, \"rewind_tape\");\n\tif (rawRewind(sam_stat)) {\n\t\tsam_medium_error(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\treturn 2;\n\t}\n\n\tif (raw_pos.hdr.blk_type != B_BOT) {\n\t\tsam_medium_error(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\treturn 2;\n\t}\n\n\tif (skip_to_next_header(sam_stat))\n\t\treturn 2;\n\n\tswitch (MediumType) {\n\tcase MEDIA_TYPE_CLEAN:\n\t\tOK_to_write = 0;\n\t\tbreak;\n\tcase MEDIA_TYPE_WORM:\n\t\t/* Special condition...\n\t\t * If we\n\t\t * - rewind,\n\t\t * - write filemark\n\t\t * - EOD\n\t\t * We set this as writable media as the tape is blank.\n\t\t */\n\t\tif (raw_pos.hdr.blk_type != B_EOD)\n\t\t\tOK_to_write = 0;\n\n\t\t/* Check that this header is a filemark and the next header\n\t\t *  is End of Data. If it is, we are OK to write\n\t\t */\n\t\tif (raw_pos.hdr.blk_type == B_FILEMARK) {\n\t\t\tskip_to_next_header(sam_stat);\n\t\t\tif (raw_pos.hdr.blk_type == B_EOD)\n\t\t\t\tOK_to_write = 1;\n\t\t}\n\t\t/* Now we have to go thru thru the rewind again.. */\n\t\tif (rawRewind(sam_stat)) {\n\t\t\tsam_medium_error(E_MEDIUM_FMT_CORRUPT,\n\t\t\t\t\t\t\t sam_stat);\n\t\t\treturn 2;\n\t\t}\n\n\t\t/* No need to do all previous error checking... */\n\t\tskip_to_next_header(sam_stat);\n\t\tbreak;\n\tcase MEDIA_TYPE_DATA:\n\t\tOK_to_write = 1; /* Reset flag to OK. */\n\t\tbreak;\n\t}\n\n\tMHVTL_DBG(1, \"Media is %s\",\n\t\t\t  (OK_to_write) ? \"writable\" : \"not writable\");\n\n\treturn 1;\n}\n\n/*\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nint position_to_block(uint32_t blk_no, uint8_t *sam_stat) {\n\tMHVTL_DBG(1, \"position_to_block\");\n\tif (!tape_loaded(sam_stat))\n\t\treturn -1;\n\n\tif (MediumType == MEDIA_TYPE_WORM)\n\t\tOK_to_write = 0;\n\n\tif (blk_no < raw_pos.hdr.blk_number &&\n\t\traw_pos.hdr.blk_number - blk_no > blk_no) {\n\t\tif (rewind_tape(sam_stat))\n\t\t\treturn -1;\n\t}\n\twhile (raw_pos.hdr.blk_number != blk_no) {\n\t\tif (raw_pos.hdr.blk_number > blk_no) {\n\t\t\tif (skip_to_prev_header(sam_stat) == -1)\n\t\t\t\treturn -1;\n\t\t} else {\n\t\t\tif (skip_to_next_header(sam_stat) == -1)\n\t\t\t\treturn -1;\n\t\t}\n\t}\n\treturn 0;\n}\n\n/*\n * 'count' is in the range 0xff000001 to 0x00ffffff\n *\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nint position_blocks(int32_t count, uint8_t *sam_stat) {\n\tMHVTL_DBG(1, \"position_blocks\");\n\tif (!tape_loaded(sam_stat))\n\t\treturn -1;\n\n\tif (MediumType == MEDIA_TYPE_WORM)\n\t\tOK_to_write = 0;\n\n\tif (count < 0) {\n\t\tfor (; count < 0; count++) {\n\t\t\tif (skip_to_prev_header(sam_stat))\n\t\t\t\treturn -1;\n\t\t\tif (raw_pos.hdr.blk_type == B_FILEMARK) {\n\t\t\t\tsam_no_sense(SD_FILEMARK, E_MARK, sam_stat);\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor (; count > 0; count--) {\n\t\t\tif (skip_to_next_header(sam_stat))\n\t\t\t\treturn -1;\n\t\t\tif (raw_pos.hdr.blk_type == B_FILEMARK) {\n\t\t\t\tsam_no_sense(SD_FILEMARK, E_MARK, sam_stat);\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\treturn 0;\n}\n\n/*\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nint position_filemarks(int32_t count, uint8_t *sam_stat) {\n\tMHVTL_DBG(1, \"position_filemarks\");\n\tif (!tape_loaded(sam_stat))\n\t\treturn -1;\n\n\tif (MediumType == MEDIA_TYPE_WORM)\n\t\tOK_to_write = 0;\n\n\tif (count < 0) {\n\t\tfor (; count < 0; count++)\n\t\t\tif (skip_prev_filemark(sam_stat))\n\t\t\t\treturn -1;\n\t} else {\n\t\tfor (; count > 0; count--)\n\t\t\tif (skip_next_filemark(sam_stat))\n\t\t\t\treturn -1;\n\t}\n\treturn 0;\n}\n\nint position_blocks_forw(uint32_t count, uint8_t *sam_stat) {\n\tMHVTL_DBG(1, \"position_blks_forw\");\n\treturn position_blocks(count, sam_stat);\n}\n\nint position_blocks_back(uint32_t count, uint8_t *sam_stat) {\n\tMHVTL_DBG(1, \"position_blks_back\");\n\treturn position_blocks(count > 0 ? -count : count, sam_stat);\n}\n\nint position_filemarks_forw(uint32_t count, uint8_t *sam_stat) {\n\tMHVTL_DBG(1, \"position_filemarks_forw\");\n\treturn position_filemarks(count, sam_stat);\n}\n\nint position_filemarks_back(uint32_t count, uint8_t *sam_stat) {\n\tMHVTL_DBG(1, \"position_filemarks_back\");\n\treturn position_filemarks(count > 0 ? -count : count, sam_stat);\n}\n\n/*\n * Writes data in struct MAM back to beginning of datafile..\n * Returns 0 if nothing written or -1 on error\n */\nint rewriteMAM(uint8_t *sam_stat) {\n\tloff_t nwrite = 0;\n\n\tMHVTL_DBG(1, \"rewriteMAM\");\n\t/* Rewrite MAM data */\n\tnwrite = pwrite(datafile, &mam, sizeof(mam), sizeof(struct blk_header));\n\tif (nwrite != sizeof(mam)) {\n\t\tsam_medium_error(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\treturn -1;\n\t}\n\tMediumType = mam.MediumType;\n\n\treturn 0;\n}\n\n/*\n * Returns:\n * == 0, the new PCL was successfully created.\n * == 2, the PCL (probably) already existed.\n * == 1, an error occurred.\n */\n\nint create_tape(const char *pcl, const struct MAM *mamp, uint8_t *sam_stat) {\n\tchar\t\t\t  newMedia[1024];\n\tstruct raw_header h;\n\n\tMHVTL_DBG(1, \"create_tape\");\n\n\t/* Attempt to create the new PCL.\n\t * It will fail if the PCL already exists.\n\t */\n\tsprintf((char *)newMedia, \"%s/%s\", MHVTL_HOME_PATH, pcl);\n\tsyslog(LOG_DAEMON | LOG_INFO, \"%s being created\", newMedia);\n\tdatafile = open((char *)newMedia, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);\n\tif (datafile == -1) {\n\t\tperror(\"Failed creating file\");\n\t\treturn 2;\n\t}\n\n\t/* Write a B_BOT record consisting of the B_BOT header plus the MAM. */\n\tmemset(&h, 0, sizeof(h));\n\th.next_blk\t   = sizeof(*mamp) + sizeof(h);\n\th.hdr.blk_type = B_BOT;\n\th.hdr.blk_size = ntohl(mamp->max_capacity) / 1048576;\n\n\tif (write(datafile, &h, sizeof(h)) != sizeof(h)) {\n\t\tperror(\"Unable to write header\");\n\t\tunlink(newMedia);\n\t\treturn 1;\n\t}\n\n\tif (write(datafile, mamp, sizeof(*mamp)) != sizeof(*mamp)) {\n\t\tperror(\"Unable to write MAM\");\n\t\tunlink(newMedia);\n\t\treturn 1;\n\t}\n\n\t/* Write a B_EOD record. */\n\n\tmemset(&h, 0, sizeof(h));\n\th.curr_blk\t   = lseek64(datafile, 0, SEEK_CUR);\n\th.next_blk\t   = h.curr_blk;\n\th.hdr.blk_type = B_EOD;\n\n\tif (write(datafile, &h, sizeof(h)) != sizeof(h)) {\n\t\tperror(\"Unable to write header\");\n\t\tunlink(newMedia);\n\t\treturn 1;\n\t}\n\n\tclose(datafile);\n\tdatafile = -1;\n\treturn 0;\n}\n\n/*\n * Attempt to load PCL - i.e. Open datafile and read in BOT header & MAM\n *\n * Returns:\n * == 0 -> Load OK\n * == 1 -> Tape already loaded.\n * == 2 -> format corrupt.\n * == 3 -> cartridge does not exist or cannot be opened.\n */\n\nint load_tape(const char *pcl, uint8_t *sam_stat) {\n\tloff_t\t nread;\n\tuint32_t version = 0;\n\n\tMHVTL_DBG(1, \"load_tape\");\n/* KFRDEBUG - sam_stat needs updates in lots of places here. */\n#if NOTDEF\n\tif (datafile == -1)\n\t\t/* return 1; */ /* don't return 1 here */\n\t\treturn 0;\n#endif\n\n\tsprintf(currentMedia, \"%s/%s\", MHVTL_HOME_PATH, pcl);\n\t/* MHVTL_DBG(2, \"Opening file/media %s\", currentMedia); */\n\tMHVTL_LOG(\"Opening file/media %s\", currentMedia);\n\tdatafile = open(currentMedia, O_RDWR | O_LARGEFILE);\n\tif (datafile == -1) {\n\t\tMHVTL_DBG(1, \"%s: open file/media failed, %s\", currentMedia,\n\t\t\t\t  strerror(errno));\n\t\treturn 3; /* Unsuccessful load */\n\t}\n\n\t/* Now read in header information from just opened datafile */\n\tnread = read(datafile, &raw_pos, sizeof(raw_pos));\n\tif (nread < 0) {\n\t\tMHVTL_LOG(\"%s: %s\",\n\t\t\t\t  \"Error reading header in datafile, load failed\",\n\t\t\t\t  strerror(errno));\n\t\tclose(datafile);\n\t\tdatafile = -1;\n\t\treturn 4;\t\t\t\t\t\t  /* Unsuccessful load */\n\t} else if (nread < sizeof(raw_pos)) { /* Did not read anything... */\n\t\tMHVTL_LOG(\"%s: %s\",\n\t\t\t\t  \"Error: Not a tape format, load failed\",\n\t\t\t\t  strerror(errno));\n\t\tclose(datafile);\n\t\tdatafile = -1;\n\t\treturn 5;\n\t}\n\tif (raw_pos.hdr.blk_type != B_BOT) {\n\t\tMHVTL_LOG(\"Header type: %d not valid, load failed\",\n\t\t\t\t  raw_pos.hdr.blk_type);\n\t\tclose(datafile);\n\t\tdatafile = -1;\n\t\treturn 6;\n\t}\n\t/* FIXME: Need better validation checking here !! */\n\tif (raw_pos.next_blk != (sizeof(raw_pos) + sizeof(mam))) {\n\t\tMHVTL_LOG(\"MAM size incorrect, load failed\"\n\t\t\t\t  \" - Expected size: %d, size found: %\" PRId64,\n\t\t\t\t  (int)(sizeof(raw_pos) + sizeof(mam)),\n\t\t\t\t  raw_pos.next_blk);\n\t\tclose(datafile);\n\t\tdatafile = -1;\n\t\treturn 7; /* Unsuccessful load */\n\t}\n\tnread = read(datafile, &mam, sizeof(mam));\n\tif (nread < 0) {\n\t\tMHVTL_LOG(\"Can not read MAM from mounted media, %s\",\n\t\t\t\t  strerror(errno));\n\t\tclose(datafile);\n\t\tdatafile = -1;\n\t\treturn 8; /* Unsuccessful load */\n\t}\n\tif (nread != sizeof(mam)) {\n\t\tMHVTL_LOG(\"Can not read MAM from mounted media, \"\n\t\t\t\t  \"insufficient data\");\n\t\tclose(datafile);\n\t\tdatafile = -1;\n\t\treturn 9; /* Unsuccessful load */\n\t}\n\n\tversion = mam.tape_fmt_version;\n\tif (version != TAPE_FMT_VERSION) {\n\t\tMHVTL_LOG(\"Incorrect media format %lu\", version);\n\t\tsam_medium_error(E_MEDIUM_FMT_CORRUPT, sam_stat);\n\t\tclose(datafile);\n\t\tdatafile = -1;\n\t\treturn 10;\n\t}\n\n\tMediumType = mam.MediumType;\n\tc_pos\t   = &raw_pos.hdr;\n\treturn 0;\n}\n\n/*\n * Returns:\n * == 0, success\n * != 0, failure\n */\n\nint write_filemarks(uint32_t count, uint8_t *sam_stat) {\n\tMHVTL_DBG(1, \"write_filemarks\");\n\tif (!tape_loaded(sam_stat))\n\t\treturn -1;\n\n\tif (count > 0) {\n\t\twhile (count > 0) {\n\t\t\tcount--;\n\t\t\tif (mkNewHeader(B_FILEMARK, 0, 0, NULL, sam_stat))\n\t\t\t\treturn -1;\n\t\t}\n\t\tmkEODHeader(sam_stat);\n\t}\n\treturn 0;\n}\n\nint write_tape_block(const uint8_t *buf, uint32_t blk_size,\n\t\t\t\t\t uint32_t comp_size, const struct encryption *cp, uint8_t *sam_stat) {\n\tloff_t\t nwrite;\n\tuint32_t iosize;\n\n\tMHVTL_DBG(1, \"write_tape_block\");\n\tif (!tape_loaded(sam_stat))\n\t\treturn -1;\n\n\t/* If comp_size is non-zero then the data is compressed, so use\n\t   comp_size for the I/O size.  If comp_size is zero, the data is\n\t   non-compressed, so use the blk_size as the I/O size.\n\t*/\n\n\tiosize = comp_size ? comp_size : blk_size;\n\n\tif (mkNewHeader(B_DATA, blk_size, comp_size, cp, sam_stat)) {\n\t\tMHVTL_DBG(1, \"Failed to write header\");\n\t\tsam_medium_error(E_WRITE_ERROR, sam_stat);\n\t\treturn -1;\n\t}\n\n\t/* now write the block of data.. */\n\tnwrite = write(datafile, buf, iosize);\n\tif (nwrite <= 0) {\n\t\tMHVTL_DBG(1, \"failed to write %d bytes, %s\", iosize,\n\t\t\t\t  strerror(errno));\n\t\tsam_medium_error(E_WRITE_ERROR, sam_stat);\n\t\treturn -1;\n\t} else if (nwrite != iosize) {\n\t\tMHVTL_DBG(1, \"Did not write all data\");\n\t\tsam_medium_error(E_WRITE_ERROR, sam_stat);\n\t\treturn -1;\n\t}\n\n\t/* Write END-OF-DATA marker */\n\tif (mkEODHeader(sam_stat)) {\n\t\tMHVTL_DBG(1, \"Did not write EOD\");\n\t\tsam_medium_error(E_WRITE_ERROR, sam_stat);\n\t\treturn -1;\n\t}\n\treturn 0;\n}\n\nvoid unload_tape(uint8_t *sam_stat) {\n\tMHVTL_DBG(1, \"unload_tape\");\n\tif (datafile >= 0) {\n\t\tclose(datafile);\n\t\tdatafile = -1;\n\t}\n}\n\nuint32_t read_tape_block(uint8_t *buf, uint32_t buf_size, uint8_t *sam_stat) {\n\tloff_t\t nread;\n\tuint32_t size;\n\n\tMHVTL_DBG(1, \"read_tape_block\");\n\tif (!tape_loaded(sam_stat))\n\t\treturn -1;\n\n\tsize = raw_pos.hdr.disk_blk_size;\n\tif (size > buf_size)\n\t\tsize = buf_size;\n\n\tnread = read(datafile, buf, size);\n\n\t/* Now read in subsequent header */\n\tskip_to_next_header(sam_stat);\n\n\treturn nread;\n}\n\nuint64_t current_tape_offset(void) {\n\tif (datafile != -1)\n\t\treturn raw_pos.curr_blk;\n\n\treturn 0;\n}\n\nvoid print_raw_header(void) {\n\tprintf(\"Hdr:\");\n\tswitch (raw_pos.hdr.blk_type) {\n\tcase B_DATA:\n\t\tif ((raw_pos.hdr.blk_flags &&\n\t\t\t (BLKHDR_FLG_COMPRESSED | BLKHDR_FLG_ENCRYPTED)) ==\n\t\t\t(BLKHDR_FLG_COMPRESSED | BLKHDR_FLG_ENCRYPTED))\n\t\t\tprintf(\" Encrypt/Comp data\");\n\t\telse if (raw_pos.hdr.blk_flags & BLKHDR_FLG_ENCRYPTED)\n\t\t\tprintf(\"    Encrypted data\");\n\t\telse if (raw_pos.hdr.blk_flags & BLKHDR_FLG_COMPRESSED)\n\t\t\tprintf(\"   Compressed data\");\n\t\telse\n\t\t\tprintf(\"             data\");\n\n\t\tprintf(\"(%02x), sz %6d/%-6d, Blk No.: %u, prev %\" PRId64\n\t\t\t   \", cur %\" PRId64 \", next %\" PRId64 \"\\n\",\n\t\t\t   raw_pos.hdr.blk_type,\n\t\t\t   raw_pos.hdr.disk_blk_size,\n\t\t\t   raw_pos.hdr.blk_size,\n\t\t\t   raw_pos.hdr.blk_number,\n\t\t\t   raw_pos.prev_blk,\n\t\t\t   raw_pos.curr_blk,\n\t\t\t   raw_pos.next_blk);\n\t\tif (raw_pos.hdr.blk_flags & BLKHDR_FLG_ENCRYPTED)\n\t\t\tprintf(\"   => Encr key length %d, ukad length %d, \"\n\t\t\t\t   \"akad length %d\\n\",\n\t\t\t\t   raw_pos.hdr.encryption.key_length,\n\t\t\t\t   raw_pos.hdr.encryption.ukad_length,\n\t\t\t\t   raw_pos.hdr.encryption.akad_length);\n\t\tbreak;\n\tcase B_FILEMARK:\n\t\tprintf(\"          Filemark\");\n\t\tprintf(\"(%02x), sz %13d, Blk No.: %u, prev %\" PRId64\n\t\t\t   \", cur %\" PRId64 \", next %\" PRId64 \"\\n\",\n\t\t\t   raw_pos.hdr.blk_type,\n\t\t\t   raw_pos.hdr.blk_size,\n\t\t\t   raw_pos.hdr.blk_number,\n\t\t\t   raw_pos.prev_blk,\n\t\t\t   raw_pos.curr_blk,\n\t\t\t   raw_pos.next_blk);\n\t\tbreak;\n\tcase B_BOT:\n\t\tprintf(\" Beginning of Tape\");\n\t\tprintf(\"(%02x), Capacity %6d Mbytes\"\n\t\t\t   \", prev %\" PRId64\n\t\t\t   \", cur %\" PRId64\n\t\t\t   \", next %\" PRId64 \"\\n\",\n\t\t\t   raw_pos.hdr.blk_type,\n\t\t\t   raw_pos.hdr.blk_size,\n\t\t\t   raw_pos.prev_blk,\n\t\t\t   raw_pos.curr_blk,\n\t\t\t   raw_pos.next_blk);\n\t\treturn;\n\t\tbreak;\n\tcase B_EOD:\n\t\tprintf(\"       End of Data\");\n\t\tprintf(\"(%02x), sz %13d, Blk No.: %u, prev %\" PRId64\n\t\t\t   \", cur %\" PRId64 \", next %\" PRId64 \"\\n\",\n\t\t\t   raw_pos.hdr.blk_type,\n\t\t\t   raw_pos.hdr.blk_size,\n\t\t\t   raw_pos.hdr.blk_number,\n\t\t\t   raw_pos.prev_blk,\n\t\t\t   raw_pos.curr_blk,\n\t\t\t   raw_pos.next_blk);\n\t\tbreak;\n\tcase B_NOOP:\n\t\tprintf(\"      No Operation\");\n\t\tbreak;\n\tdefault:\n\t\tprintf(\"      Unknown type\");\n\t\tprintf(\"(%02x), %6d/%-6d, Blk No.: %u, prev %\" PRId64\n\t\t\t   \", cur %\" PRId64 \", next %\" PRId64 \"\\n\",\n\t\t\t   raw_pos.hdr.blk_type,\n\t\t\t   raw_pos.hdr.disk_blk_size,\n\t\t\t   raw_pos.hdr.blk_size,\n\t\t\t   raw_pos.hdr.blk_number,\n\t\t\t   raw_pos.prev_blk,\n\t\t\t   raw_pos.curr_blk,\n\t\t\t   raw_pos.next_blk);\n\t\tbreak;\n\t}\n}\n\nstatic int check_for_overwrite(uint8_t *sam_stat) {\n\tMHVTL_DBG(1, \"check_for_overwrite\");\n#if NOTDEF\n\tuint32_t blk_number;\n\tuint64_t data_offset;\n\tint\t\t i;\n\n\tif (raw_pos.hdr.blk_type == B_EOD)\n\t\treturn 0;\n\n\tMHVTL_DBG(2, \"At block %ld\", (unsigned long)raw_pos.hdr.blk_number);\n\n\t/* We aren't at EOD so we are performing a rewrite.  Truncate\n\t * the data and index files back to the current length.\n\t */\n\n\tblk_number\t= raw_pos.hdr.blk_number;\n\tdata_offset = raw_pos.data_offset;\n\n\tif (ftruncate(indxfile, blk_number * sizeof(raw_pos))) {\n\t\tsam_medium_error(E_WRITE_ERROR, sam_stat);\n\t\tMHVTL_LOG(\"Index file ftruncate failure, pos: \"\n\t\t\t\t  \"%\" PRId64 \": %s\",\n\t\t\t\t  (uint64_t)blk_number * sizeof(raw_pos),\n\t\t\t\t  strerror(errno));\n\t\treturn -1;\n\t}\n\tif (ftruncate(datafile, data_offset)) {\n\t\tsam_medium_error(E_WRITE_ERROR, sam_stat);\n\t\tMHVTL_LOG(\"Data file ftruncate failure, pos: \"\n\t\t\t\t  \"%\" PRId64 \": %s\",\n\t\t\t\t  data_offset,\n\t\t\t\t  strerror(errno));\n\t\treturn -1;\n\t}\n\n\t/* Update the filemark map removing any filemarks which will be\n\t * overwritten.  Rewrite the filemark map so that the on-disk image\n\t * of the map is consistent with the new sizes of the other two files.\n\t */\n\n\tfor (i = 0; i < meta.filemark_count; i++) {\n\t\tMHVTL_DBG(2, \"filemarks[%d] %d\", i, filemarks[i]);\n\t\tif (filemarks[i] >= blk_number) {\n\t\t\tMHVTL_DBG(2, \"Setting filemark_count from %d to %d\",\n\t\t\t\t\t  meta.filemark_count, i);\n\t\t\tmeta.filemark_count = i;\n\t\t\treturn rewrite_meta_file();\n\t\t}\n\t}\n#endif\n\treturn 0;\n}\n\nvoid zero_filemark_count(void) {\n\tMHVTL_DBG(1, \"zero_filemark_count\");\n\t/*\n\t\tfree(filemarks);\n\t\tfilemark_alloc = 0;\n\t\tfilemarks = NULL;\n\n\t\tmeta.filemark_count = 0;\n\t\trewrite_meta_file();\n\t*/\n}\n\nint format_tape(uint8_t *sam_stat) {\n\tMHVTL_DBG(1, \"format_tape\");\n\tif (!tape_loaded(sam_stat))\n\t\treturn -1;\n\n\tif (check_for_overwrite(sam_stat))\n\t\treturn -1;\n\n\tzero_filemark_count();\n\n\treturn mkEODHeader(raw_pos.hdr.blk_number);\n}\n\nvoid print_filemark_count(void) {\n\t/*\tprintf(\"Total num of filemarks: %d\\n\", meta.filemark_count); */\n}\n\nvoid print_metadata(void) {\n\t/*\n\t\tint a;\n\n\t\tfor (a = 0; a < meta.filemark_count; a++)\n\t\t\tprintf(\"Filemark: %d\\n\", filemarks[a]);\n\t*/\n}\n"
  },
  {
    "path": "usr/vtllib.c",
    "content": "/*\n * Shared routines between vtltape & vtllibrary\n *\n * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n */\n#include <stdint.h>\n\n#ifndef Solaris\n#include <byteswap.h>\n#endif\n\n#define __STDC_FORMAT_MACROS\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <ctype.h>\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <sys/ioctl.h>\n#include <unistd.h>\n#include <fcntl.h>\n#include <errno.h>\n#include <sys/ipc.h>\n#include <semaphore.h>\n#include <sys/shm.h>\n#include <sys/msg.h>\n#include <time.h>\n#include <sys/sysmacros.h>\n#include <assert.h>\n#include \"be_byteshift.h\"\n#include \"mhvtl_list.h\"\n#include \"mhvtl_scsi.h\"\n#include \"vtl_common.h\"\n#include \"vtlcart.h\"\n#include \"logging.h\"\n#include \"vtllib.h\"\n#include \"smc.h\"\n#include \"mode.h\"\n#include \"q.h\"\n#include \"ssc.h\"\n#include \"mhvtl_log.h\"\n\nstatic int reset\t\t\t\t= 0;\nstatic int inquiry_data_changed = 0;\n\n/* Global variables */\nstruct MAM\t\t   mam;\nstruct priv_lu_ssc lu_ssc;\nstruct lu_phy_attr lunit;\nstruct encryption  app_encryption_state;\nint\t\t\t\t   current_state;\nint\t\t\t\t   lbp_rscrc_be = 1;\nint\t\t\t\t   OK_to_write\t= 0;\nuint8_t\t\t\t   sense[SENSE_BUF_SIZE];\nuint8_t\t\t\t   modeBlockDescriptor[8] = {0, 0, 0, 0, 0, 0, 0, 0};\nchar\t\t\t   home_directory[HOME_DIR_PATH_SZ + 1];\nuint8_t\t\t\t   debug   = 0;\nuint8_t\t\t\t   verbose = 0;\nlong\t\t\t   my_id   = 0;\n\n#define INIT_MAM_ATTR(attr_id, len, ro, fmt, field, enum_id)           \\\n\tdo {                                                               \\\n\t\t_Static_assert(sizeof(field) == (len),                         \\\n\t\t\t\t\t   \"INIT_ATTR: field size does not match length\"); \\\n\t\tmamp->attributes[(enum_id)] = (struct MAM_attr){               \\\n\t\t\t.attribute_id = (attr_id),                                 \\\n\t\t\t.length\t\t  = (len),                                     \\\n\t\t\t.read_only\t  = (ro),                                      \\\n\t\t\t.format\t\t  = (fmt),                                     \\\n\t\t\t.value\t\t  = &(field)};                                        \\\n\t} while (0)\n\n#define INIT_VTL_ATTR(attr_id, len, field, enum_id)                    \\\n\tdo {                                                               \\\n\t\t_Static_assert(sizeof(field) == (len),                         \\\n\t\t\t\t\t   \"INIT_ATTR: field size does not match length\"); \\\n\t\tmamp->mhvtl_attr[(enum_id)] = (struct MHVTL_attr){             \\\n\t\t\t.attribute_id = (attr_id),                                 \\\n\t\t\t.length\t\t  = (len),                                     \\\n\t\t\t.value\t\t  = &(field)};                                        \\\n\t} while (0)\n\nvoid init_mam(struct MAM *mamp) {\n\t/* Device (0x0000 - 0x03ff) */\n\tINIT_MAM_ATTR(0x000, 8, 1, 0, mamp->remaining_capacity, MAM_REMAINING_CAPACITY);\n\tINIT_MAM_ATTR(0x001, 8, 1, 0, mamp->max_capacity, MAM_MAX_CAPACITY);\n\tINIT_MAM_ATTR(0x002, 8, 1, 0, mamp->TapeAlert, MAM_TAPE_ALERT);\n\tINIT_MAM_ATTR(0x003, 8, 1, 0, mamp->LoadCount, MAM_LOAD_COUNT);\n\tINIT_MAM_ATTR(0x004, 8, 1, 0, mamp->MAMSpaceRemaining, MAM_MAM_SPACE_REMAINING);\n\tINIT_MAM_ATTR(0x005, 8, 1, 1, mamp->AssigningOrganization_1, MAM_ASSIGNING_ORG_1);\n\tINIT_MAM_ATTR(0x006, 1, 1, 0, mamp->FormattedDensityCode, MAM_FORMATTED_DENSITY_CODE);\n\tINIT_MAM_ATTR(0x007, 2, 1, 0, mamp->InitializationCount, MAM_INITIALIZATION_COUNT);\n\n\tINIT_MAM_ATTR(0x009, 4, 1, 0, mamp->VolumeChangeReference, MAM_VOLUME_CHANGE_REFERENCE);\n\tINIT_MAM_ATTR(0x20a, 40, 1, 1, mamp->DevMakeSerialLastLoad, MAM_DEV_MAKE_SERIAL_LAST_LOAD);\n\tINIT_MAM_ATTR(0x20b, 40, 1, 1, mamp->DevMakeSerialLastLoad1, MAM_DEV_MAKE_SERIAL_LAST_LOAD1);\n\tINIT_MAM_ATTR(0x20c, 40, 1, 1, mamp->DevMakeSerialLastLoad2, MAM_DEV_MAKE_SERIAL_LAST_LOAD2);\n\tINIT_MAM_ATTR(0x20d, 40, 1, 1, mamp->DevMakeSerialLastLoad3, MAM_DEV_MAKE_SERIAL_LAST_LOAD3);\n\tINIT_MAM_ATTR(0x220, 8, 1, 0, mamp->WrittenInMediumLife, MAM_WRITTEN_IN_MEDIUM_LIFE);\n\tINIT_MAM_ATTR(0x221, 8, 1, 0, mamp->ReadInMediumLife, MAM_READ_IN_MEDIUM_LIFE);\n\tINIT_MAM_ATTR(0x222, 8, 1, 0, mamp->WrittenInLastLoad, MAM_WRITTEN_IN_LAST_LOAD);\n\tINIT_MAM_ATTR(0x223, 8, 1, 0, mamp->ReadInLastLoad, MAM_READ_IN_LAST_LOAD);\n\n\t/* Medium (0x0400 - 0x07ff) */\n\tINIT_MAM_ATTR(0x400, 8, 1, 1, mamp->MediumManufacturer, MAM_MEDIUM_MANUFACTURER);\n\tINIT_MAM_ATTR(0x401, 32, 1, 1, mamp->MediumSerialNumber, MAM_MEDIUM_SERIAL_NUMBER);\n\tINIT_MAM_ATTR(0x402, 4, 1, 0, mamp->MediumLength, MAM_MEDIUM_LENGTH);\n\tINIT_MAM_ATTR(0x403, 4, 1, 0, mamp->MediumWidth, MAM_MEDIUM_WIDTH);\n\tINIT_MAM_ATTR(0x404, 8, 1, 1, mamp->AssigningOrganization_2, MAM_ASSIGNING_ORG_2);\n\tINIT_MAM_ATTR(0x405, 1, 1, 0, mamp->MediumDensityCode, MAM_MEDIUM_DENSITY_CODE);\n\tINIT_MAM_ATTR(0x406, 12, 1, 1, mamp->MediumManufactureDate, MAM_MEDIUM_MANUFACTURE_DATE);\n\tINIT_MAM_ATTR(0x407, 8, 1, 0, mamp->MAMCapacity, MAM_MAM_CAPACITY);\n\tINIT_MAM_ATTR(0x408, 1, 0, 0, mamp->MediumType, MAM_MEDIUM_TYPE);\n\tINIT_MAM_ATTR(0x409, 2, 1, 0, mamp->MediumTypeInformation, MAM_MEDIUM_TYPE_INFORMATION);\n\n\t/* Host (0x0800 - 0x0bff) */\n\tINIT_MAM_ATTR(0x800, 8, 0, 1, mamp->ApplicationVendor, MAM_APPLICATION_VENDOR);\n\tINIT_MAM_ATTR(0x801, 32, 0, 1, mamp->ApplicationName, MAM_APPLICATION_NAME);\n\tINIT_MAM_ATTR(0x802, 8, 0, 1, mamp->ApplicationVersion, MAM_APPLICATION_VERSION);\n\tINIT_MAM_ATTR(0x803, 160, 0, 2, mamp->UserMediumTextLabel, MAM_USER_MEDIUM_TEXT_LABEL);\n\tINIT_MAM_ATTR(0x804, 12, 0, 1, mamp->DateTimeLastWritten, MAM_DATE_TIME_LAST_WRITTEN);\n\tINIT_MAM_ATTR(0x805, 1, 0, 0, mamp->LocalizationIdentifier, MAM_LOCALIZATION_IDENTIFIER);\n\tINIT_MAM_ATTR(0x806, 32, 0, 1, mamp->Barcode, MAM_BARCODE);\n\tINIT_MAM_ATTR(0x807, 80, 0, 2, mamp->OwningHostTextualName, MAM_OWNING_HOST_TEXTUAL_NAME);\n\tINIT_MAM_ATTR(0x808, 160, 0, 2, mamp->MediaPool, MAM_MEDIA_POOL);\n\tINIT_MAM_ATTR(0x80b, 16, 0, 1, mamp->ApplicationFormatVersion, MAM_APPLICATION_FORMAT_VERSION);\n\tINIT_MAM_ATTR(0x80c, 46, 0, 0, mamp->VolumeCoherencyInformation, MAM_VOLUME_COHERENCY_INFORMATION);\n\n\t/* 0x0c00 - 0x0fff - Device - Vendor Specific */\n\t/* 0x1000 - 0x13ff - Medium - Vendor Specific */\n\t/* 0x1400 - 0x17ff -  Host  - Vendor Specific */\n\tINIT_MAM_ATTR(0x1623, 1, 1, 0, mamp->VolumeLock, MAM_VOLUME_LOCK);\n\n\t/* 0x1800 : end of implemented attributes */\n\tmamp->attributes[MAM_ATTRIBUTE_END] = (struct MAM_attr){0x1800, 0, 1, 0, NULL};\n\n\t/* mhvtl attributes */\n\tINIT_VTL_ATTR(0x01, 1, mamp->record_dirty, MAM_MHVTL_RECORD_DIRTY);\n\tINIT_VTL_ATTR(0x02, 2, mamp->Flags, MAM_MHVTL_FLAGS);\n\tINIT_VTL_ATTR(0x03, 1, mamp->max_partitions, MAM_MHVTL_MAX_PARTITIONS);\n\tINIT_VTL_ATTR(0x04, 1, mamp->num_partitions, MAM_MHVTL_NUM_PARTITIONS);\n\tINIT_VTL_ATTR(0x05, 1, mamp->MediaType, MAM_MHVTL_NUM_PARTITIONS);\n\n\tINIT_VTL_ATTR(0x06, 4, mamp->media_info.bits_per_mm, MAM_MHVTL_MEDIAINFO_BITS_PER_MM);\n\tINIT_VTL_ATTR(0x07, 2, mamp->media_info.tracks, MAM_MHVTL_MEDIAINFO_TRACKS);\n\tINIT_VTL_ATTR(0x08, 8, mamp->media_info.density_name, MAM_MHVTL_MEDIAINFO_DENSITY_NAME);\n\tINIT_VTL_ATTR(0x09, 32, mamp->media_info.description, MAM_MHVTL_MEDIAINFO_DESCRIPTION);\n}\n\nint get_config(char *buf, conf_file conf, long id) {\n\tchar  format[128];\n\tchar  config_path[CONF_DIR_PATH_SZ] = {0};\n\tFILE *fp\t\t\t\t\t\t\t= fopen(MHVTL_CONFIG_PATH \"/mhvtl.conf\", \"r\");\n\n\tsnprintf(format, sizeof(format), \"%%255[^= \\t\\r] = %%%u[^\\n]\", CONF_DIR_PATH_SZ - 1);\n\tif (fp) {\n\t\tchar  *line = NULL;\n\t\tsize_t len\t= 0;\n\n\t\twhile (getline(&line, &len, fp) != -1) {\n\t\t\tif (line[0] == '#' || line[0] == '\\n')\n\t\t\t\tcontinue;\n\t\t\tchar key[256];\n\t\t\tchar value[CONF_DIR_PATH_SZ - 1];\n\t\t\tif (sscanf(line, format, key, value) == 2) {\n\t\t\t\tif (strcmp(key, \"MHVTL_CONFIG_PATH\") == 0) {\n\t\t\t\t\tstrncpy(config_path, value, sizeof(config_path) - 1);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tMHVTL_ERR(\"Error of syntax in configuration file %s :\\n%s\",\n\t\t\t\t\t\t  MHVTL_CONFIG_PATH \"/mhvtl.conf\", line);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\tfree(line);\n\t\tfclose(fp);\n\t}\n\n\tswitch (conf) {\n\tcase DEVICE_CONF:\n\t\tsnprintf(buf, CONF_FILE_SZ, \"%s/device.conf\",\n\t\t\t\t (config_path[0] != '\\0') ? config_path : MHVTL_CONFIG_PATH);\n\t\tbreak;\n\tcase LIBCONTENTS:\n\t\tsnprintf(buf, CONF_FILE_SZ, \"%s/library_contents.%ld\",\n\t\t\t\t (config_path[0] != '\\0') ? config_path : MHVTL_CONFIG_PATH, id);\n\t\tbreak;\n\tcase LIBCONTENTS_PERSIST:\n\t\tsnprintf(buf, CONF_FILE_SZ, \"%s/library_contents.%ld.persist\",\n\t\t\t\t (config_path[0] != '\\0') ? config_path : MHVTL_CONFIG_PATH, id);\n\t\tbreak;\n\n\tdefault:\n\t\tMHVTL_ERR(\"Wrong config file requested\");\n\t\treturn -1;\n\t}\n\n\treturn 0;\n}\n\nstatic struct state_description {\n\tchar *state_desc;\n} state_desc[] = {\n\t{\n\t\t\"Initialising v2\",\n\t},\n\t{\n\t\t\"Idle\",\n\t},\n\t{\n\t\t\"Unloading\",\n\t},\n\t{\n\t\t\"Loading\",\n\t},\n\t{\n\t\t\"Loading Cleaning Tape\",\n\t},\n\t{\n\t\t\"Loading WORM media\",\n\t},\n\t{\n\t\t\"Loading NULL media\",\n\t},\n\t{\n\t\t\"Loaded\",\n\t},\n\t{\n\t\t\"Loaded - Idle\",\n\t},\n\t{\n\t\t\"Load failed\",\n\t},\n\t{\n\t\t\"Rewinding\",\n\t},\n\t{\n\t\t\"Positioning\",\n\t},\n\t{\n\t\t\"Locate\",\n\t},\n\t{\n\t\t\"Reading\",\n\t},\n\t{\n\t\t\"Writing\",\n\t},\n\t{\n\t\t\"Unloading\",\n\t},\n\t{\n\t\t\"Erasing\",\n\t},\n\n\t{\n\t\t\"Moving media from drive to slot\",\n\t},\n\t{\n\t\t\"Moving media from slot to drive\",\n\t},\n\t{\n\t\t\"Moving media from drive to MAP\",\n\t},\n\t{\n\t\t\"Moving media from MAP to drive\",\n\t},\n\t{\n\t\t\"Moving media from slot to MAP\",\n\t},\n\t{\n\t\t\"Moving media from MAP to slot\",\n\t},\n\t{\n\t\t\"Moving media from drive to drive\",\n\t},\n\t{\n\t\t\"Moving media from slot to slot\",\n\t},\n\t{\n\t\t\"Opening MAP\",\n\t},\n\t{\n\t\t\"Closing MAP\",\n\t},\n\t{\n\t\t\"Robot Inventory\",\n\t},\n\t{\n\t\t\"Initialise Elements\",\n\t},\n\t{\n\t\t\"Online\",\n\t},\n\t{\n\t\t\"Offline\",\n\t},\n\t{\n\t\t\"System Uninitialised\",\n\t},\n};\n\nstatic char *slot_type_string[] = {\n\t\"ANY\",\n\t\"Picker\",\n\t\"Storage\",\n\t\"MAP\",\n\t\"Drive\",\n};\n\nvoid mhvtl_prt_cdb(int lvl, struct scsi_cmd *cmd) {\n\tint\t\t groupCode;\n\tuint8_t *cdb = cmd->scb;\n#ifdef MHVTL_DEBUG\n\tuint64_t sn\t   = cmd->dbuf_p->serialNo;\n\tuint64_t delay = (uint64_t)cmd->pollInterval;\n#endif\n\n\tgroupCode = (cdb[0] & 0xe0) >> 5;\n\tswitch (groupCode) {\n\tcase 0: /*  6 byte commands */\n\t\tMHVTL_DBG_NO_FUNC(lvl, \"CDB (%\" PRId64 \") (delay %\" PRId64 \"): \"\n\t\t\t\t\t\t\t   \"%02x %02x %02x %02x %02x %02x\",\n\t\t\t\t\t\t  sn, delay,\n\t\t\t\t\t\t  cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5]);\n\t\tbreak;\n\tcase 1: /* 10 byte commands */\n\tcase 2: /* 10 byte commands */\n\t\tMHVTL_DBG_NO_FUNC(lvl, \"CDB (%\" PRId64 \") (delay %\" PRId64 \"): \"\n\t\t\t\t\t\t\t   \"%02x %02x %02x %02x %02x %02x\"\n\t\t\t\t\t\t\t   \" %02x %02x %02x %02x\",\n\t\t\t\t\t\t  sn, delay,\n\t\t\t\t\t\t  cdb[0], cdb[1], cdb[2], cdb[3],\n\t\t\t\t\t\t  cdb[4], cdb[5], cdb[6], cdb[7],\n\t\t\t\t\t\t  cdb[8], cdb[9]);\n\t\tbreak;\n\tcase 3: /* Reserved - There is always one exception ;) */\n\t\tMHVTL_DBG_NO_FUNC(lvl, \"CDB (%\" PRId64 \") (delay %\" PRId64 \"): \"\n\t\t\t\t\t\t\t   \"%02x %02x %02x %02x %02x %02x\"\n\t\t\t\t\t\t\t   \" %02x %02x %02x %02x %02x %02x\",\n\t\t\t\t\t\t  sn, delay,\n\t\t\t\t\t\t  cdb[0], cdb[1], cdb[2], cdb[3],\n\t\t\t\t\t\t  cdb[4], cdb[5], cdb[6], cdb[7],\n\t\t\t\t\t\t  cdb[8], cdb[9], cdb[10], cdb[11]);\n\t\tbreak;\n\tcase 4: /* 16 byte commands */\n\t\tMHVTL_DBG_NO_FUNC(lvl, \"CDB (%\" PRId64 \") (delay %\" PRId64 \"): \"\n\t\t\t\t\t\t\t   \"%02x %02x %02x %02x %02x %02x\"\n\t\t\t\t\t\t\t   \" %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\",\n\t\t\t\t\t\t  sn, delay,\n\t\t\t\t\t\t  cdb[0], cdb[1], cdb[2], cdb[3],\n\t\t\t\t\t\t  cdb[4], cdb[5], cdb[6], cdb[7],\n\t\t\t\t\t\t  cdb[8], cdb[9], cdb[10], cdb[11],\n\t\t\t\t\t\t  cdb[12], cdb[13], cdb[14], cdb[15]);\n\t\tbreak;\n\tcase 5: /* 12 byte commands */\n\t\tMHVTL_DBG_NO_FUNC(lvl, \"CDB (%\" PRId64 \") (delay %\" PRId64 \"): \"\n\t\t\t\t\t\t\t   \"%02x %02x %02x %02x %02x %02x %02x\"\n\t\t\t\t\t\t\t   \" %02x %02x %02x %02x %02x\",\n\t\t\t\t\t\t  sn, delay,\n\t\t\t\t\t\t  cdb[0], cdb[1], cdb[2], cdb[3],\n\t\t\t\t\t\t  cdb[4], cdb[5], cdb[6], cdb[7],\n\t\t\t\t\t\t  cdb[8], cdb[9], cdb[10], cdb[11]);\n\t\tbreak;\n\tcase 6: /* Vendor Specific */\n\tcase 7: /* Vendor Specific */\n\t\tMHVTL_DBG_NO_FUNC(lvl, \"CDB (%\" PRId64 \") (delay %\" PRId64 \"), \"\n\t\t\t\t\t\t\t   \"VENDOR SPECIFIC !! \"\n\t\t\t\t\t\t\t   \" %02x %02x %02x %02x %02x %02x\",\n\t\t\t\t\t\t  sn, delay,\n\t\t\t\t\t\t  cdb[0], cdb[1], cdb[2], cdb[3],\n\t\t\t\t\t\t  cdb[4], cdb[5]);\n\t\tbreak;\n\t}\n}\n\n/*\n * zalloc(int size)\n *\n * Wrapper to first call malloc() and zero out any allocated space.\n */\nvoid *zalloc(int sz) {\n#ifdef __arm__\n\tvoid *p = malloc(max(32, sz));\n\tMHVTL_DBG(2, \"arm: malloc(%d)%s\", sz, (sz < 32) ? \" : rounding up to 32\" : \"\");\n#else\n\tvoid *p = malloc(sz);\n#endif\n\tif (p)\n\t\tmemset(p, 0, sz);\n\n\treturn p;\n}\n\n/*\n * Fills in a global array with current sense data\n * Sets 'sam status' to SAM_STAT_CHECK_CONDITION.\n */\n\nstatic void return_sense(uint8_t key, uint32_t asc_ascq, struct s_sd *sd,\n\t\t\t\t\t\t uint8_t *sam_stat) {\n\tchar extended[32];\n\n\t/* Clear Sense key status */\n\tmemset(sense, 0, SENSE_BUF_SIZE);\n\n\t*sam_stat = SAM_STAT_CHECK_CONDITION;\n\n\tsense[0] = SD_CURRENT_INFORMATION_FIXED;\n\t/* SPC4 (Revision 30) Ch: 4.5.1 states:\n\t * The RESPONSE CODE field shall be set to 70h in all unit attention\n\t * condition sense data in which:\n\t * - The ADDITIONAL SENSE CODE field is set to 29h\n\t * - The ADDITIONAL SENSE CODE is set to MODE PARAMETERS CHANGED\n\t */\n\tswitch (key) {\n\tcase UNIT_ATTENTION:\n\t\tif ((asc_ascq >> 8) == 0x29)\n\t\t\tbreak;\n\t\tif (asc_ascq == E_MODE_PARAMETERS_CHANGED)\n\t\t\tbreak;\n\t\t/* Fall thru to default handling */\n\tdefault:\n\t\tsense[0] |= SD_VALID;\n\t\tbreak;\n\t}\n\n\tsense[2] = key;\n\tsense[7] = SENSE_BUF_SIZE - 8;\n\tput_unaligned_be16(asc_ascq, &sense[12]);\n\n\tif (sd) {\n\t\tsense[15] = sd->byte0;\n\t\tput_unaligned_be16(sd->field_pointer, &sense[16]);\n\t\tsprintf(extended, \" 0x%02x %04x\", sd->byte0, sd->field_pointer);\n\t}\n\n\tMHVTL_DBG(1, \"[Key/ASC/ASCQ] [%02x %02x %02x]%s\",\n\t\t\t  sense[2], sense[12], sense[13],\n\t\t\t  (sd) ? extended : \"\");\n}\n\nvoid sam_unit_attention(uint16_t ascq, uint8_t *sam_stat) {\n\treturn_sense(UNIT_ATTENTION, ascq, NULL, sam_stat);\n\tMHVTL_DBG(1, \"\");\n}\n\nvoid sam_not_ready(uint16_t ascq, uint8_t *sam_stat) {\n\treturn_sense(NOT_READY, ascq, NULL, sam_stat);\n\tMHVTL_DBG(1, \"\");\n}\n\nvoid sam_illegal_request(uint16_t ascq, struct s_sd *sd, uint8_t *sam_stat) {\n\treturn_sense(ILLEGAL_REQUEST, ascq, sd, sam_stat);\n\tMHVTL_DBG(1, \"\");\n}\n\nvoid sam_medium_error(uint16_t ascq, uint8_t *sam_stat) {\n\treturn_sense(MEDIUM_ERROR, ascq, NULL, sam_stat);\n\tMHVTL_DBG(1, \"\");\n}\n\nvoid sam_blank_check(uint16_t ascq, uint8_t *sam_stat) {\n\treturn_sense(BLANK_CHECK, ascq, NULL, sam_stat);\n\tMHVTL_DBG(1, \"\");\n}\n\nvoid sam_data_protect(uint16_t ascq, uint8_t *sam_stat) {\n\treturn_sense(DATA_PROTECT, ascq, NULL, sam_stat);\n\tMHVTL_DBG(1, \"\");\n}\n\nvoid sam_hardware_error(uint16_t ascq, uint8_t *sam_stat) {\n\treturn_sense(HARDWARE_ERROR, ascq, NULL, sam_stat);\n\tMHVTL_DBG(1, \"\");\n}\n\nvoid sam_no_sense(uint8_t key, uint16_t ascq, uint8_t *sam_stat) {\n\treturn_sense(NO_SENSE | key, ascq, NULL, sam_stat);\n\tMHVTL_DBG(1, \"\");\n}\n\nint check_reset(uint8_t *sam_stat) {\n\tint retval = reset;\n\n\tif (reset) {\n\t\tsam_unit_attention(E_POWERON_RESET, sam_stat);\n\t\treset = 0;\n\t}\n\treturn retval;\n}\n\nint check_inquiry_data_has_changed(uint8_t *sam_stat) {\n\tint retval = inquiry_data_changed;\n\n\tif (inquiry_data_changed) {\n\t\tMHVTL_DBG(1, \"Returning INQUIRY_DATA_HAS_CHANGED\");\n\t\tsam_unit_attention(E_INQUIRY_DATA_HAS_CHANGED, sam_stat);\n\t\tinquiry_data_changed = 0;\n\t}\n\treturn retval;\n}\n\nvoid reset_device(void) {\n\treset = 1;\n}\n\n/* Force flag to indicate inquiry data has changed */\nvoid set_inquiry_data_changed(void) {\n\tinquiry_data_changed = 1;\n}\n\n#define READBLOCKLIMITS_ARR_SZ 6\nint resp_read_block_limits(struct mhvtl_ds *dbuf_p, int sz) {\n\tuint8_t *arr = (uint8_t *)dbuf_p->data;\n\n\tMHVTL_DBG(2, \"Min/Max sz: %d/%d\", 1, sz);\n\tmemset(arr, 0, READBLOCKLIMITS_ARR_SZ);\n\tput_unaligned_be24(sz, &arr[1]);\n\tarr[5] = 0x1; /* Minimum block size */\n\n\treturn READBLOCKLIMITS_ARR_SZ;\n}\n\n/*\n * Respond with S/No. of media currently mounted\n */\nuint32_t resp_read_media_serial(uint8_t *sno, uint8_t *buf, uint8_t *sam_stat) {\n\tuint32_t size = 38;\n\n\tsnprintf((char *)&buf[4], size - 3, \"%-34.34s\", sno);\n\tput_unaligned_be16(size, &buf[2]);\n\n\treturn size;\n}\n\nvoid setTapeAlert(struct TapeAlert_pg *ta, uint64_t flg) {\n\tint a;\n\n\tMHVTL_DBG(2, \"Setting TapeAlert flags 0x%.8x %.8x\",\n\t\t\t  (uint32_t)(flg >> 32) & 0xffffffff,\n\t\t\t  (uint32_t)flg & 0xffffffff);\n\n\tfor (a = 0; a < 64; a++)\n\t\tta->TapeAlert[a].value = (flg & (1ull << a)) ? 1 : 0;\n}\n\n/*\n * Simple function to read 'count' bytes from the chardev into 'buf'.\n */\nint retrieve_CDB_data(int cdev, struct mhvtl_ds *ds) {\n\tint ioctl_err;\n\n\tMHVTL_DBG(3, \"retrieving %d bytes from kernel\", ds->sz);\n\tioctl_err = ioctl(cdev, VTL_GET_DATA, ds);\n\tif (ioctl_err < 0) {\n\t\tMHVTL_ERR(\"Failed retrieving data via ioctl(): %s\",\n\t\t\t\t  strerror(errno));\n\t\treturn 0;\n\t}\n\treturn ds->sz;\n}\n\n/*\n * Passes struct mhvtl_ds to kernel module.\n *   struct contains amount of data, status and pointer to data struct.\n *\n * Returns nothing.\n */\nvoid completeSCSICommand(int cdev, struct mhvtl_ds *ds) {\n\tuint8_t *s;\n\n\tioctl(cdev, VTL_PUT_DATA, ds);\n\n\ts = (uint8_t *)ds->sense_buf;\n\n\tif (ds->sam_stat == SAM_STAT_CHECK_CONDITION) {\n\t\tMHVTL_DBG(2, \"s/n: (%ld), sz: %d, sam_status: %d\"\n\t\t\t\t\t \" [%02x %02x %02x]\",\n\t\t\t\t  (unsigned long)ds->serialNo,\n\t\t\t\t  ds->sz, ds->sam_stat,\n\t\t\t\t  s[2], s[12], s[13]);\n\t} else {\n\t\tMHVTL_DBG(2, \"OP s/n: (%ld), sz: %d, sam_status: %d\",\n\t\t\t\t  (unsigned long)ds->serialNo,\n\t\t\t\t  ds->sz, ds->sam_stat);\n\t}\n\n\tds->sam_stat = 0;\n}\n\n/* Hex dump 'count' bytes at p  */\nvoid hex_dump(uint8_t *p, int count) {\n\tint j;\n\tint lvl = 2; /* Log at level 'lvl' */\n\tint n;\n\n\tfor (j = 0; j < count; j += 16) {\n\t\tn = count - j;\n\t\tswitch (n) {\n\t\tcase 0:\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tMHVTL_DBG_NO_FUNC(lvl, \"%02x %45s : %c\", p[j + 0], \" \", isprint(p[j + 0]) ? p[j + 0] : ' ');\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tMHVTL_DBG_NO_FUNC(lvl, \"%02x %02x %42s : %c%c\", p[j + 0], p[j + 1],\n\t\t\t\t\t\t\t  \" \",\n\t\t\t\t\t\t\t  isprint(p[j + 0]) ? p[j + 0] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 1]) ? p[j + 1] : '.');\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\tMHVTL_DBG_NO_FUNC(lvl, \"%02x %02x %02x %39s : %c%c%c\", p[j + 0], p[j + 1], p[j + 2],\n\t\t\t\t\t\t\t  \" \",\n\t\t\t\t\t\t\t  isprint(p[j + 0]) ? p[j + 0] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 1]) ? p[j + 1] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 2]) ? p[j + 2] : '.');\n\t\t\tbreak;\n\t\tcase 4:\n\t\t\tMHVTL_DBG_NO_FUNC(lvl, \"%02x %02x %02x %02x %36s : %c%c%c%c\", p[j + 0], p[j + 1], p[j + 2], p[j + 3],\n\t\t\t\t\t\t\t  \" \",\n\t\t\t\t\t\t\t  isprint(p[j + 0]) ? p[j + 0] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 1]) ? p[j + 1] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 2]) ? p[j + 2] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 3]) ? p[j + 3] : '.');\n\t\t\tbreak;\n\t\tcase 5:\n\t\t\tMHVTL_DBG_NO_FUNC(lvl,\n\t\t\t\t\t\t\t  \"%02x %02x %02x %02x %02x %33s : %c%c%c%c%c\",\n\t\t\t\t\t\t\t  p[j + 0], p[j + 1], p[j + 2], p[j + 3],\n\t\t\t\t\t\t\t  p[j + 4],\n\t\t\t\t\t\t\t  \" \",\n\t\t\t\t\t\t\t  isprint(p[j + 0]) ? p[j + 0] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 1]) ? p[j + 1] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 2]) ? p[j + 2] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 3]) ? p[j + 3] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 4]) ? p[j + 4] : '.');\n\t\t\tbreak;\n\t\tcase 6:\n\t\t\tMHVTL_DBG_NO_FUNC(lvl,\n\t\t\t\t\t\t\t  \"%02x %02x %02x %02x %02x %02x %30s : %c%c%c%c%c%c\",\n\t\t\t\t\t\t\t  p[j + 0], p[j + 1], p[j + 2], p[j + 3],\n\t\t\t\t\t\t\t  p[j + 4], p[j + 5],\n\t\t\t\t\t\t\t  \" \",\n\t\t\t\t\t\t\t  isprint(p[j + 0]) ? p[j + 0] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 1]) ? p[j + 1] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 2]) ? p[j + 2] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 3]) ? p[j + 3] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 4]) ? p[j + 4] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 5]) ? p[j + 5] : '.');\n\t\t\tbreak;\n\t\tcase 7:\n\t\t\tMHVTL_DBG_NO_FUNC(lvl,\n\t\t\t\t\t\t\t  \"%02x %02x %02x %02x %02x %02x %02x %27s : %c%c%c%c%c%c%c\",\n\t\t\t\t\t\t\t  p[j + 0], p[j + 1], p[j + 2], p[j + 3],\n\t\t\t\t\t\t\t  p[j + 4], p[j + 5], p[j + 6],\n\t\t\t\t\t\t\t  \" \",\n\t\t\t\t\t\t\t  isprint(p[j + 0]) ? p[j + 0] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 1]) ? p[j + 1] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 2]) ? p[j + 2] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 3]) ? p[j + 3] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 4]) ? p[j + 4] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 5]) ? p[j + 5] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 6]) ? p[j + 6] : '.');\n\t\t\tbreak;\n\t\tcase 8:\n\t\t\tMHVTL_DBG_NO_FUNC(lvl,\n\t\t\t\t\t\t\t  \"%02x %02x %02x %02x %02x %02x %02x %02x %24s : %c%c%c%c%c%c%c%c\",\n\t\t\t\t\t\t\t  p[j + 0], p[j + 1], p[j + 2], p[j + 3],\n\t\t\t\t\t\t\t  p[j + 4], p[j + 5], p[j + 6], p[j + 7],\n\t\t\t\t\t\t\t  \" \",\n\t\t\t\t\t\t\t  isprint(p[j + 0]) ? p[j + 0] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 1]) ? p[j + 1] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 2]) ? p[j + 2] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 3]) ? p[j + 3] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 4]) ? p[j + 4] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 5]) ? p[j + 5] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 6]) ? p[j + 6] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 7]) ? p[j + 7] : '.');\n\t\t\tbreak;\n\t\tcase 9:\n\t\t\tMHVTL_DBG_NO_FUNC(lvl,\n\t\t\t\t\t\t\t  \"%02x %02x %02x %02x %02x %02x %02x %02x  %02x %19s : %c%c%c%c%c%c%c%c %c\",\n\t\t\t\t\t\t\t  p[j + 0], p[j + 1], p[j + 2], p[j + 3],\n\t\t\t\t\t\t\t  p[j + 4], p[j + 5], p[j + 6], p[j + 7],\n\t\t\t\t\t\t\t  p[j + 8],\n\t\t\t\t\t\t\t  \" \",\n\t\t\t\t\t\t\t  isprint(p[j + 0]) ? p[j + 0] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 1]) ? p[j + 1] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 2]) ? p[j + 2] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 3]) ? p[j + 3] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 4]) ? p[j + 4] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 5]) ? p[j + 5] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 6]) ? p[j + 6] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 7]) ? p[j + 7] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 8]) ? p[j + 8] : '.');\n\t\t\tbreak;\n\t\tcase 10:\n\t\t\tMHVTL_DBG_NO_FUNC(lvl,\n\t\t\t\t\t\t\t  \"%02x %02x %02x %02x %02x %02x %02x %02x  %02x %02x %16s : %c%c%c%c%c%c%c%c %c%c\",\n\t\t\t\t\t\t\t  p[j + 0], p[j + 1], p[j + 2], p[j + 3],\n\t\t\t\t\t\t\t  p[j + 4], p[j + 5], p[j + 6], p[j + 7],\n\t\t\t\t\t\t\t  p[j + 8], p[j + 9],\n\t\t\t\t\t\t\t  \" \",\n\t\t\t\t\t\t\t  isprint(p[j + 0]) ? p[j + 0] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 1]) ? p[j + 1] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 2]) ? p[j + 2] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 3]) ? p[j + 3] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 4]) ? p[j + 4] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 5]) ? p[j + 5] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 6]) ? p[j + 6] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 7]) ? p[j + 7] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 8]) ? p[j + 8] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 9]) ? p[j + 9] : '.');\n\t\t\tbreak;\n\t\tcase 11:\n\t\t\tMHVTL_DBG_NO_FUNC(lvl,\n\t\t\t\t\t\t\t  \"%02x %02x %02x %02x %02x %02x %02x %02x  %02x %02x %02x %13s : %c%c%c%c%c%c%c%c %c%c%c\",\n\t\t\t\t\t\t\t  p[j + 0], p[j + 1], p[j + 2], p[j + 3],\n\t\t\t\t\t\t\t  p[j + 4], p[j + 5], p[j + 6], p[j + 7],\n\t\t\t\t\t\t\t  p[j + 8], p[j + 9], p[j + 10],\n\t\t\t\t\t\t\t  \" \",\n\t\t\t\t\t\t\t  isprint(p[j + 0]) ? p[j + 0] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 1]) ? p[j + 1] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 2]) ? p[j + 2] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 3]) ? p[j + 3] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 4]) ? p[j + 4] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 5]) ? p[j + 5] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 6]) ? p[j + 6] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 7]) ? p[j + 7] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 8]) ? p[j + 8] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 9]) ? p[j + 9] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 10]) ? p[j + 10] : '.');\n\t\t\tbreak;\n\t\tcase 12:\n\t\t\tMHVTL_DBG_NO_FUNC(lvl,\n\t\t\t\t\t\t\t  \"%02x %02x %02x %02x %02x %02x %02x %02x  %02x %02x %02x %02x %10s : %c%c%c%c%c%c%c%c %c%c%c%c\",\n\t\t\t\t\t\t\t  p[j + 0], p[j + 1], p[j + 2], p[j + 3],\n\t\t\t\t\t\t\t  p[j + 4], p[j + 5], p[j + 6], p[j + 7],\n\t\t\t\t\t\t\t  p[j + 8], p[j + 9], p[j + 10], p[j + 11],\n\t\t\t\t\t\t\t  \" \",\n\t\t\t\t\t\t\t  isprint(p[j + 0]) ? p[j + 0] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 1]) ? p[j + 1] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 2]) ? p[j + 2] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 3]) ? p[j + 3] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 4]) ? p[j + 4] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 5]) ? p[j + 5] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 6]) ? p[j + 6] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 7]) ? p[j + 7] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 8]) ? p[j + 8] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 9]) ? p[j + 9] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 10]) ? p[j + 10] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 11]) ? p[j + 11] : '.');\n\t\t\tbreak;\n\t\tcase 13:\n\t\t\tMHVTL_DBG_NO_FUNC(lvl,\n\t\t\t\t\t\t\t  \"%02x %02x %02x %02x %02x %02x %02x %02x  %02x %02x %02x %02x %02x %8s : %c%c%c%c%c%c%c%c %c%c%c%c%c\",\n\t\t\t\t\t\t\t  p[j + 0], p[j + 1], p[j + 2], p[j + 3],\n\t\t\t\t\t\t\t  p[j + 4], p[j + 5], p[j + 6], p[j + 7],\n\t\t\t\t\t\t\t  p[j + 8], p[j + 9], p[j + 10], p[j + 11],\n\t\t\t\t\t\t\t  p[j + 12],\n\t\t\t\t\t\t\t  \" \",\n\t\t\t\t\t\t\t  isprint(p[j + 0]) ? p[j + 0] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 1]) ? p[j + 1] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 2]) ? p[j + 2] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 3]) ? p[j + 3] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 4]) ? p[j + 4] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 5]) ? p[j + 5] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 6]) ? p[j + 6] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 7]) ? p[j + 7] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 8]) ? p[j + 8] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 9]) ? p[j + 9] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 10]) ? p[j + 10] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 11]) ? p[j + 11] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 12]) ? p[j + 12] : '.');\n\t\t\tbreak;\n\t\tcase 14:\n\t\t\tMHVTL_DBG_NO_FUNC(lvl,\n\t\t\t\t\t\t\t  \"%02x %02x %02x %02x %02x %02x %02x %02x  %02x %02x %02x %02x %02x %02x %5s : %c%c%c%c%c%c%c%c %c%c%c%c%c%c\",\n\t\t\t\t\t\t\t  p[j + 0], p[j + 1], p[j + 2], p[j + 3],\n\t\t\t\t\t\t\t  p[j + 4], p[j + 5], p[j + 6], p[j + 7],\n\t\t\t\t\t\t\t  p[j + 8], p[j + 9], p[j + 10], p[j + 11],\n\t\t\t\t\t\t\t  p[j + 12], p[j + 13],\n\t\t\t\t\t\t\t  \" \",\n\t\t\t\t\t\t\t  isprint(p[j + 0]) ? p[j + 0] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 1]) ? p[j + 1] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 2]) ? p[j + 2] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 3]) ? p[j + 3] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 4]) ? p[j + 4] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 5]) ? p[j + 5] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 6]) ? p[j + 6] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 7]) ? p[j + 7] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 8]) ? p[j + 8] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 9]) ? p[j + 9] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 10]) ? p[j + 10] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 11]) ? p[j + 11] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 12]) ? p[j + 12] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 13]) ? p[j + 13] : '.');\n\t\t\tbreak;\n\t\tcase 15:\n\t\t\tMHVTL_DBG_NO_FUNC(lvl,\n\t\t\t\t\t\t\t  \"%02x %02x %02x %02x %02x %02x %02x %02x  %02x %02x %02x %02x %02x %02x %02x %2s : %c%c%c%c%c%c%c%c %c%c%c%c%c%c%c\",\n\t\t\t\t\t\t\t  p[j + 0], p[j + 1], p[j + 2], p[j + 3],\n\t\t\t\t\t\t\t  p[j + 4], p[j + 5], p[j + 6], p[j + 7],\n\t\t\t\t\t\t\t  p[j + 8], p[j + 9], p[j + 10], p[j + 11],\n\t\t\t\t\t\t\t  p[j + 12], p[j + 13], p[j + 14],\n\t\t\t\t\t\t\t  \" \",\n\t\t\t\t\t\t\t  isprint(p[j + 0]) ? p[j + 0] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 1]) ? p[j + 1] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 2]) ? p[j + 2] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 3]) ? p[j + 3] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 4]) ? p[j + 4] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 5]) ? p[j + 5] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 6]) ? p[j + 6] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 7]) ? p[j + 7] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 8]) ? p[j + 8] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 9]) ? p[j + 9] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 10]) ? p[j + 10] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 11]) ? p[j + 11] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 12]) ? p[j + 12] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 13]) ? p[j + 13] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 14]) ? p[j + 14] : '.');\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tMHVTL_DBG_NO_FUNC(lvl,\n\t\t\t\t\t\t\t  \"%02x %02x %02x %02x %02x %02x %02x %02x  %02x %02x %02x %02x %02x %02x %02x %02x : %c%c%c%c%c%c%c%c %c%c%c%c%c%c%c%c\",\n\t\t\t\t\t\t\t  p[j + 0], p[j + 1], p[j + 2], p[j + 3],\n\t\t\t\t\t\t\t  p[j + 4], p[j + 5], p[j + 6], p[j + 7],\n\t\t\t\t\t\t\t  p[j + 8], p[j + 9], p[j + 10], p[j + 11],\n\t\t\t\t\t\t\t  p[j + 12], p[j + 13], p[j + 14], p[j + 15],\n\t\t\t\t\t\t\t  isprint(p[j + 0]) ? p[j + 0] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 1]) ? p[j + 1] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 2]) ? p[j + 2] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 3]) ? p[j + 3] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 4]) ? p[j + 4] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 5]) ? p[j + 5] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 6]) ? p[j + 6] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 7]) ? p[j + 7] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 8]) ? p[j + 8] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 9]) ? p[j + 9] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 10]) ? p[j + 10] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 11]) ? p[j + 11] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 12]) ? p[j + 12] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 13]) ? p[j + 13] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 14]) ? p[j + 14] : '.',\n\t\t\t\t\t\t\t  isprint(p[j + 15]) ? p[j + 15] : '.');\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nstatic int mhvtl_access(char *p, int len, char *entry) {\n\tint\t\t\tfstat;\n\tstruct stat km;\n\tchar\t\tfilename[256];\n\n\tsnprintf(filename, ARRAY_SIZE(filename),\n\t\t\t \"/sys/bus/mhvtl/drivers/mhvtl/%s\", entry);\n\tMHVTL_DBG(1, \"Testing %s\", filename);\n\tfstat = stat(filename, &km);\n\tif (fstat >= 0) {\n\t\tstrncpy(p, filename, len);\n\t\treturn 0;\n\t}\n\tsnprintf(filename, ARRAY_SIZE(filename),\n\t\t\t \"/sys/bus/pseudo9/drivers/mhvtl/%s\", entry);\n\tMHVTL_DBG(1, \"Testing %s\", filename);\n\tfstat = stat(filename, &km);\n\tif (fstat >= 0) {\n\t\tstrncpy(p, filename, len);\n\t\treturn 0;\n\t}\n\tsnprintf(filename, ARRAY_SIZE(filename),\n\t\t\t \"/sys/bus/pseudo/drivers/mhvtl/%s\", entry);\n\tMHVTL_DBG(1, \"Testing %s\", filename);\n\tfstat = stat(filename, &km);\n\tif (fstat >= 0) {\n\t\tstrncpy(p, filename, len);\n\t\treturn 0;\n\t}\n\treturn -1;\n}\n\n/* Writing to the kernel module will block until the device is created.\n * Unfortunately, we need to be polling the device and process the\n * SCSI op code before the lu can be created.\n * Chicken & Egg.\n * So spawn child process and don't wait for return.\n * Let the child process write to the kernel module\n */\npid_t add_lu(unsigned minor, struct mhvtl_ctl *ctl) {\n\tchar\tstr[1024];\n\tpid_t\tppid, pid, mypid;\n\tssize_t retval;\n\tFILE   *pseudo;\n\tchar\tpseudo_filename[256];\n\tchar\terrmsg[512];\n\n\tsprintf(str, \"add %u %d %d %d\",\n\t\t\tminor, ctl->channel, ctl->id, ctl->lun);\n\n\tif (mhvtl_access(pseudo_filename, ARRAY_SIZE(pseudo_filename), \"add_lu\") < 0) {\n\t\tsprintf(str, \"Could not find mhvtl kernel module\");\n\t\tMHVTL_ERR(\"%s: %s\", mhvtl_driver_name, str);\n\t\tprintf(\"%s: %s\\n\", mhvtl_driver_name, str);\n\t\texit(EIO);\n\t}\n\n\t/* Parent PID */\n\tppid = getpid();\n\n\tswitch (pid = fork()) {\n\tcase 0: /* Child */\n\t\tmypid  = getpid();\n\t\tpseudo = fopen(pseudo_filename, \"w\");\n\t\tif (!pseudo) {\n\t\t\tsnprintf(errmsg, ARRAY_SIZE(errmsg),\n\t\t\t\t\t \"Could not open %s: %s\", pseudo_filename, strerror(errno));\n\t\t\tMHVTL_ERR(\"Parent PID: %ld -> %s : %s\", (long)ppid, errmsg, strerror(errno));\n\t\t\tperror(\"Could not open 'add_lu'\");\n\t\t\texit(-1);\n\t\t}\n\n\t\tretval = fprintf(pseudo, \"%s\\n\", str);\n\t\tMHVTL_DBG(2, \"Wrote '%s' (%d bytes) to %s\",\n\t\t\t\t  str, (int)retval, pseudo_filename);\n\n\t\tfclose(pseudo);\n\t\tMHVTL_DBG(1, \"Parent PID: [%ld] -> Child [%ld] anounces 'lu [%d:%d:%d] created'.\",\n\t\t\t\t  (long)ppid, (long)mypid, ctl->channel, ctl->id, ctl->lun);\n\t\texit(0);\n\t\tbreak;\n\tcase -1:\n\t\tperror(\"Failed to fork()\");\n\t\tMHVTL_ERR(\"Parent PID: %ld -> Fail to fork() %s\", (long)ppid, strerror(errno));\n\t\treturn 0;\n\t\tbreak;\n\tdefault: /* Parent */\n\t\tMHVTL_DBG(2, \"[%ld] Child PID [%ld] will start logical unit [%d:%d:%d]\",\n\t\t\t\t  (long)ppid, (long)pid, ctl->channel,\n\t\t\t\t  ctl->id, ctl->lun);\n\n\t\treturn pid;\n\t\tbreak;\n\t}\n\n\treturn 0;\n}\n\nstatic int chrdev_get_major(void) {\n\tFILE\t  *f;\n\tchar\t   filename[256];\n\tconst char str[] = \"Could not locate mhvtl kernel module\";\n\tint\t\t   rc\t = 0;\n\tint\t\t   x;\n\tint\t\t   majno;\n\n\tif (mhvtl_access(filename, ARRAY_SIZE(filename), \"major\") < 0) {\n\t\tMHVTL_ERR(\"%s: %s\", mhvtl_driver_name, str);\n\t\tprintf(\"%s: %s\\n\", mhvtl_driver_name, str);\n\t\texit(EIO);\n\t}\n\n\tf = fopen(filename, \"r\");\n\tif (!f) {\n\t\tMHVTL_DBG(1, \"Can't open %s: %s\", filename, strerror(errno));\n\t\treturn -ENOENT;\n\t}\n\tx = fscanf(f, \"%d\", &majno);\n\tif (!x) {\n\t\tMHVTL_DBG(1, \"Cant identify major number for mhvtl\");\n\t\trc = -1;\n\t} else\n\t\trc = majno;\n\n\tfclose(f);\n\treturn rc;\n}\n\nint chrdev_create(unsigned minor) {\n\tint\t  majno;\n\tint\t  x;\n\tint\t  ret = 0;\n\tdev_t dev;\n\tchar  pathname[64];\n\n\tsnprintf(pathname, sizeof(pathname), \"/dev/mhvtl%u\", minor);\n\n\tmajno = chrdev_get_major();\n\tif (majno == -ENOENT) {\n\t\tMHVTL_DBG(1, \"** Incorrect version of kernel module loaded **\");\n\t\tret = -1;\n\t\tgoto err;\n\t}\n\n\tdev = makedev(majno, minor);\n\tMHVTL_DBG(2, \"Major number: %d, minor number: %u\",\n\t\t\t  major(dev), minor(dev));\n\tMHVTL_DBG(3, \"mknod(%s, %02o, major: %d minor: %d\",\n\t\t\t  pathname, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,\n\t\t\t  major(dev), minor(dev));\n\tx = mknod(pathname, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, dev);\n\tif (x < 0) {\n\t\tif (errno == EEXIST) /* Success if node already exists */\n\t\t\treturn 0;\n\n\t\tMHVTL_DBG(1, \"Error creating device node for mhvtl: %s\",\n\t\t\t\t  strerror(errno));\n\t\tret = -1;\n\t}\n\nerr:\n\treturn ret;\n}\n\nint chrdev_open(const char *name, unsigned minor) {\n\tFILE *f;\n\tchar  devname[256];\n\tchar  buf[256];\n\tint\t  devn;\n\tint\t  ctlfd;\n\n\tf = fopen(\"/proc/devices\", \"r\");\n\tif (!f) {\n\t\tprintf(\"Cannot open control path to the driver: %s\\n\",\n\t\t\t   strerror(errno));\n\t\treturn -1;\n\t}\n\n\tdevn = 0;\n\twhile (!feof(f)) {\n\t\tif (!fgets(buf, sizeof(buf), f))\n\t\t\tbreak;\n\t\tif (sscanf(buf, \"%d %s\", &devn, devname) != 2)\n\t\t\tcontinue;\n\t\tif (!strcmp(devname, name))\n\t\t\tbreak;\n\t\tdevn = 0;\n\t}\n\tfclose(f);\n\tif (!devn) {\n\t\tprintf(\"Cannot find %s in /proc/devices - \"\n\t\t\t   \"make sure the module is loaded\\n\",\n\t\t\t   name);\n\t\treturn -1;\n\t}\n\tsnprintf(devname, sizeof(devname), \"/dev/%s%u\", name, minor);\n\tctlfd = open(devname, O_RDWR | O_NONBLOCK | O_EXCL);\n\tif (ctlfd < 0) {\n\t\tprintf(\"Cannot open %s %s\\n\", devname, strerror(errno));\n\t\tfflush(NULL);\n\t\tprintf(\"\\n\\n\");\n\t\treturn -1;\n\t}\n\treturn ctlfd;\n}\n\n/* Create the fifo and open it for writing (appending)\n * Return 0 on success,\n * Return errno on failure\n */\nint open_fifo(FILE **fifo_fd, char *fifoname) {\n\tint ret;\n\n\tumask(0);\n\tret = 0;\n\n\tret = mknod(fifoname, S_IFIFO | 0644, 0);\n\tif ((ret < 0) && (errno != EEXIST)) {\n\t\tMHVTL_LOG(\"Sorry, cant create %s: %s, Disabling fifo feature\",\n\t\t\t\t  fifoname, strerror(errno));\n\t\tret = errno;\n\t} else {\n\t\t*fifo_fd = fopen(fifoname, \"w+\");\n\t\tif (*fifo_fd) {\n\t\t\tMHVTL_DBG(2, \"Successfully opened named pipe: %s\",\n\t\t\t\t\t  fifoname);\n\t\t} else {\n\t\t\tMHVTL_LOG(\"Sorry, cant open %s: %s, \"\n\t\t\t\t\t  \"Disabling fifo feature\",\n\t\t\t\t\t  fifoname, strerror(errno));\n\t\t\tret = errno;\n\t\t}\n\t}\n\treturn ret;\n}\n\nvoid status_change(FILE *fifo_fd, int current_status, int m_id, char **msg) {\n\ttime_t\t t;\n\tchar\t*timestamp;\n\tunsigned i;\n\n\tif (!fifo_fd)\n\t\treturn;\n\n\tt\t\t  = time(NULL);\n\ttimestamp = ctime(&t);\n\n\tfor (i = 14; i < strlen(timestamp); i++)\n\t\tif (timestamp[i] == '\\n')\n\t\t\ttimestamp[i] = '\\0';\n\n\tif (*msg) {\n\t\tfprintf(fifo_fd, \"%s - %d: - %s\\n\",\n\t\t\t\ttimestamp, m_id, *msg);\n\t\tfree(*msg);\n\t\t*msg = NULL;\n\t} else\n\t\tfprintf(fifo_fd, \"%s - %d: - %s\\n\", timestamp, m_id,\n\t\t\t\tstate_desc[current_status].state_desc);\n\n\tfflush_unlocked(fifo_fd);\n\n\treturn;\n}\n\n/*\n * Pinched straight from SCSI tgt code\n * Thanks guys..\n *\n * Modified to always return success. Earlier kernels don't have oom_adjust\n * 'feature' so don't fail if we can't find it..\n */\nint oom_adjust(void) {\n\tint\t fd, ret;\n\tchar path[64];\n\n\t/* Avoid oom-killer */\n\tsprintf(path, \"/proc/%d/oom_score_adj\", getpid());\n\tfd = open(path, O_WRONLY);\n\tif (fd < 0) {\n\t\tMHVTL_DBG(3, \"Can't open oom-killer's pardon %s, %s\",\n\t\t\t\t  path, strerror(errno));\n\t\treturn 0;\n\t}\n\tret = write(fd, \"-17\\n\", 4);\n\tif (ret < 0) {\n\t\tMHVTL_DBG(3, \"Can't adjust oom-killer's pardon %s, %s\",\n\t\t\t\t  path, strerror(errno));\n\t}\n\tclose(fd);\n\treturn 0;\n}\n\n/* fgets but replace '\\n' with null */\nchar *readline(char *buf, int len, FILE *s) {\n\tint\t  i;\n\tchar *ret;\n\n\tret = fgets(buf, len, s);\n\tif (!ret)\n\t\treturn ret;\n\n\t/* Skip blank line */\n\tfor (i = 1; i < len; i++)\n\t\tif (buf[i] == '\\n')\n\t\t\tbuf[i] = 0;\n\n\tMHVTL_DBG(3, \"%s\", buf);\n\treturn ret;\n}\n\n/* Copy bytes from 'src' to 'dest, blank-filling to length 'len'.  There will\n * not be a NULL byte at the end.\n */\nvoid blank_fill(uint8_t *dest, char *src, int len) {\n\tint i;\n\n\tfor (i = 0; i < len; i++) {\n\t\tif (*src != '\\0')\n\t\t\t*dest++ = *src++;\n\t\telse\n\t\t\t*dest++ = ' ';\n\t}\n}\n\nvoid truncate_spaces(char *s, int maxlen) {\n\tint x;\n\n\tfor (x = 0; x < maxlen; x++)\n\t\tif ((s[x] == ' ') || (s[x] == '\\0')) {\n\t\t\ts[x] = '\\0';\n\t\t\treturn;\n\t\t}\n}\n\n/* MHVTL_VERSION looks like : 0.18.xx or 1.xx.xx\n *\n * Convert into a string after converting the 18.xx into \"18xx\"\n *\n * NOTE: Caller has to free string after use.\n */\nchar *get_version(void) {\n\tchar  b[64];\n\tint\t  x, y, z;\n\tchar *c;\n\n\tc = (char *)zalloc(32); /* Way more than enough for a 4 byte string */\n\tif (!c)\n\t\treturn NULL;\n\n\tsprintf(b, \"%s\", MHVTL_VERSION);\n\n\tsscanf(b, \"%d.%d.%d\", &x, &y, &z);\n\tif (x)\n\t\tsprintf(c, \"%02d%02d\", x, y);\n\telse\n\t\tsprintf(c, \"%02d%02d\", y, z);\n\n\treturn c;\n}\n\nvoid log_opcode(char *opcode, struct scsi_cmd *cmd) {\n\tstruct s_sd sd;\n\n\tMHVTL_DBG(1, \"*** Unsupported op code: %s ***\", opcode);\n\tsd.byte0\t\t = SKSV | CD;\n\tsd.field_pointer = 0;\n\tsam_illegal_request(E_INVALID_OP_CODE, &sd, &cmd->dbuf_p->sam_stat);\n\tMHVTL_DBG_PRT_CDB(1, cmd);\n}\n\n#define LOCK_PATH \"/var/lock/mhvtl\"\n#define MAX_WAIT  20\nint check_for_running_daemons(unsigned minor) {\n\tchar lck_file[128];\n\tint\t lck;\n\tint\t a;\n\tlong rand;\n\n\t/* Don't really care if this dir exists already */\n\tif (mkdir(LOCK_PATH, S_IWUSR | S_IRUSR) < 0) {\n\t\tMHVTL_DBG(3, \"Unable to create lock directory %s\", LOCK_PATH);\n\t}\n\n\tsprintf(lck_file, \"%s/mhvtl%d\", LOCK_PATH, minor);\n\tMHVTL_DBG(1, \"Checking lock file %s\", lck_file);\n\n\tfor (a = 0; a < MAX_WAIT; a++) {\n\t\tlck = open(lck_file, O_CREAT | O_EXCL | O_WRONLY, S_IRWXU);\n\t\tif (lck >= 0) {\n\t\t\tMHVTL_DBG(1, \"Successfully created lock file %s\", lck_file);\n\t\t\tclose(lck);\n\t\t\treturn 0;\n\t\t} else if (errno == EEXIST) { /* Lock file still exists */\n\t\t\trand = (0xffL & random()) << 12;\n\t\t\tMHVTL_DBG(3, \"Lock file exists, sleeping for 0x%lxs\", rand);\n\t\t\tusleep((useconds_t)rand);\n\t\t} else { /* Unexpected error */\n\t\t\tMHVTL_DBG(1, \"opening lock file %s failed %s\", lck_file, strerror(errno));\n\t\t\treturn 2;\n\t\t}\n\t}\n\n\tMHVTL_DBG(1, \"Unable to obtain lock file %s - returing error\", lck_file);\n\treturn 1;\n}\n\nint free_lock(unsigned minor) {\n\tchar lck_file[128];\n\n\tsprintf(lck_file, \"%s/mhvtl%d\", LOCK_PATH, minor);\n\tMHVTL_DBG(1, \"Unlink %s\", lck_file);\n\tunlink(lck_file);\n\treturn 0;\n}\n\n/* Abort if string length > len */\nvoid checkstrlen(char *s, unsigned int len, int lineno) {\n\tif (strlen(s) > len) {\n\t\tMHVTL_DBG(1, \"Line #: %d, String %s is > %d... Aborting\",\n\t\t\t\t  lineno, s, len);\n\t\tprintf(\"String %s longer than %d chars\\n\", s, len);\n\t\tprintf(\"Please fix config file\\n\");\n\t\tabort();\n\t}\n}\n\nint device_type_register(struct lu_phy_attr *lu, struct device_type_template *t) {\n\tlu->scsi_ops = t;\n\treturn 0;\n}\n\nuint8_t set_compression_mode_pg(struct list_head *l, int lvl) {\n\tstruct mode *m;\n\tuint8_t\t\t*p;\n\n\tMHVTL_DBG(3, \"*** Trace ***\");\n\n\t/* Find pointer to Data Compression mode Page */\n\tm = lookup_mode_pg(l, MODE_DATA_COMPRESSION, 0);\n\tMHVTL_DBG(3, \"l: %p, m: %p, m->pcodePointer: %p\",\n\t\t\t  l, m, m->pcodePointer);\n\tif (m) {\n\t\tp = m->pcodePointer;\n\t\tp[2] |= 0x80; /* Set data compression enable */\n\t}\n\t/* Find pointer to Device Configuration mode Page */\n\tm = lookup_mode_pg(l, MODE_DEVICE_CONFIGURATION, 0);\n\tMHVTL_DBG(3, \"l: %p, m: %p, m->pcodePointer: %p\",\n\t\t\t  l, m, m->pcodePointer);\n\tif (m) {\n\t\tp\t  = m->pcodePointer;\n\t\tp[14] = lvl;\n\t}\n\treturn SAM_STAT_GOOD;\n}\n\nuint8_t clear_compression_mode_pg(struct list_head *l) {\n\tstruct mode *m;\n\tuint8_t\t\t*p;\n\n\tMHVTL_DBG(3, \"*** Trace ***\");\n\n\t/* Find pointer to Data Compression mode Page */\n\tm = lookup_mode_pg(l, MODE_DATA_COMPRESSION, 0);\n\tMHVTL_DBG(3, \"l: %p, m: %p, m->pcodePointer: %p\",\n\t\t\t  l, m, m->pcodePointer);\n\tif (m) {\n\t\tp = m->pcodePointer;\n\t\tp[2] &= 0x7f; /* clear data compression enable */\n\t}\n\t/* Find pointer to Device Configuration mode Page */\n\tm = lookup_mode_pg(l, MODE_DEVICE_CONFIGURATION, 0);\n\tMHVTL_DBG(3, \"l: %p, m: %p, m->pcodePointer: %p\",\n\t\t\t  l, m, m->pcodePointer);\n\tif (m) {\n\t\tp\t  = m->pcodePointer;\n\t\tp[14] = MHVTL_NO_COMPRESSION;\n\t}\n\treturn SAM_STAT_GOOD;\n}\n\nuint8_t clear_WORM(struct list_head *l) {\n\tuint8_t\t\t*smp_dp;\n\tstruct mode *m;\n\n\tm = lookup_mode_pg(l, MODE_MEDIUM_CONFIGURATION, 0);\n\tif (!m) {\n\t\tMHVTL_DBG(3, \"Did not find MODE_MEDIUM_CONFIGURATION page\");\n\t} else {\n\t\tMHVTL_DBG(3, \"l: %p, m: %p, m->pcodePointer: %p\",\n\t\t\t\t  l, m, m->pcodePointer);\n\n\t\tsmp_dp = m->pcodePointer;\n\t\tif (!smp_dp)\n\t\t\treturn SAM_STAT_GOOD;\n\t\tsmp_dp[2] = 0x0;\n\t}\n\n\treturn SAM_STAT_GOOD;\n}\n\nuint8_t set_WORM(struct list_head *l) {\n\tuint8_t\t\t*smp_dp;\n\tstruct mode *m;\n\n\tMHVTL_DBG(3, \"*** Trace ***\");\n\n\tm = lookup_mode_pg(l, MODE_MEDIUM_CONFIGURATION, 0);\n\tif (!m) {\n\t\tMHVTL_DBG(3, \"Did not find MODE_MEDIUM_CONFIGURATION page\");\n\t} else {\n\t\tMHVTL_DBG(3, \"l: %p, m: %p, m->pcodePointer: %p\",\n\t\t\t\t  l, m, m->pcodePointer);\n\n\t\tsmp_dp = m->pcodePointer;\n\t\tif (!smp_dp)\n\t\t\treturn SAM_STAT_GOOD;\n\t\tsmp_dp[2] = 0x10;\n\t\tsmp_dp[4] = 0x01; /* Indicate label overwrite */\n\t}\n\n\treturn SAM_STAT_GOOD;\n}\n\n/* Remove newline from string and fill rest of 'len' with char 'c' */\nvoid rmnl(char *s, unsigned char c, int len) {\n\tint i;\n\tint found = 0;\n\n\tfor (i = 0; i < len; i++) {\n\t\tif (s[i] == '\\n')\n\t\t\tfound = 1;\n\t\tif (found)\n\t\t\ts[i] = c;\n\t}\n}\n\nvoid update_vpd_86(struct lu_phy_attr *lu, void *p) {\n\tstruct vpd *vpd_pg = lu->lu_vpd[PCODE_OFFSET(0x86)];\n\n\tstruct ssc_personality_template *spt;\n\n\tspt = p;\n\n\tMHVTL_DBG(1, \"SPT is : 0x%02x\", spt->drive_supports_LBP);\n\n\tvpd_pg->data[0] = (spt->drive_supports_LBP) ? 0x8 : 0;\n\n\tvpd_pg->data[1] = 0x01; /* SIMPSUP (Device supports simple queing) */\n}\n\nvoid update_vpd_b0(struct lu_phy_attr *lu, void *p) {\n\tstruct vpd *vpd_pg = lu->lu_vpd[PCODE_OFFSET(0xb0)];\n\tuint8_t\t   *worm;\n\n\tworm = (uint8_t *)p;\n\n\t*vpd_pg->data = (*worm) ? 1 : 0; /* Set WORM bit */\n}\n\nvoid update_vpd_b1(struct lu_phy_attr *lu, void *p) {\n\tstruct vpd *vpd_pg = lu->lu_vpd[PCODE_OFFSET(0xb1)];\n\n\tmemcpy(vpd_pg->data, p, vpd_pg->sz);\n}\n\nvoid update_vpd_b2(struct lu_phy_attr *lu, void *p) {\n\tstruct vpd *vpd_pg = lu->lu_vpd[PCODE_OFFSET(0xb2)];\n\n\tmemcpy(vpd_pg->data, p, vpd_pg->sz);\n}\n\n/* VPD 0xB5 */\nvoid update_vpd_lbp(struct lu_phy_attr *lu, void *p) {\n\tstruct vpd *vpd_pg = lu->lu_vpd[PCODE_OFFSET(0xb2)];\n\n\tmemcpy(vpd_pg->data, p, vpd_pg->sz);\n}\n\nvoid update_vpd_c0(struct lu_phy_attr *lu, void *p) {\n\tstruct vpd *vpd_pg = lu->lu_vpd[PCODE_OFFSET(0xc0)];\n\n\tmemcpy(&vpd_pg->data[20], p, strlen((const char *)p));\n}\n\nvoid update_vpd_c1(struct lu_phy_attr *lu, void *p) {\n\tstruct vpd *vpd_pg = lu->lu_vpd[PCODE_OFFSET(0xc1)];\n\n\tmemcpy(vpd_pg->data, p, vpd_pg->sz);\n}\n\nvoid cleanup_density_support(struct list_head *l) {\n\tstruct supported_density_list *dp, *ndp;\n\n\tlist_for_each_entry_safe(dp, ndp, l, siblings) {\n\t\tlist_del(&dp->siblings);\n\t\tfree(dp);\n\t}\n}\n\nint add_density_support(struct list_head *l, struct density_info *di, int rw) {\n\tstruct supported_density_list *supported;\n\n\tsupported = zalloc(sizeof(struct supported_density_list));\n\tif (!supported)\n\t\treturn -ENOMEM;\n\n\tsupported->density_info = di;\n\tsupported->rw\t\t\t= rw;\n\tlist_add_tail(&supported->siblings, l);\n\treturn 0;\n}\n\nvoid process_fifoname(struct lu_phy_attr *lu, char *s, int flag) {\n\tMHVTL_DBG(3, \"entry: %s, flag: %d, existing name: %s\",\n\t\t\t  s, flag, lu->fifoname);\n\tif (lu->fifo_flag) /* fifo set via '-f <fifo>' switch */\n\t\treturn;\n\tcheckstrlen(s, MALLOC_SZ - 1, 0);\n\tfree(lu->fifoname);\n\tlu->fifoname = (char *)zalloc(strlen(s) + 2);\n\tif (!lu->fifoname) {\n\t\tprintf(\"Unable to malloc fifo buffer\");\n\t\texit(-ENOMEM);\n\t}\n\tlu->fifo_flag = flag;\n\t/* Already checked for sane length */\n\tstrcpy(lu->fifoname, s);\n}\n\n/* Remove message queue */\nvoid cleanup_msg(void) {\n\tint\t\t\t\tmsqid;\n\tint\t\t\t\tretval;\n\tstruct msqid_ds ds;\n\n\tmsqid = init_queue();\n\tif (msqid < 0) {\n\t\tMHVTL_ERR(\"Failed to open msg queue: %s\", strerror(errno));\n\t\treturn;\n\t}\n\tretval = msgctl(msqid, IPC_RMID, &ds);\n\tif (retval < 0) {\n\t\tMHVTL_ERR(\"Failed to remove msg queue: %s\", strerror(errno));\n\t} else {\n\t\tMHVTL_DBG(2, \"Removed ipc resources\");\n\t}\n}\n\n#define QUERYSHM 0\n#define INCSHM\t 1\n#define DECSHM\t 2\n\nstatic int mhvtl_shared_mem(int flag) {\n\tint\t\t\t\tmhvtl_shm;\n\tint\t\t\t\tretval = -1;\n\tint\t\t\t   *base;\n\tkey_t\t\t\tkey;\n\tstruct shmid_ds buf;\n\n\tkey = 0x4d61726b;\n\n\tmhvtl_shm = shmget(key, 16, IPC_CREAT | 0666);\n\tif (mhvtl_shm < 0) {\n\t\tprintf(\"Attempt to get Shared memory failed\\n\");\n\t\tMHVTL_ERR(\"Attempt to get shared memory failed\");\n\t\treturn -ENOMEM;\n\t}\n\n\tbase = (int *)shmat(mhvtl_shm, NULL, 0);\n\tif (base == (void *)-1) {\n\t\tMHVTL_ERR(\"Failed to attach to shm: %s\", strerror(errno));\n\t\treturn -1;\n\t}\n\n\tMHVTL_DBG(3, \"[%d] shm count is: %d\", (int)getpid(), *base);\n\n\tswitch (flag) {\n\tcase QUERYSHM:\n\t\tbreak;\n\tcase INCSHM:\n\t\t(*base)++;\n\t\tbreak;\n\tcase DECSHM:\n\t\tif (*base)\n\t\t\t(*base)--;\n\n\t\t/* No more consumers - mark as remove */\n\t\tif (*base == 0) {\n\t\t\tshmctl(mhvtl_shm, IPC_STAT, &buf);\n\t\t\tshmctl(mhvtl_shm, IPC_RMID, &buf);\n\t\t\tMHVTL_DBG(3, \"pid of creator: %d,\"\n\t\t\t\t\t\t \" pid of last shmat(): %d, \"\n\t\t\t\t\t\t \" Number of current attach: %d\",\n\t\t\t\t\t  buf.shm_cpid,\n\t\t\t\t\t  buf.shm_lpid,\n\t\t\t\t\t  (int)buf.shm_nattch);\n\t\t\t/* Should be no more users of the message Q either */\n\t\t\tcleanup_msg();\n\t\t}\n\t\tbreak;\n\t}\n\tMHVTL_DBG(3, \"[%d] shm count now: %d\", (int)getpid(), *base);\n\n\tretval = *base;\n\n\tshmdt(base);\n\n\treturn retval;\n}\n\nstatic int mhvtl_fifo_count(int direction) {\n\tsem_t *mhvtl_sem;\n\tint\t   sval;\n\tint\t   i;\n\tchar   errmsg[] = \"mhvtl_sem\";\n\tint\t   retval\t= -1;\n\n\tmhvtl_sem = sem_open(\"/mhVTL\", O_CREAT, 0664, 1);\n\tif (SEM_FAILED == mhvtl_sem) {\n\t\tMHVTL_ERR(\"%s : %s\", errmsg, strerror(errno));\n\t\treturn retval;\n\t}\n\n\tsem_getvalue(mhvtl_sem, &sval);\n\tfor (i = 0; i < 10; i++) {\n\t\tif (sem_trywait(mhvtl_sem)) {\n\t\t\tMHVTL_LOG(\"Waiting for semaphore: %p\", mhvtl_sem);\n\t\t\tsleep(1);\n\t\t\tif (i > 8) {\n\t\t\t\t/* Give up.. Clear the semaphore & do it */\n\t\t\t\tMHVTL_ERR(\"waiting for semaphore: %p\",\n\t\t\t\t\t\t  mhvtl_sem);\n\t\t\t\tsem_post(mhvtl_sem);\n\t\t\t}\n\t\t} else {\n\t\t\tretval = mhvtl_shared_mem(direction);\n\t\t\tsem_post(mhvtl_sem);\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tsem_close(mhvtl_sem);\n\treturn retval;\n}\n\nint dec_fifo_count(void) {\n\treturn mhvtl_fifo_count(DECSHM);\n}\n\nint inc_fifo_count(void) {\n\treturn mhvtl_fifo_count(INCSHM);\n}\n\nint get_fifo_count(void) {\n\treturn mhvtl_fifo_count(QUERYSHM);\n}\n\n/*\n * find the mhvtl home directory and the library ID supplied in the device.conf\n * file from our config directory. Use the default config directory unless one\n * is passed in\n */\nvoid find_media_home_directory(char *config_directory, long lib_id) {\n\tchar  device_conf[CONF_FILE_SZ];\n\tFILE *conf;\n\tchar *b; /* Read from file into this buffer */\n\tchar *s; /* Somewhere for sscanf to store results */\n\tlong  i;\n\tint\t  found;\n\n\tfound\t\t\t  = 0;\n\thome_directory[0] = '\\0';\n\n\tif (config_directory) {\n\t\tsnprintf(device_conf, CONF_FILE_SZ, \"%s/device.conf\", config_directory);\n\t} else if (get_config(device_conf, DEVICE_CONF, my_id) < 0) {\n\t\texit(1);\n\t}\n\n\tconf = fopen(device_conf, \"r\");\n\tif (!conf) {\n\t\tMHVTL_ERR(\"Can not open config file %s : %s\", device_conf,\n\t\t\t\t  strerror(errno));\n\t\tperror(\"Can not open config file\");\n\t\texit(1);\n\t}\n\ts = zalloc(MALLOC_SZ);\n\tif (!s) {\n\t\tperror(\"Could not allocate memory\");\n\t\texit(1);\n\t}\n\tb = zalloc(MALLOC_SZ);\n\tif (!b) {\n\t\tperror(\"Could not allocate memory\");\n\t\texit(1);\n\t}\n\twhile (readline(b, MALLOC_SZ, conf) != NULL) {\n\t\tif (b[0] == '#') /* Ignore comments */\n\t\t\tcontinue;\n\t\tif (strlen(b) < 3) /* Reset drive number of blank line */\n\t\t\ti = 0xff;\n\t\tif (sscanf(b, \"Library: %ld \", &i)) {\n\t\t\tMHVTL_DBG(2, \"Found Library %ld, looking for %ld\",\n\t\t\t\t\t  i, lib_id);\n\t\t\tif (i == lib_id)\n\t\t\t\tfound = 1;\n\t\t}\n\t\tif (found == 1) {\n\t\t\tint a;\n\t\t\ta = sscanf(b, \" Home directory: %s\", s);\n\t\t\tif (a > 0) {\n\t\t\t\tstrncpy(home_directory, s, HOME_DIR_PATH_SZ);\n\t\t\t\tMHVTL_DBG(2, \"Found home directory  : %s\",\n\t\t\t\t\t\t  home_directory);\n\t\t\t\tgoto finished; /* Found what we came for */\n\t\t\t}\n\t\t}\n\t}\n\n\t/* Not found, then append the library id to default path */\n\tsnprintf(home_directory, HOME_DIR_PATH_SZ, \"%s/%ld\",\n\t\t\t MHVTL_HOME_PATH, lib_id);\n\tMHVTL_DBG(1, \"Append library id %ld to default path %s: %s\",\n\t\t\t  lib_id, MHVTL_HOME_PATH,\n\t\t\t  home_directory);\n\nfinished:\n\tfree(s);\n\tfree(b);\n\tfclose(conf);\n}\n\nunsigned int set_media_params(struct MAM *mamp, char *density) {\n\t/* Invent some defaults */\n\tmamp->MediaType = Media_undefined;\n\tput_unaligned_be32(2048, &mamp->media_info.bits_per_mm);\n\tput_unaligned_be16(1, &mamp->media_info.tracks);\n\tput_unaligned_be32(127, &mamp->MediumWidth);\n\tput_unaligned_be32(1024, &mamp->MediumLength);\n\tmemcpy(&mamp->media_info.description, \"mhvtl\", 5);\n\tmamp->max_partitions = 1;\n\tmamp->num_partitions = 1;\n\n\tif (!(strncmp(density, \"LTO1\", 4))) {\n\t\tmamp->MediumDensityCode = medium_density_code_lto1;\n\t\tmamp->MediaType\t\t\t= Media_LTO1;\n\t\tput_unaligned_be32(384, &mamp->MediumLength);\n\t\tput_unaligned_be32(127, &mamp->MediumWidth);\n\t\tmemcpy(&mamp->media_info.description, \"Ultrium 1/8T\", 12);\n\t\tmemcpy(&mamp->media_info.density_name, \"U-18  \", 6);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"LTO-CVE\", 7);\n\t\tput_unaligned_be32(4880, &mamp->media_info.bits_per_mm);\n\t} else if (!(strncmp(density, \"LTO2\", 4))) {\n\t\tmamp->MediumDensityCode = medium_density_code_lto2;\n\t\tmamp->MediaType\t\t\t= Media_LTO2;\n\t\tput_unaligned_be32(512, &mamp->MediumLength);\n\t\tput_unaligned_be32(127, &mamp->MediumWidth);\n\t\tmemcpy(&mamp->media_info.description, \"Ultrium 2/8T\", 12);\n\t\tmemcpy(&mamp->media_info.density_name, \"U-28  \", 6);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"LTO-CVE\", 7);\n\t\tput_unaligned_be32(7398, &mamp->media_info.bits_per_mm);\n\t} else if (!(strncmp(density, \"LTO3\", 4))) {\n\t\tmamp->MediumDensityCode = medium_density_code_lto3;\n\t\tmamp->MediaType\t\t\t= Media_LTO3;\n\t\tput_unaligned_be32(704, &mamp->MediumLength);\n\t\tput_unaligned_be32(127, &mamp->MediumWidth);\n\t\tmemcpy(&mamp->media_info.description, \"Ultrium 3/16T\", 13);\n\t\tmemcpy(&mamp->media_info.density_name, \"U-316 \", 6);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"LTO-CVE\", 7);\n\t\tput_unaligned_be32(9638, &mamp->media_info.bits_per_mm);\n\t} else if (!(strncmp(density, \"LTO4\", 4))) {\n\t\tmamp->MediumDensityCode = medium_density_code_lto4;\n\t\tmamp->MediaType\t\t\t= Media_LTO4;\n\t\tput_unaligned_be32(896, &mamp->MediumLength);\n\t\tput_unaligned_be32(127, &mamp->MediumWidth);\n\t\tmemcpy(&mamp->media_info.description, \"Ultrium 4/16T\", 13);\n\t\tmemcpy(&mamp->media_info.density_name, \"U-416  \", 6);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"LTO-CVE\", 7);\n\t\tput_unaligned_be32(12725, &mamp->media_info.bits_per_mm);\n\t} else if (!(strncmp(density, \"LTO5\", 4))) {\n\t\tmamp->MediumDensityCode = medium_density_code_lto5;\n\t\tmamp->MediaType\t\t\t= Media_LTO5;\n\t\tput_unaligned_be32(1280, &mamp->MediumLength);\n\t\tput_unaligned_be32(127, &mamp->MediumWidth);\n\t\tmemcpy(&mamp->media_info.description, \"Ultrium 5/16T\", 13);\n\t\tmemcpy(&mamp->media_info.density_name, \"U-516  \", 6);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"LTO-CVE\", 7);\n\t\tput_unaligned_be32(15142, &mamp->media_info.bits_per_mm);\n\t\tmamp->max_partitions = 2;\n\t\tmamp->num_partitions = 2;\n\t} else if (!(strncmp(density, \"LTO6\", 4))) {\n\t\tmamp->MediumDensityCode = medium_density_code_lto6;\n\t\tmamp->MediaType\t\t\t= Media_LTO6;\n\t\tput_unaligned_be32(2176, &mamp->MediumLength);\n\t\tput_unaligned_be32(127, &mamp->MediumWidth);\n\t\tmemcpy(&mamp->media_info.description, \"Ultrium 6/16T\", 13);\n\t\tmemcpy(&mamp->media_info.density_name, \"U-616  \", 6);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"LTO-CVE\", 7);\n\t\tput_unaligned_be32(18441, &mamp->media_info.bits_per_mm);\n\t\tmamp->max_partitions = 2;\n\t\tmamp->num_partitions = 2;\n\t} else if (!(strncmp(density, \"LTO7\", 4))) {\n\t\tmamp->MediumDensityCode = medium_density_code_lto7;\n\t\tmamp->MediaType\t\t\t= Media_LTO7;\n\t\tput_unaligned_be32(960, &mamp->MediumLength);\n\t\tput_unaligned_be32(127, &mamp->MediumWidth);\n\t\tmemcpy(&mamp->media_info.description, \"Ultrium 7/32T\", 13);\n\t\tmemcpy(&mamp->media_info.density_name, \"U-732  \", 6);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"LTO-CVE\", 7);\n\t\tput_unaligned_be32(19107, &mamp->media_info.bits_per_mm);\n\t\tmamp->max_partitions = 2;\n\t\tmamp->num_partitions = 2;\n\t} else if (!(strncmp(density, \"LTO8\", 4))) {\n\t\tmamp->MediumDensityCode = medium_density_code_lto8;\n\t\tmamp->MediaType\t\t\t= Media_LTO8;\n\t\tput_unaligned_be32(960, &mamp->MediumLength);\n\t\tput_unaligned_be32(127, &mamp->MediumWidth);\n\t\tmemcpy(&mamp->media_info.description, \"Ultrium 8/32T\", 13);\n\t\tmemcpy(&mamp->media_info.density_name, \"U-832  \", 6);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"LTO-CVE\", 7);\n\t\tput_unaligned_be32(19107, &mamp->media_info.bits_per_mm);\n\t\tmamp->max_partitions = 2;\n\t\tmamp->num_partitions = 2;\n\t} else if (!(strncmp(density, \"LTO9\", 4))) {\n\t\tmamp->MediumDensityCode = medium_density_code_lto9;\n\t\tmamp->MediaType\t\t\t= Media_LTO9;\n\t\tput_unaligned_be32(960, &mamp->MediumLength);\n\t\tput_unaligned_be32(127, &mamp->MediumWidth);\n\t\tmemcpy(&mamp->media_info.description, \"Ultrium 9/32T\", 13);\n\t\tmemcpy(&mamp->media_info.density_name, \"U-932  \", 6);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"LTO-CVE\", 7);\n\t\tput_unaligned_be32(19107, &mamp->media_info.bits_per_mm);\n\t\tmamp->max_partitions = 2;\n\t\tmamp->num_partitions = 2;\n\t} else if (!(strncmp(density, \"AIT1\", 4))) {\n\t\t/* Vaules for AIT taken from \"Product Manual SDX-900V v1.0\" */\n\t\tmamp->MediumDensityCode = medium_density_code_ait1;\n\t\tmamp->MediaType\t\t\t= Media_AIT1;\n\t\tput_unaligned_be32(384, &mamp->MediumLength);\n\t\tput_unaligned_be32(0x50, &mamp->MediumWidth);\n\t\tmemcpy(&mamp->media_info.description, \"AdvIntelligentTape1\", 20);\n\t\tmemcpy(&mamp->media_info.density_name, \"AIT-1 \", 6);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"SONY\", 4);\n\t\tput_unaligned_be32(0x11d7, &mamp->media_info.bits_per_mm);\n\t} else if (!(strncmp(density, \"AIT2\", 4))) {\n\t\tmamp->MediumDensityCode = medium_density_code_ait2;\n\t\tmamp->MediaType\t\t\t= Media_AIT2;\n\t\tput_unaligned_be32(384, &mamp->MediumLength);\n\t\tput_unaligned_be32(0x50, &mamp->MediumWidth);\n\t\tmemcpy(&mamp->media_info.description, \"AdvIntelligentTape2\", 20);\n\t\tmemcpy(&mamp->media_info.density_name, \"AIT-2  \", 6);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"SONY\", 4);\n\t\tput_unaligned_be32(0x17d6, &mamp->media_info.bits_per_mm);\n\t} else if (!(strncmp(density, \"AIT3\", 4))) {\n\t\tmamp->MediumDensityCode = medium_density_code_ait3;\n\t\tmamp->MediaType\t\t\t= Media_AIT3;\n\t\tput_unaligned_be32(384, &mamp->MediumLength);\n\t\tput_unaligned_be32(0x50, &mamp->MediumWidth);\n\t\tmemcpy(&mamp->media_info.description, \"AdvIntelligentTape3\", 20);\n\t\tmemcpy(&mamp->media_info.density_name, \"AIT-3  \", 6);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"SONY\", 4);\n\t\tput_unaligned_be32(0x17d6, &mamp->media_info.bits_per_mm);\n\t} else if (!(strncmp(density, \"AIT4\", 4))) {\n\t\tmamp->MediumDensityCode = medium_density_code_ait4;\n\t\tmamp->MediaType\t\t\t= Media_AIT4;\n\t\tput_unaligned_be32(384, &mamp->MediumLength);\n\t\tput_unaligned_be32(0x50, &mamp->MediumWidth);\n\t\tmemcpy(&mamp->media_info.description, \"AdvIntelligentTape4\", 20);\n\t\tmemcpy(&mamp->media_info.density_name, \"AIT-4  \", 6);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"SONY\", 4);\n\t\tput_unaligned_be32(0x17d6, &mamp->media_info.bits_per_mm);\n\t} else if (!(strncmp(density, \"DLT3\", 4))) {\n\t\tmamp->MediumDensityCode = medium_density_code_dlt3;\n\t\tmamp->MediaType\t\t\t= Media_DLT3;\n\t\tmemcpy(&mamp->media_info.description, \"DLTtape III\", 11);\n\t\tmemcpy(&mamp->media_info.density_name, \"DLT-III\", 7);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"QUANTUM\", 7);\n\t} else if (!(strncmp(density, \"DLT4\", 4))) {\n\t\tmamp->MediumDensityCode = medium_density_code_dlt4;\n\t\tmamp->MediaType\t\t\t= Media_DLT4;\n\t\tmemcpy(&mamp->media_info.description, \"DLTtape IV\", 10);\n\t\tmemcpy(&mamp->media_info.density_name, \"DLT-IV\", 6);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"QUANTUM\", 7);\n\t} else if (!(strncmp(density, \"SDLT1\", 5))) {\n\t\tmamp->MediumDensityCode = 0x48;\n\t\tmamp->MediaType\t\t\t= Media_SDLT;\n\t\tmemcpy(&mamp->media_info.description, \"SDLT I media\", 12);\n\t\tmemcpy(&mamp->media_info.density_name, \"SDLT-1\", 6);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"QUANTUM\", 7);\n\t\tput_unaligned_be32(133000, &mamp->media_info.bits_per_mm);\n\t} else if (!(strncmp(density, \"SDLT220\", 7))) {\n\t\tmamp->MediumDensityCode = medium_density_code_220;\n\t\tmamp->MediaType\t\t\t= Media_SDLT220;\n\t\tmemcpy(&mamp->media_info.description, \"SDLT I media\", 12);\n\t\tmemcpy(&mamp->media_info.density_name, \"SDLT220\", 7);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"QUANTUM\", 7);\n\t\tput_unaligned_be32(133000, &mamp->media_info.bits_per_mm);\n\t} else if (!(strncmp(density, \"SDLT320\", 7))) {\n\t\tmamp->MediumDensityCode = medium_density_code_320;\n\t\tmamp->MediaType\t\t\t= Media_SDLT320;\n\t\tmemcpy(&mamp->media_info.description, \"SDLT I media\", 12);\n\t\tmemcpy(&mamp->media_info.density_name, \"SDLT320\", 7);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"QUANTUM\", 7);\n\t\tput_unaligned_be32(190000, &mamp->media_info.bits_per_mm);\n\t} else if (!(strncmp(density, \"SDLT600\", 7))) {\n\t\tmamp->MediumDensityCode = medium_density_code_600;\n\t\tmamp->MediaType\t\t\t= Media_SDLT600;\n\t\tmemcpy(&mamp->media_info.description, \"SDLT II media\", 13);\n\t\tmemcpy(&mamp->media_info.density_name, \"SDLT600\", 7);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"QUANTUM\", 7);\n\t\tput_unaligned_be32(233000, &mamp->media_info.bits_per_mm);\n\t} else if (!(strncmp(density, \"9840A\", 5))) {\n\t\tmamp->MediumDensityCode = medium_density_code_9840A;\n\t\tmamp->MediaType\t\t\t= Media_9840A;\n\t\tmemcpy(&mamp->media_info.description, \"Raven 20 GB\", 11);\n\t\tmemcpy(&mamp->media_info.density_name, \"R-20\", 4);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"STK\", 3);\n\t\tput_unaligned_be32(0, &mamp->media_info.bits_per_mm);\n\t\tput_unaligned_be16(288, &mamp->media_info.tracks);\n\t\tput_unaligned_be32(127, &mamp->MediumWidth);\n\t\tput_unaligned_be32(1024, &mamp->MediumLength);\n\t} else if (!(strncmp(density, \"9840B\", 5))) {\n\t\tmamp->MediumDensityCode = medium_density_code_9840B;\n\t\tmamp->MediaType\t\t\t= Media_9840B;\n\t\tmemcpy(&mamp->media_info.description, \"Raven 20 GB\", 11);\n\t\tmemcpy(&mamp->media_info.density_name, \"R-20\", 4);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"STK\", 3);\n\t\tput_unaligned_be32(0, &mamp->media_info.bits_per_mm);\n\t\tput_unaligned_be16(288, &mamp->media_info.tracks);\n\t\tput_unaligned_be32(127, &mamp->MediumWidth);\n\t\tput_unaligned_be32(1024, &mamp->MediumLength);\n\t} else if (!(strncmp(density, \"9840C\", 5))) {\n\t\tmamp->MediumDensityCode = medium_density_code_9840C;\n\t\tmamp->MediaType\t\t\t= Media_9840C;\n\t\tmemcpy(&mamp->media_info.description, \"Raven 40 GB\", 11);\n\t\tmemcpy(&mamp->media_info.density_name, \"R-40\", 4);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"STK\", 3);\n\t\tput_unaligned_be32(0, &mamp->media_info.bits_per_mm);\n\t\tput_unaligned_be16(288, &mamp->media_info.tracks);\n\t\tput_unaligned_be32(127, &mamp->MediumWidth);\n\t\tput_unaligned_be32(1024, &mamp->MediumLength);\n\t} else if (!(strncmp(density, \"9840D\", 5))) {\n\t\tmamp->MediumDensityCode = medium_density_code_9840D;\n\t\tmamp->MediaType\t\t\t= Media_9840D;\n\t\tmemcpy(&mamp->media_info.description, \"Raven 75 GB\", 11);\n\t\tmemcpy(&mamp->media_info.density_name, \"R-75\", 4);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"STK\", 3);\n\t\tput_unaligned_be32(0, &mamp->media_info.bits_per_mm);\n\t\tput_unaligned_be16(576, &mamp->media_info.tracks);\n\t\tput_unaligned_be32(127, &mamp->MediumWidth);\n\t\tput_unaligned_be32(1024, &mamp->MediumLength);\n\t} else if (!(strncmp(density, \"9940A\", 5))) {\n\t\tmamp->MediumDensityCode = medium_density_code_9940A;\n\t\tmamp->MediaType\t\t\t= Media_9940A;\n\t\tmemcpy(&mamp->media_info.description, \"PeakCapacity 60 GB\", 18);\n\t\tmemcpy(&mamp->media_info.density_name, \"P-60\", 4);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"STK\", 3);\n\t\tput_unaligned_be32(0, &mamp->media_info.bits_per_mm);\n\t\tput_unaligned_be16(288, &mamp->media_info.tracks);\n\t\tput_unaligned_be32(127, &mamp->MediumWidth);\n\t\tput_unaligned_be32(1024, &mamp->MediumLength);\n\t} else if (!(strncmp(density, \"9940B\", 5))) {\n\t\tmamp->MediumDensityCode = medium_density_code_9940B;\n\t\tmamp->MediaType\t\t\t= Media_9940B;\n\t\tmemcpy(&mamp->media_info.description,\n\t\t\t   \"PeakCapacity 200 GB\", 19);\n\t\tmemcpy(&mamp->media_info.density_name, \"P-200\", 5);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"STK\", 3);\n\t\tput_unaligned_be32(0, &mamp->media_info.bits_per_mm);\n\t\tput_unaligned_be16(576, &mamp->media_info.tracks);\n\t\tput_unaligned_be32(127, &mamp->MediumWidth);\n\t\tput_unaligned_be32(1024, &mamp->MediumLength);\n\t} else if (!(strncmp(density, \"T10KA\", 5))) {\n\t\tmamp->MediumDensityCode = medium_density_code_10kA;\n\t\tmamp->MediaType\t\t\t= Media_T10KA;\n\t\tmemcpy(&mamp->media_info.description, \"STK T10KA media\", 15);\n\t\tmemcpy(&mamp->media_info.density_name, \"T10000A\", 7);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"STK\", 3);\n\t\tput_unaligned_be32(233000, &mamp->media_info.bits_per_mm);\n\t} else if (!(strncmp(density, \"T10KB\", 5))) {\n\t\tmamp->MediumDensityCode = medium_density_code_10kB;\n\t\tmamp->MediaType\t\t\t= Media_T10KB;\n\t\tmemcpy(&mamp->media_info.description, \"STK T10KB media\", 15);\n\t\tmemcpy(&mamp->media_info.density_name, \"T10000B\", 7);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"STK\", 3);\n\t\tput_unaligned_be32(233000, &mamp->media_info.bits_per_mm);\n\t} else if (!(strncmp(density, \"T10KC\", 5))) {\n\t\tmamp->MediumDensityCode = medium_density_code_10kC;\n\t\tmamp->MediaType\t\t\t= Media_T10KC;\n\t\tmemcpy(&mamp->media_info.description, \"STK T10KC media\", 15);\n\t\tmemcpy(&mamp->media_info.density_name, \"T10000C\", 7);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"STK\", 3);\n\t\tput_unaligned_be32(233000, &mamp->media_info.bits_per_mm);\n\t} else if (!(strncmp(density, \"DDS1\", 4))) {\n\t\tmamp->MediumDensityCode = medium_density_code_DDS1;\n\t\tmamp->MediaType\t\t\t= Media_DDS1;\n\t\tmemcpy(&mamp->media_info.description, \"4MM DDS-1 media\", 15);\n\t\tmemcpy(&mamp->media_info.density_name, \"DDS1\", 4);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"HP\", 2);\n\t\tput_unaligned_be32(233000, &mamp->media_info.bits_per_mm);\n\t} else if (!(strncmp(density, \"DDS2\", 4))) {\n\t\tmamp->MediumDensityCode = medium_density_code_DDS2;\n\t\tmamp->MediaType\t\t\t= Media_DDS2;\n\t\tmemcpy(&mamp->media_info.description, \"4MM DDS-2 media\", 15);\n\t\tmemcpy(&mamp->media_info.density_name, \"DDS2\", 4);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"HP\", 2);\n\t\tput_unaligned_be32(233000, &mamp->media_info.bits_per_mm);\n\t} else if (!(strncmp(density, \"DDS3\", 4))) {\n\t\tmamp->MediumDensityCode = medium_density_code_DDS3;\n\t\tmamp->MediaType\t\t\t= Media_DDS3;\n\t\tmemcpy(&mamp->media_info.description, \"4MM DDS-3 media\", 15);\n\t\tmemcpy(&mamp->media_info.density_name, \"DDS3\", 4);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"HP\", 2);\n\t\tput_unaligned_be32(233000, &mamp->media_info.bits_per_mm);\n\t} else if (!(strncmp(density, \"DDS4\", 4))) {\n\t\tmamp->MediumDensityCode = medium_density_code_DDS4;\n\t\tmamp->MediaType\t\t\t= Media_DDS4;\n\t\tmemcpy(&mamp->media_info.description, \"4MM DDS-4 media\", 15);\n\t\tmemcpy(&mamp->media_info.density_name, \"DDS4\", 4);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"HP\", 2);\n\t\tput_unaligned_be32(233000, &mamp->media_info.bits_per_mm);\n\t} else if (!(strncmp(density, \"J1A\", 3))) {\n\t\tmamp->MediumDensityCode = medium_density_code_j1a;\n\t\tmamp->MediaType\t\t\t= Media_3592_JA;\n\t\tmemcpy(&mamp->media_info.description, \"3592 J1A media\", 14);\n\t\tmemcpy(&mamp->media_info.density_name, \"3592J1A\", 7);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"IBM\", 3);\n\t\tput_unaligned_be32(233000, &mamp->media_info.bits_per_mm);\n\t} else if (!(strncmp(density, \"E05\", 3))) {\n\t\tmamp->MediumDensityCode = medium_density_code_e05;\n\t\tmamp->MediaType\t\t\t= Media_3592_JB;\n\t\tmemcpy(&mamp->media_info.description, \"3592 E05 media\", 14);\n\t\tmemcpy(&mamp->media_info.density_name, \"3592E05\", 7);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"IBM\", 3);\n\t\tput_unaligned_be32(233000, &mamp->media_info.bits_per_mm);\n\t} else if (!(strncmp(density, \"E06\", 3))) {\n\t\tmamp->MediumDensityCode = medium_density_code_e06;\n\t\tmamp->MediaType\t\t\t= Media_3592_JX;\n\t\tmemcpy(&mamp->media_info.description, \"3592 E06 media\", 14);\n\t\tmemcpy(&mamp->media_info.density_name, \"3592E06\", 7);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"IBM\", 3);\n\t} else if (!(strncmp(density, \"E07\", 3))) {\n\t\tmamp->MediumDensityCode = medium_density_code_e07;\n\t\tmamp->MediaType\t\t\t= Media_3592_JK;\n\t\tmemcpy(&mamp->media_info.description, \"3592 E07 media\", 14);\n\t\tmemcpy(&mamp->media_info.density_name, \"3592E07\", 7);\n\t\tmemcpy(&mamp->AssigningOrganization_1, \"IBM\", 3);\n\t} else\n\t\tprintf(\"'%s' is an invalid density\\n\", density);\n\n\tif (mamp->MediaType == Media_undefined) {\n\t\tprintf(\"Warning: mamp->MediaType is still undefined\\n\");\n\t\treturn 1;\n\t}\n\tmamp->FormattedDensityCode = mamp->MediumDensityCode;\n\treturn 0;\n}\n\nvoid ymd(int *year, int *month, int *day, int *hh, int *min, int *sec) {\n\tsscanf(__TIME__, \"%d:%d:%d\", hh, min, sec);\n\n\tif (sscanf(__DATE__, \"Jan %d %d\", day, year) == 2)\n\t\t*month = 1;\n\tif (sscanf(__DATE__, \"Feb %d %d\", day, year) == 2)\n\t\t*month = 2;\n\tif (sscanf(__DATE__, \"Mar %d %d\", day, year) == 2)\n\t\t*month = 3;\n\tif (sscanf(__DATE__, \"Apr %d %d\", day, year) == 2)\n\t\t*month = 4;\n\tif (sscanf(__DATE__, \"May %d %d\", day, year) == 2)\n\t\t*month = 5;\n\tif (sscanf(__DATE__, \"Jun %d %d\", day, year) == 2)\n\t\t*month = 6;\n\tif (sscanf(__DATE__, \"Jul %d %d\", day, year) == 2)\n\t\t*month = 7;\n\tif (sscanf(__DATE__, \"Aug %d %d\", day, year) == 2)\n\t\t*month = 8;\n\tif (sscanf(__DATE__, \"Sep %d %d\", day, year) == 2)\n\t\t*month = 9;\n\tif (sscanf(__DATE__, \"Oct %d %d\", day, year) == 2)\n\t\t*month = 10;\n\tif (sscanf(__DATE__, \"Nov %d %d\", day, year) == 2)\n\t\t*month = 11;\n\tif (sscanf(__DATE__, \"Dec %d %d\", day, year) == 2)\n\t\t*month = 12;\n}\n\nvoid opcode_6_params(struct scsi_cmd *cmd, int *num, int *sz) {\n\tuint8_t *cdb = cmd->scb;\n\n\tif (cdb[1] & FIXED_BLOCK) { /* If Fixed block writes */\n\t\t*num = get_unaligned_be24(&cdb[2]);\n\t\t*sz\t = get_unaligned_be24(&modeBlockDescriptor[5]);\n\t} else { /* else - Variable Block writes */\n\t\t*num = 1;\n\t\t*sz\t = get_unaligned_be24(&cdb[2]);\n\t}\n}\n\nchar *slot_type_str(int type) {\n\treturn slot_type_string[type];\n}\n\nvoid init_smc_log_pages(struct lu_phy_attr *lu) {\n\tadd_log_temperature_page(lu);\n\tadd_log_tape_alert(lu);\n}\n\nvoid init_smc_mode_pages(struct lu_phy_attr *lu) {\n\tadd_mode_disconnect_reconnect(lu);\n\tadd_mode_control_extension(lu);\n\tadd_mode_power_condition(lu);\n\tadd_mode_information_exception(lu);\n\tadd_mode_element_address_assignment(lu);\n\tadd_mode_transport_geometry(lu);\n\tadd_mode_device_capabilities(lu);\n}\n\nvoid bubbleSort(int *array, int size) {\n\tint swapped;\n\tint i;\n\tint j;\n\n\tfor (i = 1; i < size; i++) {\n\t\tswapped = 0;\n\t\tfor (j = 0; j < size - i; j++) {\n\t\t\tif (array[j] > array[j + 1]) {\n\t\t\t\tint temp\t = array[j];\n\t\t\t\tarray[j]\t = array[j + 1];\n\t\t\t\tarray[j + 1] = temp;\n\t\t\t\tswapped\t\t = 1;\n\t\t\t}\n\t\t}\n\t\tif (!swapped)\n\t\t\tbreak; /* if it is sorted then stop */\n\t}\n}\n\nvoid sort_library_slot_type(struct lu_phy_attr *lu, struct smc_type_slot *type) {\n\tint\t\t\t\t i;\n\tstruct smc_priv *smc_p = lu->lu_private;\n\tint\t\t\t\t arr[4];\n\n\tarr[0] = smc_p->pm->start_drive;\n\tarr[1] = smc_p->pm->start_picker;\n\tarr[2] = smc_p->pm->start_map;\n\tarr[3] = smc_p->pm->start_storage;\n\n\tbubbleSort(arr, 4);\n\n\tfor (i = 0; i < 4; i++) {\n\t\tif (smc_p->pm->start_drive == arr[i]) {\n\t\t\ttype[i].type  = DATA_TRANSFER;\n\t\t\ttype[i].start = smc_p->pm->start_drive;\n\t\t}\n\t\tif (smc_p->pm->start_picker == arr[i]) {\n\t\t\ttype[i].type  = MEDIUM_TRANSPORT;\n\t\t\ttype[i].start = smc_p->pm->start_picker;\n\t\t}\n\t\tif (smc_p->pm->start_map == arr[i]) {\n\t\t\ttype[i].type  = MAP_ELEMENT;\n\t\t\ttype[i].start = smc_p->pm->start_map;\n\t\t}\n\t\tif (smc_p->pm->start_storage == arr[i]) {\n\t\t\ttype[i].type  = STORAGE_ELEMENT;\n\t\t\ttype[i].start = smc_p->pm->start_storage;\n\t\t}\n\t}\n}\n\n/* Set VPD data with device serial number */\nvoid update_vpd_80(struct lu_phy_attr *lu, void *p) {\n\tstruct vpd *vpd_pg = lu->lu_vpd[PCODE_OFFSET(0x80)];\n\n\tassert(vpd_pg); /* space should have been pre-allocated */\n\n\tmemcpy(vpd_pg->data, p, strlen((const char *)p));\n}\n\nvoid update_vpd_83(struct lu_phy_attr *lu, void *p) {\n\tstruct vpd *vpd_pg = lu->lu_vpd[PCODE_OFFSET(0x83)];\n\tuint8_t\t   *d;\n\tchar\t   *ptr;\n\tint\t\t\tnum;\n\tint\t\t\tlen, j;\n\n\tassert(vpd_pg); /* space should have been pre-allocated */\n\n\td = vpd_pg->data;\n\n\td[0] = 2;\n\td[1] = 1;\n\td[2] = 0;\n\tnum\t = VENDOR_ID_LEN + PRODUCT_ID_LEN + 10;\n\td[3] = num;\n\n\tmemcpy(&d[4], &lu->vendor_id, VENDOR_ID_LEN);\n\tmemcpy(&d[12], &lu->product_id, PRODUCT_ID_LEN);\n\tmemcpy(&d[28], &lu->lu_serial_no, 10);\n\tlen = (int)strlen(lu->lu_serial_no);\n\tptr = &lu->lu_serial_no[len];\n\n\tnum += 4;\n\t/* NAA IEEE registered identifier (faked) */\n\td[num]\t\t= 0x1; /* Binary */\n\td[num + 1]\t= 0x3;\n\td[num + 2]\t= 0x0;\n\td[num + 3]\t= 0x8;\n\td[num + 4]\t= 0x51;\n\td[num + 5]\t= 0x23;\n\td[num + 6]\t= 0x45;\n\td[num + 7]\t= 0x60;\n\td[num + 8]\t= 0x3;\n\td[num + 9]\t= 0x3;\n\td[num + 10] = 0x3;\n\td[num + 11] = 0x3;\n\n\tif (lu->naa) { /* If defined in config file */\n\t\tsscanf((const char *)lu->naa,\n\t\t\t   \"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx\",\n\t\t\t   &d[num + 4],\n\t\t\t   &d[num + 5],\n\t\t\t   &d[num + 6],\n\t\t\t   &d[num + 7],\n\t\t\t   &d[num + 8],\n\t\t\t   &d[num + 9],\n\t\t\t   &d[num + 10],\n\t\t\t   &d[num + 11]);\n\t} else { /* Else munge the serial number */\n\t\tptr--;\n\t\tfor (j = 11; j > 3; ptr--, j--)\n\t\t\td[num + j] = *ptr;\n\t}\n\t/* Bug reported by Stefan Hauser.\n\t * [num +4] is always 0x5x\n\t */\n\td[num + 4] &= 0x0f;\n\td[num + 4] |= 0x50;\n}\n"
  },
  {
    "path": "vagrant/README.MD",
    "content": "# Testing with Vagrant\nTo test mhvtl on different distros, we use vagrant to spin up virtual boxes with different distros and install mhvtl from source on each box.\n\n## Prerequisites\n\nTo be able to test with Vagrant, you need:\n\n- Vagrant (tested with 2.2.4)\n- Virtualbox (tested with 5.2.26)\n\n## Test in different Operating Systems\n\nRun any of the following commands to test the code on different GNU/Linux distributions.\n\n```\nVagrant up ubuntu\n```\n\nor\n\n```\nVagrant up centos\n```\n\nor\n\n```\nVagrant up opensuse\n```\n**_NOTE:_** OpenSUSE in currently not working\n\nThe test will build and install mhvtl from source in the virtual machine. If the output looks something like this, then the installation went fine:\n```\n...\n    ubuntu: Show your tape libraries now!\n    ubuntu: [2:0:0:0]    disk    VBOX     HARDDISK         1.0   /dev/sda   /dev/sg0\n    ubuntu: [2:0:1:0]    disk    VBOX     HARDDISK         1.0   /dev/sdb   /dev/sg1\n    ubuntu: [3:0:0:0]    mediumx STK      L700             0106  -          /dev/sg7\n    ubuntu: [3:0:1:0]    tape    IBM      ULT3580-TD5      0106  -          /dev/sg6\n    ubuntu: [3:0:2:0]    tape    IBM      ULT3580-TD5      0106  -          /dev/sg11\n    ubuntu: [3:0:3:0]    tape    IBM      ULT3580-TD4      0106  -          /dev/sg4\n    ubuntu: [3:0:4:0]    tape    IBM      ULT3580-TD4      0106  -          /dev/sg8\n    ubuntu: [3:0:8:0]    mediumx STK      L80              0106  -          /dev/sg3\n    ubuntu: [3:0:9:0]    tape    STK      T10000B          0106  -          /dev/sg5\n    ubuntu: [3:0:10:0]   tape    STK      T10000B          0106  -          /dev/sg2\n    ubuntu: [3:0:11:0]   tape    STK      T10000B          0106  -          /dev/sg9\n    ubuntu: [3:0:12:0]   tape    STK      T10000B          0106  -          /dev/sg10\n    ubuntu: Found some virtual tapes, success!\n```\n\n### Cleanup\n\nWhen you are done, and you want to remove the box, run the following command:\n\n```\nVagrant destroy -f\n```\n"
  },
  {
    "path": "vagrant/Vagrantfile",
    "content": "# -*- mode: ruby -*-\n# vi: set ft=ruby :\n\ndef gui_enabled?\n  !ENV.fetch('GUI', '').empty?\nend\n\nVagrant.configure(\"2\") do |config|\n  config.vm.box_check_update = false\n\n  config.vm.define \"ubuntu\" do |instance|\n    instance.vm.box = \"generic/ubuntu1804\"\n    instance.vm.network \"private_network\", ip: \"192.168.56.20\"\n  end\n\n  config.vm.define \"rocky\" do |instance|\n    instance.vm.hostname = \"rocky\"\n    instance.vm.box = \"rockylinux/8\"\n    instance.vm.network \"private_network\", ip: \"192.168.56.21\"\n  end\n\n  config.vm.define \"centos8\" do |instance|\n    instance.vm.box = \"centos/8\"\n    instance.vm.network \"private_network\", ip: \"192.168.56.22\"\n  end\n\n  config.vm.define \"centos\" do |instance|\n    instance.vm.box = \"geerlingguy/centos7\"\n    instance.vm.network \"private_network\", ip: \"192.168.56.23\"\n  end\n\n  config.vm.define \"opensuse\" do |instance|\n    instance.vm.box = \"opensuse/Leap-15.2.x86_64\"\n    instance.vm.network \"private_network\", ip: \"192.168.56.24\"\n  end\n\n  config.vm.define \"alma\" do |instance|\n    instance.vm.hostname = \"alma\"\n    instance.vm.box = \"almalinux/9\"\n    instance.vm.network \"private_network\", ip: \"192.168.56.25\"\n    config.vbguest.auto_update = false\n  end\n\n  config.vm.provider \"virtualbox\" do |vb|\n    vb.memory = \"2048\"\n    vb.gui = gui_enabled?\n  end\n\n  config.vm.synced_folder \"../\", \"/vagrant_data\"\n\n  config.vm.provision \"shell\", inline: <<-SHELL\n    cd /vagrant_data/vagrant\n    sudo ./install.sh\n  SHELL\nend\n"
  },
  {
    "path": "vagrant/install.sh",
    "content": "#!/bin/bash\n\n# This script assumes it is located in a subdirectory from 'mhvtl' source root\n\necho \"Script Begin\"\n\nget_os_name()\n{\n\tif [ \"$(hostnamectl | grep -i ubuntu | wc -l)\" != \"0\" ]; then\n\t\tOS_NAME='ubuntu'\n\telif [ \"$(hostnamectl | grep -i sles | wc -l)\" != \"0\" ]; then\n\t\tOS_NAME='sles'\n\telif [ \"$(hostnamectl | grep -i opensuse | wc -l)\" != \"0\" ]; then\n\t\tOS_NAME='opensuse'\n\telif [ \"$(hostnamectl | grep -i centos | wc -l)\" != \"0\" ]; then\n\t\tOS_NAME='centos'\n\telif [ \"$(hostnamectl | grep -i rocky | wc -l)\" != \"0\" ]; then\n\t\tOS_NAME='rockylinux'\n\telif [ \"$(hostnamectl | grep -i alma | wc -l)\" != \"0\" ]; then\n\t\tOS_NAME='almalinux'\n\telse\n\t\techo 'This os is not supported!'\n\t\texit 1\n\tfi\n\techo \"OS_NAME is $OS_NAME\"\n}\n\n# check our script has been started with root auth\nif [ \"$(id -u)\" != \"0\" ]; then\n\techo \"This script must be run with root privileges. Please run again as either root or using sudo.\"\n\ttput sgr0\n\texit 1\nfi\n\nget_os_name\n\n# Lets break the script if there are any errors\nset -e\n\ninstall_ubuntu_pre_req()\n{\n\techo \"Ubuntu\"\n\tsudo apt-get update && sudo apt-get install ntp sysstat mtx mt-st sg3-utils zlib1g-dev git lsscsi build-essential gawk alien fakeroot linux-headers-$(uname -r) linux-modules-extra-$(uname -r) targetcli-fb -y\n}\n\ninstall_alma_pre_req()\n{\n\techo \"alma\"\n\n#\tsudo dnf install -y deltarpm\n\tsudo dnf update -y && sudo yum install -y git mc gcc gcc-c++ make kernel-devel-$(uname -r) zlib-devel sg3_utils lsscsi mt-st mtx targetcli vim chrony policycoreutils-python-utils policycoreutils\n\tsudo dnf upgrade -y\n\t# Rebuild VBox guest tools for any new kernel(s) installed\n#\t/sbin/rcvboxadd quicksetup all\n}\n\ninstall_rocky_pre_req()\n{\n\techo \"Rocky\"\n\n#\tsudo yum install -y deltarpm\n\tsudo yum update -y && sudo yum install -y git mc gcc gcc-c++ make kernel-devel-$(uname -r) zlib-devel sg3_utils lsscsi mt-st mtx targetcli vim policycoreutils-python-utils policycoreutils\n\tsudo yum upgrade -y\n\t# Rebuild VBox guest tools for any new kernel(s) installed\n\t/sbin/rcvboxadd quicksetup all\n}\n\ninstall_centos_pre_req()\n{\n\techo \"CentOS\"\n\n\tsed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*\n\tsed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*\n\n\tsudo yum install -y deltarpm\n\tsudo yum update -y && sudo yum install -y git mc ntp gcc gcc-c++ make kernel-devel-$(uname -r) zlib-devel sg3_utils lsscsi mt-st mtx perl-Config-General targetcli policycoreutils-python-utils policycoreutils\n\tsudo yum upgrade -y\n\t# Rebuild VBox guest tools for any new kernel(s) installed\n\t/sbin/rcvboxadd quicksetup all\n\n}\n\ninstall_sles_pre_req()\n{\n\techo \"SLES/OpenSuse\"\n\n\t# Workaround so that we install the same kernel-devel and kernel-syms version as the running kernel.\n\tUNAME_R=$(echo $(uname -r) | cut -d \"-\" -f-2)\n\tPATCHED_KERNEL_VERSION=$(sudo zypper se -s kernel-devel | grep ${UNAME_R} | cut -d \"|\" -f4 | tr -d \" \")\n\tsudo zypper install -y --oldpackage kernel-devel-${PATCHED_KERNEL_VERSION}\n\tsudo zypper install -y --oldpackage kernel-syms-${PATCHED_KERNEL_VERSION}\n\n\tsudo zypper install -y git mc ntp gcc gcc-c++ make zlib-devel sg3_utils lsscsi mtx perl-Config-General targetcli-fb python-semanage\n}\n\ninstall_pre_req()\n{\n\tif [ ${OS_NAME} == 'ubuntu' ]; then\n\t\tSYSTEMD_GENERATOR_DIR=\"/lib/systemd/system-generators\"\n\t\tinstall_ubuntu_pre_req\n\n\telif [ ${OS_NAME} == 'rockylinux' ]; then\n\t\tSYSTEMD_GENERATOR_DIR=\"/lib/systemd/system-generators\"\n\t\tinstall_rocky_pre_req\n\n\telif [ ${OS_NAME} == 'centos' ]; then\n\t\tSYSTEMD_GENERATOR_DIR=\"/lib/systemd/system-generators\"\n\t\tinstall_centos_pre_req\n\n\telif [ ${OS_NAME} == 'almalinux' ]; then\n\t\tSYSTEMD_GENERATOR_DIR=\"/usr/lib/systemd/system-generators\"\n\t\tinstall_alma_pre_req\n\n\telif [ ${OS_NAME} == 'sles' ] || [ ${OS_NAME} == 'opensuse' ]; then\n\t\tSYSTEMD_GENERATOR_DIR=\"/usr/lib/systemd/system-generators\"\n\t\tinstall_sles_pre_req\n\telse\n\t\techo \"Unable to handle install_pre_req for ${OS_NAME}\"\n\tfi\n}\n\ninstall_mhvtl_kernel_module()\n{\n\tmake distclean\n\tif [ ${OS_NAME} == 'ubuntu' ]; then\n\t\tmake\n\t\tsudo make install\n\telif [ ${OS_NAME} == 'centos' ] || [ ${OS_NAME} == 'rockylinux' ] || [ ${OS_NAME} == 'almalinux' ]; then\n\t\tfor a in `rpm -qa | awk '/kernel-devel/ {print $1}' | sed -e \"s/kernel-devel-//g\"`\n\t\tdo\n\t\t\techo \"Building mhVTL kernel module for ${a}\"\n\t\t\tmake V=${a}\n\t\t\tsudo make install V=${a}\n\t\t\tmake distclean\n\t\tdone\n\telif [ ${OS_NAME} == 'sles' ] || [ ${OS_NAME} == 'opensuse' ]; then\n\t\tmake\n\t\tsudo make install\n\tfi\n}\n\nsetup_time()\n{\n\techo \"Setting timezone to $1\"\n\ttimedatectl set-timezone $1\n\n\tif [ ${OS_NAME} == 'almalinux' ]; then\n\t\techo \"Alma linux - ntp (timesyncd) enabled by default\"\n\t\tsystemctl restart chronyd\n\t\treturn\n\tfi\n\tif [ ${OS_NAME} == 'rockylinux' ]; then\n\t\techo \"Rocky linux - ntp (timesyncd) enabled by default\"\n\t\tsystemctl restart chronyd\n\t\treturn\n\tfi\n\t# And enable ntp.\n\tif [ $(egrep \"^server|^pool\" /etc/ntp.conf | wc -l) -eq 0 ]; then\n\t\trcntpd addserver 0.au.pool.ntp.org\n\t\trcntpd addserver 1.au.pool.ntp.org\n\tfi\n\tif [ ${OS_NAME} == 'ubuntu' ]; then\n\t\tNTP=\"ntp\"\n\telif [ ${OS_NAME} == 'almalinux' ]; then\n\t\tNTP=\"chrony\"\n\telif [ ${OS_NAME} == 'rockylinux' ]; then\n\t\tNTP=\"chrony\"\n\telif [ ${OS_NAME} == 'centos' ]; then\n\t\tNTP=\"ntpd\"\n\telif [ ${OS_NAME} == 'sles' ] || [ ${OS_NAME} == 'opensuse' ]; then\n\t\tNTP=\"ntpd\"\n\telse\n\t\techo 'Could not determine os type'\n\t\treturn\n\tfi\n\tsystemctl enable ${NTP}\n\tsystemctl start ${NTP}\n\t# Rocky Linux - ntp (chrony) is already running, so restart\n\tsystemctl restart ${NTP}\n}\n\n# Install required packages\ninstall_pre_req\n\n# Use 'timedatectl list-timezones' to view valid timezone strings\nsetup_time \"Australia/Sydney\"\n\n# Change to mhVTL folder\ncd ../\n\n# Clean up any previous build\nmake distclean\n\n# Build kernel module for all versions which have the development package installed\ncd kernel/\ninstall_mhvtl_kernel_module\n\n# Now make user-space binaries and install\ncd ..\nmake\necho \"placing SYSTEMD_GENERATOR_DIR : ${SYSTEMD_GENERATOR_DIR}\"\nsudo make install SYSTEMD_GENERATOR_DIR=${SYSTEMD_GENERATOR_DIR}\n\n# Load it\nsudo depmod -a\nsudo systemctl daemon-reload\nsudo systemctl enable mhvtl.target\nsudo systemctl start mhvtl.target\n\nsleep 3\necho \"Show your tape libraries now!\"\nhba=`lsscsi -H | awk '/mhvtl/ {print $1}' | sed -e 's/\\[//g' -e 's/\\]//g'`\nlsscsi ${hba} -g\n\necho \"\"\nif [ \"$(lsscsi -g ${hba} | wc -l)\" -gt 2 ]; then\n\techo \"Found some virtual tapes, success!\"\nelse\n\techo \"Could not find the virtual tapes, the installation failed!\"\n\texit 1\nfi\n\nexit 0\n"
  },
  {
    "path": "webgui/index.php",
    "content": "<html>\n<head>\n</head>\n<body>\n\n<?php\n\necho \"<h1 align=\\\"center\\\">mhvtl configuration</h1>\";\n\necho \"<hr width=\\\"80%\\\">\";\n\necho \"<hr width=\\\"80%\\\">\";\n\n phpinfo();\n\n?>\n</body>\n</html>\n\n"
  }
]