mirror of
https://github.com/moibenko/mtx.git
synced 2025-12-23 05:55:13 +00:00
MTX original from Sourceforge
This commit is contained in:
373
mtx-1.3.12/CHANGES
Normal file
373
mtx-1.3.12/CHANGES
Normal file
@@ -0,0 +1,373 @@
|
||||
CHANGES, mtx 1.3.12
|
||||
- Incorporate debian packaging
|
||||
- Remove strip of binaries
|
||||
- Remove unsupported nsmhack from list of binaries built by default
|
||||
- Add support for building outside of source tree
|
||||
- Update copyrights
|
||||
- Fix typo in mtx.1 man page
|
||||
- Clear outstanding UNIT ATTENTION state at start
|
||||
|
||||
CHANGES, mtx 1.3.11
|
||||
- loaderinfo: Print RequestSense information if an operation fails.
|
||||
- loaderinfo: Print all information from the Device Configuration Page.
|
||||
- mtx: Fix problems with a lot of loaders determining the number of elements.
|
||||
- mtx: Implement Previous command.
|
||||
- mtx: Fix bugs in Last command.
|
||||
- scsieject: New tool that handles start/stop, load/unload.
|
||||
- tapeinfo: Fix inconsistencies in output.
|
||||
- Fix timeout handling on Linux.
|
||||
- Merge in fixes from the Debian and FreeBSD distributions.
|
||||
|
||||
CHANGES, mtx 1.3.10
|
||||
- Add support for Microsoft Windows.
|
||||
- Add support for Sony VGP-XL1B(2) Media Changer.
|
||||
Thanks to Will (nodenet at hotmail dot com)
|
||||
- Add build support for Microsoft Windows using MinGW native and Linux
|
||||
cross-compile.
|
||||
- Add build support for Microsoft Windows using Microsoft Visual Studio 2005.
|
||||
- Add support for building on x86_64.
|
||||
- Add more debugging information.
|
||||
- Eliminate compiler warnings.
|
||||
|
||||
CHANGES, mtx 1.3.9
|
||||
- Cleaned up scsi_linux.c a little to eliminate around 40 lines of code.
|
||||
- Change to using SG_IO ioctl rather than write-read interface. This
|
||||
should make us a little safer, as well as (on 2.6.x) letting us issue SCSI
|
||||
commands to regular block devices as well as to /dev/sgXX devices.
|
||||
WARNING: Can cause the system to *CRASH* if the SCSI device is in use, due
|
||||
to brokenness inside the Linux kernel! It's always preferable to use the
|
||||
/dev/sgXX device, which has specialness in its buffer handling that bypasses
|
||||
some of the brokenness elsewhere in the SCSI subsystem.
|
||||
- Check SG version before using SG_IO interface, so that if we're run on a
|
||||
Linux 2.2 system and we were compiled on Linux 2.4 or above,
|
||||
- If a tape is in the drive, make tapeinfo print out its partition info. Seems
|
||||
to work on my DAT drive, anyhow (shrug).
|
||||
- Minor cleanups in mtxl.c (other cleanups necessary in tapeinfo and etc.).
|
||||
|
||||
CHANGES, mtx 1.3.8
|
||||
- Forgot about 8 bytes for header
|
||||
- Handle pedantic loader whose firmware writer spends too much time
|
||||
parsing phrases in the SCSI spec and not enough time in the
|
||||
real world.
|
||||
|
||||
CHANGES, mtx 1.3.6
|
||||
- The You Gotta Be F'ing Kidding Release (see rant on mailing list)
|
||||
- Added AIX support with http://fz.eryx.net/aix/ GSC driver, courtesy
|
||||
of Steve Heck.
|
||||
- Make __WEIRD_CHAR_SUPPRESS the default to stop barcode garbling
|
||||
- Fix core dump on invalid inputs in mtx.c
|
||||
- Add retry with bigger ALLOCATION_LENGTH if
|
||||
BYTE_COUNT_OF_REPORT_AVAILABLE is > than our original estimate. (see rant
|
||||
on mailing list).
|
||||
- Shut up the low-level SCSI sg_read and sg_write routines, which were poofting
|
||||
all over the place on innocuous things like no EAAP.
|
||||
|
||||
CHANGES, mtx 1.3.5
|
||||
- The I-Need-A-Job Release (see http://badtux.org) :-}
|
||||
- Change Makefile so that it works w/systems whose 'install' program
|
||||
accepts only one argument. That's it.
|
||||
- Uncomment the Exabyte hack in the drive parsing code so that it works
|
||||
with ATL loaders again.
|
||||
- Add hack for ATL stacked loaders to keep them from reporting ghost slots
|
||||
|
||||
CHANGES, mtx 1.3.4
|
||||
- Forward-ported the ATL/Exabyte patches from mtx 1.2
|
||||
- Added progress indicator to 'tapeinfo' for DAT drives. (PLEASE TEST)
|
||||
- Purged a few more estinc.com out of the documentation, point to bru.com.
|
||||
|
||||
CHANGES, mtx 1.3.3
|
||||
- Reversed James' long descriptor patch until can figure out what's wrong with
|
||||
it.
|
||||
- Fixed some debug declarations, courtesy of Kevin Wang.
|
||||
- Point COMPATIBILITY file at mtx.sourceforge.net.
|
||||
|
||||
CHANGES, mtx 1.3.2
|
||||
- Merged Makefile changes from mtx-1.2 code
|
||||
- Changes from James Dugal to get all info for newer loaders, fix debugging
|
||||
|
||||
CHANGES, mtx 1.3.1
|
||||
- add an Exchange command
|
||||
|
||||
CHANGES, mtx 1.3.0
|
||||
- New Linux SCSI subsystem interface for 2.4 kernels, ripped boldly
|
||||
from sgtools by Doug Gilbert
|
||||
- mtx 'next' now skips blank slots, courtesy of Christopher McCrory
|
||||
- mtx 'unload' now prints an error message telling you that you need to
|
||||
eject the tape in the drive prior to unloading it, under certain
|
||||
conditions.
|
||||
- Started work on 'nsmhack' for controlling NSM jukeboxes.
|
||||
- copy_barcode was off by one.
|
||||
- 'position to element' command now added, courtesy of Mahlon Stacy
|
||||
|
||||
CHANGES, mtx 1.2.15:
|
||||
- Some Solaris fixes, courtesy of Matt Ward
|
||||
- Fix URL in .spec file
|
||||
|
||||
CHANGES, mtx 1.2.14:
|
||||
- Fix so it'll work if 0 is result of SCSI open (e.g., in cron jobs on Linux)
|
||||
- Move changelog to end of .spec file for easier reading
|
||||
- Added a bit of text to beginning of COMPATIBILITY file
|
||||
|
||||
CHANGES, mtx 1.2.13:
|
||||
- Fixed some autoloader bugs w/autoloaders that don't report an arm.
|
||||
- Fixed barcode backoff.
|
||||
- Added "nobarcode" option
|
||||
- Increased timeout for 'mtx inventory' to 30 minutes
|
||||
(note: may increase this even more if needed, please let me know!)
|
||||
- Shortened timeout for 'mtx inquiry' to 30 seconds
|
||||
- tapeinfo now prints SCSI ID/LUN info if available (only on Linux at the
|
||||
moment, sigh).
|
||||
- update documentation w/new email addresses, updated compile directions,
|
||||
various fixes.
|
||||
|
||||
CHANGES, mtx 1.2.12:
|
||||
- Fix FreeBSD compile bugs
|
||||
- Fix SGI compile bugs
|
||||
- Add HP/UX port (I hope!), courtesy of William Smith.
|
||||
- Re-wrote ReadElementStatus to make work for %!@# brain dead firmware that
|
||||
reports non-existent drives (I hope!). Also has side-effect of now working
|
||||
with multiple-arm libraries (though it only sees first arm!).
|
||||
- Cleaned up all -Wall messages.
|
||||
- Cleaned up Linux Sparc, installs loaderinfo.1, courtesy of Matt Dainty.
|
||||
- tapeinfo now reports status of CheckUnitReady.
|
||||
- tapeinfo no longer puts out Block Position if CheckUnitReady says 'no'.
|
||||
- tapeinfo now puts out Density Code and Medium Type/Not Loaded (modification
|
||||
of patches sent in by Bob Rahe)
|
||||
|
||||
CHANGES, mtx 1.2.11:
|
||||
- Added a GNU autoconf Makefile.in (still provide a Makefile for your use)
|
||||
*WARNING* autoconf is not yet working on all supported OS's! You may need
|
||||
to do the old-fashioned 'edit Makefile' bit!
|
||||
- Changed mtx.h and mtxl.c to include and define various things based upon
|
||||
what features autoconf detected (e.g., if 'camlib.h', use FreeBSD-style
|
||||
'cam', if 'scsi/sg.h' use Linux-style 'sg', etc.). If I ever port to a
|
||||
Unix that has same SCSI interface as one of the existing ports, autoconf
|
||||
will handle it without me having to add another set of #if's or #ifdefs.
|
||||
- Went ahead and tossed mtxctl into contrib.
|
||||
- In 'tapeinfo', skip \0 characters in serial numbers (some use \0
|
||||
terminator, some do not, skip it if this one does).
|
||||
- in 'tapeinfo', dump out the block position and (if at BOP) the "BOP: Yes"
|
||||
flag. Also dump out other info such as block limits.
|
||||
- Put file 'sparc-patch1' contributed by Chaskiel M Grundman, and applied
|
||||
it (sigh)
|
||||
- Added tapeinfo.py to 'contrib' directory
|
||||
- Updated mtx.py in 'contrib' directory
|
||||
- Created 'loaderinfo' program to report some misc. info about loaders.
|
||||
- Created 'scsitape' program so that I don't have to keep messing with
|
||||
#@$%@! tape ioctls on the various Unixes that I'm porting tape software
|
||||
to. (But see the warnings!).
|
||||
- Applied the Solaris patch to the read_element_status command (sigh).
|
||||
- Added timeout adjustment to the SCSI subsystem.
|
||||
- WARNING: DIGITAL UNIX AND VMS ARE PROBABLY IRREPERABLY BROKEN, due to the
|
||||
timeout changes to the SCSI subsystem. If anybody wishes to fix them,
|
||||
feel free to send me patches.
|
||||
- added contrib program "mtx-changer" (an Amanda tape changer script for
|
||||
?Solaris? that uses mtx rather than stc)
|
||||
- Jiggered Linux SCSI module for smarter error conditions handling (there are
|
||||
some error conditions that are normal for READ of tape drives).
|
||||
- Added contrib program "config_sgen_solaris.sh" which should ease
|
||||
setting up the 'sgen' driver on Solaris 8 (still no easy Solaris 7 or
|
||||
below config).
|
||||
|
||||
CHANGES, mtx 1.2.10:
|
||||
- Added FAQ and COMPATIBILITY (feel free to send me patches to these files!)
|
||||
- Added LICENSE
|
||||
- Added serial number to 'tapeinfo' output.
|
||||
- Fixed stupid syntax error in mtx.c (compiled with gcc, not with others!)
|
||||
- Fixed spec file for building rpms (maybe).
|
||||
- Added an 'erase' command (undocumented) for use on Linux for doing
|
||||
short erases on tapes (the Linux device driver defaults to a long erase).
|
||||
- Made mtx inventory return an error code if the inventory
|
||||
fails, so that we can wait for inventory to be completed at system
|
||||
startup for libraries that auto-inventory (sigh).
|
||||
|
||||
CHANGES, mtx 1.2.9:
|
||||
- Added an 'eject' command that, if directed to a tape drive, will eject the
|
||||
tape, and for some autoloaders, if directed to LUN 1, will eject the entire
|
||||
magazine.
|
||||
- Fixed the 'transfer' command to be 1 based rather than 0 based (sigh)
|
||||
- Now properly reports bar code for the tape that's in the tape drive.
|
||||
- Added some miscellaneous Python and Perl scripts to 'contrib'. Thanks
|
||||
to Frank Samuelson for the Perl scripts.
|
||||
|
||||
CHANGES, mtx 1.2.8:
|
||||
- Spec file has been changed to use the "portable" patch supplied by Red
|
||||
Hat so it should work on Linux Alpha and Linux SPARC too... maybe...
|
||||
- Now will accept 4-byte element status for most element types, despite fact
|
||||
that these don't comply with SCSI standards :-(. This should make many
|
||||
older changers work, including HP optical changers.
|
||||
- Fixed PeripheralDeviceType table, courtesy of Rob Turk.
|
||||
- Now looks for CHANGER environment variable if a device is not specified
|
||||
on the command line. If can't find CHANGER, then tries TAPE environment
|
||||
variable.
|
||||
- Properly sets TransportElementAddress in the CDB for the MOVE MEDIUM command
|
||||
with what was discovered via the READ_ELEMENT_STATUS command, rather
|
||||
than setting them to zero (SCSI spec says that zero should be the default
|
||||
arm, but at least one changer out there didn't like it).
|
||||
- Added a '--version' command (sigh).
|
||||
- Added an 'inventory' command for Breece Hill libraries that don't
|
||||
automatically do an inventory at powerup.
|
||||
|
||||
CHANGES, mtx 1.2.7:
|
||||
- Fixed problem w/single drive Exabyte 220 reporting element status data for
|
||||
both drives (sigh).
|
||||
- some general cleanup in the barcode fallback code (what a cruft!). Discovered
|
||||
that ADIC DAT AUTOCHANGER does not work w/mtx because it produces
|
||||
gibberish (will apparently only produce one element status page per request).
|
||||
- Fixed the RPM .spec file to have updated file locations, doc locations.
|
||||
- Fixed MoveMedium to say 'Output' for direction, to make it work with
|
||||
Solaris 8
|
||||
- Some changes to the Solaris low-level module to report more errors (though
|
||||
it still doesn't work as well as the Linux low-level module). Should now
|
||||
work properly with Solaris 2.6/7/8. (Solaris changes courtesy of Richard
|
||||
Fish of Enhanced Software Technologies).
|
||||
|
||||
CHANGES, mtx 1.2.6:
|
||||
- Fixed 'eepos' stuff to use | rather than || (whoops!)
|
||||
- Accept a 4-byte element descriptor for the robot arm for certain older
|
||||
autochangers.
|
||||
|
||||
CHANGES, mtx 1.2.5:
|
||||
- Added 'noattach' command. If on command line prior to other commands, forces
|
||||
them to use the regular SCSI changer API rather than the _ATTACHED API,
|
||||
no matter what the _ATTACHED bit in the Inquiry page said.
|
||||
- Created 'tapeinfo' program.
|
||||
|
||||
CHANGES, mtx 1.2.4:
|
||||
- Major overhaul of element guts to dynamically allocate the arrays
|
||||
using the result of a MODE_SENSE on the Element Address Assignment
|
||||
Page. If mtx 1.2.3 works for you and mtx 1.2.4 does NOT work for you,
|
||||
please un-comment the '#define DEBUG_MODE_SENSE' in file 'mtxl.c' and
|
||||
EMAIL me the results.
|
||||
|
||||
CHANGES, mtx 1.2.3:
|
||||
- Fixed the source storage element number stuff (again, sigh)
|
||||
- Because of above fix, 'next' etc. ought to work right again.
|
||||
|
||||
CHANGES, mtx 1.2.2:
|
||||
- Fixed that it was saying everything was an Import/Export element (oops!)
|
||||
- Properly update the Import/Export element count.
|
||||
|
||||
CHANGES, mtx 1.2.1:
|
||||
- Now explicitly output that a Storage element is in fact an Import/Export
|
||||
element.
|
||||
- Added 'transfer' command to transfer between two Storage elements (so that
|
||||
you can get a tape to an Import/Export element.
|
||||
- Added 'eepos' command for controlling tray retraction on the Breecehill
|
||||
import/export trays. (Works with "load" and "unload" commands too, though
|
||||
that is not documented on "mtx -h").
|
||||
|
||||
CHANGES, mtx 1.2.0:
|
||||
- Re-numbered now that Leonard has asked me to take over maintenance of the
|
||||
'mtx' program.
|
||||
- Temporarily treat Import/Export elements the same as Storage elements. Need
|
||||
to fix this eventually so that the GUI knows what kind of element we're
|
||||
talking about.
|
||||
- Removed quotes from the source element # to make it easier to parse
|
||||
from Perl or Python (just do a split on spaces).
|
||||
- Added sample program, 'mam2debug', showing how to use mtxl library for
|
||||
your own programs (this happens to dump the Exabyte Mammoth 2's internal
|
||||
debug buffer to a file, using the Mammoth2-specific SCSI commands to do so).
|
||||
|
||||
CHANGES, mtxl 1.4.8:
|
||||
- Whoops, report logical rather than physical when I have to scan for
|
||||
open slots :-).
|
||||
|
||||
CHANGES, mtxl 1.4.7:
|
||||
- Update comment to reflect mtxl 1.4.6 stuff :-).
|
||||
- Fix the part of the code that scans for open slots as sources for media.
|
||||
|
||||
CHANGES, mtxl 1.4.6:
|
||||
- Don't use _ATTACHED interface if it reports itself as a Medium Changer!
|
||||
|
||||
CHANGES, mtxl 1.4.5:
|
||||
- Changed "whoops" compile error on Linux (teach me to release w/o testing on
|
||||
the most popular platform!)
|
||||
- Changed declarations to remove compile-time warnings.
|
||||
|
||||
CHANGES, mtxl 1.4.4:
|
||||
- Added support for FreeBSD. (uses pass device, NOT native FreeBSD ch device).
|
||||
- Change all 'int' DeviceFD to DEVICE_TYPE DeviceFD. Note that SGI and FreeBSD
|
||||
use a struct * to access the CAM SCSI layer, rather than a file fd.
|
||||
- Fixed goof where I'd hard-wired max # of elements to 127 for testing
|
||||
purposes (it should be sum of MAX_STORAGE_ELEMENTS + MAX_TRANSFER_ELEMENTS
|
||||
+ MAX_TRANSPORT_ELEMENTS from mtx.h -- change those if you need more
|
||||
elements, bearing in mind that the code for ReadElementStatus in
|
||||
mtxl.c maxes out at 255 elements unless you fix that too).
|
||||
- Cleaned some cruft out of the MOVE_MEDIUM code.
|
||||
- Must have GNU Make to process Makefile. In reality, I don't know of
|
||||
any machine where we voluntarily use the native 'make' command, because
|
||||
a) there's a half dozen native 'make' all with their own perverted
|
||||
syntaxes, and b) most of them are brain dead beyond belief.
|
||||
|
||||
CHANGES, mtxl 1.4.3:
|
||||
- Do an INQUIRY prior to doing a MOVE_MEDIUM or READ_ELEMENT_STATUS so that I
|
||||
can detect the MChanger bit and use MOVE_MEDIUM_ATTACHED or
|
||||
READ_ELEMENT_STATUS_ATTACHED commands instead.
|
||||
- Successfully tested with dual drives!
|
||||
- first, next, last now working
|
||||
- Created a man page
|
||||
- Created a 'make install', edit Makefile to alter destinations.
|
||||
|
||||
CHANGES, mtxl 1.4.2:
|
||||
- Found the problem with the DAT changer! It was burping on the
|
||||
'bar code' bit... so I intercept that sense key, re-issue w/out the
|
||||
'bar code' bit, and success!
|
||||
- Added a 'TODO' file...
|
||||
|
||||
CHANGES, mtxl 1.4.1:
|
||||
- Added 'invert' qualifier to 'load' and 'unload' commands to invert
|
||||
the media (for HP optical jukeboxes). Type './mtx' by itself to
|
||||
see the syntax.
|
||||
- Figured out why my code wasn't properly detecting errors --
|
||||
turns out the 'sg' device can return ok
|
||||
status even when there is sense data to be reported!
|
||||
- Still to fix: *still* isn't working right with my Seagate
|
||||
6-tape DDS-4 DAT changer... also need to put the
|
||||
second drive into the Exabyte 220 to make sure the dual-drive stuff
|
||||
works properly (!).
|
||||
|
||||
CHANGES, mtxl 1.4:
|
||||
- Have now tested the barcode (volume tag) stuff. It works! (Well, there was
|
||||
an index-by-one problem that I had to squash, but after that...)
|
||||
- Changed to use SCSI Generic device API on Linux rather than
|
||||
SCSI_IOCTL_SEND_COMMAND API, which cut things off at 4095 bytes on i386
|
||||
Linux.
|
||||
- Added a bunch of debugging output that needs to be ripped out :-(.
|
||||
Make sure you remove the -DDEBUG from the Makefile, and probably
|
||||
-DLONG_PRINT_REQUEST_SENSE too (unless you LIKE sense results that make
|
||||
sense!)
|
||||
- Still have annoying bug on Linux of only reading 1st 16 bytes of sense
|
||||
data. Alas, this appears to be a problem in the Linux 2.2 kernel, not in
|
||||
anything that we're doing :-(. Hmm... cdrecord has the same problem, Mr.
|
||||
Schilling says he's been saying it's a problem since 1997. Sigh.
|
||||
- Still need to test the dual-drive stuff!
|
||||
|
||||
CHANGES, mtxl 1.3:
|
||||
- Hacked in the barcode (volume tag) stuff. NEED SOMEONE TO TEST
|
||||
WHETHER IT WORKS!
|
||||
- started issuing redundant initial READ_ELEMENT_STATUS with Allocation Length
|
||||
of 8 in order to get a BYTE_COUNT_OF_REPORT_AVAILABLE in order to calculate a
|
||||
better Allocation Length for the "real" READ_ELEMENT_STATUS. Trying to send a
|
||||
query to a small 6-tape changer with an Allocation Length suited for a
|
||||
200-element tape library was resulting in some errors and lockups on the
|
||||
part of the tape changer device.
|
||||
- first, last, next, previous are STILL broken. Sorry :-(.
|
||||
|
||||
CHANGES, mtxl 1.2:
|
||||
|
||||
- Changed many output messages to make them more easily parsed by
|
||||
scripts written in awk/perl/python
|
||||
- Extracted out a library of SCSI tape library routines usable by "C"
|
||||
programs (must be GPL'ed). Extensive re-arranging of code.
|
||||
- Added support for multiple drives.
|
||||
- Started adding support for tape changers that use the "MCHangr"
|
||||
bit rather than a separate ID or LUN.
|
||||
- Increased limits so we could deal with LARGE tape libraries.
|
||||
- Started adding support for barcode readers in said tape libraries
|
||||
- broke first, last, next, previous. Sorry :-(.
|
||||
- Added ability to chain commands on command line. Thus could say 'mtx -f
|
||||
/dev/sg4 unload 4 0 load 7 0' to unload a tape from drive 0 and load the
|
||||
tape in slot 7 into drive 0.
|
||||
|
||||
|
||||
163
mtx-1.3.12/COMPATABILITY
Normal file
163
mtx-1.3.12/COMPATABILITY
Normal file
@@ -0,0 +1,163 @@
|
||||
WARNING: THIS FILE IS OBSOLETE AND FOR HISTORICAL USE ONLY. Please
|
||||
see http://mtx.sourceforge.net for a more up-to-date compatibility list.
|
||||
|
||||
Operating Systems:
|
||||
-----------------
|
||||
|
||||
mtx 1.2 is currently known to work flawlessly under the following
|
||||
operating systems:
|
||||
|
||||
Linux (2.2.5 kernel and above)
|
||||
FreeBSD (tested with versions 3.2 and above, but should work for all 3.x
|
||||
and 4.x).
|
||||
|
||||
Various people have reported that they have managed to make mtx work
|
||||
on various versions of Solaris. Please check the mtx list archives (
|
||||
http://mtx.sourceforge.net ) to see how they've done it.
|
||||
|
||||
IRIX 6.5 apparently works flawlessly:
|
||||
|
||||
(Richard.Lefebvre(@AROBAS)cerca(.POINT)umontreal(.POINT)ca):
|
||||
I just wanted to send you 1 or 2 comments on mtx. I just downloaded it
|
||||
last friday to use with and SGI Origin2000 and an 8 slot DLT autoloader.
|
||||
The whole thing compiled fine (under gcc).
|
||||
|
||||
From Dan Wright (dtwright at uiuc dot uiuc.edu):
|
||||
I just wanted to send an e-mail to let you know that mtx 1.2.9
|
||||
works great for me on IRIX 6.5 with an ADIC FastStor DLT8000.
|
||||
IRIX 6.5 has a generic scsi interface installed by default, so to
|
||||
access the autoloader I use "mtx -f /dev/scsi/sc1d1l0" (bus 1 id 1
|
||||
lun 0).
|
||||
|
||||
----------------
|
||||
Changer Devices
|
||||
----------------
|
||||
The following has been directly tested:
|
||||
|
||||
* Exabyte 220 with 1 drive (21 slots)
|
||||
* Exabyte 220 with 2 drives (21 slots)
|
||||
* Exabyte EZ-17 (7 slots)
|
||||
Known quirks: Must eject tape using 'mt' or 'tapectl' prior to using
|
||||
the 'unload' command.
|
||||
|
||||
* Seagate DDS-4 DAT AutoLoader (1 drive, 6 slots)
|
||||
Product ID: 'DAT 06241-XXX'
|
||||
Known quirks: Uses LUN 1 for robot. On Linux, must compile kernel with
|
||||
"Scan SCSI LUNs" or add the following line to your /etc/lilo.conf (and
|
||||
re-run /sbin/lilo):
|
||||
append="max_scsi_luns=2"
|
||||
|
||||
* DISC D-40 optical library (2 drives, 40 slots, 1 import/export): Yes,
|
||||
it really does report that it's a Maxoptix!
|
||||
Product Type: Medium Changer
|
||||
Vendor ID: 'Maxoptix'
|
||||
Product ID: 'MAXLYB '
|
||||
Revision: '3.04'
|
||||
Attached Changer: No
|
||||
|
||||
The following have been tested by others, and information may be
|
||||
incomplete or in error even.
|
||||
|
||||
* Compaq DLT Library 20/40, 1 drive 15 slots (antony at elizatravel dot com)
|
||||
Vendor: HP Model: C5173-4000
|
||||
|
||||
* Vendor ID: 'ADIC ' (boris dot klug at ibs dash ag dot de)
|
||||
Product ID: 'VLS DLT ' 7 slot 1 import/export 1 drive.
|
||||
|
||||
* Unknown Overland changer (phreno at pacbell dot net):
|
||||
> > > Vendor ID: 'OVERLAND'
|
||||
> > > Product ID: 'LXB '
|
||||
|
||||
* "old Exabyte 10e tape loaders" (drew at pctc dot com)
|
||||
|
||||
* Unknown HP DLT changer: (eric at collab dot net)
|
||||
> > Storage Changer /dev/sgd:1 Drives, 15 Slots ( 0 Import/Export )
|
||||
> > Vendor ID: 'HP '
|
||||
> > Product ID: 'C5173-4000 '
|
||||
|
||||
* "Lago Sys LS-380L/StorageTek 9704/Imation ITL-2225 (mine's a
|
||||
StorageTek labeled)" 25-slot, 2-drive, 1-arm, 1-import/export
|
||||
(eswan at lips dot net)
|
||||
|
||||
* HP SureStore Optical 80fx. (mmarchione at nyhomes dot org )
|
||||
Vendor: HP Model: C1160F Rev: 0.40
|
||||
Type: Medium Changer ANSI SCSI revision: 02
|
||||
|
||||
* Breece Hill tape library (unknown configuration, unknown reporter):
|
||||
Vendor ID: 'BHTI'
|
||||
Product ID: 'Q2 '
|
||||
Oddities: Must either turn on auto-inventory, or run 'mtx inventory'
|
||||
prior to running any other mtx command. Reads bar codes by yanking
|
||||
tapes out of slots and waving them in front of bar code reader, so
|
||||
inventory of tapes with no bar code is VERY slow (bar code your tapes!).
|
||||
|
||||
|
||||
* Seagate Scorpion DDS-3 4-tape autochanger
|
||||
(jsled at normandy dot smarttouch dot com):
|
||||
Vendor ID: 'ARCHIVE '
|
||||
Product ID: 'Python 04377-XXX'
|
||||
|
||||
* Overland 15 tape 1 drive DLT changer: (asmith at umdgrb dot umd dot edu)
|
||||
Vendor ID: 'OVERLAND'
|
||||
Product ID: 'LXB '
|
||||
|
||||
* ADIC DAT AutoChanger -- 1 drive, 12 slots, 1 import-export:
|
||||
Vendor ID: 'ADIC ' (andrew_gray at irobotics dot com)
|
||||
Product ID: 'DAT AutoChanger '
|
||||
Quirks: firmware version 0357 does not appear to work w/mtx (request
|
||||
from ADIC that they upgrade your firmeware to 0361, which does
|
||||
seem to work), firmware version revision `0462` does work. Use
|
||||
'mtx inquiry' to detirmine which firmware you have.
|
||||
|
||||
* HP 1/20 DLT loader: "We have a HP 1/20, but I think it's all the
|
||||
same hardware. mtx works fine with it." (jo2y at midnightlinux dot com)
|
||||
|
||||
* Exabyte 120 (116 slots, 4 tape drives): (wsb at paralleldata dot com)
|
||||
Quirks: This loader does not properly support the loader slot assignment
|
||||
page used to allocate element structures, so the #defines must be
|
||||
changed in mtx.h for MAX_STORAGE_ELEMENTS, MAX_TRANSFER_ELEMENTS, and
|
||||
MAX_TRANSPORT_ELEMENTS. May also need to increase the SCSI timeout to
|
||||
do inventories. Takes a LONG time to do inventories if you don't have
|
||||
bar codes!
|
||||
|
||||
* Exabyte 210 (wsb at paralleldata dot com)
|
||||
|
||||
|
||||
* Adic FastStor DLT4000 (7-Slot 1 drive):
|
||||
Vendor ID: 'ADIC '
|
||||
Product ID: 'FastStor DLT '
|
||||
|
||||
* Ecrix AutoPak VXA (15-slot 1 drive) in configuration mode 0 (mark
|
||||
at commerceengine dot com):
|
||||
"This drive can be configured to emulate several types, but I've
|
||||
only tested it in this one mode."
|
||||
Vendor ID: 'SPECTRA '
|
||||
Product ID: '215 '
|
||||
Revision: '1008'
|
||||
Attached Changer: No
|
||||
SerialNumber: '023201'
|
||||
|
||||
* ATL P1000 2 drive, 31 slot, 1 import/output: (dna plus mtx at clas.ufl.edu)
|
||||
# ./mtx -f /dev/scsi/changer/c2t0d0 inquiry
|
||||
Product Type: Medium Changer
|
||||
Vendor ID: 'ATL '
|
||||
Product ID: 'P1000 6220070'
|
||||
Revision: '2.01'
|
||||
Attached Changer: No
|
||||
|
||||
* NSM DVD Jukebox:
|
||||
Storage Changer /dev/sg4:4 Drives, 561 Slots ( 1 Import/Export )
|
||||
Product Type: Medium Changer
|
||||
Vendor ID: 'NSM '
|
||||
Product ID: 'NSM6000 '
|
||||
Revision: '1120'
|
||||
Attached Changer: No
|
||||
|
||||
* Spectralogic Treefrog/Bullfrog:
|
||||
Storage Changer /dev/sg0:2 Drives, 15 Slots ( 0 Import/Export )
|
||||
Product Type: Medium Changer
|
||||
Vendor ID: 'SPECTRA '
|
||||
Product ID: '10000 '
|
||||
Revision: 'X010'
|
||||
Attached Changer: No
|
||||
|
||||
144
mtx-1.3.12/FAQ
Normal file
144
mtx-1.3.12/FAQ
Normal file
@@ -0,0 +1,144 @@
|
||||
Frequently Asked Questions List, v 1.0.1
|
||||
|
||||
Index:
|
||||
I. Compiling
|
||||
II. Finding the correct device
|
||||
III. Operational Issues
|
||||
|
||||
Part I: Compiling.
|
||||
|
||||
Q: Where is the Makefile in the tarball?
|
||||
A: MTX now uses GNU Autoconf to generate the Makefile. Type "./configure"
|
||||
while in the extracted mtx directory.
|
||||
|
||||
Q: Typing 'make' gives me a bunch of errors in the Makefile. Why can't
|
||||
you provide a Makefile that works?
|
||||
A: Note that you need the GNU 'make'. The BSD 'make' won't work, and
|
||||
Solaris 'make' probably won't work either. If you want a better
|
||||
configuration and makefile system, write one, then EMAIL me the results --
|
||||
mtx is Open Source software and needs your code contributions to grow.
|
||||
|
||||
Q: How do I compile for operating systems other than Linux?
|
||||
A: MTX no longer needs you to edit the Makefile to compile for operating
|
||||
systems other than Linux. Just type ./configure and go with it.
|
||||
|
||||
Q: How do I port it to OS's other than the supported ones?
|
||||
A: Create a new scsi_ module using one of the existing modules as an
|
||||
example (scsi_freebsd.c might be a good model). Decide what symbol
|
||||
you want #ifdef'ed in order to include that scsi_ module. Edit
|
||||
mtxl.c to #include your scsi_ module. Edit the Makefile to add the
|
||||
new target, including the -D needed to #include your new scsi_ module.
|
||||
|
||||
*********************************************************************
|
||||
Part II: Finding the correct device.
|
||||
|
||||
Q: Why does this command not work??
|
||||
[root@Scotty mtxl-1.4.8]# ./mtx -f /dev/st0 inquiry
|
||||
In /var/log/messages I see:
|
||||
st0: Write not multiple of tape block size.
|
||||
A: Note that mtx 1.2 and above use the SCSI GENERIC interface on Linux,
|
||||
FreeBSD, and Solaris (at least). They do NOT use the tape device node.
|
||||
|
||||
Q: When I do 'mtx -f /dev/sga inquiry' it shows
|
||||
Product Type: Tape Drive
|
||||
Vendor Id: HP
|
||||
Product ID: C1553A
|
||||
But when I do a 'mtx -f /dev/sga status' it fails. Why?!
|
||||
A: You're trying to send a robotics command to a tape drive. You need
|
||||
to send robotics commands to robotics devices, not to tape drives. Look in
|
||||
/proc/scsi/scsi (Linux) or camcontrol (FreeBSD) to find out what the
|
||||
robotics device is. It will be reported as a 'Medium Changer', not a
|
||||
'Sequential Access' or 'Tape Drive'.
|
||||
|
||||
Q: When I do 'cat /proc/scsi/scsi' it shows only one device, the tape device!
|
||||
A: You are using a DAT autochanger that has one SCSI ID but two LUN's, LUN 0
|
||||
and LUN 1. You need to compile a new kernel with SCAN SCSI LUNS enabled
|
||||
or add this line to your /etc/lilo.conf (then run /sbin/lilo and reboot):
|
||||
append="max_scsi_luns=2"
|
||||
|
||||
Q: I'm tired of typing '-f /dev/sgc' all the time. How do I set a default
|
||||
device that 'mtx' looks at?
|
||||
A: Set the CHANGER environment variable. For example, with 'bash':
|
||||
export CHANGER=/dev/sgc
|
||||
|
||||
Q: I get "modprobe: can't locate module char-major-21"
|
||||
syslog messages being squirreled away into a file on our syslog host,
|
||||
and mtx doesn't work. What's the problem?
|
||||
A: You need to compile SCSI generic support into your kernel (or as a module).
|
||||
|
||||
Q: When I installed mtx, a message showed
|
||||
up on the console stating that a scsi changer was found at
|
||||
dev sgr. However, I have no device /dev/sgr.
|
||||
A: On Linux, do 'mknod /dev/sgr c 21 19' to create a device node. By default
|
||||
only 16 SCSI generic nodes are created, which might not be enough if
|
||||
you have multiple SCSI controllers with lots of devices.
|
||||
|
||||
******************************************************
|
||||
III. Operational issues:
|
||||
|
||||
Q: I'm using Red Hat 7.0 and mtx works fine when I type ./mtx from the
|
||||
command line, but when I use it from scripts I get the following:
|
||||
mtx: Request Sense: Error Code=70 (Current)
|
||||
mtx: Request Sense: Sense Key=Aborted Command
|
||||
mtx: Request Sense: Additional Sense Code = 4E
|
||||
mtx: Request Sense: Additional Sense Qualifier = 00
|
||||
What's happening?
|
||||
A: Do "rpm -e mtx". Red Hat 7.0 includes a busted version of mtx. Your
|
||||
script is apparently picking up the busted mtx in your path. Get rid
|
||||
of the busted mtx, make sure that /usr/local/bin (or wherever you
|
||||
put the "good" mtx) is in the path, and all should be well.
|
||||
|
||||
Q: I get
|
||||
# /usr/local/bin/mtx -f /dev/sgr status
|
||||
mtx: Request Sense: Error Code=70 (Current)
|
||||
mtx: Request Sense: Sense Key=Not Ready
|
||||
mtx: Request Sense: Additional Sense Code = 04
|
||||
mtx: Request Sense: Additional Sense Qualifier = 8E
|
||||
mtx: READ ELEMENT STATUS Command Failed
|
||||
What gives?
|
||||
A: Make sure your loader is in random mode, not sequential mode.
|
||||
Most "real" loaders (as vs. DAT autoloaders) will not properly report
|
||||
status information unless they are in "random" mode.
|
||||
|
||||
|
||||
Q: I issue 'mtx load 5' and it loads tape 5. But when I try to put the tape
|
||||
back in the magazine, we hit problems:
|
||||
mtx: MOVE MEDIUM from Element Address 82 to 5 Failed
|
||||
What gives?
|
||||
A: Many loaders require you to first eject the tape (using 'mt' or 'tapectl')
|
||||
before you issue an 'unload' command via 'mtx'.
|
||||
|
||||
Q: My Breece Hill loader does not properly report its slots.
|
||||
A: Either set the "auto-inventory" feature in the loader's control panel,
|
||||
or run 'mtx inventory' prior to running 'mtx status'.
|
||||
|
||||
Q: My Breece Hill loader takes a long time to do an inventory. mtx times
|
||||
out and spits all over the place. Help!
|
||||
A: Many loaders that support barcodes will perform poorly if you place tapes
|
||||
into them without bar codes. Place bar codes on all your tapes and you
|
||||
should be able to run 'mtx inventory' without that failure.
|
||||
|
||||
Q: How do I eject the magazine of my autoloader?
|
||||
A: Many low-end DAT autoloaders support the removable media 'EJECT' command
|
||||
sent to the robotics device, even though it's not documented (or required)
|
||||
in the SCSI standards. If the loader is at /dev/sgb, simply do
|
||||
'mtx -f /dev/sgb eject' and see what happens. (If nothing happens,
|
||||
your autoloader doesn't support 'eject'). Some high-end libraries have
|
||||
their own proprietary way for ejecting magazine trays, generally
|
||||
involving abuse of the 'transfer' command and 'eepos' addendums,
|
||||
but this is totally non-standard and undocumented.
|
||||
|
||||
Q: Is there a standard for cleaning tape bar codes?
|
||||
A: Many libraries, and many backup programs, expect cleaning tape bar
|
||||
codes to start with "CLN".
|
||||
|
||||
Q: How do I report a bug?
|
||||
A: First, read this FAQ. Next, check the mtx list archives at
|
||||
http://mtx.sourceforge.net to make sure that it's not already addressed
|
||||
by somebody else. If your problem is still not solved, send
|
||||
(to the mtx list) the following information:
|
||||
Result of 'mtx inquiry' on the loader,
|
||||
Result of 'mtx status' on the loader (minus a bunch of tapes if
|
||||
it's a 50+ tape loader!),
|
||||
Results of the operation that isn't working correctly.
|
||||
|
||||
280
mtx-1.3.12/LICENSE
Normal file
280
mtx-1.3.12/LICENSE
Normal file
@@ -0,0 +1,280 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
515
mtx-1.3.12/LICENSE.html
Normal file
515
mtx-1.3.12/LICENSE.html
Normal file
@@ -0,0 +1,515 @@
|
||||
<!DOCTYPE html PUBLIC "-//IETF//DTD HTML 2.0//EN">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>GNU General Public License - GNU Project - Free Software Foundation (FSF)</TITLE>
|
||||
<LINK REV="made" HREF="mailto:webmasters@www.gnu.org">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#1F00FF" ALINK="#FF0000" VLINK="#9900DD">
|
||||
<H1>GNU General Public License</H1>
|
||||
|
||||
<P>
|
||||
<HR>
|
||||
|
||||
<P>
|
||||
|
||||
<H2>Table of Contents</H2>
|
||||
<UL>
|
||||
|
||||
<LI><A NAME="TOC1" HREF="gpl.html#SEC1">GNU GENERAL PUBLIC LICENSE</A>
|
||||
<UL>
|
||||
<LI><A NAME="TOC2" HREF="gpl.html#SEC2">Preamble</A>
|
||||
<LI><A NAME="TOC3" HREF="gpl.html#SEC3">TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</A>
|
||||
<LI><A NAME="TOC4" HREF="gpl.html#SEC4">How to Apply These Terms to Your New Programs</A>
|
||||
|
||||
</UL>
|
||||
</UL>
|
||||
|
||||
<P>
|
||||
|
||||
<HR>
|
||||
|
||||
<P>
|
||||
|
||||
|
||||
|
||||
<H2><A NAME="SEC1" HREF="gpl.html#TOC1">GNU GENERAL PUBLIC LICENSE</A></H2>
|
||||
<P>
|
||||
Version 2, June 1991
|
||||
|
||||
</P>
|
||||
|
||||
<PRE>
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
</PRE>
|
||||
|
||||
|
||||
|
||||
<H2><A NAME="SEC2" HREF="gpl.html#TOC2">Preamble</A></H2>
|
||||
|
||||
<P>
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
</P>
|
||||
<P>
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
</P>
|
||||
<P>
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
</P>
|
||||
<P>
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
</P>
|
||||
<P>
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
</P>
|
||||
<P>
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
</P>
|
||||
<P>
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
</P>
|
||||
<P>
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
</P>
|
||||
|
||||
|
||||
<H2><A NAME="SEC3" HREF="gpl.html#TOC3">TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</A></H2>
|
||||
|
||||
|
||||
<P>
|
||||
|
||||
<STRONG>0.</STRONG>
|
||||
This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
<P>
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
<P>
|
||||
|
||||
<STRONG>1.</STRONG>
|
||||
You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
<P>
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
<P>
|
||||
|
||||
<STRONG>2.</STRONG>
|
||||
You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
<P>
|
||||
|
||||
<UL>
|
||||
|
||||
<LI><STRONG>a)</STRONG>
|
||||
You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
<P>
|
||||
<LI><STRONG>b)</STRONG>
|
||||
You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
<P>
|
||||
<LI><STRONG>c)</STRONG>
|
||||
If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
</UL>
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
<P>
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
<P>
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
<P>
|
||||
|
||||
<STRONG>3.</STRONG>
|
||||
You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
|
||||
<!-- we use this doubled UL to get the sub-sections indented, -->
|
||||
<!-- while making the bullets as unobvious as possible. -->
|
||||
<UL>
|
||||
|
||||
<LI><STRONG>a)</STRONG>
|
||||
Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
<P>
|
||||
<LI><STRONG>b)</STRONG>
|
||||
Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
<P>
|
||||
<LI><STRONG>c)</STRONG>
|
||||
Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
</UL>
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
<P>
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
<P>
|
||||
|
||||
<STRONG>4.</STRONG>
|
||||
You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
<P>
|
||||
|
||||
<STRONG>5.</STRONG>
|
||||
You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
<P>
|
||||
|
||||
<STRONG>6.</STRONG>
|
||||
Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
<P>
|
||||
|
||||
<STRONG>7.</STRONG>
|
||||
If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
<P>
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
<P>
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
<P>
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
<P>
|
||||
|
||||
<STRONG>8.</STRONG>
|
||||
If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
<P>
|
||||
|
||||
<STRONG>9.</STRONG>
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
<P>
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
<P>
|
||||
|
||||
|
||||
<STRONG>10.</STRONG>
|
||||
If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
|
||||
|
||||
<P><STRONG>NO WARRANTY</STRONG></P>
|
||||
|
||||
<P>
|
||||
|
||||
<STRONG>11.</STRONG>
|
||||
BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
<P>
|
||||
|
||||
<STRONG>12.</STRONG>
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
<P>
|
||||
|
||||
|
||||
<H2>END OF TERMS AND CONDITIONS</H2>
|
||||
|
||||
|
||||
|
||||
<H2><A NAME="SEC4" HREF="gpl.html#TOC4">How to Apply These Terms to Your New Programs</A></H2>
|
||||
|
||||
<P>
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
</P>
|
||||
<P>
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
</P>
|
||||
|
||||
<PRE>
|
||||
<VAR>one line to give the program's name and an idea of what it does.</VAR>
|
||||
Copyright (C) <VAR>yyyy</VAR> <VAR>name of author</VAR>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
</PRE>
|
||||
|
||||
<P>
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
</P>
|
||||
<P>
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
</P>
|
||||
|
||||
<PRE>
|
||||
Gnomovision version 69, Copyright (C) <VAR>year</VAR> <VAR>name of author</VAR>
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details
|
||||
type `show w'. This is free software, and you are welcome
|
||||
to redistribute it under certain conditions; type `show c'
|
||||
for details.
|
||||
</PRE>
|
||||
|
||||
<P>
|
||||
The hypothetical commands <SAMP>`show w'</SAMP> and <SAMP>`show c'</SAMP> should show
|
||||
the appropriate parts of the General Public License. Of course, the
|
||||
commands you use may be called something other than <SAMP>`show w'</SAMP> and
|
||||
<SAMP>`show c'</SAMP>; they could even be mouse-clicks or menu items--whatever
|
||||
suits your program.
|
||||
|
||||
</P>
|
||||
<P>
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
</P>
|
||||
|
||||
<PRE>
|
||||
Yoyodyne, Inc., hereby disclaims all copyright
|
||||
interest in the program `Gnomovision'
|
||||
(which makes passes at compilers) written
|
||||
by James Hacker.
|
||||
|
||||
<VAR>signature of Ty Coon</VAR>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
</PRE>
|
||||
|
||||
<P>
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
|
||||
<HR>
|
||||
|
||||
<P>
|
||||
FSF & GNU inquiries & questions to
|
||||
<A HREF="mailto:gnu@gnu.org"><EM>gnu@gnu.org</EM></A>.
|
||||
send other questions to
|
||||
<A HREF="mailto:gnu@gnu.org"><EM>gnu@gnu.org</EM></A>.
|
||||
<P>
|
||||
Copyright notice above.<BR>
|
||||
Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111, USA
|
||||
<P>
|
||||
<HR>
|
||||
</BODY>
|
||||
</HTML>
|
||||
176
mtx-1.3.12/Makefile.in
Normal file
176
mtx-1.3.12/Makefile.in
Normal file
@@ -0,0 +1,176 @@
|
||||
# WARNING -- THIS HAS BEEN RE-WRITTEN TO USE GNU MAKE. DO NOT
|
||||
# TRY TO PROCESS THIS WITH A NORMAL MAKE! (FREEBSD GUYS, THIS MEANS
|
||||
# USE GMAKE, NOT REGULAR BSD MAKE!)
|
||||
#
|
||||
# Valid targets:
|
||||
# linux86 freebsd86 solarissparc sgi dec vms
|
||||
#
|
||||
# Makefile changes by Lars Kellogg-Stedman for better integration with
|
||||
# GNU Autoconf.
|
||||
|
||||
# Version # for 'make dist'...
|
||||
VERSION=1.3.12
|
||||
|
||||
BINS = mtx@EXEEXT@ tapeinfo@EXEEXT@ loaderinfo@EXEEXT@ scsitape@EXEEXT@ scsieject@EXEEXT@
|
||||
EXTRA_BINS = nsmhack@EXEEXT@
|
||||
DBGS := $(BINS:%@EXEEXT@=%.dbg)
|
||||
MAN = mtx.1 tapeinfo.1 loaderinfo.1 scsitape.1 scsieject.1
|
||||
MAN_HTML := $(MAN:%.1=%.html)
|
||||
MAN_TXT := $(MAN:%.1=%.txt)
|
||||
|
||||
TARGET = @TARGET@
|
||||
CPU = @CPU@
|
||||
CC = @CC@
|
||||
INSTALL = @INSTALL@
|
||||
|
||||
CFLAGS = @CFLAGS@
|
||||
CPPFLAGS = @CPPFLAGS@ -DVERSION="\"$(VERSION)\"" -I$(srcdir) -I.
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBS = @LIBS@
|
||||
USE_OBJCOPY = @USE_OBJCOPY@
|
||||
|
||||
INSTALL_DOC = $(INSTALL) -m 644
|
||||
INSTALL_BIN = $(INSTALL) -m 755
|
||||
INSTALL_DIR = $(INSTALL) -m 755 -d
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
sbindir = @sbindir@
|
||||
mandir = @mandir@
|
||||
srcdir = @srcdir@
|
||||
|
||||
VPATH = $(srcdir)
|
||||
|
||||
#
|
||||
# Linux on x86...
|
||||
#
|
||||
ifeq ($(TARGET),linux)
|
||||
CFLAGS += -Wall
|
||||
CPPFLAGS += -DLONG_PRINT_REQUEST_SENSE=1
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET),mingw)
|
||||
CFLAGS += -Wall
|
||||
CPPFLAGS += -DLONG_PRINT_REQUEST_SENSE=1
|
||||
endif
|
||||
|
||||
#
|
||||
# FreeBSD
|
||||
#
|
||||
ifeq ($(TARGET),freebsd86)
|
||||
CPPFLAGS += -DLONG_PRINT_REQUEST_SENSE=1
|
||||
LIBS += -lcam
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET),hpux)
|
||||
CFLAGS += -O -D_HPUX_SOURCE -D __hpux__
|
||||
endif
|
||||
|
||||
#
|
||||
# Solaris/SPARC
|
||||
#
|
||||
ifeq ($(TARGET),solarissparc)
|
||||
CFLAGS += -O6
|
||||
endif
|
||||
|
||||
#
|
||||
# SGI IRIX
|
||||
#
|
||||
ifeq ($(TARGET),sgi)
|
||||
CFLAGS += -O6
|
||||
LIBS += -lds
|
||||
endif
|
||||
|
||||
#
|
||||
# Digital Unix
|
||||
#
|
||||
ifeq ($(TARGET),dec)
|
||||
CFLAGS += -O
|
||||
endif
|
||||
|
||||
#
|
||||
# OpenVMS (see vms/000readme)
|
||||
#
|
||||
ifeq ($(TARGET),vms)
|
||||
See vms/000readme for information.
|
||||
endif
|
||||
|
||||
%.dbg : %@EXEEXT@
|
||||
ifeq ($(USE_OBJCOPY),yes)
|
||||
objcopy --only-keep-debug $< $@
|
||||
objcopy --strip-debug $<
|
||||
objcopy --add-gnu-debuglink=$@ $<
|
||||
else
|
||||
strip $< -o $@
|
||||
endif
|
||||
|
||||
all: $(BINS)
|
||||
|
||||
dbgs: $(DBGS)
|
||||
|
||||
install: $(BINS)
|
||||
$(INSTALL_DIR) $(sbindir)
|
||||
for file in $(BINS); do \
|
||||
$(INSTALL_BIN) "$$file" $(sbindir) ; \
|
||||
done
|
||||
$(INSTALL_DIR) $(mandir) $(mandir)/man1
|
||||
for file in mtx.1 tapeinfo.1 scsitape.1 scsieject.1 loaderinfo.1 ; do \
|
||||
$(INSTALL_DOC) "$$file" $(mandir)/man1 ; \
|
||||
done
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ mtx-*.zip
|
||||
rm -f $(BINS)
|
||||
rm -f $(DBGS)
|
||||
rm -f $(MAN_HTML)
|
||||
rm -f $(MAN_TXT)
|
||||
rm -f mam2debug@EXEEXT@ mam2debug2@EXEEXT@
|
||||
rm -rf autom4te.cache
|
||||
|
||||
distclean: clean
|
||||
rm -f Makefile config.h config.log config.cache config.status
|
||||
|
||||
dist: distclean
|
||||
./makedist $(VERSION)
|
||||
|
||||
loaderinfo@EXEEXT@: loaderinfo.o mtxl.o mtxl.h mtx.h $(EXTRA)
|
||||
$(CC) $(LDFLAGS) -o loaderinfo@EXEEXT@ loaderinfo.o mtxl.o $(EXTRA) $(LIBS)
|
||||
|
||||
nsmhack@EXEEXT@: nsmhack.o mtxl.o $(EXTRA)
|
||||
$(CC) $(LDFLAGS) -o nsmhack@EXEEXT@ nsmhack.o mtxl.o $(EXTRA) $(LIBS)
|
||||
|
||||
mtx@EXEEXT@: mtx.o mtxl.o mtxl.h mtx.h $(EXTRA)
|
||||
$(CC) $(LDFLAGS) -o mtx@EXEEXT@ mtx.o mtxl.o $(EXTRA) $(LIBS)
|
||||
|
||||
mam2debug@EXEEXT@: mtxl.o mam2debug.o mtx.h $(EXTRA)
|
||||
$(CC) $(LDFLAGS) -o mam2debug@EXEEXT@ mtxl.o mam2debug.o $(EXTRA) $(LIBS)
|
||||
|
||||
tapeinfo@EXEEXT@: tapeinfo.o mtxl.o mtx.h mtxl.h $(EXTRA)
|
||||
$(CC) $(LDFLAGS) -o tapeinfo@EXEEXT@ tapeinfo.o mtxl.o $(EXTRA) $(LIBS)
|
||||
|
||||
mam2debug2@EXEEXT@: mtxl.o mam2debug2.o mtx.h $(EXTRA)
|
||||
$(CC) $(LDFLAGS) -o mam2debug2@EXEEXT@ mtxl.o mam2debug2.o $(EXTRA) $(LIBS)
|
||||
|
||||
scsitape@EXEEXT@: scsitape.o mtxl.o mtxl.h mtx.h $(EXTRA)
|
||||
$(CC) $(LDFLAGS) -o scsitape@EXEEXT@ scsitape.o mtxl.o $(EXTRA) $(LIBS)
|
||||
|
||||
scsitape.o: scsitape.c mtx.h mtxl.h
|
||||
|
||||
scsieject@EXEEXT@: scsieject.o mtxl.o mtxl.h mtx.h $(EXTRA)
|
||||
$(CC) $(LDFLAGS) -o scsieject@EXEEXT@ scsieject.o mtxl.o $(EXTRA) $(LIBS)
|
||||
|
||||
scsieject.o: scsieject.c mtx.h mtxl.h
|
||||
|
||||
loaderinfo.o: loaderinfo.c mtx.h mtxl.h
|
||||
|
||||
tapeinfo.o: tapeinfo.c mtx.h mtxl.h
|
||||
|
||||
mam2debug.o: mam2debug.c mtx.h mtxl.h
|
||||
|
||||
mam2debug2.o: mam2debug2.c mtx.h mtxl.h
|
||||
|
||||
mtx.o: mtx.c mtx.h mtxl.h
|
||||
|
||||
mtxl.o: mtxl.c mtx.h mtxl.h scsi_linux.c scsi_win32.c
|
||||
|
||||
nsmhack.o: nsmhack.c mtxl.h mtx.h
|
||||
38
mtx-1.3.12/README
Normal file
38
mtx-1.3.12/README
Normal file
@@ -0,0 +1,38 @@
|
||||
MTX
|
||||
|
||||
Programs:
|
||||
mtx is the media changer control program
|
||||
tapeinfo dumps some interesting stuff out of tape drives' mode pages and
|
||||
sense pages.
|
||||
loaderinfo dumps some interesting stuff out of loaders' mode pages and
|
||||
sense pages.
|
||||
scsitape sends raw SCSI commands to tape drives. Do not use this unless
|
||||
you know exactly what you're doing, because you can easily get into a feud
|
||||
with the system's own tape driver and end up locking up the whole system.
|
||||
|
||||
INSTALLATION:
|
||||
|
||||
WARNING: MUST HAVE GNU 'make' TO DO THIS! (e.g. use 'gmake' on freebsd, not
|
||||
BSD 'make'!).
|
||||
|
||||
Type ./configure to create a Makefile. Type 'make', then 'make
|
||||
install'. Type 'man mtx' for info about mtx, and 'man tapeinfo' for
|
||||
info about tapeinfo. Enjoy.
|
||||
|
||||
Credits:
|
||||
|
||||
The original 'mtx' program is copyright 1996-1997 by Leonard Zubkoff
|
||||
<lnz@dandelion.com>. This version was modified for multi-drive,
|
||||
optical changer, and tape library support by Eric Lee Green
|
||||
<eric@badtux.org>. Also added FreeBSD support. Please see the man page
|
||||
for current info, and the file 'mtx.doc' for historical info.
|
||||
|
||||
My thanks to Doug Bonnell of Breece Hill for suggestions on
|
||||
dynamically allocating element info, Tien That Ton of Tandberg for
|
||||
being the original tester of the Import/Export Element stuff, Ken
|
||||
Porter for RPM's, William D. Smith for the HP/UX port, Kai Makisara
|
||||
for the barcode backoff fix, and to all the other people out there who
|
||||
have used it, found problems with it, and let me know about it (you
|
||||
know who you are).
|
||||
|
||||
-- Eric Lee Green <eric@badtux.org>
|
||||
45
mtx-1.3.12/README.win32
Normal file
45
mtx-1.3.12/README.win32
Normal file
@@ -0,0 +1,45 @@
|
||||
BUILDING FOR MICROSOFT WINDOWS
|
||||
==============================
|
||||
|
||||
You can perform the build using either MinGW or Microsoft Visual Studio 2005.
|
||||
|
||||
Microsoft Visual Studio 2005
|
||||
----------------------------
|
||||
|
||||
Open the solution in msvc/mtx.sln.
|
||||
|
||||
Select the Build / Build Solution menu item.
|
||||
|
||||
|
||||
MinGW with GCC
|
||||
--------------
|
||||
|
||||
You must be using at least version 2.16.91 of binutils.
|
||||
|
||||
To generate the initial configure script, this only needs to be
|
||||
done once.
|
||||
|
||||
./configure --host=mingw32
|
||||
make
|
||||
|
||||
CHANGES FROM UNIX
|
||||
=================
|
||||
|
||||
The only difference is in the naming of devices. On Linux the changer is
|
||||
accessed using /dev/sg<N>, on Windows you use Changer<N>.
|
||||
|
||||
On Linux the tape drive is referenced using /dev/nst<N>, on Windows you use Tape<N>.
|
||||
|
||||
There is one exception, in the case where there isn't a driver loaded for the device.
|
||||
This is usually only the case on Windows 2000 or if the Windows XP or Windows Server
|
||||
2003 system supplied driver has been disabled.
|
||||
|
||||
In the case where there is no driver loaded you can access the device directly
|
||||
through the SCSI driver using the following notation:
|
||||
|
||||
<port>:<bus>:<target>:<lun>
|
||||
|
||||
Port is the adapter number
|
||||
Bus is the SCSI bus number relative to the adapter
|
||||
Target is the SCSI device's target ID
|
||||
LUN is the SCSI device's logical unit number
|
||||
15
mtx-1.3.12/TODO
Normal file
15
mtx-1.3.12/TODO
Normal file
@@ -0,0 +1,15 @@
|
||||
1 Fix the big element descriptor overflow problem by adding a retry/reallocate
|
||||
if things overflow.
|
||||
1 Add a 'timeout' command to adjust the timeout (timeout will be in seconds!).
|
||||
1 Add IES command (sets CDB[5] to something in routine Inventory() ).
|
||||
1 Fix 'scsitape' READ and WRITE so that block counts work.
|
||||
1 Add EXCHANGE command so that we can exchange media between slots in
|
||||
NSM/DISC optical jukeboxes.
|
||||
1 If moving media to/from import/export slot, try to do it even if the slot
|
||||
reports that it's empty or full, this will let us stick our tongue out
|
||||
on NSM/DISC optical jukeboxes for importing media.
|
||||
2 Fix ports to other Unixes/VMS.
|
||||
2 Add a range to 'mtx status' so that we request status only of
|
||||
the elements we're interested in, rather than of all of them.
|
||||
(nice for the very big loaders!).
|
||||
3 Better Import/Export port support?
|
||||
15
mtx-1.3.12/build.win32
Executable file
15
mtx-1.3.12/build.win32
Executable file
@@ -0,0 +1,15 @@
|
||||
manpages="mtx.1 tapeinfo.1 loaderinfo.1 scsitape.1 scsieject.1"
|
||||
txtpages="mtx.txt tapeinfo.txt loaderinfo.txt scsitape.txt scsieject.txt"
|
||||
htmlpages="mtx.html tapeinfo.html loaderinfo.html scsitape.html scsieject.html"
|
||||
|
||||
./configure --host=mingw32
|
||||
make
|
||||
make dbgs
|
||||
|
||||
for i in $manpages
|
||||
do
|
||||
groff -et -Thtml -mandoc $i | col -b > `basename $i .1`.html
|
||||
groff -et -Tascii -mandoc $i | col -b > `basename $i .1`.txt
|
||||
done
|
||||
|
||||
zip mtx-$1.zip README.win32 *.exe $htmlpages $txtpages
|
||||
1500
mtx-1.3.12/config.guess
vendored
Executable file
1500
mtx-1.3.12/config.guess
vendored
Executable file
File diff suppressed because it is too large
Load Diff
37
mtx-1.3.12/config.h.in
Normal file
37
mtx-1.3.12/config.h.in
Normal file
@@ -0,0 +1,37 @@
|
||||
/* Copyright 2001 Enhanced Software Technologies Inc.
|
||||
* Released under GNU General Public License V2 or Above
|
||||
* See http://www.gnu.org for more information about the terms of
|
||||
* the GNU General Public License.
|
||||
* $Date: 2007-02-13 08:45:31 -0800 (Tue, 13 Feb 2007) $
|
||||
* $Revision: 144 $
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H 1
|
||||
|
||||
/* autoconf changes these. */
|
||||
#define HAVE_STRING_H 0
|
||||
#define HAVE_UNISTD_H 0
|
||||
#define HAVE_STDLIB_H 0
|
||||
#define HAVE_STDARG_H 0
|
||||
#define HAVE_SYS_PARAM_H 0
|
||||
#define HAVE_SCSI_SCSI_H 0
|
||||
#define HAVE_SCSI_SCSI_IOCTL_H 0
|
||||
#define HAVE_SCSI_SG_H 0
|
||||
#define HAVE_SYS_GSCDDS_H 0
|
||||
#define HAVE_CAMLIB_H 0
|
||||
#define HAVE_SYS_SCSI_IMPL_USCSI_H 0
|
||||
#define HAVE_SYS_SCSI_CTL_H 0
|
||||
#define HAVE_DSLIB_H 0
|
||||
#define HAVE_DU_DEFS_H 0
|
||||
#define HAVE_SYS_STAT_H 0
|
||||
#define HAVE_SYS_TYPES_H 0
|
||||
#define HAVE_FCNTL_H 0
|
||||
#define HAVE_SYS_IOCTL_H 0
|
||||
#define HAVE_SYS_MTIO_H 0
|
||||
#define HAVE_DDK_NTDDSCSI_H 0
|
||||
|
||||
#define WORDS_BIGENDIAN 0
|
||||
|
||||
#endif
|
||||
|
||||
1616
mtx-1.3.12/config.sub
vendored
Executable file
1616
mtx-1.3.12/config.sub
vendored
Executable file
File diff suppressed because it is too large
Load Diff
6545
mtx-1.3.12/configure
vendored
Executable file
6545
mtx-1.3.12/configure
vendored
Executable file
File diff suppressed because it is too large
Load Diff
113
mtx-1.3.12/configure.in
Executable file
113
mtx-1.3.12/configure.in
Executable file
@@ -0,0 +1,113 @@
|
||||
dnl Copyright 2001 Enhanced Software Technologies Inc.
|
||||
dnl Written Jan. 2001 Eric Lee Green
|
||||
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
AC_INIT(mtx.c)
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
|
||||
dnl Check system.
|
||||
AC_CANONICAL_SYSTEM
|
||||
AC_PREFIX_DEFAULT(/usr/local)
|
||||
|
||||
case "$host_os" in
|
||||
*linux*) AC_DEFINE(LINUX)
|
||||
TARGET=linux
|
||||
;;
|
||||
*solaris*) AC_DEFINE(SOLARIS)
|
||||
TARGET=solarissparc
|
||||
;;
|
||||
*sunos*) TARGET=solarissparc
|
||||
;;
|
||||
*freebsd*) TARGET=freebsd86
|
||||
;;
|
||||
*aix*) TARGET=aix
|
||||
;;
|
||||
*irix*) TARGET=sgi
|
||||
;;
|
||||
*hp*) TARGET=hpux
|
||||
;;
|
||||
*HP*) TARGET=hpux
|
||||
;;
|
||||
*sequent*) AC_DEFINE(SEQUENT)
|
||||
;;
|
||||
*MINGW*) TARGET=mingw
|
||||
;;
|
||||
*MinGW*) TARGET=mingw
|
||||
;;
|
||||
*mingw*) TARGET=mingw
|
||||
;;
|
||||
*) TARGET=$host_os
|
||||
;;
|
||||
esac
|
||||
AC_SUBST(TARGET)
|
||||
case "$host_cpu" in
|
||||
# force us down to '386 if we're on some other machine.
|
||||
*?86*) host_cpu='i386'
|
||||
CPU=386
|
||||
;;
|
||||
*) CPU=$host_cpu;
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_SUBST(CPU)
|
||||
|
||||
|
||||
dnl Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
AC_CHECK_PROG(USE_OBJCOPY, objcopy, yes, no)
|
||||
|
||||
dnl Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS(\
|
||||
unistd.h \
|
||||
stdlib.h \
|
||||
errno.h \
|
||||
fcntl.h \
|
||||
stdarg.h \
|
||||
string.h \
|
||||
scsi/scsi.h \
|
||||
scsi/scsi_ioctl.h \
|
||||
scsi/sg.h \
|
||||
sys/gscdds.h \
|
||||
camlib.h \
|
||||
cam/cam_ccb.h \
|
||||
cam/scsi/scsi_message.h \
|
||||
sys/fsid.h \
|
||||
sys/fstyp.h \
|
||||
sys/stat.h \
|
||||
sys/types.h \
|
||||
sys/mnttab.h \
|
||||
sys/param.h \
|
||||
sys/time.h \
|
||||
sys/scsi/impl/uscsi.h \
|
||||
sys/scsi.h \
|
||||
sys/scsi_ctl.h \
|
||||
sys/ioctl.h \
|
||||
sys/mtio.h \
|
||||
sys/param.h \
|
||||
dslib.h \
|
||||
du/defs.h \
|
||||
ddk/ntddscsi.h)
|
||||
|
||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
AC_TYPE_SIZE_T
|
||||
AC_TYPE_PID_T
|
||||
AC_HEADER_TIME
|
||||
AC_STRUCT_TM
|
||||
AC_CHECK_SIZEOF(int)
|
||||
AC_CHECK_SIZEOF(long)
|
||||
AC_C_BIGENDIAN
|
||||
|
||||
|
||||
|
||||
dnl Checks for library functions.
|
||||
dnl AC_FUNC_ALLOCA
|
||||
|
||||
AC_TYPE_SIGNAL
|
||||
AC_FUNC_VPRINTF
|
||||
|
||||
dnl Check for files
|
||||
|
||||
AC_OUTPUT(Makefile)
|
||||
209
mtx-1.3.12/contrib/MTX.html
Normal file
209
mtx-1.3.12/contrib/MTX.html
Normal file
@@ -0,0 +1,209 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>TapeChanger::MTX - use 'mtx' to manipulate a tape library</TITLE>
|
||||
<LINK REV="made" HREF="mailto:none">
|
||||
</HEAD>
|
||||
|
||||
<BODY>
|
||||
|
||||
<A NAME="__index__"></A>
|
||||
<!-- INDEX BEGIN -->
|
||||
|
||||
<UL>
|
||||
|
||||
<LI><A HREF="#name">NAME</A></LI>
|
||||
<LI><A HREF="#synopsis">SYNOPSIS</A></LI>
|
||||
<LI><A HREF="#description">DESCRIPTION</A></LI>
|
||||
<LI><A HREF="#variables">VARIABLES</A></LI>
|
||||
<LI><A HREF="#usage">USAGE</A></LI>
|
||||
<LI><A HREF="#notes">NOTES</A></LI>
|
||||
<LI><A HREF="#requirements">REQUIREMENTS</A></LI>
|
||||
<LI><A HREF="#todo">TODO</A></LI>
|
||||
<LI><A HREF="#see also">SEE ALSO</A></LI>
|
||||
<LI><A HREF="#author">AUTHOR</A></LI>
|
||||
<LI><A HREF="#copyright">COPYRIGHT</A></LI>
|
||||
</UL>
|
||||
<!-- INDEX END -->
|
||||
|
||||
<HR>
|
||||
<P>
|
||||
<H1><A NAME="name">NAME</A></H1>
|
||||
<P>TapeChanger::MTX - use 'mtx' to manipulate a tape library</P>
|
||||
<P>
|
||||
<HR>
|
||||
<H1><A NAME="synopsis">SYNOPSIS</A></H1>
|
||||
<PRE>
|
||||
use TapeChanger::MTX;</PRE>
|
||||
<PRE>
|
||||
my $loaded = TapeChanger::MTX->loadedtape;
|
||||
print "Currently loaded: $loaded\n" if ($loaded);</PRE>
|
||||
<PRE>
|
||||
TapeChanger::MTX->loadtape('next');
|
||||
my $nowloaded = TapeChanger::MTX->loadedtape;
|
||||
print "Currently loaded: $nowloaded\n" if ($nowloaded);
|
||||
</PRE>
|
||||
<PRE>
|
||||
|
||||
See below for more available functions.</PRE>
|
||||
<P>
|
||||
<HR>
|
||||
<H1><A NAME="description">DESCRIPTION</A></H1>
|
||||
<P>TapeChanger::MTX is a module to manipulate a tape library using the 'mtx'
|
||||
tape library program. It is meant to work with a simple shell/perl script
|
||||
to load and unload tapes as appropriate, and to provide a interface for
|
||||
more complicated programs to do the same. The below functions and
|
||||
variables should do as good a job as explaining this as anything.</P>
|
||||
<P>
|
||||
<HR>
|
||||
<H1><A NAME="variables">VARIABLES</A></H1>
|
||||
<DL>
|
||||
<DT><STRONG><A NAME="item_%24TapeChanger%3A%3AMTX%3A%3AMT_%3Ditem_%24TapeCha">$TapeChanger::MTX::MT
|
||||
=item $TapeChanger::MTX::MTX</A></STRONG><BR>
|
||||
<DD>
|
||||
What is the location of the 'mt' and 'mtx' binaries? Can be set with
|
||||
'$MT' and '$MTX' in ~/.mtxrc, or defaults to '/usr/sbin/mt' and
|
||||
'/usr/local/sbin/mtx'.
|
||||
<P></P>
|
||||
<DT><STRONG><A NAME="item_%24TapeChanger%3A%3AMTX%3A%3ADRIVE">$TapeChanger::MTX::DRIVE</A></STRONG><BR>
|
||||
<DD>
|
||||
<DT><STRONG><A NAME="item_%24TapeChanger%3A%3AMTX%3A%3ACONTROL">$TapeChanger::MTX::CONTROL</A></STRONG><BR>
|
||||
<DD>
|
||||
What are the names of the tape (DRIVE) and changer (CONTROL) device
|
||||
nodes? Can be set with $DRIVE or $CONTROL in ~/.mtxrc, or default to
|
||||
'/dev/rmt/0' and '/dev/changer' respectively.
|
||||
<P></P>
|
||||
<DT><STRONG><A NAME="item_%24TapeChanger%3A%3AMTX%3A%3AEJECT">$TapeChanger::MTX::EJECT</A></STRONG><BR>
|
||||
<DD>
|
||||
Does the tape drive have to eject the tape before the changer retrieves
|
||||
it? It's okay to say 'yes' if it's not necessary, in most cases. Can be
|
||||
set with $EJECT in ~/.mtxrc, or defaults to '1'.
|
||||
<P></P>
|
||||
<DT><STRONG><A NAME="item_%24TapeChanger%3A%3AMTX%3A%3AREADY_TIME">$TapeChanger::MTX::READY_TIME</A></STRONG><BR>
|
||||
<DD>
|
||||
How long should we wait to see if the drive is ready, in seconds, after
|
||||
mounting a volume? Can be set with $READY_TIME in ~/.mtxrc, or defaults
|
||||
to 60.
|
||||
<P></P>
|
||||
<DT><STRONG><A NAME="item_%24TapeChanger%3A%3AMTX%3A%3ADEBUG">$TapeChanger::MTX::DEBUG</A></STRONG><BR>
|
||||
<DD>
|
||||
Print debugging information? Set to '0' for normal verbosity, '1' for
|
||||
debugging information, or '-1' for 'quiet mode' (be as quiet as possible).
|
||||
<P></P></DL>
|
||||
<P>
|
||||
<HR>
|
||||
<H1><A NAME="usage">USAGE</A></H1>
|
||||
<P>This module uses the following functions:</P>
|
||||
<DL>
|
||||
<DT><STRONG><A NAME="item_tape_cmd">tape_cmd ( COMMAND )</A></STRONG><BR>
|
||||
<DD>
|
||||
<DT><STRONG><A NAME="item_mt_cmd">mt_cmd ( COMMAND )</A></STRONG><BR>
|
||||
<DD>
|
||||
Runs 'mtx' and 'mt' as appropriate. <CODE>COMMAND</CODE> is the command you're
|
||||
trying to send to them. Uses 'warn()' to print the commands to the screen
|
||||
if $TapeChanger::MTX::DEBUG is set.
|
||||
<P></P>
|
||||
<DT><STRONG><A NAME="item_numdrives">numdrives ()</A></STRONG><BR>
|
||||
<DD>
|
||||
<DT><STRONG><A NAME="item_numslots">numslots ()</A></STRONG><BR>
|
||||
<DD>
|
||||
<DT><STRONG><A NAME="item_loadedtape">loadedtape ()</A></STRONG><BR>
|
||||
<DD>
|
||||
Returns the number of drives, number of slots, and currently loaded tape
|
||||
values, respectively, by parsing <STRONG>tape_cmd('status')</STRONG>.
|
||||
<P></P>
|
||||
<DT><STRONG><A NAME="item_loadtape">loadtape ( SLOT [, DRIVE] )</A></STRONG><BR>
|
||||
<DD>
|
||||
Loads a tape into the tape changer, and waits until the drive is again
|
||||
ready to be written to. <CODE>SLOT</CODE> can be any of the following (with the
|
||||
relevant function indicated):
|
||||
<PRE>
|
||||
current C<loadedtape()>
|
||||
prev C<loadprevtape()>
|
||||
next C<loadnexttape()>
|
||||
first C<loadfirsttape()>
|
||||
last C<loadlasttape()>
|
||||
0 C<_ejectdrive()>
|
||||
1..99 Loads the specified tape number, ejecting whatever is
|
||||
currently in the drive.</PRE>
|
||||
<P><CODE>DRIVE</CODE> is the drive to load, and defaults to 0. Returns 0 if
|
||||
successful, an error string otherwise.</P>
|
||||
<P></P>
|
||||
<DT><STRONG><A NAME="item_loadnexttape">loadnexttape ()</A></STRONG><BR>
|
||||
<DD>
|
||||
<DT><STRONG><A NAME="item_loadprevtape">loadprevtape ()</A></STRONG><BR>
|
||||
<DD>
|
||||
<DT><STRONG><A NAME="item_loadfirsttape">loadfirsttape ()</A></STRONG><BR>
|
||||
<DD>
|
||||
<DT><STRONG><A NAME="item_loadlasttape">loadlasttape ()</A></STRONG><BR>
|
||||
<DD>
|
||||
Loads the next, previous, first, and last tapes in the changer
|
||||
respectively. Use <STRONG>tape_cmd('next')</STRONG>, <STRONG>tape_cmd('previous')</STRONG>,
|
||||
<STRONG>tape_cmd('first')</STRONG>, and <STRONG>tape_cmd('last')</STRONG>, respectively.
|
||||
<P></P>
|
||||
<DT><STRONG><A NAME="item_ejecttape">ejecttape ()</A></STRONG><BR>
|
||||
<DD>
|
||||
Ejects the tape, by first ejecting the tape from the drive
|
||||
(<STRONG>mt_cmd(rewind)</STRONG> then <STRONG>mt_cmd(offline)</STRONG>) and then returning it to its
|
||||
slot (<STRONG>tape_cmd(unload)</STRONG>). Returns 1 if successful, 0 otherwise.
|
||||
<P></P>
|
||||
<DT><STRONG><A NAME="item_resetchanger">resetchanger ()</A></STRONG><BR>
|
||||
<DD>
|
||||
Resets the changer, ejecting the tape and loading the first one from the
|
||||
changer.
|
||||
<P></P>
|
||||
<DT><STRONG><A NAME="item_checkdrive">checkdrive ()</A></STRONG><BR>
|
||||
<DD>
|
||||
Checks to see if the drive is ready or not, by waiting for up to
|
||||
$TapeChanger::MTX::READY_TIME seconds to see if it can get status
|
||||
information using <STRONG>mt_cmd(status)</STRONG>. Returns 1 if so, 0 otherwise.
|
||||
<P></P>
|
||||
<DT><STRONG><A NAME="item_reportstatus">reportstatus</A></STRONG><BR>
|
||||
<DD>
|
||||
Returns a string containing the loaded tape and the drive that it's
|
||||
mounted on.
|
||||
<P></P>
|
||||
<DT><STRONG><A NAME="item_cannot_run">cannot_run ()</A></STRONG><BR>
|
||||
<DD>
|
||||
Does some quick checks to see if you're actually capable of using this
|
||||
module, based on your user permissions. Returns a list of problems if
|
||||
there are any, 0 otherwise.
|
||||
<P></P></DL>
|
||||
<P>
|
||||
<HR>
|
||||
<H1><A NAME="notes">NOTES</A></H1>
|
||||
<P>~/.mtxrc is automatically loaded when this module is used, if it exists,
|
||||
using do(). This could cause security problems if you're trying to use
|
||||
this with <CODE>setuid()</CODE> programs - so just don't do that. If you want someone
|
||||
to have permission to mess with the tape drive and/or changer, let them
|
||||
have that permission directly.</P>
|
||||
<P>
|
||||
<HR>
|
||||
<H1><A NAME="requirements">REQUIREMENTS</A></H1>
|
||||
<P>Perl 5.6.0 or better, an installed 'mtx' binary, and a tape changer and
|
||||
reader connected to the system.</P>
|
||||
<P>
|
||||
<HR>
|
||||
<H1><A NAME="todo">TODO</A></H1>
|
||||
<P>Support for Input/Export slots is not included, though it may be later.
|
||||
Possibly works for multiple drives per changer, but I haven't tested it,
|
||||
so I probably missed something. 'load previous' doesn't actually work,
|
||||
because mtx doesn't support it (though the help says it does).</P>
|
||||
<P>
|
||||
<HR>
|
||||
<H1><A NAME="see also">SEE ALSO</A></H1>
|
||||
<P><STRONG>mtx</STRONG>, <STRONG>mt</STRONG>, <STRONG>tapechanger</STRONG>. Inspired by <STRONG>stc-changer</STRONG>, which comes
|
||||
with the AMANDA tape backup package (http://www.amanda.org), and MTX,
|
||||
available at <A HREF="http://mtx.sourceforge.net.">http://mtx.sourceforge.net.</A></P>
|
||||
<P>
|
||||
<HR>
|
||||
<H1><A NAME="author">AUTHOR</A></H1>
|
||||
<P>Tim Skirvin <<A HREF="mailto:tskirvin@uiuc.edu">tskirvin@uiuc.edu</A>></P>
|
||||
<P>
|
||||
<HR>
|
||||
<H1><A NAME="copyright">COPYRIGHT</A></H1>
|
||||
<P>Copyright 2001-2002 by the University of Illinois Board of Trustees and
|
||||
Tim Skirvin <<A HREF="mailto:tskirvin@ks.uiuc.edu">tskirvin@ks.uiuc.edu</A>>.</P>
|
||||
|
||||
</BODY>
|
||||
|
||||
</HTML>
|
||||
3
mtx-1.3.12/contrib/README
Normal file
3
mtx-1.3.12/contrib/README
Normal file
@@ -0,0 +1,3 @@
|
||||
Everything in here is copyrighted by its original copyright holder.
|
||||
The contents of this directory are not maintained as part of the 'mtx'
|
||||
project, they are maintained by their original copyright holders.
|
||||
BIN
mtx-1.3.12/contrib/TapeChanger-MTX-0.71b.tar.gz
Normal file
BIN
mtx-1.3.12/contrib/TapeChanger-MTX-0.71b.tar.gz
Normal file
Binary file not shown.
151
mtx-1.3.12/contrib/config_sgen_solaris.sh
Executable file
151
mtx-1.3.12/contrib/config_sgen_solaris.sh
Executable file
@@ -0,0 +1,151 @@
|
||||
#!/bin/sh
|
||||
# Copyright 2001 Enhanced Software Technologies Inc.
|
||||
# All Rights Reserved
|
||||
#
|
||||
# This software is licensed under the terms of the Free Software Foundation's
|
||||
# General Public License, version 2. See http://www.fsf.org for more
|
||||
# inforation on the General Public License. It is released for public use in
|
||||
# the hope that others will find it useful. Please contact eric@estinc.com
|
||||
# if you have problems. Also check out our backup products at
|
||||
# http://www.estinc.com (grin).
|
||||
#
|
||||
# usage: config_sgen_solaris.sh check|[un]install
|
||||
#
|
||||
# This configures sgen under Solaris (we hope! :-). Note that this
|
||||
# *CAN* do a reboot of the system. Do NOT call this function unless
|
||||
# you are willing to let it do a reboot of the system! Also note that
|
||||
# this *must* be run as user 'root', since it does highly grokety things.
|
||||
|
||||
|
||||
mode="$1"
|
||||
cvs upd
|
||||
SGEN="/kernel/drv/sgen"
|
||||
SGEN_CONF="/kernel/drv/sgen.conf"
|
||||
|
||||
do_check() {
|
||||
if test ! -f $SGEN_CONF; then
|
||||
# sgen.conf not installed...
|
||||
return 1
|
||||
fi
|
||||
|
||||
changer_type_count=`grep "changer" $SGEN_CONF | grep -v "^#" | wc -l`
|
||||
target_count=`grep "target=" $SGEN_CONF | grep -v "^#" | wc -l`
|
||||
|
||||
if test $changer_type_count = 0 -o $target_count = 0; then
|
||||
# sgen.conf not configured
|
||||
return 1
|
||||
fi
|
||||
|
||||
# sgen.conf installed, and configured
|
||||
return 0
|
||||
}
|
||||
|
||||
do_install() {
|
||||
|
||||
# see if already installed
|
||||
do_check
|
||||
if test $? = 0; then
|
||||
echo "sgen already configured, skipping"
|
||||
return 0 # successfully installed (?)
|
||||
fi
|
||||
|
||||
if test ! -f $SGEN; then
|
||||
echo "sgen driver not installed, aborting"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "configuring sgen driver..."
|
||||
|
||||
echo 'device-type-config-list="changer"; # BRU-PRO' >>$SGEN_CONF
|
||||
target=0
|
||||
while test $target -le 15; do
|
||||
echo "name=\"sgen\" class=\"scsi\" target=$target lun=0; # BRU-PRO" >>$SGEN_CONF
|
||||
target=`expr $target + 1`
|
||||
done
|
||||
|
||||
echo "Attempting to reload driver..."
|
||||
rem_drv sgen >/dev/null 2>&1
|
||||
add_drv sgen
|
||||
if test "$?" != "0"; then
|
||||
# failed
|
||||
touch /reconfigure
|
||||
echo "Driver was successfully configured, but could not be re-loaded."
|
||||
echo "The system must be rebooted for the driver changes to take effect."
|
||||
|
||||
ans=""
|
||||
while test "$ans" = ""; do
|
||||
printf "Do you want to reboot now (shutdown -g 1 -y -i 6)? [Y/n] "
|
||||
read ans
|
||||
|
||||
if test "$ans" = "Y"; then
|
||||
ans="y"
|
||||
fi
|
||||
|
||||
if test "$ans" = "N"; then
|
||||
ans="n"
|
||||
fi
|
||||
|
||||
if test "$ans" != "y" -a "$ans" != "n"; then
|
||||
echo "Please enter 'y' or 'n'"
|
||||
ans=""
|
||||
fi
|
||||
done
|
||||
|
||||
if test "$ans" = "y"; then
|
||||
shutdown -g 1 -y -i 6
|
||||
# will be killed by reboot...
|
||||
while true; do
|
||||
echo "Waiting for reboot..."
|
||||
sleep 300
|
||||
done
|
||||
fi
|
||||
|
||||
# not rebooted, exit with error
|
||||
return 2
|
||||
fi
|
||||
|
||||
# successful
|
||||
return 0
|
||||
}
|
||||
|
||||
do_uninstall() {
|
||||
do_check
|
||||
if test $? = 1; then
|
||||
echo "sgen not configured, skipping"
|
||||
return 0 # successfully uninstalled (?)
|
||||
fi
|
||||
|
||||
printf "removing BRU-PRO configuration from $SGEN_CONF..."
|
||||
grep -v "# BRU-PRO" $SGEN_CONF > ${SGEN_CONF}.$$ || return 1
|
||||
cat ${SGEN_CONF}.$$ >${SGEN_CONF} || return 1
|
||||
rm -f ${SGEN_CONF}.$$ >/dev/null || return 1
|
||||
printf "done\n"
|
||||
|
||||
touch /reconfigure
|
||||
printf "Devices will be reconfigured at next reboot.\n"
|
||||
return 0
|
||||
}
|
||||
|
||||
uname | grep SunOS >/dev/null 2>&1
|
||||
if test $? != 0; then
|
||||
echo "$0: not on Solaris, ABORT!"
|
||||
exit 99
|
||||
fi
|
||||
|
||||
case "$mode" in
|
||||
check)
|
||||
do_check
|
||||
;;
|
||||
install)
|
||||
do_install
|
||||
;;
|
||||
uninstall)
|
||||
do_uninstall
|
||||
;;
|
||||
*)
|
||||
echo "usage: $0 check|[un]install"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit $?
|
||||
431
mtx-1.3.12/contrib/mtx-changer
Executable file
431
mtx-1.3.12/contrib/mtx-changer
Executable file
@@ -0,0 +1,431 @@
|
||||
#! /bin/sh
|
||||
###############################################################################
|
||||
# AMANDA Tape Changer script for use with the MTX tape changer program
|
||||
# Version 1.0 - Tue Feb 20 13:59:39 CST 2001
|
||||
#
|
||||
# Based on 'stc-changer' by Eric Berggren (eric@ee.pdx.edu)
|
||||
# Updated by Tim Skirvin (tskirvin@ks.uiuc.edu)
|
||||
#
|
||||
# Given that there's no license...let's make this the Perl Artistic License.
|
||||
# Just make sure you give me and Eric credit if you modify this.
|
||||
###############################################################################
|
||||
|
||||
### USER CONFIGURATION
|
||||
# Name of the tape drive (takes place of "tapedev" option in amanda.conf)
|
||||
# and default driver number in library (usu 0) that DRIVE_NAME points to
|
||||
DRIVE_NAME="/dev/rmt/0n"
|
||||
DRIVE_NUM=0
|
||||
|
||||
# Location of "STC" command and control device
|
||||
MTX_CMD="/usr/local/sbin/mtx";
|
||||
MTX_CONTROL="/dev/scsi/changer/c4t1d0";
|
||||
|
||||
# Whether tape drive must eject tape before changer retrieves
|
||||
# (ie, EXB-2x0). Usually okay if set while not necessary, bad if
|
||||
# required but not set.
|
||||
DRIVE_MUST_EJECT=1
|
||||
|
||||
# How long to check drive readiness (in seconds) after mounting (or
|
||||
# ejecting) a volume (on some libraries, the motion or eject command may
|
||||
# complete before the drive has the volume fully mounted and online,
|
||||
# or ready for retrieval, resulting in "Drive not ready"/"Media not
|
||||
# ready" errors). Do an "mt status" command every 5 seconds upto this
|
||||
# time.
|
||||
DRIVE_READY_TIME_MAX=120
|
||||
|
||||
# tape "mt" command location...
|
||||
MT_CMD="/usr/bin/mt" # called via "MT_CMD -f DRIVE_NAME rewind" &
|
||||
# "MT_CMD -f DRIVE_NAME offline" to eject
|
||||
# and "MT_CMD -f DRIVE_NAME status" to get ready info
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
NumDrives=-1
|
||||
NumSlots=-1
|
||||
LastSlot=-1
|
||||
LoadedTape=-1
|
||||
|
||||
#
|
||||
# Usage information
|
||||
#
|
||||
usage()
|
||||
{
|
||||
echo
|
||||
echo "Usage: $Progname <command> [arg...]"
|
||||
echo " -info reports capability and loaded tape"
|
||||
echo " -slot <slot> loads specified tape into drive"
|
||||
echo " current reports current mounted tape"
|
||||
echo " next loads logically next tape (loops to top)"
|
||||
echo " prev loads logically previous tape (loops to bot)"
|
||||
echo " first loads first tape"
|
||||
echo " last loads last tape"
|
||||
echo " 0..99 loads tape from specified slot#"
|
||||
echo " -eject uloads current mounted tape"
|
||||
echo " -reset resets changer (and drive); loads first tape"
|
||||
echo
|
||||
exit 5
|
||||
}
|
||||
|
||||
#
|
||||
# Perform "stc" changer command (& handle the "fatal" errors)
|
||||
# else, set 'CommandResStr' and 'CommandRawResStr' to the result string
|
||||
# and 'CommandResCode' to the exit code
|
||||
#
|
||||
dotapecmd()
|
||||
{
|
||||
cmd=$1
|
||||
arg=$2
|
||||
|
||||
CommandResStr=`$MTX_CMD $MTX_CONTROL $cmd $arg 2>&1`
|
||||
CommandRawResStr=$CommandResStr
|
||||
CommandResCode=$?
|
||||
|
||||
CommandResStr=`echo $CommandResStr | head -1 | sed 's/^[^:]*: //'`
|
||||
if [ $CommandResCode -gt 1 ]; then
|
||||
echo "0 $Progname: returned $CommandResStr"
|
||||
exit 2
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# Unload tape from drive (a drive command; "ejecttape" is a changer command
|
||||
# to actually retrieve the tape). Needed by some changers (controlled by
|
||||
# setting "DRIVE_MUST_EJECT")
|
||||
#
|
||||
ejectdrive()
|
||||
{
|
||||
# Tell drive to eject tape before changer retrieves; req'd by some
|
||||
# drives (ie, EXB-2x0). Not needed by QDLT-4x00. Do a "rewind"
|
||||
# command first, then "offline" to eject (instead of "rewoffl")
|
||||
#
|
||||
if [ "$DRIVE_MUST_EJECT" -ne 0 ]; then
|
||||
mtresstr=`$MT_CMD -f $DRIVE_NAME rewind 2>&1`
|
||||
mtrescode=$?
|
||||
|
||||
if [ $mtrescode -ne 0 ]; then
|
||||
if echo "$mtresstr" | egrep -s 'no tape'; then
|
||||
:; # no tape mounted; assume okay...
|
||||
else
|
||||
# can't eject tape, bad; output: <tape#> reason
|
||||
echo "0 $mtresstr"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
mtresstr=`$MT_CMD -f $DRIVE_NAME offline 2>&1`
|
||||
mtrescode=$?
|
||||
|
||||
checkdrive 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# Check drive readiness after (un)mounting a volume (which may take a while
|
||||
# after the volume change command completes)
|
||||
#
|
||||
checkdrive()
|
||||
{
|
||||
unmounting=$1
|
||||
|
||||
if [ "$DRIVE_READY_TIME_MAX" -gt 0 ]; then
|
||||
|
||||
# sleep time between checks
|
||||
pausetime=5
|
||||
|
||||
# number of interations to check
|
||||
numchecks=`expr $DRIVE_READY_TIME_MAX / $pausetime`
|
||||
if [ "$numchecks" -eq 0 ]; then
|
||||
numchecks=1
|
||||
fi
|
||||
|
||||
# check until success, or out of attempts...
|
||||
while [ "$numchecks" -gt 0 ]; do
|
||||
mtresstr=`$MT_CMD -f $DRIVE_NAME status 2>&1`
|
||||
mtrescode=$?
|
||||
|
||||
if [ $mtrescode -eq 0 ]; then
|
||||
# Success ?
|
||||
return 0
|
||||
else
|
||||
# pause, before trying again....
|
||||
if [ "$numchecks" -gt 1 ]; then
|
||||
sleep $pausetime
|
||||
|
||||
# if unmounting a volume, check for 'mt' command
|
||||
# failure; (sleep first for additional comfort)
|
||||
if [ "$unmounting" -ne 0 ]; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
numchecks=`expr $numchecks - 1`
|
||||
done
|
||||
|
||||
# failed; output: -1 reason
|
||||
echo "-1 drive won't report ready"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# Get changer parameters
|
||||
#
|
||||
getchangerparms()
|
||||
{
|
||||
dotapecmd status
|
||||
if [ $CommandResCode -eq 0 ] && \
|
||||
echo "$CommandResStr" | egrep -s '^Storage Changer'; then
|
||||
|
||||
NumDrives=`echo $dspec | wc -l`
|
||||
NumDrives=`echo "$CommandRawResStr" | \
|
||||
grep 'Data Transfer Element' | wc -l`
|
||||
if [ "$NumDrives" -le "$DRIVE_NUM" ]; then
|
||||
echo "$Program: Invalid drive # specified ($DRIVE_NUM > $NumDrives)"
|
||||
exit 3
|
||||
fi
|
||||
# grep 'Data Transfer Element $DRIVE_NUM' | \
|
||||
LoadedTape=`echo "$CommandRawResStr" | \
|
||||
grep 'Data Transfer Element' | \
|
||||
grep 'Storage Element [0-9]' | \
|
||||
awk '{ print $7 }' `
|
||||
if [ -z "$LoadedTape" -o "$LoadedTape" = "e" ]; then
|
||||
LoadedTape=-1
|
||||
fi
|
||||
NumSlots=`echo "$CommandRawResStr" | \
|
||||
grep 'Storage Element [0-9]\{1,\}:' | \
|
||||
grep -v 'Data Element' | \
|
||||
wc -l | sed -e 's/ //g' `
|
||||
LastSlot=`expr $NumSlots - 1`
|
||||
else
|
||||
echo \
|
||||
"$Progname: Can't get changer parameters; Result was $CommandResStr"
|
||||
exit 3
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# Display changer info
|
||||
#
|
||||
changerinfo()
|
||||
{
|
||||
getchangerparms
|
||||
|
||||
# output status string: currenttape numslots randomaccess?
|
||||
echo "$LoadedTape $NumSlots 1"
|
||||
exit 0
|
||||
}
|
||||
|
||||
#
|
||||
# Eject current mounted tape
|
||||
#
|
||||
ejecttape()
|
||||
{
|
||||
getchangerparms
|
||||
ct=$LoadedTape
|
||||
|
||||
# If no tape reported mounted, assume success (could be bad if changer
|
||||
# lost track of tape)
|
||||
#
|
||||
if [ $ct -lt 0 ]; then
|
||||
CommandResCode=0
|
||||
else
|
||||
ejectdrive
|
||||
dotapecmd unload
|
||||
fi
|
||||
|
||||
if [ $CommandResCode -ne 0 ]; then
|
||||
# failed; output: <tape#> reason
|
||||
echo "$ct $CommandResStr"
|
||||
exit 1
|
||||
else
|
||||
# success; output: <tape#> drive
|
||||
echo "$ct $DRIVE_NAME"
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# Move specified tape into drive (operation level)
|
||||
#
|
||||
doloadtape()
|
||||
{
|
||||
slot=$1
|
||||
if [ "$slot" -eq "$LoadedTape" ]; then
|
||||
return 0
|
||||
fi
|
||||
ejectdrive
|
||||
dotapecmd load $slot
|
||||
return $CommandResCode
|
||||
}
|
||||
|
||||
#
|
||||
# Load next available tape into drive
|
||||
#
|
||||
loadnexttape()
|
||||
{
|
||||
curslot=$1
|
||||
direction=$2
|
||||
|
||||
startslot=$curslot
|
||||
while true; do
|
||||
if doloadtape $curslot; then
|
||||
return 0
|
||||
else
|
||||
if echo $CommandResStr | egrep -s 'Slot.*reported empty'; then
|
||||
|
||||
if [ "$direction" -lt 0 ]; then
|
||||
curslot=`expr $curslot - 1`
|
||||
if [ "$curslot" -lt 0 ]; then
|
||||
curslot=$LastSlot
|
||||
fi
|
||||
else
|
||||
curslot=`expr $curslot + 1`
|
||||
if [ "$curslot" -gt "$LastSlot" ]; then
|
||||
curslot=0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if we're back to where we started...
|
||||
if [ "$curslot" = "$startslot" ]; then
|
||||
if [ "$direction" -lt 0 ]; then
|
||||
CommandResStr="No previous volume available"
|
||||
else
|
||||
CommandResStr="No subsequent volume available"
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
#
|
||||
# Report loadtape() status
|
||||
#
|
||||
reportstatus()
|
||||
{
|
||||
if [ $CommandResCode -eq 0 ]; then
|
||||
# success; output currenttape drivename
|
||||
echo "$LoadedTape $DRIVE_NAME"
|
||||
exit 0
|
||||
else
|
||||
# failed (empty slot?); output currenttape reason
|
||||
echo "$LoadedTape $CommandResStr"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Move specified tape into drive (command level)
|
||||
#
|
||||
loadtape()
|
||||
{
|
||||
slot=$1
|
||||
|
||||
getchangerparms
|
||||
|
||||
case "$slot" in
|
||||
current)
|
||||
if [ $LoadedTape -lt 0 ]; then
|
||||
CommandResStr="Can't determine current tape; drive empty ?"
|
||||
CommandResCode=1
|
||||
fi
|
||||
;;
|
||||
prev)
|
||||
if [ $LoadedTape -le 0 ]; then
|
||||
loadnexttape $LastSlot -1
|
||||
else
|
||||
loadnexttape `expr $LoadedTape - 1` -1
|
||||
fi
|
||||
;;
|
||||
next)
|
||||
if [ $LoadedTape -ge $LastSlot -o $LoadedTape -lt 0 ]; then
|
||||
loadnexttape 0 1
|
||||
else
|
||||
loadnexttape `expr $LoadedTape + 1` 1
|
||||
fi
|
||||
;;
|
||||
first)
|
||||
loadnexttape 0 1
|
||||
;;
|
||||
last)
|
||||
loadnexttape $LastSlot -1
|
||||
;;
|
||||
[0-9]*)
|
||||
doloadtape $slot
|
||||
;;
|
||||
*)
|
||||
# error; no valid slot specified
|
||||
echo "$Progname: No valid slot specified"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ $CommandResCode -eq 0 ]; then
|
||||
getchangerparms
|
||||
checkdrive
|
||||
fi
|
||||
reportstatus
|
||||
}
|
||||
|
||||
#
|
||||
# Reset changer to known state
|
||||
#
|
||||
resetchanger()
|
||||
{
|
||||
ejectdrive
|
||||
dotapecmd reset
|
||||
if [ $CommandResCode -ne 0 ]; then
|
||||
# failed; output: failed? reason
|
||||
echo "-1 $CommandResStr"
|
||||
exit 2;
|
||||
else
|
||||
loadtape first
|
||||
fi
|
||||
}
|
||||
|
||||
#############################################################################
|
||||
#
|
||||
# MAIN
|
||||
#
|
||||
Progname=`basename $0`
|
||||
|
||||
if [ ! -x "$MTX_CMD" ]; then
|
||||
echo "-1 $Progname: cannot run STC command ($MTX_CMD)"
|
||||
exit 2
|
||||
fi
|
||||
if [ -n "$MTX_CONTROL" ]; then
|
||||
if echo "$MTX_CONTROL" | egrep -s '^-f'; then
|
||||
:;
|
||||
else
|
||||
MTX_CONTROL="-f $MTX_CONTROL"
|
||||
fi
|
||||
fi
|
||||
if [ -n "$DRIVE_NUM" ]; then
|
||||
DRIVE_NUM=0
|
||||
fi
|
||||
|
||||
if [ $# -ge 1 ]; then command=$1; else command="-usage"; fi
|
||||
|
||||
case "$command" in
|
||||
-info)
|
||||
changerinfo
|
||||
;;
|
||||
-slot)
|
||||
loadtape $2
|
||||
;;
|
||||
-eject)
|
||||
ejecttape
|
||||
;;
|
||||
-reset)
|
||||
resetchanger
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
306
mtx-1.3.12/contrib/mtx.py
Normal file
306
mtx-1.3.12/contrib/mtx.py
Normal file
@@ -0,0 +1,306 @@
|
||||
# Copyright 2000 Enhanced Software Technologies Inc.
|
||||
# Released under Free Software Foundation's General Public License,
|
||||
# Version 2 or above
|
||||
#
|
||||
# This is an example of how to parse the 'mtx' output from a scripting
|
||||
# language.
|
||||
#
|
||||
# Routine to call 'mtx' and read status, or
|
||||
# whatever.
|
||||
#
|
||||
# We do this here rather than creating a Python "C" module because:
|
||||
# 1) Reduces complexity of compile environment
|
||||
# 2) Easier debugging.
|
||||
# 3) More in keeping with the Unix philosophy of things.
|
||||
# 4) Easier to add new functionality.
|
||||
#
|
||||
#
|
||||
|
||||
import string
|
||||
import os
|
||||
import time # we can do some waiting here...
|
||||
|
||||
def readpipe(command):
|
||||
result=""
|
||||
|
||||
infile=os.popen(command,"r")
|
||||
|
||||
try:
|
||||
s=infile.read()
|
||||
except:
|
||||
s=""
|
||||
pass
|
||||
if not s:
|
||||
return None # didn't get anything :-(.
|
||||
result=result+s
|
||||
return result
|
||||
|
||||
|
||||
|
||||
|
||||
# these are returned by the mtx.status routine:
|
||||
class slotstatus:
|
||||
def __init__(self,slotnum,middle,barcode=None):
|
||||
middle=string.strip(middle)
|
||||
try:
|
||||
left,right=string.split(middle," ")
|
||||
except:
|
||||
left=middle
|
||||
right=None
|
||||
pass
|
||||
# Note: We will not be able to test this at the moment since the
|
||||
# 220 has no import/export port!
|
||||
if right=="IMPORT/EXPORT":
|
||||
self.importexport=1
|
||||
else:
|
||||
self.importexport=0
|
||||
pass
|
||||
self.slotnum=int(slotnum) # make sure it's an integer...
|
||||
if left=="Full":
|
||||
self.full=1
|
||||
else:
|
||||
self.full=None
|
||||
pass
|
||||
if not barcode:
|
||||
self.voltag=None
|
||||
else:
|
||||
l=string.split(barcode,"=",1)
|
||||
self.voltag=l[1]
|
||||
pass
|
||||
return
|
||||
pass
|
||||
|
||||
# Drive status lines have this format:
|
||||
#Data Transfer Element 0:Full (Storage Element 10 Loaded):VolumeTag = B0000009H
|
||||
#Data Transfer Element 1:Empty
|
||||
|
||||
class drivestatus:
|
||||
def __init__(self,slotnum,middle,barcode=None):
|
||||
self.slotnum=slotnum
|
||||
if middle=="Empty":
|
||||
self.full=None
|
||||
self.origin=None
|
||||
self.voltag=None
|
||||
return
|
||||
else:
|
||||
self.full=1
|
||||
pass
|
||||
|
||||
# okay, we know we have a tape in the drive.
|
||||
# split and find out our origin: we will always have
|
||||
# an origin, even if the #$@% mtx program had to dig one
|
||||
# out of the air:
|
||||
|
||||
l=string.split(middle," ")
|
||||
self.origin=int(l[3])
|
||||
|
||||
if not barcode:
|
||||
self.voltag=None # barcode of this element.
|
||||
else:
|
||||
l=string.split(barcode," ")
|
||||
self.voltag=string.strip(l[2])
|
||||
pass
|
||||
return
|
||||
pass
|
||||
|
||||
# This is the return value for mtx.status.
|
||||
class mtxstatus:
|
||||
def __init__(self):
|
||||
self.numdrives=None
|
||||
self.numslots=None
|
||||
self.numexport=None
|
||||
self.drives=[] # a list of drivestatus instances.
|
||||
self.slots=[] # a list of slotstatus instances
|
||||
self.export=[] # another list of slotstatus instances
|
||||
return
|
||||
pass
|
||||
|
||||
# call 'mtx' and get barcode info, if possible:
|
||||
# okay, we now have a string that consists of a number of lines.
|
||||
# we want to explode this string into its component parts.
|
||||
# Example format:
|
||||
# Storage Changer /dev/sgd:2 Drives, 21 Slots
|
||||
# Data Transfer Element 0:Full (Storage Element '5' Loaded)
|
||||
# Data Transfer Element 1:Empty
|
||||
# Storage Element 1:Full :VolumeTag=CLNA0001
|
||||
# Storage Element 2:Full :VolumeTag=B0000009
|
||||
# Storage Element 3:Full :VolumeTag=B0000010
|
||||
# ....
|
||||
# What we want to do, then, is:
|
||||
# 1) Turn it into lines by doing a string.split on newline.
|
||||
# 2) Split the 1st line on ":" to get left and right.
|
||||
# 3) Split the right half on space to get #drives "Drives," #slots
|
||||
# 4) process the drives (Full,Empty, etc.)
|
||||
# 5) For each of the remaining lines: Split on ':'
|
||||
# 6) Full/Empty status is in 2)
|
||||
#
|
||||
configdir="/opt/brupro/bin" # sigh.
|
||||
|
||||
def status(device):
|
||||
retval=mtxstatus()
|
||||
command="%s/mtx -f %s status" % (configdir,device)
|
||||
result=readpipe(command)
|
||||
if not result:
|
||||
return None # sorry!
|
||||
# now to parse:
|
||||
|
||||
try:
|
||||
lines=string.split(result,"\n")
|
||||
except:
|
||||
return None # sorry, no status!
|
||||
|
||||
# print "DEBUG:lines=",lines
|
||||
|
||||
try:
|
||||
l=string.split(lines[0],":")
|
||||
except:
|
||||
return None # sorry, no status!
|
||||
|
||||
# print "DEBUG:l=",l
|
||||
leftside=l[0]
|
||||
rightside=l[1]
|
||||
if len(l) > 2:
|
||||
barcode=l[3]
|
||||
else:
|
||||
barcode=None
|
||||
pass
|
||||
t=string.split(rightside)
|
||||
retval.numdrives=int(t[0])
|
||||
retval.numslots=int(t[2])
|
||||
|
||||
for s in lines[1:]:
|
||||
if not s:
|
||||
continue # skip blank lines!
|
||||
#print "DEBUG:s=",s
|
||||
parts=string.split(s,":")
|
||||
leftpart=string.split(parts[0])
|
||||
rightpart=parts[1]
|
||||
try:
|
||||
barcode=parts[2]
|
||||
except:
|
||||
barcode=None
|
||||
pass
|
||||
#print "DEBUG:leftpart=",leftpart
|
||||
if leftpart[0]=="Data" and leftpart[1]=="Transfer":
|
||||
retval.drives.append(drivestatus(leftpart[3],rightpart,barcode))
|
||||
pass
|
||||
if leftpart[0]=="Storage" and leftpart[1]=="Element":
|
||||
element=slotstatus(leftpart[2],rightpart,barcode)
|
||||
if element.importexport:
|
||||
retval.export.append(element)
|
||||
else:
|
||||
retval.slots.append(element)
|
||||
pass
|
||||
pass
|
||||
continue
|
||||
|
||||
return retval
|
||||
|
||||
# Output of a mtx inquiry looks like:
|
||||
#
|
||||
#Product Type: Medium Changer
|
||||
#Vendor ID: 'EXABYTE '
|
||||
#Product ID: 'Exabyte EZ17 '
|
||||
#Revision: '1.07'
|
||||
#Attached Changer: No
|
||||
#
|
||||
# We simply return a hash table with these values { left:right } format.
|
||||
|
||||
def mtxinquiry(device):
|
||||
command="%s/mtx -f %s inquiry" % (configdir,device)
|
||||
str=readpipe(command) # calls the command, returns all its data.
|
||||
|
||||
str=string.strip(str)
|
||||
lines=string.split(str,"\n")
|
||||
retval={}
|
||||
for l in lines:
|
||||
# DEBUG #
|
||||
l=string.strip(l)
|
||||
print "splitting line: '",l,"'"
|
||||
idx,val=string.split(l,':',1)
|
||||
val=string.strip(val)
|
||||
if val[0]=="'":
|
||||
val=val[1:-1] # strip off single quotes, sigh.
|
||||
pass
|
||||
retval[idx]=val
|
||||
continue
|
||||
return retval
|
||||
|
||||
# Now for the easy part:
|
||||
|
||||
def load(device,slot,drive=0):
|
||||
command="%s/mtx -f %s load %s %s >/dev/null " % (configdir,device,slot,drive)
|
||||
status=os.system(command)
|
||||
return status
|
||||
|
||||
def unload(device,slot,drive=0):
|
||||
command="%s/mtx -f %s unload %s %s >/dev/null " % (configdir,device,slot,drive)
|
||||
return os.system(command)
|
||||
|
||||
def inventory(device):
|
||||
command="%s/mtx -f %s inventory >/dev/null " % (configdir,device)
|
||||
return os.system(command)
|
||||
|
||||
def wait_for_inventory(device):
|
||||
# loop while we have an error return...
|
||||
errcount=0
|
||||
while inventory(device):
|
||||
if errcount==0:
|
||||
print "Waiting for loader '%s'" % device
|
||||
pass
|
||||
time.sleep(1)
|
||||
try:
|
||||
s=status(device)
|
||||
except:
|
||||
s=None
|
||||
pass
|
||||
if s:
|
||||
return 0 # well, whatever we're doing, we're inventoried :-(
|
||||
errcount=errcount+1
|
||||
if errcount==600: # we've been waiting for 10 minutes :-(
|
||||
return 1 # sorry!
|
||||
continue
|
||||
return 0 # we succeeded!
|
||||
|
||||
# RCS REVISION LOG:
|
||||
# $Log$
|
||||
# Revision 1.1 2001/06/05 17:10:51 elgreen
|
||||
# Initial revision
|
||||
#
|
||||
# Revision 1.2 2000/12/22 14:17:19 eric
|
||||
# mtx 1.2.11pre1
|
||||
#
|
||||
# Revision 1.14 2000/11/12 20:35:29 eric
|
||||
# do string.strip on the voltag
|
||||
#
|
||||
# Revision 1.13 2000/11/04 00:33:38 eric
|
||||
# if we can get an inventory on the loader after we send it 'mtx inventory',
|
||||
# then obviously we managed to do SOMETHING.
|
||||
#
|
||||
# Revision 1.12 2000/10/28 00:04:34 eric
|
||||
# added wait_for_inventory command
|
||||
#
|
||||
# Revision 1.11 2000/10/27 23:27:58 eric
|
||||
# Added inventory command...
|
||||
#
|
||||
# Revision 1.10 2000/10/01 01:06:29 eric
|
||||
# evening checkin
|
||||
#
|
||||
# Revision 1.9 2000/09/29 02:49:29 eric
|
||||
# evening checkin
|
||||
#
|
||||
# Revision 1.8 2000/09/02 01:05:33 eric
|
||||
# Evening Checkin
|
||||
#
|
||||
# Revision 1.7 2000/09/01 00:08:11 eric
|
||||
# strip lines in mtxinquiry
|
||||
#
|
||||
# Revision 1.6 2000/09/01 00:05:33 eric
|
||||
# debugging
|
||||
#
|
||||
# Revision 1.5 2000/08/31 23:46:01 eric
|
||||
# fix def:
|
||||
#
|
||||
# Revision 1.4 2000/08/31 23:44:06 eric
|
||||
# =->==
|
||||
#
|
||||
BIN
mtx-1.3.12/contrib/mtxctl-0.0.2.tar.gz
Normal file
BIN
mtx-1.3.12/contrib/mtxctl-0.0.2.tar.gz
Normal file
Binary file not shown.
BIN
mtx-1.3.12/contrib/qdback.tar.gz
Normal file
BIN
mtx-1.3.12/contrib/qdback.tar.gz
Normal file
Binary file not shown.
209
mtx-1.3.12/contrib/tapechanger.html
Normal file
209
mtx-1.3.12/contrib/tapechanger.html
Normal file
@@ -0,0 +1,209 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>TapeChanger::MTX - use 'mtx' to manipulate a tape library</TITLE>
|
||||
<LINK REV="made" HREF="mailto:none">
|
||||
</HEAD>
|
||||
|
||||
<BODY>
|
||||
|
||||
<A NAME="__index__"></A>
|
||||
<!-- INDEX BEGIN -->
|
||||
|
||||
<UL>
|
||||
|
||||
<LI><A HREF="#name">NAME</A></LI>
|
||||
<LI><A HREF="#synopsis">SYNOPSIS</A></LI>
|
||||
<LI><A HREF="#description">DESCRIPTION</A></LI>
|
||||
<LI><A HREF="#variables">VARIABLES</A></LI>
|
||||
<LI><A HREF="#usage">USAGE</A></LI>
|
||||
<LI><A HREF="#notes">NOTES</A></LI>
|
||||
<LI><A HREF="#requirements">REQUIREMENTS</A></LI>
|
||||
<LI><A HREF="#todo">TODO</A></LI>
|
||||
<LI><A HREF="#see also">SEE ALSO</A></LI>
|
||||
<LI><A HREF="#author">AUTHOR</A></LI>
|
||||
<LI><A HREF="#copyright">COPYRIGHT</A></LI>
|
||||
</UL>
|
||||
<!-- INDEX END -->
|
||||
|
||||
<HR>
|
||||
<P>
|
||||
<H1><A NAME="name">NAME</A></H1>
|
||||
<P>TapeChanger::MTX - use 'mtx' to manipulate a tape library</P>
|
||||
<P>
|
||||
<HR>
|
||||
<H1><A NAME="synopsis">SYNOPSIS</A></H1>
|
||||
<PRE>
|
||||
use TapeChanger::MTX;</PRE>
|
||||
<PRE>
|
||||
my $loaded = TapeChanger::MTX->loadedtape;
|
||||
print "Currently loaded: $loaded\n" if ($loaded);</PRE>
|
||||
<PRE>
|
||||
TapeChanger::MTX->loadtape('next');
|
||||
my $nowloaded = TapeChanger::MTX->loadedtape;
|
||||
print "Currently loaded: $nowloaded\n" if ($nowloaded);
|
||||
</PRE>
|
||||
<PRE>
|
||||
|
||||
See below for more available functions.</PRE>
|
||||
<P>
|
||||
<HR>
|
||||
<H1><A NAME="description">DESCRIPTION</A></H1>
|
||||
<P>TapeChanger::MTX is a module to manipulate a tape library using the 'mtx'
|
||||
tape library program. It is meant to work with a simple shell/perl script
|
||||
to load and unload tapes as appropriate, and to provide a interface for
|
||||
more complicated programs to do the same. The below functions and
|
||||
variables should do as good a job as explaining this as anything.</P>
|
||||
<P>
|
||||
<HR>
|
||||
<H1><A NAME="variables">VARIABLES</A></H1>
|
||||
<DL>
|
||||
<DT><STRONG><A NAME="item_%24TapeChanger%3A%3AMTX%3A%3AMT_%3Ditem_%24TapeCha">$TapeChanger::MTX::MT
|
||||
=item $TapeChanger::MTX::MTX</A></STRONG><BR>
|
||||
<DD>
|
||||
What is the location of the 'mt' and 'mtx' binaries? Can be set with
|
||||
'$MT' and '$MTX' in ~/.mtxrc, or defaults to '/usr/sbin/mt' and
|
||||
'/usr/local/sbin/mtx'.
|
||||
<P></P>
|
||||
<DT><STRONG><A NAME="item_%24TapeChanger%3A%3AMTX%3A%3ADRIVE">$TapeChanger::MTX::DRIVE</A></STRONG><BR>
|
||||
<DD>
|
||||
<DT><STRONG><A NAME="item_%24TapeChanger%3A%3AMTX%3A%3ACONTROL">$TapeChanger::MTX::CONTROL</A></STRONG><BR>
|
||||
<DD>
|
||||
What are the names of the tape (DRIVE) and changer (CONTROL) device
|
||||
nodes? Can be set with $DRIVE or $CONTROL in ~/.mtxrc, or default to
|
||||
'/dev/rmt/0' and '/dev/changer' respectively.
|
||||
<P></P>
|
||||
<DT><STRONG><A NAME="item_%24TapeChanger%3A%3AMTX%3A%3AEJECT">$TapeChanger::MTX::EJECT</A></STRONG><BR>
|
||||
<DD>
|
||||
Does the tape drive have to eject the tape before the changer retrieves
|
||||
it? It's okay to say 'yes' if it's not necessary, in most cases. Can be
|
||||
set with $EJECT in ~/.mtxrc, or defaults to '1'.
|
||||
<P></P>
|
||||
<DT><STRONG><A NAME="item_%24TapeChanger%3A%3AMTX%3A%3AREADY_TIME">$TapeChanger::MTX::READY_TIME</A></STRONG><BR>
|
||||
<DD>
|
||||
How long should we wait to see if the drive is ready, in seconds, after
|
||||
mounting a volume? Can be set with $READY_TIME in ~/.mtxrc, or defaults
|
||||
to 60.
|
||||
<P></P>
|
||||
<DT><STRONG><A NAME="item_%24TapeChanger%3A%3AMTX%3A%3ADEBUG">$TapeChanger::MTX::DEBUG</A></STRONG><BR>
|
||||
<DD>
|
||||
Print debugging information? Set to '0' for normal verbosity, '1' for
|
||||
debugging information, or '-1' for 'quiet mode' (be as quiet as possible).
|
||||
<P></P></DL>
|
||||
<P>
|
||||
<HR>
|
||||
<H1><A NAME="usage">USAGE</A></H1>
|
||||
<P>This module uses the following functions:</P>
|
||||
<DL>
|
||||
<DT><STRONG><A NAME="item_tape_cmd">tape_cmd ( COMMAND )</A></STRONG><BR>
|
||||
<DD>
|
||||
<DT><STRONG><A NAME="item_mt_cmd">mt_cmd ( COMMAND )</A></STRONG><BR>
|
||||
<DD>
|
||||
Runs 'mtx' and 'mt' as appropriate. <CODE>COMMAND</CODE> is the command you're
|
||||
trying to send to them. Uses 'warn()' to print the commands to the screen
|
||||
if $TapeChanger::MTX::DEBUG is set.
|
||||
<P></P>
|
||||
<DT><STRONG><A NAME="item_numdrives">numdrives ()</A></STRONG><BR>
|
||||
<DD>
|
||||
<DT><STRONG><A NAME="item_numslots">numslots ()</A></STRONG><BR>
|
||||
<DD>
|
||||
<DT><STRONG><A NAME="item_loadedtape">loadedtape ()</A></STRONG><BR>
|
||||
<DD>
|
||||
Returns the number of drives, number of slots, and currently loaded tape
|
||||
values, respectively, by parsing <STRONG>tape_cmd('status')</STRONG>.
|
||||
<P></P>
|
||||
<DT><STRONG><A NAME="item_loadtape">loadtape ( SLOT [, DRIVE] )</A></STRONG><BR>
|
||||
<DD>
|
||||
Loads a tape into the tape changer, and waits until the drive is again
|
||||
ready to be written to. <CODE>SLOT</CODE> can be any of the following (with the
|
||||
relevant function indicated):
|
||||
<PRE>
|
||||
current C<loadedtape()>
|
||||
prev C<loadprevtape()>
|
||||
next C<loadnexttape()>
|
||||
first C<loadfirsttape()>
|
||||
last C<loadlasttape()>
|
||||
0 C<_ejectdrive()>
|
||||
1..99 Loads the specified tape number, ejecting whatever is
|
||||
currently in the drive.</PRE>
|
||||
<P><CODE>DRIVE</CODE> is the drive to load, and defaults to 0. Returns 0 if
|
||||
successful, an error string otherwise.</P>
|
||||
<P></P>
|
||||
<DT><STRONG><A NAME="item_loadnexttape">loadnexttape ()</A></STRONG><BR>
|
||||
<DD>
|
||||
<DT><STRONG><A NAME="item_loadprevtape">loadprevtape ()</A></STRONG><BR>
|
||||
<DD>
|
||||
<DT><STRONG><A NAME="item_loadfirsttape">loadfirsttape ()</A></STRONG><BR>
|
||||
<DD>
|
||||
<DT><STRONG><A NAME="item_loadlasttape">loadlasttape ()</A></STRONG><BR>
|
||||
<DD>
|
||||
Loads the next, previous, first, and last tapes in the changer
|
||||
respectively. Use <STRONG>tape_cmd('next')</STRONG>, <STRONG>tape_cmd('previous')</STRONG>,
|
||||
<STRONG>tape_cmd('first')</STRONG>, and <STRONG>tape_cmd('last')</STRONG>, respectively.
|
||||
<P></P>
|
||||
<DT><STRONG><A NAME="item_ejecttape">ejecttape ()</A></STRONG><BR>
|
||||
<DD>
|
||||
Ejects the tape, by first ejecting the tape from the drive
|
||||
(<STRONG>mt_cmd(rewind)</STRONG> then <STRONG>mt_cmd(offline)</STRONG>) and then returning it to its
|
||||
slot (<STRONG>tape_cmd(unload)</STRONG>). Returns 1 if successful, 0 otherwise.
|
||||
<P></P>
|
||||
<DT><STRONG><A NAME="item_resetchanger">resetchanger ()</A></STRONG><BR>
|
||||
<DD>
|
||||
Resets the changer, ejecting the tape and loading the first one from the
|
||||
changer.
|
||||
<P></P>
|
||||
<DT><STRONG><A NAME="item_checkdrive">checkdrive ()</A></STRONG><BR>
|
||||
<DD>
|
||||
Checks to see if the drive is ready or not, by waiting for up to
|
||||
$TapeChanger::MTX::READY_TIME seconds to see if it can get status
|
||||
information using <STRONG>mt_cmd(status)</STRONG>. Returns 1 if so, 0 otherwise.
|
||||
<P></P>
|
||||
<DT><STRONG><A NAME="item_reportstatus">reportstatus</A></STRONG><BR>
|
||||
<DD>
|
||||
Returns a string containing the loaded tape and the drive that it's
|
||||
mounted on.
|
||||
<P></P>
|
||||
<DT><STRONG><A NAME="item_cannot_run">cannot_run ()</A></STRONG><BR>
|
||||
<DD>
|
||||
Does some quick checks to see if you're actually capable of using this
|
||||
module, based on your user permissions. Returns a list of problems if
|
||||
there are any, 0 otherwise.
|
||||
<P></P></DL>
|
||||
<P>
|
||||
<HR>
|
||||
<H1><A NAME="notes">NOTES</A></H1>
|
||||
<P>~/.mtxrc is automatically loaded when this module is used, if it exists,
|
||||
using do(). This could cause security problems if you're trying to use
|
||||
this with <CODE>setuid()</CODE> programs - so just don't do that. If you want someone
|
||||
to have permission to mess with the tape drive and/or changer, let them
|
||||
have that permission directly.</P>
|
||||
<P>
|
||||
<HR>
|
||||
<H1><A NAME="requirements">REQUIREMENTS</A></H1>
|
||||
<P>Perl 5.6.0 or better, an installed 'mtx' binary, and a tape changer and
|
||||
reader connected to the system.</P>
|
||||
<P>
|
||||
<HR>
|
||||
<H1><A NAME="todo">TODO</A></H1>
|
||||
<P>Support for Input/Export slots is not included, though it may be later.
|
||||
Possibly works for multiple drives per changer, but I haven't tested it,
|
||||
so I probably missed something. 'load previous' doesn't actually work,
|
||||
because mtx doesn't support it (though the help says it does).</P>
|
||||
<P>
|
||||
<HR>
|
||||
<H1><A NAME="see also">SEE ALSO</A></H1>
|
||||
<P><STRONG>mtx</STRONG>, <STRONG>mt</STRONG>, <STRONG>tapechanger</STRONG>. Inspired by <STRONG>stc-changer</STRONG>, which comes
|
||||
with the AMANDA tape backup package (http://www.amanda.org), and MTX,
|
||||
available at <A HREF="http://mtx.sourceforge.net.">http://mtx.sourceforge.net.</A></P>
|
||||
<P>
|
||||
<HR>
|
||||
<H1><A NAME="author">AUTHOR</A></H1>
|
||||
<P>Tim Skirvin <<A HREF="mailto:tskirvin@uiuc.edu">tskirvin@uiuc.edu</A>></P>
|
||||
<P>
|
||||
<HR>
|
||||
<H1><A NAME="copyright">COPYRIGHT</A></H1>
|
||||
<P>Copyright 2001-2002 by the University of Illinois Board of Trustees and
|
||||
Tim Skirvin <<A HREF="mailto:tskirvin@ks.uiuc.edu">tskirvin@ks.uiuc.edu</A>>.</P>
|
||||
|
||||
</BODY>
|
||||
|
||||
</HTML>
|
||||
55
mtx-1.3.12/contrib/tapeinfo.py
Normal file
55
mtx-1.3.12/contrib/tapeinfo.py
Normal file
@@ -0,0 +1,55 @@
|
||||
# Copyright 2000 Enhanced Software Technologies Inc.
|
||||
# All Rights Reserved
|
||||
# Released under Free Software Foundation's General Public License,
|
||||
# Version 2 or above
|
||||
|
||||
# Routine to call 'tapeinfo' and read status for a node. This is an
|
||||
# example of how to parse the 'tapeinfo' output from a scripting language.
|
||||
#
|
||||
|
||||
import os
|
||||
import string
|
||||
import sys
|
||||
|
||||
|
||||
configdir="/opt/brupro/bin" # sigh.
|
||||
|
||||
def inquiry(device):
|
||||
retval={}
|
||||
|
||||
# okay, now do the thing:
|
||||
|
||||
command="%s/tapeinfo -f %s" % (configdir,device)
|
||||
|
||||
# Now to read:
|
||||
|
||||
infile=os.popen(command,"r")
|
||||
|
||||
try:
|
||||
s=infile.readline()
|
||||
except:
|
||||
s=""
|
||||
pass
|
||||
if not s:
|
||||
return None # did not get anything.
|
||||
while s:
|
||||
s=string.strip(s)
|
||||
idx,val=string.split(s,':',1)
|
||||
val=string.strip(val)
|
||||
if val[0]=="'":
|
||||
val=val[1:-1] # strip off single quotes, sigh.
|
||||
val=string.strip(val)
|
||||
pass
|
||||
while "\0" in val:
|
||||
# zapo!
|
||||
val=string.replace(val,"\0","")
|
||||
pass
|
||||
retval[idx]=val
|
||||
try:
|
||||
s=infile.readline()
|
||||
except:
|
||||
s=""
|
||||
pass
|
||||
continue # to top of loop!
|
||||
return retval
|
||||
|
||||
118
mtx-1.3.12/contrib/tapeload.pl
Normal file
118
mtx-1.3.12/contrib/tapeload.pl
Normal file
@@ -0,0 +1,118 @@
|
||||
!/usr/bin/perl
|
||||
########################## tapeload ###########################
|
||||
# This script uses mtx 1.2.9pre2 to load a tape based
|
||||
# on its volume tag. You can
|
||||
# specify a tape drive by number, but if you don`t, it puts the
|
||||
# tape in the first available drive and returns the number of that drive,
|
||||
# both from the standard output and as the exit value.
|
||||
# A negative exit value indicates an error.
|
||||
# If volume tags are missing from any full slot, bar codes are rescanned
|
||||
# automatically.
|
||||
#
|
||||
# usage:
|
||||
# tapeload TAPE_LABEL_1 # Loads tape with label TAPE_LABEL_1 into a drive
|
||||
# or
|
||||
# tapeload TAPE_LABEL_1 1 # Loads tape with label TAPE_LABEL_1 into drive #1
|
||||
#
|
||||
|
||||
# Set this variable to your mtx binary and proper scsi library device.
|
||||
$MTXBIN="/usr/local/bin/mtx -f /dev/sga" ;
|
||||
|
||||
# Additions and corrections are welcome.
|
||||
# This software comes with absolutely no warranty and every other imaginable
|
||||
# disclaimer.
|
||||
# -- Frank Samuelson sam@milagro.lanl.gov
|
||||
##################################################################
|
||||
|
||||
@wt= &mdo("status"); #slurp in the list of slots
|
||||
|
||||
# Check to be certain that every full slot has a volume tag
|
||||
for ($i=0; $i< $#wt; $i++) { # look through every line
|
||||
if ( $wt[$i] =~ /Full/ && $wt[$i] !~ /VolumeTag/ ) {
|
||||
# if the element is full, but there is no volume tag, do inventory
|
||||
@wt= &mdo("inventory status");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#try to find our tape
|
||||
$slot=-1;
|
||||
for ($i=0; $i< $#wt; $i++) { # look through every line
|
||||
if ($wt[$i] =~ / *Storage Element (d*):Full :VolumeTag=(.*)/ ) {
|
||||
if ($ARGV[0] eq $2) { # We found the tape
|
||||
$slot=$1; # set the slot number
|
||||
break; # stop reading the rest of the file.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $slot>0) { # we found the tape you wanted.
|
||||
|
||||
$drivefound=-1; # set flag to bad value
|
||||
for ($i=0; $i< $#wt; $i++) { # look through every line
|
||||
# if this is a tape drive
|
||||
if ($wt[$i] =~ / *Data Transfer Element (d*):(.*)/ ) { #parse the line
|
||||
$drive=$1;
|
||||
$state=$2;
|
||||
# print STDERR "$wt[$i] $drive $state";
|
||||
if ($state =~ /Full/) { # This drive is full.
|
||||
# if we are looking for a particular drive and this is it
|
||||
if ( $#ARGV==1 && $drive == $ARGV[1]) {
|
||||
print STDERR " ERROR: Specified drive $ARGV[1] is full.";
|
||||
print STDERR @wt;
|
||||
exit(-6);
|
||||
}
|
||||
} elsif ($state =~ /Empty/) { #This is a tape drive and it`s empty.
|
||||
if ( $#ARGV==1 ) { # If we want a particular drive
|
||||
if ($drive == $ARGV[1]) { # and this is it,
|
||||
$drivefound=$drive; # mark it so.
|
||||
break;
|
||||
}
|
||||
} else { # If any old drive will do
|
||||
$drivefound=$drive; # Mark it.
|
||||
break;
|
||||
}
|
||||
} else { # This is a tape drive, but what the heck is it?
|
||||
print STDERR " Cannot assess drive status in line";
|
||||
print STDERR $wt[$i];
|
||||
exit(-7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $drivefound < 0 ) { # specified drive was not found
|
||||
print STDERR "Error: Specified drive $ARGV[1] was not found";
|
||||
print STDERR @wt;
|
||||
exit(-8);
|
||||
}
|
||||
# Now we actually load the tape.
|
||||
@dump=&mdo(" load $slot $drivefound ");
|
||||
print "$drivefound";
|
||||
exit($drivefound);
|
||||
# The end.
|
||||
|
||||
|
||||
} else {
|
||||
print STDERR " Ug. Tape $ARGV[0] is not in the library.";
|
||||
print STDERR @wt;
|
||||
exit(-4);
|
||||
}
|
||||
|
||||
|
||||
sub mdo # a subroutine to call mtx ;
|
||||
{
|
||||
# print STDERR "$_[0]";
|
||||
if (!open(FD,"$MTXBIN $_[0] |")) { #call mtx function
|
||||
print STDERR " ERRKK. Could not start mtx ";
|
||||
exit (-9);
|
||||
}
|
||||
|
||||
@twt= <FD>; # slurp in the output
|
||||
|
||||
if (! close(FD)) { # if mtx exited with a nonzero value...
|
||||
print STDERR " Mtx gave an error. Tapeload is exiting... ";
|
||||
exit (-10);
|
||||
}
|
||||
|
||||
@twt;
|
||||
}
|
||||
98
mtx-1.3.12/contrib/tapeunload.pl
Normal file
98
mtx-1.3.12/contrib/tapeunload.pl
Normal file
@@ -0,0 +1,98 @@
|
||||
#!/usr/bin/perl
|
||||
########################## tapeunload ###########################
|
||||
# This script uses mtx 1.2.9pre2 to unload a tape
|
||||
# based on its volume tag. You can
|
||||
# specify a slot into which the tape should go, but if you don`t, it puts the
|
||||
# tape into the slot from which it was taken. This slot number
|
||||
# is returned
|
||||
# both from the standard output and as the exit value.
|
||||
# A negative exit value indicates an error.
|
||||
# If volume tags are missing from any full slot or drive,
|
||||
# bar codes are rescanned automatically.
|
||||
# Note: This script assumes that the tape is ready to be removed from
|
||||
# the drive. That means you may have to unload the tape from the drive
|
||||
# with "mt offline" before the tape can be moved to a storage slot.
|
||||
#
|
||||
|
||||
# usage:
|
||||
# tapeunload TAPE_LABEL_1
|
||||
# Removes tape with label TAPE_LABEL_1 from a drive and puts it
|
||||
# back into its storage slot. Or,
|
||||
# tapeunload TAPE_LABEL_1 40
|
||||
# Removes tape with label TAPE_LABEL_1 from a drive and puts it
|
||||
# into its storage slot 40.
|
||||
#
|
||||
|
||||
# Set this variable to your mtx binary and proper scsi library device.
|
||||
$MTXBIN="/usr/local/bin/mtx -f /dev/sga" ;
|
||||
|
||||
# Additions and corrections are welcome.
|
||||
# This software comes with absolutely no warranty and every other imaginable
|
||||
# disclaimer.
|
||||
# -- Frank Samuelson sam@milagro.lanl.gov
|
||||
|
||||
##################################################################
|
||||
|
||||
@wt= &mdo("status"); #slurp in the list of slots
|
||||
|
||||
# Check to be certain that every full slot has a volume tag
|
||||
# Rescanning probably will not help. I haven`t seen any bar code
|
||||
# readers that read tapes that are in the drives. But you never know...
|
||||
for ($i=0; $i< $#wt; $i++) { # look through every line
|
||||
if ( $wt[$i] =~ /Full/ && $wt[$i] !~ /VolumeTag/ ) {
|
||||
# if the element is full, but there is no volume tag, do inventory
|
||||
@wt= &mdo("inventory status");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#try to find our tape
|
||||
$drivein=-1;
|
||||
for ($i=0; $i< $#wt; $i++) { # look through every line
|
||||
# for a full tape drive
|
||||
if ($wt[$i] =~ / *Data Transfer Element (d*):Full (Storage Element
|
||||
(d*) Loaded):VolumeTag = (.*)/ ){
|
||||
if ($ARGV[0] eq $3) { # We found our tape
|
||||
$drivein=$1; # set the drive number
|
||||
$slottogo=$2; # set the slot number
|
||||
break; # stop reading the rest of the file.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $drivein>=0) { # we found the tape you wanted.
|
||||
if ($#ARGV==1) { #If an alternative slot was requested, set it.
|
||||
$slottogo=$ARGV[1]; # and let mtx handle the errors.
|
||||
}
|
||||
|
||||
# Now we unload the tape.
|
||||
@dump=&mdo(" unload $slottogo $drivein ");
|
||||
print "$slottogo";
|
||||
exit($slottogo);
|
||||
# The end.
|
||||
|
||||
|
||||
} else {
|
||||
print STDERR " Ug. Tape $ARGV[0] is not in a tape drive.";
|
||||
print STDERR @wt;
|
||||
exit(-4);
|
||||
}
|
||||
|
||||
|
||||
sub mdo # a subroutine to call mtx ;
|
||||
{
|
||||
# print STDERR "$_[0]";
|
||||
if (!open(FD,"$MTXBIN $_[0] |")) { #call mtx function
|
||||
print STDERR " ERRKK. Could not start mtx ";
|
||||
exit (-9);
|
||||
}
|
||||
|
||||
@twt= <FD>; # slurp in the output
|
||||
|
||||
if (! close(FD)) { # if mtx exited with a nonzero value...
|
||||
print STDERR " Mtx gave an error. Tapeload is exiting... ";
|
||||
exit (-10);
|
||||
}
|
||||
|
||||
@twt;
|
||||
}
|
||||
45
mtx-1.3.12/debian/bash_completion
Normal file
45
mtx-1.3.12/debian/bash_completion
Normal file
@@ -0,0 +1,45 @@
|
||||
# mtx completion by Jon Middleton <jjm@ixtab.org.uk>
|
||||
#
|
||||
# $Id: bash_completion,v 1.1 2004-02-15 05:43:25 bdale Exp $
|
||||
|
||||
_mtx()
|
||||
{
|
||||
local cur prev options tapes drives
|
||||
|
||||
COMPREPLY=()
|
||||
cur=${COMP_WORDS[COMP_CWORD]}
|
||||
prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||
|
||||
options="-f nobarcode invert noattach --version inquiry noattach \
|
||||
inventory status load unload eepos first last next"
|
||||
|
||||
tapes=$(mtx status | \
|
||||
awk '/Storage Element [0-9]+:Full/ { printf "%s ", $3 }')
|
||||
tapes=${tapes//:Full}
|
||||
|
||||
drives=$(mtx status | \
|
||||
awk '/Data Transfer Element [0-9]+:(Full|Empty)/ { printf "%s ", $4 }')
|
||||
drives=${drives//:Full}
|
||||
drives=${drives//:Empty}
|
||||
|
||||
if [ $COMP_CWORD -gt 1 ]; then
|
||||
case $prev in
|
||||
load)
|
||||
COMPREPLY=( $( compgen -W "$tapes" -- $cur ) )
|
||||
;;
|
||||
unload|first|last|next)
|
||||
COMPREPLY=( $( compgen -W "$drives" -- $cur ) )
|
||||
;;
|
||||
-f)
|
||||
true
|
||||
;;
|
||||
*)
|
||||
true
|
||||
;;
|
||||
esac
|
||||
else
|
||||
COMPREPLY=( $( compgen -W "$options" -- $cur ) )
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
complete -F _mtx mtx
|
||||
159
mtx-1.3.12/debian/changelog
Normal file
159
mtx-1.3.12/debian/changelog
Normal file
@@ -0,0 +1,159 @@
|
||||
mtx (1.3.12-1) unstable; urgency=low
|
||||
|
||||
* Incorporate debian packaging into upsteam version
|
||||
* Remove strip of binaries
|
||||
* Remove unsupported nsmhack from list of binaries built by default
|
||||
* Add support for building outside of source tree
|
||||
* Update copyrights
|
||||
* Fix typo in mtx.1 man page
|
||||
* Clear outstanding UNIT ATTENTION state at start
|
||||
|
||||
-- Robert Nelson <robertn@the-nelsons.org> Tue, 19 Aug 2008 09:04:00 +0000
|
||||
|
||||
mtx (1.3.11-1) unstable; urgency=low
|
||||
|
||||
* new upstream version, closes: #425687, #425688
|
||||
* don't let Makefile.in strip binaries, let dh_strip do it, closes: #437589
|
||||
|
||||
-- Bdale Garbee <bdale@gag.com> Tue, 15 Apr 2008 14:34:32 -0600
|
||||
|
||||
mtx (1.2.17rel-2) unstable; urgency=low
|
||||
|
||||
* update config.sub and config.guess in rules clean target using the
|
||||
autotools-dev package, closes: #367467
|
||||
|
||||
-- Bdale Garbee <bdale@gag.com> Sat, 19 Aug 2006 18:44:54 -0600
|
||||
|
||||
mtx (1.2.17rel-1) unstable; urgency=low
|
||||
|
||||
* new upstream version
|
||||
|
||||
-- Bdale Garbee <bdale@gag.com> Wed, 28 Jun 2006 23:57:44 -0400
|
||||
|
||||
mtx (1.2.16rel-5) unstable; urgency=low
|
||||
|
||||
* add build-deps needed for GNU/kFreeBSD, closes: #367467
|
||||
* update debhelper build dependency
|
||||
|
||||
-- Bdale Garbee <bdale@gag.com> Wed, 28 Jun 2006 23:42:00 -0400
|
||||
|
||||
mtx (1.2.16rel-4) unstable; urgency=medium
|
||||
|
||||
* revert SG_SCSI_DEFAULT_TIMEOUT to 5 minutes since at least the Sony
|
||||
TLS-9000 takes more than a minute to load sometimes, closes: #229169
|
||||
* remove 'previous' from command summary, since it's not actually
|
||||
implemented in the program, closes: #230041
|
||||
* include bash_completion file from Jon Middleton, closes: #227456
|
||||
|
||||
-- Bdale Garbee <bdale@gag.com> Sat, 14 Feb 2004 22:36:23 -0700
|
||||
|
||||
mtx (1.2.16rel-3) unstable; urgency=low
|
||||
|
||||
* apply patch from Torsten Werner <twerner@debian.org> that elminates
|
||||
hard-coding of the value of HZ, closes: #224147
|
||||
|
||||
-- Bdale Garbee <bdale@gag.com> Tue, 16 Dec 2003 10:04:26 -0700
|
||||
|
||||
mtx (1.2.16rel-2) unstable; urgency=low
|
||||
|
||||
* apply patch from R.A.Owen <rao3@leicester.ac.uk> that fixes the "staggered"
|
||||
output from the status command on some changers, closes: #129910
|
||||
|
||||
-- Bdale Garbee <bdale@gag.com> Tue, 9 Apr 2002 19:30:06 -0600
|
||||
|
||||
mtx (1.2.16rel-1) unstable; urgency=low
|
||||
|
||||
* new upstream version, bug-fixing release, reportedly fixes timeout
|
||||
problem with some drives, closes: #113947
|
||||
|
||||
-- Bdale Garbee <bdale@gag.com> Mon, 4 Mar 2002 01:27:48 -0700
|
||||
|
||||
mtx (1.2.15-1) unstable; urgency=low
|
||||
|
||||
* new upstream source
|
||||
* update standards version, rebuild rules file
|
||||
* man pages all included now, mtx-changer and other pieces from contrib
|
||||
provided as examples, though chg-mtx in the amanda package is probably
|
||||
a better choice for use with amanda, closes: #113728
|
||||
* apply diffs to correct "spelling errors" (actually hyphenation) in the
|
||||
descriptions in the control file, closes: #125160
|
||||
|
||||
-- Bdale Garbee <bdale@gag.com> Sun, 30 Dec 2001 21:28:46 -0700
|
||||
|
||||
mtx (1.2.10-1) unstable; urgency=low
|
||||
|
||||
* new upstream source
|
||||
|
||||
-- Bdale Garbee <bdale@gag.com> Mon, 11 Dec 2000 17:34:13 -0700
|
||||
|
||||
mtx (1.0-10) frozen unstable; urgency=low
|
||||
|
||||
* deliver mtx.doc, lost when the package was made FHS compliant,
|
||||
closes: #56276 Target frozen since including the documentation
|
||||
is worthwhile for potato, and there is no added risk.
|
||||
|
||||
-- Bdale Garbee <bdale@gag.com> Wed, 9 Feb 2000 12:27:58 -0700
|
||||
|
||||
mtx (1.0-9) unstable; urgency=low
|
||||
|
||||
* fix postinst/postrm scripts to be executable again
|
||||
|
||||
-- Bdale Garbee <bdale@gag.com> Tue, 11 Jan 2000 23:00:17 -0700
|
||||
|
||||
mtx (1.0-8) unstable; urgency=low
|
||||
|
||||
* update to latest standards revision, add Build-Depends
|
||||
* fix all the lintian errors that aren't intentional, override the two
|
||||
permissions warnings since they're precisely what is needed
|
||||
|
||||
-- Bdale Garbee <bdale@gag.com> Fri, 7 Jan 2000 02:47:08 -0700
|
||||
|
||||
mtx (1.0-7) unstable; urgency=low
|
||||
|
||||
* grab a local copy of scsi_ioctl.h from the 2.2.10 kernel source tree. This
|
||||
doesn't change often in any way we care about, and this is much simpler
|
||||
than having to reference a live kernel tree somewhere...
|
||||
* move to debhelper and CVS
|
||||
|
||||
-- Bdale Garbee <bdale@gag.com> Sun, 20 Jun 1999 10:42:39 -0600
|
||||
|
||||
mtx (1.0-6) unstable; urgency=low
|
||||
|
||||
* put mtx in group backup, setuid root, perms set so that only members of
|
||||
group backup can run mtx. This makes mtx compatible with amanda.
|
||||
|
||||
-- Bdale Garbee <bdale@gag.com> Tue, 27 Jan 1998 15:06:13 -0700
|
||||
|
||||
mtx (1.0-5) unstable; urgency=low
|
||||
|
||||
* explicit include path to find <scsi/scsi_ioctl.h> in the
|
||||
/usr/src/linux/include tree. closes bug 16877
|
||||
|
||||
-- Bdale Garbee <bdale@gag.com> Sun, 25 Jan 1998 23:02:46 -0700
|
||||
|
||||
mtx (1.0-4) unstable; urgency=low
|
||||
|
||||
* actually install the mtx.doc file that's referenced in the man page /o\
|
||||
|
||||
-- Bdale Garbee <bdale@gag.com> Sun, 21 Sep 1997 02:38:50 -0600
|
||||
|
||||
mtx (1.0-3) unstable; urgency=low
|
||||
|
||||
* libc6
|
||||
|
||||
-- Bdale Garbee <bdale@gag.com> Thu, 4 Sep 1997 02:56:39 -0600
|
||||
|
||||
mtx (1.0-2) unstable; urgency=low
|
||||
|
||||
* Add an 'mtx-changer' wrapper script from the amanda-users mailing list
|
||||
to make this more useful with Amanda.
|
||||
* Hack mtx-changer to report 6 slots instead of 4, since I have an HP
|
||||
SureStore 12000e. Should make it configurable, someday.
|
||||
|
||||
-- Bdale Garbee <bdale@gag.com> Sun, 10 Aug 1997 03:50:42 -0600
|
||||
|
||||
mtx (1.0-1) unstable; urgency=low
|
||||
|
||||
* Initial Release.
|
||||
|
||||
-- Bdale Garbee <bdale@gag.com> Sun, 10 Aug 1997 03:05:18 -0600
|
||||
1
mtx-1.3.12/debian/compat
Normal file
1
mtx-1.3.12/debian/compat
Normal file
@@ -0,0 +1 @@
|
||||
4
|
||||
16
mtx-1.3.12/debian/control
Normal file
16
mtx-1.3.12/debian/control
Normal file
@@ -0,0 +1,16 @@
|
||||
Source: mtx
|
||||
Section: admin
|
||||
Priority: extra
|
||||
Maintainer: Robert Nelson <robertn@the-nelsons.org>
|
||||
Build-Depends: debhelper (>= 4), libcam-dev [kfreebsd-i386 kfreebsd-amd64], autotools-dev
|
||||
Standards-Version: 3.7.3
|
||||
|
||||
Package: mtx
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}
|
||||
Description: controls tape autochangers
|
||||
MTX can be used to manipulate tape auto-changers, also known as "jukeboxes",
|
||||
such that backup software can make use of the multiple tape capabilities of
|
||||
the auto-changer. In particular, this is necessary glue for using a backup
|
||||
system like Amanda with a DDS auto-changer like the HP Surestore 12000e.
|
||||
|
||||
15
mtx-1.3.12/debian/copyright
Normal file
15
mtx-1.3.12/debian/copyright
Normal file
@@ -0,0 +1,15 @@
|
||||
This package was debianized by Bdale Garbee bdale@gag.com on
|
||||
Sun, 10 Aug 1997 03:05:18 -0600.
|
||||
|
||||
mtx was downloaded from http://mtx.sourceforge.net/
|
||||
|
||||
Copyright:
|
||||
|
||||
Copyright 1997, 1998 Leonard Zubkoff <lnz@dandelion.com>
|
||||
Changes copyright 2000, 2001 Eric Green <eric@badtux.org>
|
||||
Changes copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
|
||||
|
||||
GPL, version 2
|
||||
|
||||
On Debian GNU/Linux systems, the complete text of the GNU General
|
||||
Public License can be found in `/usr/share/common-licenses/GPL'.
|
||||
2
mtx-1.3.12/debian/dirs
Normal file
2
mtx-1.3.12/debian/dirs
Normal file
@@ -0,0 +1,2 @@
|
||||
etc/bash_completion.d
|
||||
usr/sbin
|
||||
69
mtx-1.3.12/debian/rules
Executable file
69
mtx-1.3.12/debian/rules
Executable file
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/make -f
|
||||
# Sample debian/rules that uses debhelper.
|
||||
# GNU copyright 1997 to 1999 by Joey Hess.
|
||||
|
||||
export DH_VERBOSE=1
|
||||
|
||||
configure: configure-stamp
|
||||
configure-stamp:
|
||||
dh_testdir
|
||||
./configure --prefix=/usr
|
||||
touch configure-stamp
|
||||
|
||||
build: build-stamp
|
||||
|
||||
build-stamp: configure-stamp
|
||||
dh_testdir
|
||||
$(MAKE)
|
||||
touch build-stamp
|
||||
|
||||
clean:
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
rm -f build-stamp configure-stamp
|
||||
[ ! -f Makefile ] || $(MAKE) distclean
|
||||
|
||||
-test -r /usr/share/misc/config.sub && \
|
||||
cp -f /usr/share/misc/config.sub config.sub
|
||||
-test -r /usr/share/misc/config.guess && \
|
||||
cp -f /usr/share/misc/config.guess config.guess
|
||||
|
||||
dh_clean
|
||||
|
||||
install: build
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_clean -k
|
||||
dh_installdirs
|
||||
|
||||
make install bindir=`pwd`/debian/mtx/bin prefix=`pwd`/debian/mtx/usr \
|
||||
mandir=`pwd`/debian/mtx/usr/share/man
|
||||
install -o root -g root -m 0644 debian/bash_completion \
|
||||
debian/mtx/etc/bash_completion.d/mtx
|
||||
|
||||
# Build architecture-independent files here.
|
||||
binary-indep: build install
|
||||
|
||||
# Build architecture-dependent files here.
|
||||
binary-arch: build install
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_installdocs
|
||||
dh_installexamples contrib/*
|
||||
dh_installmenu
|
||||
dh_installcron
|
||||
# dh_installman
|
||||
dh_installinfo
|
||||
dh_installchangelogs CHANGES
|
||||
dh_link
|
||||
dh_strip
|
||||
dh_compress
|
||||
dh_fixperms
|
||||
dh_installdeb
|
||||
dh_shlibdeps
|
||||
dh_gencontrol
|
||||
dh_md5sums
|
||||
dh_builddeb
|
||||
|
||||
binary: binary-indep binary-arch
|
||||
.PHONY: build clean binary-indep binary-arch binary install configure
|
||||
25
mtx-1.3.12/du/defs.h
Normal file
25
mtx-1.3.12/du/defs.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef int DEVICE_TYPE;
|
||||
|
||||
#ifdef __osf__
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <io/common/iotypes.h>
|
||||
#else /* must be ultrix */
|
||||
#include <sys/devio.h>
|
||||
#endif
|
||||
#include <io/cam/cam.h>
|
||||
#include <io/cam/uagt.h>
|
||||
#include <io/cam/dec_cam.h>
|
||||
#include <io/cam/scsi_all.h>
|
||||
#define DEV_CAM "/dev/cam" /* CAM device path */
|
||||
|
||||
|
||||
#define DIGITAL_UNIX
|
||||
214
mtx-1.3.12/du/scsi.c
Normal file
214
mtx-1.3.12/du/scsi.c
Normal file
@@ -0,0 +1,214 @@
|
||||
/* SCSI.C - Digital Unix-specific SCSI routines.
|
||||
**
|
||||
** TECSys Development, Inc., April 1998
|
||||
**
|
||||
** This module began life as a part of XMCD, an X-windows CD player
|
||||
** program for many platforms. No real functionality from the original XMCD
|
||||
** is present in this module, but in the interest of making certain that
|
||||
** proper credit is given where it may be due, the copyrights and inclusions
|
||||
** from the XMCD module OS_DEC.C are included below.
|
||||
**
|
||||
** The portions of coding in this module ascribable to TECSys Development
|
||||
** are hereby also released under the terms and conditions of version 2
|
||||
** of the GNU General Public License as described below....
|
||||
*/
|
||||
|
||||
/*
|
||||
* libdi - scsipt SCSI Device Interface Library
|
||||
*
|
||||
* Copyright (C) 1993-1997 Ti Kan
|
||||
* E-mail: ti@amb.org
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Digital UNIX (OSF/1) and Ultrix support
|
||||
*
|
||||
* Contributing author: Matt Thomas
|
||||
* E-Mail: thomas@lkg.dec.com
|
||||
*
|
||||
* This software fragment contains code that interfaces the
|
||||
* application to the Digital UNIX and Ultrix operating systems.
|
||||
* The term Digital, Ultrix and OSF/1 are used here for identification
|
||||
* purposes only.
|
||||
*/
|
||||
|
||||
static int bus = -1,
|
||||
target = -1,
|
||||
lun = -1;
|
||||
|
||||
static int SCSI_OpenDevice(char *DeviceName)
|
||||
{
|
||||
int fd;
|
||||
struct stat stbuf;
|
||||
int saverr;
|
||||
|
||||
/* Check for validity of device node */
|
||||
if (stat(DeviceName, &stbuf) < 0)
|
||||
{
|
||||
FatalError("cannot stat SCSI device '%s' - %m\n", DeviceName);
|
||||
}
|
||||
if (!S_ISCHR(stbuf.st_mode))
|
||||
{
|
||||
FatalError("device '%s': not appropriate device type - %m\n", DeviceName);
|
||||
}
|
||||
|
||||
if ((fd = open(DeviceName, O_RDONLY | O_NDELAY, 0)) >= 0)
|
||||
{
|
||||
struct devget devget;
|
||||
|
||||
if (ioctl(fd, DEVIOCGET, &devget) >= 0)
|
||||
{
|
||||
#ifdef __osf__
|
||||
lun = devget.slave_num % 8;
|
||||
devget.slave_num /= 8;
|
||||
#else
|
||||
lun = 0;
|
||||
#endif
|
||||
target = devget.slave_num % 8;
|
||||
devget.slave_num /= 8;
|
||||
bus = devget.slave_num % 8;
|
||||
(void) close(fd);
|
||||
|
||||
if ((fd = open(DEV_CAM, O_RDWR, 0)) >= 0 ||
|
||||
(fd = open(DEV_CAM, O_RDONLY, 0)) >= 0)
|
||||
{
|
||||
return (fd);
|
||||
}
|
||||
fd = bus = target = lun = -1;
|
||||
FatalError("error %d opening SCSI device '%s' - %m\n",
|
||||
errno, DEV_CAM);
|
||||
}
|
||||
else
|
||||
{
|
||||
(void) close(fd);
|
||||
fd = bus = target = lun = -1;
|
||||
FatalError("error %d on DEVIOCGET ioctl for '%s' - %m\n",
|
||||
errno, DeviceName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
saverr = errno;
|
||||
fd = bus = target = lun = -1;
|
||||
FatalError("cannot open SCSI device '%s', error %d - %m\n",
|
||||
DeviceName, saverr);
|
||||
}
|
||||
|
||||
fd = bus = target = lun = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static void SCSI_CloseDevice(char *DeviceName, int DeviceFD)
|
||||
{
|
||||
(void) close(DeviceFD);
|
||||
bus = target = lun = -1;
|
||||
}
|
||||
|
||||
|
||||
static int SCSI_ExecuteCommand(int DeviceFD,
|
||||
Direction_T Direction,
|
||||
CDB_T *CDB,
|
||||
int CDB_Length,
|
||||
void *DataBuffer,
|
||||
int DataBufferLength,
|
||||
RequestSense_T *RequestSense)
|
||||
{
|
||||
UAGT_CAM_CCB uagt;
|
||||
CCB_SCSIIO ccb;
|
||||
|
||||
if (DeviceFD < 0)
|
||||
return -1;
|
||||
|
||||
(void) memset(&uagt, 0, sizeof(uagt));
|
||||
(void) memset(&ccb, 0, sizeof(ccb));
|
||||
|
||||
/* Setup the user agent ccb */
|
||||
uagt.uagt_ccb = (CCB_HEADER *) &ccb;
|
||||
uagt.uagt_ccblen = sizeof(CCB_SCSIIO);
|
||||
|
||||
/* Setup the scsi ccb */
|
||||
(void) memcpy((unsigned char *) ccb.cam_cdb_io.cam_cdb_bytes,
|
||||
CDB, CDB_Length);
|
||||
ccb.cam_cdb_len = CDB_Length;
|
||||
ccb.cam_ch.my_addr = (CCB_HEADER *) &ccb;
|
||||
ccb.cam_ch.cam_ccb_len = sizeof(CCB_SCSIIO);
|
||||
ccb.cam_ch.cam_func_code = XPT_SCSI_IO;
|
||||
|
||||
if (DataBuffer != NULL && DataBufferLength > 0)
|
||||
{
|
||||
ccb.cam_ch.cam_flags |= (Direction == Input) ?
|
||||
CAM_DIR_IN : CAM_DIR_OUT;
|
||||
uagt.uagt_buffer = (u_char *) DataBuffer;
|
||||
uagt.uagt_buflen = DataBufferLength;
|
||||
}
|
||||
else
|
||||
ccb.cam_ch.cam_flags |= CAM_DIR_NONE;
|
||||
|
||||
ccb.cam_ch.cam_flags |= CAM_DIS_AUTOSENSE;
|
||||
ccb.cam_data_ptr = uagt.uagt_buffer;
|
||||
ccb.cam_dxfer_len = uagt.uagt_buflen;
|
||||
ccb.cam_timeout = 300; /* Timeout set to 5 minutes */
|
||||
|
||||
ccb.cam_sense_ptr = (u_char *) RequestSense;
|
||||
ccb.cam_sense_len = sizeof(RequestSense_T);
|
||||
|
||||
ccb.cam_ch.cam_path_id = bus;
|
||||
ccb.cam_ch.cam_target_id = target;
|
||||
ccb.cam_ch.cam_target_lun = lun;
|
||||
|
||||
if (ioctl(DeviceFD, UAGT_CAM_IO, (caddr_t) &uagt) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check return status */
|
||||
if ((ccb.cam_ch.cam_status & CAM_STATUS_MASK) != CAM_REQ_CMP)
|
||||
{
|
||||
if (ccb.cam_ch.cam_status & CAM_SIM_QFRZN)
|
||||
{
|
||||
(void) memset(&ccb, 0, sizeof(ccb));
|
||||
(void) memset(&uagt, 0, sizeof(uagt));
|
||||
|
||||
/* Setup the user agent ccb */
|
||||
uagt.uagt_ccb = (CCB_HEADER *) &ccb;
|
||||
uagt.uagt_ccblen = sizeof(CCB_RELSIM);
|
||||
|
||||
/* Setup the scsi ccb */
|
||||
ccb.cam_ch.my_addr = (struct ccb_header *) &ccb;
|
||||
ccb.cam_ch.cam_ccb_len = sizeof(CCB_RELSIM);
|
||||
ccb.cam_ch.cam_func_code = XPT_REL_SIMQ;
|
||||
|
||||
ccb.cam_ch.cam_path_id = bus;
|
||||
ccb.cam_ch.cam_target_id = target;
|
||||
ccb.cam_ch.cam_target_lun = lun;
|
||||
|
||||
if (ioctl(DeviceFD, UAGT_CAM_IO, (caddr_t) &uagt) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf( "mtx: %s:\n%s=0x%x %s=0x%x\n",
|
||||
"SCSI command fault",
|
||||
"Opcode",
|
||||
CDB[0],
|
||||
"Status",
|
||||
ccb.cam_scsi_status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
253
mtx-1.3.12/install-sh
Executable file
253
mtx-1.3.12/install-sh
Executable file
@@ -0,0 +1,253 @@
|
||||
#!/bin/sh
|
||||
# $Date: 2001-06-05 10:10:15 -0700 (Tue, 05 Jun 2001) $
|
||||
# $Revision: 2 $
|
||||
#
|
||||
# install - install a program, script, or datafile
|
||||
# This comes from X11R5 (mit/util/scripts/install.sh).
|
||||
#
|
||||
# Copyright 1991 by the Massachusetts Institute of Technology
|
||||
#
|
||||
# Permission to use, copy, modify, distribute, and sell this software and its
|
||||
# documentation for any purpose is hereby granted without fee, provided that
|
||||
# the above copyright notice appear in all copies and that both that
|
||||
# copyright notice and this permission notice appear in supporting
|
||||
# documentation, and that the name of M.I.T. not be used in advertising or
|
||||
# publicity pertaining to distribution of the software without specific,
|
||||
# written prior permission. M.I.T. makes no representations about the
|
||||
# suitability of this software for any purpose. It is provided "as is"
|
||||
# without express or implied warranty.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# `make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch. It can only install one file at a time, a restriction
|
||||
# shared with many OS's install programs.
|
||||
|
||||
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit="${DOITPROG-}"
|
||||
|
||||
|
||||
# put in absolute paths if you don't have them in your path; or use env. vars.
|
||||
|
||||
mvprog="${MVPROG-mv}"
|
||||
cpprog="${CPPROG-cp}"
|
||||
chmodprog="${CHMODPROG-chmod}"
|
||||
chownprog="${CHOWNPROG-chown}"
|
||||
chgrpprog="${CHGRPPROG-chgrp}"
|
||||
stripprog="${STRIPPROG-strip}"
|
||||
rmprog="${RMPROG-rm}"
|
||||
mkdirprog="${MKDIRPROG-mkdir}"
|
||||
|
||||
transformbasename=""
|
||||
transform_arg=""
|
||||
instcmd="$mvprog"
|
||||
chmodcmd="$chmodprog 0755"
|
||||
chowncmd=""
|
||||
chgrpcmd=""
|
||||
stripcmd=""
|
||||
rmcmd="$rmprog -f"
|
||||
mvcmd="$mvprog"
|
||||
src=""
|
||||
dst=""
|
||||
dir_arg=""
|
||||
|
||||
while [ x"$1" != x ]; do
|
||||
case $1 in
|
||||
-c) instcmd="$cpprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-d) dir_arg=true
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-m) chmodcmd="$chmodprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-s) stripcmd="$stripprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
*) if [ x"$src" = x ]
|
||||
then
|
||||
src=$1
|
||||
else
|
||||
# this colon is to work around a 386BSD /bin/sh bug
|
||||
:
|
||||
dst=$1
|
||||
fi
|
||||
shift
|
||||
continue;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ x"$src" = x ]
|
||||
then
|
||||
echo "install: no input file specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]; then
|
||||
dst=$src
|
||||
src=""
|
||||
|
||||
if [ -d $dst ]; then
|
||||
instcmd=:
|
||||
chmodcmd=""
|
||||
else
|
||||
instcmd=mkdir
|
||||
fi
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
|
||||
if [ -f $src -o -d $src ]
|
||||
then
|
||||
true
|
||||
else
|
||||
echo "install: $src does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ x"$dst" = x ]
|
||||
then
|
||||
echo "install: no destination specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# If destination is a directory, append the input filename; if your system
|
||||
# does not like double slashes in filenames, you may need to add some logic
|
||||
|
||||
if [ -d $dst ]
|
||||
then
|
||||
dst="$dst"/`basename $src`
|
||||
else
|
||||
true
|
||||
fi
|
||||
fi
|
||||
|
||||
## this sed command emulates the dirname command
|
||||
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
|
||||
|
||||
# Make sure that the destination directory exists.
|
||||
# this part is taken from Noah Friedman's mkinstalldirs script
|
||||
|
||||
# Skip lots of stat calls in the usual case.
|
||||
if [ ! -d "$dstdir" ]; then
|
||||
defaultIFS='
|
||||
'
|
||||
IFS="${IFS-${defaultIFS}}"
|
||||
|
||||
oIFS="${IFS}"
|
||||
# Some sh's can't handle IFS=/ for some reason.
|
||||
IFS='%'
|
||||
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
|
||||
IFS="${oIFS}"
|
||||
|
||||
pathcomp=''
|
||||
|
||||
while [ $# -ne 0 ] ; do
|
||||
pathcomp="${pathcomp}${1}"
|
||||
shift
|
||||
|
||||
if [ ! -d "${pathcomp}" ] ;
|
||||
then
|
||||
$mkdirprog "${pathcomp}"
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
pathcomp="${pathcomp}/"
|
||||
done
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]
|
||||
then
|
||||
$doit $instcmd $dst &&
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
|
||||
else
|
||||
|
||||
# If we're going to rename the final executable, determine the name now.
|
||||
|
||||
if [ x"$transformarg" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
dstfile=`basename $dst $transformbasename |
|
||||
sed $transformarg`$transformbasename
|
||||
fi
|
||||
|
||||
# don't allow the sed command to completely eliminate the filename
|
||||
|
||||
if [ x"$dstfile" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# Make a temp file name in the proper directory.
|
||||
|
||||
dsttmp=$dstdir/#inst.$$#
|
||||
|
||||
# Move or copy the file name to the temp name
|
||||
|
||||
$doit $instcmd $src $dsttmp &&
|
||||
|
||||
trap "rm -f ${dsttmp}" 0 &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits
|
||||
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $instcmd $src $dsttmp" command.
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
|
||||
$doit $rmcmd -f $dstdir/$dstfile &&
|
||||
$doit $mvcmd $dsttmp $dstdir/$dstfile
|
||||
|
||||
fi &&
|
||||
|
||||
|
||||
exit 0
|
||||
90
mtx-1.3.12/loaderinfo.1
Normal file
90
mtx-1.3.12/loaderinfo.1
Normal file
@@ -0,0 +1,90 @@
|
||||
.\" tapeinfo.1 Document copyright 2000 Eric Lee Green
|
||||
.\" Program Copyright 2000 Eric Lee Green <eric@badtux.org>
|
||||
.\" Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
|
||||
.\"
|
||||
.\" This is free documentation; you can redistribute it and/or
|
||||
.\" modify it under the terms of the GNU General Public License as
|
||||
.\" published by the Free Software Foundation; either version 2 of
|
||||
.\" the License, or (at your option) any later version.
|
||||
.\"
|
||||
.\" The GNU General Public License's references to "object code"
|
||||
.\" and "executables" are to be interpreted as the output of any
|
||||
.\" document formatting or typesetting system, including
|
||||
.\" intermediate and printed output.
|
||||
.\"
|
||||
.\" This manual is distributed in the hope that it will be useful,
|
||||
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
.\" GNU General Public License for more details.
|
||||
.\"
|
||||
.\" You should have received a copy of the GNU General Public
|
||||
.\" License along with this manual; if not, write to the Free
|
||||
.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
|
||||
.\" USA.
|
||||
.\"
|
||||
.TH LOADERINFO 1 LOADERINFO1.0
|
||||
.SH NAME
|
||||
loaderinfo \- report SCSI tape device info
|
||||
.SH SYNOPSIS
|
||||
loaderinfo -f <scsi-generic-device>
|
||||
.SH DESCRIPTION
|
||||
The
|
||||
.B loaderinfo
|
||||
command reads various information from SCSI tape loaders. Its intended
|
||||
use is for high-level programs that are trying to decide what the
|
||||
capabilities of a device are.
|
||||
.P
|
||||
The following are printed:
|
||||
.TP 10
|
||||
.B Element Address Assignment Page:
|
||||
This tells how many elements are in the loader, and what their raw
|
||||
hardware addresses are.
|
||||
|
||||
.TP 10
|
||||
.B Transport Geometry Descriptor Page:
|
||||
Will display whether media is invertible or not (usable with some
|
||||
optical jukeboxes for detirmining whether to "flip" media after writing
|
||||
to the first side).
|
||||
|
||||
.TP 10
|
||||
.B Device Capabilities Page
|
||||
Currently will only display whether we can transfer between slots (i.e.
|
||||
whether 'mtx transfer' works).
|
||||
|
||||
.TP 10
|
||||
.B Inquiry Page
|
||||
Aside from the normal inquiry info, will also print out whether we have
|
||||
a bar code reader (for loaders that support the Exabyte extension for
|
||||
reporting presense of said reader).
|
||||
|
||||
|
||||
.SH OPTIONS
|
||||
The first argument, given following
|
||||
.B -f
|
||||
, is the SCSI generic device corresponding to your tape loader.
|
||||
Consult your operating system's documentation for more information (for
|
||||
example, under Linux these are generally start at /dev/sg0
|
||||
under FreeBSD these start at /dev/pass0).
|
||||
.P
|
||||
Under FreeBSD, 'camcontrol devlist' will tell you what SCSI devices you
|
||||
have, along with which 'pass' device controls them. Under Linux,
|
||||
"cat /proc/scsi/scsi" will tell you what SCSI devices you have. Under
|
||||
Solaris 8,
|
||||
.B find /devices -name '*changer*'
|
||||
will display the device names for your attached changers. Make sure
|
||||
to configure your 'sgen' driver first.
|
||||
|
||||
.SH BUGS AND LIMITATIONS
|
||||
.P
|
||||
This program has only been tested on Linux with a limited number of
|
||||
loaders (Ecrix Autopack, Exabyte 220).
|
||||
.P
|
||||
.SH AVAILABILITY
|
||||
.B loaderinfo
|
||||
is currently being maintained by Robert Nelson <robertnelson@users.sourceforge.net>
|
||||
as part of the 'mtx' suite of programs. The 'mtx' home page is
|
||||
http://mtx.sourceforge.net and the actual code is currently available there and via
|
||||
SVN from http://sourceforge.net/projects/mtx.
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR mt (1), tapeinfo (1), mtx (1)
|
||||
510
mtx-1.3.12/loaderinfo.c
Normal file
510
mtx-1.3.12/loaderinfo.c
Normal file
@@ -0,0 +1,510 @@
|
||||
/* Copyright 2000 Enhanced Software Technologies Inc.
|
||||
* Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
|
||||
* Released under terms of the GNU General Public License as
|
||||
* required by the license on 'mtxl.c'.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $
|
||||
* $Revision: 193 $
|
||||
*/
|
||||
|
||||
/* What this does: Basically dumps out contents of:
|
||||
* Mode Sense: Element Address Assignment Page (0x1d)
|
||||
* 1Eh (Transport Geometry Parameters) has a bit which indicates is
|
||||
* a robot is capable of rotating the media. It`s the
|
||||
* `Rotate` bit, byte 2, bit 1.
|
||||
* Device Capabilities page (0x1f)
|
||||
* Inquiry -- prints full inquiry info.
|
||||
* DeviceType:
|
||||
* Manufacturer:
|
||||
* ProdID:
|
||||
* ProdRevision:
|
||||
* If there is a byte 55, we use the Exabyte extension to
|
||||
* print out whether we have a bar code reader or not. This is
|
||||
* bit 0 of byte 55.
|
||||
*
|
||||
* Next, we request element status on the drives. We do not
|
||||
* request volume tags though. If Exabyte
|
||||
* extensions are supported, we report the following information for
|
||||
* each drive:
|
||||
*
|
||||
* Drive number
|
||||
* EXCEPT (with ASC and ASCQ), if there is a problem.
|
||||
* SCSI address and LUN
|
||||
* Tape drive Serial number
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "mtx.h"
|
||||
#include "mtxl.h"
|
||||
|
||||
DEVICE_TYPE MediumChangerFD; /* historic purposes... */
|
||||
|
||||
char *argv0;
|
||||
|
||||
/* A table for printing out the peripheral device type as ASCII. */
|
||||
static char *PeripheralDeviceType[32] =
|
||||
{
|
||||
"Disk Drive",
|
||||
"Tape Drive",
|
||||
"Printer",
|
||||
"Processor",
|
||||
"Write-once",
|
||||
"CD-ROM",
|
||||
"Scanner",
|
||||
"Optical",
|
||||
"Medium Changer",
|
||||
"Communications",
|
||||
"ASC IT8",
|
||||
"ASC IT8",
|
||||
"RAID Array",
|
||||
"Enclosure Services",
|
||||
"OCR/W",
|
||||
"Bridging Expander", /* 0x10 */
|
||||
"Reserved", /* 0x11 */
|
||||
"Reserved", /* 0x12 */
|
||||
"Reserved", /* 0x13 */
|
||||
"Reserved", /* 0x14 */
|
||||
"Reserved", /* 0x15 */
|
||||
"Reserved", /* 0x16 */
|
||||
"Reserved", /* 0x17 */
|
||||
"Reserved", /* 0x18 */
|
||||
"Reserved", /* 0x19 */
|
||||
"Reserved", /* 0x1a */
|
||||
"Reserved", /* 0x1b */
|
||||
"Reserved", /* 0x1c */
|
||||
"Reserved", /* 0x1d */
|
||||
"Reserved", /* 0x1e */
|
||||
"Unknown" /* 0x1f */
|
||||
};
|
||||
|
||||
|
||||
/* okay, now for the structure of an Element Address Assignment Page: */
|
||||
|
||||
typedef struct EAAP
|
||||
{
|
||||
unsigned char Page_Code;
|
||||
unsigned char Parameter_Length;
|
||||
unsigned char MediumTransportElementAddress[2];
|
||||
unsigned char NumMediumTransportElements[2];
|
||||
unsigned char FirstStorageElementAdddress[2];
|
||||
unsigned char NumStorageElements[2];
|
||||
unsigned char FirstImportExportElementAddress[2];
|
||||
unsigned char NumImportExportElements[2];
|
||||
unsigned char FirstDataTransferElementAddress[2];
|
||||
unsigned char NumDataTransferElements[2];
|
||||
unsigned char Reserved[2];
|
||||
} EAAP_Type;
|
||||
|
||||
/* okay, now for the structure of a transport geometry
|
||||
* descriptor page:
|
||||
*/
|
||||
typedef struct TGDP
|
||||
{
|
||||
unsigned char Page_Code;
|
||||
unsigned char ParameterLength;
|
||||
unsigned char Rotate;
|
||||
unsigned char ElementNumber; /* we don't care about this... */
|
||||
} TGDP_Type;
|
||||
|
||||
|
||||
/* Structure of the Device Capabilities Page: */
|
||||
typedef struct DCP
|
||||
{
|
||||
unsigned char Page_Code;
|
||||
unsigned char ParameterLength;
|
||||
unsigned char CanStore; /* bits about whether elements can store carts */
|
||||
unsigned char SMC2_Caps;
|
||||
unsigned char MT_Transfer; /* bits about whether mt->xx transfers work. */
|
||||
unsigned char ST_Transfer; /* bits about whether st->xx transfers work. */
|
||||
unsigned char IE_Transfer; /* bits about whether id->xx transfers work. */
|
||||
unsigned char DT_Transfer; /* bits about whether DT->xx transfers work. */
|
||||
unsigned char Reserved[4]; /* more reserved data */
|
||||
unsigned char MT_Exchange; /* bits about whether mt->xx exchanges work. */
|
||||
unsigned char ST_Exchange; /* bits about whether st->xx exchanges work. */
|
||||
unsigned char IE_Exchange; /* bits about whether id->xx exchanges work. */
|
||||
unsigned char DT_Exchange; /* bits about whether DT->xx exchanges work. */
|
||||
unsigned char Reserved2[4]; /* more reserved data */
|
||||
} DCP_Type;
|
||||
|
||||
#define MT_BIT 0x01
|
||||
#define ST_BIT 0x02
|
||||
#define IE_BIT 0x04
|
||||
#define DT_BIT 0x08
|
||||
|
||||
/* Okay, now for the inquiry information: */
|
||||
|
||||
static void ReportInquiry(DEVICE_TYPE MediumChangerFD)
|
||||
{
|
||||
RequestSense_T RequestSense;
|
||||
Inquiry_T *Inquiry;
|
||||
int i;
|
||||
|
||||
Inquiry = RequestInquiry(MediumChangerFD,&RequestSense);
|
||||
if (Inquiry == NULL)
|
||||
{
|
||||
PrintRequestSense(&RequestSense);
|
||||
FatalError("INQUIRY Command Failed\n");
|
||||
}
|
||||
|
||||
printf("Product Type: %s\n",PeripheralDeviceType[Inquiry->PeripheralDeviceType]);
|
||||
|
||||
printf("Vendor ID: '");
|
||||
for (i = 0; i < sizeof(Inquiry->VendorIdentification); i++)
|
||||
printf("%c", Inquiry->VendorIdentification[i]);
|
||||
|
||||
printf("'\nProduct ID: '");
|
||||
for (i = 0; i < sizeof(Inquiry->ProductIdentification); i++)
|
||||
printf("%c", Inquiry->ProductIdentification[i]);
|
||||
|
||||
printf("'\nRevision: '");
|
||||
for (i = 0; i < sizeof(Inquiry->ProductRevisionLevel); i++)
|
||||
printf("%c", Inquiry->ProductRevisionLevel[i]);
|
||||
|
||||
printf("'\n");
|
||||
|
||||
if (Inquiry->MChngr)
|
||||
{
|
||||
/* check the attached-media-changer bit... */
|
||||
printf("Attached Changer: Yes\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Attached Changer: No\n");
|
||||
}
|
||||
|
||||
/* Now see if we have a bar code flag: */
|
||||
if (Inquiry->AdditionalLength > 50)
|
||||
{
|
||||
/* see if we have 56 bytes: */
|
||||
if (Inquiry->VendorFlags & 1)
|
||||
{
|
||||
printf("Bar Code Reader: Yes\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Bar Code Reader: No\n");
|
||||
}
|
||||
}
|
||||
|
||||
free(Inquiry); /* well, we're about to exit, but ... */
|
||||
}
|
||||
|
||||
/*********** MODE SENSE *******************/
|
||||
/* We need 3 different mode sense pages. This is a generic
|
||||
* routine for obtaining mode sense pages.
|
||||
*/
|
||||
|
||||
static unsigned char
|
||||
*mode_sense(DEVICE_TYPE fd, char pagenum, int alloc_len, RequestSense_T *RequestSense)
|
||||
{
|
||||
CDB_T CDB;
|
||||
unsigned char *input_buffer; /*the input buffer -- has junk prepended to
|
||||
* actual sense page.
|
||||
*/
|
||||
unsigned char *tmp;
|
||||
unsigned char *retval; /* the return value. */
|
||||
int i,pagelen;
|
||||
|
||||
if (alloc_len > 255)
|
||||
{
|
||||
FatalError("mode_sense(6) can only read up to 255 characters!\n");
|
||||
}
|
||||
|
||||
input_buffer = (unsigned char *)xzmalloc(256); /* overdo it, eh? */
|
||||
|
||||
/* clear the sense buffer: */
|
||||
slow_bzero((char *)RequestSense, sizeof(RequestSense_T));
|
||||
|
||||
/* returns an array of bytes in the page, or, if not possible, NULL. */
|
||||
CDB[0] = 0x1a; /* Mode Sense(6) */
|
||||
CDB[1] = 0x08;
|
||||
CDB[2] = pagenum; /* the page to read. */
|
||||
CDB[3] = 0;
|
||||
CDB[4] = 255; /* allocation length. This does max of 256 bytes! */
|
||||
CDB[5] = 0;
|
||||
|
||||
if (SCSI_ExecuteCommand(fd, Input, &CDB, 6,
|
||||
input_buffer, 255, RequestSense) != 0)
|
||||
{
|
||||
#ifdef DEBUG_MODE_SENSE
|
||||
fprintf(stderr,"Could not execute mode sense...\n");
|
||||
fflush(stderr);
|
||||
#endif
|
||||
return NULL; /* sorry, couldn't do it. */
|
||||
}
|
||||
|
||||
/* First skip past any header.... */
|
||||
tmp = input_buffer + 4 + input_buffer[3];
|
||||
/* now find out real length of page... */
|
||||
pagelen=tmp[1] + 2;
|
||||
retval = xmalloc(pagelen);
|
||||
/* and copy our data to the new page. */
|
||||
for (i = 0; i < pagelen; i++)
|
||||
{
|
||||
retval[i] = tmp[i];
|
||||
}
|
||||
/* okay, free our input buffer: */
|
||||
free(input_buffer);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Report the Element Address Assignment Page */
|
||||
static void ReportEAAP(DEVICE_TYPE MediumChangerFD)
|
||||
{
|
||||
EAAP_Type *EAAP;
|
||||
RequestSense_T RequestSense;
|
||||
|
||||
EAAP = (EAAP_Type *)mode_sense(MediumChangerFD, 0x1d, sizeof(EAAP_Type), &RequestSense);
|
||||
|
||||
if (EAAP == NULL)
|
||||
{
|
||||
PrintRequestSense(&RequestSense);
|
||||
printf("EAAP: No\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* we did get an EAAP, so do our thing: */
|
||||
printf("EAAP: Yes\n");
|
||||
printf("Number of Medium Transport Elements: %d\n", ( ((unsigned int)EAAP->NumMediumTransportElements[0]<<8) + (unsigned int)EAAP->NumMediumTransportElements[1]));
|
||||
printf("Number of Storage Elements: %d\n", ( ((unsigned int)EAAP->NumStorageElements[0]<<8) + (unsigned int)EAAP->NumStorageElements[1]));
|
||||
printf("Number of Import/Export Elements: %d\n", ( ((unsigned int)EAAP->NumImportExportElements[0]<<8) + (unsigned int)EAAP->NumImportExportElements[1]));
|
||||
printf("Number of Data Transfer Elements: %d\n", ( ((unsigned int)EAAP->NumDataTransferElements[0]<<8) + (unsigned int)EAAP->NumDataTransferElements[1]));
|
||||
|
||||
free(EAAP);
|
||||
}
|
||||
|
||||
/* See if we can get some invert information: */
|
||||
|
||||
static void Report_TGDP(DEVICE_TYPE MediumChangerFD)
|
||||
{
|
||||
TGDP_Type *result;
|
||||
|
||||
RequestSense_T RequestSense;
|
||||
|
||||
result=(TGDP_Type *)mode_sense(MediumChangerFD,0x1e,255,&RequestSense);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
printf("Transport Geometry Descriptor Page: No\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Transport Geometry Descriptor Page: Yes\n");
|
||||
|
||||
/* Now print out the invert bit: */
|
||||
if ( result->Rotate & 1 )
|
||||
{
|
||||
printf("Invertable: Yes\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Invertable: No\n");
|
||||
}
|
||||
|
||||
free(result);
|
||||
}
|
||||
|
||||
/* Okay, let's get the Device Capabilities Page. We don't care
|
||||
* about much here, just whether 'mtx transfer' will work (i.e.,
|
||||
* ST->ST).
|
||||
*/
|
||||
|
||||
void TransferExchangeTargets(unsigned char ucValue, char *szPrefix)
|
||||
{
|
||||
if (ucValue & DT_BIT)
|
||||
{
|
||||
printf("%sData Transfer", szPrefix);
|
||||
}
|
||||
|
||||
if (ucValue & IE_BIT)
|
||||
{
|
||||
printf("%s%sImport/Export", ucValue > (IE_BIT | (IE_BIT - 1)) ? ", " : "", szPrefix);
|
||||
}
|
||||
|
||||
if (ucValue & ST_BIT)
|
||||
{
|
||||
printf("%s%sStorage", ucValue > (ST_BIT | (ST_BIT - 1)) ? ", " : "", szPrefix);
|
||||
}
|
||||
|
||||
if (ucValue & MT_BIT)
|
||||
{
|
||||
printf("%s%sMedium Transfer", ucValue > (MT_BIT | (MT_BIT - 1)) ? ", " : "", szPrefix);
|
||||
}
|
||||
}
|
||||
|
||||
static void Report_DCP(DEVICE_TYPE MediumChangerFD)
|
||||
{
|
||||
DCP_Type *result;
|
||||
RequestSense_T RequestSense;
|
||||
|
||||
/* Get the page. */
|
||||
result=(DCP_Type *)mode_sense(MediumChangerFD,0x1f,sizeof(DCP_Type),&RequestSense);
|
||||
if (!result)
|
||||
{
|
||||
printf("Device Configuration Page: No\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Device Configuration Page: Yes\n");
|
||||
|
||||
printf("Storage: ");
|
||||
|
||||
if (result->CanStore & DT_BIT)
|
||||
{
|
||||
printf("Data Transfer");
|
||||
}
|
||||
|
||||
if (result->CanStore & IE_BIT)
|
||||
{
|
||||
printf("%sImport/Export", result->CanStore > (IE_BIT | (IE_BIT - 1)) ? ", " : "");
|
||||
}
|
||||
|
||||
if (result->CanStore & ST_BIT)
|
||||
{
|
||||
printf("%sStorage", result->CanStore > (ST_BIT | (ST_BIT - 1)) ? ", " : "");
|
||||
}
|
||||
|
||||
if (result->CanStore & MT_BIT)
|
||||
{
|
||||
printf("%sMedium Transfer", result->CanStore > (MT_BIT | (MT_BIT - 1)) ? ", " : "");
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("SCSI Media Changer (rev 2): ");
|
||||
|
||||
if (result->SMC2_Caps & 0x01)
|
||||
{
|
||||
printf("Yes\n");
|
||||
|
||||
printf("Volume Tag Reader Present: %s\n", result->SMC2_Caps & 0x02 ? "Yes" : "No");
|
||||
printf("Auto-Clean Enabled: %s\n", result->SMC2_Caps & 0x04 ? "Yes" : "No");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("No\n");
|
||||
}
|
||||
|
||||
printf("Transfer Medium Transport: ");
|
||||
if ((result->MT_Transfer & 0x0F) != 0)
|
||||
{
|
||||
TransferExchangeTargets(result->MT_Transfer, "->");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("None");
|
||||
}
|
||||
|
||||
printf("\nTransfer Storage: ");
|
||||
if ((result->ST_Transfer & 0x0F) != 0)
|
||||
{
|
||||
TransferExchangeTargets(result->ST_Transfer, "->");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("None");
|
||||
}
|
||||
|
||||
printf("\nTransfer Import/Export: ");
|
||||
if ((result->IE_Transfer & 0x0F) != 0)
|
||||
{
|
||||
TransferExchangeTargets(result->IE_Transfer, "->");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("None");
|
||||
}
|
||||
|
||||
printf("\nTransfer Data Transfer: ");
|
||||
if ((result->DT_Transfer & 0x0F) != 0)
|
||||
{
|
||||
TransferExchangeTargets(result->DT_Transfer, "->");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("None");
|
||||
}
|
||||
|
||||
printf("\nExchange Medium Transport: ");
|
||||
if ((result->MT_Exchange & 0x0F) != 0)
|
||||
{
|
||||
TransferExchangeTargets(result->MT_Exchange, "<>");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("None");
|
||||
}
|
||||
|
||||
printf("\nExchange Storage: ");
|
||||
if ((result->ST_Exchange & 0x0F) != 0)
|
||||
{
|
||||
TransferExchangeTargets(result->ST_Exchange, "<>");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("None");
|
||||
}
|
||||
|
||||
printf("\nExchange Import/Export: ");
|
||||
if ((result->IE_Exchange & 0x0F) != 0)
|
||||
{
|
||||
TransferExchangeTargets(result->IE_Exchange, "<>");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("None");
|
||||
}
|
||||
|
||||
printf("\nExchange Data Transfer: ");
|
||||
if ((result->DT_Exchange & 0x0F) != 0)
|
||||
{
|
||||
TransferExchangeTargets(result->DT_Exchange, "<>");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("None");
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
free(result);
|
||||
}
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
FatalError("Usage: loaderinfo -f <generic-device>\n");
|
||||
}
|
||||
|
||||
|
||||
/* we only have one argument: "-f <device>". */
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
DEVICE_TYPE fd;
|
||||
char *filename;
|
||||
|
||||
argv0=argv[0];
|
||||
if (argc != 3)
|
||||
{
|
||||
fprintf(stderr,"argc=%d",argc);
|
||||
usage();
|
||||
}
|
||||
|
||||
if (strcmp(argv[1],"-f")!=0)
|
||||
{
|
||||
usage();
|
||||
}
|
||||
|
||||
filename=argv[2];
|
||||
|
||||
fd=SCSI_OpenDevice(filename);
|
||||
|
||||
/* Now to call the various routines: */
|
||||
ReportInquiry(fd);
|
||||
ReportEAAP(fd);
|
||||
Report_TGDP(fd);
|
||||
Report_DCP(fd);
|
||||
exit(0);
|
||||
}
|
||||
19
mtx-1.3.12/makedist
Executable file
19
mtx-1.3.12/makedist
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
|
||||
# note -- this assumes 'bash' shell, GNU tar, 'gzip'.
|
||||
|
||||
# pass a version number e.g. 1.4.3 as 1st parameter...
|
||||
ME=`pwd`
|
||||
|
||||
# okay, now to create a spec file w/the proper version number:
|
||||
sed -e "1,\$s/@@VERSION@@/${1}/g" <mtx.spec.in >mtx.spec
|
||||
|
||||
cd ..
|
||||
if [ ! -s mtx-${1} ]
|
||||
then
|
||||
ln -s "${ME}" "mtx-${1}"
|
||||
fi
|
||||
|
||||
|
||||
tar --exclude CVS --exclude .svn -czvhf mtx-${1}.tar.gz mtx-${1}
|
||||
|
||||
124
mtx-1.3.12/mam2debug.c
Normal file
124
mtx-1.3.12/mam2debug.c
Normal file
@@ -0,0 +1,124 @@
|
||||
/* Mammoth 2 Debug Buffer Dumper
|
||||
Copyright 2000 Enhanced Software Technologies Inc.
|
||||
Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
|
||||
|
||||
$Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $
|
||||
$Revision: 193 $
|
||||
|
||||
Written by Eric Lee Green <eric@badtux.org>
|
||||
Released under the terms of the GNU General Public License v2 or
|
||||
above.
|
||||
|
||||
This is an example of how to use the mtx library file 'mtxl.c' to
|
||||
do a special-purpose task -- dump the Mammoth2 debug buffer, in this case.
|
||||
Note that this debug buffer is 1M-4M in size, thus may overwhelm the
|
||||
SCSI generic subsystem on some supported platforms...
|
||||
|
||||
syntax:
|
||||
|
||||
mam2debug generic-filename output-filename.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "mtx.h"
|
||||
#include "mtxl.h"
|
||||
|
||||
/* This is a TOTALLY UNDOCUMENTED feature to read the debug data buffer
|
||||
* in an Exabyte Mammoth II and dump it to a file:
|
||||
*/
|
||||
|
||||
static RequestSense_T *DumpM2DebugBuff(DEVICE_TYPE MediumChangerFD, int outfile)
|
||||
{
|
||||
RequestSense_T *RequestSense = xmalloc(sizeof(RequestSense_T));
|
||||
CDB_T CDB;
|
||||
|
||||
unsigned char *databuffer;
|
||||
unsigned char buff_descriptor[4];
|
||||
int numbytes;
|
||||
int testbytes;
|
||||
|
||||
CDB[0]=0x3c; /* command. */
|
||||
CDB[1]=0x03; /* mode - read buff_descriptor! */
|
||||
CDB[2]=0x01; /* page. */
|
||||
CDB[3]=0; /* offset. */
|
||||
CDB[4]=0;
|
||||
CDB[5]=0;
|
||||
CDB[6]=0; /* length. */
|
||||
CDB[7]=0;
|
||||
CDB[8]=4; /* the descriptor is 4 long. */
|
||||
CDB[9]=0;
|
||||
|
||||
if ((testbytes=SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 10,
|
||||
buff_descriptor, 4, RequestSense)) != 0){
|
||||
fprintf(stderr,"mam2debug: could not read buff_descriptor. [%d]\n",testbytes);
|
||||
return RequestSense; /* couldn't do it. */
|
||||
}
|
||||
|
||||
/* okay, read numbytes: */
|
||||
numbytes=(buff_descriptor[1]<<16) + (buff_descriptor[2]<<8) + buff_descriptor[3];
|
||||
databuffer=(unsigned char *) xmalloc(numbytes+1000000); /* see if this helps :-(. */
|
||||
CDB[6]=buff_descriptor[1];
|
||||
CDB[7]=buff_descriptor[2];
|
||||
CDB[8]=buff_descriptor[3];
|
||||
|
||||
CDB[1]=0x02; /* mode -- read buffer! */
|
||||
|
||||
if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 10,
|
||||
databuffer, numbytes, RequestSense) != 0){
|
||||
fprintf(stderr,"mam2debug: could not read buffer.\n");
|
||||
free(databuffer);
|
||||
return RequestSense; /* couldn't do it. */
|
||||
}
|
||||
|
||||
write(outfile,databuffer,numbytes);
|
||||
close(outfile);
|
||||
free(databuffer);
|
||||
free(RequestSense);
|
||||
return NULL; /* okay! */
|
||||
}
|
||||
|
||||
static void usage(void) {
|
||||
fprintf(stderr,"Usage: mam2debug scsi-generic-file output-file-name\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Now for the actual main() routine: */
|
||||
|
||||
int main(int argc,char** argv) {
|
||||
DEVICE_TYPE changer_fd;
|
||||
static RequestSense_T *result;
|
||||
int outfile;
|
||||
|
||||
if (argc != 3) {
|
||||
usage();
|
||||
}
|
||||
|
||||
changer_fd=SCSI_OpenDevice(argv[1]);
|
||||
|
||||
if (changer_fd <= 0) {
|
||||
fprintf(stderr,"Could not open input device\n");
|
||||
usage();
|
||||
}
|
||||
|
||||
outfile=open(argv[2],O_CREAT|O_WRONLY);
|
||||
if (outfile <=0) {
|
||||
fprintf(stderr,"Could not open output file\n");
|
||||
usage();
|
||||
}
|
||||
|
||||
result=DumpM2DebugBuff(changer_fd, outfile);
|
||||
|
||||
if (result) {
|
||||
PrintRequestSense(result);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
124
mtx-1.3.12/mam2debug2.c
Normal file
124
mtx-1.3.12/mam2debug2.c
Normal file
@@ -0,0 +1,124 @@
|
||||
/* Mammoth 2 Debug Buffer Dumper
|
||||
Copyright 2000 Enhanced Software Technologies Inc.
|
||||
Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
|
||||
|
||||
$Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $
|
||||
$Revision: 193 $
|
||||
|
||||
Written by Eric Lee Green <eric@badtux.org>
|
||||
Released under the terms of the GNU General Public License v2 or
|
||||
above.
|
||||
|
||||
This is an example of how to use the mtx library file 'mtxl.c' to
|
||||
do a special-purpose task -- dump the Mammoth2 debug buffer, in this case.
|
||||
Note that this debug buffer is 1M-4M in size, thus may overwhelm the
|
||||
SCSI generic subsystem on some supported platforms...
|
||||
|
||||
syntax:
|
||||
|
||||
mam2debug generic-filename output-filename.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "mtx.h"
|
||||
#include "mtxl.h"
|
||||
|
||||
/* This is a TOTALLY UNDOCUMENTED feature to read the debug data buffer
|
||||
* in an Exabyte Mammoth II and dump it to a file:
|
||||
*/
|
||||
|
||||
static RequestSense_T *DumpM2DebugBuff(DEVICE_TYPE MediumChangerFD, int outfile)
|
||||
{
|
||||
RequestSense_T *RequestSense = xmalloc(sizeof(RequestSense_T));
|
||||
CDB_T CDB;
|
||||
|
||||
unsigned char *databuffer;
|
||||
unsigned char buff_descriptor[4];
|
||||
int numbytes;
|
||||
int testbytes;
|
||||
|
||||
CDB[0]=0x3c; /* command. */
|
||||
CDB[1]=0x03; /* mode - read buff_descriptor! */
|
||||
CDB[2]=0x00; /* page -- data. */
|
||||
CDB[3]=0; /* offset. */
|
||||
CDB[4]=0;
|
||||
CDB[5]=0;
|
||||
CDB[6]=0; /* length. */
|
||||
CDB[7]=0;
|
||||
CDB[8]=4; /* the descriptor is 4 long. */
|
||||
CDB[9]=0;
|
||||
|
||||
if ((testbytes=SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 10,
|
||||
buff_descriptor, 4, RequestSense)) != 0){
|
||||
fprintf(stderr,"mam2debug: could not read buff_descriptor. [%d]\n",testbytes);
|
||||
return RequestSense; /* couldn't do it. */
|
||||
}
|
||||
|
||||
/* okay, read numbytes: */
|
||||
numbytes=(buff_descriptor[1]<<16) + (buff_descriptor[2]<<8) + buff_descriptor[3];
|
||||
databuffer=(unsigned char *) xmalloc(numbytes+1000000); /* see if this helps :-(. */
|
||||
CDB[6]=buff_descriptor[1];
|
||||
CDB[7]=buff_descriptor[2];
|
||||
CDB[8]=buff_descriptor[3];
|
||||
|
||||
CDB[1]=0x02; /* mode -- read buffer! */
|
||||
|
||||
if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 10,
|
||||
databuffer, numbytes, RequestSense) != 0){
|
||||
fprintf(stderr,"mam2debug: could not read buffer.\n");
|
||||
free(databuffer);
|
||||
return RequestSense; /* couldn't do it. */
|
||||
}
|
||||
|
||||
write(outfile,databuffer,numbytes);
|
||||
close(outfile);
|
||||
free(databuffer);
|
||||
free(RequestSense);
|
||||
return NULL; /* okay! */
|
||||
}
|
||||
|
||||
static void usage(void) {
|
||||
fprintf(stderr,"Usage: mam2debug scsi-generic-file output-file-name\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Now for the actual main() routine: */
|
||||
|
||||
int main(int argc,char** argv) {
|
||||
DEVICE_TYPE changer_fd;
|
||||
static RequestSense_T *result;
|
||||
int outfile;
|
||||
|
||||
if (argc != 3) {
|
||||
usage();
|
||||
}
|
||||
|
||||
changer_fd=SCSI_OpenDevice(argv[1]);
|
||||
|
||||
if (changer_fd <= 0) {
|
||||
fprintf(stderr,"Could not open input device\n");
|
||||
usage();
|
||||
}
|
||||
|
||||
outfile=open(argv[2],O_CREAT|O_WRONLY);
|
||||
if (outfile <=0) {
|
||||
fprintf(stderr,"Could not open output file\n");
|
||||
usage();
|
||||
}
|
||||
|
||||
result=DumpM2DebugBuff(changer_fd, outfile);
|
||||
|
||||
if (result) {
|
||||
PrintRequestSense(result);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
37
mtx-1.3.12/msvc/config.h
Normal file
37
mtx-1.3.12/msvc/config.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/* config.h. Generated by configure. */
|
||||
/* Copyright 2001 Enhanced Software Technologies Inc.
|
||||
* Released under GNU General Public License V2 or Above
|
||||
* See http://www.gnu.org for more information about the terms of
|
||||
* the GNU General Public License.
|
||||
* $Date: 2007-01-28 19:23:33 -0800 (Sun, 28 Jan 2007) $
|
||||
* $Revision: 125 $
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H 1
|
||||
|
||||
/* autoconf changes these. */
|
||||
#define HAVE_STRING_H 1
|
||||
#define HAVE_UNISTD_H 0
|
||||
#define HAVE_STDLIB_H 1
|
||||
#define HAVE_STDARG_H 1
|
||||
#define HAVE_SCSI_SCSI_H 0
|
||||
#define HAVE_SCSI_SCSI_IOCTL_H 0
|
||||
#define HAVE_SCSI_SG_H 0
|
||||
#define HAVE_SYS_GSCDDS_H 0
|
||||
#define HAVE_CAMLIB_H 0
|
||||
#define HAVE_SYS_SCSI_IMPL_USCSI_H 0
|
||||
#define HAVE_SYS_SCSI_CTL_H 0
|
||||
#define HAVE_DSLIB_H 0
|
||||
#define HAVE_DU_DEFS_H 0
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
#define HAVE_FCNTL_H 1
|
||||
#define HAVE_SYS_IOCTL_H 0
|
||||
#define HAVE_SYS_MTIO_H 0
|
||||
#define HAVE_DDK_NTDDSCSI_H 0
|
||||
|
||||
#define WORDS_BIGENDIAN 0
|
||||
|
||||
#endif
|
||||
|
||||
205
mtx-1.3.12/msvc/loaderinfo/loaderinfo.vcproj
Normal file
205
mtx-1.3.12/msvc/loaderinfo/loaderinfo.vcproj
Normal file
@@ -0,0 +1,205 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="loaderinfo"
|
||||
ProjectGUID="{13712060-F1FC-4498-97A7-5DA5A38F04DD}"
|
||||
RootNamespace="loaderinfo"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories=".."
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="4"
|
||||
DisableSpecificWarnings="4214"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories=".."
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="3"
|
||||
DisableSpecificWarnings="4214"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\loaderinfo.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\mtxl.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
50
mtx-1.3.12/msvc/mtx.sln
Normal file
50
mtx-1.3.12/msvc/mtx.sln
Normal file
@@ -0,0 +1,50 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 9.00
|
||||
# Visual Studio 2005
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "loaderinfo", "loaderinfo\loaderinfo.vcproj", "{13712060-F1FC-4498-97A7-5DA5A38F04DD}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mtx", "mtx\mtx.vcproj", "{7DD926F5-30EA-47D4-B67B-E32C0E221440}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scsitape", "scsitape\scsitape.vcproj", "{D19E95BD-87C6-4C91-A208-FB8338580F75}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tapeinfo", "tapeinfo\tapeinfo.vcproj", "{A1C8D34F-66EC-4F74-8261-C96B97727218}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nsmhack", "nsmhack\nsmhack.vcproj", "{1B3C0A23-4021-4928-92FA-76743B7F7F76}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scsieject", "scsieject\scsieject.vcproj", "{E3B77A78-FD72-4AD7-933A-0503FB21551D}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{13712060-F1FC-4498-97A7-5DA5A38F04DD}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{13712060-F1FC-4498-97A7-5DA5A38F04DD}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{13712060-F1FC-4498-97A7-5DA5A38F04DD}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{13712060-F1FC-4498-97A7-5DA5A38F04DD}.Release|Win32.Build.0 = Release|Win32
|
||||
{7DD926F5-30EA-47D4-B67B-E32C0E221440}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{7DD926F5-30EA-47D4-B67B-E32C0E221440}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{7DD926F5-30EA-47D4-B67B-E32C0E221440}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{7DD926F5-30EA-47D4-B67B-E32C0E221440}.Release|Win32.Build.0 = Release|Win32
|
||||
{D19E95BD-87C6-4C91-A208-FB8338580F75}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{D19E95BD-87C6-4C91-A208-FB8338580F75}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{D19E95BD-87C6-4C91-A208-FB8338580F75}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{D19E95BD-87C6-4C91-A208-FB8338580F75}.Release|Win32.Build.0 = Release|Win32
|
||||
{A1C8D34F-66EC-4F74-8261-C96B97727218}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{A1C8D34F-66EC-4F74-8261-C96B97727218}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{A1C8D34F-66EC-4F74-8261-C96B97727218}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{A1C8D34F-66EC-4F74-8261-C96B97727218}.Release|Win32.Build.0 = Release|Win32
|
||||
{1B3C0A23-4021-4928-92FA-76743B7F7F76}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{1B3C0A23-4021-4928-92FA-76743B7F7F76}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{1B3C0A23-4021-4928-92FA-76743B7F7F76}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{1B3C0A23-4021-4928-92FA-76743B7F7F76}.Release|Win32.Build.0 = Release|Win32
|
||||
{E3B77A78-FD72-4AD7-933A-0503FB21551D}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{E3B77A78-FD72-4AD7-933A-0503FB21551D}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{E3B77A78-FD72-4AD7-933A-0503FB21551D}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{E3B77A78-FD72-4AD7-933A-0503FB21551D}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
49
mtx-1.3.12/msvc/mtx/Distributions.txt
Normal file
49
mtx-1.3.12/msvc/mtx/Distributions.txt
Normal file
@@ -0,0 +1,49 @@
|
||||
Debian
|
||||
======
|
||||
|
||||
Maintainer: BDale Garbee (bdale@gag.com) (Official)
|
||||
Stable Version: 1.2.16rel-4
|
||||
Testing Version: 1.2.17rel-2
|
||||
|
||||
Merged: Yes
|
||||
|
||||
FreeBSD
|
||||
|
||||
Maintainer: mbr@freebsd.org
|
||||
Stable Version: 1.2.17rel
|
||||
|
||||
Merged: Yes
|
||||
|
||||
Gentoo
|
||||
======
|
||||
|
||||
Maintainer: Tom Gall (tgall@gentoo.org) (Last change)
|
||||
Stable Version: 1.2.18
|
||||
|
||||
Merged: No changes
|
||||
|
||||
Mandriva
|
||||
========
|
||||
|
||||
Maintainer: Buchan Milne <bgmilne@linux-mandrake.com>
|
||||
Stable Version: 1.2.18-1mdk
|
||||
|
||||
Merged: No changes
|
||||
|
||||
|
||||
Redhat
|
||||
======
|
||||
|
||||
Maintainer: Jesse Keating <jkeating@redhat.com> (Last change) (jnovy@redhat.com)
|
||||
Stable Version: 1.2.18-8
|
||||
|
||||
Merged: No additional changes
|
||||
|
||||
|
||||
SuSE
|
||||
====
|
||||
|
||||
Maintainer http://www.suse.de/feedback
|
||||
Stable Version: 1.2.18rel-119
|
||||
|
||||
Merged: No additional changes
|
||||
247
mtx-1.3.12/msvc/mtx/mtx.vcproj
Normal file
247
mtx-1.3.12/msvc/mtx/mtx.vcproj
Normal file
@@ -0,0 +1,247 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="mtx"
|
||||
ProjectGUID="{7DD926F5-30EA-47D4-B67B-E32C0E221440}"
|
||||
RootNamespace="mtx"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="VERSION=\"1.3.9-rbn\";LONG_PRINT_REQUEST_SENSE;WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="4"
|
||||
DisableSpecificWarnings="4214"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="VERSION=\"1.3.11\";WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="3"
|
||||
DisableSpecificWarnings="4214"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\mtx.c"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
CompileAs="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
CompileAs="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\mtxl.c"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
CompileAs="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
CompileAs="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\mtx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\mtxl.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath=".\Distributions.txt"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
213
mtx-1.3.12/msvc/nsmhack/nsmhack.vcproj
Normal file
213
mtx-1.3.12/msvc/nsmhack/nsmhack.vcproj
Normal file
@@ -0,0 +1,213 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="nsmhack"
|
||||
ProjectGUID="{1B3C0A23-4021-4928-92FA-76743B7F7F76}"
|
||||
RootNamespace="nsmhack"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories=".."
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="4"
|
||||
DisableSpecificWarnings="4214"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories=".."
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="3"
|
||||
DisableSpecificWarnings="4214"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\mtxl.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\nsmhack.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\mtx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\mtxl.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
203
mtx-1.3.12/msvc/scsieject/scsieject.vcproj
Normal file
203
mtx-1.3.12/msvc/scsieject/scsieject.vcproj
Normal file
@@ -0,0 +1,203 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="scsieject"
|
||||
ProjectGUID="{E3B77A78-FD72-4AD7-933A-0503FB21551D}"
|
||||
RootNamespace="scsieject"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="4"
|
||||
DisableSpecificWarnings="4214;4996"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="3"
|
||||
DisableSpecificWarnings="4214;4996"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\mtxl.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\scsieject.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
203
mtx-1.3.12/msvc/scsitape/scsitape.vcproj
Normal file
203
mtx-1.3.12/msvc/scsitape/scsitape.vcproj
Normal file
@@ -0,0 +1,203 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="scsitape"
|
||||
ProjectGUID="{D19E95BD-87C6-4C91-A208-FB8338580F75}"
|
||||
RootNamespace="scsitape"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="4"
|
||||
DisableSpecificWarnings="4214;4996"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="3"
|
||||
DisableSpecificWarnings="4214;4996"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\mtxl.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\scsitape.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
213
mtx-1.3.12/msvc/tapeinfo/tapeinfo.vcproj
Normal file
213
mtx-1.3.12/msvc/tapeinfo/tapeinfo.vcproj
Normal file
@@ -0,0 +1,213 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="tapeinfo"
|
||||
ProjectGUID="{A1C8D34F-66EC-4F74-8261-C96B97727218}"
|
||||
RootNamespace="tapeinfo"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories=".."
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="4"
|
||||
DisableSpecificWarnings="4214"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories=".."
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="3"
|
||||
DisableSpecificWarnings="4214"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\mtxl.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\tapeinfo.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\mtx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\mtxl.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
257
mtx-1.3.12/mtx.1
Normal file
257
mtx-1.3.12/mtx.1
Normal file
@@ -0,0 +1,257 @@
|
||||
.\" mtx.1 Document copyright 2000 Eric Lee Green
|
||||
.\" Program Copyright 1996, 1997 Leonard Zubkoff
|
||||
.\" Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
|
||||
.\" Extensive changes 2000 by Eric Lee Green <eric@badtux.org>
|
||||
.\"
|
||||
.\" This is free documentation; you can redistribute it and/or
|
||||
.\" modify it under the terms of the GNU General Public License as
|
||||
.\" published by the Free Software Foundation; either version 2 of
|
||||
.\" the License, or (at your option) any later version.
|
||||
.\"
|
||||
.\" The GNU General Public License's references to "object code"
|
||||
.\" and "executables" are to be interpreted as the output of any
|
||||
.\" document formatting or typesetting system, including
|
||||
.\" intermediate and printed output.
|
||||
.\"
|
||||
.\" This manual is distributed in the hope that it will be useful,
|
||||
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
.\" GNU General Public License for more details.
|
||||
.\"
|
||||
.\" You should have received a copy of the GNU General Public
|
||||
.\" License along with this manual; if not, write to the Free
|
||||
.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
|
||||
.\" USA.
|
||||
.\"
|
||||
.TH MTX 1 MTX1.3
|
||||
.SH NAME
|
||||
mtx \- control SCSI media changer devices
|
||||
.SH SYNOPSIS
|
||||
mtx [-f <scsi-generic-device>] [nobarcode] [invert] [noattach] command [ command ... ]
|
||||
.SH DESCRIPTION
|
||||
The
|
||||
.B mtx
|
||||
command controls single or multi-drive SCSI media changers such as
|
||||
tape changers, autoloaders, tape libraries, or optical media jukeboxes.
|
||||
It can also be used with media changers that use the 'ATTACHED' API,
|
||||
presuming that they properly report the MChanger bit as required
|
||||
by the SCSI T-10 SMC specification.
|
||||
.SH OPTIONS
|
||||
The first argument, given following
|
||||
.B -f
|
||||
, is the SCSI generic device corresponding to your media changer.
|
||||
Consult your operating system's documentation for more information (for
|
||||
example, under Linux these are generally /dev/sg0 through /dev/sg15,
|
||||
under FreeBSD these are /dev/pass0 through /dev/passX,
|
||||
under SunOS it may be a file under /dev/rdsk).
|
||||
.P
|
||||
The 'invert' option will invert (flip) the media (for optical jukeboxes that
|
||||
allow such) before inserting it into the drive or returning it to the
|
||||
storage slot.
|
||||
.P
|
||||
The 'noattach' option forces the regular media changer API even if the
|
||||
media changer incorrectly reported that it uses the 'ATTACHED' API.
|
||||
.P
|
||||
The 'nobarcode' option forces the loader to not request barcodes even if
|
||||
the loader is capable of reporting them.
|
||||
.P
|
||||
Following these options there may follow
|
||||
one or more robotics control
|
||||
commands. Note that the 'invert' and 'noattach'
|
||||
options apply to ALL of robotics control
|
||||
commands.
|
||||
|
||||
.SH COMMANDS
|
||||
.TP 10
|
||||
.B --version
|
||||
Report the mtx version number (e.g. mtx 1.2.8) and exit.
|
||||
|
||||
.TP 10
|
||||
.B inquiry
|
||||
Report the product type (Medium Changer, Tape Drive, etc.), Vendor ID,
|
||||
Product ID, Revision, and whether this uses the Attached Changer API
|
||||
(some tape drives use this rather than reporting a Medium Changer on a
|
||||
separate LUN or SCSI address).
|
||||
.TP 10
|
||||
.B noattach
|
||||
Make further commands use the regular media changer API rather than the
|
||||
_ATTACHED API, no matter what the "Attached" bit said in the Inquiry info.
|
||||
Needed with some brain-dead changers that report Attached bit but don't respond
|
||||
to _ATTACHED API.
|
||||
.TP 10
|
||||
.B inventory
|
||||
Makes the robot arm go and check what elements are in the slots. This
|
||||
is needed for a few libraries like the Breece Hill ones that do not
|
||||
automatically check the tape inventory at system startup.
|
||||
.TP 10
|
||||
.B status
|
||||
Reports how many drives and storage elements are contained in the
|
||||
device. For each drive, reports whether it has media loaded in it, and
|
||||
if so, from which storage slot the media originated. For each storage
|
||||
slot, reports whether it is empty or full, and if the media changer
|
||||
has a bar code, MIC reader, or some other way of uniquely identifying
|
||||
media without loading it into a drive, this reports the volume tag
|
||||
and/or alternate volume tag for each piece of media.
|
||||
For historical reasons drives are numbered from 0 and storage slots are
|
||||
numbered from 1.
|
||||
.TP 10
|
||||
.B load <slotnum> [ <drivenum> ]
|
||||
Load media from slot <slotnum> into drive <drivenum>. Drive 0 is assumed
|
||||
if the drive number is omitted.
|
||||
.TP 10
|
||||
.B unload [<slotnum>] [ <drivenum> ]
|
||||
Unloads media from drive <drivenum> into slot <slotnum>. If <drivenum> is
|
||||
omitted, defaults to drive 0 (as do all commands).
|
||||
If <slotnum> is omitted, defaults to the slot
|
||||
that the drive was loaded from. Note that there's currently no way to
|
||||
say 'unload drive 1's media to the slot it came from', other than to
|
||||
explicitly use that slot number as the destination.
|
||||
.TP 10
|
||||
.B [eepos <operation>] transfer <slotnum> <slotnum>
|
||||
Transfers media from one slot to another, assuming that your mechanism is
|
||||
capable of doing so. Usually used to move media to/from an import/export
|
||||
port. 'eepos' is used to extend/retract the import/export
|
||||
tray on certain mid-range to high end tape libraries (if, e.g., the tray was
|
||||
slot 32, you might say say 'eepos 1 transfer 32 32' to extend the tray).
|
||||
Valid values for eepos <operation>
|
||||
are 0 (do nothing to the import/export tray), 1, and 2 (what 1 and 2 do varies
|
||||
depending upon the library, consult your library's SCSI-level
|
||||
documentation).
|
||||
.TP 10
|
||||
.B [eepos <operation>] [invert] [invert2] exchange <slotnum> <slotnum> [<slotnum>]
|
||||
Move medium from the first slot to the second slot, placing the medium
|
||||
currently in the second slot either back into the first slot or into the
|
||||
optional third slot.
|
||||
|
||||
.TP 10
|
||||
.B first [<drivenum>]
|
||||
Loads drive <drivenum> from the first slot in the media
|
||||
changer. Unloads the drive if there is already media in it (note: you
|
||||
may need to eject the tape using your OS's tape control commands
|
||||
first). Note that this command may not be what you want on large
|
||||
tape libraries -- e.g. on Exabyte 220, the first slot is usually a
|
||||
cleaning tape. If <drivenum> is omitted, defaults to first drive.
|
||||
|
||||
.TP 10
|
||||
.B last [<drivenum>]
|
||||
Loads drive <drivenum> from the last slot in the media changer. Unloads
|
||||
the drive if there is already a tape in it. (Note: you may need to eject
|
||||
the tape using your OS's tape control commands first).
|
||||
.TP 10
|
||||
.B next [<drivenum>]
|
||||
Unloads the drive and loads the next tape in sequence. If the drive was
|
||||
empty, loads the first tape into the drive.
|
||||
.TP 10
|
||||
.B position <slotnum>
|
||||
Positions the robot at a specific slot. Needed by some changers to
|
||||
move to and open the import/export, or mailbox, slot.
|
||||
|
||||
.SH AUTHORS
|
||||
The original 'mtx' program was written by Leonard Zubkoff and extensively
|
||||
revised for large multi-drive libraries with bar code readers
|
||||
by Eric Lee Green <eric@badtux.org>. See 'mtx.c' for other contributors.
|
||||
.SH BUGS AND LIMITATIONS
|
||||
.P
|
||||
You may need to do a 'mt offline' on the tape drive to eject the tape
|
||||
before you can issue the 'mtx unload' command. The Exabyte EZ-17 and 220
|
||||
in particular will happily sit there snapping the robot arm's claws around
|
||||
thin air trying to grab a tape that's not there.
|
||||
.P
|
||||
For some Linux distributions, you may need to re-compile the kernel to
|
||||
scan SCSI LUN's in order to detect the media changer. Check /proc/scsi/scsi
|
||||
to see what's going on.
|
||||
.P
|
||||
If you try to unload a tape to its 'source' slot, and said slot is
|
||||
full, it will instead put the tape into the first empty
|
||||
slot. Unfortunately the list of empty slots is not updated between
|
||||
commands on the command line, so if you try to unload another drive to
|
||||
a full 'source' slot during the same invocation of 'mtx', it will try
|
||||
to unload to the same (no longer empty) slot and will urp with a SCSI
|
||||
error.
|
||||
.P
|
||||
|
||||
This program reads the Mode Sense Element Address Assignment Page
|
||||
(SCSI) and requests data on all available elements. For larger
|
||||
libraries (more than a couple dozen elements)
|
||||
this sets a big Allocation_Size in the SCSI command block for the
|
||||
REQUEST_ELEMENT_STATUS command in order to be able to read the entire
|
||||
result of a big tape library. Some operating systems may not be able
|
||||
to handle this. Versions of Linux earlier than 2.2.6, in particular,
|
||||
may fail this request due to inability to find contiguous pages of
|
||||
memory for the SCSI transfer (later versions of Linux 'sg' device do
|
||||
scatter-gather so that this should no longer be a problem).
|
||||
.P
|
||||
The
|
||||
.B eepos
|
||||
command remains in effect for all further commands on a command
|
||||
line. Thus you might want to follow
|
||||
.B eepos 1 transfer 32 32
|
||||
with
|
||||
.B eepos 0
|
||||
as
|
||||
the next command (which clears the
|
||||
.B eepos
|
||||
bits).
|
||||
.P
|
||||
Need a better name for 'eepos' command! ('eepos' is the name of the bit
|
||||
field in the actual low-level SCSI command, and has nothing to do with what
|
||||
it does).
|
||||
.P
|
||||
|
||||
This program has only been tested on Linux with a limited number of
|
||||
tape loaders (a dual-drive Exabyte 220 tape library, with bar-code
|
||||
reader and 21 slots, an Exabyte EZ-17 7-slot autoloader, and a Seagate
|
||||
DDS-4 autochanger with 6 slots). It may not work on other operating systems
|
||||
with larger libraries,
|
||||
due to the big SCSI request size.
|
||||
Please see the projecdt page http://sourceforge.net/projects/mtx for information
|
||||
on reporting bugs, requesting features and the mailing list for peer support.
|
||||
.SH HINTS
|
||||
Under Linux,
|
||||
.B cat /proc/scsi/scsi
|
||||
will tell you what SCSI devices you have.
|
||||
You can then refer to them as
|
||||
.B /dev/sga,
|
||||
.B /dev/sgb,
|
||||
etc. by the order they
|
||||
are reported.
|
||||
.P
|
||||
Under FreeBSD,
|
||||
.B camcontrol devlist
|
||||
will tell you what SCSI devices you
|
||||
have, along with which
|
||||
.B pass
|
||||
device controls them.
|
||||
.P
|
||||
Under Solaris, set up your 'sgen' driver so that it'll look for
|
||||
tape changers (see /kernel/drv/sgen.conf and the sgen man page), type
|
||||
.B touch /reconfigure
|
||||
then reboot. You can find your changer in /devices by typing
|
||||
.B /usr/sbin/devfsadm -C
|
||||
to clean out no-longer-extant entries in your /devices directory, then
|
||||
.B find /devices -name \e\(**changer -print
|
||||
to find the device name. Set the symbolic link
|
||||
.B /dev/changer
|
||||
to point
|
||||
to that device name (if it is not doing so already).
|
||||
.P
|
||||
With BRU, set your mount and unmount commands as described on the BRU
|
||||
web site at http://www.bru.com to move to the next tape when backing up
|
||||
or restoring. With GNU
|
||||
.B tar,
|
||||
see
|
||||
.B mtx.doc
|
||||
for an example of how to use
|
||||
.B tar
|
||||
and
|
||||
.B mtx
|
||||
to make multi-tape backups.
|
||||
|
||||
.SH AVAILABILITY
|
||||
This version of
|
||||
.B mtx
|
||||
is currently being maintained by Robert Nelson <robertnelson@users.sourceforge.net> .
|
||||
The 'mtx' home page is http://mtx.sourceforge.net and the actual code is currently available
|
||||
there and via SVN from http://sourceforge.net/projects/mtx.
|
||||
.SH SEE ALSO
|
||||
.BR mt (1), loaderinfo (1), tapeinfo (1), scsitape (1), scsieject (1)
|
||||
1075
mtx-1.3.12/mtx.c
Normal file
1075
mtx-1.3.12/mtx.c
Normal file
File diff suppressed because it is too large
Load Diff
209
mtx-1.3.12/mtx.doc
Normal file
209
mtx-1.3.12/mtx.doc
Normal file
@@ -0,0 +1,209 @@
|
||||
[WARNING: This document is of historical value only! Please read
|
||||
'mtxl.README.html' and 'man mtx' for current documentation! The only
|
||||
thing useful here is examples of how to use the 'tar' command for
|
||||
multi-tape backups.
|
||||
]
|
||||
|
||||
MTX - SCSI Tape Medium Changer Control Program
|
||||
|
||||
Version 1.1 for Linux, Solaris, IRIX, Digital Unix, and OpenVMS
|
||||
|
||||
2 June 1998
|
||||
|
||||
Leonard N. Zubkoff
|
||||
Dandelion Digital
|
||||
lnz@dandelion.com
|
||||
|
||||
Copyright 1997-1998 by Leonard N. Zubkoff <lnz@dandelion.com>
|
||||
|
||||
|
||||
INTRODUCTION
|
||||
|
||||
The MTX program controls the robotic mechanism in DDS Autoloaders such as the
|
||||
Seagate 4586NP (Archive Python 28849-XXX). This program is also reported to
|
||||
work with the Seagate 4584NP, HP Surestore 12000, Quantum DLT 2500 XT, and AIWA
|
||||
DL-210. The 4586NP responds to both Logical Units 0 and 1 on the selected
|
||||
Target ID. Logical Unit 0 supports commands from the SCSI-3 Sequential Stream
|
||||
Device Command Set and must be accessed via the SCSI tape devices /dev/st<N>.
|
||||
Logical Unit 1 only supports commands from the SCSI-3 Medium Changer Command
|
||||
Set and must be accessed via the SCSI Generic devices /dev/sg<N>. In addition,
|
||||
Logical Unit 0 also acts as an Attached Medium Changer and supports the READ
|
||||
ELEMENT STATUS and MOVE MEDIUM commands. Since using the Primary Device
|
||||
(Logical Unit 0) via the Attached Medium Changer interface is sufficient for
|
||||
the commands provided by this program, Logical Unit 1 is not normally used.
|
||||
The AIWA DL-210, by contrast, does not support the Attached Medium Changer
|
||||
commands on Logical Unit 0 and so MTX must be used with Logical Unit 1 via the
|
||||
SCSI Generic devices /dev/sg<N>. Note that when using the SCSI Generic devices
|
||||
the Linux kernel option "max_scsi_luns=2" may be necessary.
|
||||
|
||||
Medium Changers support four types of elements: Medium Transport Elements,
|
||||
Storage Elements, Import Export Elements, and Data Transfer Elements. For the
|
||||
limited case of DDS Autoloaders, only the Data Transfer Element and Storage
|
||||
Element types are really applicable. The Data Transfer Element is the primary
|
||||
device where a volume can be loaded to actually perform data transfers. A
|
||||
Storage Element is a place a volume can be when it is waiting to be used. For
|
||||
a DDS Autoloader, the Storage Elements are the slots in the cartridge where
|
||||
tapes may be placed, and the Data Transfer Element is the tape mechanism.
|
||||
|
||||
Every Medium Changer Element has a unique integer Element Address that
|
||||
identifies it in the address space of all Elements known to the Medium Changer.
|
||||
For the 4586NP, the Data Transfer Element is Address 1 and the Storage Elements
|
||||
are Addresses 2-5 or 2-13. To simplify the human interface, this program does
|
||||
not use Element Addresses directly. Rather, it uses Storage Element Numbers
|
||||
which range from 1 to the number of Storage Elements available.
|
||||
|
||||
The specific tape device to be operated on can either be supplied on the
|
||||
command line with the "-f <tape-device>" option, or via the TAPE environment
|
||||
variable.
|
||||
|
||||
|
||||
BUILDING MTX
|
||||
|
||||
The Makefile contains sections for Linux, Solaris/SPARC, SGI IRIX, and Digital
|
||||
UNIX. Comment/uncomment as necessary for the target environment. For OpenVMS,
|
||||
see the file "vms/000readme" for information on building MTX; a VMS release
|
||||
including pre-built binaries should be available from the WKU VMS FILESERV
|
||||
ARCHIVES, which are located at URLs http://www2.wku.edu/www/fileserv/ and
|
||||
ftp://ftp.wku.edu/vms/fileserv/.
|
||||
|
||||
|
||||
COMMANDS
|
||||
|
||||
MTX provides the following commands:
|
||||
|
||||
|
||||
mtx [ -f <tape-device> ] inquiry
|
||||
|
||||
The "inquiry" command reports the Vendor ID, Product ID, and Revision from a
|
||||
SCSI INQUIRY command.
|
||||
|
||||
kelewan:~# setenv TAPE /dev/st0
|
||||
|
||||
kelewan:~# mtx inquiry
|
||||
Vendor ID: 'ARCHIVE ', Product ID: 'Python 28849-XXX', Revision: '4.CM'
|
||||
|
||||
|
||||
mtx [ -f <tape-device> ] status
|
||||
|
||||
The "status" command reports on the status of the DDS Autloader. The report
|
||||
indicates the status of the Data Transfer Element and each of the Storage
|
||||
Elements. In the first example, no tape is currently loaded. In the second
|
||||
example, Storage Element Number 1 is loaded. The Storage Element loaded into
|
||||
the Data Transfer Element is usually reported by the DDS Autoloader, or it can
|
||||
be inferred by MTX if there is only a single empty Storage Element.
|
||||
|
||||
kelewan:~# mtx status
|
||||
Data Transfer Element: Empty
|
||||
Storage Element 1: Full
|
||||
Storage Element 2: Full
|
||||
Storage Element 3: Full
|
||||
Storage Element 4: Full
|
||||
|
||||
|
||||
kelewan:~# mtx status
|
||||
Data Transfer Element: Full (Storage Element 1 Loaded)
|
||||
Storage Element 1: Empty
|
||||
Storage Element 2: Full
|
||||
Storage Element 3: Full
|
||||
Storage Element 4: Full
|
||||
|
||||
|
||||
mtx [ -f <tape-device> ] load <storage-element-number>
|
||||
|
||||
The "load" command loads the volume in Storage Element <storage-element-number>
|
||||
into the Data Transfer Element. An error is signaled if the Data Transfer
|
||||
Element is already full.
|
||||
|
||||
|
||||
mtx [ -f <tape-device> ] unload [ <storage-element-number> ]
|
||||
|
||||
The "unload" command unloads the volume in the Data Transfer Element into
|
||||
Storage Element <storage-element-number>. If <storage-element-number> is not
|
||||
provided, then the volume is unloaded back into the Storage Element from which
|
||||
it was originally loaded, if known. An error is signaled if the Storage
|
||||
Element is already full.
|
||||
|
||||
|
||||
mtx [ -f <tape-device> ] first
|
||||
|
||||
The "first" command unloads any volume in the Data Transfer Element and then
|
||||
loads the volume in the lowest numbered non-empty Storage Element. If the
|
||||
correct Storage Element is already loaded, the unload/load is suppressed.
|
||||
|
||||
|
||||
mtx [ -f <tape-device> ] next
|
||||
|
||||
The "next" command unloads any volume in the Data Transfer Element and then
|
||||
loads the volume in the lowest numbered non-empty Storage Element above the
|
||||
Storage Element that was just unloaded. If there is no next Storage Element,
|
||||
the unload is still performed and the Data Transfer Element will be left empty
|
||||
so that the volume is not accidentally overwritten.
|
||||
|
||||
|
||||
mtx [ -f <tape-device> ] last
|
||||
|
||||
The "last" command unloads any volume in the Data Transfer Element and then
|
||||
loads the volume in the highest numbered non-empty Storage Element. If the
|
||||
correct Storage Element is already loaded, the unload/load is suppressed.
|
||||
|
||||
|
||||
mtx [ -f <tape-device> ] previous
|
||||
|
||||
The "previous" command unloads any volume in the Data Transfer Element and then
|
||||
loads the volume in the highest numbered non-empty Storage Element below the
|
||||
Storage Element that was just unloaded. If there is no previous Storage
|
||||
Element, the unload is still performed and the Data Transfer Element will be
|
||||
left empty so that the volume is not accidentally overwritten.
|
||||
|
||||
|
||||
The interface is designed to allow both explicit control of precisely which
|
||||
Storage Element is loaded, as well as sequential access among only the Storage
|
||||
Elements that actually have volumes present. Thus for example, one way of
|
||||
using MTX would be to perform Monday's incremental backups on Storage Element
|
||||
1, Tuesday's on Storage Element 2, and so on. Multi-volume full backups are
|
||||
also conveniently supported, as in:
|
||||
|
||||
setenv TAPE "/dev/st0"
|
||||
|
||||
mtx status
|
||||
|
||||
mtx first
|
||||
|
||||
time tar --create --one-file-system --atime-preserve \
|
||||
--listed-incremental `date +%y%m%d`.ss \
|
||||
--multi-volume --new-volume-script "mtx next" \
|
||||
--directory / <wherever>
|
||||
|
||||
mtx first
|
||||
|
||||
time tar --compare --multi-volume --new-volume-script "mtx next" \
|
||||
--directory /
|
||||
|
||||
mtx unload
|
||||
|
||||
|
||||
LINUX KERNEL REQUIREMENTS
|
||||
|
||||
Because the MOVE MEDIUM command may require 60 seconds or more to perform a
|
||||
volume load or unload request, a longer timeout must be provided. Linux
|
||||
kernels 2.0.30 and 2.1.28 should already contain a long enough timeout. For
|
||||
earlier kernels, edit the file "linux/drivers/scsi/scsi_ioctl.c" and add the
|
||||
following entries to the switch statement in ioctl_command:
|
||||
|
||||
case MOVE_MEDIUM:
|
||||
case READ_ELEMENT_STATUS:
|
||||
timeout = 5 * 60 * HZ; /* 5 minutes */
|
||||
retries = 1;
|
||||
break;
|
||||
|
||||
For older kernels, you may also need to add the following definitions to
|
||||
"linux/include/scsi/scsi.h":
|
||||
|
||||
#define MOVE_MEDIUM 0xa5
|
||||
#define READ_ELEMENT_STATUS 0xb8
|
||||
|
||||
Note also that "/usr/include/scsi" should be a symbolic link to the directory
|
||||
"linux/include/scsi" from your kernel source.
|
||||
|
||||
Finally, when using MTX you may see some console messages from the SCSI tape
|
||||
driver mentioning that there is no tape present. These can safely be ignored.
|
||||
607
mtx-1.3.12/mtx.h
Normal file
607
mtx-1.3.12/mtx.h
Normal file
@@ -0,0 +1,607 @@
|
||||
/* MTX -- SCSI Tape Attached Medium Control Program
|
||||
|
||||
Copyright 1997-1998 Leonard N. Zubkoff <lnz@dandelion.com>
|
||||
|
||||
Changes 1999 Eric Lee Green to add support for multi-drive tape changers.
|
||||
Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
|
||||
|
||||
$Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $
|
||||
$Revision: 193 $
|
||||
See mtx.c for licensing information.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef MTX_H /* protect against multiple includes... */
|
||||
#define MTX_H 1
|
||||
|
||||
/* surround all the Unix-stuff w/ifndef VMS */
|
||||
#ifdef VMS
|
||||
#include "[.vms]defs.h"
|
||||
#else /* all the Unix stuff: */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include "msvc/config.h" /* all the autoconf stuff. */
|
||||
#else
|
||||
#include "config.h" /* all the autoconf stuff. */
|
||||
#endif
|
||||
|
||||
/* all the general Unix includes: */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_FCNTL_H
|
||||
# include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# include <strings.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_STDARG_H
|
||||
# include <stdarg.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_SYS_STAT_H
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_SYS_IOCTL_H
|
||||
# include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_SYS_PARAM_H
|
||||
# include <sys/param.h>
|
||||
#endif
|
||||
|
||||
/* Now greatly modified to use GNU Autoconf stuff: */
|
||||
/* If we use the 'sg' interface, like Linux, do this: */
|
||||
#if HAVE_SCSI_SG_H
|
||||
# include <scsi/scsi.h>
|
||||
# include <scsi/scsi_ioctl.h>
|
||||
# include <scsi/sg.h>
|
||||
typedef int DEVICE_TYPE; /* the sg interface uses this. */
|
||||
# define HAVE_GET_ID_LUN 1 /* signal that we have it... */
|
||||
#endif
|
||||
|
||||
/* Windows Native programs built using MinGW */
|
||||
#if HAVE_DDK_NTDDSCSI_H
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# include <ddk/ntddscsi.h>
|
||||
# undef DEVICE_TYPE
|
||||
|
||||
typedef int DEVICE_TYPE;
|
||||
#endif
|
||||
|
||||
/* Windows Native programs built using Microsoft Visual C */
|
||||
#ifdef _MSC_VER
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# include <winioctl.h>
|
||||
# include <ntddscsi.h>
|
||||
# undef DEVICE_TYPE
|
||||
|
||||
typedef int DEVICE_TYPE;
|
||||
#endif
|
||||
|
||||
/* The 'cam' interface, like FreeBSD: */
|
||||
#if HAVE_CAMLIB_H
|
||||
# include <camlib.h> /* easy (?) access to the CAM user library. */
|
||||
# include <cam/cam_ccb.h>
|
||||
# include <cam/scsi/scsi_message.h> /* sigh sigh sigh! */
|
||||
typedef struct cam_device *DEVICE_TYPE;
|
||||
#endif
|
||||
|
||||
|
||||
/* the 'uscsi' interface, as used on Solaris: */
|
||||
#if HAVE_SYS_SCSI_IMPL_USCSI_H
|
||||
#include <sys/scsi/impl/uscsi.h>
|
||||
typedef int DEVICE_TYPE;
|
||||
#endif
|
||||
|
||||
/* the scsi_ctl interface, as used on HP/UX: */
|
||||
#if HAVE_SYS_SCSI_CTL_H
|
||||
# include <sys/wsio.h>
|
||||
# include <sys/spinlock.h>
|
||||
# include <sys/scsi.h>
|
||||
# include <sys/scsi_ctl.h>
|
||||
typedef int DEVICE_TYPE;
|
||||
# ifndef VERSION
|
||||
# define VERSION "1.2.12 hbb"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* the 'gsc' interface, as used on AIX: */
|
||||
#if HAVE_SYS_GSCDDS_H
|
||||
# include <sys/gscdds.h>
|
||||
typedef int DEVICE_TYPE;
|
||||
#endif
|
||||
|
||||
/* the 'dslib' interface, as used on SGI. */
|
||||
#if HAVE_DSLIB_H
|
||||
#include <dslib.h>
|
||||
typedef dsreq_t *DEVICE_TYPE; /* 64-bit pointers/32bit int on later sgi? */
|
||||
#endif
|
||||
|
||||
|
||||
#if ((defined(__alpha) && defined(__osf__)) || \
|
||||
defined(ultrix) || defined(__ultrix))
|
||||
#include "du/defs.h"
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* VMS protect. */
|
||||
|
||||
/* Do a test for LITTLE_ENDIAN_BITFIELDS. Use WORDS_BIGENDIAN as set
|
||||
* by configure:
|
||||
*/
|
||||
|
||||
#if WORDS_BIGENDIAN
|
||||
# define BIG_ENDIAN_BITFIELDS
|
||||
#else
|
||||
# define LITTLE_ENDIAN_BITFIELDS
|
||||
#endif
|
||||
|
||||
/* Get rid of some Hocky Pux defines: */
|
||||
#ifdef S_NO_SENSE
|
||||
#undef S_NO_SENSE
|
||||
#endif
|
||||
#ifdef S_RECOVERED_ERROR
|
||||
#undef S_RECOVERED_ERROR
|
||||
#endif
|
||||
#ifdef S_NOT_READY
|
||||
#undef S_NOT_READY
|
||||
#endif
|
||||
#ifdef S_MEDIUM_ERROR
|
||||
#undef S_MEDIUM_ERROR
|
||||
#endif
|
||||
#ifdef S_HARDWARE_ERROR
|
||||
#undef S_HARDWARE_ERROR
|
||||
#endif
|
||||
#ifdef S_UNIT_ATTENTION
|
||||
#undef S_UNIT_ATTENTION
|
||||
#endif
|
||||
#ifdef S_BLANK_CHECK
|
||||
#undef S_BLANK_CHECK
|
||||
#endif
|
||||
#ifdef S_VOLUME_OVERFLOW
|
||||
#undef S_VOLUME_OVERFLOW
|
||||
#endif
|
||||
|
||||
/* Note: These are only used for defaults for when we don't have
|
||||
* the element assignment mode page to tell us real amount...
|
||||
*/
|
||||
#define MAX_STORAGE_ELEMENTS 64 /* for the BIG jukeboxes! */
|
||||
#define MAX_TRANSFER_ELEMENTS 2 /* we just do dual-drive for now :-} */
|
||||
#define MAX_TRANSPORT_ELEMENTS 1 /* we just do one arm for now... */
|
||||
|
||||
#define MTX_ELEMENTSTATUS_ORIGINAL 0
|
||||
#define MTX_ELEMENTSTATUS_READALL 1
|
||||
|
||||
/* These are flags used for the READ_ELEMENT_STATUS and MOVE_MEDIUM
|
||||
* commands:
|
||||
*/
|
||||
typedef struct SCSI_Flags_Struct
|
||||
{
|
||||
unsigned char eepos;
|
||||
unsigned char invert;
|
||||
unsigned char no_attached; /* ignore _attached bit */
|
||||
unsigned char no_barcodes; /* don't try to get barcodes. */
|
||||
int numbytes;
|
||||
int elementtype;
|
||||
int numelements;
|
||||
int attached;
|
||||
int has_barcodes;
|
||||
int querytype; //MTX_ELEMENTSTATUS
|
||||
unsigned char invert2; /* used for EXCHANGE command, sigh. */
|
||||
} SCSI_Flags_T;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
typedef unsigned char boolean;
|
||||
|
||||
#define false 0
|
||||
#define true 1
|
||||
|
||||
typedef unsigned char Direction_T;
|
||||
|
||||
#define Input 0
|
||||
#define Output 1
|
||||
#else
|
||||
typedef enum { false, true } boolean;
|
||||
|
||||
typedef enum { Input, Output } Direction_T;
|
||||
#endif
|
||||
|
||||
|
||||
typedef unsigned char CDB_T[12];
|
||||
|
||||
|
||||
typedef struct Inquiry
|
||||
{
|
||||
#ifdef LITTLE_ENDIAN_BITFIELDS
|
||||
unsigned char PeripheralDeviceType:5; /* Byte 0 Bits 0-4 */
|
||||
unsigned char PeripheralQualifier:3; /* Byte 0 Bits 5-7 */
|
||||
unsigned char DeviceTypeModifier:7; /* Byte 1 Bits 0-6 */
|
||||
boolean RMB:1; /* Byte 1 Bit 7 */
|
||||
unsigned char ANSI_ApprovedVersion:3; /* Byte 2 Bits 0-2 */
|
||||
unsigned char ECMA_Version:3; /* Byte 2 Bits 3-5 */
|
||||
unsigned char ISO_Version:2; /* Byte 2 Bits 6-7 */
|
||||
unsigned char ResponseDataFormat:4; /* Byte 3 Bits 0-3 */
|
||||
unsigned char :2; /* Byte 3 Bits 4-5 */
|
||||
boolean TrmIOP:1; /* Byte 3 Bit 6 */
|
||||
boolean AENC:1; /* Byte 3 Bit 7 */
|
||||
#else
|
||||
unsigned char PeripheralQualifier:3; /* Byte 0 Bits 5-7 */
|
||||
unsigned char PeripheralDeviceType:5; /* Byte 0 Bits 0-4 */
|
||||
boolean RMB:1; /* Byte 1 Bit 7 */
|
||||
unsigned char DeviceTypeModifier:7; /* Byte 1 Bits 0-6 */
|
||||
unsigned char ISO_Version:2; /* Byte 2 Bits 6-7 */
|
||||
unsigned char ECMA_Version:3; /* Byte 2 Bits 3-5 */
|
||||
unsigned char ANSI_ApprovedVersion:3; /* Byte 2 Bits 0-2 */
|
||||
boolean AENC:1; /* Byte 3 Bit 7 */
|
||||
boolean TrmIOP:1; /* Byte 3 Bit 6 */
|
||||
unsigned char :2; /* Byte 3 Bits 4-5 */
|
||||
unsigned char ResponseDataFormat:4; /* Byte 3 Bits 0-3 */
|
||||
#endif
|
||||
unsigned char AdditionalLength; /* Byte 4 */
|
||||
unsigned char :8; /* Byte 5 */
|
||||
#ifdef LITTLE_ENDIAN_BITFIELDS
|
||||
boolean ADDR16:1; /* Byte 6 bit 0 */
|
||||
boolean Obs6_1:1; /* Byte 6 bit 1 */
|
||||
boolean Obs6_2:1; /* obsolete */ /* Byte 6 bit 2 */
|
||||
boolean MChngr:1; /* Media Changer */ /* Byte 6 bit 3 */
|
||||
boolean MultiP:1; /* Byte 6 bit 4 */
|
||||
boolean VS:1; /* Byte 6 bit 5 */
|
||||
boolean EncServ:1; /* Byte 6 bit 6 */
|
||||
boolean BQue:1; /* Byte 6 bit 7 */
|
||||
#else
|
||||
boolean BQue:1; /* Byte 6 bit 7 */
|
||||
boolean EncServ:1; /* Byte 6 bit 6 */
|
||||
boolean VS:1; /* Byte 6 bit 5 */
|
||||
boolean MultiP:1; /* Byte 6 bit 4 */
|
||||
boolean MChngr:1; /* Media Changer */ /* Byte 6 bit 3 */
|
||||
boolean Obs6_2:1; /* obsolete */ /* Byte 6 bit 2 */
|
||||
boolean Obs6_1:1; /* Byte 6 bit 1 */
|
||||
boolean ADDR16:1; /* Byte 6 bit 0 */
|
||||
#endif
|
||||
#ifdef LITTLE_ENDIAN_BITFIELDS
|
||||
boolean SftRe:1; /* Byte 7 Bit 0 */
|
||||
boolean CmdQue:1; /* Byte 7 Bit 1 */
|
||||
boolean :1; /* Byte 7 Bit 2 */
|
||||
boolean Linked:1; /* Byte 7 Bit 3 */
|
||||
boolean Sync:1; /* Byte 7 Bit 4 */
|
||||
boolean WBus16:1; /* Byte 7 Bit 5 */
|
||||
boolean WBus32:1; /* Byte 7 Bit 6 */
|
||||
boolean RelAdr:1; /* Byte 7 Bit 7 */
|
||||
#else
|
||||
boolean RelAdr:1; /* Byte 7 Bit 7 */
|
||||
boolean WBus32:1; /* Byte 7 Bit 6 */
|
||||
boolean WBus16:1; /* Byte 7 Bit 5 */
|
||||
boolean Sync:1; /* Byte 7 Bit 4 */
|
||||
boolean Linked:1; /* Byte 7 Bit 3 */
|
||||
boolean :1; /* Byte 7 Bit 2 */
|
||||
boolean CmdQue:1; /* Byte 7 Bit 1 */
|
||||
boolean SftRe:1; /* Byte 7 Bit 0 */
|
||||
#endif
|
||||
unsigned char VendorIdentification[8]; /* Bytes 8-15 */
|
||||
unsigned char ProductIdentification[16]; /* Bytes 16-31 */
|
||||
unsigned char ProductRevisionLevel[4]; /* Bytes 32-35 */
|
||||
unsigned char FullProductRevisionLevel[19]; /* bytes 36-54 */
|
||||
unsigned char VendorFlags; /* byte 55 */
|
||||
}
|
||||
Inquiry_T;
|
||||
|
||||
/* Hockey Pux may define these. If so, *UN*define them. */
|
||||
#ifdef ILI
|
||||
#undef ILI
|
||||
#endif
|
||||
|
||||
#ifdef EOM
|
||||
#undef EOM
|
||||
#endif
|
||||
|
||||
typedef struct RequestSense
|
||||
{
|
||||
#ifdef LITTLE_ENDIAN_BITFIELDS
|
||||
unsigned char ErrorCode:7; /* Byte 0 Bits 0-6 */
|
||||
boolean Valid:1; /* Byte 0 Bit 7 */
|
||||
#else
|
||||
boolean Valid:1; /* Byte 0 Bit 7 */
|
||||
unsigned char ErrorCode:7; /* Byte 0 Bits 0-6 */
|
||||
#endif
|
||||
unsigned char SegmentNumber; /* Byte 1 */
|
||||
#ifdef LITTLE_ENDIAN_BITFIELDS
|
||||
unsigned char SenseKey:4; /* Byte 2 Bits 0-3 */
|
||||
unsigned char :1; /* Byte 2 Bit 4 */
|
||||
boolean ILI:1; /* Byte 2 Bit 5 */
|
||||
boolean EOM:1; /* Byte 2 Bit 6 */
|
||||
boolean Filemark:1; /* Byte 2 Bit 7 */
|
||||
#else
|
||||
boolean Filemark:1; /* Byte 2 Bit 7 */
|
||||
boolean EOM:1; /* Byte 2 Bit 6 */
|
||||
boolean ILI:1; /* Byte 2 Bit 5 */
|
||||
unsigned char :1; /* Byte 2 Bit 4 */
|
||||
unsigned char SenseKey:4; /* Byte 2 Bits 0-3 */
|
||||
#endif
|
||||
unsigned char Information[4]; /* Bytes 3-6 */
|
||||
unsigned char AdditionalSenseLength; /* Byte 7 */
|
||||
unsigned char CommandSpecificInformation[4]; /* Bytes 8-11 */
|
||||
unsigned char AdditionalSenseCode; /* Byte 12 */
|
||||
unsigned char AdditionalSenseCodeQualifier; /* Byte 13 */
|
||||
unsigned char :8; /* Byte 14 */
|
||||
#ifdef LITTLE_ENDIAN_BITFIELDS
|
||||
unsigned char BitPointer:3; /* Byte 15 */
|
||||
boolean BPV:1;
|
||||
unsigned char :2;
|
||||
boolean CommandData :1;
|
||||
boolean SKSV:1;
|
||||
#else
|
||||
boolean SKSV:1;
|
||||
boolean CommandData :1;
|
||||
unsigned char :2;
|
||||
boolean BPV:1;
|
||||
unsigned char BitPointer:3; /* Byte 15 */
|
||||
#endif
|
||||
unsigned char FieldData[2]; /* Byte 16,17 */
|
||||
}
|
||||
RequestSense_T;
|
||||
|
||||
/* Okay, now for the element status mode sense page (0x1d): */
|
||||
|
||||
typedef struct ElementModeSensePageHeader {
|
||||
unsigned char PageCode; /* byte 0 */
|
||||
unsigned char ParameterLengthList; /* byte 1; */
|
||||
unsigned char MediumTransportStartHi; /* byte 2,3 */
|
||||
unsigned char MediumTransportStartLo;
|
||||
unsigned char NumMediumTransportHi; /* byte 4,5 */
|
||||
unsigned char NumMediumTransportLo; /* byte 4,5 */
|
||||
unsigned char StorageStartHi; /* byte 6,7 */
|
||||
unsigned char StorageStartLo; /* byte 6,7 */
|
||||
unsigned char NumStorageHi; /* byte 8,9 */
|
||||
unsigned char NumStorageLo; /* byte 8,9 */
|
||||
unsigned char ImportExportStartHi; /* byte 10,11 */
|
||||
unsigned char ImportExportStartLo; /* byte 10,11 */
|
||||
unsigned char NumImportExportHi; /* byte 12,13 */
|
||||
unsigned char NumImportExportLo; /* byte 12,13 */
|
||||
unsigned char DataTransferStartHi; /* byte 14,15 */
|
||||
unsigned char DataTransferStartLo; /* byte 14,15 */
|
||||
unsigned char NumDataTransferHi; /* byte 16,17 */
|
||||
unsigned char NumDataTransferLo; /* byte 16,17 */
|
||||
unsigned char Reserved1; /* byte 18, 19 */
|
||||
unsigned char Reserved2; /* byte 18, 19 */
|
||||
} ElementModeSensePage_T;
|
||||
|
||||
typedef struct ElementModeSenseHeader {
|
||||
int MaxReadElementStatusData; /* 'nuff for all of below. */
|
||||
int NumElements; /* total # of elements. */
|
||||
int MediumTransportStart;
|
||||
int NumMediumTransport;
|
||||
int StorageStart;
|
||||
int NumStorage;
|
||||
int ImportExportStart;
|
||||
int NumImportExport;
|
||||
int DataTransferStart;
|
||||
int NumDataTransfer;
|
||||
} ElementModeSense_T;
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
typedef char ElementTypeCode_T;
|
||||
|
||||
#define AllElementTypes 0
|
||||
#define MediumTransportElement 1
|
||||
#define StorageElement 2
|
||||
#define ImportExportElement 3
|
||||
#define DataTransferElement 4
|
||||
#else
|
||||
typedef enum ElementTypeCode
|
||||
{
|
||||
AllElementTypes = 0,
|
||||
MediumTransportElement = 1,
|
||||
StorageElement = 2,
|
||||
ImportExportElement = 3,
|
||||
DataTransferElement = 4
|
||||
}
|
||||
ElementTypeCode_T;
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct ElementStatusDataHeader
|
||||
{
|
||||
unsigned char FirstElementAddressReported[2]; /* Bytes 0-1 */
|
||||
unsigned char NumberOfElementsAvailable[2]; /* Bytes 2-3 */
|
||||
unsigned char :8; /* Byte 4 */
|
||||
unsigned char ByteCountOfReportAvailable[3]; /* Bytes 5-7 */
|
||||
}
|
||||
ElementStatusDataHeader_T;
|
||||
|
||||
|
||||
typedef struct ElementStatusPage
|
||||
{
|
||||
ElementTypeCode_T ElementTypeCode:8; /* Byte 0 */
|
||||
#ifdef LITTLE_ENDIAN_BITFIELDS
|
||||
unsigned char :6; /* Byte 1 Bits 0-5 */
|
||||
boolean AVolTag:1; /* Byte 1 Bit 6 */
|
||||
boolean PVolTag:1; /* Byte 1 Bit 7 */
|
||||
#else
|
||||
boolean PVolTag:1; /* Byte 1 Bit 7 */
|
||||
boolean AVolTag:1; /* Byte 1 Bit 6 */
|
||||
unsigned char :6; /* Byte 1 Bits 0-5 */
|
||||
#endif
|
||||
unsigned char ElementDescriptorLength[2]; /* Bytes 2-3 */
|
||||
unsigned char :8; /* Byte 4 */
|
||||
unsigned char ByteCountOfDescriptorDataAvailable[3]; /* Bytes 5-7 */
|
||||
}
|
||||
ElementStatusPage_T;
|
||||
|
||||
typedef struct Element2StatusPage
|
||||
{
|
||||
ElementTypeCode_T ElementTypeCode:8; /* Byte 0 */
|
||||
unsigned char VolBits ; /* byte 1 */
|
||||
#define E2_PVOLTAG 0x80
|
||||
#define E2_AVOLTAG 0x40
|
||||
unsigned char ElementDescriptorLength[2]; /* Bytes 2-3 */
|
||||
unsigned char :8; /* Byte 4 */
|
||||
unsigned char ByteCountOfDescriptorDataAvailable[3]; /* Bytes 5-7 */
|
||||
}
|
||||
Element2StatusPage_T;
|
||||
|
||||
|
||||
|
||||
typedef struct TransportElementDescriptorShort
|
||||
{
|
||||
unsigned char ElementAddress[2]; /* Bytes 0-1 */
|
||||
#ifdef LITTLE_ENDIAN_BITFIELDS
|
||||
boolean Full:1; /* Byte 2 Bit 0 */
|
||||
unsigned char :1; /* Byte 2 Bit 1 */
|
||||
boolean Except:1; /* Byte 2 Bit 2 */
|
||||
unsigned char :5; /* Byte 2 Bits 3-7 */
|
||||
#else
|
||||
unsigned char :5; /* Byte 2 Bits 3-7 */
|
||||
boolean Except:1; /* Byte 2 Bit 2 */
|
||||
unsigned char :1; /* Byte 2 Bit 1 */
|
||||
boolean Full:1; /* Byte 2 Bit 0 */
|
||||
#endif
|
||||
unsigned char :8; /* Byte 3 */
|
||||
unsigned char AdditionalSenseCode; /* Byte 4 */
|
||||
unsigned char AdditionalSenseCodeQualifier; /* Byte 5 */
|
||||
unsigned char :8; /* Byte 6 */
|
||||
unsigned char :8; /* Byte 7 */
|
||||
unsigned char :8; /* Byte 8 */
|
||||
#ifdef LITTLE_ENDIAN_BITFIELDS
|
||||
unsigned char :6; /* Byte 9 Bits 0-5 */
|
||||
boolean SValid:1; /* Byte 9 Bit 6 */
|
||||
boolean Invert:1; /* Byte 9 Bit 7 */
|
||||
#else
|
||||
boolean Invert:1; /* Byte 9 Bit 7 */
|
||||
boolean SValid:1; /* Byte 9 Bit 6 */
|
||||
unsigned char :6; /* Byte 9 Bits 0-5 */
|
||||
#endif
|
||||
unsigned char SourceStorageElementAddress[2]; /* Bytes 10-11 */
|
||||
#ifdef HAS_LONG_DESCRIPTORS
|
||||
unsigned char Reserved[4]; /* Bytes 12-15 */
|
||||
#endif
|
||||
}
|
||||
TransportElementDescriptorShort_T;
|
||||
|
||||
|
||||
typedef struct TransportElementDescriptor
|
||||
{
|
||||
unsigned char ElementAddress[2]; /* Bytes 0-1 */
|
||||
#ifdef LITTLE_ENDIAN_BITFIELDS
|
||||
boolean Full:1; /* Byte 2 Bit 0 */
|
||||
unsigned char :1; /* Byte 2 Bit 1 */
|
||||
boolean Except:1; /* Byte 2 Bit 2 */
|
||||
unsigned char :5; /* Byte 2 Bits 3-7 */
|
||||
#else
|
||||
unsigned char :5; /* Byte 2 Bits 3-7 */
|
||||
boolean Except:1; /* Byte 2 Bit 2 */
|
||||
unsigned char :1; /* Byte 2 Bit 1 */
|
||||
boolean Full:1; /* Byte 2 Bit 0 */
|
||||
#endif
|
||||
unsigned char :8; /* Byte 3 */
|
||||
unsigned char AdditionalSenseCode; /* Byte 4 */
|
||||
unsigned char AdditionalSenseCodeQualifier; /* Byte 5 */
|
||||
unsigned char :8; /* Byte 6 */
|
||||
unsigned char :8; /* Byte 7 */
|
||||
unsigned char :8; /* Byte 8 */
|
||||
#ifdef LITTLE_ENDIAN_BITFIELDS
|
||||
unsigned char :6; /* Byte 9 Bits 0-5 */
|
||||
boolean SValid:1; /* Byte 9 Bit 6 */
|
||||
boolean Invert:1; /* Byte 9 Bit 7 */
|
||||
#else
|
||||
boolean Invert:1; /* Byte 9 Bit 7 */
|
||||
boolean SValid:1; /* Byte 9 Bit 6 */
|
||||
unsigned char :6; /* Byte 9 Bits 0-5 */
|
||||
#endif
|
||||
unsigned char SourceStorageElementAddress[2]; /* Bytes 10-11 */
|
||||
unsigned char PrimaryVolumeTag[36]; /* barcode */
|
||||
unsigned char AlternateVolumeTag[36];
|
||||
#ifdef HAS_LONG_DESCRIPTORS
|
||||
unsigned char Reserved[4]; /* 4 extra bytes? */
|
||||
#endif
|
||||
|
||||
}
|
||||
TransportElementDescriptor_T;
|
||||
|
||||
|
||||
|
||||
|
||||
/* Now for element status data; */
|
||||
|
||||
typedef unsigned char barcode[37];
|
||||
|
||||
typedef struct ElementStatus {
|
||||
|
||||
int StorageElementCount;
|
||||
int ImportExportCount;
|
||||
int DataTransferElementCount;
|
||||
int *DataTransferElementAddress; /* array. */
|
||||
int *DataTransferElementSourceStorageElementNumber; /* array */
|
||||
barcode *DataTransferPrimaryVolumeTag; /* array. */
|
||||
barcode *DataTransferAlternateVolumeTag; /* array. */
|
||||
barcode *PrimaryVolumeTag; /* array */
|
||||
barcode *AlternateVolumeTag; /* array */
|
||||
int *StorageElementAddress; /* array */
|
||||
boolean *StorageElementIsImportExport; /* array */
|
||||
|
||||
int TransportElementAddress; /* assume only one of those... */
|
||||
|
||||
boolean *DataTransferElementFull; /* array */
|
||||
boolean *StorageElementFull; /* array */
|
||||
|
||||
} ElementStatus_T;
|
||||
|
||||
|
||||
/* Now for the SCSI ID and LUN information: */
|
||||
typedef struct scsi_id {
|
||||
int id;
|
||||
int lun;
|
||||
} scsi_id_t;
|
||||
|
||||
#define MEDIUM_CHANGER_TYPE 8 /* what type bits are set for medium changers. */
|
||||
|
||||
/* The following two structs are used for the brain-dead functions of the
|
||||
* NSM jukebox.
|
||||
*/
|
||||
|
||||
typedef struct NSM_Param {
|
||||
unsigned char page_code;
|
||||
unsigned char reserved;
|
||||
unsigned char page_len_msb;
|
||||
unsigned char page_len_lsb;
|
||||
unsigned char allocation_msb;
|
||||
unsigned char allocation_lsb;
|
||||
unsigned char reserved2[2];
|
||||
unsigned char command_code[4];
|
||||
unsigned char command_params[2048]; /* egregious overkill. */
|
||||
} NSM_Param_T;
|
||||
|
||||
extern RequestSense_T scsi_error_sense;
|
||||
|
||||
typedef struct NSM_Result {
|
||||
unsigned char page_code;
|
||||
unsigned char reserved;
|
||||
unsigned char page_len_msb;
|
||||
unsigned char page_len_lsb;
|
||||
unsigned char command_code[4];
|
||||
unsigned char ces_code[2];
|
||||
unsigned char return_data[0xffff]; /* egregioius overkill */
|
||||
} NSM_Result_T;
|
||||
|
||||
#endif /* of multi-include protection. */
|
||||
109
mtx-1.3.12/mtx.spec
Normal file
109
mtx-1.3.12/mtx.spec
Normal file
@@ -0,0 +1,109 @@
|
||||
Name: mtx
|
||||
Version: 1.3.12
|
||||
Release: 1%{?dist}
|
||||
Summary: SCSI media changer control program
|
||||
License: GPL
|
||||
Group: Utilities/System
|
||||
Source0: ftp://ftp.opensource-sw.net/pub/mtx/stable/%{name}-%{version}.tar.gz
|
||||
Url: http://%{name}.sourceforge.net
|
||||
BuildRoot: /var/tmp/%{name}-%{version}
|
||||
|
||||
|
||||
%description
|
||||
The MTX program controls the robotic mechanism in autoloaders and tape
|
||||
libraries such as the HP SureStore DAT 40x6, Exabyte EZ-17, and
|
||||
Exabyte 220. This program is also reported to work with a variety of other tape
|
||||
libraries and autochangers from Tandberg/Overland, Breece Hill, HP, and
|
||||
Seagate.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%build
|
||||
%configure
|
||||
make
|
||||
|
||||
%install
|
||||
mkdir -p $RPM_BUILD_ROOT/sbin
|
||||
install mtx $RPM_BUILD_ROOT/sbin/mtx
|
||||
mkdir -p $RPM_BUILD_ROOT/usr/sbin
|
||||
install loaderinfo $RPM_BUILD_ROOT/usr/sbin/loaderinfo
|
||||
install scsieject $RPM_BUILD_ROOT/usr/sbin/scsieject
|
||||
install scsitape $RPM_BUILD_ROOT/usr/sbin/scsitape
|
||||
install tapeinfo $RPM_BUILD_ROOT/usr/sbin/tapeinfo
|
||||
mkdir -p $RPM_BUILD_ROOT/%{_mandir}/man1
|
||||
install mtx.1 $RPM_BUILD_ROOT/%{_mandir}/man1/mtx.1
|
||||
install loaderinfo.1 $RPM_BUILD_ROOT/%{_mandir}/man1/loaderinfo.1
|
||||
install scsieject.1 $RPM_BUILD_ROOT/%{_mandir}/man1/scsieject.1
|
||||
install scsitape.1 $RPM_BUILD_ROOT/%{_mandir}/man1/scsitape.1
|
||||
install tapeinfo.1 $RPM_BUILD_ROOT/%{_mandir}/man1/tapeinfo.1
|
||||
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%files
|
||||
%defattr(-,root,root)
|
||||
%doc mtx.doc CHANGES README mtxl.README.html
|
||||
%doc COMPATABILITY FAQ LICENSE* TODO contrib
|
||||
%{_mandir}/man1/*
|
||||
/sbin/mtx
|
||||
/usr/sbin/*
|
||||
|
||||
%changelog
|
||||
* Fri Sep 27 2002 Eric Green <eric@badtux.org>
|
||||
- 1.3.0rel
|
||||
- move changelog to end.
|
||||
- change source directory to ftp.badtux.net.
|
||||
- use * for files to catch new files.
|
||||
|
||||
* Wed Apr 18 2001 Kenneth Porter <shiva@well.com>
|
||||
- 1.2.12pre1
|
||||
- Need to create usr/sbin for install
|
||||
|
||||
* Fri Mar 02 2001 Eric Green <eric@estinc.com>
|
||||
- 1.2.11pre6
|
||||
- Move tapeinfo,loaderinfo, scsitape to /usr/sbin rather than /sbin
|
||||
|
||||
* Wed Feb 28 2001 Kenneth Porter <shiva@well.com>
|
||||
- 1.2.11pre5
|
||||
- Remove commented-out patch.
|
||||
- Use mandir FHS macro and configure macro.
|
||||
- Install more stuff.
|
||||
- Use build policy for stripping.
|
||||
|
||||
* Wed Jan 17 2001 Eric Green <eric@estinc.com>
|
||||
- 1.2.11pre3
|
||||
- Removed patch, now use ./configure.
|
||||
|
||||
* Mon Nov 27 2000 Eric Green <eric@estinc.com>
|
||||
- 1.2.10
|
||||
- Fixed patching to use the portable.patch.
|
||||
|
||||
* Tue Jul 25 2000 Eric Green <eric@estinc.com>
|
||||
- 1.2.8
|
||||
- Added portability patch to mtx.spec so should compile on Red Hat Alpha etc.
|
||||
|
||||
* Thu Jun 6 2000 Eric Green <eric@estinc.com>
|
||||
- 1.2.7
|
||||
- Fixed single-drive Exabyte 220 special case.
|
||||
- Fixed ADIC DAT Autochanger special case.
|
||||
- Fixed mtx.spec to move the binaries to /sbin since we need root access
|
||||
|
||||
* Fri May 12 2000 Kenneth Porter <shiva@well.com>
|
||||
- 1.2.6
|
||||
- Fixed 'eepos' stuff to use | rather than || (whoops!)
|
||||
- Accept a 4-byte element descriptor for the robot arm for certain older
|
||||
- autochangers.
|
||||
|
||||
* Mon May 8 2000 Kenneth Porter <shiva@well.com>
|
||||
- Spell sourceforge right so the link at rpmfind.net will work.
|
||||
|
||||
* Thu May 4 2000 Kenneth Porter <shiva@well.com>
|
||||
- 1.2.5
|
||||
|
||||
* Thu Oct 29 1998 Ian Macdonald <ianmacd@xs4all.nl>
|
||||
- moved mtx from /sbin to /bin, seeing as mt is also located there
|
||||
|
||||
* Fri Oct 23 1998 Ian Macdonald <ianmacd@xs4all.nl>
|
||||
- first RPM release
|
||||
109
mtx-1.3.12/mtx.spec.in
Normal file
109
mtx-1.3.12/mtx.spec.in
Normal file
@@ -0,0 +1,109 @@
|
||||
Name: mtx
|
||||
Version: @@VERSION@@
|
||||
Release: 1%{?dist}
|
||||
Summary: SCSI media changer control program
|
||||
License: GPL
|
||||
Group: Utilities/System
|
||||
Source0: ftp://ftp.opensource-sw.net/pub/mtx/stable/%{name}-%{version}.tar.gz
|
||||
Url: http://%{name}.sourceforge.net
|
||||
BuildRoot: /var/tmp/%{name}-%{version}
|
||||
|
||||
|
||||
%description
|
||||
The MTX program controls the robotic mechanism in autoloaders and tape
|
||||
libraries such as the HP SureStore DAT 40x6, Exabyte EZ-17, and
|
||||
Exabyte 220. This program is also reported to work with a variety of other tape
|
||||
libraries and autochangers from Tandberg/Overland, Breece Hill, HP, and
|
||||
Seagate.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%build
|
||||
%configure
|
||||
make
|
||||
|
||||
%install
|
||||
mkdir -p $RPM_BUILD_ROOT/sbin
|
||||
install mtx $RPM_BUILD_ROOT/sbin/mtx
|
||||
mkdir -p $RPM_BUILD_ROOT/usr/sbin
|
||||
install loaderinfo $RPM_BUILD_ROOT/usr/sbin/loaderinfo
|
||||
install scsieject $RPM_BUILD_ROOT/usr/sbin/scsieject
|
||||
install scsitape $RPM_BUILD_ROOT/usr/sbin/scsitape
|
||||
install tapeinfo $RPM_BUILD_ROOT/usr/sbin/tapeinfo
|
||||
mkdir -p $RPM_BUILD_ROOT/%{_mandir}/man1
|
||||
install mtx.1 $RPM_BUILD_ROOT/%{_mandir}/man1/mtx.1
|
||||
install loaderinfo.1 $RPM_BUILD_ROOT/%{_mandir}/man1/loaderinfo.1
|
||||
install scsieject.1 $RPM_BUILD_ROOT/%{_mandir}/man1/scsieject.1
|
||||
install scsitape.1 $RPM_BUILD_ROOT/%{_mandir}/man1/scsitape.1
|
||||
install tapeinfo.1 $RPM_BUILD_ROOT/%{_mandir}/man1/tapeinfo.1
|
||||
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%files
|
||||
%defattr(-,root,root)
|
||||
%doc mtx.doc CHANGES README mtxl.README.html
|
||||
%doc COMPATABILITY FAQ LICENSE* TODO contrib
|
||||
%{_mandir}/man1/*
|
||||
/sbin/mtx
|
||||
/usr/sbin/*
|
||||
|
||||
%changelog
|
||||
* Fri Sep 27 2002 Eric Green <eric@badtux.org>
|
||||
- 1.3.0rel
|
||||
- move changelog to end.
|
||||
- change source directory to ftp.badtux.net.
|
||||
- use * for files to catch new files.
|
||||
|
||||
* Wed Apr 18 2001 Kenneth Porter <shiva@well.com>
|
||||
- 1.2.12pre1
|
||||
- Need to create usr/sbin for install
|
||||
|
||||
* Fri Mar 02 2001 Eric Green <eric@estinc.com>
|
||||
- 1.2.11pre6
|
||||
- Move tapeinfo,loaderinfo, scsitape to /usr/sbin rather than /sbin
|
||||
|
||||
* Wed Feb 28 2001 Kenneth Porter <shiva@well.com>
|
||||
- 1.2.11pre5
|
||||
- Remove commented-out patch.
|
||||
- Use mandir FHS macro and configure macro.
|
||||
- Install more stuff.
|
||||
- Use build policy for stripping.
|
||||
|
||||
* Wed Jan 17 2001 Eric Green <eric@estinc.com>
|
||||
- 1.2.11pre3
|
||||
- Removed patch, now use ./configure.
|
||||
|
||||
* Mon Nov 27 2000 Eric Green <eric@estinc.com>
|
||||
- 1.2.10
|
||||
- Fixed patching to use the portable.patch.
|
||||
|
||||
* Tue Jul 25 2000 Eric Green <eric@estinc.com>
|
||||
- 1.2.8
|
||||
- Added portability patch to mtx.spec so should compile on Red Hat Alpha etc.
|
||||
|
||||
* Thu Jun 6 2000 Eric Green <eric@estinc.com>
|
||||
- 1.2.7
|
||||
- Fixed single-drive Exabyte 220 special case.
|
||||
- Fixed ADIC DAT Autochanger special case.
|
||||
- Fixed mtx.spec to move the binaries to /sbin since we need root access
|
||||
|
||||
* Fri May 12 2000 Kenneth Porter <shiva@well.com>
|
||||
- 1.2.6
|
||||
- Fixed 'eepos' stuff to use | rather than || (whoops!)
|
||||
- Accept a 4-byte element descriptor for the robot arm for certain older
|
||||
- autochangers.
|
||||
|
||||
* Mon May 8 2000 Kenneth Porter <shiva@well.com>
|
||||
- Spell sourceforge right so the link at rpmfind.net will work.
|
||||
|
||||
* Thu May 4 2000 Kenneth Porter <shiva@well.com>
|
||||
- 1.2.5
|
||||
|
||||
* Thu Oct 29 1998 Ian Macdonald <ianmacd@xs4all.nl>
|
||||
- moved mtx from /sbin to /bin, seeing as mt is also located there
|
||||
|
||||
* Fri Oct 23 1998 Ian Macdonald <ianmacd@xs4all.nl>
|
||||
- first RPM release
|
||||
165
mtx-1.3.12/mtxl.README.html
Normal file
165
mtx-1.3.12/mtxl.README.html
Normal file
@@ -0,0 +1,165 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>SCSI Media Changer and Backup Device Control System</title>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<center>
|
||||
<h1>SCSI Media Changer and Backup Device Control System</h1>
|
||||
</center>
|
||||
<p>
|
||||
[Also see the SourceForge <a href="http://sourceforge.net/projects/mtx">
|
||||
project page</a>.]
|
||||
<p>
|
||||
<i>mtx</i> is a set of low level driver programs to control features
|
||||
of SCSI backup related devices such as autoloaders, tape changers,
|
||||
media jukeboxes, and tape drives. It can also report much data,
|
||||
including serial numbers, maximum block sizes, and TapeAlert(tm)
|
||||
messages that most modern tape drives implement (to tell you the exact
|
||||
reason why a backup or restore failed), as well as do raw SCSI READ
|
||||
and WRITE commands to tape drives (not important on Linux, but
|
||||
important on Solaris due to the fact that the Solaris tape driver
|
||||
supports none of the additional features of tape drives invented after
|
||||
1988). <i>mtx</i> is designed to be a low level driver in a larger
|
||||
scripted backup solution, such as <a
|
||||
href="http://amanda.sourceforge.net">Amanda</a>.
|
||||
<i>mtx</i> is not
|
||||
supposed to itself be a high level interface to the SCSI devices that
|
||||
it controls.
|
||||
<p>
|
||||
This version has the following features:
|
||||
|
||||
<ul>
|
||||
<li> Will deal with LARGE media libraries (over a hundred elements).
|
||||
<li> Supports multi-drive media changers such as the Exabyte 220 dual-
|
||||
drive tape library.
|
||||
<li> Supports the 'invert' bit for optical jukeboxes that need that in
|
||||
order to flip their media.
|
||||
<li> Supports the 'eepos' bits for libraries that need this to extend/retract
|
||||
their import/export tray.
|
||||
<li> Now supports import/export elements!
|
||||
<li> Reports volume tags (bar codes) and "alternate volume tags"
|
||||
(whatever those are!) for those tape libraries
|
||||
that support them.
|
||||
<li> Now runs under FreeBSD and at least Solaris 8.
|
||||
|
||||
<li> Now has a 'man' page!
|
||||
<li> The actual SCSI manipulation has been separated out into a library, so
|
||||
that you can create your own "C" programs that manipulate SCSI media changers
|
||||
directly. (Please note: this is under GPL, so any such programs will have
|
||||
to be under GPL also).
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
This program supposedly supports FreeBSD, Solaris, Linux, HP/UX, and
|
||||
IRIX. Tru64 Unix and VMS are probably irretrievably broken at this
|
||||
time. This program has been tested under FreeBSD, Solaris, and Linux,
|
||||
and there only with a limited set of hardware. See the COMPATIBILITY
|
||||
list in the source code.
|
||||
</ul>
|
||||
<h2> Source Code </h2>
|
||||
The current source code is:
|
||||
<ul>
|
||||
<li> <a href="http://mtx.sourceforge.net/mtx-1.2.13.tar.gz">http://mtx.sourceforge.net/mtx-1.2.13.tar.gz</a>
|
||||
</ul>
|
||||
RPMs may be available from the following place:
|
||||
<ul>
|
||||
<li> <a href="http://rpmfind.net/linux/RPM/mtx.html">RPMfind's 'mtx' page</a>
|
||||
</ul>
|
||||
A .spec file is now included in the 'mtx' distribution for building your
|
||||
own RPM's.
|
||||
<p>
|
||||
Note that RPMs
|
||||
are courtesy of <a href="http://www.sewingwitch.com/ken/">Kenneth Porter</a>,
|
||||
who should be contacted regarding rpm-related problems.
|
||||
<p>
|
||||
|
||||
<h2> Known Bugs And Limitations </h2>
|
||||
<ul>
|
||||
<li>
|
||||
You may need to do a 'mt offline' (or equivalent for your OS)
|
||||
on the tape drive to
|
||||
eject the tape before you can issue the 'mtx unload' command.
|
||||
The Exabyte EZ-17 and 220 in particular will happily
|
||||
sit there snapping the robot arm's claws around thin air
|
||||
trying to grab a tape that's not there.
|
||||
<li>
|
||||
The 'next' command does not understand the 'invert' bit (i.e., does not
|
||||
recognize that for optical jukeboxes, the 'next' of side one is to unload,
|
||||
invert, and reload the same disk). It always advances to the next
|
||||
slot instead.
|
||||
<li>
|
||||
For some Linux distributions, you may need to re-compile
|
||||
the kernel to scan SCSI LUN's in order to detect the media
|
||||
changer. Check /proc/scsi/scsi to see what's going on.
|
||||
|
||||
<li>
|
||||
If you try to unload a tape to its 'source' slot, and said
|
||||
slot is full, it will instead put the tape into the first
|
||||
empty slot. Unfortunately the list of empty slots is not
|
||||
updated between commands on the command line, so if you
|
||||
try to unload another drive to a full 'source' slot during
|
||||
the same invocation of 'mtx', it will try to unload to the
|
||||
same (no longer empty) slot and will urp with a SCSI
|
||||
error.
|
||||
|
||||
<li> For big tape libraries (more than a couple dozen elements) this
|
||||
may set a big Allocation_Size in the SCSI command block for the
|
||||
REQUEST_ELEMENT_STATUS command. Some operating systems may not be able
|
||||
to handle this. Versions of Linux earlier than 2.2.6, in particular,
|
||||
may fail this request due to inability to find contiguous pages of
|
||||
memory for the SCSI transfer (later versions of Linux 'sg' device do
|
||||
scatter-gather so that this should no longer be a problem).
|
||||
|
||||
<li> VMS and Tru64 support are probably irretrievably busted.
|
||||
|
||||
|
||||
<li> This program will only use the first arm of multiple-arm robots unless
|
||||
the robot re-maps all arms to one element ID.
|
||||
|
||||
<li> It has been reported that this program works on Solaris 7 using the 'sst'
|
||||
driver, and may work on Solaris 8 using the 'sgen' driver. 'sst' can
|
||||
be gotten from the Amanda contrib directory at
|
||||
<a href="http://download.sourceforge.net/amanda/">http://download.sourceforge.net/amanda</a>.
|
||||
|
||||
</ul>
|
||||
|
||||
<h2> Philosophy </h2>
|
||||
The Unix philosophy is "many small tools chained together". <i>mtx</i> supplies
|
||||
those small tools so that you can create your own backup and
|
||||
recovery tools by chaining
|
||||
<i>mtx</i> pieces together, whether it be with /bin/sh, Perl, Python, or
|
||||
CAML.
|
||||
|
||||
|
||||
<h2> Support </h2>
|
||||
<ul>
|
||||
<li>There is now a 'mtx' mailing list at <a href="http://sourceforge.net/projects/mtx/">http://sourceforge.net/projects/mtx/</a>.
|
||||
<li>There is now a 'mtx' home page at <a href="http://mtx.sourceforge.net">http://mtx.sourceforge.net</a>.
|
||||
<li> There is now a FAQ that is part of the source code. Please read the
|
||||
FAQ first.
|
||||
<li>Report problems to Eric Lee Green (<a
|
||||
href="mailto:eric@badtux.org">eric@badtux.org</a>). READ THE FAQ FIRST!
|
||||
</ul>
|
||||
|
||||
<h2> See Also: </h2>
|
||||
<ul>
|
||||
<li>The man page for 'mtx'! (once you get it installed).
|
||||
<li>T-10 SCSI Working Group home page at <a href="http://www.t10.org">www.t10.org</a>.
|
||||
<li>The Linux 'sg' SCSI generic driver home page at <a href="http://www.torque.net/sg/">http://www.torque.net/sg/</a>.
|
||||
<li> <a href="http://badtux.org/eric">The Home Page Of <UL> Tags Anonymous</a> Hi, my name is Eric, and I am addicted to the <UL> tag...
|
||||
</ul>
|
||||
<hr>
|
||||
<address>Maintained by <a href="mailto:eric@badtux.org">Eric Lee Green</a><br>
|
||||
Hosted by <a href="http://www.valinux.com">VA Linux</a>'s <a href="http://www.sourceforge.net">SourceForge</a></address><br>
|
||||
|
||||
|
||||
<!-- Created: Fri Mar 3 12:19:38 MST 2000 -->
|
||||
<!-- hhmts start -->
|
||||
Last modified: Mon Jun 25 15:37:22 MST 2001
|
||||
<!-- hhmts end -->
|
||||
</body>
|
||||
</html>
|
||||
1907
mtx-1.3.12/mtxl.c
Normal file
1907
mtx-1.3.12/mtxl.c
Normal file
File diff suppressed because it is too large
Load Diff
109
mtx-1.3.12/mtxl.h
Normal file
109
mtx-1.3.12/mtxl.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
MTX -- SCSI Tape Attached Medium Changer Control Program
|
||||
|
||||
Copyright 1997-1998 Leonard N. Zubkoff <lnz@dandelion.com>
|
||||
Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
|
||||
This file created by Eric Lee Green <eric@badtux.org>
|
||||
|
||||
This program is free software; you may redistribute and/or modify it under
|
||||
the terms of the GNU General Public License Version 2 as published by the
|
||||
Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for complete details.
|
||||
|
||||
$Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $
|
||||
$Revision: 193 $
|
||||
*/
|
||||
|
||||
/* Much of the guts of mtx.c has been extracted to mtxl.c, a library file
|
||||
* full of utility routines. This file is the header file for that library.
|
||||
* -E
|
||||
*/
|
||||
|
||||
#ifndef MTXL_H
|
||||
#define MTXL_H 1
|
||||
|
||||
#include "mtx.h"
|
||||
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
void FatalError(char *ErrorMessage, ...);
|
||||
void *xmalloc(size_t Size);
|
||||
void *xzmalloc(size_t Size);
|
||||
void slow_bzero(char *buffer, int numchars);
|
||||
|
||||
DEVICE_TYPE SCSI_OpenDevice(char *DeviceName);
|
||||
void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD);
|
||||
int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
|
||||
Direction_T Direction,
|
||||
CDB_T *CDB,
|
||||
int CDB_Length,
|
||||
void *DataBuffer,
|
||||
int DataBufferLength,
|
||||
RequestSense_T *RequestSense);
|
||||
|
||||
void PrintRequestSense(RequestSense_T *RequestSense);
|
||||
|
||||
int BigEndian16(unsigned char *BigEndianData);
|
||||
int BigEndian24(unsigned char *BigEndianData);
|
||||
int min(int x, int y);
|
||||
int max(int x, int y);
|
||||
|
||||
void PrintHex(int Indent, unsigned char *Buffer, int Length);
|
||||
int ClearUnitAttention(DEVICE_TYPE fd, RequestSense_T *RequestSense);
|
||||
|
||||
ElementStatus_T *ReadElementStatus( DEVICE_TYPE MediumChangerFD,
|
||||
RequestSense_T *RequestSense,
|
||||
Inquiry_T *inquiry_info,
|
||||
SCSI_Flags_T *flags);
|
||||
|
||||
Inquiry_T *RequestInquiry( DEVICE_TYPE fd,
|
||||
RequestSense_T *RequestSense);
|
||||
|
||||
RequestSense_T *MoveMedium( DEVICE_TYPE MediumChangerFD,
|
||||
int SourceAddress,
|
||||
int DestinationAddress,
|
||||
ElementStatus_T *ElementStatus,
|
||||
Inquiry_T *inquiry_info,
|
||||
SCSI_Flags_T *flags);
|
||||
|
||||
RequestSense_T *ExchangeMedium( DEVICE_TYPE MediumChangerFD,
|
||||
int SourceAddress,
|
||||
int DestinationAddress,
|
||||
int Dest2Address,
|
||||
ElementStatus_T *ElementStatus,
|
||||
SCSI_Flags_T *flags);
|
||||
|
||||
RequestSense_T *PositionElement(DEVICE_TYPE MediumChangerFD,
|
||||
int DestinationAddress,
|
||||
ElementStatus_T *ElementStatus);
|
||||
|
||||
int Inventory(DEVICE_TYPE MediumChangerFD); /* inventory library */
|
||||
int LoadUnload(DEVICE_TYPE fd, int bLoad); /* load/unload tape, magazine or disc */
|
||||
int StartStop(DEVICE_TYPE fd, int bStart); /* start/stop device */
|
||||
int LockUnlock(DEVICE_TYPE fd, int bLock); /* lock/unlock medium in device */
|
||||
RequestSense_T *Erase(DEVICE_TYPE fd); /* send SHORT erase to drive */
|
||||
|
||||
void SCSI_Set_Timeout(int secs); /* set the SCSI timeout */
|
||||
void SCSI_Default_Timeout(void); /* go back to default timeout */
|
||||
|
||||
/* we may not have this function :-(. */
|
||||
#ifdef HAVE_GET_ID_LUN
|
||||
scsi_id_t *SCSI_GetIDLun(DEVICE_TYPE fd);
|
||||
#endif
|
||||
|
||||
/* These two hacks are so that I can stick the tongue out on an
|
||||
* NSM optical jukebox.
|
||||
*/
|
||||
NSM_Result_T *RecNSMHack(DEVICE_TYPE MediumChangerFD,
|
||||
int param_len, int timeout);
|
||||
|
||||
int SendNSMHack(DEVICE_TYPE MediumChangerFD, NSM_Param_T *nsm_command,
|
||||
int param_len, int timeout);
|
||||
|
||||
#endif
|
||||
|
||||
342
mtx-1.3.12/nsmhack.c
Normal file
342
mtx-1.3.12/nsmhack.c
Normal file
@@ -0,0 +1,342 @@
|
||||
/* Copyright 2001 DISC Inc.
|
||||
* Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
|
||||
* Released under terms of the GNU General Public License as required
|
||||
* by the license on the file "mtxl.c". See file "LICENSE" for details.
|
||||
*/
|
||||
|
||||
#define DEBUG_NSM 1
|
||||
|
||||
/* This is a hack to make the NSM modular series jukeboxes stick out
|
||||
* their tongue, then retract tongue, so we can import media. They
|
||||
* automatically stick out their tongue when exporting media, but
|
||||
* importing media is not working, you try to do a MOVE_MEDIUM and
|
||||
* it says "What medium?" before even sticking out its tongue.
|
||||
* My manager has turned in a change request to NSM engineering to direct
|
||||
* their firmware guys to add EEPOS support to the NSM modular jukeboxes so
|
||||
* that we have tongue firmware that's compatible with Exabyte, Sony, Breece
|
||||
* Hill, etc., but until that new firmware is here, this hack will work.
|
||||
*/
|
||||
|
||||
/* Note: Perhaps "hack" is an overstatement, since this will also
|
||||
* eventually add pack management and other things of that nature
|
||||
* that are extremely loader dependent.
|
||||
*/
|
||||
|
||||
/* Commands:
|
||||
-f <devicenode>
|
||||
tongue_out <sourceslot>
|
||||
tongue_in
|
||||
tongue_button_wait
|
||||
tongue_button_enable
|
||||
tongue_button_disable
|
||||
*/
|
||||
|
||||
|
||||
#include "mtxl.h" /* get the SCSI routines out of the main file */
|
||||
|
||||
/****************************************************************/
|
||||
/* Variables: */
|
||||
/****************************************************************/
|
||||
|
||||
/* the device handle we're operating upon, sigh. */
|
||||
static char *device; /* the text of the device thingy. */
|
||||
static DEVICE_TYPE MediumChangerFD = (DEVICE_TYPE) -1;
|
||||
char *argv0;
|
||||
int arg[4]; /* arguments for the command. */
|
||||
#define arg1 (arg[0]) /* for backward compatibility, sigh */
|
||||
static SCSI_Flags_T SCSI_Flags = { 0, 0, 0,0 };
|
||||
|
||||
static ElementStatus_T *ElementStatus = NULL;
|
||||
|
||||
/* Okay, now let's do the main routine: */
|
||||
|
||||
void Usage(void) {
|
||||
FatalError("Usage: nsmhack -f <generic-device> <command> where <command> is:\n [tongue_out] | [tongue_in] | [tongue_button_wait] | [tongue_button_enable]\n | tongue_button_disable. \n");
|
||||
}
|
||||
|
||||
static int S_tongue_out(void);
|
||||
static int S_tongue_in(void);
|
||||
static int S_slotinfo(void);
|
||||
static int S_jukeinfo(void);
|
||||
|
||||
struct command_table_struct {
|
||||
int num_args;
|
||||
char *name;
|
||||
int (*command)(void);
|
||||
} command_table[] = {
|
||||
{ 1, "tongue_out", S_tongue_out },
|
||||
{ 0, "tongue_in", S_tongue_in },
|
||||
{ 0, "slotinfo", S_slotinfo },
|
||||
{ 0, "jukeinfo", S_jukeinfo },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
|
||||
/* open_device() -- set the 'fh' variable.... */
|
||||
void open_device(void) {
|
||||
|
||||
if (MediumChangerFD != -1) {
|
||||
SCSI_CloseDevice("Unknown",MediumChangerFD); /* close it, sigh... new device now! */
|
||||
}
|
||||
|
||||
MediumChangerFD = SCSI_OpenDevice(device);
|
||||
|
||||
}
|
||||
|
||||
static int get_arg(char *arg) {
|
||||
int retval=-1;
|
||||
|
||||
if (*arg < '0' || *arg > '9') {
|
||||
return -1; /* sorry! */
|
||||
}
|
||||
|
||||
retval=atoi(arg);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* we see if we've got a file open. If not, we open one :-(. Then
|
||||
* we execute the actual command. Or not :-(.
|
||||
*/
|
||||
int execute_command(struct command_table_struct *command) {
|
||||
|
||||
/* if the device is not already open, then open it from the
|
||||
* environment.
|
||||
*/
|
||||
if (MediumChangerFD == -1) {
|
||||
/* try to get it from STAPE or TAPE environment variable... */
|
||||
device=getenv("STAPE");
|
||||
if (device==NULL) {
|
||||
device=getenv("TAPE");
|
||||
if (device==NULL) {
|
||||
Usage();
|
||||
}
|
||||
}
|
||||
open_device();
|
||||
}
|
||||
|
||||
|
||||
/* okay, now to execute the command... */
|
||||
return command->command();
|
||||
}
|
||||
|
||||
/* parse_args():
|
||||
* Basically, we are parsing argv/argc. We can have multiple commands
|
||||
* on a line now, such as "unload 3 0 load 4 0" to unload one tape and
|
||||
* load in another tape into drive 0, and we execute these commands one
|
||||
* at a time as we come to them. If we don't have a -f at the start, we
|
||||
* barf. If we leave out a drive #, we default to drive 0 (the first drive
|
||||
* in the cabinet).
|
||||
*/
|
||||
|
||||
int parse_args(int argc,char **argv) {
|
||||
int i,cmd_tbl_idx,retval,arg_idx;
|
||||
struct command_table_struct *command;
|
||||
|
||||
i=1;
|
||||
arg_idx=0;
|
||||
while (i<argc) {
|
||||
if (strcmp(argv[i],"-f") == 0) {
|
||||
i++;
|
||||
if (i>=argc) {
|
||||
Usage();
|
||||
}
|
||||
device=argv[i++];
|
||||
open_device(); /* open the device and do a status scan on it... */
|
||||
} else {
|
||||
cmd_tbl_idx=0;
|
||||
command=&command_table[0]; /* default to the first command... */
|
||||
command=&command_table[cmd_tbl_idx];
|
||||
while (command->name) {
|
||||
if (!strcmp(command->name,argv[i])) {
|
||||
/* we have a match... */
|
||||
break;
|
||||
}
|
||||
/* otherwise we don't have a match... */
|
||||
cmd_tbl_idx++;
|
||||
command=&command_table[cmd_tbl_idx];
|
||||
}
|
||||
/* if it's not a command, exit.... */
|
||||
if (!command->name) {
|
||||
Usage();
|
||||
}
|
||||
i++; /* go to the next argument, if possible... */
|
||||
/* see if we need to gather arguments, though! */
|
||||
arg1=-1; /* default it to something */
|
||||
for (arg_idx=0;arg_idx < command->num_args ; arg_idx++) {
|
||||
if (i < argc) {
|
||||
arg[arg_idx]=get_arg(argv[i]);
|
||||
if (arg[arg_idx] != -1) {
|
||||
i++; /* increment i over the next cmd. */
|
||||
}
|
||||
} else {
|
||||
arg[arg_idx]=0; /* default to 0 setmarks or whatever */
|
||||
}
|
||||
}
|
||||
retval=execute_command(command); /* execute_command handles 'stuff' */
|
||||
exit(retval);
|
||||
}
|
||||
}
|
||||
return 0; /* should never get here */
|
||||
}
|
||||
|
||||
static void init_param(NSM_Param_T *param, char *command, int paramlen, int resultlen) {
|
||||
int i;
|
||||
|
||||
/* zero it out first: */
|
||||
memset((char *)param,0,sizeof(NSM_Param_T));
|
||||
|
||||
resultlen=resultlen+sizeof(NSM_Result_T)-0xffff;
|
||||
|
||||
|
||||
param->page_code=0x80;
|
||||
param->reserved=0;
|
||||
param->page_len_msb=((paramlen+8)>>8) & 0xff;
|
||||
param->page_len_lsb=(paramlen+8) & 0xff;
|
||||
param->allocation_msb=((resultlen + 10) >> 8) & 0xff;
|
||||
param->allocation_lsb= (resultlen+10) & 0xff;
|
||||
param->reserved2[0]=0;
|
||||
param->reserved2[1]=0;
|
||||
|
||||
for (i=0;i<4;i++) {
|
||||
param->command_code[i]=command[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static NSM_Result_T *SendRecHack(NSM_Param_T *param,int param_len,
|
||||
int read_len) {
|
||||
NSM_Result_T *result;
|
||||
/* send the command: */
|
||||
if (SendNSMHack(MediumChangerFD,param,param_len,0)) {
|
||||
PrintRequestSense(&scsi_error_sense);
|
||||
FatalError("SendNSMHack failed.\n");
|
||||
}
|
||||
|
||||
/* Now read the result: */
|
||||
result=RecNSMHack(MediumChangerFD,read_len,0);
|
||||
if (!result) {
|
||||
PrintRequestSense(&scsi_error_sense);
|
||||
FatalError("RecNSMHack failed.\n");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Print some info about the NSM jukebox. */
|
||||
static int S_jukeinfo(void) {
|
||||
NSM_Result_T *result;
|
||||
NSM_Param_T param;
|
||||
|
||||
if (!device)
|
||||
Usage();
|
||||
|
||||
/* okay, we have a device: Let's get vendor ID: */
|
||||
init_param(¶m,"1010",0,8);
|
||||
result=SendRecHack(¶m,0,8);
|
||||
/* Okay, we got our result, print out the vendor ID: */
|
||||
result->return_data[8]=0;
|
||||
printf("Vendor ID: %s\n",result->return_data);
|
||||
free(result);
|
||||
|
||||
/* Get our product ID: */
|
||||
init_param(¶m,"1011",0,16);
|
||||
result=SendRecHack(¶m,0,16);
|
||||
result->return_data[16]=0;
|
||||
printf("Product ID: %s\n",result->return_data);
|
||||
free(result);
|
||||
|
||||
init_param(¶m,"1012",0,4);
|
||||
result=SendRecHack(¶m,0,4);
|
||||
result->return_data[4]=0;
|
||||
printf("Product Revision: %s\n",result->return_data);
|
||||
free(result);
|
||||
|
||||
init_param(¶m,"1013",0,8);
|
||||
result=SendRecHack(¶m,0,8);
|
||||
result->return_data[8]=0;
|
||||
printf("Production Date: %s\n",result->return_data);
|
||||
free(result);
|
||||
|
||||
init_param(¶m,"1014",0,8);
|
||||
result=SendRecHack(¶m,0,8);
|
||||
result->return_data[8]=0;
|
||||
printf("Part Number: %s\n",result->return_data);
|
||||
free(result);
|
||||
|
||||
init_param(¶m,"1015",0,12);
|
||||
result=SendRecHack(¶m,0,12);
|
||||
result->return_data[12]=0;
|
||||
printf("Serial Number: %s\n",result->return_data);
|
||||
free(result);
|
||||
|
||||
init_param(¶m,"1016",0,4);
|
||||
result=SendRecHack(¶m,0,4);
|
||||
result->return_data[4]=0;
|
||||
printf("Firmware Release: %s\n",result->return_data);
|
||||
free(result);
|
||||
|
||||
init_param(¶m,"1017",0,8);
|
||||
result=SendRecHack(¶m,0,8);
|
||||
result->return_data[8]=0;
|
||||
printf("Firmware Date: %s\n",result->return_data);
|
||||
free(result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int S_slotinfo(void) {
|
||||
NSM_Result_T *result;
|
||||
NSM_Param_T param;
|
||||
|
||||
if (!device)
|
||||
Usage();
|
||||
|
||||
/* Okay, let's see what I can get from slotinfo: */
|
||||
init_param(¶m,"1020",0,6);
|
||||
result=SendRecHack(¶m,0,6);
|
||||
result->return_data[6]=0;
|
||||
printf("Layout: %s\n",result->return_data);
|
||||
free(result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int S_tongue_in(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* okay, stick our tongue out. We need a slot ID to grab a caddy from. */
|
||||
static int S_tongue_out(void) {
|
||||
int slotnum=arg1;
|
||||
Inquiry_T *inquiry_info; /* needed by MoveMedium etc... */
|
||||
RequestSense_T RequestSense;
|
||||
|
||||
/* see if we have element status: */
|
||||
if (ElementStatus==NULL) {
|
||||
inquiry_info=RequestInquiry(MediumChangerFD,&RequestSense);
|
||||
if (!inquiry_info) {
|
||||
PrintRequestSense(&RequestSense);
|
||||
FatalError("INQUIRY Command Failed\n");
|
||||
}
|
||||
ElementStatus = ReadElementStatus(MediumChangerFD,&RequestSense,inquiry_info,&SCSI_Flags);
|
||||
if (!ElementStatus) {
|
||||
PrintRequestSense(&RequestSense);
|
||||
FatalError("READ ELEMENT STATUS Command Failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Okay, we have element status, so now let's assume that */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* See parse_args for the scoop. parse_args does all. */
|
||||
int main(int argc, char **argv) {
|
||||
argv0=argv[0];
|
||||
parse_args(argc,argv);
|
||||
|
||||
if (device)
|
||||
SCSI_CloseDevice(device,MediumChangerFD);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
159
mtx-1.3.12/scsi_aix.c
Normal file
159
mtx-1.3.12/scsi_aix.c
Normal file
@@ -0,0 +1,159 @@
|
||||
/* Changes 2003 Steve Heck <steve.heck@am.sony.com>
|
||||
Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
|
||||
|
||||
$Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $
|
||||
$Revision: 193 $
|
||||
|
||||
This program is free software; you may redistribute and/or modify it under
|
||||
the terms of the GNU General Public License Version 2 as published by the
|
||||
Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for complete details.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* This is the SCSI commands for AIX using GSC Generic SCSI Interface. */
|
||||
|
||||
#define LONG_PRINT_REQUEST_SENSE /* sigh! */
|
||||
|
||||
DEVICE_TYPE SCSI_OpenDevice(char *DeviceName)
|
||||
{
|
||||
int DeviceFD = open(DeviceName, 0);
|
||||
|
||||
if (DeviceFD < 0)
|
||||
FatalError("cannot open SCSI device '%s' - %m\n", DeviceName);
|
||||
return (DEVICE_TYPE) DeviceFD;
|
||||
}
|
||||
|
||||
|
||||
void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD)
|
||||
{
|
||||
if (close(DeviceFD) < 0)
|
||||
FatalError("cannot close SCSI device '%s' - %m\n", DeviceName);
|
||||
}
|
||||
|
||||
|
||||
#define HAS_SCSI_TIMEOUT
|
||||
|
||||
static int timeout = 9 * 60;
|
||||
|
||||
void SCSI_Set_Timeout(int to)
|
||||
{
|
||||
timeout = to;
|
||||
}
|
||||
|
||||
void SCSI_Default_Timeout(void)
|
||||
{
|
||||
timeout = 9 * 60; /* the default */
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
int SCSI_DumpBuffer(int DataBufferLength, unsigned char *DataBuffer)
|
||||
{
|
||||
int i, j;
|
||||
j = 0;
|
||||
|
||||
for (i = 0; i < DataBufferLength; i++)
|
||||
{
|
||||
if (j == 25)
|
||||
{
|
||||
fprintf(stderr, "\n");
|
||||
j = 0;
|
||||
}
|
||||
|
||||
if (j == 0)
|
||||
{
|
||||
fprintf(stderr, "%04x:", i);
|
||||
}
|
||||
|
||||
if (j > 0)
|
||||
{
|
||||
fprintf(stderr, " ");
|
||||
}
|
||||
|
||||
fprintf(stderr, "%02x", (int)DataBuffer[i]);
|
||||
j++;
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
|
||||
Direction_T Direction,
|
||||
CDB_T *CDB,
|
||||
int CDB_Length,
|
||||
void *DataBuffer,
|
||||
int DataBufferLength,
|
||||
RequestSense_T *RequestSense)
|
||||
{
|
||||
int ioctl_result;
|
||||
char sbyte;
|
||||
scmd_t scmd;
|
||||
|
||||
#ifdef DEBUG_SCSI
|
||||
fprintf(stderr,"------CDB--------\n");
|
||||
SCSI_DumpBuffer(CDB_Length,(char *)CDB);
|
||||
#endif
|
||||
|
||||
/* memset(&scmd, 0, sizeof(struct scmd_t)); */
|
||||
/* memset(RequestSense, 0, sizeof(RequestSense_T)); */
|
||||
switch (Direction)
|
||||
{
|
||||
case Input:
|
||||
scmd.rw = 1;
|
||||
if (DataBufferLength > 0)
|
||||
{
|
||||
memset(DataBuffer, 0, DataBufferLength);
|
||||
}
|
||||
break;
|
||||
|
||||
case Output:
|
||||
scmd.rw = 2;
|
||||
break;
|
||||
}
|
||||
/* Set timeout to 5 minutes. */
|
||||
#ifdef DEBUG_TIMEOUT
|
||||
fprintf(stderr,"timeout=%d\n",timeout);
|
||||
fflush(stderr);
|
||||
#endif
|
||||
|
||||
scmd.timeval = timeout;
|
||||
|
||||
scmd.cdb = (caddr_t) CDB;
|
||||
scmd.cdblen = CDB_Length;
|
||||
scmd.data_buf = DataBuffer;
|
||||
scmd.datalen = DataBufferLength;
|
||||
scmd.sense_buf = (caddr_t) RequestSense;
|
||||
scmd.senselen = sizeof(RequestSense_T);
|
||||
scmd.statusp = &sbyte;
|
||||
ioctl_result = ioctl(DeviceFD, GSC_CMD, (caddr_t) &scmd);
|
||||
|
||||
SCSI_Default_Timeout(); /* set it back to default, sigh. */
|
||||
|
||||
if (ioctl_result < 0)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
perror("mtx");
|
||||
#endif
|
||||
return ioctl_result;
|
||||
}
|
||||
|
||||
if (sbyte != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#ifdef DEBUG_SCSI
|
||||
if (Direction==Input)
|
||||
{
|
||||
fprintf(stderr,"--------input data-----------\n");
|
||||
SCSI_DumpBuffer(DataBufferLength,DataBuffer);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
116
mtx-1.3.12/scsi_freebsd.c
Normal file
116
mtx-1.3.12/scsi_freebsd.c
Normal file
@@ -0,0 +1,116 @@
|
||||
/* Copyright 2000 Enhanced Software Technologies Inc. (http://www.estinc.com)
|
||||
Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
|
||||
Written by Eric Lee Green <eric@badtux.org>
|
||||
|
||||
$Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $
|
||||
$Revision: 193 $
|
||||
|
||||
This program is free software; you may redistribute and/or modify it under
|
||||
the terms of the GNU General Public License Version 2 as published by the
|
||||
Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for complete details.
|
||||
|
||||
*/
|
||||
|
||||
/* This is the SCSI commands for FreeBSD */
|
||||
DEVICE_TYPE SCSI_OpenDevice(char *DeviceName)
|
||||
{
|
||||
struct cam_device *DeviceFD = cam_open_pass(DeviceName, O_RDWR | O_EXCL, NULL);
|
||||
if (DeviceFD == 0)
|
||||
FatalError("cannot open SCSI device '%s' - %m\n", DeviceName);
|
||||
return (DEVICE_TYPE) DeviceFD;
|
||||
}
|
||||
|
||||
|
||||
void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD)
|
||||
{
|
||||
cam_close_device((struct cam_device *) DeviceFD);
|
||||
}
|
||||
|
||||
#define PASS_HZ 1000*60
|
||||
#define PASS_DEFAULT_TIMEOUT 5*PASS_HZ
|
||||
static int pass_timeout = PASS_DEFAULT_TIMEOUT;
|
||||
|
||||
void SCSI_Set_Timeout(int secs)
|
||||
{
|
||||
pass_timeout=secs*PASS_HZ;
|
||||
}
|
||||
|
||||
void SCSI_Default_Timeout(void) {
|
||||
pass_timeout=5*PASS_HZ;
|
||||
}
|
||||
|
||||
int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
|
||||
Direction_T Direction,
|
||||
CDB_T *CDB,
|
||||
int CDB_Length,
|
||||
void *DataBuffer,
|
||||
int DataBufferLength,
|
||||
RequestSense_T *RequestSense)
|
||||
{
|
||||
struct cam_device *dsp = (struct cam_device *) DeviceFD;
|
||||
int retval;
|
||||
union ccb *ccb;
|
||||
CDB_T *cdb;
|
||||
int Result;
|
||||
|
||||
ccb = cam_getccb(dsp);
|
||||
cdb = (CDB_T *) &ccb->csio.cdb_io.cdb_bytes; /* pointer to actual cdb. */
|
||||
|
||||
/* cam_getccb() zeros the CCB header only. So now clear the
|
||||
* payload portion of the ccb.
|
||||
*/
|
||||
bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
|
||||
|
||||
/* copy the CDB... */
|
||||
memcpy(cdb,CDB,CDB_Length);
|
||||
|
||||
/* set the command control block stuff.... the rather involved
|
||||
* conditional expression sets the direction to NONE if there is no
|
||||
* data to go in or out, and IN or OUT if we want data. Movement
|
||||
* commands will have no data buffer, just a CDB, while INQUIRY and
|
||||
* READ_ELEMENT_STATUS will have input data, and we don't have any
|
||||
* stuff that outputs data -- yet -- but we may eventually.
|
||||
*/
|
||||
cam_fill_csio( &ccb->csio,
|
||||
1, /* retries */
|
||||
NULL, /* cbfcnp*/
|
||||
(DataBufferLength ?
|
||||
(Direction == Input ? CAM_DIR_IN : CAM_DIR_OUT) :
|
||||
CAM_DIR_NONE), /* flags */
|
||||
MSG_SIMPLE_Q_TAG, /* tag action */
|
||||
DataBuffer, /* data ptr */
|
||||
DataBufferLength, /* xfer_len */
|
||||
SSD_FULL_SIZE, /* sense_len */
|
||||
CDB_Length, /* cdb_len */
|
||||
pass_timeout /* timeout */ /* should be 5 minutes or more?! */
|
||||
);
|
||||
|
||||
pass_timeout = PASS_DEFAULT_TIMEOUT; /* make sure it gets reset. */
|
||||
memset(RequestSense, 0, sizeof(RequestSense_T)); /* clear sense buffer... */
|
||||
|
||||
if (Direction == Input)
|
||||
{
|
||||
memset(DataBuffer, 0, DataBufferLength);
|
||||
}
|
||||
|
||||
Result = cam_send_ccb(DeviceFD,ccb);
|
||||
if (Result < 0 ||
|
||||
(ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
|
||||
{
|
||||
/* copy our sense data, sigh... */
|
||||
memcpy(RequestSense,(void *) &ccb->csio.sense_data,
|
||||
min(sizeof(RequestSense_T), sizeof(struct scsi_sense_data)));
|
||||
|
||||
cam_freeccb(ccb);
|
||||
return -1; /* sorry! */
|
||||
}
|
||||
|
||||
/* okay, we did good, maybe? */
|
||||
cam_freeccb(ccb);
|
||||
return 0; /* and done? */
|
||||
}
|
||||
134
mtx-1.3.12/scsi_hpux.c
Normal file
134
mtx-1.3.12/scsi_hpux.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/* Copyright 1997, 1998 Leonard Zubkoff <lnz@dandelion.com>
|
||||
Changes copyright 2000 Eric Green <eric@badtux.org>
|
||||
Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
|
||||
|
||||
This program is free software; you may redistribute and/or modify it under
|
||||
the terms of the GNU General Public License Version 2 as published by the
|
||||
Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for complete details.
|
||||
|
||||
struct sctl_io
|
||||
{
|
||||
unsigned flags; // IN: SCTL_READ
|
||||
unsigned cdb_length; // IN
|
||||
unsigned char cdb[16]; // IN
|
||||
void *data; // IN
|
||||
unsigned data_length; // IN
|
||||
unsigned max_msecs; // IN: milli-seconds before abort
|
||||
unsigned data_xfer; // OUT
|
||||
unsigned cdb_status; // OUT: SCSI status
|
||||
unsigned char sense[256]; // OUT
|
||||
unsigned sense_status; // OUT: SCSI status
|
||||
unsigned sense_xfer; // OUT: bytes of sense data received
|
||||
unsigned reserved[16]; // IN: Must be zero; OUT: undefined
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* Hockey Pux may define these. If so, *UN*define them. */
|
||||
#ifdef ILI
|
||||
#undef ILI
|
||||
#endif
|
||||
|
||||
#ifdef EOM
|
||||
#undef EOM
|
||||
#endif
|
||||
|
||||
/* This is the SCSI commands for HPUX. */
|
||||
|
||||
#define LONG_PRINT_REQUEST_SENSE /* Sigh! */
|
||||
|
||||
DEVICE_TYPE SCSI_OpenDevice(char *DeviceName)
|
||||
{
|
||||
int DeviceFD = open(DeviceName, O_RDWR | O_NDELAY);
|
||||
|
||||
if (DeviceFD < 0)
|
||||
FatalError("cannot open SCSI device '%s' - %m\n", DeviceName);
|
||||
|
||||
return (DEVICE_TYPE) DeviceFD;
|
||||
}
|
||||
|
||||
|
||||
void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD)
|
||||
{
|
||||
if (close(DeviceFD) < 0)
|
||||
FatalError("cannot close SCSI device '%s' - %m\n", DeviceName);
|
||||
}
|
||||
|
||||
#define MTX_HZ 1000
|
||||
#define DEFAULT_HZ (5*60*MTX_HZ)
|
||||
|
||||
static int sctl_io_timeout=DEFAULT_HZ; /* default timeout is 5 minutes. */
|
||||
|
||||
|
||||
void SCSI_Set_Timeout(int to)
|
||||
{
|
||||
sctl_io_timeout=to*60*MTX_HZ;
|
||||
}
|
||||
|
||||
void SCSI_Default_Timeout(void)
|
||||
{
|
||||
sctl_io_timeout=DEFAULT_HZ;
|
||||
}
|
||||
|
||||
|
||||
int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
|
||||
Direction_T Direction,
|
||||
CDB_T *CDB,
|
||||
int CDB_Length,
|
||||
void *DataBuffer,
|
||||
int DataBufferLength,
|
||||
RequestSense_T *RequestSense)
|
||||
{
|
||||
int ioctl_result;
|
||||
struct sctl_io Command;
|
||||
|
||||
int i;
|
||||
|
||||
memset(&Command, 0, sizeof(struct sctl_io));
|
||||
memset(RequestSense, 0, sizeof(RequestSense_T));
|
||||
|
||||
switch (Direction)
|
||||
{
|
||||
case Input:
|
||||
if (DataBufferLength > 0)
|
||||
memset(DataBuffer, 0, DataBufferLength);
|
||||
Command.flags = SCTL_READ | SCTL_INIT_SDTR;
|
||||
break;
|
||||
|
||||
case Output:
|
||||
Command.flags = SCTL_INIT_WDTR | SCTL_INIT_SDTR;
|
||||
break;
|
||||
}
|
||||
|
||||
Command.max_msecs = sctl_io_timeout; /* Set timeout to <n> minutes. */
|
||||
memcpy(Command.cdb, CDB, CDB_Length);
|
||||
Command.cdb_length = CDB_Length;
|
||||
Command.data = DataBuffer;
|
||||
Command.data_length = DataBufferLength;
|
||||
ioctl_result=ioctl(DeviceFD, SIOC_IO, &Command);
|
||||
SCSI_Default_Timeout(); /* change the default back to 5 minutes */
|
||||
|
||||
if (ioctl_result < 0)
|
||||
{
|
||||
perror("mtx");
|
||||
return ioctl_result;
|
||||
}
|
||||
|
||||
if (Command.sense_xfer > sizeof(RequestSense_T))
|
||||
{
|
||||
Command.sense_xfer=sizeof(RequestSense_T);
|
||||
}
|
||||
|
||||
if (Command.sense_xfer)
|
||||
{
|
||||
memcpy(RequestSense, Command.sense, Command.sense_xfer);
|
||||
}
|
||||
|
||||
return Command.sense_status;
|
||||
}
|
||||
491
mtx-1.3.12/scsi_linux.c
Normal file
491
mtx-1.3.12/scsi_linux.c
Normal file
@@ -0,0 +1,491 @@
|
||||
/* Copyright 1997, 1998 Leonard Zubkoff <lnz@dandelion.com>
|
||||
Changes in Feb 2000 Eric Green <eric@badtux.org>
|
||||
Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
|
||||
|
||||
$Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $
|
||||
$Revision: 193 $
|
||||
|
||||
This program is free software; you may redistribute and/or modify it under
|
||||
the terms of the GNU General Public License Version 2 as published by the
|
||||
Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for complete details.
|
||||
|
||||
*/
|
||||
|
||||
/* this is the SCSI commands for Linux. Note that <eric@badtux.org> changed
|
||||
* it from using SCSI_IOCTL_SEND_COMMAND to using the SCSI generic interface.
|
||||
*/
|
||||
|
||||
#ifndef HZ
|
||||
#warning "HZ is not defined, mtx might not work correctly!"
|
||||
#define HZ 100 /* Jiffys for SG_SET_TIMEOUT */
|
||||
#endif
|
||||
|
||||
/* These are copied out of BRU 16.1, with all the boolean masks changed
|
||||
* to our bitmasks.
|
||||
*/
|
||||
#define S_NO_SENSE(s) ((s)->SenseKey == 0x0)
|
||||
#define S_RECOVERED_ERROR(s) ((s)->SenseKey == 0x1)
|
||||
|
||||
#define S_NOT_READY(s) ((s)->SenseKey == 0x2)
|
||||
#define S_MEDIUM_ERROR(s) ((s)->SenseKey == 0x3)
|
||||
#define S_HARDWARE_ERROR(s) ((s)->SenseKey == 0x4)
|
||||
#define S_UNIT_ATTENTION(s) ((s)->SenseKey == 0x6)
|
||||
#define S_BLANK_CHECK(s) ((s)->SenseKey == 0x8)
|
||||
#define S_VOLUME_OVERFLOW(s) ((s)->SenseKey == 0xd)
|
||||
|
||||
#define DEFAULT_TIMEOUT 3*60 /* 3 minutes here */
|
||||
|
||||
/* Sigh, the T-10 SSC spec says all of the following is needed to
|
||||
* detect a short read while in variable block mode, and that even
|
||||
* though we got a BLANK_CHECK or MEDIUM_ERROR, it's still a valid read.
|
||||
*/
|
||||
|
||||
#define HIT_FILEMARK(s) (S_NO_SENSE((s)) && (s)->Filemark && (s)->Valid)
|
||||
#define SHORT_READ(s) (S_NO_SENSE((s)) && (s)->ILI && (s)->Valid && (s)->AdditionalSenseCode==0 && (s)->AdditionalSenseCodeQualifier==0)
|
||||
#define HIT_EOD(s) (S_BLANK_CHECK((s)) && (s)->Valid)
|
||||
#define HIT_EOP(s) (S_MEDIUM_ERROR((s)) && (s)->EOM && (s)->Valid)
|
||||
#define HIT_EOM(s) ((s)->EOM && (s)->Valid)
|
||||
|
||||
#define STILL_A_VALID_READ(s) (HIT_FILEMARK(s) || SHORT_READ(s) || HIT_EOD(s) || HIT_EOP(s) || HIT_EOM(s))
|
||||
|
||||
#define SG_SCSI_DEFAULT_TIMEOUT (HZ*60*5) /* 5 minutes? */
|
||||
|
||||
static int pack_id;
|
||||
static int sg_timeout;
|
||||
|
||||
DEVICE_TYPE SCSI_OpenDevice(char *DeviceName)
|
||||
{
|
||||
int timeout = SG_SCSI_DEFAULT_TIMEOUT;
|
||||
#ifdef SG_IO
|
||||
int k; /* version */
|
||||
#endif
|
||||
int DeviceFD = open(DeviceName, O_RDWR);
|
||||
|
||||
if (DeviceFD < 0)
|
||||
FatalError("cannot open SCSI device '%s' - %m\n", DeviceName);
|
||||
|
||||
|
||||
#ifdef SG_IO
|
||||
/* It is prudent to check we have a sg device by trying an ioctl */
|
||||
if ((ioctl(DeviceFD, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000))
|
||||
{
|
||||
FatalError("%s is not an sg device, or old sg driver\n", DeviceName);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ioctl(DeviceFD, SG_SET_TIMEOUT, &timeout))
|
||||
{
|
||||
FatalError("failed to set sg timeout - %m\n");
|
||||
}
|
||||
pack_id = 1; /* used for SG v3 interface if possible. */
|
||||
return (DEVICE_TYPE) DeviceFD;
|
||||
}
|
||||
|
||||
void SCSI_Set_Timeout(int secs)
|
||||
{
|
||||
sg_timeout = secs * HZ;
|
||||
}
|
||||
|
||||
void SCSI_Default_Timeout(void)
|
||||
{
|
||||
sg_timeout = SG_SCSI_DEFAULT_TIMEOUT;
|
||||
}
|
||||
|
||||
void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD)
|
||||
{
|
||||
if (close(DeviceFD) < 0)
|
||||
FatalError("cannot close SCSI device '%s' - %m\n", DeviceName);
|
||||
}
|
||||
|
||||
|
||||
/* Added by Eric Green <eric@estinc.com> to deal with burping
|
||||
* Seagate autoloader (hopefully!).
|
||||
*/
|
||||
/* Get the SCSI ID and LUN... */
|
||||
scsi_id_t *SCSI_GetIDLun(DEVICE_TYPE fd)
|
||||
{
|
||||
int status;
|
||||
scsi_id_t *retval;
|
||||
|
||||
struct my_scsi_idlun
|
||||
{
|
||||
int word1;
|
||||
int word2;
|
||||
} idlun;
|
||||
|
||||
status = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &idlun);
|
||||
if (status)
|
||||
{
|
||||
return NULL; /* sorry! */
|
||||
}
|
||||
|
||||
retval = (scsi_id_t *)xmalloc(sizeof(scsi_id_t));
|
||||
retval->id = idlun.word1 & 0xff;
|
||||
retval->lun = idlun.word1 >> 8 & 0xff;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "SCSI:ID=%d LUN=%d\n", retval->id, retval->lun);
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/* Changed January 2001 by Eric Green <eric@badtux.org> to
|
||||
* use the Linux version 2.4 SCSI Generic facility if available.
|
||||
* Liberally cribbed code from Doug Gilbert's sg3 utils.
|
||||
*/
|
||||
|
||||
#ifdef SG_IO
|
||||
#include "sg_err.h" /* error stuff. */
|
||||
#include "sg_err.c" /* some of Doug Gilbert's routines */
|
||||
|
||||
/* Use the new SG_IO structure */
|
||||
int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
|
||||
Direction_T Direction,
|
||||
CDB_T *CDB,
|
||||
int CDB_Length,
|
||||
void *DataBuffer,
|
||||
int DataBufferLength,
|
||||
RequestSense_T *RequestSense)
|
||||
{
|
||||
unsigned int status;
|
||||
sg_io_hdr_t io_hdr;
|
||||
|
||||
memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
|
||||
memset(RequestSense, 0, sizeof(RequestSense_T));
|
||||
|
||||
/* Fill in the common stuff... */
|
||||
io_hdr.interface_id = 'S';
|
||||
io_hdr.cmd_len = CDB_Length;
|
||||
io_hdr.mx_sb_len = sizeof(RequestSense_T);
|
||||
io_hdr.dxfer_len = DataBufferLength;
|
||||
io_hdr.cmdp = (unsigned char *) CDB;
|
||||
io_hdr.sbp = (unsigned char *) RequestSense;
|
||||
io_hdr.dxferp = DataBuffer;
|
||||
io_hdr.timeout = sg_timeout * 10; /* Convert from Jiffys to milliseconds */
|
||||
|
||||
if (Direction==Input)
|
||||
{
|
||||
/* fprintf(stderr,"direction=input\n"); */
|
||||
io_hdr.dxfer_direction=SG_DXFER_FROM_DEV;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* fprintf(stderr,"direction=output\n"); */
|
||||
io_hdr.dxfer_direction=SG_DXFER_TO_DEV;
|
||||
}
|
||||
|
||||
/* Now do it: */
|
||||
if ((status = ioctl(DeviceFD, SG_IO , &io_hdr)) || io_hdr.masked_status)
|
||||
{
|
||||
/* fprintf(stderr, "smt_scsi_cmd: Rval=%d Status=%d, errno=%d [%s]\n",status, io_hdr.masked_status,
|
||||
errno,
|
||||
strerror(errno)); */
|
||||
|
||||
switch (sg_err_category3(&io_hdr))
|
||||
{
|
||||
case SG_ERR_CAT_CLEAN:
|
||||
case SG_ERR_CAT_RECOVERED:
|
||||
break;
|
||||
|
||||
case SG_ERR_CAT_MEDIA_CHANGED:
|
||||
return 2;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* fprintf(stderr,"host_status=%d driver_status=%d residual=%d writelen=%d\n",io_hdr.host_status,io_hdr.driver_status,io_hdr.resid,io_hdr.sb_len_wr ); */
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* Now check the returned statuses: */
|
||||
/* fprintf(stderr,"host_status=%d driver_status=%d residual=%d writelen=%d\n",io_hdr.host_status,io_hdr.driver_status,io_hdr.resid,io_hdr.sb_len_wr ); */
|
||||
|
||||
SCSI_Default_Timeout(); /* reset back to default timeout, sigh. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Changed February 2000 by Eric Green <eric@estinc.com> to
|
||||
* use the SCSI generic interface rather than SCSI_IOCTL_SEND_COMMAND
|
||||
* so that we can get more than PAGE_SIZE data....
|
||||
*
|
||||
* Note that the SCSI generic interface abuses READ and WRITE calls to serve
|
||||
* the same purpose as IOCTL calls, i.e., for "writes", the contents of the
|
||||
* buffer that you send as the argument to the write() call are actually
|
||||
* altered to fill in result status and sense data (if needed).
|
||||
* Also note that this brain-dead interface does not have any sort of
|
||||
* provisions for expanding the sg_header struct in a backward-compatible
|
||||
* manner. This sucks. But sucks less than SCSI_IOCTL_SEND_COMMAND, sigh.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef OLD_EXECUTE_COMMAND_STUFF
|
||||
|
||||
static void slow_memcopy(unsigned char *src, unsigned char *dest, int numbytes)
|
||||
{
|
||||
while (numbytes--)
|
||||
{
|
||||
*dest++ = *src++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
|
||||
Direction_T Direction,
|
||||
CDB_T *CDB,
|
||||
int CDB_Length,
|
||||
void *DataBuffer,
|
||||
int DataBufferLength,
|
||||
RequestSense_T *RequestSense)
|
||||
{
|
||||
unsigned char *Command=NULL; /* the command data struct sent to them... */
|
||||
unsigned char *ResultBuf=NULL; /* the data we read in return... */
|
||||
|
||||
unsigned char *src; /* for copying stuff, sigh. */
|
||||
unsigned char *dest; /* for copy stuff, again, sigh. */
|
||||
|
||||
int write_length = sizeof(struct sg_header)+CDB_Length;
|
||||
int i; /* a random index... */
|
||||
int result; /* the result of the write... */
|
||||
|
||||
struct sg_header *Header; /* we actually point this into Command... */
|
||||
struct sg_header *ResultHeader; /* we point this into ResultBuf... */
|
||||
|
||||
/* First, see if we need to set our SCSI timeout to something different */
|
||||
if (sg_timeout != SG_SCSI_DEFAULT_TIMEOUT)
|
||||
{
|
||||
/* if not default, set it: */
|
||||
#ifdef DEBUG_TIMEOUT
|
||||
fprintf(stderr,"Setting timeout to %d\n", sg_timeout);
|
||||
fflush(stderr);
|
||||
#endif
|
||||
if(ioctl(DeviceFD, SG_SET_TIMEOUT, &sg_timeout))
|
||||
{
|
||||
FatalError("failed to set sg timeout - %m\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (Direction == Output)
|
||||
{
|
||||
/* if we're writing, our length is longer... */
|
||||
write_length += DataBufferLength;
|
||||
}
|
||||
|
||||
/* allocate some memory... enough for the command plus the header +
|
||||
* any other data that we may need here...
|
||||
*/
|
||||
|
||||
Command = (unsigned char *)xmalloc(write_length);
|
||||
Header = (struct sg_header *) Command; /* make it point to start of buf */
|
||||
|
||||
dest = Command; /* now to copy the CDB... from start of buffer,*/
|
||||
dest += sizeof(struct sg_header); /* increment it past the header. */
|
||||
|
||||
slow_memcopy((char *)CDB, dest, CDB_Length);
|
||||
|
||||
/* if we are writing additional data, tack it on here! */
|
||||
if (Direction == Output)
|
||||
{
|
||||
dest += CDB_Length;
|
||||
slow_memcopy(DataBuffer, dest, DataBufferLength); /* copy to end of command */
|
||||
}
|
||||
|
||||
/* Now to fill in the Header struct: */
|
||||
Header->reply_len=DataBufferLength+sizeof(struct sg_header);
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"sg:reply_len(sent)=%d\n",Header->reply_len);
|
||||
#endif
|
||||
Header->twelve_byte = CDB_Length == 12;
|
||||
Header->result = 0;
|
||||
Header->pack_len = write_length; /* # of bytes written... */
|
||||
Header->pack_id = 0; /* not used */
|
||||
Header->other_flags = 0; /* not used. */
|
||||
Header->sense_buffer[0]=0; /* used? */
|
||||
|
||||
/* Now to do the write... */
|
||||
result = write(DeviceFD,Command,write_length);
|
||||
|
||||
/* Now to check the result :-(. */
|
||||
/* Note that we don't have any request sense here. So we have no
|
||||
* idea what's going on.
|
||||
*/
|
||||
if (result < 0 || result != write_length || Header->result || Header->sense_buffer[0])
|
||||
{
|
||||
#ifdef DEBUG_SCSI
|
||||
fprintf(stderr,"scsi:result=%d Header->result=%d Header->sense_buffer[0]=%d\n",
|
||||
result,Header->result,Header->sense_buffer[0]);
|
||||
#endif
|
||||
/* we don't have any real sense data, sigh :-(. */
|
||||
if (Header->sense_buffer[0])
|
||||
{
|
||||
/* well, I guess we DID have some! eep! copy the sense data! */
|
||||
slow_memcopy((char *)Header->sense_buffer,(char *)RequestSense,
|
||||
sizeof(Header->sense_buffer));
|
||||
}
|
||||
else
|
||||
{
|
||||
dest=(unsigned char *)RequestSense;
|
||||
*dest=(unsigned char)Header->result; /* may chop, sigh... */
|
||||
}
|
||||
|
||||
/* okay, now, we may or may not need to find a non-zero value to return.
|
||||
* For tape drives, we may get a BLANK_CHECK or MEDIUM_ERROR and find
|
||||
* that it's *STILL* a good read! Use the STILL_A_VALID_READ macro
|
||||
* that calls all those macros I cribbed from Richard.
|
||||
*/
|
||||
|
||||
if (!STILL_A_VALID_READ(RequestSense))
|
||||
{
|
||||
free(Command); /* zap memory leak, sigh */
|
||||
/* okay, find us a non-zero value to return :-(. */
|
||||
if (result)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else if (Header->result)
|
||||
{
|
||||
return Header->result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1; /* sigh */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result=-1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result=0; /* we're okay! */
|
||||
}
|
||||
|
||||
/* now to allocate the new block.... */
|
||||
ResultBuf=(unsigned char *)xmalloc(Header->reply_len);
|
||||
/* now to clear ResultBuf... */
|
||||
slow_bzero(ResultBuf,Header->reply_len);
|
||||
|
||||
ResultHeader=(struct sg_header *)ResultBuf;
|
||||
|
||||
/* copy the original Header... */
|
||||
ResultHeader->result=0;
|
||||
ResultHeader->pack_id=0;
|
||||
ResultHeader->other_flags=0;
|
||||
ResultHeader->reply_len=Header->reply_len;
|
||||
ResultHeader->twelve_byte = CDB_Length == 12;
|
||||
ResultHeader->pack_len = write_length; /* # of bytes written... */
|
||||
ResultHeader->sense_buffer[0]=0; /* whoops! Zero that! */
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"sg:Reading %d bytes from DeviceFD\n",Header->reply_len);
|
||||
fflush(stderr);
|
||||
#endif
|
||||
result=read(DeviceFD,ResultBuf,Header->reply_len);
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"sg:result=%d ResultHeader->result=%d\n",
|
||||
result,ResultHeader->result);
|
||||
fflush(stderr);
|
||||
#endif
|
||||
/* New: added check to see if the result block is still all zeros! */
|
||||
if (result < 0 ||
|
||||
result != Header->reply_len ||
|
||||
ResultHeader->result ||
|
||||
ResultHeader->sense_buffer[0])
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,
|
||||
"scsi: result=%d Header->reply_len=%d ResultHeader->result=%d ResultHeader->sense_buffer[0]=%d\n",
|
||||
result,
|
||||
Header->reply_len,
|
||||
ResultHeader->result,
|
||||
ResultHeader->sense_buffer[0]);
|
||||
#endif
|
||||
/* eep! copy the sense data! */
|
||||
slow_memcopy((char *)ResultHeader->sense_buffer,(char *)RequestSense,
|
||||
sizeof(ResultHeader->sense_buffer));
|
||||
/* sense data copied, now find us a non-zero value to return :-(. */
|
||||
/* NOTE: Some commands return sense data even though they validly
|
||||
* executed! We catch a few of those with the macro STILL_A_VALID_READ.
|
||||
*/
|
||||
|
||||
if (!STILL_A_VALID_READ(RequestSense))
|
||||
{
|
||||
free(Command);
|
||||
if (result)
|
||||
{
|
||||
free(ResultBuf);
|
||||
return result;
|
||||
}
|
||||
else if (ResultHeader->result)
|
||||
{
|
||||
free(ResultBuf);
|
||||
return ResultHeader->result;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(ResultBuf);
|
||||
return -1; /* sigh! */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result=-1; /* if it was a valid read, still have -1 result. */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result=0;
|
||||
}
|
||||
|
||||
/* See if we need to reset our SCSI timeout */
|
||||
if (sg_timeout != SG_SCSI_DEFAULT_TIMEOUT)
|
||||
{
|
||||
sg_timeout = SG_SCSI_DEFAULT_TIMEOUT; /* reset it back to default */
|
||||
|
||||
#ifdef DEBUG_TIMEOUT
|
||||
fprintf(stderr,"Setting timeout to %d\n", sg_timeout);
|
||||
fflush(stderr);
|
||||
#endif
|
||||
/* if not default, set it: */
|
||||
if (ioctl(DeviceFD, SG_SET_TIMEOUT, &sg_timeout))
|
||||
{
|
||||
FatalError("failed to set sg timeout - %m\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* now for the crowning moment: copying any result into the DataBuffer! */
|
||||
/* (but only if it were an input command and not an output command :-} */
|
||||
if (Direction == Input)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"Header->reply_len=%d,ResultHeader->reply_len=%d\n",
|
||||
Header->reply_len,ResultHeader->reply_len);
|
||||
#endif
|
||||
src=ResultBuf+sizeof(struct sg_header);
|
||||
dest=DataBuffer;
|
||||
for (i = 0; i < ResultHeader->reply_len; i++)
|
||||
{
|
||||
if (i >= DataBufferLength)
|
||||
break; /* eep! */
|
||||
*dest++ = *src++;
|
||||
}
|
||||
}
|
||||
|
||||
/* and return! */
|
||||
free(Command); /* clean up memory leak... */
|
||||
free(ResultBuf);
|
||||
return result; /* good stuff ! */
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* #ifdef SG_IO */
|
||||
81
mtx-1.3.12/scsi_sgi.c
Normal file
81
mtx-1.3.12/scsi_sgi.c
Normal file
@@ -0,0 +1,81 @@
|
||||
/* Copyright 1997, 1998 Leonard Zubkoff <lnz@dandelion.com>
|
||||
Changes copyright 2000 Eric Green <eric@badtux.org>
|
||||
Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
|
||||
|
||||
$Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $
|
||||
$Revision: 193 $
|
||||
|
||||
This program is free software; you may redistribute and/or modify it under
|
||||
the terms of the GNU General Public License Version 2 as published by the
|
||||
Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for complete details.
|
||||
|
||||
*/
|
||||
|
||||
/* This is the SCSI commands for SGI Iris */
|
||||
DEVICE_TYPE SCSI_OpenDevice(char *DeviceName)
|
||||
{
|
||||
dsreq_t *DeviceFD = dsopen(DeviceName, O_RDWR | O_EXCL);
|
||||
if (DeviceFD == 0)
|
||||
FatalError("cannot open SCSI device '%s' - %m\n", DeviceName);
|
||||
return (DEVICE_TYPE) DeviceFD;
|
||||
}
|
||||
|
||||
|
||||
void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD)
|
||||
{
|
||||
dsclose((dsreq_t *) DeviceFD);
|
||||
}
|
||||
|
||||
#define MTX_HZ 1000
|
||||
#define MTX_DEFAULT_SCSI_TIMEOUT 60*5*MTX_HZ /* 5 minutes! */
|
||||
|
||||
static int mtx_default_timeout = MTX_DEFAULT_SCSI_TIMEOUT ;
|
||||
void SCSI_Set_Timeout(int sec)
|
||||
{
|
||||
mtx_default_timeout=sec*MTX_HZ;
|
||||
}
|
||||
|
||||
void SCSI_Default_Timeout()
|
||||
{
|
||||
mtx_default_timeout=MTX_DEFAULT_SCSI_TIMEOUT;
|
||||
}
|
||||
|
||||
int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
|
||||
Direction_T Direction,
|
||||
CDB_T *CDB,
|
||||
int CDB_Length,
|
||||
void *DataBuffer,
|
||||
int DataBufferLength,
|
||||
RequestSense_T *RequestSense)
|
||||
{
|
||||
dsreq_t *dsp = (dsreq_t *) DeviceFD;
|
||||
int Result;
|
||||
memset(RequestSense, 0, sizeof(RequestSense_T));
|
||||
memcpy(CMDBUF(dsp), CDB, CDB_Length);
|
||||
|
||||
if (Direction == Input)
|
||||
{
|
||||
memset(DataBuffer, 0, DataBufferLength);
|
||||
filldsreq(dsp, (unsigned char *) DataBuffer, DataBufferLength, DSRQ_READ | DSRQ_SENSE);
|
||||
}
|
||||
else
|
||||
filldsreq(dsp, (unsigned char *) DataBuffer, DataBufferLength, DSRQ_WRITE | DSRQ_SENSE);
|
||||
|
||||
/* Set 5 minute timeout. */
|
||||
/* TIME(dsp) = 300 * 1000; */
|
||||
TIME(dsp) = mtx_default_timeout;
|
||||
Result = doscsireq(getfd((dsp)), dsp);
|
||||
|
||||
if (SENSESENT(dsp) > 0)
|
||||
{
|
||||
memcpy(RequestSense, SENSEBUF(dsp), min(sizeof(RequestSense_T), SENSESENT(dsp)));
|
||||
}
|
||||
|
||||
SCSI_Default_Timeout(); /* reset the mtx default timeout */
|
||||
return Result;
|
||||
}
|
||||
156
mtx-1.3.12/scsi_sun.c
Normal file
156
mtx-1.3.12/scsi_sun.c
Normal file
@@ -0,0 +1,156 @@
|
||||
/* Copyright 1997, 1998 Leonard Zubkoff <lnz@dandelion.com>
|
||||
Changes copyright 2000 Eric Green <eric@badtux.org>
|
||||
Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
|
||||
|
||||
$Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $
|
||||
$Revision: 193 $
|
||||
|
||||
This program is free software; you may redistribute and/or modify it under
|
||||
the terms of the GNU General Public License Version 2 as published by the
|
||||
Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for complete details.
|
||||
|
||||
*/
|
||||
|
||||
/* This is the SCSI commands for Sun Solaris. */
|
||||
|
||||
#define LONG_PRINT_REQUEST_SENSE /* sigh! */
|
||||
|
||||
DEVICE_TYPE SCSI_OpenDevice(char *DeviceName)
|
||||
{
|
||||
int DeviceFD = open(DeviceName, O_RDWR | O_NDELAY);
|
||||
if (DeviceFD < 0)
|
||||
FatalError("cannot open SCSI device '%s' - %m\n", DeviceName);
|
||||
return (DEVICE_TYPE) DeviceFD;
|
||||
}
|
||||
|
||||
|
||||
void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD)
|
||||
{
|
||||
if (close(DeviceFD) < 0)
|
||||
FatalError("cannot close SCSI device '%s' - %m\n", DeviceName);
|
||||
}
|
||||
|
||||
|
||||
#define HAS_SCSI_TIMEOUT
|
||||
|
||||
static int uscsi_timeout=5*60;
|
||||
|
||||
void SCSI_Set_Timeout(int to)
|
||||
{
|
||||
uscsi_timeout = to;
|
||||
}
|
||||
|
||||
void SCSI_Default_Timeout(void)
|
||||
{
|
||||
uscsi_timeout=5*60; /* the default */
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
int SCSI_DumpBuffer(int DataBufferLength, unsigned char *DataBuffer)
|
||||
{
|
||||
int i,j;
|
||||
j = 0;
|
||||
|
||||
for (i = 0; i < DataBufferLength; i++)
|
||||
{
|
||||
if (j == 25)
|
||||
{
|
||||
fprintf(stderr,"\n");
|
||||
j = 0;
|
||||
}
|
||||
|
||||
if (j == 0)
|
||||
{
|
||||
fprintf(stderr, "%04x:", i);
|
||||
}
|
||||
|
||||
if (j > 0)
|
||||
{
|
||||
fprintf(stderr," ");
|
||||
}
|
||||
|
||||
fprintf(stderr, "%02x", (int)DataBuffer[i]);
|
||||
j++;
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
|
||||
Direction_T Direction,
|
||||
CDB_T *CDB,
|
||||
int CDB_Length,
|
||||
void *DataBuffer,
|
||||
int DataBufferLength,
|
||||
RequestSense_T *RequestSense)
|
||||
{
|
||||
int ioctl_result;
|
||||
struct uscsi_cmd Command;
|
||||
|
||||
#ifdef DEBUG_SCSI
|
||||
fprintf(stderr,"------CDB--------\n");
|
||||
SCSI_DumpBuffer(CDB_Length,(char *)CDB);
|
||||
#endif
|
||||
|
||||
memset(&Command, 0, sizeof(struct uscsi_cmd));
|
||||
memset(RequestSense, 0, sizeof(RequestSense_T));
|
||||
switch (Direction)
|
||||
{
|
||||
case Input:
|
||||
Command.uscsi_flags = USCSI_DIAGNOSE | USCSI_ISOLATE | USCSI_RQENABLE;
|
||||
if (DataBufferLength > 0)
|
||||
{
|
||||
memset(DataBuffer, 0, DataBufferLength);
|
||||
Command.uscsi_flags |= USCSI_READ;
|
||||
}
|
||||
break;
|
||||
case Output:
|
||||
Command.uscsi_flags = USCSI_DIAGNOSE | USCSI_ISOLATE |
|
||||
USCSI_WRITE | USCSI_RQENABLE;
|
||||
break;
|
||||
}
|
||||
/* Set timeout to 5 minutes. */
|
||||
#ifdef DEBUG_TIMEOUT
|
||||
fprintf(stderr,"uscsi_timeout=%d\n",uscsi_timeout);
|
||||
fflush(stderr);
|
||||
#endif
|
||||
Command.uscsi_timeout = uscsi_timeout;
|
||||
|
||||
Command.uscsi_cdb = (caddr_t) CDB;
|
||||
Command.uscsi_cdblen = CDB_Length;
|
||||
Command.uscsi_bufaddr = DataBuffer;
|
||||
Command.uscsi_buflen = DataBufferLength;
|
||||
Command.uscsi_rqbuf = (caddr_t) RequestSense;
|
||||
Command.uscsi_rqlen = sizeof(RequestSense_T);
|
||||
ioctl_result = ioctl(DeviceFD, USCSICMD, &Command);
|
||||
|
||||
SCSI_Default_Timeout(); /* set it back to default, sigh. */
|
||||
|
||||
if (ioctl_result < 0)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
perror("mtx");
|
||||
#endif
|
||||
return ioctl_result;
|
||||
}
|
||||
|
||||
if (RequestSense->ErrorCode > 1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_SCSI
|
||||
if (Direction==Input)
|
||||
{
|
||||
fprintf(stderr,"--------input data-----------\n");
|
||||
SCSI_DumpBuffer(DataBufferLength, DataBuffer);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
355
mtx-1.3.12/scsi_win32.c
Normal file
355
mtx-1.3.12/scsi_win32.c
Normal file
@@ -0,0 +1,355 @@
|
||||
/* Copyright 2006-2008 Robert Nelson <robertn@the-nelsons.org>
|
||||
|
||||
$Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $
|
||||
$Revision: 193 $
|
||||
|
||||
This program is free software; you may redistribute and/or modify it under
|
||||
the terms of the GNU General Public License Version 2 as published by the
|
||||
Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for complete details.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is the SCSI commands for Windows.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <ntddscsi.h>
|
||||
#else
|
||||
#include <ddk/ntddscsi.h>
|
||||
#endif
|
||||
|
||||
#define SCSI_DEFAULT_TIMEOUT 300 /* 1 minutes */
|
||||
#define SCSI_MAX_TIMEOUT 108000 /* 30 hours */
|
||||
|
||||
typedef struct _HANDLE_ENTRY
|
||||
{
|
||||
HANDLE hDevice;
|
||||
UCHAR PortId;
|
||||
UCHAR PathId;
|
||||
UCHAR TargetId;
|
||||
UCHAR Lun;
|
||||
} HANDLE_ENTRY, *PHANDLE_ENTRY;
|
||||
|
||||
PHANDLE_ENTRY HandleTable = NULL;
|
||||
int nEntries = 0;
|
||||
|
||||
DEVICE_TYPE SCSI_OpenDevice(char *DeviceName)
|
||||
{
|
||||
int DeviceIndex;
|
||||
TCHAR szDevicePath[256];
|
||||
|
||||
int nColons = 0;
|
||||
int index;
|
||||
|
||||
int port, path, target, lun;
|
||||
|
||||
for (DeviceIndex = 0; DeviceIndex < nEntries; DeviceIndex++)
|
||||
{
|
||||
if (HandleTable[DeviceIndex].hDevice == INVALID_HANDLE_VALUE)
|
||||
break;
|
||||
}
|
||||
|
||||
if (DeviceIndex >= nEntries)
|
||||
{
|
||||
PHANDLE_ENTRY pNewTable;
|
||||
|
||||
nEntries += 4;
|
||||
|
||||
if (HandleTable == NULL)
|
||||
{
|
||||
pNewTable = (PHANDLE_ENTRY)malloc(nEntries * sizeof(HANDLE_ENTRY));
|
||||
}
|
||||
else
|
||||
{
|
||||
pNewTable = (PHANDLE_ENTRY)realloc(HandleTable, nEntries * sizeof(HANDLE_ENTRY));
|
||||
}
|
||||
|
||||
if (pNewTable == NULL)
|
||||
{
|
||||
FatalError("cannot open SCSI device '%s' - %m\n", DeviceName);
|
||||
}
|
||||
|
||||
HandleTable = pNewTable;
|
||||
}
|
||||
|
||||
for (index = 0; DeviceName[index] != '\0'; index++)
|
||||
{
|
||||
if (DeviceName[index] == ':')
|
||||
nColons++;
|
||||
else if (DeviceName[index] < '0' || DeviceName[index] > '9')
|
||||
break;
|
||||
}
|
||||
|
||||
if (DeviceName[index] == '\0' && nColons == 3 &&
|
||||
sscanf(DeviceName, "%d:%d:%d:%d", &port, &path, &target, &lun) == 4)
|
||||
{
|
||||
HandleTable[DeviceIndex].PortId = (UCHAR)port;
|
||||
HandleTable[DeviceIndex].PathId = (UCHAR)path;
|
||||
HandleTable[DeviceIndex].TargetId = (UCHAR)target;
|
||||
HandleTable[DeviceIndex].Lun = (UCHAR)lun;
|
||||
|
||||
sprintf(szDevicePath, "\\\\.\\scsi%d:", port);
|
||||
}
|
||||
else
|
||||
{
|
||||
int nPrefixLength = 0;
|
||||
|
||||
if (DeviceName[0] != '\\') {
|
||||
memcpy(szDevicePath, "\\\\.\\", 4 * sizeof(TCHAR));
|
||||
nPrefixLength = 4;
|
||||
}
|
||||
|
||||
HandleTable[DeviceIndex].PortId = 0;
|
||||
HandleTable[DeviceIndex].PathId = 0;
|
||||
HandleTable[DeviceIndex].TargetId = 0;
|
||||
HandleTable[DeviceIndex].Lun = 0;
|
||||
|
||||
strncpy(&szDevicePath[nPrefixLength],
|
||||
DeviceName,
|
||||
sizeof(szDevicePath) / sizeof(TCHAR) - nPrefixLength - 1);
|
||||
|
||||
szDevicePath[sizeof(szDevicePath) / sizeof(TCHAR) - 1] = '\0';
|
||||
}
|
||||
|
||||
HandleTable[DeviceIndex].hDevice = CreateFile(szDevicePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
|
||||
if (HandleTable[DeviceIndex].hDevice == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD dwError = GetLastError();
|
||||
|
||||
#if DEBUG
|
||||
LPSTR lpszMessage;
|
||||
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0, (LPSTR)&lpszMessage, 0, NULL);
|
||||
fputs(lpszMessage, stderr);
|
||||
#endif
|
||||
|
||||
switch (dwError)
|
||||
{
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
case ERROR_PATH_NOT_FOUND:
|
||||
errno = ENOENT;
|
||||
break;
|
||||
|
||||
case ERROR_TOO_MANY_OPEN_FILES:
|
||||
errno = EMFILE;
|
||||
break;
|
||||
|
||||
default:
|
||||
case ERROR_ACCESS_DENIED:
|
||||
case ERROR_SHARING_VIOLATION:
|
||||
case ERROR_LOCK_VIOLATION:
|
||||
case ERROR_INVALID_NAME:
|
||||
errno = EACCES;
|
||||
break;
|
||||
|
||||
case ERROR_FILE_EXISTS:
|
||||
errno = EEXIST;
|
||||
break;
|
||||
|
||||
case ERROR_INVALID_PARAMETER:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
FatalError("cannot open SCSI device '%s' - %m\n", DeviceName);
|
||||
}
|
||||
|
||||
return DeviceIndex;
|
||||
}
|
||||
|
||||
static int scsi_timeout = SCSI_DEFAULT_TIMEOUT;
|
||||
|
||||
void SCSI_Set_Timeout(int secs)
|
||||
{
|
||||
if (secs > SCSI_MAX_TIMEOUT)
|
||||
{
|
||||
secs = SCSI_MAX_TIMEOUT;
|
||||
}
|
||||
|
||||
scsi_timeout = secs;
|
||||
}
|
||||
|
||||
void SCSI_Default_Timeout(void)
|
||||
{
|
||||
scsi_timeout = SCSI_DEFAULT_TIMEOUT;
|
||||
}
|
||||
|
||||
void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD)
|
||||
{
|
||||
if (DeviceFD < nEntries)
|
||||
{
|
||||
CloseHandle(HandleTable[DeviceFD].hDevice);
|
||||
HandleTable[DeviceFD].hDevice = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EBADF;
|
||||
FatalError("cannot close SCSI device '%s' - %m\n", DeviceName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Get the SCSI ID and LUN... */
|
||||
scsi_id_t *SCSI_GetIDLun(DEVICE_TYPE fd)
|
||||
{
|
||||
scsi_id_t * retval;
|
||||
|
||||
SCSI_ADDRESS ScsiAddress;
|
||||
BOOL bResult;
|
||||
DWORD dwBytesReturned;
|
||||
|
||||
if (fd < nEntries)
|
||||
{
|
||||
retval = (scsi_id_t *)xmalloc(sizeof(scsi_id_t));
|
||||
retval->id = HandleTable[fd].TargetId;
|
||||
retval->lun = HandleTable[fd].Lun;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"SCSI:ID=%d LUN=%d\n", retval->id, retval->lun);
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EBADF;
|
||||
FatalError("cannot close SCSI device - %m\n");
|
||||
}
|
||||
|
||||
memset(&ScsiAddress, 0, sizeof(ScsiAddress));
|
||||
|
||||
ScsiAddress.Length = sizeof(ScsiAddress);
|
||||
|
||||
bResult = DeviceIoControl( HandleTable[fd].hDevice,
|
||||
IOCTL_SCSI_GET_ADDRESS,
|
||||
&ScsiAddress, sizeof(ScsiAddress),
|
||||
&ScsiAddress, sizeof(ScsiAddress),
|
||||
&dwBytesReturned,
|
||||
NULL);
|
||||
|
||||
if (!bResult)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
retval = (scsi_id_t *)xmalloc(sizeof(scsi_id_t));
|
||||
retval->id = ScsiAddress.TargetId;
|
||||
retval->lun = ScsiAddress.Lun;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"SCSI:ID=%d LUN=%d\n",retval->id,retval->lun);
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
|
||||
int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
|
||||
Direction_T Direction,
|
||||
CDB_T *CDB,
|
||||
int CDB_Length,
|
||||
void *DataBuffer,
|
||||
int DataBufferLength,
|
||||
RequestSense_T *RequestSense)
|
||||
{
|
||||
PSCSI_PASS_THROUGH ScsiPassThrough;
|
||||
|
||||
const DWORD dwDataBufferOffset = sizeof(SCSI_PASS_THROUGH) + (sizeof(RequestSense_T) + 3) / 4 * 4;
|
||||
const DWORD dwBufferSize = dwDataBufferOffset + DataBufferLength;
|
||||
|
||||
BOOL bResult;
|
||||
DWORD dwBytesReturned;
|
||||
DWORD dwInputLength;
|
||||
DWORD dwOutputLength;
|
||||
|
||||
if (DeviceFD >= nEntries || HandleTable[DeviceFD].hDevice == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ScsiPassThrough = (PSCSI_PASS_THROUGH)malloc(dwBufferSize);
|
||||
|
||||
memset(ScsiPassThrough, 0, dwDataBufferOffset);
|
||||
|
||||
ScsiPassThrough->Length = sizeof(SCSI_PASS_THROUGH);
|
||||
|
||||
ScsiPassThrough->PathId = HandleTable[DeviceFD].PathId;
|
||||
ScsiPassThrough->TargetId = HandleTable[DeviceFD].TargetId;
|
||||
ScsiPassThrough->Lun = HandleTable[DeviceFD].Lun;
|
||||
ScsiPassThrough->CdbLength = (UCHAR)CDB_Length;
|
||||
ScsiPassThrough->DataIn = Direction == Input;
|
||||
ScsiPassThrough->DataBufferOffset = dwDataBufferOffset;
|
||||
ScsiPassThrough->DataTransferLength = DataBufferLength;
|
||||
ScsiPassThrough->SenseInfoOffset = sizeof(SCSI_PASS_THROUGH);
|
||||
ScsiPassThrough->SenseInfoLength = sizeof(RequestSense_T);
|
||||
ScsiPassThrough->TimeOutValue = scsi_timeout;
|
||||
|
||||
memcpy(ScsiPassThrough->Cdb, CDB, CDB_Length);
|
||||
dwBytesReturned = 0;
|
||||
|
||||
if (Direction == Output)
|
||||
{
|
||||
memcpy((void *)(((char *)ScsiPassThrough) + dwDataBufferOffset), DataBuffer, DataBufferLength);
|
||||
dwInputLength = dwBufferSize;
|
||||
dwOutputLength = dwDataBufferOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
dwInputLength = sizeof(SCSI_PASS_THROUGH);
|
||||
dwOutputLength = dwBufferSize;
|
||||
}
|
||||
|
||||
bResult = DeviceIoControl( HandleTable[DeviceFD].hDevice,
|
||||
IOCTL_SCSI_PASS_THROUGH,
|
||||
ScsiPassThrough, dwInputLength,
|
||||
ScsiPassThrough, dwOutputLength,
|
||||
&dwBytesReturned,
|
||||
NULL);
|
||||
if (bResult)
|
||||
{
|
||||
if (ScsiPassThrough->ScsiStatus != 0)
|
||||
{
|
||||
memcpy(RequestSense, &ScsiPassThrough[1], sizeof(RequestSense_T));
|
||||
#if DEBUG
|
||||
fprintf(stderr, "Command failed - ScsiStatus = %d\n", ScsiPassThrough->ScsiStatus);
|
||||
PrintRequestSense(RequestSense);
|
||||
#endif
|
||||
bResult = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Direction == Input)
|
||||
{
|
||||
memcpy( DataBuffer,
|
||||
(void *)(((char *)ScsiPassThrough) + dwDataBufferOffset),
|
||||
DataBufferLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
DWORD dwError = GetLastError();
|
||||
LPSTR lpszMessage;
|
||||
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0, (LPSTR)&lpszMessage, 0, NULL);
|
||||
fputs(lpszMessage, stderr);
|
||||
LocalFree(lpszMessage);
|
||||
#endif
|
||||
|
||||
memset(RequestSense, 0, sizeof(RequestSense_T));
|
||||
}
|
||||
|
||||
free(ScsiPassThrough);
|
||||
|
||||
return bResult ? 0 : -1;
|
||||
}
|
||||
116
mtx-1.3.12/scsieject.1
Normal file
116
mtx-1.3.12/scsieject.1
Normal file
@@ -0,0 +1,116 @@
|
||||
.\" scsieject.1 Document Copyright 2007-2008 Robert Nelson
|
||||
.\"
|
||||
.\" This is free documentation; you can redistribute it and/or
|
||||
.\" modify it under the terms of the GNU General Public License as
|
||||
.\" published by the Free Software Foundation; either version 2 of
|
||||
.\" the License, or (at your option) any later version.
|
||||
.\"
|
||||
.\" The GNU General Public License's references to "object code"
|
||||
.\" and "executables" are to be interpreted as the output of any
|
||||
.\" document formatting or typesetting system, including
|
||||
.\" intermediate and printed output.
|
||||
.\"
|
||||
.\" This manual is distributed in the hope that it will be useful,
|
||||
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
.\" GNU General Public License for more details.
|
||||
.\"
|
||||
.\" You should have received a copy of the GNU General Public
|
||||
.\" License along with this manual; if not, write to the Free
|
||||
.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
|
||||
.\" USA.
|
||||
.\"
|
||||
.TH scsieject 1 scsieject1.0
|
||||
.SH NAME
|
||||
scsieject \- control SCSI tape devices
|
||||
.SH SYNOPSIS
|
||||
scsieject [-f <scsi-generic-device>] commands
|
||||
.SH DESCRIPTION
|
||||
The
|
||||
.B scsieject
|
||||
command controls SCSI devices in a platform-independent
|
||||
manner. As long as 'mtx' works on the platform, so does 'scsieject'.
|
||||
.SH OPTIONS
|
||||
The first argument, given following
|
||||
.B -f
|
||||
, is the SCSI generic device corresponding to your tape drive.
|
||||
Consult your operating system's documentation for more information (for
|
||||
example, under Linux these are generally /dev/sg0 through /dev/sg15,
|
||||
under FreeBSD these are /dev/pass0 through /dev/passX. Under Solaris
|
||||
this is usually the same as your tape drive (Solaris has a SCSI passthrough
|
||||
ioctl). You can set the STAPE or TAPE environment variable rather
|
||||
than use -f.
|
||||
.P
|
||||
.SH COMMANDS
|
||||
.TP 10
|
||||
.B load
|
||||
Load the medium into the drive. When this command is issued to a CD/DVD drive
|
||||
and the tray is extended the tray will be retracted if the drive is capable of it.
|
||||
|
||||
.TP 10
|
||||
.B unload
|
||||
Unload the medium from the drive (also known as eject). When this command is issued
|
||||
to a CD/DVD drive or a tape drive the media will be ejected if the device supports it.
|
||||
|
||||
.TP 10
|
||||
.B start
|
||||
Start the device. Some devices require a start command after a media changer has
|
||||
loaded new media into the device.
|
||||
|
||||
.TP 10
|
||||
.B stop
|
||||
Stop the device. Some devices require a stop command prior to unloading the medium
|
||||
from the device when using a media changer.
|
||||
|
||||
.TP 10
|
||||
.B lock
|
||||
Lock the device. Locks the device so that the medium cannot be removed manually.
|
||||
|
||||
.TP 10
|
||||
.B unlock
|
||||
Unlock the device. Unlocks the device so that the medium can be removed manually.
|
||||
|
||||
.SH AUTHORS
|
||||
This program was written by Robert Nelson <robertnelson@users.sourceforge.net>
|
||||
based on the scsitape program written by Eric Lee Green <eric@badtux.org>.
|
||||
Major portions of the 'mtxl.c' library used herein were written by
|
||||
Leonard Zubkoff.
|
||||
.P
|
||||
|
||||
.SH HINTS
|
||||
Under Linux,
|
||||
.B cat /proc/scsi/scsi
|
||||
will tell you what SCSI devices you have.
|
||||
You can then refer to them as
|
||||
.B /dev/sga,
|
||||
.B /dev/sgb,
|
||||
etc. by the order they
|
||||
are reported.
|
||||
.P
|
||||
Under FreeBSD,
|
||||
.B camcontrol devlist
|
||||
will tell you what SCSI devices you
|
||||
have, along with which
|
||||
.B pass
|
||||
device controls them.
|
||||
.P
|
||||
Under Solaris 7 and 8,
|
||||
.B /usr/sbin/devfsadm -C
|
||||
will clean up your /devices directory. Then
|
||||
.B find /devices -name 'st@*' -print
|
||||
will return a list of all tape drives. /dev on Solaris is apparently only
|
||||
of historical interest.
|
||||
|
||||
.SH BUGS AND LIMITATIONS
|
||||
There are no known bugs or limitations.
|
||||
|
||||
.SH AVAILABILITY
|
||||
This version of
|
||||
.B scsieject
|
||||
is currently being maintained by Robert Nelson <robertnelson@users.sourceforge.net>
|
||||
as part of the 'mtx' suite of programs. The 'mtx' home page is
|
||||
http://mtx.sourceforge.net and the actual code is currently available there and via
|
||||
SVN from http://sourceforge.net/projects/mtx.
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR loaderinfo (1), tapeinfo (1), mtx (1)
|
||||
255
mtx-1.3.12/scsieject.c
Normal file
255
mtx-1.3.12/scsieject.c
Normal file
@@ -0,0 +1,255 @@
|
||||
/* Copyright 2007-2008, Robert Nelson <robertn@the-nelsons.org>
|
||||
* Released under terms of the GNU General Public License as
|
||||
* required by the license on 'mtxl.c'.
|
||||
* $Date: 2007-01-28 19:23:33 -0800 (Sun, 28 Jan 2007) $
|
||||
* $Revision: 125 $
|
||||
*/
|
||||
|
||||
/* This is a generic SCSI device control program. It operates by
|
||||
* directly sending commands to the device.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Commands:
|
||||
* load -- Load medium
|
||||
* unload -- Unload medium
|
||||
* start -- Start device
|
||||
* stop -- Stop device
|
||||
* lock -- Lock medium
|
||||
* unlock -- Unlock medium
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mtx.h"
|
||||
#include "mtxl.h"
|
||||
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
char *argv0;
|
||||
|
||||
/* the device handle we're operating upon. */
|
||||
static char *device; /* the device name. */
|
||||
static DEVICE_TYPE DeviceFD = (DEVICE_TYPE) -1;
|
||||
|
||||
static int S_load(void);
|
||||
static int S_unload(void);
|
||||
static int S_start(void);
|
||||
static int S_stop(void);
|
||||
static int S_lock(void);
|
||||
static int S_unlock(void);
|
||||
|
||||
struct command_table_struct
|
||||
{
|
||||
char *name;
|
||||
int (*command)(void);
|
||||
}
|
||||
command_table[] =
|
||||
{
|
||||
{ "load", S_load },
|
||||
{ "unload", S_unload },
|
||||
{ "start", S_start },
|
||||
{ "stop", S_stop },
|
||||
{ "lock", S_lock },
|
||||
{ "unlock", S_unlock },
|
||||
{ NULL, NULL } /* terminate list */
|
||||
};
|
||||
|
||||
void Usage(void)
|
||||
{
|
||||
FatalError("Usage: scsieject -f <generic-device> <command> where <command> is:\n load | unload | start | stop | lock | unlock\n");
|
||||
}
|
||||
|
||||
/* open_device() -- set the 'DeviceFD' variable.... */
|
||||
void open_device(void)
|
||||
{
|
||||
if (DeviceFD != -1)
|
||||
{
|
||||
SCSI_CloseDevice("Unknown", DeviceFD);
|
||||
}
|
||||
|
||||
DeviceFD = SCSI_OpenDevice(device);
|
||||
}
|
||||
|
||||
/* we see if we've got a file open. If not, we open one :-(. Then
|
||||
* we execute the actual command. Or not :-(.
|
||||
*/
|
||||
int execute_command(struct command_table_struct *command)
|
||||
{
|
||||
/*
|
||||
* If the device is not already open, then open it from the
|
||||
* environment.
|
||||
*/
|
||||
if (DeviceFD == -1)
|
||||
{
|
||||
/* try to get it from STAPE or TAPE environment variable... */
|
||||
if ((device = getenv("STAPE")) == NULL &&
|
||||
(device = getenv("TAPE")) == NULL)
|
||||
{
|
||||
Usage(); /* Doesn't return */
|
||||
}
|
||||
|
||||
open_device();
|
||||
}
|
||||
|
||||
/* okay, now to execute the command... */
|
||||
return command->command();
|
||||
}
|
||||
|
||||
|
||||
/* parse_args():
|
||||
* Basically, we are parsing argv/argc. We can have multiple commands
|
||||
* on a line, such as "load start" to load a tape and start the device.
|
||||
* We execute these commands one at a time as we come to them. If we don't
|
||||
* have a -f at the start and the default device isn't defined in a TAPE or
|
||||
* STAPE environment variable, we exit.
|
||||
*/
|
||||
|
||||
int parse_args(int argc, char **argv)
|
||||
{
|
||||
int index, retval;
|
||||
struct command_table_struct *command;
|
||||
|
||||
argv0 = argv[0];
|
||||
|
||||
for (index = 1; index < argc; index++)
|
||||
{
|
||||
if (strcmp(argv[index], "-f") == 0)
|
||||
{
|
||||
index++;
|
||||
if (index >= argc)
|
||||
{
|
||||
Usage(); /* Doesn't return */
|
||||
}
|
||||
device = argv[index];
|
||||
open_device();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (command = &command_table[0]; command->name != NULL; command++)
|
||||
{
|
||||
if (strcmp(command->name, argv[index]) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (command->name == NULL)
|
||||
{
|
||||
Usage(); /* Doesn't return */
|
||||
}
|
||||
|
||||
retval = execute_command(command);
|
||||
|
||||
if (retval < 0)
|
||||
{
|
||||
/* Command failed, we probably shouldn't continue */
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int S_load(void)
|
||||
{
|
||||
int result = LoadUnload(DeviceFD, 1);
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
fputs("scsieject: load failed\n", stderr);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int S_unload(void)
|
||||
{
|
||||
int result = LoadUnload(DeviceFD, 0);
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
fputs("scsieject: unload failed\n", stderr);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int S_start(void)
|
||||
{
|
||||
int result = StartStop(DeviceFD, 1);
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
fputs("scsieject: start failed\n", stderr);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int S_stop(void)
|
||||
{
|
||||
int result = StartStop(DeviceFD, 0);
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
fputs("scsieject: stop failed\n", stderr);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int S_lock(void)
|
||||
{
|
||||
int result = LockUnlock(DeviceFD, 1);
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
fputs("scsieject: lock failed\n", stderr);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int S_unlock(void)
|
||||
{
|
||||
int result = LockUnlock(DeviceFD, 0);
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
fputs("scsieject: unlock failed\n", stderr);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* See parse_args for the scoop. parse_args does all. */
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
parse_args(argc, argv);
|
||||
|
||||
if (device)
|
||||
{
|
||||
SCSI_CloseDevice(device, DeviceFD);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
179
mtx-1.3.12/scsitape.1
Normal file
179
mtx-1.3.12/scsitape.1
Normal file
@@ -0,0 +1,179 @@
|
||||
.\" scsitape.1 Document Copyright 2001 Eric Lee Green
|
||||
.\" Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
|
||||
.\"
|
||||
.\" This is free documentation; you can redistribute it and/or
|
||||
.\" modify it under the terms of the GNU General Public License as
|
||||
.\" published by the Free Software Foundation; either version 2 of
|
||||
.\" the License, or (at your option) any later version.
|
||||
.\"
|
||||
.\" The GNU General Public License's references to "object code"
|
||||
.\" and "executables" are to be interpreted as the output of any
|
||||
.\" document formatting or typesetting system, including
|
||||
.\" intermediate and printed output.
|
||||
.\"
|
||||
.\" This manual is distributed in the hope that it will be useful,
|
||||
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
.\" GNU General Public License for more details.
|
||||
.\"
|
||||
.\" You should have received a copy of the GNU General Public
|
||||
.\" License along with this manual; if not, write to the Free
|
||||
.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
|
||||
.\" USA.
|
||||
.\"
|
||||
.TH SCSITAPE 1 SCSITAPE1.0
|
||||
.SH NAME
|
||||
scsitape \- control SCSI tape devices
|
||||
.SH SYNOPSIS
|
||||
scsitape [-f <scsi-generic-device>] commands
|
||||
.SH DESCRIPTION
|
||||
The
|
||||
.B scsitape
|
||||
command controls SCSI tape drives in a platform-independent
|
||||
manner. As long as 'mtx' works on the platform, so does 'scsitape'.
|
||||
.P
|
||||
Note that 'scsitape' and your OS's native tape driver may stomp on each
|
||||
other. In particular, if you use 'setblk' and your OS's native tape
|
||||
driver has a different notion of the block size, you may get evil results.
|
||||
It is recommended to use 'scsitape' only for software where you've written
|
||||
your own low-level READ and WRITE routines that use the SCSI command set
|
||||
to directly talk to tape drives (i.e., you do not use the OS's native tape
|
||||
driver at all).
|
||||
.SH OPTIONS
|
||||
The first argument, given following
|
||||
.B -f
|
||||
, is the SCSI generic device corresponding to your tape drive.
|
||||
Consult your operating system's documentation for more information (for
|
||||
example, under Linux these are generally /dev/sg0 through /dev/sg15,
|
||||
under FreeBSD these are /dev/pass0 through /dev/passX. Under Solaris
|
||||
this is usually the same as your tape drive (Solaris has a SCSI passthrough
|
||||
ioctl). You can set the STAPE or TAPE environment variable rather
|
||||
than use -f.
|
||||
.P
|
||||
.SH COMMANDS
|
||||
.TP 10
|
||||
.B setblk <n>
|
||||
Set the tape drive's SCSI block size to <n> bytes. (NOTE: if you are
|
||||
using your OS's native tape driver, THIS IS EVIL!).
|
||||
|
||||
.TP 10
|
||||
.B fsf <n>
|
||||
Go forward by <n> tapemarks.
|
||||
.TP 10
|
||||
.B bsf <n>
|
||||
Go to immediately previous the <n>th previous tapemark. (WARNING: This
|
||||
probably doesn't do what you expect -- e.g. if you are immediately
|
||||
after a tapemark and type 'bfs 1', it moves to immediately *before*
|
||||
that tape mark, for a sum total of zero effective movement!).
|
||||
.TP 10
|
||||
.B eod
|
||||
Go to end of data.
|
||||
.TP 10
|
||||
.B rewind
|
||||
Rewind the tape drive.
|
||||
.TP 10
|
||||
.B eject
|
||||
Eject the tape currently in the drive.
|
||||
.TP 10
|
||||
.B erase
|
||||
Does a *short* erase (warning: does NOT work on all drives!).
|
||||
.TP 10
|
||||
.B mark <n>
|
||||
write <n> filemarks ( 'mark 0' flushes the drive's buffers ).
|
||||
.TP 10
|
||||
.B seek <n>
|
||||
Seek to a logical position <n> that was reported by a previous 'tapeinfo'
|
||||
command.
|
||||
.TP 10
|
||||
.B write <blocksize>
|
||||
write blocks from stdin to the tape. Chunk the data into <blocksize>-sized
|
||||
chunks. *DOES NOT WRITE OUT A TAPEMARK!* (you will need to use a
|
||||
subsequent
|
||||
.B mark 1
|
||||
command to write out a tape mark).
|
||||
.TP 10
|
||||
.B read [<blocksize>] [ <#blocks/#bytes> ]
|
||||
read blocks from the tape, write them to stdout. If we are in variable
|
||||
block mode, <blocksize> should be zero (note: The maximum block size
|
||||
we currently support in variable block mode is 128K, MAX_READ_SIZE will
|
||||
need to be turned into a settable variable to allow bigger reads). If
|
||||
<blocksize> is ommitted, we assume that we're in variable block mode, and
|
||||
that we are going to read from tape until we hit a tapemark or end of
|
||||
partition or end of tape.
|
||||
|
||||
|
||||
.SH AUTHORS
|
||||
This program was written by Eric Lee Green <eric@badtux.org>.
|
||||
Major portions of the 'mtxl.c' library used herein were written by
|
||||
Leonard Zubkoff.
|
||||
.P
|
||||
|
||||
The SCSI read and write routines are based upon those that Richard
|
||||
Fish wrote for Enhanced Software Technology's BRU 16.1 product,
|
||||
substantially modified to work in our particular environment (in
|
||||
particular, all the variable block stuff is new since BRU only does
|
||||
fixed block reads and writes, and the BRU code uses bitmasks rather
|
||||
than bitfields for the various flags and such in return values, as
|
||||
well as the BRU code having a different SCSI API and having variable
|
||||
names considerably shorter than the rather sesquipedalian 'mtx'
|
||||
identifiers). As required by 'mtxl.c', these routines are licensed
|
||||
under the GNU General Public License.
|
||||
|
||||
.SH HINTS
|
||||
Under Linux,
|
||||
.B cat /proc/scsi/scsi
|
||||
will tell you what SCSI devices you have.
|
||||
You can then refer to them as
|
||||
.B /dev/sga,
|
||||
.B /dev/sgb,
|
||||
etc. by the order they
|
||||
are reported.
|
||||
.P
|
||||
Under FreeBSD,
|
||||
.B camcontrol devlist
|
||||
will tell you what SCSI devices you
|
||||
have, along with which
|
||||
.B pass
|
||||
device controls them.
|
||||
.P
|
||||
Under Solaris 7 and 8,
|
||||
.B /usr/sbin/devfsadm -C
|
||||
will clean up your /devices directory. Then
|
||||
.B find /devices -name 'st@*' -print
|
||||
will return a list of all tape drives. /dev on Solaris is apparently only
|
||||
of historical interest.
|
||||
|
||||
.SH BUGS AND LIMITATIONS
|
||||
|
||||
for
|
||||
.B scsitape read 0 <n>
|
||||
where you are doing variable-block-size reads and wish for <n> bytes,
|
||||
it instead reads one and exactly one block from tape and prints that
|
||||
(no matter what its size). Use 'dd' on the output of scsitape if you
|
||||
want finer control.
|
||||
.P
|
||||
.B scsitape read 0
|
||||
attempts reads of MAX_READ_SIZE, which is currently 128K. If blocks on tape
|
||||
are larger than 128K, only the first 128K will be read -- the remainder
|
||||
will be silently dumped in the toilet.
|
||||
.P
|
||||
This program does not interact well (or at all :-) with your OS's
|
||||
native tape driver. You will likely see weird things happen if you
|
||||
attempt to intermingle scsitape commands with native tape driver
|
||||
operations. Note that BRU 16.1 for Solaris (and possibly others, but
|
||||
Solaris I know about) will have a 'scsi' keyword to bypass the
|
||||
native tape driver and write via direct uscsi commands, so if you use
|
||||
\'scsitape\' to bypass the flaws of the native Solaris driver, you can use
|
||||
BRU 16.1 to write your actual tape archives. (Assuming that BRU 16.1
|
||||
has been released at the time that you read this).
|
||||
|
||||
.SH AVAILABILITY
|
||||
This version of
|
||||
.B scsitape
|
||||
is currently being maintained by Robert Nelson <robertnelson@users.sourceforge.net>
|
||||
as part of the 'mtx' suite of programs. The 'mtx' home page is
|
||||
http://mtx.sourceforge.net and the actual code is currently available there and via
|
||||
SVN from http://sourceforge.net/projects/mtx.
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR loaderinfo (1), tapeinfo (1), mtx (1)
|
||||
941
mtx-1.3.12/scsitape.c
Normal file
941
mtx-1.3.12/scsitape.c
Normal file
@@ -0,0 +1,941 @@
|
||||
/* Copyright 2001 Enhanced Software Technologies Inc.
|
||||
* Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
|
||||
* Released under terms of the GNU General Public License as
|
||||
* required by the license on 'mtxl.c'.
|
||||
* $Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $
|
||||
* $Revision: 193 $
|
||||
*/
|
||||
|
||||
/* This is a generic SCSI tape control program. It operates by
|
||||
* directly sending commands to the tape drive. If you are going
|
||||
* through your operating system's SCSI tape driver, do *NOT* use
|
||||
* this program! If, on the other hand, you are using raw READ and WRITE
|
||||
* commands through your operating system's generic SCSI interface (or
|
||||
* through our built-in 'read' and 'write'), this is the place for you.
|
||||
*/
|
||||
|
||||
/*#define DEBUG_PARTITION */
|
||||
/*#define DEBUG 1 */
|
||||
|
||||
/*
|
||||
Commands:
|
||||
setblk <n> -- set the block size to <n>
|
||||
fsf <n> -- go forward by <n> filemarks
|
||||
bsf <n> -- go backward by <n> filemarks
|
||||
eod -- go to end of data
|
||||
rewind -- rewind back to start of data
|
||||
eject -- rewind, then eject the tape.
|
||||
erase -- (short) erase the tape (we have no long erase)
|
||||
mark <n> -- write <n> filemarks.
|
||||
seek <n> -- seek to position <n>.
|
||||
|
||||
write <blksize> <-- write blocks from stdin to the tape
|
||||
read [<blksize>] [<#blocks/#bytes>] -- read blocks from tape, write to stdout.
|
||||
|
||||
See the 'tapeinfo' program for status info about the tape drive.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mtx.h"
|
||||
#include "mtxl.h"
|
||||
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_SYS_MTIO_H
|
||||
#include <sys/mtio.h> /* will try issuing some ioctls for Solaris, sigh. */
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
void Usage(void) {
|
||||
FatalError("Usage: scsitape -f <generic-device> <command> where <command> is:\n setblk <n> | fsf <n> | bsf <n> | eod | rewind | eject | mark <n> |\n seek <n> | read [<blksize> [<numblocks]] | write [<blocksize>] \n");
|
||||
}
|
||||
|
||||
#define arg1 (arg[0]) /* for backward compatibility, sigh */
|
||||
static int arg[4]; /* the argument for the command, sigh. */
|
||||
|
||||
/* the device handle we're operating upon, sigh. */
|
||||
static char *device; /* the text of the device thingy. */
|
||||
static DEVICE_TYPE MediumChangerFD = (DEVICE_TYPE) -1;
|
||||
|
||||
|
||||
|
||||
static int S_setblk(void);
|
||||
static int S_fsf(void);
|
||||
static int S_bsf(void);
|
||||
static int S_eod(void);
|
||||
static int S_rewind(void);
|
||||
static int S_eject(void);
|
||||
static int S_mark(void);
|
||||
static int S_seek(void);
|
||||
static int S_reten(void);
|
||||
static int S_erase(void);
|
||||
|
||||
static int S_read(void);
|
||||
static int S_write(void);
|
||||
|
||||
|
||||
struct command_table_struct {
|
||||
int num_args;
|
||||
char *name;
|
||||
int (*command)(void);
|
||||
} command_table[] = {
|
||||
{ 1, "setblk", S_setblk },
|
||||
{ 1, "fsf", S_fsf },
|
||||
{ 1, "bsf", S_bsf },
|
||||
{ 0, "eod", S_eod },
|
||||
{ 0, "rewind", S_rewind },
|
||||
{ 0, "eject", S_eject },
|
||||
{ 0, "reten", S_reten },
|
||||
{ 0, "erase", S_erase },
|
||||
{ 1, "mark", S_mark },
|
||||
{ 1, "seek", S_seek },
|
||||
{ 2, "read", S_read },
|
||||
{ 2, "write",S_write },
|
||||
{ 0, NULL, NULL } /* terminate list */
|
||||
};
|
||||
|
||||
char *argv0;
|
||||
|
||||
|
||||
/* open_device() -- set the 'fh' variable.... */
|
||||
void open_device(void)
|
||||
{
|
||||
if (MediumChangerFD != -1)
|
||||
{
|
||||
SCSI_CloseDevice("Unknown",MediumChangerFD); /* close it, sigh... new device now! */
|
||||
}
|
||||
|
||||
MediumChangerFD = SCSI_OpenDevice(device);
|
||||
}
|
||||
|
||||
static int get_arg(char *arg)
|
||||
{
|
||||
int retval=-1;
|
||||
|
||||
if (*arg < '0' || *arg > '9')
|
||||
{
|
||||
return -1; /* sorry! */
|
||||
}
|
||||
|
||||
retval=atoi(arg);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/* we see if we've got a file open. If not, we open one :-(. Then
|
||||
* we execute the actual command. Or not :-(.
|
||||
*/
|
||||
int execute_command(struct command_table_struct *command)
|
||||
{
|
||||
/* if the device is not already open, then open it from the
|
||||
* environment.
|
||||
*/
|
||||
if (!MediumChangerFD == -1)
|
||||
{
|
||||
/* try to get it from STAPE or TAPE environment variable... */
|
||||
device = getenv("STAPE");
|
||||
if (device == NULL)
|
||||
{
|
||||
device = getenv("TAPE");
|
||||
if (device == NULL)
|
||||
{
|
||||
Usage();
|
||||
}
|
||||
}
|
||||
open_device();
|
||||
}
|
||||
|
||||
/* okay, now to execute the command... */
|
||||
return command->command();
|
||||
}
|
||||
|
||||
|
||||
/* parse_args():
|
||||
* Basically, we are parsing argv/argc. We can have multiple commands
|
||||
* on a line now, such as "unload 3 0 load 4 0" to unload one tape and
|
||||
* load in another tape into drive 0, and we execute these commands one
|
||||
* at a time as we come to them. If we don't have a -f at the start, we
|
||||
* barf. If we leave out a drive #, we default to drive 0 (the first drive
|
||||
* in the cabinet).
|
||||
*/
|
||||
|
||||
int parse_args(int argc, char **argv)
|
||||
{
|
||||
int i, cmd_tbl_idx,retval,arg_idx;
|
||||
struct command_table_struct *command;
|
||||
|
||||
i=1;
|
||||
arg_idx = 0;
|
||||
while (i < argc)
|
||||
{
|
||||
if (strcmp(argv[i],"-f") == 0)
|
||||
{
|
||||
i++;
|
||||
if (i >= argc)
|
||||
{
|
||||
Usage();
|
||||
}
|
||||
device = argv[i++];
|
||||
open_device(); /* open the device and do a status scan on it... */
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd_tbl_idx=0;
|
||||
command = &command_table[0]; /* default to the first command... */
|
||||
command = &command_table[cmd_tbl_idx];
|
||||
while (command->name)
|
||||
{
|
||||
if (strcmp(command->name,argv[i]) == 0)
|
||||
{
|
||||
/* we have a match... */
|
||||
break;
|
||||
}
|
||||
/* otherwise we don't have a match... */
|
||||
cmd_tbl_idx++;
|
||||
command = &command_table[cmd_tbl_idx];
|
||||
}
|
||||
/* if it's not a command, exit.... */
|
||||
if (command->name == NULL)
|
||||
{
|
||||
Usage();
|
||||
}
|
||||
i++; /* go to the next argument, if possible... */
|
||||
/* see if we need to gather arguments, though! */
|
||||
arg1 = -1; /* default it to something */
|
||||
for (arg_idx=0;arg_idx < command->num_args ; arg_idx++)
|
||||
{
|
||||
if (i < argc)
|
||||
{
|
||||
arg[arg_idx] = get_arg(argv[i]);
|
||||
if (arg[arg_idx] != -1)
|
||||
{
|
||||
i++; /* increment i over the next cmd. */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
arg[arg_idx] = 0; /* default to 0 setmarks or whatever */
|
||||
}
|
||||
}
|
||||
retval=execute_command(command); /* execute_command handles 'stuff' */
|
||||
exit(retval);
|
||||
}
|
||||
}
|
||||
return 0; /* should never get here */
|
||||
}
|
||||
|
||||
/* For Linux, this allows us to do a short erase on a tape (sigh!).
|
||||
* Note that you'll need to do a 'mt status' on the tape afterwards in
|
||||
* order to get the tape driver in sync with the tape drive again. Also
|
||||
* note that on other OS's, this might do other evil things to the tape
|
||||
* driver. Note that to do an erase, you must first rewind!
|
||||
|
||||
*/
|
||||
static int S_erase(void)
|
||||
{
|
||||
int retval;
|
||||
RequestSense_T *RequestSense;
|
||||
|
||||
retval=S_rewind();
|
||||
if (retval)
|
||||
{
|
||||
return retval; /* we have an exit status :-(. */
|
||||
}
|
||||
|
||||
RequestSense=Erase(MediumChangerFD);
|
||||
if (RequestSense)
|
||||
{
|
||||
PrintRequestSense(RequestSense);
|
||||
exit(1); /* exit with an error status. */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This should eject a tape or magazine, depending upon the device sent
|
||||
* to.
|
||||
*/
|
||||
static int S_eject(void)
|
||||
{
|
||||
int i;
|
||||
i = LoadUnload(MediumChangerFD, 0);
|
||||
if ( i < 0)
|
||||
{
|
||||
fprintf(stderr,"scsitape:eject failed\n");
|
||||
fflush(stderr);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* We write a filemarks of 0 before going to grab position, in order
|
||||
* to insure that data in the buffer is not a problem.
|
||||
*/
|
||||
|
||||
static int S_mark(void)
|
||||
{
|
||||
RequestSense_T RequestSense; /* for result of ReadElementStatus */
|
||||
CDB_T CDB;
|
||||
unsigned char buffer[6];
|
||||
int count = arg1; /* voila! */
|
||||
|
||||
CDB[0] = 0x10; /* SET_MARK */
|
||||
CDB[1] = 0;
|
||||
CDB[2] = (unsigned char)(count >> 16);
|
||||
CDB[3] = (unsigned char)(count >> 8);
|
||||
CDB[4] = (unsigned char)count;
|
||||
CDB[5] = 0;
|
||||
|
||||
/* we really don't care if this command works or not, sigh. */
|
||||
slow_bzero((char *)&RequestSense, sizeof(RequestSense_T));
|
||||
|
||||
if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 6, buffer, 0, &RequestSense)!= 0)
|
||||
{
|
||||
PrintRequestSense(&RequestSense);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* let's rewind to bod!
|
||||
*/
|
||||
|
||||
static int S_rewind(void)
|
||||
{
|
||||
RequestSense_T sense;
|
||||
CDB_T CDB;
|
||||
unsigned char buffer[6];
|
||||
|
||||
CDB[0] = 0x01; /* REWIND */
|
||||
CDB[1] = 0;
|
||||
CDB[2] = 0;
|
||||
CDB[3] = 0;
|
||||
CDB[4] = 0;
|
||||
CDB[5] = 0;
|
||||
|
||||
/* we really don't care if this command works or not, sigh. */
|
||||
slow_bzero((char *)&sense,sizeof(RequestSense_T));
|
||||
if (SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,6,buffer,0,&sense)!=0)
|
||||
{
|
||||
PrintRequestSense(&sense);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* This is used for fsf and bsf. */
|
||||
static int Space(int count, char code)
|
||||
{
|
||||
RequestSense_T sense;
|
||||
CDB_T CDB;
|
||||
unsigned char buffer[6];
|
||||
|
||||
CDB[0] = 0x11; /* SET_MARK */
|
||||
CDB[1] = code;
|
||||
CDB[2] = (unsigned char)(count >> 16);
|
||||
CDB[3] = (unsigned char)(count >> 8);
|
||||
CDB[4] = (unsigned char)count;
|
||||
CDB[5] = 0;
|
||||
|
||||
/* we really don't care if this command works or not, sigh. */
|
||||
slow_bzero((char *)&sense,sizeof(RequestSense_T));
|
||||
if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 6, buffer, 0, &sense) != 0)
|
||||
{
|
||||
PrintRequestSense(&sense);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Let's try a fsf: */
|
||||
/* We write a filemarks of 0 before going to grab position, in order
|
||||
* to insure that data in the buffer is not a problem.
|
||||
*/
|
||||
|
||||
static int S_fsf(void)
|
||||
{
|
||||
return Space(arg1,1); /* go forward! */
|
||||
}
|
||||
|
||||
static int S_bsf(void)
|
||||
{
|
||||
return Space(-arg1,1); /* go backward! */
|
||||
}
|
||||
|
||||
static int S_eod(void)
|
||||
{
|
||||
return Space(0,3); /* go to eod! */
|
||||
}
|
||||
|
||||
/* sigh, abuse of the LOAD command...
|
||||
|
||||
*/
|
||||
static int S_reten(void)
|
||||
{
|
||||
RequestSense_T sense;
|
||||
CDB_T CDB;
|
||||
unsigned char buffer[6];
|
||||
|
||||
CDB[0] = 0x1B; /* START_STOP */
|
||||
CDB[1] = 0; /* wait */
|
||||
CDB[2] = 0;
|
||||
CDB[3] = 0;
|
||||
CDB[4] = 3; /* reten. */
|
||||
CDB[5] = 0;
|
||||
|
||||
/* we really don't care if this command works or not, sigh. */
|
||||
slow_bzero((char *)&sense, sizeof(RequestSense_T));
|
||||
if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 6, buffer, 0, &sense) != 0)
|
||||
{
|
||||
PrintRequestSense(&sense);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* seek a position on the tape (sigh!) */
|
||||
static int S_seek(void)
|
||||
{
|
||||
RequestSense_T sense;
|
||||
CDB_T CDB;
|
||||
unsigned char buffer[6];
|
||||
int count = arg1;
|
||||
|
||||
/* printf("count=%d\n",arg1); */
|
||||
|
||||
CDB[0] = 0x2B; /* LOCATE */
|
||||
CDB[1] = 0; /* Logical */
|
||||
CDB[2] = 0; /* padding */
|
||||
CDB[3] = (unsigned char)(count >> 24);
|
||||
CDB[4] = (unsigned char)(count >> 16);
|
||||
CDB[5] = (unsigned char)(count >> 8);
|
||||
CDB[6] = (unsigned char)count;
|
||||
CDB[7] = 0;
|
||||
CDB[8] = 0;
|
||||
CDB[9] = 0;
|
||||
|
||||
/* we really don't care if this command works or not, sigh. */
|
||||
slow_bzero((char *)&sense,sizeof(RequestSense_T));
|
||||
if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 10, buffer, 0, &sense) != 0)
|
||||
{
|
||||
PrintRequestSense(&sense);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef MTSRSZ
|
||||
static int Solaris_setblk(int fh,int count)
|
||||
{
|
||||
/* we get here only if we have a MTSRSZ, which means Solaris. */
|
||||
struct mtop mt_com; /* the struct used for the MTIOCTOP ioctl */
|
||||
int result;
|
||||
|
||||
/* okay, we have fh and count.... */
|
||||
|
||||
/* Now to try the ioctl: */
|
||||
mt_com.mt_op=MTSRSZ;
|
||||
mt_com.mt_count=count;
|
||||
|
||||
/* surround the actual ioctl to enable threading, since fsf/etc. can be
|
||||
* big time consumers and we want other threads to be able to run too.
|
||||
*/
|
||||
|
||||
result=ioctl(fh, MTIOCTOP, (char *)&mt_com);
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
return errno;
|
||||
}
|
||||
|
||||
/* okay, we did okay. Return a value of None... */
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* okay, this is a write: we need to set the block size to something: */
|
||||
static int S_setblk(void)
|
||||
{
|
||||
RequestSense_T sense;
|
||||
CDB_T CDB;
|
||||
char buffer[12];
|
||||
unsigned int count = (unsigned int) arg1;
|
||||
|
||||
CDB[0] = 0x15; /* MODE SELECT */
|
||||
CDB[1] = 0x10; /* scsi2 */
|
||||
CDB[2] = 0;
|
||||
CDB[3] = 0;
|
||||
CDB[4] = 12; /* length of data */
|
||||
CDB[5] = 0;
|
||||
|
||||
slow_bzero((char *)&sense, sizeof(RequestSense_T));
|
||||
slow_bzero(buffer, 12);
|
||||
|
||||
/* Now to set the mode page header: */
|
||||
buffer[0] = 0;
|
||||
buffer[1] = 0;
|
||||
buffer[2] = 0x10; /* we are in buffered mode now, people! */
|
||||
buffer[3] = 8; /* block descriptor length. */
|
||||
buffer[4] = 0; /* reset to default density, sigh. */ /* 0 */
|
||||
buffer[5] = 0; /* 1 */
|
||||
buffer[6] = 0; /* 2 */
|
||||
buffer[7] = 0; /* 3 */
|
||||
buffer[8] = 0; /* 4 */
|
||||
buffer[9] = (unsigned char)(count >> 16); /* 5 */
|
||||
buffer[10] = (unsigned char)(count >> 8); /* 6 */
|
||||
buffer[11] = (unsigned char)count; /* 7 */
|
||||
|
||||
if (SCSI_ExecuteCommand(MediumChangerFD,Output,&CDB,6,buffer,12,&sense)!=0)
|
||||
{
|
||||
PrintRequestSense(&sense);
|
||||
return 1;
|
||||
}
|
||||
#ifdef MTSRSZ
|
||||
/* Solaris_setblk(MediumChangerFD,count); */
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
/* SCSI read/write calls. These are mostly pulled out of BRU 16.1,
|
||||
* modified to work within the mtxl.h framework rather than the
|
||||
* scsi_lowlevel.h framework.
|
||||
*************************************************************************/
|
||||
|
||||
#define MAX_READ_SIZE 128*1024 /* max size of a variable-block read */
|
||||
|
||||
#define READ_OK 0
|
||||
#define READ_FILEMARK 1
|
||||
#define READ_EOD 2
|
||||
#define READ_EOP 3
|
||||
#define READ_SHORT 5
|
||||
#define READ_ERROR 255
|
||||
|
||||
#define WRITE_OK 0
|
||||
#define WRITE_ERROR 1
|
||||
#define WRITE_EOM 2
|
||||
#define WRITE_EOV 3
|
||||
|
||||
|
||||
/* These are copied out of BRU 16.1, with all the boolean masks changed
|
||||
* to our bitmasks.
|
||||
*/
|
||||
#define S_NO_SENSE(s) ((s).SenseKey == 0x0)
|
||||
#define S_RECOVERED_ERROR(s) ((s).SenseKey == 0x1)
|
||||
|
||||
#define S_NOT_READY(s) ((s).SenseKey == 0x2)
|
||||
#define S_MEDIUM_ERROR(s) ((s).SenseKey == 0x3)
|
||||
#define S_HARDWARE_ERROR(s) ((s).SenseKey == 0x4)
|
||||
#define S_UNIT_ATTENTION(s) ((s).SenseKey == 0x6)
|
||||
#define S_BLANK_CHECK(s) ((s).SenseKey == 0x8)
|
||||
#define S_VOLUME_OVERFLOW(s) ((s).SenseKey == 0xd)
|
||||
|
||||
#define DEFAULT_TIMEOUT 3*60 /* 3 minutes here */
|
||||
|
||||
#define HIT_FILEMARK(s) (S_NO_SENSE((s)) && (s).Filemark && (s).Valid)
|
||||
/* Sigh, the T-10 SSC spec says all of the following is needed to
|
||||
* detect a short read while in variable block mode. We'll see.
|
||||
*/
|
||||
#define SHORT_READ(s) (S_NO_SENSE((s)) && (s).ILI && (s).Valid && (s).AdditionalSenseCode==0 && (s).AdditionalSenseCodeQualifier==0)
|
||||
|
||||
#define HIT_EOD(s) (S_BLANK_CHECK((s)) && (s).Valid)
|
||||
#define HIT_EOP(s) (S_MEDIUM_ERROR((s)) && (s).EOM && (s).Valid)
|
||||
#define HIT_EOM(s) ((s).EOM && (s).Valid)
|
||||
#define BECOMING_READY(s) (S_UNIT_ATTENTION((s)) && (s).AdditionalSenseCode == 0x28 && (s).AdditionalSenseCodeQualifier == 0)
|
||||
|
||||
/* Reading is a problem. We can hit a filemark, hit an EOD, or hit an
|
||||
* EOP. Our caller may do something about that. Note that we assume that
|
||||
* our caller has already put us into fixed block mode. If he has not, then
|
||||
* we are in trouble anyhow.
|
||||
*/
|
||||
int SCSI_readt(DEVICE_TYPE fd, char * buf, unsigned int bufsize, unsigned int *len, unsigned int timeout) {
|
||||
int rtnval;
|
||||
CDB_T cmd;
|
||||
|
||||
int blockCount;
|
||||
int info;
|
||||
|
||||
RequestSense_T RequestSense;
|
||||
|
||||
if (bufsize==0)
|
||||
{
|
||||
/* we are in variable block mode */
|
||||
blockCount=MAX_READ_SIZE; /* variable block size. */
|
||||
}
|
||||
else
|
||||
{
|
||||
blockCount= *len / bufsize;
|
||||
if ((*len % bufsize) != 0)
|
||||
{
|
||||
fprintf(stderr,"Error: Data (%d bytes) not even multiple of block size (%d bytes).\n",*len,bufsize);
|
||||
exit(1); /* we're finished, sigh. */
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout == 0)
|
||||
{
|
||||
timeout = 1 * 60; /* 1 minutes */
|
||||
}
|
||||
|
||||
memset(&cmd, 0, sizeof(CDB_T));
|
||||
cmd[0] = 0x08; /* READ */
|
||||
cmd[1] = (bufsize) ? 1 : 0; /* fixed length or var length blocks */
|
||||
cmd[2] = (unsigned char)(blockCount >> 16); /* MSB */
|
||||
cmd[3] = (unsigned char)(blockCount >> 8);
|
||||
cmd[4] = (unsigned char)blockCount; /* LSB */
|
||||
|
||||
/* okay, let's read, look @ the result code: */
|
||||
rtnval=READ_OK;
|
||||
if (SCSI_ExecuteCommand(fd,Input,&cmd,6,buf,(bufsize) ? *len : MAX_READ_SIZE,&RequestSense))
|
||||
{
|
||||
rtnval=READ_ERROR;
|
||||
if (HIT_EOP(RequestSense))
|
||||
{
|
||||
cmd[0]=0x08;
|
||||
rtnval=READ_EOP;
|
||||
}
|
||||
|
||||
if (HIT_FILEMARK(RequestSense))
|
||||
{
|
||||
rtnval=READ_FILEMARK;
|
||||
}
|
||||
|
||||
if (HIT_EOD(RequestSense))
|
||||
{
|
||||
rtnval=READ_EOD;
|
||||
}
|
||||
|
||||
if ( (bufsize==0) && SHORT_READ(RequestSense))
|
||||
{
|
||||
rtnval=READ_SHORT; /* we only do short reads for variable block mode */
|
||||
}
|
||||
|
||||
if (rtnval != READ_ERROR)
|
||||
{
|
||||
/* info contains number of blocks or bytes *not* read. May be
|
||||
negative if the block we were trying to read was too big. So
|
||||
we will have to account for that and set it to zero if so, so that
|
||||
we return the proper # of blocks read.
|
||||
*/
|
||||
info = ((RequestSense.Information[0] << 24) +
|
||||
(RequestSense.Information[1] << 16) +
|
||||
(RequestSense.Information[2] << 8) +
|
||||
RequestSense.Information[3]);
|
||||
|
||||
/* on 64-bit platforms, we may need to turn 'info' into a negative # */
|
||||
if (info > 0x7fffffff)
|
||||
info = 0;
|
||||
|
||||
if (info < 0)
|
||||
info=0; /* make sure we don't return too big len read. */
|
||||
|
||||
/* Now set *len to # of bytes read. */
|
||||
*len= bufsize ? (blockCount-info) * bufsize : MAX_READ_SIZE-info ;
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintRequestSense(&RequestSense);
|
||||
exit(1); /* foo. */
|
||||
}
|
||||
}
|
||||
|
||||
return rtnval;
|
||||
}
|
||||
|
||||
/* Low level SCSI write. Modified from BRU 16.1, with much BRU smarts
|
||||
* taken out and with the various types changed to mtx types rather than
|
||||
* BRU types.
|
||||
*/
|
||||
int SCSI_write(DEVICE_TYPE fd, char * buf, unsigned int blocksize,
|
||||
unsigned int *len)
|
||||
{
|
||||
CDB_T cmd;
|
||||
|
||||
int blockCount;
|
||||
int rtnval=0;
|
||||
RequestSense_T RequestSense;
|
||||
|
||||
if (blocksize == 0)
|
||||
{
|
||||
/* we are in variable block mode */
|
||||
blockCount = *len; /* variable block size. */
|
||||
}
|
||||
else
|
||||
{
|
||||
blockCount= *len / blocksize ;
|
||||
if ((*len % blocksize) != 0)
|
||||
{
|
||||
fprintf(stderr,"Error: Data (%d bytes) not even multiple of block size (%d bytes).\n",*len,blocksize);
|
||||
exit(1); /* we're finished, sigh. */
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr,"Writing %d blocks\n",blockCount);
|
||||
|
||||
memset(&cmd, 0, sizeof(CDB_T));
|
||||
cmd[0] = 0x0a; /* WRITE */
|
||||
cmd[1] = (blocksize) ? 1 : 0; /* fixed length or var length blocks */
|
||||
cmd[2] = (unsigned char)(blockCount >> 16); /* MSB */
|
||||
cmd[3] = (unsigned char)(blockCount >> 8);
|
||||
cmd[4] = (unsigned char)blockCount; /* LSB */
|
||||
|
||||
|
||||
if (SCSI_ExecuteCommand(fd,Output,&cmd,6,buf, *len, &RequestSense))
|
||||
{
|
||||
if (HIT_EOM(RequestSense))
|
||||
{
|
||||
/* we hit end of media. Return -1. */
|
||||
if (S_VOLUME_OVERFLOW(RequestSense))
|
||||
{
|
||||
exit(WRITE_EOV);
|
||||
}
|
||||
exit(WRITE_EOM); /* end of media! */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* it was plain old write error: */
|
||||
PrintRequestSense(&RequestSense);
|
||||
exit(WRITE_ERROR);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rtnval = *len; /* worked! */
|
||||
}
|
||||
return rtnval;
|
||||
}
|
||||
|
||||
/* S_write is not implemented yet! */
|
||||
static int S_write(void)
|
||||
{
|
||||
char *buffer; /* the buffer we're gonna read/write out of. */
|
||||
int buffersize;
|
||||
int len; /* the length of the data in the buffer */
|
||||
int blocksize = arg[0];
|
||||
int numblocks = arg[1];
|
||||
int varsize=0; /* variable size block flag */
|
||||
int result;
|
||||
int eof_input;
|
||||
int infile=fileno(stdin); /* sigh */
|
||||
|
||||
if (blocksize == 0)
|
||||
{
|
||||
varsize = 1;
|
||||
buffersize = MAX_READ_SIZE;
|
||||
len = MAX_READ_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
varsize = 0; /* fixed block mode */
|
||||
buffersize = blocksize;
|
||||
len = blocksize;
|
||||
}
|
||||
|
||||
/* sigh, make it oversized just to have some */
|
||||
buffer = malloc(buffersize+8);
|
||||
|
||||
eof_input = 0;
|
||||
while (!eof_input)
|
||||
{
|
||||
/* size_t could be 64 bit on a 32 bit platform, so do casts. */
|
||||
len=0;
|
||||
/* If it is a pipe, we could read 4096 bytes rather than the full
|
||||
* 128K bytes or whatever, so we must gather multiple reads into
|
||||
* the buffer.
|
||||
*/
|
||||
while (len < buffersize)
|
||||
{
|
||||
result=(int)read(infile, buffer + len, (size_t)(buffersize - len));
|
||||
if (!result)
|
||||
{
|
||||
eof_input = 1;
|
||||
if (!len)
|
||||
{
|
||||
/* if we have no deata in our buffer, exit */
|
||||
return 0; /* we're at end of file! */
|
||||
}
|
||||
break; /* otherwise, break and write the data */
|
||||
}
|
||||
len += result; /* add the result input to our length. */
|
||||
}
|
||||
|
||||
result = SCSI_write(MediumChangerFD, buffer, blocksize, (unsigned int *)&len);
|
||||
if (!result)
|
||||
{
|
||||
return 1; /* at end of tape! */
|
||||
}
|
||||
|
||||
/* Now see if we have numbytes or numblocks. If so, we may wish to exit
|
||||
this loop.
|
||||
*/
|
||||
if (arg[1])
|
||||
{
|
||||
if (varsize)
|
||||
{
|
||||
/***BUG***/
|
||||
return 0; /* we will only write one block in variable size mode :-( */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (numblocks)
|
||||
{
|
||||
numblocks--;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0; /* we're done. */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* and done! */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Okay, the read thingy: */
|
||||
|
||||
/* We have a device opened (we hope!) by the parser.
|
||||
* we will have arg[0] and arg[1] being the blocksize and # of blocks
|
||||
* (respectively).
|
||||
*/
|
||||
|
||||
|
||||
static int S_read(void)
|
||||
{
|
||||
char *buffer; /* the buffer we're going to be reading out of */
|
||||
int buffersize;
|
||||
unsigned int len; /* the length of the data in the buffer */
|
||||
int blocksize = arg[0];
|
||||
int numblocks = arg[1];
|
||||
int varsize = 0; /* variable size block flag. */
|
||||
|
||||
int result;
|
||||
|
||||
int outfile=fileno(stdout); /* sigh. */
|
||||
|
||||
if (blocksize == 0)
|
||||
{
|
||||
varsize=1;
|
||||
buffersize=MAX_READ_SIZE;
|
||||
len=MAX_READ_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
varsize=0; /* fixed block mode */
|
||||
buffersize=blocksize;
|
||||
len=blocksize;
|
||||
}
|
||||
|
||||
/* sigh, make it oversized just to have some */
|
||||
buffer = malloc(buffersize + 8);
|
||||
|
||||
for ( ; ; )
|
||||
{
|
||||
if (varsize)
|
||||
{
|
||||
/* it could have gotten reset by prior short read... */
|
||||
len=MAX_READ_SIZE;
|
||||
}
|
||||
result=SCSI_readt(MediumChangerFD,buffer,blocksize, &len, DEFAULT_TIMEOUT);
|
||||
|
||||
if (result==READ_FILEMARK || result==READ_EOD || result==READ_EOP)
|
||||
{
|
||||
/* okay, normal end of file? */
|
||||
if (len > 0)
|
||||
{
|
||||
write(outfile,buffer,len);
|
||||
}
|
||||
|
||||
#ifdef NEED_TO_GO_PAST_FILEMARK
|
||||
/* Now, let's try to go past the filemark if that's what we hit: */
|
||||
if (result==READ_FILEMARK)
|
||||
{
|
||||
arg1 = 1; /* arg for S_fsf. */
|
||||
S_fsf(); /* and go forward 1 filemark, we hope! */
|
||||
}
|
||||
#endif
|
||||
return 0; /* hit normal end of file. */
|
||||
}
|
||||
else if (result == READ_SHORT)
|
||||
{
|
||||
/* short reads are only valid in variable block mode. */
|
||||
if (varsize)
|
||||
{
|
||||
if (len > 0)
|
||||
{
|
||||
write(outfile,buffer,len);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"scsitape:Short Read encountered on input. Aborting.\n");
|
||||
fflush(stderr);
|
||||
exit(1); /* error exit! */
|
||||
}
|
||||
}
|
||||
else if (result == READ_OK)
|
||||
{
|
||||
write(outfile,buffer,len);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"scsitape:Read Error\n");
|
||||
fflush(stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Now see if we have numbytes or numblocks: if so, we may wish to
|
||||
* exit this loop.
|
||||
*/
|
||||
if (arg[1])
|
||||
{
|
||||
if (varsize)
|
||||
{
|
||||
/****BUG****/
|
||||
return 0; /* we're only reading one block in var size mode! */
|
||||
}
|
||||
else if (numblocks)
|
||||
{
|
||||
numblocks--;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0; /* we're done. */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* See parse_args for the scoop. parse_args does all. */
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
argv0 = argv[0];
|
||||
parse_args(argc, argv);
|
||||
|
||||
if (device)
|
||||
SCSI_CloseDevice(device,MediumChangerFD);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
645
mtx-1.3.12/sg_err.c
Normal file
645
mtx-1.3.12/sg_err.c
Normal file
@@ -0,0 +1,645 @@
|
||||
|
||||
/* This file is a huge cut, paste and hack from linux/drivers/scsi/constant.c
|
||||
* which I guess was written by:
|
||||
* Copyright (C) 1993, 1994, 1995 Eric Youngdale
|
||||
|
||||
* The rest of this is:
|
||||
* Copyright (C) 1999 - 2001 D. Gilbert
|
||||
* Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* ASCII values for a number of symbolic constants, printing functions, etc.
|
||||
*
|
||||
* Some of the tables have been updated for SCSI 2.
|
||||
*
|
||||
* Version 0.84 (20010115)
|
||||
* Change output from stdout to stderr
|
||||
*/
|
||||
|
||||
#define OUTP stderr
|
||||
|
||||
static const unsigned char scsi_command_size[8] = { 6, 10, 10, 12,
|
||||
12, 12, 10, 10 };
|
||||
|
||||
#define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7]
|
||||
|
||||
static const char unknown[] = "UNKNOWN";
|
||||
|
||||
static const char * group_0_commands[] = {
|
||||
/* 00-03 */ "Test Unit Ready", "Rezero Unit", unknown, "Request Sense",
|
||||
/* 04-07 */ "Format Unit", "Read Block Limits", unknown, "Reasssign Blocks",
|
||||
/* 08-0d */ "Read (6)", unknown, "Write (6)", "Seek (6)", unknown, unknown,
|
||||
/* 0e-12 */ unknown, "Read Reverse", "Write Filemarks", "Space", "Inquiry",
|
||||
/* 13-16 */ "Verify", "Recover Buffered Data", "Mode Select", "Reserve",
|
||||
/* 17-1b */ "Release", "Copy", "Erase", "Mode Sense", "Start/Stop Unit",
|
||||
/* 1c-1d */ "Receive Diagnostic", "Send Diagnostic",
|
||||
/* 1e-1f */ "Prevent/Allow Medium Removal", unknown,
|
||||
};
|
||||
|
||||
|
||||
static const char *group_1_commands[] = {
|
||||
/* 20-22 */ unknown, unknown, unknown,
|
||||
/* 23-28 */ unknown, "Define window parameters", "Read Capacity",
|
||||
unknown, unknown, "Read (10)",
|
||||
/* 29-2d */ "Read Generation", "Write (10)", "Seek (10)", "Erase",
|
||||
"Read updated block",
|
||||
/* 2e-31 */ "Write Verify","Verify", "Search High", "Search Equal",
|
||||
/* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position",
|
||||
/* 35-37 */ "Synchronize Cache","Lock/Unlock Cache", "Read Defect Data",
|
||||
/* 38-3c */ "Medium Scan", "Compare", "Copy Verify", "Write Buffer",
|
||||
"Read Buffer",
|
||||
/* 3d-3f */ "Update Block", "Read Long", "Write Long",
|
||||
};
|
||||
|
||||
static const char *group_2_commands[] = {
|
||||
/* 40-41 */ "Change Definition", "Write Same",
|
||||
/* 42-48 */ "Read sub-channel", "Read TOC", "Read header",
|
||||
"Play audio (10)", unknown, "Play audio msf",
|
||||
"Play audio track/index",
|
||||
/* 49-4f */ "Play track relative (10)", unknown, "Pause/resume",
|
||||
"Log Select", "Log Sense", unknown, unknown,
|
||||
/* 50-55 */ unknown, unknown, unknown, unknown, unknown, "Mode Select (10)",
|
||||
/* 56-5b */ unknown, unknown, unknown, unknown, "Mode Sense (10)", unknown,
|
||||
/* 5c-5f */ unknown, unknown, unknown,
|
||||
};
|
||||
|
||||
|
||||
/* The following are 12 byte commands in group 5 */
|
||||
static const char *group_5_commands[] = {
|
||||
/* a0-a5 */ unknown, unknown, unknown, unknown, unknown,
|
||||
"Move medium/play audio(12)",
|
||||
/* a6-a9 */ "Exchange medium", unknown, "Read(12)", "Play track relative(12)",
|
||||
/* aa-ae */ "Write(12)", unknown, "Erase(12)", unknown,
|
||||
"Write and verify(12)",
|
||||
/* af-b1 */ "Verify(12)", "Search data high(12)", "Search data equal(12)",
|
||||
/* b2-b4 */ "Search data low(12)", "Set limits(12)", unknown,
|
||||
/* b5-b6 */ "Request volume element address", "Send volume tag",
|
||||
/* b7-b9 */ "Read defect data(12)", "Read element status", unknown,
|
||||
/* ba-bf */ unknown, unknown, unknown, unknown, unknown, unknown,
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#define group(opcode) (((opcode) >> 5) & 7)
|
||||
|
||||
#define RESERVED_GROUP 0
|
||||
#define VENDOR_GROUP 1
|
||||
|
||||
static const char **commands[] = {
|
||||
group_0_commands, group_1_commands, group_2_commands,
|
||||
(const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP,
|
||||
group_5_commands, (const char **) VENDOR_GROUP,
|
||||
(const char **) VENDOR_GROUP
|
||||
};
|
||||
|
||||
static const char reserved[] = "RESERVED";
|
||||
static const char vendor[] = "VENDOR SPECIFIC";
|
||||
|
||||
static void print_opcode(int opcode) {
|
||||
const char **table = commands[ group(opcode) ];
|
||||
switch ((unsigned long) table) {
|
||||
case RESERVED_GROUP:
|
||||
fprintf(OUTP, "%s(0x%02x) ", reserved, opcode);
|
||||
break;
|
||||
case VENDOR_GROUP:
|
||||
fprintf(OUTP, "%s(0x%02x) ", vendor, opcode);
|
||||
break;
|
||||
default:
|
||||
if (table[opcode & 0x1f] != unknown)
|
||||
fprintf(OUTP, "%s ",table[opcode & 0x1f]);
|
||||
else
|
||||
fprintf(OUTP, "%s(0x%02x) ", unknown, opcode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void sg_print_command (const unsigned char * command) {
|
||||
int i,s;
|
||||
print_opcode(command[0]);
|
||||
for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
|
||||
fprintf(OUTP, "%02x ", command[i]);
|
||||
fprintf(OUTP, "\n");
|
||||
}
|
||||
|
||||
static const char * statuses[] = {
|
||||
/* 0-4 */ "Good", "Check Condition", "Condition Met", unknown, "Busy",
|
||||
/* 5-9 */ unknown, unknown, unknown, "Intermediate", unknown,
|
||||
/* a-c */ "Intermediate-Condition Met", unknown, "Reservation Conflict",
|
||||
/* d-10 */ unknown, unknown, unknown, unknown,
|
||||
/* 11-14 */ "Command Terminated", unknown, unknown, "Queue Full",
|
||||
/* 15-1a */ unknown, unknown, unknown, unknown, unknown, unknown,
|
||||
/* 1b-1f */ unknown, unknown, unknown, unknown, unknown,
|
||||
};
|
||||
|
||||
void sg_print_status (int masked_status) {
|
||||
/* status = (status >> 1) & 0xf; */ /* already done */
|
||||
fprintf(OUTP, "%s ",statuses[masked_status]);
|
||||
}
|
||||
|
||||
#define D 0x001 /* DIRECT ACCESS DEVICE (disk) */
|
||||
#define T 0x002 /* SEQUENTIAL ACCESS DEVICE (tape) */
|
||||
#define L 0x004 /* PRINTER DEVICE */
|
||||
#define P 0x008 /* PROCESSOR DEVICE */
|
||||
#define W 0x010 /* WRITE ONCE READ MULTIPLE DEVICE */
|
||||
#define R 0x020 /* READ ONLY (CD-ROM) DEVICE */
|
||||
#define S 0x040 /* SCANNER DEVICE */
|
||||
#define O 0x080 /* OPTICAL MEMORY DEVICE */
|
||||
#define M 0x100 /* MEDIA CHANGER DEVICE */
|
||||
#define C 0x200 /* COMMUNICATION DEVICE */
|
||||
|
||||
struct error_info{
|
||||
unsigned char code1, code2;
|
||||
unsigned short int devices;
|
||||
const char * text;
|
||||
};
|
||||
|
||||
struct error_info2{
|
||||
unsigned char code1, code2_min, code2_max;
|
||||
unsigned short int devices;
|
||||
const char * text;
|
||||
};
|
||||
|
||||
static struct error_info2 additional2[] =
|
||||
{
|
||||
{0x40,0x00,0x7f,D,"Ram failure (%x)"},
|
||||
{0x40,0x80,0xff,D|T|L|P|W|R|S|O|M|C,"Diagnostic failure on component (%x)"},
|
||||
{0x41,0x00,0xff,D,"Data path failure (%x)"},
|
||||
{0x42,0x00,0xff,D,"Power-on or self-test failure (%x)"},
|
||||
{0, 0, 0, 0, NULL}
|
||||
};
|
||||
|
||||
static struct error_info additional[] =
|
||||
{
|
||||
{0x00,0x01,T,"Filemark detected"},
|
||||
{0x00,0x02,T|S,"End-of-partition/medium detected"},
|
||||
{0x00,0x03,T,"Setmark detected"},
|
||||
{0x00,0x04,T|S,"Beginning-of-partition/medium detected"},
|
||||
{0x00,0x05,T|S,"End-of-data detected"},
|
||||
{0x00,0x06,D|T|L|P|W|R|S|O|M|C,"I/O process terminated"},
|
||||
{0x00,0x11,R,"Audio play operation in progress"},
|
||||
{0x00,0x12,R,"Audio play operation paused"},
|
||||
{0x00,0x13,R,"Audio play operation successfully completed"},
|
||||
{0x00,0x14,R,"Audio play operation stopped due to error"},
|
||||
{0x00,0x15,R,"No current audio status to return"},
|
||||
{0x01,0x00,D|W|O,"No index/sector signal"},
|
||||
{0x02,0x00,D|W|R|O|M,"No seek complete"},
|
||||
{0x03,0x00,D|T|L|W|S|O,"Peripheral device write fault"},
|
||||
{0x03,0x01,T,"No write current"},
|
||||
{0x03,0x02,T,"Excessive write errors"},
|
||||
{0x04,0x00,D|T|L|P|W|R|S|O|M|C,
|
||||
"Logical unit not ready, cause not reportable"},
|
||||
{0x04,0x01,D|T|L|P|W|R|S|O|M|C,
|
||||
"Logical unit is in process of becoming ready"},
|
||||
{0x04,0x02,D|T|L|P|W|R|S|O|M|C,
|
||||
"Logical unit not ready, initializing command required"},
|
||||
{0x04,0x03,D|T|L|P|W|R|S|O|M|C,
|
||||
"Logical unit not ready, manual intervention required"},
|
||||
{0x04,0x04,D|T|L|O,"Logical unit not ready, format in progress"},
|
||||
{0x05,0x00,D|T|L|W|R|S|O|M|C,"Logical unit does not respond to selection"},
|
||||
{0x06,0x00,D|W|R|O|M,"No reference position found"},
|
||||
{0x07,0x00,D|T|L|W|R|S|O|M,"Multiple peripheral devices selected"},
|
||||
{0x08,0x00,D|T|L|W|R|S|O|M|C,"Logical unit communication failure"},
|
||||
{0x08,0x01,D|T|L|W|R|S|O|M|C,"Logical unit communication time-out"},
|
||||
{0x08,0x02,D|T|L|W|R|S|O|M|C,"Logical unit communication parity error"},
|
||||
{0x09,0x00,D|T|W|R|O,"Track following error"},
|
||||
{0x09,0x01,W|R|O,"Tracking servo failure"},
|
||||
{0x09,0x02,W|R|O,"Focus servo failure"},
|
||||
{0x09,0x03,W|R|O,"Spindle servo failure"},
|
||||
{0x0A,0x00,D|T|L|P|W|R|S|O|M|C,"Error log overflow"},
|
||||
{0x0C,0x00,T|S,"Write error"},
|
||||
{0x0C,0x01,D|W|O,"Write error recovered with auto reallocation"},
|
||||
{0x0C,0x02,D|W|O,"Write error - auto reallocation failed"},
|
||||
{0x10,0x00,D|W|O,"Id crc or ecc error"},
|
||||
{0x11,0x00,D|T|W|R|S|O,"Unrecovered read error"},
|
||||
{0x11,0x01,D|T|W|S|O,"Read retries exhausted"},
|
||||
{0x11,0x02,D|T|W|S|O,"Error too long to correct"},
|
||||
{0x11,0x03,D|T|W|S|O,"Multiple read errors"},
|
||||
{0x11,0x04,D|W|O,"Unrecovered read error - auto reallocate failed"},
|
||||
{0x11,0x05,W|R|O,"L-ec uncorrectable error"},
|
||||
{0x11,0x06,W|R|O,"Circ unrecovered error"},
|
||||
{0x11,0x07,W|O,"Data resynchronization error"},
|
||||
{0x11,0x08,T,"Incomplete block read"},
|
||||
{0x11,0x09,T,"No gap found"},
|
||||
{0x11,0x0A,D|T|O,"Miscorrected error"},
|
||||
{0x11,0x0B,D|W|O,"Unrecovered read error - recommend reassignment"},
|
||||
{0x11,0x0C,D|W|O,"Unrecovered read error - recommend rewrite the data"},
|
||||
{0x12,0x00,D|W|O,"Address mark not found for id field"},
|
||||
{0x13,0x00,D|W|O,"Address mark not found for data field"},
|
||||
{0x14,0x00,D|T|L|W|R|S|O,"Recorded entity not found"},
|
||||
{0x14,0x01,D|T|W|R|O,"Record not found"},
|
||||
{0x14,0x02,T,"Filemark or setmark not found"},
|
||||
{0x14,0x03,T,"End-of-data not found"},
|
||||
{0x14,0x04,T,"Block sequence error"},
|
||||
{0x15,0x00,D|T|L|W|R|S|O|M,"Random positioning error"},
|
||||
{0x15,0x01,D|T|L|W|R|S|O|M,"Mechanical positioning error"},
|
||||
{0x15,0x02,D|T|W|R|O,"Positioning error detected by read of medium"},
|
||||
{0x16,0x00,D|W|O,"Data synchronization mark error"},
|
||||
{0x17,0x00,D|T|W|R|S|O,"Recovered data with no error correction applied"},
|
||||
{0x17,0x01,D|T|W|R|S|O,"Recovered data with retries"},
|
||||
{0x17,0x02,D|T|W|R|O,"Recovered data with positive head offset"},
|
||||
{0x17,0x03,D|T|W|R|O,"Recovered data with negative head offset"},
|
||||
{0x17,0x04,W|R|O,"Recovered data with retries and/or circ applied"},
|
||||
{0x17,0x05,D|W|R|O,"Recovered data using previous sector id"},
|
||||
{0x17,0x06,D|W|O,"Recovered data without ecc - data auto-reallocated"},
|
||||
{0x17,0x07,D|W|O,"Recovered data without ecc - recommend reassignment"},
|
||||
{0x18,0x00,D|T|W|R|O,"Recovered data with error correction applied"},
|
||||
{0x18,0x01,D|W|R|O,"Recovered data with error correction and retries applied"},
|
||||
{0x18,0x02,D|W|R|O,"Recovered data - data auto-reallocated"},
|
||||
{0x18,0x03,R,"Recovered data with circ"},
|
||||
{0x18,0x04,R,"Recovered data with lec"},
|
||||
{0x18,0x05,D|W|R|O,"Recovered data - recommend reassignment"},
|
||||
{0x19,0x00,D|O,"Defect list error"},
|
||||
{0x19,0x01,D|O,"Defect list not available"},
|
||||
{0x19,0x02,D|O,"Defect list error in primary list"},
|
||||
{0x19,0x03,D|O,"Defect list error in grown list"},
|
||||
{0x1A,0x00,D|T|L|P|W|R|S|O|M|C,"Parameter list length error"},
|
||||
{0x1B,0x00,D|T|L|P|W|R|S|O|M|C,"Synchronous data transfer error"},
|
||||
{0x1C,0x00,D|O,"Defect list not found"},
|
||||
{0x1C,0x01,D|O,"Primary defect list not found"},
|
||||
{0x1C,0x02,D|O,"Grown defect list not found"},
|
||||
{0x1D,0x00,D|W|O,"Miscompare during verify operation"},
|
||||
{0x1E,0x00,D|W|O,"Recovered id with ecc correction"},
|
||||
{0x20,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid command operation code"},
|
||||
{0x21,0x00,D|T|W|R|O|M,"Logical block address out of range"},
|
||||
{0x21,0x01,M,"Invalid element address"},
|
||||
{0x22,0x00,D,"Illegal function (should use 20 00, 24 00, or 26 00)"},
|
||||
{0x24,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid field in cdb"},
|
||||
{0x25,0x00,D|T|L|P|W|R|S|O|M|C,"Logical unit not supported"},
|
||||
{0x26,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid field in parameter list"},
|
||||
{0x26,0x01,D|T|L|P|W|R|S|O|M|C,"Parameter not supported"},
|
||||
{0x26,0x02,D|T|L|P|W|R|S|O|M|C,"Parameter value invalid"},
|
||||
{0x26,0x03,D|T|L|P|W|R|S|O|M|C,"Threshold parameters not supported"},
|
||||
{0x27,0x00,D|T|W|O,"Write protected"},
|
||||
{0x28,0x00,D|T|L|P|W|R|S|O|M|C,"Not ready to ready transition (medium may have changed)"},
|
||||
{0x28,0x01,M,"Import or export element accessed"},
|
||||
{0x29,0x00,D|T|L|P|W|R|S|O|M|C,"Power on, reset, or bus device reset occurred"},
|
||||
{0x2A,0x00,D|T|L|W|R|S|O|M|C,"Parameters changed"},
|
||||
{0x2A,0x01,D|T|L|W|R|S|O|M|C,"Mode parameters changed"},
|
||||
{0x2A,0x02,D|T|L|W|R|S|O|M|C,"Log parameters changed"},
|
||||
{0x2B,0x00,D|T|L|P|W|R|S|O|C,"Copy cannot execute since host cannot disconnect"},
|
||||
{0x2C,0x00,D|T|L|P|W|R|S|O|M|C,"Command sequence error"},
|
||||
{0x2C,0x01,S,"Too many windows specified"},
|
||||
{0x2C,0x02,S,"Invalid combination of windows specified"},
|
||||
{0x2D,0x00,T,"Overwrite error on update in place"},
|
||||
{0x2F,0x00,D|T|L|P|W|R|S|O|M|C,"Commands cleared by another initiator"},
|
||||
{0x30,0x00,D|T|W|R|O|M,"Incompatible medium installed"},
|
||||
{0x30,0x01,D|T|W|R|O,"Cannot read medium - unknown format"},
|
||||
{0x30,0x02,D|T|W|R|O,"Cannot read medium - incompatible format"},
|
||||
{0x30,0x03,D|T,"Cleaning cartridge installed"},
|
||||
{0x31,0x00,D|T|W|O,"Medium format corrupted"},
|
||||
{0x31,0x01,D|L|O,"Format command failed"},
|
||||
{0x32,0x00,D|W|O,"No defect spare location available"},
|
||||
{0x32,0x01,D|W|O,"Defect list update failure"},
|
||||
{0x33,0x00,T,"Tape length error"},
|
||||
{0x36,0x00,L,"Ribbon, ink, or toner failure"},
|
||||
{0x37,0x00,D|T|L|W|R|S|O|M|C,"Rounded parameter"},
|
||||
{0x39,0x00,D|T|L|W|R|S|O|M|C,"Saving parameters not supported"},
|
||||
{0x3A,0x00,D|T|L|W|R|S|O|M,"Medium not present"},
|
||||
{0x3B,0x00,T|L,"Sequential positioning error"},
|
||||
{0x3B,0x01,T,"Tape position error at beginning-of-medium"},
|
||||
{0x3B,0x02,T,"Tape position error at end-of-medium"},
|
||||
{0x3B,0x03,L,"Tape or electronic vertical forms unit not ready"},
|
||||
{0x3B,0x04,L,"Slew failure"},
|
||||
{0x3B,0x05,L,"Paper jam"},
|
||||
{0x3B,0x06,L,"Failed to sense top-of-form"},
|
||||
{0x3B,0x07,L,"Failed to sense bottom-of-form"},
|
||||
{0x3B,0x08,T,"Reposition error"},
|
||||
{0x3B,0x09,S,"Read past end of medium"},
|
||||
{0x3B,0x0A,S,"Read past beginning of medium"},
|
||||
{0x3B,0x0B,S,"Position past end of medium"},
|
||||
{0x3B,0x0C,S,"Position past beginning of medium"},
|
||||
{0x3B,0x0D,M,"Medium destination element full"},
|
||||
{0x3B,0x0E,M,"Medium source element empty"},
|
||||
{0x3D,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid bits in identify message"},
|
||||
{0x3E,0x00,D|T|L|P|W|R|S|O|M|C,"Logical unit has not self-configured yet"},
|
||||
{0x3F,0x00,D|T|L|P|W|R|S|O|M|C,"Target operating conditions have changed"},
|
||||
{0x3F,0x01,D|T|L|P|W|R|S|O|M|C,"Microcode has been changed"},
|
||||
{0x3F,0x02,D|T|L|P|W|R|S|O|M|C,"Changed operating definition"},
|
||||
{0x3F,0x03,D|T|L|P|W|R|S|O|M|C,"Inquiry data has changed"},
|
||||
{0x43,0x00,D|T|L|P|W|R|S|O|M|C,"Message error"},
|
||||
{0x44,0x00,D|T|L|P|W|R|S|O|M|C,"Internal target failure"},
|
||||
{0x45,0x00,D|T|L|P|W|R|S|O|M|C,"Select or reselect failure"},
|
||||
{0x46,0x00,D|T|L|P|W|R|S|O|M|C,"Unsuccessful soft reset"},
|
||||
{0x47,0x00,D|T|L|P|W|R|S|O|M|C,"Scsi parity error"},
|
||||
{0x48,0x00,D|T|L|P|W|R|S|O|M|C,"Initiator detected error message received"},
|
||||
{0x49,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid message error"},
|
||||
{0x4A,0x00,D|T|L|P|W|R|S|O|M|C,"Command phase error"},
|
||||
{0x4B,0x00,D|T|L|P|W|R|S|O|M|C,"Data phase error"},
|
||||
{0x4C,0x00,D|T|L|P|W|R|S|O|M|C,"Logical unit failed self-configuration"},
|
||||
{0x4E,0x00,D|T|L|P|W|R|S|O|M|C,"Overlapped commands attempted"},
|
||||
{0x50,0x00,T,"Write append error"},
|
||||
{0x50,0x01,T,"Write append position error"},
|
||||
{0x50,0x02,T,"Position error related to timing"},
|
||||
{0x51,0x00,T|O,"Erase failure"},
|
||||
{0x52,0x00,T,"Cartridge fault"},
|
||||
{0x53,0x00,D|T|L|W|R|S|O|M,"Media load or eject failed"},
|
||||
{0x53,0x01,T,"Unload tape failure"},
|
||||
{0x53,0x02,D|T|W|R|O|M,"Medium removal prevented"},
|
||||
{0x54,0x00,P,"Scsi to host system interface failure"},
|
||||
{0x55,0x00,P,"System resource failure"},
|
||||
{0x57,0x00,R,"Unable to recover table-of-contents"},
|
||||
{0x58,0x00,O,"Generation does not exist"},
|
||||
{0x59,0x00,O,"Updated block read"},
|
||||
{0x5A,0x00,D|T|L|P|W|R|S|O|M,"Operator request or state change input (unspecified)"},
|
||||
{0x5A,0x01,D|T|W|R|O|M,"Operator medium removal request"},
|
||||
{0x5A,0x02,D|T|W|O,"Operator selected write protect"},
|
||||
{0x5A,0x03,D|T|W|O,"Operator selected write permit"},
|
||||
{0x5B,0x00,D|T|L|P|W|R|S|O|M,"Log exception"},
|
||||
{0x5B,0x01,D|T|L|P|W|R|S|O|M,"Threshold condition met"},
|
||||
{0x5B,0x02,D|T|L|P|W|R|S|O|M,"Log counter at maximum"},
|
||||
{0x5B,0x03,D|T|L|P|W|R|S|O|M,"Log list codes exhausted"},
|
||||
{0x5C,0x00,D|O,"Rpl status change"},
|
||||
{0x5C,0x01,D|O,"Spindles synchronized"},
|
||||
{0x5C,0x02,D|O,"Spindles not synchronized"},
|
||||
{0x60,0x00,S,"Lamp failure"},
|
||||
{0x61,0x00,S,"Video acquisition error"},
|
||||
{0x61,0x01,S,"Unable to acquire video"},
|
||||
{0x61,0x02,S,"Out of focus"},
|
||||
{0x62,0x00,S,"Scan head positioning error"},
|
||||
{0x63,0x00,R,"End of user area encountered on this track"},
|
||||
{0x64,0x00,R,"Illegal mode for this track"},
|
||||
{0, 0, 0, NULL}
|
||||
};
|
||||
|
||||
static const char *snstext[] = {
|
||||
"None", /* There is no sense information */
|
||||
"Recovered Error", /* The last command completed successfully
|
||||
but used error correction */
|
||||
"Not Ready", /* The addressed target is not ready */
|
||||
"Medium Error", /* Data error detected on the medium */
|
||||
"Hardware Error", /* Controller or device failure */
|
||||
"Illegal Request",
|
||||
"Unit Attention", /* Removable medium was changed, or
|
||||
the target has been reset */
|
||||
"Data Protect", /* Access to the data is blocked */
|
||||
"Blank Check", /* Reached unexpected written or unwritten
|
||||
region of the medium */
|
||||
"Key=9", /* Vendor specific */
|
||||
"Copy Aborted", /* COPY or COMPARE was aborted */
|
||||
"Aborted Command", /* The target aborted the command */
|
||||
"Equal", /* A SEARCH DATA command found data equal */
|
||||
"Volume Overflow", /* Medium full with still data to be written */
|
||||
"Miscompare", /* Source data and data on the medium
|
||||
do not agree */
|
||||
"Key=15" /* Reserved */
|
||||
};
|
||||
|
||||
/* Print sense information */
|
||||
void sg_print_sense(const char * leadin, const unsigned char * sense_buffer,
|
||||
int sb_len)
|
||||
{
|
||||
int i, s;
|
||||
int sense_class, valid, code;
|
||||
const char * error = NULL;
|
||||
|
||||
sense_class = (sense_buffer[0] >> 4) & 0x07;
|
||||
code = sense_buffer[0] & 0xf;
|
||||
valid = sense_buffer[0] & 0x80;
|
||||
|
||||
if (sense_class == 7) { /* extended sense data */
|
||||
s = sense_buffer[7] + 8;
|
||||
if(s > sb_len)
|
||||
s = sb_len;
|
||||
|
||||
if (!valid)
|
||||
fprintf(OUTP, "[valid=0] ");
|
||||
fprintf(OUTP, "Info fld=0x%x, ", (int)((sense_buffer[3] << 24) |
|
||||
(sense_buffer[4] << 16) | (sense_buffer[5] << 8) |
|
||||
sense_buffer[6]));
|
||||
|
||||
if (sense_buffer[2] & 0x80)
|
||||
fprintf(OUTP, "FMK "); /* current command has read a filemark */
|
||||
if (sense_buffer[2] & 0x40)
|
||||
fprintf(OUTP, "EOM "); /* end-of-medium condition exists */
|
||||
if (sense_buffer[2] & 0x20)
|
||||
fprintf(OUTP, "ILI "); /* incorrect block length requested */
|
||||
|
||||
switch (code) {
|
||||
case 0x0:
|
||||
error = "Current"; /* error concerns current command */
|
||||
break;
|
||||
case 0x1:
|
||||
error = "Deferred"; /* error concerns some earlier command */
|
||||
/* e.g., an earlier write to disk cache succeeded, but
|
||||
now the disk discovers that it cannot write the data */
|
||||
break;
|
||||
default:
|
||||
error = "Invalid";
|
||||
}
|
||||
|
||||
fprintf(OUTP, "%s ", error);
|
||||
|
||||
if (leadin)
|
||||
fprintf(OUTP, "%s: ", leadin);
|
||||
fprintf(OUTP, "sense key: %s\n", snstext[sense_buffer[2] & 0x0f]);
|
||||
|
||||
/* Check to see if additional sense information is available */
|
||||
if(sense_buffer[7] + 7 < 13 ||
|
||||
(sense_buffer[12] == 0 && sense_buffer[13] == 0)) goto done;
|
||||
|
||||
for(i=0; additional[i].text; i++)
|
||||
if(additional[i].code1 == sense_buffer[12] &&
|
||||
additional[i].code2 == sense_buffer[13])
|
||||
fprintf(OUTP, "Additional sense indicates: %s\n",
|
||||
additional[i].text);
|
||||
|
||||
for(i=0; additional2[i].text; i++)
|
||||
if(additional2[i].code1 == sense_buffer[12] &&
|
||||
additional2[i].code2_min >= sense_buffer[13] &&
|
||||
additional2[i].code2_max <= sense_buffer[13]) {
|
||||
fprintf(OUTP, "Additional sense indicates: ");
|
||||
fprintf(OUTP, additional2[i].text, sense_buffer[13]);
|
||||
fprintf(OUTP, "\n");
|
||||
};
|
||||
} else { /* non-extended sense data */
|
||||
|
||||
/*
|
||||
* Standard says:
|
||||
* sense_buffer[0] & 0200 : address valid
|
||||
* sense_buffer[0] & 0177 : vendor-specific error code
|
||||
* sense_buffer[1] & 0340 : vendor-specific
|
||||
* sense_buffer[1..3] : 21-bit logical block address
|
||||
*/
|
||||
|
||||
if (leadin)
|
||||
fprintf(OUTP, "%s: ", leadin);
|
||||
if (sense_buffer[0] < 15)
|
||||
fprintf(OUTP,
|
||||
"old sense: key %s\n", snstext[sense_buffer[0] & 0x0f]);
|
||||
else
|
||||
fprintf(OUTP, "sns = %2x %2x\n", sense_buffer[0], sense_buffer[2]);
|
||||
|
||||
fprintf(OUTP, "Non-extended sense class %d code 0x%0x ",
|
||||
sense_class, code);
|
||||
s = 4;
|
||||
}
|
||||
|
||||
done:
|
||||
fprintf(OUTP, "Raw sense data (in hex):\n ");
|
||||
for (i = 0; i < s; ++i) {
|
||||
if ((i > 0) && (0 == (i % 24)))
|
||||
fprintf(OUTP, "\n ");
|
||||
fprintf(OUTP, "%02x ", sense_buffer[i]);
|
||||
}
|
||||
fprintf(OUTP, "\n");
|
||||
return;
|
||||
}
|
||||
|
||||
static const char * hostbyte_table[]={
|
||||
"DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET",
|
||||
"DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR",
|
||||
"DID_PASSTHROUGH", "DID_SOFT_ERROR", NULL};
|
||||
|
||||
void sg_print_host_status(int host_status)
|
||||
{ static int maxcode=0;
|
||||
int i;
|
||||
|
||||
if(! maxcode) {
|
||||
for(i = 0; hostbyte_table[i]; i++) ;
|
||||
maxcode = i-1;
|
||||
}
|
||||
fprintf(OUTP, "Host_status=0x%02x", host_status);
|
||||
if(host_status > maxcode) {
|
||||
fprintf(OUTP, "is invalid ");
|
||||
return;
|
||||
}
|
||||
fprintf(OUTP, "(%s) ",hostbyte_table[host_status]);
|
||||
}
|
||||
|
||||
static const char * driverbyte_table[]={
|
||||
"DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA", "DRIVER_ERROR",
|
||||
"DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE", NULL};
|
||||
|
||||
static const char * driversuggest_table[]={"SUGGEST_OK",
|
||||
"SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP", "SUGGEST_DIE",
|
||||
unknown,unknown,unknown, "SUGGEST_SENSE",NULL};
|
||||
|
||||
|
||||
void sg_print_driver_status(int driver_status)
|
||||
{
|
||||
static int driver_max =0 , suggest_max=0;
|
||||
int i;
|
||||
int dr = driver_status & SG_ERR_DRIVER_MASK;
|
||||
int su = (driver_status & SG_ERR_SUGGEST_MASK) >> 4;
|
||||
|
||||
if(! driver_max) {
|
||||
for(i = 0; driverbyte_table[i]; i++) ;
|
||||
driver_max = i;
|
||||
for(i = 0; driversuggest_table[i]; i++) ;
|
||||
suggest_max = i;
|
||||
}
|
||||
fprintf(OUTP, "Driver_status=0x%02x",driver_status);
|
||||
fprintf(OUTP, " (%s,%s) ",
|
||||
dr < driver_max ? driverbyte_table[dr]:"invalid",
|
||||
su < suggest_max ? driversuggest_table[su]:"invalid");
|
||||
}
|
||||
|
||||
#ifdef SG_IO
|
||||
int sg_chk_n_print3(const char * leadin, struct sg_io_hdr * hp)
|
||||
{
|
||||
return sg_chk_n_print(leadin, hp->masked_status, hp->host_status,
|
||||
hp->driver_status, hp->sbp, hp->sb_len_wr);
|
||||
}
|
||||
#endif
|
||||
|
||||
int sg_chk_n_print(const char * leadin, int masked_status,
|
||||
int host_status, int driver_status,
|
||||
const unsigned char * sense_buffer, int sb_len)
|
||||
{
|
||||
int done_leadin = 0;
|
||||
int done_sense = 0;
|
||||
|
||||
if ((0 == masked_status) && (0 == host_status) &&
|
||||
(0 == driver_status))
|
||||
return 1; /* No problems */
|
||||
if (0 != masked_status) {
|
||||
if (leadin)
|
||||
fprintf(OUTP, "%s: ", leadin);
|
||||
done_leadin = 1;
|
||||
sg_print_status(masked_status);
|
||||
fprintf(OUTP, "\n");
|
||||
if (sense_buffer && ((masked_status == CHECK_CONDITION) ||
|
||||
(masked_status == COMMAND_TERMINATED))) {
|
||||
sg_print_sense(0, sense_buffer, sb_len);
|
||||
done_sense = 1;
|
||||
}
|
||||
}
|
||||
if (0 != host_status) {
|
||||
if (leadin && (! done_leadin))
|
||||
fprintf(OUTP, "%s: ", leadin);
|
||||
if (done_leadin)
|
||||
fprintf(OUTP, "plus...: ");
|
||||
else
|
||||
done_leadin = 1;
|
||||
sg_print_host_status(host_status);
|
||||
fprintf(OUTP, "\n");
|
||||
}
|
||||
if (0 != driver_status) {
|
||||
if (leadin && (! done_leadin))
|
||||
fprintf(OUTP, "%s: ", leadin);
|
||||
if (done_leadin)
|
||||
fprintf(OUTP, "plus...: ");
|
||||
else
|
||||
done_leadin = 1;
|
||||
sg_print_driver_status(driver_status);
|
||||
fprintf(OUTP, "\n");
|
||||
if (sense_buffer && (! done_sense) &&
|
||||
(SG_ERR_DRIVER_SENSE & driver_status))
|
||||
sg_print_sense(0, sense_buffer, sb_len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef SG_IO
|
||||
int sg_err_category3(struct sg_io_hdr * hp)
|
||||
{
|
||||
return sg_err_category(hp->masked_status, hp->host_status,
|
||||
hp->driver_status, hp->sbp, hp->sb_len_wr);
|
||||
}
|
||||
#endif
|
||||
|
||||
int sg_err_category(int masked_status, int host_status,
|
||||
int driver_status, const unsigned char * sense_buffer,
|
||||
int sb_len)
|
||||
{
|
||||
if ((0 == masked_status) && (0 == host_status) &&
|
||||
(0 == driver_status))
|
||||
return SG_ERR_CAT_CLEAN;
|
||||
if ((CHECK_CONDITION == masked_status) ||
|
||||
(COMMAND_TERMINATED == masked_status) ||
|
||||
(SG_ERR_DRIVER_SENSE & driver_status)) {
|
||||
if (sense_buffer && (sb_len > 2)) {
|
||||
if(RECOVERED_ERROR == sense_buffer[2])
|
||||
return SG_ERR_CAT_RECOVERED;
|
||||
else if ((UNIT_ATTENTION == (0x0f & sense_buffer[2])) &&
|
||||
(sb_len > 12)) {
|
||||
if (0x28 == sense_buffer[12])
|
||||
return SG_ERR_CAT_MEDIA_CHANGED;
|
||||
if (0x29 == sense_buffer[12])
|
||||
return SG_ERR_CAT_RESET;
|
||||
}
|
||||
}
|
||||
return SG_ERR_CAT_SENSE;
|
||||
}
|
||||
if (0 != host_status) {
|
||||
if ((SG_ERR_DID_NO_CONNECT == host_status) ||
|
||||
(SG_ERR_DID_BUS_BUSY == host_status) ||
|
||||
(SG_ERR_DID_TIME_OUT == host_status))
|
||||
return SG_ERR_CAT_TIMEOUT;
|
||||
}
|
||||
if (0 != driver_status) {
|
||||
if (SG_ERR_DRIVER_TIMEOUT == driver_status)
|
||||
return SG_ERR_CAT_TIMEOUT;
|
||||
}
|
||||
return SG_ERR_CAT_OTHER;
|
||||
}
|
||||
|
||||
int sg_get_command_size(unsigned char opcode)
|
||||
{
|
||||
return COMMAND_SIZE(opcode);
|
||||
}
|
||||
140
mtx-1.3.12/sg_err.h
Normal file
140
mtx-1.3.12/sg_err.h
Normal file
@@ -0,0 +1,140 @@
|
||||
#ifndef SG_ERR_H
|
||||
#define SG_ERR_H
|
||||
|
||||
/* Feel free to copy and modify this GPL-ed code into your applications. */
|
||||
|
||||
/* Version 0.84 (20010115)
|
||||
- all output now sent to stderr rather thatn stdout
|
||||
- remove header files included in this file
|
||||
*/
|
||||
|
||||
|
||||
/* Some of the following error/status codes are exchanged between the
|
||||
various layers of the SCSI sub-system in Linux and should never
|
||||
reach the user. They are placed here for completeness. What appears
|
||||
here is copied from drivers/scsi/scsi.h which is not visible in
|
||||
the user space. */
|
||||
|
||||
/* The following are 'host_status' codes */
|
||||
#ifndef DID_OK
|
||||
#define DID_OK 0x00
|
||||
#endif
|
||||
#ifndef DID_NO_CONNECT
|
||||
#define DID_NO_CONNECT 0x01 /* Unable to connect before timeout */
|
||||
#define DID_BUS_BUSY 0x02 /* Bus remain busy until timeout */
|
||||
#define DID_TIME_OUT 0x03 /* Timed out for some other reason */
|
||||
#define DID_BAD_TARGET 0x04 /* Bad target (id?) */
|
||||
#define DID_ABORT 0x05 /* Told to abort for some other reason */
|
||||
#define DID_PARITY 0x06 /* Parity error (on SCSI bus) */
|
||||
#define DID_ERROR 0x07 /* Internal error */
|
||||
#define DID_RESET 0x08 /* Reset by somebody */
|
||||
#define DID_BAD_INTR 0x09 /* Received an unexpected interrupt */
|
||||
#define DID_PASSTHROUGH 0x0a /* Force command past mid-level */
|
||||
#define DID_SOFT_ERROR 0x0b /* The low-level driver wants a retry */
|
||||
#endif
|
||||
|
||||
/* These defines are to isolate applictaions from kernel define changes */
|
||||
#define SG_ERR_DID_OK DID_OK
|
||||
#define SG_ERR_DID_NO_CONNECT DID_NO_CONNECT
|
||||
#define SG_ERR_DID_BUS_BUSY DID_BUS_BUSY
|
||||
#define SG_ERR_DID_TIME_OUT DID_TIME_OUT
|
||||
#define SG_ERR_DID_BAD_TARGET DID_BAD_TARGET
|
||||
#define SG_ERR_DID_ABORT DID_ABORT
|
||||
#define SG_ERR_DID_PARITY DID_PARITY
|
||||
#define SG_ERR_DID_ERROR DID_ERROR
|
||||
#define SG_ERR_DID_RESET DID_RESET
|
||||
#define SG_ERR_DID_BAD_INTR DID_BAD_INTR
|
||||
#define SG_ERR_DID_PASSTHROUGH DID_PASSTHROUGH
|
||||
#define SG_ERR_DID_SOFT_ERROR DID_SOFT_ERROR
|
||||
|
||||
/* The following are 'driver_status' codes */
|
||||
#ifndef DRIVER_OK
|
||||
#define DRIVER_OK 0x00
|
||||
#endif
|
||||
#ifndef DRIVER_BUSY
|
||||
#define DRIVER_BUSY 0x01
|
||||
#define DRIVER_SOFT 0x02
|
||||
#define DRIVER_MEDIA 0x03
|
||||
#define DRIVER_ERROR 0x04
|
||||
#define DRIVER_INVALID 0x05
|
||||
#define DRIVER_TIMEOUT 0x06
|
||||
#define DRIVER_HARD 0x07
|
||||
#define DRIVER_SENSE 0x08 /* Sense_buffer has been set */
|
||||
|
||||
/* Following "suggests" are "or-ed" with one of previous 8 entries */
|
||||
#define SUGGEST_RETRY 0x10
|
||||
#define SUGGEST_ABORT 0x20
|
||||
#define SUGGEST_REMAP 0x30
|
||||
#define SUGGEST_DIE 0x40
|
||||
#define SUGGEST_SENSE 0x80
|
||||
#define SUGGEST_IS_OK 0xff
|
||||
#endif
|
||||
#ifndef DRIVER_MASK
|
||||
#define DRIVER_MASK 0x0f
|
||||
#endif
|
||||
#ifndef SUGGEST_MASK
|
||||
#define SUGGEST_MASK 0xf0
|
||||
#endif
|
||||
|
||||
/* These defines are to isolate applictaions from kernel define changes */
|
||||
#define SG_ERR_DRIVER_OK DRIVER_OK
|
||||
#define SG_ERR_DRIVER_BUSY DRIVER_BUSY
|
||||
#define SG_ERR_DRIVER_SOFT DRIVER_SOFT
|
||||
#define SG_ERR_DRIVER_MEDIA DRIVER_MEDIA
|
||||
#define SG_ERR_DRIVER_ERROR DRIVER_ERROR
|
||||
#define SG_ERR_DRIVER_INVALID DRIVER_INVALID
|
||||
#define SG_ERR_DRIVER_TIMEOUT DRIVER_TIMEOUT
|
||||
#define SG_ERR_DRIVER_HARD DRIVER_HARD
|
||||
#define SG_ERR_DRIVER_SENSE DRIVER_SENSE
|
||||
#define SG_ERR_SUGGEST_RETRY SUGGEST_RETRY
|
||||
#define SG_ERR_SUGGEST_ABORT SUGGEST_ABORT
|
||||
#define SG_ERR_SUGGEST_REMAP SUGGEST_REMAP
|
||||
#define SG_ERR_SUGGEST_DIE SUGGEST_DIE
|
||||
#define SG_ERR_SUGGEST_SENSE SUGGEST_SENSE
|
||||
#define SG_ERR_SUGGEST_IS_OK SUGGEST_IS_OK
|
||||
#define SG_ERR_DRIVER_MASK DRIVER_MASK
|
||||
#define SG_ERR_SUGGEST_MASK SUGGEST_MASK
|
||||
|
||||
|
||||
|
||||
/* The following "print" functions send ACSII to stdout */
|
||||
extern void sg_print_command(const unsigned char * command);
|
||||
extern void sg_print_sense(const char * leadin,
|
||||
const unsigned char * sense_buffer, int sb_len);
|
||||
extern void sg_print_status(int masked_status);
|
||||
extern void sg_print_host_status(int host_status);
|
||||
extern void sg_print_driver_status(int driver_status);
|
||||
|
||||
/* sg_chk_n_print() returns 1 quietly if there are no errors/warnings
|
||||
else it prints to standard output and returns 0. */
|
||||
extern int sg_chk_n_print(const char * leadin, int masked_status,
|
||||
int host_status, int driver_status,
|
||||
const unsigned char * sense_buffer, int sb_len);
|
||||
|
||||
/* The following function declaration is for the sg version 3 driver.
|
||||
Only version 3 sg_err.c defines it. */
|
||||
struct sg_io_hdr;
|
||||
extern int sg_chk_n_print3(const char * leadin, struct sg_io_hdr * hp);
|
||||
|
||||
|
||||
/* The following "category" function returns one of the following */
|
||||
#define SG_ERR_CAT_CLEAN 0 /* No errors or other information */
|
||||
#define SG_ERR_CAT_MEDIA_CHANGED 1 /* interpreted from sense buffer */
|
||||
#define SG_ERR_CAT_RESET 2 /* interpreted from sense buffer */
|
||||
#define SG_ERR_CAT_TIMEOUT 3
|
||||
#define SG_ERR_CAT_RECOVERED 4 /* Successful command after recovered err */
|
||||
#define SG_ERR_CAT_SENSE 98 /* Something else is in the sense buffer */
|
||||
#define SG_ERR_CAT_OTHER 99 /* Some other error/warning has occurred */
|
||||
|
||||
extern int sg_err_category(int masked_status, int host_status,
|
||||
int driver_status, const unsigned char * sense_buffer,
|
||||
int sb_len);
|
||||
|
||||
/* The following function declaration is for the sg version 3 driver.
|
||||
Only version 3 sg_err.c defines it. */
|
||||
extern int sg_err_category3(struct sg_io_hdr * hp);
|
||||
|
||||
/* Returns length of SCSI command given the opcode (first byte) */
|
||||
int sg_get_command_size(unsigned char opcode);
|
||||
|
||||
#endif
|
||||
72
mtx-1.3.12/tapeinfo.1
Normal file
72
mtx-1.3.12/tapeinfo.1
Normal file
@@ -0,0 +1,72 @@
|
||||
.\" tapeinfo.1 Document copyright 2000 Eric Lee Green
|
||||
.\" Program Copyright 2000 Eric Lee Green <eric@badtux.org>
|
||||
.\" Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
|
||||
.\"
|
||||
.\" This is free documentation; you can redistribute it and/or
|
||||
.\" modify it under the terms of the GNU General Public License as
|
||||
.\" published by the Free Software Foundation; either version 2 of
|
||||
.\" the License, or (at your option) any later version.
|
||||
.\"
|
||||
.\" The GNU General Public License's references to "object code"
|
||||
.\" and "executables" are to be interpreted as the output of any
|
||||
.\" document formatting or typesetting system, including
|
||||
.\" intermediate and printed output.
|
||||
.\"
|
||||
.\" This manual is distributed in the hope that it will be useful,
|
||||
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
.\" GNU General Public License for more details.
|
||||
.\"
|
||||
.\" You should have received a copy of the GNU General Public
|
||||
.\" License along with this manual; if not, write to the Free
|
||||
.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
|
||||
.\" USA.
|
||||
.\"
|
||||
.TH TAPEINFO 1 TAPEINFO1.0
|
||||
.SH NAME
|
||||
tapeinfo \- report SCSI tape device info
|
||||
.SH SYNOPSIS
|
||||
tapeinfo -f <scsi-generic-device>
|
||||
.SH DESCRIPTION
|
||||
The
|
||||
.B tapeinfo
|
||||
command reads various information from SCSI tape drives that is not
|
||||
generally available via most vendors' tape drivers. It issues raw
|
||||
commands directly to the tape drive, using either the operating system's
|
||||
SCSI generic device ( e.g. /dev/sg0 on Linux, /dev/pass0 on FreeBSD) or
|
||||
the raw SCSI I/O ioctl on a tape device on some operating systems.
|
||||
.P
|
||||
One good time to use 'tapeinfo' is immediately after a tape i/o operation has
|
||||
failed. On tape drives that support HP's 'tapealert' API, 'tapeinfo' will
|
||||
report a more exact description of what went wrong.
|
||||
.P
|
||||
Do be aware that 'tapeinfo' is not a substitute for your operating system's
|
||||
own 'mt' or similar tape driver control program. It is intended to supplement,
|
||||
not replace, programs like 'mt' that access your operating system's tape
|
||||
driver in order to report or set information.
|
||||
.SH OPTIONS
|
||||
The first argument, given following
|
||||
.B -f
|
||||
, is the SCSI generic device corresponding to your tape drive.
|
||||
Consult your operating system's documentation for more information (for
|
||||
example, under Linux these are generally start at /dev/sg0
|
||||
under FreeBSD these start at /dev/pass0).
|
||||
.P
|
||||
Under FreeBSD, 'camcontrol devlist' will tell you what SCSI devices you
|
||||
have, along with which 'pass' device controls them. Under Linux,
|
||||
"cat /proc/scsi/scsi" will tell you what SCSI devices you have.
|
||||
|
||||
.SH BUGS AND LIMITATIONS
|
||||
.P
|
||||
This program has only been tested on Linux with a limited number of
|
||||
tape drives (HP DDS4, Seagate AIT).
|
||||
.P
|
||||
.SH AVAILABILITY
|
||||
.B tapeinfo
|
||||
is currently being maintained by Robert Nelson <robertnelson@users.sourceforge.net>
|
||||
as part of the 'mtx' suite of programs. The 'mtx' home page is
|
||||
http://mtx.sourceforge.net and the actual code is currently available there and via
|
||||
SVN from http://sourceforge.net/projects/mtx.
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR mt (1), mtx (1), scsitape (1), scsieject (1), loaderinfo (1)
|
||||
969
mtx-1.3.12/tapeinfo.c
Normal file
969
mtx-1.3.12/tapeinfo.c
Normal file
@@ -0,0 +1,969 @@
|
||||
/* Copyright 2000 Enhanced Software Technologies Inc.
|
||||
* Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
|
||||
* Released under terms of the GNU General Public License as
|
||||
* required by the license on 'mtxl.c'.
|
||||
* $Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $
|
||||
* $Revision: 193 $
|
||||
*/
|
||||
|
||||
/*#define DEBUG_PARTITION */
|
||||
/*#define DEBUG 1 */
|
||||
|
||||
/* What this does: This basically dumps out the contents of the following
|
||||
* pages:
|
||||
*
|
||||
* Inquiry -- prints full inquiry info. If it's not a tape drive, this is
|
||||
* the end of things.
|
||||
* DeviceType:
|
||||
* Manufacturer:
|
||||
* ProdID:
|
||||
* ProdRevision:
|
||||
*
|
||||
* Log Sense: TapeAlert Page (if supported):
|
||||
* TapeAlert:[message#]<Message> e.g. "TapeAlert:[22]Cleaning Cartridge Worn Out"
|
||||
*
|
||||
* Mode Sense:
|
||||
* Data Compression Page:
|
||||
* DataCompEnabled:<yes|no>
|
||||
* DataCompCapable:<yes|no>
|
||||
* DataDeCompEnabled:<yes|no>
|
||||
* CompType:<number>
|
||||
* DeCompType:<number>
|
||||
*
|
||||
* Device Configuration Page:
|
||||
* ActivePartition:<#>
|
||||
* DevConfigComp:<#> -- the compression byte in device config page.
|
||||
* EarlyWarningSize:<#> -- size of early warning buffer?
|
||||
*
|
||||
* Medium Partition Page:
|
||||
* NumPartitions:<#>
|
||||
* MaxPartitions:<#>
|
||||
* Partition[0]:<size>
|
||||
* Partition[1]:<size>...
|
||||
*
|
||||
* Read Block Limits command:
|
||||
* MinBlock:<#> -- Minimum block size.
|
||||
* MaxBlock:<#> -- Maximum block size.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "mtx.h"
|
||||
#include "mtxl.h"
|
||||
|
||||
char *argv0;
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
FatalError("Usage: tapeinfo -f <generic-device>\n");
|
||||
}
|
||||
|
||||
/* A table for printing out the peripheral device type as ASCII. */
|
||||
static char *PeripheralDeviceType[32] =
|
||||
{
|
||||
"Disk Drive",
|
||||
"Tape Drive",
|
||||
"Printer",
|
||||
"Processor",
|
||||
"Write-once",
|
||||
"CD-ROM",
|
||||
"Scanner",
|
||||
"Optical",
|
||||
"Medium Changer",
|
||||
"Communications",
|
||||
"ASC IT8",
|
||||
"ASC IT8",
|
||||
"RAID Array",
|
||||
"Enclosure Services",
|
||||
"OCR/W",
|
||||
"Bridging Expander", /* 0x10 */
|
||||
"Reserved", /* 0x11 */
|
||||
"Reserved", /* 0x12 */
|
||||
"Reserved", /* 0x13 */
|
||||
"Reserved", /* 0x14 */
|
||||
"Reserved", /* 0x15 */
|
||||
"Reserved", /* 0x16 */
|
||||
"Reserved", /* 0x17 */
|
||||
"Reserved", /* 0x18 */
|
||||
"Reserved", /* 0x19 */
|
||||
"Reserved", /* 0x1a */
|
||||
"Reserved", /* 0x1b */
|
||||
"Reserved", /* 0x1c */
|
||||
"Reserved", /* 0x1d */
|
||||
"Reserved", /* 0x1e */
|
||||
"Unknown" /* 0x1f */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* we call it MediumChangerFD for history reasons, sigh. */
|
||||
|
||||
/* now to print inquiry information: Copied from other one.... */
|
||||
|
||||
static void ReportInquiry(DEVICE_TYPE MediumChangerFD)
|
||||
{
|
||||
RequestSense_T RequestSense;
|
||||
Inquiry_T *Inquiry;
|
||||
int i;
|
||||
|
||||
Inquiry = RequestInquiry(MediumChangerFD, &RequestSense);
|
||||
if (Inquiry == NULL)
|
||||
{
|
||||
PrintRequestSense(&RequestSense);
|
||||
FatalError("INQUIRY Command Failed\n");
|
||||
}
|
||||
|
||||
printf("Product Type: %s\n", PeripheralDeviceType[Inquiry->PeripheralDeviceType]);
|
||||
|
||||
printf("Vendor ID: '");
|
||||
for (i = 0; i < sizeof(Inquiry->VendorIdentification); i++)
|
||||
printf("%c", Inquiry->VendorIdentification[i]);
|
||||
|
||||
printf("'\nProduct ID: '");
|
||||
for (i = 0; i < sizeof(Inquiry->ProductIdentification); i++)
|
||||
printf("%c", Inquiry->ProductIdentification[i]);
|
||||
|
||||
printf("'\nRevision: '");
|
||||
for (i = 0; i < sizeof(Inquiry->ProductRevisionLevel); i++)
|
||||
printf("%c", Inquiry->ProductRevisionLevel[i]);
|
||||
printf("'\n");
|
||||
|
||||
if (Inquiry->MChngr)
|
||||
{
|
||||
/* check the attached-media-changer bit... */
|
||||
printf("Attached Changer API: Yes\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Attached Changer API: No\n");
|
||||
}
|
||||
|
||||
free(Inquiry); /* well, we're about to exit, but ... */
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Okay, now for the Log Sense Tape Alert Page (if supported): */
|
||||
#define TAPEALERT_SIZE 2048 /* max size of tapealert buffer. */
|
||||
#define MAX_TAPE_ALERT 0x41
|
||||
|
||||
static char *tapealert_messages[] =
|
||||
{
|
||||
"Undefined", /* 0 */
|
||||
" Read: Having problems reading (slowing down)", /* 1 */
|
||||
" Write: Having problems writing (losing capacity)", /* 2 */
|
||||
" Hard Error: Uncorrectable read/write error", /* 3 */
|
||||
" Media: Media Performance Degraded, Data Is At Risk", /* 4 */
|
||||
" Read Failure: Tape faulty or tape drive broken", /* 5 */
|
||||
"Write Failure: Tape faulty or tape drive broken", /* 6 */
|
||||
" Media Life: The tape has reached the end of its useful life", /* 7 */
|
||||
"Not Data Grade:Replace cartridge with one containing data grade tape",/*8*/
|
||||
"Write Protect: Attempted to write to a write-protected cartridge",/*9 */
|
||||
" No Removal: Cannot unload, initiator is preventing media removal", /*a*/
|
||||
"Cleaning Media:Cannot back up or restore to a cleaning cartridge", /* b */
|
||||
" Bad Format: The loaded tape contains data in an unsupported format", /*c */
|
||||
" Snapped Tape: The data cartridge contains a broken tape", /* d */
|
||||
"Undefined", /* e */
|
||||
"Undefined", /* f */
|
||||
"Undefined", /* 10 */
|
||||
"Undefined", /* 11 */
|
||||
"Undefined", /* 12 */
|
||||
"Undefined", /* 13 */
|
||||
" Clean Now: The tape drive neads cleaning NOW", /* 0x14 */
|
||||
"Clean Periodic:The tape drive needs to be cleaned at next opportunity", /* 0x15 */
|
||||
"Cleaning Media:Cannot clean because cleaning cartridge used up, insert new cleaning cartridge to clean the drive", /* 0x16 */
|
||||
"Undefined", /* 0x17 */
|
||||
"Undefined", /* 0x18 */
|
||||
"Undefined", /* 0x19 */
|
||||
"Undefined", /* 0x1a */
|
||||
"Undefined", /* 0x1b */
|
||||
"Undefined", /* 0x1c */
|
||||
"Undefined", /* 0x1d */
|
||||
" Hardware A: Tape drive has a problem not read/write related", /* 0x1e */
|
||||
" Hardware B: Tape drive has a problem not read/write related", /* 0x1f */
|
||||
" Interface: Problem with SCSI interface between tape drive and initiator", /* 0x20 */
|
||||
" Eject Media: The current operation has failed. Eject and reload media", /* 0x21 */
|
||||
"Download Fail: Attempt to download new firmware failed", /* 0x22 */
|
||||
"Undefined", /* 0x23 */
|
||||
"Undefined", /* 0x24 */
|
||||
"Undefined", /* 0x25 */
|
||||
"Undefined", /* 0x26 */
|
||||
"Undefined", /* 0x27 */
|
||||
"Loader Hardware A: Changer having problems communicating with tape drive", /* 0x28 40 */
|
||||
"Loader Stray Tape: Stray tape left in drive from prior error", /* 0x29 41 */
|
||||
"Loader Hardware B: Autoloader mechanism has a fault", /* 0x2a 42 */
|
||||
" Loader Door: Loader door is open, please close it", /* 0x2b 43 */
|
||||
"Undefined", /* 0x2c */
|
||||
"Undefined", /* 0x2d */
|
||||
"Undefined", /* 0x2e */
|
||||
"Undefined", /* 0x2f */
|
||||
"Undefined", /* 0x30 */
|
||||
"Undefined", /* 0x31 */
|
||||
"Undefined", /* 0x32 */
|
||||
"Undefined", /* 0x33 */
|
||||
"Undefined", /* 0x34 */
|
||||
"Undefined", /* 0x35 */
|
||||
"Undefined", /* 0x36 */
|
||||
"Undefined", /* 0x37 */
|
||||
"Undefined", /* 0x38 */
|
||||
"Undefined", /* 0x39 */
|
||||
"Undefined", /* 0x3a */
|
||||
"Undefined", /* 0x3b */
|
||||
"Undefined", /* 0x3c */
|
||||
"Undefined", /* 0x3d */
|
||||
"Undefined", /* 0x3e */
|
||||
"Undefined", /* 0x3f */
|
||||
"Undefined" /* 0x40 */
|
||||
};
|
||||
|
||||
typedef struct TapeCapacityStruct
|
||||
{
|
||||
unsigned int partition0_remaining;
|
||||
unsigned int partition1_remaining;
|
||||
unsigned int partition0_size;
|
||||
unsigned int partition1_size;
|
||||
} TapeCapacity;
|
||||
|
||||
#if defined(DEBUG)
|
||||
/* DEBUG */
|
||||
static void dump_data(unsigned char *data, int len)
|
||||
{
|
||||
if (len != 0)
|
||||
{
|
||||
fprintf(stderr,"DATA:");
|
||||
PrintHex(1, data, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "**NO DATA**\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Request the tape capacity page defined by some DAT autoloaders. */
|
||||
|
||||
static TapeCapacity *RequestTapeCapacity(DEVICE_TYPE fd, RequestSense_T *sense)
|
||||
{
|
||||
CDB_T CDB;
|
||||
TapeCapacity *result;
|
||||
int result_len;
|
||||
|
||||
unsigned char buffer[TAPEALERT_SIZE]; /* Overkill, but ... */
|
||||
|
||||
slow_bzero((char *)buffer,TAPEALERT_SIZE); /*zero it... */
|
||||
|
||||
/* now to create the CDB block: */
|
||||
CDB[0] = 0x4d; /* Log Sense */
|
||||
CDB[1] = 0;
|
||||
CDB[2] = 0x31; /* Tape Capacity Page. */
|
||||
CDB[3] = 0;
|
||||
CDB[4] = 0;
|
||||
CDB[5] = 0;
|
||||
CDB[6] = 0;
|
||||
CDB[7] = TAPEALERT_SIZE >> 8 & 0xff; /* hi byte, allocation size */
|
||||
CDB[8] = TAPEALERT_SIZE & 0xff; /* lo byte, allocation size */
|
||||
CDB[9] = 0; /* reserved */
|
||||
|
||||
if (SCSI_ExecuteCommand(fd, Input, &CDB, 10, buffer, TAPEALERT_SIZE, sense) != 0)
|
||||
{
|
||||
/* fprintf(stderr,"RequestTapeCapacity: Command failed: Log Sense\n"); */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* dump_data(buffer,64); */
|
||||
|
||||
/* okay, we have stuff in the result buffer: the first 4 bytes are a header:
|
||||
* byte 0 should be 0x31, byte 1 == 0, bytes 2,3 tell how long the
|
||||
* log page is.
|
||||
*/
|
||||
if ((buffer[0]&0x3f) != 0x31)
|
||||
{
|
||||
/* fprintf(stderr,"RequestTapeCapacity: Invalid header for page (not 0x31).\n"); */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result_len = ((int)buffer[2] << 8) + buffer[3];
|
||||
|
||||
if (result_len != 32)
|
||||
{
|
||||
/* fprintf(stderr,"RequestTapeCapacity: Page was %d bytes long, not 32 bytes\n",result_len); */
|
||||
return NULL; /* This Is Not The Page You're Looking For */
|
||||
}
|
||||
|
||||
result = xmalloc(sizeof(TapeCapacity));
|
||||
|
||||
/* okay, now allocate data and move the buffer over there: */
|
||||
|
||||
/* 0 1 2 3 4 5 6 7 8 9
|
||||
DATA: 31 00 00 20 00 01 4c 04 01 3a
|
||||
10 11 12 13 14 15 16 17 18 19
|
||||
DATA: 81 0c 00 02 4c 04 00 00 00 00
|
||||
20 21 22 23 24 25 26 27 28 29
|
||||
DATA: 00 03 4c 04 01 3f 4b 1f 00 04
|
||||
30 31 32 33 34 35
|
||||
DATA: 4c 04 00 00 00 00 00 00 00 00
|
||||
DATA: 00 00 00 00 00 00 00 00 00 00
|
||||
DATA: 00 00 00 00 00 00 00 00 00 00
|
||||
DATA: 00 00 00 00
|
||||
*/
|
||||
|
||||
result->partition0_remaining =
|
||||
((unsigned int)buffer[8] << 24) +
|
||||
((unsigned int)buffer[9] << 16) +
|
||||
((unsigned int)buffer[10] << 8) +
|
||||
buffer[11];
|
||||
|
||||
result->partition1_remaining =
|
||||
((unsigned int)buffer[16] << 24) +
|
||||
((unsigned int)buffer[17] << 16) +
|
||||
((unsigned int)buffer[18] << 8) +
|
||||
buffer[19];
|
||||
|
||||
result->partition0_size =
|
||||
((unsigned int)buffer[24] << 24) +
|
||||
((unsigned int)buffer[25] << 16) +
|
||||
((unsigned int)buffer[26] << 8) +
|
||||
buffer[27];
|
||||
|
||||
result->partition1_size =
|
||||
((unsigned int)buffer[32] << 24) +
|
||||
((unsigned int)buffer[33] << 16) +
|
||||
((unsigned int)buffer[34] << 8) +
|
||||
buffer[35];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct tapealert_struct
|
||||
{
|
||||
int length;
|
||||
unsigned char *data;
|
||||
};
|
||||
|
||||
static struct tapealert_struct *RequestTapeAlert(DEVICE_TYPE fd, RequestSense_T *sense)
|
||||
{
|
||||
CDB_T CDB;
|
||||
|
||||
struct tapealert_struct *result;
|
||||
int i, tapealert_len, result_idx;
|
||||
|
||||
unsigned char buffer[TAPEALERT_SIZE];
|
||||
unsigned char *walkptr;
|
||||
|
||||
slow_bzero((char *)buffer, TAPEALERT_SIZE); /*zero it... */
|
||||
|
||||
/* now to create the CDB block: */
|
||||
CDB[0] = 0x4d; /* Log Sense */
|
||||
CDB[1] = 0;
|
||||
CDB[2] = 0x2e; /* Tape Alert Page. */
|
||||
CDB[3] = 0;
|
||||
CDB[4] = 0;
|
||||
CDB[5] = 0;
|
||||
CDB[6] = 0;
|
||||
CDB[7] = TAPEALERT_SIZE >> 8 & 0xff; /* hi byte, allocation size */
|
||||
CDB[8] = TAPEALERT_SIZE & 0xff; /* lo byte, allocation size */
|
||||
CDB[9] = 0; /* reserved */
|
||||
|
||||
if (SCSI_ExecuteCommand(fd,Input,&CDB,10,buffer,TAPEALERT_SIZE,sense)!=0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = xmalloc(sizeof(struct tapealert_struct));
|
||||
|
||||
/* okay, we have stuff in the result buffer: the first 4 bytes are a header:
|
||||
* byte 0 should be 0x2e, byte 1 == 0, bytes 2,3 tell how long the
|
||||
* tapealert page is.
|
||||
*/
|
||||
if ((buffer[0]&0x3f) != 0x2e)
|
||||
{
|
||||
result->data = NULL;
|
||||
result->length = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
tapealert_len = ((int)buffer[2] << 8) + buffer[3];
|
||||
|
||||
if (!tapealert_len)
|
||||
{
|
||||
result->length = 0;
|
||||
result->data = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* okay, now allocate data and move the buffer over there: */
|
||||
result->length = MAX_TAPE_ALERT;
|
||||
result->data = xzmalloc(MAX_TAPE_ALERT); /* alloc & zero. */
|
||||
|
||||
walkptr = &buffer[4];
|
||||
i = 0;
|
||||
|
||||
while (i < tapealert_len)
|
||||
{
|
||||
result_idx=(((int)walkptr[0])<<8) + walkptr[1]; /* the parameter #. */
|
||||
if (result_idx > 0 && result_idx < MAX_TAPE_ALERT)
|
||||
{
|
||||
if (walkptr[4])
|
||||
{
|
||||
result->data[result_idx] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
result->data[result_idx] = 0;
|
||||
}
|
||||
#ifdef DEBUGOLD1
|
||||
fprintf(stderr,"Alert[0x%x]=%d\n",result_idx,result->data[result_idx]);
|
||||
fflush(stderr);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
FatalError("Invalid tapealert page: %d\n",result_idx);
|
||||
}
|
||||
|
||||
i = i + 4 + walkptr[3]; /* length byte! */
|
||||
walkptr = walkptr + 4 + walkptr[3]; /* next! */
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void ReportTapeCapacity(DEVICE_TYPE fd)
|
||||
{
|
||||
/* we actually ignore a bad sense reading, like might happen if the
|
||||
* tape drive does not support the tape capacity page.
|
||||
*/
|
||||
|
||||
RequestSense_T RequestSense;
|
||||
|
||||
TapeCapacity *result;
|
||||
|
||||
result=RequestTapeCapacity(fd,&RequestSense);
|
||||
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
printf("Partition 0 Remaining Kbytes: %d\n", result->partition0_remaining);
|
||||
printf("Partition 0 Size in Kbytes: %d\n", result->partition0_size);
|
||||
|
||||
if (result->partition1_size)
|
||||
{
|
||||
printf("Partition 1 Remaining Kbytes: %d\n", result->partition1_remaining);
|
||||
printf("Partition 1 Size in Kbytes: %d\n", result->partition1_size);
|
||||
}
|
||||
|
||||
free(result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void ReportTapeAlert(DEVICE_TYPE fd)
|
||||
{
|
||||
/* we actually ignore a bad sense reading, like might happen if the
|
||||
* tape drive does not support the tapealert page.
|
||||
*/
|
||||
|
||||
RequestSense_T RequestSense;
|
||||
|
||||
struct tapealert_struct *result;
|
||||
int i;
|
||||
|
||||
result=RequestTapeAlert(fd,&RequestSense);
|
||||
|
||||
if (!result)
|
||||
return; /* sorry. Don't print sense here. */
|
||||
|
||||
if (!result->length)
|
||||
return; /* sorry, no alerts valid. */
|
||||
|
||||
for (i = 0; i < result->length; i++)
|
||||
{
|
||||
if (result->data[i])
|
||||
{
|
||||
printf("TapeAlert[%d]: %s.\n", i, tapealert_messages[i]);
|
||||
}
|
||||
}
|
||||
|
||||
free(result->data);
|
||||
free(result);
|
||||
}
|
||||
|
||||
static unsigned char
|
||||
*mode_sense(DEVICE_TYPE fd, char pagenum, int alloc_len, RequestSense_T *RequestSense)
|
||||
{
|
||||
CDB_T CDB;
|
||||
|
||||
unsigned char *input_buffer;
|
||||
unsigned char *tmp;
|
||||
unsigned char *retval;
|
||||
int i, pagelen;
|
||||
|
||||
if (alloc_len > 255)
|
||||
{
|
||||
FatalError("mode_sense(6) can only read up to 255 characters!\n");
|
||||
}
|
||||
|
||||
input_buffer = (unsigned char *)xzmalloc(256); /* overdo it, eh? */
|
||||
|
||||
/* clear the sense buffer: */
|
||||
slow_bzero((char *)RequestSense, sizeof(RequestSense_T));
|
||||
|
||||
/* returns an array of bytes in the page, or, if not possible, NULL. */
|
||||
CDB[0] = 0x1a; /* Mode Sense(6) */
|
||||
CDB[1] = 0;
|
||||
CDB[2] = pagenum; /* the page to read. */
|
||||
CDB[3] = 0;
|
||||
CDB[4] = 255; /* allocation length. This does max of 256 bytes! */
|
||||
CDB[5] = 0;
|
||||
|
||||
if (SCSI_ExecuteCommand(fd, Input, &CDB, 6, input_buffer, 255, RequestSense) != 0)
|
||||
{
|
||||
#ifdef DEBUG_MODE_SENSE
|
||||
fprintf(stderr,"Could not execute mode sense...\n");
|
||||
fflush(stderr);
|
||||
#endif
|
||||
return NULL; /* sorry, couldn't do it. */
|
||||
}
|
||||
|
||||
/* Oh hell, write protect is the only thing I have: always print
|
||||
* it if our mode page was 0x0fh, before skipping past buffer:
|
||||
* if the media is *NOT* write protected, just skip, sigh.
|
||||
*
|
||||
* Oh poops, the blocksize is reported in the block descriptor header
|
||||
* < * too. Again, just print if our mode page was 0x0f...
|
||||
*/
|
||||
if (pagenum == 0x0f)
|
||||
{
|
||||
int blocklen;
|
||||
|
||||
if (input_buffer[2] & 0x80)
|
||||
{
|
||||
printf("WriteProtect: yes\n");
|
||||
}
|
||||
|
||||
if (input_buffer[2] & 0x70)
|
||||
{
|
||||
printf("BufferedMode: yes\n");
|
||||
}
|
||||
|
||||
if (input_buffer[1] )
|
||||
{
|
||||
printf("Medium Type: 0x%x\n", input_buffer[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Medium Type: Not Loaded\n");
|
||||
}
|
||||
|
||||
printf("Density Code: 0x%x\n", input_buffer[4]);
|
||||
/* Put out the block size: */
|
||||
|
||||
blocklen = ((int)input_buffer[9] << 16)+
|
||||
((int)input_buffer[10] << 8)+
|
||||
input_buffer[11];
|
||||
|
||||
printf("BlockSize: %d\n", blocklen);
|
||||
}
|
||||
|
||||
/* First skip past any header.... */
|
||||
tmp = input_buffer + 4 + input_buffer[3];
|
||||
|
||||
/* now find out real length of page... */
|
||||
pagelen = tmp[1] + 2;
|
||||
retval = xmalloc(pagelen);
|
||||
|
||||
/* and copy our data to the new page. */
|
||||
for (i=0;i<pagelen;i++)
|
||||
{
|
||||
retval[i]=tmp[i];
|
||||
}
|
||||
|
||||
/* okay, free our input buffer: */
|
||||
free(input_buffer);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
#define DCE_MASK 0x80
|
||||
#define DCC_MASK 0x40
|
||||
#define DDE_MASK 0x80
|
||||
|
||||
static void ReportCompressionPage(DEVICE_TYPE fd)
|
||||
{
|
||||
/* actually ignore a bad sense reading, like might happen if the tape
|
||||
* drive does not support the mode sense compression page.
|
||||
*/
|
||||
|
||||
RequestSense_T RequestSense;
|
||||
|
||||
unsigned char *compression_page;
|
||||
|
||||
compression_page=mode_sense(fd,0x0f,16,&RequestSense);
|
||||
|
||||
if (!compression_page)
|
||||
{
|
||||
return; /* sorry! */
|
||||
}
|
||||
|
||||
/* Okay, we now have the compression page. Now print stuff from it: */
|
||||
printf("DataCompEnabled: %s\n", (compression_page[2] & DCE_MASK)? "yes" : "no");
|
||||
printf("DataCompCapable: %s\n", (compression_page[2] & DCC_MASK)? "yes" : "no");
|
||||
printf("DataDeCompEnabled: %s\n", (compression_page[3] & DDE_MASK)? "yes" : "no");
|
||||
printf("CompType: 0x%x\n",
|
||||
(compression_page[4] << 24) +
|
||||
(compression_page[5] << 16) +
|
||||
(compression_page[6] << 8) +
|
||||
compression_page[7]);
|
||||
|
||||
printf("DeCompType: 0x%x\n",
|
||||
(compression_page[8] << 24) +
|
||||
(compression_page[9] << 16) +
|
||||
(compression_page[10] << 8) +
|
||||
compression_page[11]);
|
||||
|
||||
free(compression_page);
|
||||
}
|
||||
|
||||
/* Now for the device configuration mode page: */
|
||||
|
||||
static void ReportConfigPage(DEVICE_TYPE fd)
|
||||
{
|
||||
RequestSense_T RequestSense;
|
||||
unsigned char *config_page;
|
||||
|
||||
config_page = mode_sense(fd, 0x10, 16, &RequestSense);
|
||||
if (!config_page)
|
||||
return;
|
||||
|
||||
/* Now to print the stuff: */
|
||||
printf("ActivePartition: %d\n", config_page[3]);
|
||||
|
||||
/* The following does NOT work accurately on any tape drive I know of... */
|
||||
/* printf("DevConfigComp: %s\n", config_page[14] ? "yes" : "no"); */
|
||||
printf("EarlyWarningSize: %d\n",
|
||||
(config_page[11] << 16) +
|
||||
(config_page[12] << 8) +
|
||||
config_page[13]);
|
||||
}
|
||||
|
||||
/* ***************************************
|
||||
* Medium Partition Page:
|
||||
*
|
||||
* The problem here, as we oh so graphically demonstrated during debugging
|
||||
* of the Linux 'st' driver :-), is that there are actually *TWO* formats for
|
||||
* the Medium Partition Page: There is the "long" format, where there is a
|
||||
* partition size word for each partition on the page, and there is a "short"
|
||||
* format, beloved of DAT drives, which only has a partition size word for
|
||||
* partition #1 (and no partition size word for partition #0, and no
|
||||
* provisions for any more partitions). So we must look at the size and
|
||||
* # of partitions defined to know what to report as what.
|
||||
*
|
||||
********************************************/
|
||||
|
||||
static void ReportPartitionPage(DEVICE_TYPE fd)
|
||||
{
|
||||
RequestSense_T RequestSense;
|
||||
unsigned char *partition_page;
|
||||
|
||||
int num_parts,max_parts;
|
||||
int i;
|
||||
|
||||
partition_page=mode_sense(fd,0x11,255,&RequestSense);
|
||||
if (!partition_page)
|
||||
return;
|
||||
|
||||
/* Okay, now we have either old format or new format: */
|
||||
num_parts = partition_page[3];
|
||||
max_parts = partition_page[2];
|
||||
|
||||
printf("NumPartitions: %d\n", num_parts);
|
||||
printf("MaxPartitions: %d\n", max_parts);
|
||||
|
||||
if (!num_parts)
|
||||
{
|
||||
/* if no additional partitions, then ... */
|
||||
free(partition_page);
|
||||
return;
|
||||
}
|
||||
|
||||
/* we know we have at least one partition if we got here. Check the
|
||||
* page size field. If it is 8 or below, then we are the old format....
|
||||
*/
|
||||
|
||||
#ifdef DEBUG_PARTITION
|
||||
fprintf(stderr,"partition_page[1]=%d\n",partition_page[1]);
|
||||
fflush(stderr);
|
||||
#endif
|
||||
if (partition_page[1]==8)
|
||||
{
|
||||
/* old-style! */
|
||||
printf("Partition1: %d\n",(partition_page[8]<<8)+partition_page[9]);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* new-style! */
|
||||
for (i=0;i<=max_parts;i++)
|
||||
{
|
||||
#ifdef DEBUG_PARTITION
|
||||
fprintf(stderr,"partition%d:[%d]%d [%d]%d\n", i, 8 + i * 2,
|
||||
partition_page[8+i*2]<<8, 9+i*2,partition_page[9 + i * 2]);
|
||||
fflush(stderr);
|
||||
#endif
|
||||
printf("Partition%d: %d\n", i,
|
||||
(partition_page[8 + i * 2] << 8) + partition_page[9 + i * 2]);
|
||||
}
|
||||
}
|
||||
free(partition_page);
|
||||
}
|
||||
|
||||
static void ReportSerialNumber(DEVICE_TYPE fd)
|
||||
{
|
||||
/* Actually ignore a bad sense reading, like might happen if the
|
||||
tape drive does not support the inquiry page 0x80.
|
||||
*/
|
||||
|
||||
RequestSense_T sense;
|
||||
CDB_T CDB;
|
||||
|
||||
#define WILD_SER_SIZE 30
|
||||
unsigned char buffer[WILD_SER_SIZE]; /* just wildly overestimate serial# length! */
|
||||
|
||||
int i, lim;
|
||||
char *bufptr;
|
||||
|
||||
CDB[0] = 0x12; /* INQUIRY */
|
||||
CDB[1] = 1; /* EVPD = 1 */
|
||||
CDB[2] = 0x80; /* The serial # page, hopefully. */
|
||||
CDB[3] = 0; /* reserved */
|
||||
CDB[4] = WILD_SER_SIZE;
|
||||
CDB[5] = 0;
|
||||
|
||||
if (SCSI_ExecuteCommand(fd, Input, &CDB, 6, &buffer, sizeof(buffer), &sense) != 0)
|
||||
{
|
||||
/* PrintRequestSense(&sense); */ /* zap debugging output :-) */
|
||||
/* printf("No Serial Number: None\n"); */
|
||||
return;
|
||||
}
|
||||
|
||||
/* okay, we have something in our buffer. Byte 3 should be the length of
|
||||
the sernum field, and bytes 4 onward are the serial #. */
|
||||
|
||||
lim = (int)buffer[3];
|
||||
bufptr = (char *)&(buffer[4]);
|
||||
|
||||
printf("SerialNumber: '");
|
||||
for (i=0;i<lim;i++)
|
||||
{
|
||||
putchar(*bufptr++);
|
||||
}
|
||||
printf("'\n");
|
||||
}
|
||||
|
||||
/* Read Block Limits! */
|
||||
|
||||
void ReportBlockLimits(DEVICE_TYPE fd)
|
||||
{
|
||||
RequestSense_T sense;
|
||||
CDB_T CDB;
|
||||
unsigned char buffer[6];
|
||||
|
||||
CDB[0] = 0x05; /* READ_BLOCK_LIMITS */
|
||||
CDB[1] = 0;
|
||||
CDB[2] = 0;
|
||||
CDB[3] = 0; /* 1-5 all unused. */
|
||||
CDB[4] = 0;
|
||||
CDB[5] = 0;
|
||||
|
||||
slow_bzero((char *)&sense,sizeof(RequestSense_T));
|
||||
if (SCSI_ExecuteCommand(fd, Input, &CDB, 6, buffer, 6, &sense) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* okay, but if we did get a result, print it: */
|
||||
printf("MinBlock: %d\n", (buffer[4] << 8) + buffer[5]);
|
||||
printf("MaxBlock: %d\n", (buffer[1] << 16) + (buffer[2]<<8) + buffer[3]);
|
||||
}
|
||||
|
||||
/* Do a READ_POSITION. This may not be always valid, but (shrug). */
|
||||
void ReadPosition(DEVICE_TYPE fd)
|
||||
{
|
||||
RequestSense_T sense;
|
||||
CDB_T CDB;
|
||||
unsigned char buffer[20];
|
||||
unsigned int position;
|
||||
|
||||
CDB[0] = 0x34; /* READ_POSITION */
|
||||
CDB[1] = 0;
|
||||
CDB[2] = 0;
|
||||
CDB[3] = 0; /* 1-9 all unused. */
|
||||
CDB[4] = 0;
|
||||
CDB[5] = 0;
|
||||
CDB[6] = 0;
|
||||
CDB[7] = 0;
|
||||
CDB[8] = 0;
|
||||
CDB[9] = 0;
|
||||
|
||||
slow_bzero((char *)&sense, sizeof(RequestSense_T));
|
||||
|
||||
SCSI_Set_Timeout(2); /* set timeout to 2 seconds! */
|
||||
|
||||
/* if we don't get a result (e.g. we issue this to a disk drive), punt. */
|
||||
if (SCSI_ExecuteCommand(fd, Input, &CDB, 10, buffer, 20, &sense) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SCSI_Default_Timeout(); /* reset it to 5 minutes, sigh! */
|
||||
/* okay, but if we did get a result, print it: */
|
||||
|
||||
#define RBL_BOP 0x80
|
||||
#define RBL_EOP 0x40
|
||||
#define RBL_BCU 0x20
|
||||
#define RBL_BYCU 0x10
|
||||
#define RBL_R1 0x08
|
||||
#define RBL_BPU 0x04
|
||||
#define RBL_PERR 0x02
|
||||
|
||||
/* If we have BOP, go ahead and print that. */
|
||||
if (buffer[0]&RBL_BOP)
|
||||
{
|
||||
printf("BOP: yes\n");
|
||||
}
|
||||
|
||||
/* if we have valid data, print it: */
|
||||
if (buffer[0]&RBL_BPU)
|
||||
{
|
||||
printf("Block Position: -1");
|
||||
}
|
||||
else
|
||||
{
|
||||
position = (unsigned int)(((unsigned int)buffer[4] << 24) +
|
||||
((unsigned int)buffer[5] << 16) +
|
||||
((unsigned int)buffer[6] << 8) +
|
||||
buffer[7]);
|
||||
|
||||
printf("Block Position: %d\n",position);
|
||||
}
|
||||
}
|
||||
|
||||
/* Test unit ready: This will tell us whether the tape drive
|
||||
* is currently ready to read or write.
|
||||
*/
|
||||
|
||||
int TestUnitReady(DEVICE_TYPE fd)
|
||||
{
|
||||
RequestSense_T sense;
|
||||
CDB_T CDB;
|
||||
unsigned char buffer[6];
|
||||
|
||||
CDB[0] = 0x00; /* TEST_UNIT_READY */
|
||||
CDB[1] = 0;
|
||||
CDB[2] = 0;
|
||||
CDB[3] = 0; /* 1-5 all unused. */
|
||||
CDB[4] = 0;
|
||||
CDB[5] = 0;
|
||||
|
||||
slow_bzero((char *)&sense,sizeof(RequestSense_T));
|
||||
if (SCSI_ExecuteCommand(fd,Input,&CDB,6,buffer,0,&sense)!=0)
|
||||
{
|
||||
printf("Ready: no\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("Ready: yes\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* We write a filemarks of 0 before going to grab position, in order
|
||||
* to insure that data in the buffer is not a problem.
|
||||
*/
|
||||
|
||||
int WriteFileMarks(DEVICE_TYPE fd,int count)
|
||||
{
|
||||
RequestSense_T sense;
|
||||
CDB_T CDB;
|
||||
unsigned char buffer[6];
|
||||
|
||||
CDB[0] = 0x10; /* WRITE_FILE_MARKS */
|
||||
CDB[1] = 0;
|
||||
CDB[2] = (unsigned char)(count >> 16);
|
||||
CDB[3] = (unsigned char)(count >> 8);
|
||||
CDB[4] = (unsigned char)count;
|
||||
CDB[5] = 0;
|
||||
|
||||
/* we really don't care if this command works or not, sigh. */
|
||||
slow_bzero((char *)&sense, sizeof(RequestSense_T));
|
||||
if (SCSI_ExecuteCommand(fd, Input, &CDB, 6, buffer, 0, &sense) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* This will get the SCSI ID and LUN of the target device, if such
|
||||
* is available from the OS. Currently only Linux supports this,
|
||||
* but other drivers could, if someone wants to write a
|
||||
* SCSI_GetIDLun function for them.
|
||||
*/
|
||||
#ifdef HAVE_GET_ID_LUN
|
||||
|
||||
static void ReportIDLun(DEVICE_TYPE fd)
|
||||
{
|
||||
scsi_id_t *scsi_id;
|
||||
|
||||
scsi_id = SCSI_GetIDLun(fd);
|
||||
printf("SCSI ID: %d\nSCSI LUN: %d\n", scsi_id->id, scsi_id->lun);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* we only have one argument: "-f <device>". */
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
DEVICE_TYPE fd;
|
||||
char *filename;
|
||||
|
||||
argv0=argv[0];
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
fprintf(stderr,"argc=%d",argc);
|
||||
usage();
|
||||
}
|
||||
|
||||
if (strcmp(argv[1],"-f")!=0)
|
||||
{
|
||||
usage();
|
||||
}
|
||||
filename=argv[2];
|
||||
|
||||
fd=SCSI_OpenDevice(filename);
|
||||
|
||||
/* Now to call the various routines: */
|
||||
ReportInquiry(fd);
|
||||
ReportSerialNumber(fd);
|
||||
ReportTapeAlert(fd);
|
||||
ReportBlockLimits(fd);
|
||||
|
||||
#ifdef HAVE_GET_ID_LUN
|
||||
ReportIDLun(fd);
|
||||
#endif
|
||||
|
||||
/* okay, we should only report position if the unit is ready :-(. */
|
||||
if (TestUnitReady(fd))
|
||||
{
|
||||
ReportCompressionPage(fd);
|
||||
ReadPosition(fd);
|
||||
ReportTapeCapacity(fd); /* only if we have it */
|
||||
ReportConfigPage(fd); /* only valid if unit is ready. */
|
||||
ReportPartitionPage(fd);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
175
mtx-1.3.12/vms/000readme
Normal file
175
mtx-1.3.12/vms/000readme
Normal file
@@ -0,0 +1,175 @@
|
||||
MTX -- SCSI Tape Attached Medium Changer Control Program
|
||||
|
||||
Copyright 1997 by Leonard N. Zubkoff <lnz@dandelion.com>
|
||||
|
||||
VMS port, April 1998, by TECSys Development, Inc.
|
||||
|
||||
SECTION I - Disclaimer
|
||||
|
||||
These programs / ports are distributed in the hopes that they
|
||||
will be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
While a significant amount of testing has been performed, and while
|
||||
TDI believes that this utility is safe, ONLY YOU can make that
|
||||
determination with respect to your environment. There are NO
|
||||
GUARANTEES WHATSOEVER that use of this program will not CRASH
|
||||
YOUR SYSTEM or worse. TDI disclaims any responsibility for any
|
||||
losses or damages from the use of this program.
|
||||
|
||||
SECTION II - MTX program
|
||||
|
||||
***CAUTIONS***
|
||||
* Attempting to check the status of the drive with 1 tape manually
|
||||
inserted in the drive, and no magazine results in an unexpected
|
||||
SCSI status message. During porting of this program on a VS4000/90a,
|
||||
it is believed that the handling of this status message caused
|
||||
some sort of scsi state problem wherein subsequent accesses to
|
||||
the changer from normal MKDRIVER activity resulted in SCSI bus
|
||||
phase errors and an ultimate system failure. Power cycles of both
|
||||
the drive and the host were required to rectify the problem.
|
||||
|
||||
Instructions:
|
||||
Read instructions (particularly section III below on the LDRSET utility).
|
||||
Compile (DEC C) and link image, copy to an appropriate install location
|
||||
Define a foreign symbol to access the program
|
||||
Use UNIX syntax to operate program per documentation (MTX.DOC)
|
||||
|
||||
A descrip.mms file is provided if you have MMS or MMK installed.
|
||||
You can build everything from scratch by doing a MMK/FROM_SOURCE. This
|
||||
includes the LDRSET utility described below. You should be in the mtx
|
||||
root directory before you do this, NOT [.vms].
|
||||
|
||||
If you do not have or use MMS or MMK, I can highly recommend MMK as
|
||||
a great tool. It is available from www.madgoat.com. If you still do
|
||||
not have mmk or mms, a build.com is provided. Again, you should be in
|
||||
the mtx root directory before you do this, NOT [.vms].
|
||||
|
||||
Note: If you are on an alpha, the mms[k]-built exe files will be called
|
||||
.alpha_exe, not .exe. Adjust following instructions accordingly.
|
||||
|
||||
Example:
|
||||
$ MMS/DESCRIP=[.VMS] !Or MMK, or @[.VMS]BUILD
|
||||
$ copy mtx.exe DISK$USERDISK:[USERS.FRED.UTILS]MTX
|
||||
$ MTX:==$DISK$USERDISK:[USERS.FRED.UTILS]MTX.EXE
|
||||
$ MTX -f MKA500 status
|
||||
--or--
|
||||
$ DEFINE TAPE MKA500
|
||||
$ MTX status
|
||||
|
||||
Notes:
|
||||
* This code does NOT compile under VAX C... the only issue is VAX C's
|
||||
incorrect assertion that a 'boolean' is not an acceptable "expression"
|
||||
on either side of a || operator. If you are on VAX C - upgrade. If you
|
||||
really must... then use a ((int)...) around the left-hand-side
|
||||
of the lines where the compiler complains.... like so:
|
||||
if (((int)StorageElementFull[FirstStorageElementNumber]) ||
|
||||
|
||||
* The following symbols result from 'status' or element movement commands:
|
||||
MTX_DTE (Data Transfer Element)
|
||||
FULL:n (Full, with element 'n'... if n=0, then unknown ele)
|
||||
EMPTY
|
||||
MTX_MSZ (Magazine SiZe)
|
||||
n (Number of magazine slots)
|
||||
MTX_STE01 thru MTX_STExx (STorage Element, Max is MTX_MSZ)
|
||||
FULL
|
||||
EMPTY
|
||||
These will allow a DCL program to process the results
|
||||
of the status command
|
||||
|
||||
* PHY_IO and DIAGNOSE are required to run the program as it stands
|
||||
today. Yes, the GKdriver dox say PHY_IO or LOG_IO.... MKdriver
|
||||
thinks otherwise. It wins.
|
||||
|
||||
* The program IS equipped to handle being installed with DIAGNOSE
|
||||
and PHY_IO. A certain level of checking is done to see that the
|
||||
right type of device is being targeted for the autoloader manipulation
|
||||
SCSI commands. [see next item]
|
||||
|
||||
* There is an indicator bit in DEVCHAR2 that indicates the presence of
|
||||
a loader on a tape. Unfortunately, it appears that the "knowledge" of
|
||||
whether a loader is present or not is hard-coded into mkdriver. This
|
||||
means that if you don't have the magic DEC rom's in your Archive
|
||||
loader, then the LDR bit is not set. This makes the LDR bit effectively
|
||||
useless unless you want to write a kernel dinker program you could
|
||||
run from startup to "fix" the DEVCHAR2 longword. (Incidentally,
|
||||
if you ship the autoloader commands at a TZ30 (a non-loader drive),
|
||||
the tz30 blows it off w/o any adverse side-effects - I would hope
|
||||
that other drives are as tolerant.)
|
||||
|
||||
Because of this misfeature, the code to check the LDR flag in DEVCHAR2
|
||||
is commented out.
|
||||
|
||||
*See section below on LDRSET utility if you want to use this
|
||||
feature anyway (recommended).
|
||||
|
||||
* This program has been tested under:
|
||||
VAX C V2.2, VAX/VMS 6.1, VS 4000/90A **with code modifications
|
||||
DEC C V5.2, VAX/VMS 6.1, VS 4000/90A
|
||||
DEC C V5.3, AXP/VMS 6.2, DEC3000-300X
|
||||
|
||||
|
||||
SECTION III - LDRSET Utility
|
||||
|
||||
Description:
|
||||
This is a small KERNEL MODE utility program to go set or reset
|
||||
the DEV$M_LDR flag in UCB$L_DEVCHAR2 for a specified device. While
|
||||
a certain amount of checking is performed, and while the author
|
||||
believes that this utility is safe, ONLY YOU can make that
|
||||
determination with respect to your environment. There are NO
|
||||
GUARANTEES WHATSOEVER that use of this program will not CRASH
|
||||
YOUR SYSTEM or worse. TDI disclaims any responsibility for any
|
||||
losses or damages from the use of this program.
|
||||
|
||||
With all that said... this utility can be used [example: system
|
||||
startup] to set the LDR flag for the autoloader tape device.
|
||||
With the loader flag properly set, you can re-enable the LDR
|
||||
check section in MTX and be fairly well certain that the MTX
|
||||
utility will not be used against a drive that is not a SCSI
|
||||
MAGTAPE with a LOADER attached.
|
||||
|
||||
Instructions:
|
||||
Compile (DEC C ***ONLY***) the LDRSET C program
|
||||
|
||||
Alpha:
|
||||
MACRO/MIGRATE the LDRUTIL.MAR program
|
||||
LINK LDRSET,LDRUTIL/SYSEXE to generate the image
|
||||
|
||||
Vax
|
||||
MACRO the LDRUTIL.MAR program
|
||||
LINK LDRSET,LDRUTIL to generate the image
|
||||
|
||||
[NOTE!!! ---> DO NOT USE RESULTING IMAGE IF THERE ARE ANY COMPILE OR LINK
|
||||
ERRORS!!!]
|
||||
|
||||
Copy to an appropriate install location.
|
||||
|
||||
Edit provided CLD file to reflect the installed location
|
||||
|
||||
Use the following syntax:
|
||||
$ SET COMMAND LDRSET
|
||||
$ LDRSET MKA500: /SET !Sets the loader present flag on MKA500
|
||||
$ LDRSET MKA500: /RESET !Clears the loader present flag on MKA500
|
||||
|
||||
Alpha example:
|
||||
$ CC/DECC/DEBUG/NOOPT LDRSET
|
||||
$ MACRO/MIGRATE LDRUTIL
|
||||
$ LINK LDRSET,LDRUTIL/SYSEXE
|
||||
|
||||
Vax example:
|
||||
$ CC/DECC/DEBUG/NOOPT LDRSET
|
||||
$ MACRO LDRUTIL
|
||||
$ LINK LDRSET,LDRUTIL
|
||||
|
||||
Common:
|
||||
$ copy LDRSET.EXE DISK$USERDISK:[USERS.FRED.UTILS]LDRSET.EXE
|
||||
$ copy LDRSET.CLD DISK$USERDISK:[USERS.FRED.UTILS]LDRSET.CLD
|
||||
$ EDIT DISK$USERDISK:[USERS.FRED.UTILS]LDRSET.CLD
|
||||
...change image sys$disk:[]ldrset line to :
|
||||
image DISK$USERDISK:[USERS.FRED.UTILS]LDRSET.EXE
|
||||
$ LDRSET MKA500 /SET
|
||||
|
||||
* This program has been tested under:
|
||||
DEC C V5.2, VAX/VMS 6.1, VS 4000/90A
|
||||
DEC C V5.6, AXP/VMS 7.1, AS 1000A
|
||||
|
||||
34
mtx-1.3.12/vms/build.com
Normal file
34
mtx-1.3.12/vms/build.com
Normal file
@@ -0,0 +1,34 @@
|
||||
$!x='f$ver(0)
|
||||
$ if f$parse("[.VMS]A.A").eqs.""
|
||||
$ then
|
||||
$ write sys$output "?Error: Use $ @[.VMS]BUILD from the mtx directory"
|
||||
$ exit 44
|
||||
$ endif
|
||||
$ alpha = f$getsyi("hw_model").ge.1024
|
||||
$ vax = .not.alpha
|
||||
$ exe = "EXE"
|
||||
$ obj = "OBJ"
|
||||
$ sysexe=""
|
||||
$ migrate=""
|
||||
$ if alpha then exe="ALPHA_EXE"
|
||||
$ if alpha then obj="ALPHA_OBJ"
|
||||
$ if alpha then sysexe="/SYSEXE"
|
||||
$ if alpha then migrate="/MIGRATION/NOOPT"
|
||||
$ set verify
|
||||
$ if "''p1'".eqs."LINK" then goto do_link
|
||||
$ CC /DECC/DEB/NOOP MTX.C/DEB/NOOP/OBJECT=MTX.'obj'
|
||||
$ if f$search("MTX.''obj';-1").nes."" then -
|
||||
purge/log MTX.'obj'
|
||||
$ CC /DECC/DEB/NOOP [.VMS]LDRSET.C/DEB/NOOP/OBJECT=[.VMS]LDRSET.'obj'
|
||||
$ if f$search("[.VMS]LDRSET.''obj';-1").nes."" then -
|
||||
purge/log [.VMS]LDRSET.'obj'
|
||||
$ MACRO'migrate' /DEB [.VMS]LDRUTIL.MAR -
|
||||
/OBJECT=[.VMS]LDRUTIL.'obj'
|
||||
$ if f$search("[.VMS]LDRUTIL.''obj';-1").nes."" then -
|
||||
purge/log [.VMS]LDRUTIL.'obj'
|
||||
$!
|
||||
$ do_link:
|
||||
$ link/notrace mtx.'obj'/exe=mtx.'exe'
|
||||
$ link [.vms]ldrset.'obj',[.vms]ldrutil.'obj' -
|
||||
/exe=ldrset.'exe' 'sysexe'
|
||||
$ exit
|
||||
42
mtx-1.3.12/vms/defs.h
Normal file
42
mtx-1.3.12/vms/defs.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifdef __DECC
|
||||
#pragma module MTX "V01-00"
|
||||
#else
|
||||
#module MTX "V01-00"
|
||||
#endif
|
||||
|
||||
typedef int DEVICE_TYPE;
|
||||
|
||||
#include <ssdef.h>
|
||||
#include <lib$routines.h>
|
||||
#include <ots$routines.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <iodef.h>
|
||||
#include <descrip.h>
|
||||
#include <dcdef.h>
|
||||
#include <devdef.h>
|
||||
#include <dvidef.h>
|
||||
#include <starlet.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <prvdef.h>
|
||||
|
||||
#if defined(__DECC)
|
||||
#pragma member_alignment save
|
||||
#pragma nomember_alignment
|
||||
#endif
|
||||
|
||||
/*
|
||||
Define either of the following symbols as 1 to enable checking of
|
||||
the LDR flag for specified devices. DO NOT set these bits if you
|
||||
do not 1) have a DEC-recognized autoloader, or 2) use the LDRSET
|
||||
utility to set the LDR flag for the target devices.
|
||||
*/
|
||||
|
||||
#define USING_DEC_DRIVE 0
|
||||
#define USING_LDRSET 0
|
||||
|
||||
static unsigned long VMS_ExitCode = SS$_ABORT;
|
||||
77
mtx-1.3.12/vms/descrip.mms
Normal file
77
mtx-1.3.12/vms/descrip.mms
Normal file
@@ -0,0 +1,77 @@
|
||||
!
|
||||
! MMS System build for MTX and LDRSET utility
|
||||
!
|
||||
!Global build flag macros
|
||||
!
|
||||
CDEBUG = /DEB/NOOP
|
||||
MDEBUG = /DEB
|
||||
|
||||
CFLAGS = /DECC$(CDEBUG)
|
||||
MFLAGS = $(MDEBUG)
|
||||
|
||||
.IFDEF __AXP__
|
||||
.SUFFIXES .ALPHA_OBJ
|
||||
MFLAGS = /MIGRATE$(MFLAGS)/NOOP
|
||||
DBG = .ALPHA_DBG
|
||||
EXE = .ALPHA_EXE
|
||||
OBJ = .ALPHA_OBJ
|
||||
OPT = .ALPHA_OPT
|
||||
SYSEXE=/SYSEXE
|
||||
|
||||
.ELSE
|
||||
DBG = .DBG
|
||||
EXE = .EXE
|
||||
OPT = .OPT
|
||||
OBJ = .OBJ
|
||||
SYSEXE=
|
||||
|
||||
.ENDIF
|
||||
|
||||
PURGEOBJ = if f$search("$(MMS$TARGET_NAME)$(OBJ);-1").nes."" then purge/log $(MMS$TARGET_NAME)$(OBJ)
|
||||
|
||||
!
|
||||
!Bend the default build rules for C, MACRO, and MESSAGE
|
||||
!
|
||||
.C$(OBJ) :
|
||||
$(CC) $(CFLAGS) $(MMS$SOURCE)$(CDEBUG)/OBJECT=$(MMS$TARGET_NAME)$(OBJ)
|
||||
$(PURGEOBJ)
|
||||
.MAR$(OBJ) :
|
||||
$(MACRO) $(MFLAGS) $(MMS$SOURCE)$(MDEBUG)/OBJECT=$(MMS$TARGET_NAME)$(OBJ)
|
||||
$(PURGEOBJ)
|
||||
.CLD$(OBJ) :
|
||||
SET COMMAND/OBJECT=$(MMS$TARGET_NAME)$(OBJ) $(MMS$SOURCE)
|
||||
$(PURGEOBJ)
|
||||
.MSG$(OBJ) :
|
||||
MESSAGE $(MMS$SOURCE)/OBJECT=$(MMS$TARGET_NAME)$(OBJ)
|
||||
$(PURGEOBJ)
|
||||
|
||||
|
||||
DEFAULT : ERROR,-
|
||||
MTX,-
|
||||
LDRSET
|
||||
@ !
|
||||
|
||||
ERROR :
|
||||
@ if f$parse("[.VMS]A.A").eqs."" then write sys$output "?Error: Use $ MMS/DESCRIP=[.VMS] from the mtx directory"
|
||||
|
||||
MTX : mtx$(EXE)
|
||||
@ !
|
||||
|
||||
mtx$(EXE) : mtx$(OBJ)
|
||||
$ link/notrace mtx$(OBJ)/exe=mtx$(EXE)
|
||||
|
||||
mtx$(OBJ) : mtx.c,[.vms]scsi.c,[.vms]defs.h
|
||||
|
||||
LDRSET : ldrset$(EXE),ldrset.cld
|
||||
@ !
|
||||
|
||||
ldrset.cld : [.vms]ldrset.cld
|
||||
$ copy [.vms]ldrset.cld []/log
|
||||
|
||||
ldrset$(EXE) : [.vms]ldrset$(OBJ),[.vms]ldrutil$(OBJ)
|
||||
$ link [.vms]ldrset$(OBJ),[.vms]ldrutil$(OBJ)/exe=ldrset$(EXE)$(SYSEXE)
|
||||
|
||||
[.vms]ldrset$(OBJ) : [.vms]ldrset.c
|
||||
|
||||
[.vms]ldrutil$(OBJ) : [.vms]ldrutil.mar
|
||||
|
||||
183
mtx-1.3.12/vms/ldrset.c
Normal file
183
mtx-1.3.12/vms/ldrset.c
Normal file
@@ -0,0 +1,183 @@
|
||||
/* LDRSET - Set the state of the LDR flag in UCB$L_DEVCHAR2 for a
|
||||
** SCSI magtape. REQUIRES CMKRNL privilege.
|
||||
**
|
||||
** Copyright 1999 by TECSys Development, Inc. http://www.tditx.com
|
||||
**
|
||||
** This program is free software; you may redistribute and/or modify it under
|
||||
** the terms of the GNU General Public License Version 2 as published by the
|
||||
** Free Software Foundation.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful, but
|
||||
** WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
|
||||
** or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
** for complete details.
|
||||
**
|
||||
** Description:
|
||||
** This is a small KERNEL MODE utility program to go set or reset
|
||||
** the DEV$M_LDR flag in UCB$L_DEVCHAR2 for a specified device. While
|
||||
** a certain amount of checking is performed, and while the author
|
||||
** believes that this utility is safe, ONLY YOU can make that
|
||||
** determination with respect to your environment. There are NO
|
||||
** GUARANTEES WHATSOEVER that use of this program will not CRASH
|
||||
** YOUR SYSTEM or worse. TDI disclaims any responsibility for any
|
||||
** losses or damages from the use of this program.
|
||||
**
|
||||
** With all that said... this utility can be used [example: system
|
||||
** startup] to set the LDR flag for the autoloader tape device.
|
||||
** With the loader flag properly set, you can re-enable the LDR
|
||||
** check section in MTX and be fairly well certain that the MTX
|
||||
** utility will not be used against a drive that is not a SCSI
|
||||
** MAGTAPE with a LOADER attached.
|
||||
**
|
||||
**
|
||||
** LDRSET.CLD:
|
||||
** define verb LDRSET
|
||||
** image sys$disk:[]ldrset.exe
|
||||
** parameter p1, label=device,
|
||||
** prompt="Device",
|
||||
** value(required,type=$FILE)
|
||||
** qualifier SET, nonnegatable
|
||||
** qualifier RESET, nonnegatable
|
||||
** disallow any2 (SET, RESET)
|
||||
** disallow NOT SET AND NOT RESET
|
||||
*/
|
||||
#ifdef __DECC
|
||||
#pragma module LDRSET "V01-00"
|
||||
#else
|
||||
#module LDRSET "V01-00"
|
||||
#endif
|
||||
|
||||
#include <ssdef.h>
|
||||
#include <dcdef.h>
|
||||
#include <devdef.h>
|
||||
#include <dvidef.h>
|
||||
#include <descrip.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <lib$routines.h>
|
||||
#include <starlet.h>
|
||||
|
||||
#ifndef DESCR_CNT
|
||||
#define DESCR_CNT 16
|
||||
/* MUST BE of the form 2^N!, big enough for max concurrent usage */
|
||||
#endif
|
||||
|
||||
static struct dsc$descriptor_s *
|
||||
descr(
|
||||
char *str)
|
||||
{
|
||||
static struct dsc$descriptor_s d_descrtbl[DESCR_CNT]; /* MAX usage! */
|
||||
static unsigned short int descridx=0;
|
||||
struct dsc$descriptor_s *d_ret = &d_descrtbl[descridx];
|
||||
|
||||
descridx = (descridx+1)&(DESCR_CNT-1);
|
||||
|
||||
d_ret->dsc$w_length = strlen((const char *)str);
|
||||
d_ret->dsc$a_pointer = (char *)str;
|
||||
|
||||
d_ret->dsc$b_class =
|
||||
d_ret->dsc$b_dtype = 0;
|
||||
return(d_ret);
|
||||
}
|
||||
|
||||
extern unsigned long int finducb();
|
||||
extern unsigned long int _setldr();
|
||||
extern unsigned long int _clrldr();
|
||||
|
||||
unsigned long int
|
||||
set_ldrstate(
|
||||
int devch,
|
||||
int setstate)
|
||||
{
|
||||
unsigned long int ret;
|
||||
struct ucbdef *ucb;
|
||||
|
||||
if (~(ret=finducb(devch,&ucb))&1)
|
||||
return(ret);
|
||||
|
||||
if (setstate)
|
||||
return(_setldr(ucb));
|
||||
else
|
||||
return(_clrldr(ucb));
|
||||
}
|
||||
|
||||
extern unsigned long int CLI$PRESENT();
|
||||
extern unsigned long int CLI$GET_VALUE();
|
||||
|
||||
static unsigned long int
|
||||
cld_special(
|
||||
char *kwd_name)
|
||||
{
|
||||
lib$establish(lib$sig_to_ret);
|
||||
return(CLI$PRESENT(descr(kwd_name)));
|
||||
}
|
||||
|
||||
int
|
||||
main(){
|
||||
unsigned long int ret;
|
||||
unsigned long int ismnt = 0;
|
||||
unsigned long int dvcls = 0;
|
||||
unsigned long int dchr2 = 0;
|
||||
struct itmlst_3 {
|
||||
unsigned short int ilen;
|
||||
unsigned short int code;
|
||||
unsigned long int *returnP;
|
||||
unsigned long int ignored;
|
||||
} dvi_itmlst[] = {
|
||||
{4, DVI$_MNT, 0/*&ismnt*/, 0},
|
||||
{4, DVI$_DEVCLASS, 0/*&dvcls*/, 0},
|
||||
{4, DVI$_DEVCHAR2, 0/*&dchr2*/, 0},
|
||||
{0,0,0,0} };
|
||||
unsigned long int iosb[2];
|
||||
struct dsc$descriptor_s *dp_tmp;
|
||||
struct dsc$descriptor_d dy_devn = { 0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0 };
|
||||
unsigned long int devch=0;
|
||||
|
||||
dvi_itmlst[0].returnP = &ismnt;
|
||||
dvi_itmlst[1].returnP = &dvcls;
|
||||
dvi_itmlst[2].returnP = &dchr2;
|
||||
|
||||
if (~(ret=CLI$PRESENT(dp_tmp=descr("DEVICE")))&1) {
|
||||
printf("?Error obtaining CLD DEVICE parameter\n");
|
||||
return(ret); }
|
||||
if (~(ret=CLI$GET_VALUE(dp_tmp,&dy_devn,0))&1) {
|
||||
printf("?Error obtaining CLD DEVICE value\n");
|
||||
return(ret); }
|
||||
|
||||
if (~(ret=sys$alloc(&dy_devn,0,0,0,0))&1) {
|
||||
printf("?Error allocating specified device\n");
|
||||
return(ret); }
|
||||
|
||||
if (~(ret=sys$assign(&dy_devn,&devch,0,0))&1) {
|
||||
printf("?Error assigning a channel to specified device\n");
|
||||
return(ret); }
|
||||
|
||||
if (~(ret=sys$getdviw(0,devch,0,&dvi_itmlst,&iosb,0,0,0))&1) {
|
||||
printf("?Error obtaining device information(1)\n");
|
||||
return(ret); }
|
||||
if (~(ret=iosb[0])&1) {
|
||||
printf("?Error obtaining device information(2)\n");
|
||||
return(ret); }
|
||||
|
||||
if (dvcls != DC$_TAPE) {
|
||||
printf("?Device is not a tape drive\n");
|
||||
return(SS$_IVDEVNAM); }
|
||||
|
||||
if (~dchr2 & DEV$M_SCSI) {
|
||||
printf("?Device is not a SCSI device\n");
|
||||
return(SS$_IVDEVNAM); }
|
||||
|
||||
if (ismnt) {
|
||||
printf("?Device is mounted\n");
|
||||
return(SS$_DEVMOUNT); }
|
||||
|
||||
if (cld_special("SET")&1)
|
||||
return(set_ldrstate(devch,1));
|
||||
|
||||
if (cld_special("RESET")&1)
|
||||
return(set_ldrstate(devch,0));
|
||||
|
||||
/* Either SET or RESET above must be present to win */
|
||||
printf("?CLD structural error - see source\n");
|
||||
return(SS$_BADPARAM);
|
||||
}
|
||||
9
mtx-1.3.12/vms/ldrset.cld
Normal file
9
mtx-1.3.12/vms/ldrset.cld
Normal file
@@ -0,0 +1,9 @@
|
||||
define verb LDRSET
|
||||
image sys$disk:[]ldrset.exe
|
||||
parameter p1, label=device,
|
||||
prompt="Device",
|
||||
value(required,type=$FILE)
|
||||
qualifier SET, nonnegatable
|
||||
qualifier RESET, nonnegatable
|
||||
disallow any2 (SET, RESET)
|
||||
disallow NOT SET AND NOT RESET
|
||||
104
mtx-1.3.12/vms/ldrutil.mar
Normal file
104
mtx-1.3.12/vms/ldrutil.mar
Normal file
@@ -0,0 +1,104 @@
|
||||
.title LDRUTIL - Obtain ucb for assigned channel
|
||||
.ident /LDRUTIL V1.0/
|
||||
; LDRUTIL - VMS UCB LDR bit utility library
|
||||
;
|
||||
; TECSys Development, Inc., April 1998
|
||||
;
|
||||
; This file may be copied under the terms and conditions of version 2
|
||||
; of the GNU General Public License, as published by the Free
|
||||
; Software Foundation (Cambridge, Massachusetts).
|
||||
;
|
||||
; This program is distributed in the hope that it will be useful,
|
||||
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
; GNU General Public License for more details.
|
||||
;
|
||||
; You should have received a copy of the GNU General Public License
|
||||
; along with this program; if not, write to the Free Software
|
||||
; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
;
|
||||
;
|
||||
.link "sys$system:sys.stb"/selective_search
|
||||
.library /sys$share:lib/
|
||||
|
||||
.NTYPE ...IS_IT_ALPHA,R22 ;Get the type of R22
|
||||
...IS_IT_ALPHA = <...IS_IT_ALPHA@-4&^XF>-5
|
||||
.IIF EQ,...IS_IT_ALPHA, ALPHA=1
|
||||
|
||||
$ssdef
|
||||
$ucbdef
|
||||
$ccbdef
|
||||
$chfdef
|
||||
$dcdef
|
||||
$devdef
|
||||
$pcbdef
|
||||
|
||||
.psect $$code,exe,rd,nowrt,shr
|
||||
.IF NDF,ALPHA
|
||||
.entry finducb,^m<r2,r3,r4,r5,r6,r7,r8,r9> ;Find UCB address from channel
|
||||
.IFF
|
||||
.call_entry, 2,home_args=TRUE,-
|
||||
preserve=<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>,-
|
||||
output=<r0,r1>,-
|
||||
label=finducb
|
||||
.endc
|
||||
movzwl 4(AP),r0 ;prep to find UCB
|
||||
jsb g^IOC$VERIFYCHAN ;callable from user mode!
|
||||
blbc r0,20$
|
||||
movl CCB$L_UCB(r1),@8(AP) ;save UCB address
|
||||
movzbl #1,r0
|
||||
20$: ret
|
||||
|
||||
.IF NDF,ALPHA
|
||||
.entry __setldr,^m<r2,r3,r4,r5,r6,r7,r8,r9> ;Find UCB address from channel
|
||||
.IFF
|
||||
.call_entry, 2,home_args=TRUE,-
|
||||
preserve=<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>,-
|
||||
output=<r0,r1>,-
|
||||
label=__setldr
|
||||
.endc
|
||||
movl 4(AP),r1
|
||||
bisl #DEV$M_LDR,UCB$L_DEVCHAR2(r1)
|
||||
movzbl #1,r0
|
||||
ret
|
||||
|
||||
.IF NDF,ALPHA
|
||||
.entry _setldr,^m<r2,r3,r4,r5,r6,r7,r8,r9> ;Find UCB address from channel
|
||||
.IFF
|
||||
.call_entry, 2,home_args=TRUE,-
|
||||
preserve=<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>,-
|
||||
output=<r0,r1>,-
|
||||
label=_setldr
|
||||
.endc
|
||||
$cmkrnl_s -
|
||||
routin = __setldr,-
|
||||
arglst = (AP)
|
||||
ret
|
||||
|
||||
.IF NDF,ALPHA
|
||||
.entry __clrldr,^m<r2,r3,r4,r5,r6,r7,r8,r9> ;Find UCB address from channel
|
||||
.IFF
|
||||
.call_entry, 2,home_args=TRUE,-
|
||||
preserve=<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>,-
|
||||
output=<r0,r1>,-
|
||||
label=__clrldr
|
||||
.endc
|
||||
movl 4(AP),r1
|
||||
bicl #DEV$M_LDR,UCB$L_DEVCHAR2(r1)
|
||||
movzbl #1,r0
|
||||
ret
|
||||
|
||||
.IF NDF,ALPHA
|
||||
.entry _clrldr,^m<r2,r3,r4,r5,r6,r7,r8,r9> ;Find UCB address from channel
|
||||
.IFF
|
||||
.call_entry, 2,home_args=TRUE,-
|
||||
preserve=<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>,-
|
||||
output=<r0,r1>,-
|
||||
label=_clrldr
|
||||
.endc
|
||||
$cmkrnl_s -
|
||||
routin = __clrldr,-
|
||||
arglst = (AP)
|
||||
ret
|
||||
|
||||
.end
|
||||
400
mtx-1.3.12/vms/scsi.c
Normal file
400
mtx-1.3.12/vms/scsi.c
Normal file
@@ -0,0 +1,400 @@
|
||||
/* SCSI.C - VMS-specific SCSI routines.
|
||||
**
|
||||
** TECSys Development, Inc., April 1998
|
||||
**
|
||||
** This module began life as a program called CDWRITE20, a CD-R control
|
||||
** program for VMS. No real functionality from the original CDWRITE20
|
||||
** is present in this module, but in the interest of making certain that
|
||||
** proper credit is given where it may be due, the copyrights and inclusions
|
||||
** from the CDWRITE20 program are included below.
|
||||
**
|
||||
** The portions of coding in this module ascribable to TECSys Development
|
||||
** are hereby also released under the terms and conditions of version 2
|
||||
** of the GNU General Public License as described below....
|
||||
*/
|
||||
|
||||
/* The remainder of these credits are included directly from the CDWRITE20
|
||||
** sources. */
|
||||
|
||||
/* Copyright 1994 Yggdrasil Computing, Inc. */
|
||||
/* Written by Adam J. Richter (adam@yggdrasil.com) */
|
||||
|
||||
/* Rewritten February 1997 by Eberhard Heuser-Hofmann*/
|
||||
/* using the OpenVMS generic scsi-interface */
|
||||
/* see the README-file, how to setup your machine */
|
||||
|
||||
/*
|
||||
** Modified March 1997 by John Vottero to use overlapped, async I/O
|
||||
** and lots of buffers to help prevent buffer underruns.
|
||||
** Also improved error reporting.
|
||||
*/
|
||||
|
||||
/* This file may be copied under the terms and conditions of version 2
|
||||
of the GNU General Public License, as published by the Free
|
||||
Software Foundation (Cambridge, Massachusetts).
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* The second notice comes from sys$examples:gktest.c (OpenVMS 7.0)*/
|
||||
|
||||
/*
|
||||
** COPYRIGHT (c) 1993 BY
|
||||
** DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASSACHUSETTS.
|
||||
** ALL RIGHTS RESERVED.
|
||||
**
|
||||
** THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED
|
||||
** ONLY IN ACCORDANCE OF THE TERMS OF SUCH LICENSE AND WITH THE
|
||||
** INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER
|
||||
** COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
|
||||
** OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY
|
||||
** TRANSFERRED.
|
||||
**
|
||||
** THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE
|
||||
** AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT
|
||||
** CORPORATION.
|
||||
**
|
||||
** DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS
|
||||
** SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL.
|
||||
*/
|
||||
|
||||
/*
|
||||
Define the Generic SCSI Command Descriptor.
|
||||
*/
|
||||
|
||||
typedef struct scsi$desc
|
||||
{
|
||||
unsigned int SCSI$L_OPCODE; /* SCSI Operation Code */
|
||||
unsigned int SCSI$L_FLAGS; /* SCSI Flags Bit Map */
|
||||
unsigned char *SCSI$A_CMD_ADDR; /* ->SCSI Command Buffer */
|
||||
unsigned int SCSI$L_CMD_LEN; /* SCSI Command Length (bytes) */
|
||||
unsigned char *SCSI$A_DATA_ADDR; /* ->SCSI Data Buffer */
|
||||
unsigned int SCSI$L_DATA_LEN; /* SCSI Data Length (bytes) */
|
||||
unsigned int SCSI$L_PAD_LEN; /* SCSI Pad Length (bytes) */
|
||||
unsigned int SCSI$L_PH_CH_TMOUT; /* SCSI Phase Change Timeout (seconds) */
|
||||
unsigned int SCSI$L_DISCON_TMOUT; /* SCSI Disconnect Timeout (seconds) */
|
||||
unsigned int SCSI$L_RES_1; /* Reserved */
|
||||
unsigned int SCSI$L_RES_2; /* Reserved */
|
||||
unsigned int SCSI$L_RES_3; /* Reserved */
|
||||
unsigned int SCSI$L_RES_4; /* Reserved */
|
||||
unsigned int SCSI$L_RES_5; /* Reserved */
|
||||
unsigned int SCSI$L_RES_6; /* Reserved */
|
||||
}
|
||||
SCSI$DESC;
|
||||
|
||||
|
||||
/*
|
||||
Define the SCSI Input/Output Status Block.
|
||||
*/
|
||||
|
||||
typedef struct scsi$iosb
|
||||
{
|
||||
unsigned short SCSI$W_VMS_STAT; /* VMS Status Code */
|
||||
unsigned long SCSI$L_IOSB_TFR_CNT; /* Actual Byte Count Transferred */
|
||||
unsigned char SCSI$B_IOSB_FILL_1; /* Unused */
|
||||
unsigned char SCSI$B_IOSB_STS; /* SCSI Device Status */
|
||||
}
|
||||
SCSI$IOSB;
|
||||
|
||||
|
||||
/*
|
||||
Define the VMS symbolic representation for a successful SCSI command.
|
||||
*/
|
||||
|
||||
#define SCSI$K_GOOD 0
|
||||
|
||||
|
||||
/*
|
||||
Define the SCSI Flag Field Constants.
|
||||
*/
|
||||
|
||||
#define SCSI$K_WRITE 0x0 /* Data Transfer Direction: Write */
|
||||
#define SCSI$K_READ 0x1 /* Data Transfer Direction: Read */
|
||||
#define SCSI$K_FL_ENAB_DIS 0x2 /* Enable Disconnect/Reconnect */
|
||||
|
||||
|
||||
/*
|
||||
Define DESCR_CNT. It must be a power of two and large enough
|
||||
for the maximum concurrent usage of descriptors.
|
||||
*/
|
||||
|
||||
#define DESCR_CNT 16
|
||||
|
||||
|
||||
#define MK_EFN 0 /* Event Flag Number */
|
||||
#define FailureStatusP(Status) (~(Status) & 1)
|
||||
|
||||
|
||||
static struct dsc$descriptor_s *descr(char *String)
|
||||
{
|
||||
static struct dsc$descriptor_s d_descrtbl[DESCR_CNT];
|
||||
static unsigned short descridx = 0;
|
||||
struct dsc$descriptor_s *d_ret = &d_descrtbl[descridx];
|
||||
descridx = (descridx + 1) & (DESCR_CNT - 1);
|
||||
d_ret->dsc$w_length = strlen((const char *) String);
|
||||
d_ret->dsc$a_pointer = String;
|
||||
d_ret->dsc$b_class = 0;
|
||||
d_ret->dsc$b_dtype = 0;
|
||||
|
||||
return d_ret;
|
||||
}
|
||||
|
||||
|
||||
static int SCSI_OpenDevice(char *DeviceName)
|
||||
{
|
||||
unsigned long d_dev[2], iosb[2], Status;
|
||||
union prvdef setprivs, newprivs;
|
||||
unsigned long ismnt = 0;
|
||||
unsigned long dvcls = 0;
|
||||
unsigned long dchr2 = 0;
|
||||
int DeviceFD = 0;
|
||||
struct itmlst_3
|
||||
{
|
||||
unsigned short ilen;
|
||||
unsigned short code;
|
||||
unsigned long *returnP;
|
||||
unsigned long ignored;
|
||||
}
|
||||
dvi_itmlst[] = {
|
||||
{ 4, DVI$_MNT, 0 /*&ismnt*/, 0 },
|
||||
{ 4, DVI$_DEVCLASS, 0 /*&dvcls*/, 0 },
|
||||
{ 4, DVI$_DEVCHAR2, 0 /*&dchr2*/, 0 },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
dvi_itmlst[0].returnP = &ismnt;
|
||||
dvi_itmlst[1].returnP = &dvcls;
|
||||
dvi_itmlst[2].returnP = &dchr2;
|
||||
|
||||
Status = sys$alloc(descr(DeviceName), 0, 0, 0, 0);
|
||||
|
||||
if (FailureStatusP(Status))
|
||||
{
|
||||
VMS_ExitCode = Status;
|
||||
FatalError("cannot allocate device '%s' - %X\n", DeviceName, Status);
|
||||
}
|
||||
|
||||
Status = sys$assign(descr(DeviceName), &DeviceFD, 0, 0);
|
||||
if (FailureStatusP(Status))
|
||||
{
|
||||
VMS_ExitCode = Status;
|
||||
FatalError("cannot open device '%s' - %X\n", DeviceName, Status);
|
||||
}
|
||||
|
||||
Status = sys$getdviw(0, DeviceFD, 0, &dvi_itmlst, &iosb, 0, 0, 0);
|
||||
if (FailureStatusP(Status))
|
||||
{
|
||||
VMS_ExitCode = Status;
|
||||
FatalError("cannot $getdvi(1) on device '%s' - %X\n", DeviceName, Status);
|
||||
}
|
||||
|
||||
if (FailureStatusP(Status = iosb[0]))
|
||||
{
|
||||
VMS_ExitCode = Status;
|
||||
FatalError("cannot $getdvi(2) on device '%s' - %X\n", DeviceName, Status);
|
||||
}
|
||||
|
||||
if (dvcls != DC$_TAPE)
|
||||
{
|
||||
VMS_ExitCode = SS$_IVDEVNAM;
|
||||
FatalError("specified device is NOT a magtape: operation denied\n");
|
||||
}
|
||||
#ifndef __DECC
|
||||
#ifndef DEV$M_SCSI
|
||||
#define DEV$M_SCSI 0x1000000
|
||||
#endif
|
||||
#endif
|
||||
if (~dchr2 & DEV$M_SCSI)
|
||||
{
|
||||
VMS_ExitCode = SS$_IVDEVNAM;
|
||||
FatalError("specified magtape is NOT a SCSI device: operation denied\n");
|
||||
}
|
||||
#if USING_DEC_DRIVE | USING_LDRSET
|
||||
#ifndef __DECC
|
||||
#ifndef DEV$M_LDR
|
||||
#define DEV$M_LDR 0x100000
|
||||
#endif
|
||||
#endif
|
||||
if (~dchr2 & DEV$M_LDR)
|
||||
{
|
||||
VMS_ExitCode = SS$_IVDEVNAM;
|
||||
FatalError("specified SCSI magtape does not have a loader: operation denied\n");
|
||||
}
|
||||
#endif
|
||||
if (ismnt)
|
||||
{
|
||||
VMS_ExitCode = SS$_DEVMOUNT;
|
||||
FatalError("specified device is mounted: operation denied\n");
|
||||
}
|
||||
|
||||
ots$move5(0, 0, 0, sizeof(newprivs), &newprivs);
|
||||
newprivs.prv$v_diagnose = 1;
|
||||
newprivs.prv$v_log_io = 1;
|
||||
newprivs.prv$v_phy_io = 1;
|
||||
Status = sys$setprv(1, &newprivs, 0, 0);
|
||||
|
||||
if (FailureStatusP(Status))
|
||||
{
|
||||
VMS_ExitCode = Status;
|
||||
FatalError("error enabling privs (diagnose,log_io,phy_io): operation denied\n");
|
||||
}
|
||||
|
||||
Status = sys$setprv(1, 0, 0, &setprivs);
|
||||
if (FailureStatusP(Status))
|
||||
{
|
||||
VMS_ExitCode = Status;
|
||||
FatalError("error retrieving current privs: operation denied\n");
|
||||
}
|
||||
|
||||
if (!setprivs.prv$v_diagnose)
|
||||
{
|
||||
VMS_ExitCode = SS$_NODIAGNOSE;
|
||||
FatalError("DIAGNOSE privilege is required: operation denied\n");
|
||||
}
|
||||
|
||||
if (!setprivs.prv$v_phy_io && !setprivs.prv$v_log_io)
|
||||
{
|
||||
VMS_ExitCode = SS$_NOPHY_IO;
|
||||
FatalError("PHY_IO or LOG_IO privilege is required: operation denied\n");
|
||||
}
|
||||
|
||||
return DeviceFD;
|
||||
}
|
||||
|
||||
|
||||
static void SCSI_CloseDevice(char *DeviceName, int DeviceFD)
|
||||
{
|
||||
unsigned long Status;
|
||||
|
||||
Status = sys$dassgn(DeviceFD);
|
||||
if (FailureStatusP(Status))
|
||||
FatalError("cannot close SCSI device '%s' - %X\n", DeviceName, Status);
|
||||
}
|
||||
|
||||
|
||||
static int SCSI_ExecuteCommand( int DeviceFD,
|
||||
Direction_T Direction,
|
||||
CDB_T *CDB,
|
||||
int CDB_Length,
|
||||
void *DataBuffer,
|
||||
int DataBufferLength,
|
||||
RequestSense_T *RequestSense)
|
||||
{
|
||||
SCSI$DESC cmd_desc;
|
||||
SCSI$IOSB cmd_iosb;
|
||||
unsigned long Status;
|
||||
int Result;
|
||||
memset(RequestSense, 0, sizeof(RequestSense_T));
|
||||
/* Issue the QIO to send the SCSI Command. */
|
||||
ots$move5(0, 0, 0, sizeof(cmd_desc), &cmd_desc);
|
||||
cmd_desc.SCSI$L_OPCODE = 1; /* Only defined SCSI opcode... a VMS thing */
|
||||
cmd_desc.SCSI$A_CMD_ADDR = CDB;
|
||||
cmd_desc.SCSI$L_CMD_LEN = CDB_Length;
|
||||
cmd_desc.SCSI$A_DATA_ADDR = DataBuffer;
|
||||
cmd_desc.SCSI$L_DATA_LEN = DataBufferLength;
|
||||
cmd_desc.SCSI$L_PAD_LEN = 0;
|
||||
cmd_desc.SCSI$L_PH_CH_TMOUT = 180; /* SCSI Phase Change Timeout (seconds) */
|
||||
cmd_desc.SCSI$L_DISCON_TMOUT = 180; /* SCSI Disconnect Timeout (seconds) */
|
||||
|
||||
switch (Direction)
|
||||
{
|
||||
/*
|
||||
NOTE: Do NOT include flag SCSI$K_FL_ENAB_SYNC.
|
||||
It does NOT work for this case.
|
||||
*/
|
||||
case Input:
|
||||
cmd_desc.SCSI$L_FLAGS = SCSI$K_READ | SCSI$K_FL_ENAB_DIS;
|
||||
break;
|
||||
|
||||
case Output:
|
||||
cmd_desc.SCSI$L_FLAGS = SCSI$K_WRITE | SCSI$K_FL_ENAB_DIS;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Issue the SCSI Command. */
|
||||
Status = sys$qiow(MK_EFN, DeviceFD, IO$_DIAGNOSE, &cmd_iosb, 0, 0,
|
||||
&cmd_desc, sizeof(cmd_desc), 0, 0, 0, 0);
|
||||
Result = SCSI$K_GOOD;
|
||||
|
||||
if (Status & 1)
|
||||
Status = cmd_iosb.SCSI$W_VMS_STAT;
|
||||
|
||||
if (Status & 1)
|
||||
Result = cmd_iosb.SCSI$B_IOSB_STS;
|
||||
|
||||
if (Result != SCSI$K_GOOD)
|
||||
{
|
||||
unsigned char RequestSenseCDB[6] =
|
||||
{ 0x03 /* REQUEST_SENSE */, 0, 0, 0, sizeof(RequestSense_T), 0 };
|
||||
|
||||
printf("SCSI command error: %d - requesting sense data\n", Result);
|
||||
|
||||
/* Execute Request Sense to determine the failure reason. */
|
||||
ots$move5(0, 0, 0, sizeof(cmd_desc), &cmd_desc);
|
||||
cmd_desc.SCSI$L_OPCODE = 1; /* Only defined SCSI opcode... a VMS thing */
|
||||
cmd_desc.SCSI$L_FLAGS = SCSI$K_READ | SCSI$K_FL_ENAB_DIS;
|
||||
cmd_desc.SCSI$A_CMD_ADDR = RequestSenseCDB;
|
||||
cmd_desc.SCSI$L_CMD_LEN = 6;
|
||||
cmd_desc.SCSI$A_DATA_ADDR = RequestSense;
|
||||
cmd_desc.SCSI$L_DATA_LEN = sizeof(RequestSense_T);
|
||||
cmd_desc.SCSI$L_PH_CH_TMOUT = 180;
|
||||
cmd_desc.SCSI$L_DISCON_TMOUT = 180;
|
||||
|
||||
/* Issue the QIO to send the Request Sense Command. */
|
||||
Status = sys$qiow(MK_EFN, DeviceFD, IO$_DIAGNOSE, &cmd_iosb, 0, 0,
|
||||
&cmd_desc, sizeof(cmd_desc), 0, 0, 0, 0);
|
||||
if (FailureStatusP(Status))
|
||||
{
|
||||
printf("?Error returned from REQUEST_SENSE(1): %%X%08lX\n", Status);
|
||||
sys$exit(Status);
|
||||
}
|
||||
|
||||
/* Check the VMS Status from QIO. */
|
||||
Status = cmd_iosb.SCSI$W_VMS_STAT;
|
||||
if (FailureStatusP(Status))
|
||||
{
|
||||
printf("?Error returned from REQUEST_SENSE(2): %%X%08lX\n", Status);
|
||||
sys$exit(Status);
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
static void VMS_DefineStatusSymbols(void)
|
||||
{
|
||||
char SymbolName[32], SymbolValue[32];
|
||||
int StorageElementNumber;
|
||||
|
||||
if (DataTransferElementFull)
|
||||
{
|
||||
/* Define MTX_DTE Symbol (environment variable) as 'FULL:n'. */
|
||||
sprintf(SymbolValue, "FULL:%d",
|
||||
DataTransferElementSourceStorageElementNumber);
|
||||
lib$set_symbol(descr("MTX_DTE"), descr(SymbolValue), &2);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Define MTX_DTE Symbol (environment variable) as 'EMPTY'. */
|
||||
lib$set_symbol(descr("MTX_DTE"), descr("EMPTY"), &2);
|
||||
}
|
||||
|
||||
/* Define MTX_MSZ Symbol (environment variable) "Magazine SiZe" as 'n'. */
|
||||
sprintf(SymbolValue, "%d", StorageElementCount);
|
||||
lib$set_symbol(descr("MTX_MSZ"), descr(SymbolValue), &2);
|
||||
for (StorageElementNumber = 1;
|
||||
StorageElementNumber <= StorageElementCount;
|
||||
StorageElementNumber++)
|
||||
{
|
||||
sprintf(SymbolName, "MTX_STE%02d", StorageElementNumber);
|
||||
strcpy(SymbolValue,
|
||||
(StorageElementFull[StorageElementNumber] ? "FULL" : "EMPTY"));
|
||||
lib$set_symbol(descr(SymbolName), descr(SymbolValue), &2);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user