mirror of
https://github.com/iustin/mt-st.git
synced 2026-01-08 04:55:16 +00:00
Backdated import of mt-st version 0.7
This is an import of the mt-st upstream release 0.7 as it appeared in the Debian archives.
This commit is contained in:
351
COPYING
Normal file
351
COPYING
Normal file
@@ -0,0 +1,351 @@
|
||||
|
||||
NOTE! This copyright does *not* cover user programs that use kernel
|
||||
services by normal system calls - this is merely considered normal use
|
||||
of the kernel, and does *not* fall under the heading of "derived work".
|
||||
Also note that the GPL below is copyrighted by the Free Software
|
||||
Foundation, but the instance of code that it refers to (the linux
|
||||
kernel) is copyrighted by me and others who actually wrote it.
|
||||
|
||||
Linus Torvalds
|
||||
|
||||
----------------------------------------
|
||||
|
||||
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
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
25
Makefile
Normal file
25
Makefile
Normal file
@@ -0,0 +1,25 @@
|
||||
CFLAGS= -Wall -O2
|
||||
SBINDIR= /sbin
|
||||
BINDIR= /bin
|
||||
MANDIR= /usr/man
|
||||
|
||||
all: mt stinit
|
||||
|
||||
mt: mt.c
|
||||
$(CC) $(CFLAGS) -o mt mt.c
|
||||
|
||||
stinit: stinit.c
|
||||
$(CC) $(CFLAGS) -o stinit stinit.c
|
||||
|
||||
install: mt stinit
|
||||
install -s mt $(BINDIR)
|
||||
install -c -m 444 mt.1 $(MANDIR)/man1
|
||||
install -s stinit $(SBINDIR)
|
||||
install -c -m 444 stinit.8 $(MANDIR)/man8
|
||||
|
||||
dist: clean
|
||||
(mydir=`basename \`pwd\``;\
|
||||
cd .. && tar cvvf - $$mydir | gzip -9 > $${mydir}.tar.gz)
|
||||
|
||||
clean:
|
||||
rm -f *~ \#*\# *.o mt stinit
|
||||
83
README
Normal file
83
README
Normal file
@@ -0,0 +1,83 @@
|
||||
This directory contains two programs; mt and stinit. Mt is basically
|
||||
a "standard" mt with additional commands to send the ioctls specific
|
||||
to the Linux SCSI tape driver. The source supports all ioctls up to
|
||||
kernel version 2.4.0 but it can also be compiled in kernels >= 2.0.x
|
||||
(and hopefully with 1.2.x). Although this mt program is tailored for
|
||||
SCSI tapes, it can also be used with other Linux tape drivers using the
|
||||
same ioctls (some of the commands may not work with all drivers).
|
||||
|
||||
Stinit is a program to initialize the tape drive characteristics. The
|
||||
current version should be considered alpha. See README.stinit for more
|
||||
information.
|
||||
|
||||
The files:
|
||||
README - This file.
|
||||
README.stinit - Information about the stinit program
|
||||
COPYING - The GNU Public License
|
||||
Makefile - Makefile for programs
|
||||
mt.c - The mt source
|
||||
mt.1 - The man page for mt
|
||||
mtio.h - The tape command definitions
|
||||
qic117.h - Needed by mtio.h
|
||||
stinit.c - The stinit source
|
||||
stinit.8 - The man page for stinit
|
||||
stinit.def.examples - example configurations for different devices
|
||||
|
||||
Installation:
|
||||
- review the makefile
|
||||
- make
|
||||
- make install
|
||||
|
||||
Changes in version 0.7:
|
||||
- add command eject for compatibility with GNU mt (synonym for offline
|
||||
and rewoffl)
|
||||
- the load and ersae commands accept an argument
|
||||
- add CLN (cleaning request) to status
|
||||
- add command stsetcln to set the cleaning request recognition options
|
||||
- add the flag no-wait to the settable/clearable options
|
||||
- some new density codes added
|
||||
|
||||
Changes in version 0.6:
|
||||
- uses local mtio.h to include support for the most recent driver
|
||||
features even when compiled on a system having old mtio.h
|
||||
- on-line and write-protect are checked after some errors and a
|
||||
message is printed if the probable error reason is found
|
||||
- the tape is opened with flag O_NONBLOCK for commands that are
|
||||
useful even when the device is not ready (no tape)
|
||||
- some new density codes added for printout
|
||||
- OnStream drives using the osst driver recognised
|
||||
- the obsolete command 'datcompression' is removed
|
||||
- new option --version in mt
|
||||
|
||||
Changes in version 0.5b:
|
||||
- corrected the bug that caused the command argument to be ignored if
|
||||
option -f was used
|
||||
- added #include <errno.h> to stinit.c to enable compilation with glibc
|
||||
- density 0x45 (TR-4) added to known density list
|
||||
|
||||
Changes in version 0.5:
|
||||
- utility stinit added to package
|
||||
- command asf added
|
||||
- command datcompression not compiled in default configuration
|
||||
- support added for setting timeouts
|
||||
- bugs in argument parsing corrected
|
||||
- help prints all commands
|
||||
- binaries not distributed any more
|
||||
- mt code cleaned
|
||||
- GNU Public License used for both programs
|
||||
|
||||
Changes in version 0.4:
|
||||
- support for the ioctls for partitioned tapes
|
||||
- compiles also with 1.2.13
|
||||
- the driver options can be specified also with keywords
|
||||
- floppy tape type is shown
|
||||
- (not working) support for other operating systems removed
|
||||
|
||||
Changes in version 0.3:
|
||||
- support for new ioctls
|
||||
- accepts hexadecimal numbers with prefix 0x
|
||||
- the datcompression command improved (although it is being overrided
|
||||
by the command compression using a new ioctl)
|
||||
- bus fixes
|
||||
|
||||
November 8, 2001 Kai Makisara (email Kai.Makisara@metla.fi)
|
||||
51
README.stinit
Normal file
51
README.stinit
Normal file
@@ -0,0 +1,51 @@
|
||||
The program stinit is meant for initializing of SCSI tape drive modes
|
||||
at system startup, when the tape driver module is loaded, or when new
|
||||
tape drivers are initialized using
|
||||
echo "scsi add-single-device" x y z v >/proc/scsi/scsi
|
||||
|
||||
The parameters used in initialization of a tape drive are fetched from
|
||||
a text file. The parameter file is indexed by the inquiry data
|
||||
returned by the drive, i.e., the parameters are defined by the drive
|
||||
manufacturer, model, etc. This means that the initialization for a
|
||||
drive does not depend on its hardware address. A similar method is
|
||||
used by most Unices either within the kernel or outside the kernel.
|
||||
|
||||
The contents of the configuration file and the command line parameters
|
||||
are defined in the man page stinit.8. A sample configuration file
|
||||
stinit.def.examples is included in this distribution. It can be used as
|
||||
example when writing descriptions for the tape drives in a
|
||||
system. NOTE that the examples by no means specify what are the
|
||||
"correct" parameters for different types of devices.
|
||||
|
||||
The program is configured for maximum of 32 tapes and 4 modes (the
|
||||
default Linux configuration). If the kernel is configured for
|
||||
different number of tape modes, the definitions MAX_TAPES and
|
||||
NBR_MODES in stinit.c should be configured accordingly. (With 8 bit
|
||||
minor numbers NBR_MODES * MAX_TAPES == 128.)
|
||||
|
||||
The files:
|
||||
stinit.c - the program source code
|
||||
stinit.8 - the man page
|
||||
stinit.def.examples - a file containing example definitions for
|
||||
imaginary tape drives
|
||||
Makefile - a sample makefile for the program
|
||||
README.stinit - this file
|
||||
|
||||
Changes in version 0.7:
|
||||
- the directory scanning for tape devices is restricted to files with
|
||||
certain names in some directories to avoid triggering automatic
|
||||
module loading for device that don't exist (original patch from
|
||||
Philippe Troin)
|
||||
- support for devfs (/dev/tapes) added
|
||||
- logging bug fixes
|
||||
- add setting the cleaning request parameter
|
||||
- add setting the no-wait (immediate) bit
|
||||
|
||||
Changes in version 0.6:
|
||||
- fix the bug with whitespace at the beginning of lines
|
||||
- use O_NONBLOCK to open the tape (anticipate kernel change)
|
||||
|
||||
Initial version 0.5.
|
||||
|
||||
November 8, 2001 Kai M<>kisara <Kai.Makisara@metla.fi>
|
||||
|
||||
16
mt-st-0.7.lsm
Normal file
16
mt-st-0.7.lsm
Normal file
@@ -0,0 +1,16 @@
|
||||
Begin4
|
||||
Title: mt-st
|
||||
Version: 0.7
|
||||
Entered-date: 2001-11-21
|
||||
Description: Includes a mt-like program supporting additional
|
||||
commands using ioctls specific to the Linux SCSI tape driver (up
|
||||
to kernel 2.4.15), and the program stinit to define the SCSI tape
|
||||
devices in system startup scripts.
|
||||
Keywords: tape SCSI
|
||||
Author: Kai.Makisara@metla.fi (Kai Makisara)
|
||||
Maintained-by: Kai.Makisara@metla.fi (Kai Makisara)
|
||||
Primary-site: ftp.ibiblio.org /pub/Linux/system/backup
|
||||
35 kB mt-st-0.7.tar.gz
|
||||
0.7 kB mt-st-0.7.lsm
|
||||
Copying-policy: GPL
|
||||
End
|
||||
264
mt.1
Normal file
264
mt.1
Normal file
@@ -0,0 +1,264 @@
|
||||
.TH MT 1 "November 2001" \" -*- nroff -*-
|
||||
.SH NAME
|
||||
mt \- control magnetic tape drive operation
|
||||
.SH SYNOPSIS
|
||||
.B mt
|
||||
[\-h] [\-f device] operation [count] [arguments...]
|
||||
.SH DESCRIPTION
|
||||
This manual page documents the tape control program
|
||||
.BR mt .
|
||||
.B mt
|
||||
performs the given
|
||||
.IR operation ,
|
||||
which must be one of the tape operations listed below, on a tape
|
||||
drive. The commands can also be listed by running the program with the
|
||||
.I \-h
|
||||
option. The version of mt is printed with the
|
||||
.I \-v
|
||||
or
|
||||
.I \-\-version
|
||||
option. The path of the tape device to operate on can be given with
|
||||
the
|
||||
.I \-f
|
||||
or
|
||||
.I \-t
|
||||
option. If neither of those options is given, and the environment
|
||||
variable
|
||||
.B TAPE
|
||||
is set, it is used. Otherwise, a default device defined in the file
|
||||
.I /usr/include/sys/mtio.h
|
||||
is used.
|
||||
.PP
|
||||
Some operations optionally take an argument or repeat count, which can be given
|
||||
after the operation name and defaults to 1.
|
||||
.PP
|
||||
The available operations are listed below. Unique abbreviations are
|
||||
accepted. Not all operations are available on all systems, or work on
|
||||
all types of tape drives.
|
||||
.IP fsf
|
||||
Forward space
|
||||
.I count
|
||||
files.
|
||||
The tape is positioned on the first block of the next file.
|
||||
.IP fsfm
|
||||
Forward space
|
||||
.I count
|
||||
files.
|
||||
The tape is positioned on the last block of the previous file.
|
||||
.IP bsf
|
||||
Backward space
|
||||
.I count
|
||||
files.
|
||||
The tape is positioned on the last block of the previous file.
|
||||
.IP bsfm
|
||||
Backward space
|
||||
.I count
|
||||
files.
|
||||
The tape is positioned on the first block of the next file.
|
||||
.IP asf
|
||||
The tape is positioned at the beginning of the
|
||||
.I count
|
||||
file. Positioning is done by first rewinding the tape and then spacing
|
||||
forward over
|
||||
.I count
|
||||
filemarks.
|
||||
.IP fsr
|
||||
Forward space
|
||||
.I count
|
||||
records.
|
||||
.IP bsr
|
||||
Backward space
|
||||
.I count
|
||||
records.
|
||||
.IP fss
|
||||
(SCSI tapes) Forward space
|
||||
.I count
|
||||
setmarks.
|
||||
.IP bss
|
||||
(SCSI tapes) Backward space
|
||||
.I count
|
||||
setmarks.
|
||||
.IP "eod, seod"
|
||||
Space to end of valid data. Used on streamer tape
|
||||
drives to append data to the logical and of tape.
|
||||
.IP rewind
|
||||
Rewind the tape.
|
||||
.IP "offline, rewoffl, eject"
|
||||
Rewind the tape and, if applicable, unload the tape.
|
||||
.IP retension
|
||||
Rewind the tape, then wind it to the end of the reel,
|
||||
then rewind it again.
|
||||
.IP "weof, eof"
|
||||
Write
|
||||
.I count
|
||||
EOF marks at current position.
|
||||
.IP "wset"
|
||||
(SCSI tapes) Write
|
||||
.I count
|
||||
setmarks at current position (only SCSI tape).
|
||||
.IP erase
|
||||
Erase the tape.
|
||||
.IP status
|
||||
Print status information about the tape unit. (If the density code is
|
||||
"no translation" in the status output, this does not affect working of the
|
||||
tape drive.)
|
||||
.IP seek
|
||||
(SCSI tapes) Seek to the
|
||||
.I count
|
||||
block on the tape. This operation is available on some
|
||||
Tandberg and Wangtek streamers and some SCSI-2 tape drives. The block
|
||||
address should be obtained from a
|
||||
.I tell
|
||||
call earlier.
|
||||
.IP tell
|
||||
(SCSI tapes) Tell the current block on tape. This operation is available on some
|
||||
Tandberg and Wangtek streamers and some SCSI-2 tape drives.
|
||||
.IP setpartition
|
||||
(SCSI tapes) Switch to the partition determined by
|
||||
.I count.
|
||||
The default data partition of the tape is numbered zero. Switching
|
||||
partition is available only if enabled for the device, the device
|
||||
supports multiple partitions, and the tape is formatted with multiple
|
||||
partitions.
|
||||
.IP partseek
|
||||
(SCSI tapes) The tape position is set to block
|
||||
.I count
|
||||
in the partition given by the argument after count. The default
|
||||
partition is zero.
|
||||
.IP mkpartition
|
||||
(SCSI tapes) Format the tape with one (count is zero) or two partitions
|
||||
(count gives the size of the second partition in megabytes). The tape
|
||||
drive must be able to format partitioned tapes with
|
||||
initiator-specified partition size and partition support
|
||||
must be enabled for the drive.
|
||||
.IP load
|
||||
(SCSI tapes) Send the load command to the tape drive. The drives usually load the
|
||||
tape when a new cartridge is inserted. The argument
|
||||
.I count
|
||||
can usually be omitted. Some HP changers load tape n if the
|
||||
.I count
|
||||
10000 + n is given (a special funtion in the Linux st driver).
|
||||
.IP lock
|
||||
(SCSI tapes) Lock the tape drive door.
|
||||
.IP unlock
|
||||
(SCSI tapes) Unlock the tape drive door.
|
||||
.IP setblk
|
||||
(SCSI tapes) Set the block size of the drive to
|
||||
.I count
|
||||
bytes per record.
|
||||
.IP setdensity
|
||||
(SCSI tapes) Set the tape density code to
|
||||
.I count.
|
||||
The proper codes to use with each drive should be looked up from the
|
||||
drive documentation.
|
||||
.IP densities
|
||||
(SCSI tapes) Write explanation of some common density codes to
|
||||
standard output.
|
||||
.IP drvbuffer
|
||||
(SCSI tapes) Set the tape drive buffer code to
|
||||
.I number.
|
||||
The proper value for unbuffered operation is zero and "normal" buffered
|
||||
operation one. The meanings of other values can be found in the drive
|
||||
documentation or, in case of a SCSI-2 drive, from the SCSI-2 standard.
|
||||
.IP compression
|
||||
(SCSI tapes) The compression within the drive can be switched on or
|
||||
off using the MTCOMPRESSION ioctl. Note that this method is not
|
||||
supported by all drives implementing compression. For instance, the
|
||||
Exabyte 8 mm drives use density codes to select compression.
|
||||
.IP stoptions
|
||||
(SCSI tapes) Set the driver options bits for the device to the defined
|
||||
values. Allowed only for the superuser. The bits can be set
|
||||
either by oring the option bits from the file /usr/include/linux/mtio.h to
|
||||
.I count,
|
||||
or by using the following keywords (as many keywords can be used on
|
||||
the same line as necessary, unambiguous abbreviations allowed):
|
||||
.RS
|
||||
.IP buffer-writes 15
|
||||
buffered writes enabled
|
||||
.IP async-writes
|
||||
asynchronous writes enabled
|
||||
.IP read-ahead
|
||||
read-ahead for fixed block size
|
||||
.IP debug
|
||||
debugging (if compiled into driver)
|
||||
.IP two-fms
|
||||
write two filemarks when file closed
|
||||
.IP fast-eod
|
||||
space directly to eod (and lose file number)
|
||||
.IP no-wait
|
||||
don't wait until rewind, etc. complete
|
||||
.IP auto-lock
|
||||
automatically lock/unlock drive door
|
||||
.IP def-writes
|
||||
the block size and density are for writes
|
||||
.IP can-bsr
|
||||
drive can space backwards well
|
||||
.IP no-blklimits
|
||||
drive doesn't support read block limits
|
||||
.IP can-partitions
|
||||
drive can handle partitioned tapes
|
||||
.IP scsi2logical
|
||||
seek and tell use SCSI-2 logical block addresses instead of device
|
||||
dependent addresses
|
||||
.IP sysv
|
||||
enable the System V semantics
|
||||
.RE
|
||||
.IP stsetoptions
|
||||
(SCSI tapes) Set selected driver options bits. The methods to specify
|
||||
the bits to set are given above in description of stoptions.
|
||||
Allowed only for the superuser.
|
||||
.IP stclearoptions
|
||||
(SCSI tapes) Clear selected driver option bits. The methods to specify
|
||||
the bits to clear are given above in description of stoptions.
|
||||
Allowed only for the superuser.
|
||||
.IP stwrthreshold
|
||||
(SCSI tapes) The write threshold for the tape device is set to
|
||||
.I count
|
||||
kilobytes. The value must be smaller than or equal to the driver
|
||||
buffer size. Allowed only for the superuser.
|
||||
.IP defblksize
|
||||
(SCSI tapes) Set the default block size of the device to
|
||||
.I count
|
||||
bytes. The value -1 disables the default block size.
|
||||
The block size set by
|
||||
.I setblk
|
||||
overrides the default until a new tape is inserted.
|
||||
Allowed only for the superuser.
|
||||
.IP defdensity
|
||||
(SCSI tapes) Set the default density code. The value -1 disables the
|
||||
default density. The density set by
|
||||
.I setdensity
|
||||
overrides the default until a new tape is inserted. Allowed only for the
|
||||
superuser.
|
||||
.IP defdrvbuffer
|
||||
(SCSI tapes) Set the default drive buffer code. The value -1 disables the
|
||||
default drive buffer code. The drive buffer code set by
|
||||
.I drvbuffer
|
||||
overrides the default until a new tape is inserted. Allowed only for the
|
||||
superuser.
|
||||
.IP defcompression
|
||||
(SCSI tapes) Set the default compression state. The value -1 disables the
|
||||
default compression. The compression state set by
|
||||
.I compression
|
||||
overrides the default until a new tape is inserted. Allowed only for the
|
||||
superuser.
|
||||
.IP sttimeout
|
||||
sets the normal timeout for the device. The value is given in
|
||||
seconds. Allowed only for the superuser.
|
||||
.IP stlongtimeout
|
||||
sets the long timeout for the device. The value is given in
|
||||
seconds. Allowed only for the superuser.
|
||||
.IP stsetcln
|
||||
set the cleaning request interpretation parameters.
|
||||
.PP
|
||||
.B mt
|
||||
exits with a status of 0 if the operation succeeded, 1 if the
|
||||
operation or device name given was invalid, or 2 if the operation
|
||||
failed.
|
||||
.SH AUTHOR
|
||||
The program is written by Kai Makisara <Kai.Makisara@metla.fi>.
|
||||
.SH COPYRIGHT
|
||||
The program and the manual page are copyrighted by Kai Makisara, 1998-2001.
|
||||
They can be distributed according to the GNU Copyleft.
|
||||
.SH SEE ALSO
|
||||
st(4)
|
||||
701
mt.c
Normal file
701
mt.c
Normal file
@@ -0,0 +1,701 @@
|
||||
/* This file contains the source of the 'mt' program intended for
|
||||
Linux systems. The program supports the basic mt commands found
|
||||
in most Unix-like systems. In addition to this the program
|
||||
supports several commands designed for use with the Linux SCSI
|
||||
tape drive.
|
||||
|
||||
Maintained by Kai M<>kisara (email Kai.Makisara@metla.fi)
|
||||
Copyright by Kai M<>kisara, 1998 - 2001. The program may be distributed
|
||||
according to the GNU Public License
|
||||
|
||||
Last Modified: Wed Nov 21 23:14:29 2001 by makisara@kai.makisara.local
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char rcsid[] = "$Id: /home/makisara/src/sys/mt-st-0.7/mt.c at Wed Nov 21 23:14:29 2001 by makisara@kai.makisara.local$";
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "mtio.h"
|
||||
|
||||
#ifndef DEFTAPE
|
||||
#define DEFTAPE "/dev/tape" /* default tape device */
|
||||
#endif /* DEFTAPE */
|
||||
|
||||
#define VERSION "0.7"
|
||||
|
||||
typedef int (* cmdfunc)(/* int, struct cmdef_tr *, int, char ** */);
|
||||
|
||||
typedef struct cmdef_tr {
|
||||
char *cmd_name;
|
||||
int cmd_code;
|
||||
cmdfunc cmd_function;
|
||||
int cmd_count_bits;
|
||||
unsigned char cmd_fdtype;
|
||||
unsigned char arg_cnt;
|
||||
int error_tests;
|
||||
} cmdef_tr;
|
||||
|
||||
#define NO_FD 0
|
||||
#define FD_RDONLY 1
|
||||
#define FD_RDWR 2
|
||||
|
||||
#define NO_ARGS 0
|
||||
#define ONE_ARG 1
|
||||
#define TWO_ARGS 2
|
||||
#define MULTIPLE_ARGS 255
|
||||
|
||||
#define DO_BOOLEANS 1002
|
||||
#define SET_BOOLEANS 1003
|
||||
#define CLEAR_BOOLEANS 1004
|
||||
|
||||
#define ET_ONLINE 1
|
||||
#define ET_WPROT 2
|
||||
|
||||
static void usage(int);
|
||||
static int do_standard(int, cmdef_tr *, int, char **);
|
||||
static int do_drvbuffer(int, cmdef_tr *, int, char **);
|
||||
static int do_options(int, cmdef_tr *, int, char **);
|
||||
static int do_tell(int, cmdef_tr *, int, char **);
|
||||
static int do_partseek(int, cmdef_tr *, int, char **);
|
||||
static int do_status(int, cmdef_tr *, int, char **);
|
||||
static int print_densities(int, cmdef_tr *, int, char **);
|
||||
static int do_asf(int, cmdef_tr *, int, char **);
|
||||
static void test_error(int, cmdef_tr *);
|
||||
|
||||
static cmdef_tr cmds[] = {
|
||||
{ "weof", MTWEOF, do_standard, 0, FD_RDWR, ONE_ARG,
|
||||
ET_ONLINE | ET_WPROT },
|
||||
{ "wset", MTWSM, do_standard, 0, FD_RDWR, ONE_ARG,
|
||||
ET_ONLINE | ET_WPROT },
|
||||
{ "eof", MTWEOF, do_standard, 0, FD_RDWR, ONE_ARG,
|
||||
ET_ONLINE },
|
||||
{ "fsf", MTFSF, do_standard, 0, FD_RDONLY, ONE_ARG,
|
||||
ET_ONLINE },
|
||||
{ "fsfm", MTFSFM, do_standard, 0, FD_RDONLY, ONE_ARG,
|
||||
ET_ONLINE },
|
||||
{ "bsf", MTBSF, do_standard, 0, FD_RDONLY, ONE_ARG,
|
||||
ET_ONLINE },
|
||||
{ "bsfm", MTBSFM, do_standard, 0, FD_RDONLY, ONE_ARG,
|
||||
ET_ONLINE },
|
||||
{ "fsr", MTFSR, do_standard, 0, FD_RDONLY, ONE_ARG,
|
||||
ET_ONLINE },
|
||||
{ "bsr", MTBSR, do_standard, 0, FD_RDONLY, ONE_ARG,
|
||||
ET_ONLINE },
|
||||
{ "fss", MTFSS, do_standard, 0, FD_RDONLY, ONE_ARG,
|
||||
ET_ONLINE },
|
||||
{ "bss", MTBSS, do_standard, 0, FD_RDONLY, ONE_ARG,
|
||||
ET_ONLINE },
|
||||
{ "rewind", MTREW, do_standard, 0, FD_RDONLY, NO_ARGS,
|
||||
ET_ONLINE },
|
||||
{ "offline", MTOFFL, do_standard, 0, FD_RDONLY, NO_ARGS,
|
||||
ET_ONLINE },
|
||||
{ "rewoffl", MTOFFL, do_standard, 0, FD_RDONLY, NO_ARGS,
|
||||
ET_ONLINE },
|
||||
{ "eject", MTOFFL, do_standard, 0, FD_RDONLY, NO_ARGS,
|
||||
ET_ONLINE },
|
||||
{ "retension", MTRETEN, do_standard, 0, FD_RDONLY, NO_ARGS,
|
||||
ET_ONLINE },
|
||||
{ "eod", MTEOM, do_standard, 0, FD_RDONLY, NO_ARGS,
|
||||
ET_ONLINE },
|
||||
{ "seod", MTEOM, do_standard, 0, FD_RDONLY, NO_ARGS,
|
||||
ET_ONLINE },
|
||||
{ "seek", MTSEEK, do_standard, 0, FD_RDONLY, ONE_ARG,
|
||||
ET_ONLINE },
|
||||
{ "tell", MTTELL, do_tell, 0, FD_RDONLY, NO_ARGS,
|
||||
ET_ONLINE },
|
||||
{ "status", MTNOP, do_status, 0, FD_RDONLY, NO_ARGS,
|
||||
0 },
|
||||
{ "erase", MTERASE, do_standard, 0, FD_RDWR, ONE_ARG,
|
||||
ET_ONLINE },
|
||||
{ "setblk", MTSETBLK, do_standard, 0, FD_RDONLY, ONE_ARG,
|
||||
0 },
|
||||
{ "lock", MTLOCK, do_standard, 0, FD_RDONLY, NO_ARGS,
|
||||
ET_ONLINE },
|
||||
{ "unlock", MTUNLOCK, do_standard, 0, FD_RDONLY, NO_ARGS,
|
||||
ET_ONLINE },
|
||||
{ "load", MTLOAD, do_standard, 0, FD_RDONLY, ONE_ARG,
|
||||
0 },
|
||||
{ "compression", MTCOMPRESSION, do_standard, 0, FD_RDONLY, ONE_ARG,
|
||||
0 },
|
||||
{ "setdensity", MTSETDENSITY, do_standard, 0, FD_RDONLY, ONE_ARG,
|
||||
0 },
|
||||
{ "drvbuffer", MTSETDRVBUFFER, do_drvbuffer, 0, FD_RDONLY, ONE_ARG,
|
||||
0 },
|
||||
{ "stwrthreshold", MTSETDRVBUFFER, do_drvbuffer, MT_ST_WRITE_THRESHOLD,
|
||||
FD_RDONLY, ONE_ARG, 0},
|
||||
{ "stoptions", DO_BOOLEANS, do_options, 0, FD_RDONLY,
|
||||
MULTIPLE_ARGS, 0},
|
||||
{ "stsetoptions", SET_BOOLEANS, do_options, 0, FD_RDONLY,
|
||||
MULTIPLE_ARGS, 0},
|
||||
{ "stclearoptions", CLEAR_BOOLEANS, do_options, 0, FD_RDONLY,
|
||||
MULTIPLE_ARGS, 0},
|
||||
{ "defblksize", MTSETDRVBUFFER, do_drvbuffer, MT_ST_DEF_BLKSIZE,
|
||||
FD_RDONLY, ONE_ARG, 0},
|
||||
{ "defdensity", MTSETDRVBUFFER, do_drvbuffer, MT_ST_DEF_DENSITY,
|
||||
FD_RDONLY, ONE_ARG, 0},
|
||||
{ "defdrvbuffer", MTSETDRVBUFFER, do_drvbuffer, MT_ST_DEF_DRVBUFFER,
|
||||
FD_RDONLY, ONE_ARG, 0},
|
||||
{ "defcompression", MTSETDRVBUFFER, do_drvbuffer, MT_ST_DEF_COMPRESSION,
|
||||
FD_RDONLY, ONE_ARG, 0},
|
||||
{ "stsetcln", MTSETDRVBUFFER, do_drvbuffer, MT_ST_SET_CLN,
|
||||
FD_RDONLY, ONE_ARG, 0},
|
||||
{ "sttimeout", MTSETDRVBUFFER, do_drvbuffer, MT_ST_SET_TIMEOUT,
|
||||
FD_RDONLY, ONE_ARG, 0},
|
||||
{ "stlongtimeout", MTSETDRVBUFFER, do_drvbuffer, MT_ST_SET_LONG_TIMEOUT,
|
||||
FD_RDONLY, ONE_ARG, 0},
|
||||
{ "densities", 0, print_densities, 0, NO_FD, NO_ARGS,
|
||||
0 },
|
||||
{ "setpartition", MTSETPART, do_standard, 0, FD_RDONLY, ONE_ARG,
|
||||
ET_ONLINE },
|
||||
{ "mkpartition", MTMKPART, do_standard, 0, FD_RDWR, ONE_ARG,
|
||||
ET_ONLINE },
|
||||
{ "partseek", 0, do_partseek, 0, FD_RDONLY, TWO_ARGS,
|
||||
ET_ONLINE },
|
||||
{ "asf", 0, do_asf, MTREW, FD_RDONLY, ONE_ARG,
|
||||
ET_ONLINE },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
static struct densities {
|
||||
int code;
|
||||
char *name;
|
||||
} density_tbl[] = {
|
||||
{0x00, "default"},
|
||||
{0x01, "NRZI (800 bpi)"},
|
||||
{0x02, "PE (1600 bpi)"},
|
||||
{0x03, "GCR (6250 bpi)"},
|
||||
{0x04, "QIC-11"},
|
||||
{0x05, "QIC-45/60 (GCR, 8000 bpi)"},
|
||||
{0x06, "PE (3200 bpi)"},
|
||||
{0x07, "IMFM (6400 bpi)"},
|
||||
{0x08, "GCR (8000 bpi)"},
|
||||
{0x09, "GCR (37871 bpi)"},
|
||||
{0x0a, "MFM (6667 bpi)"},
|
||||
{0x0b, "PE (1600 bpi)"},
|
||||
{0x0c, "GCR (12960 bpi)"},
|
||||
{0x0d, "GCR (25380 bpi)"},
|
||||
{0x0f, "QIC-120 (GCR 10000 bpi)"},
|
||||
{0x10, "QIC-150/250 (GCR 10000 bpi)"},
|
||||
{0x11, "QIC-320/525 (GCR 16000 bpi)"},
|
||||
{0x12, "QIC-1350 (RLL 51667 bpi)"},
|
||||
{0x13, "DDS (61000 bpi)"},
|
||||
{0x14, "EXB-8200 (RLL 43245 bpi)"},
|
||||
{0x15, "EXB-8500 or QIC-1000"},
|
||||
{0x16, "MFM 10000 bpi"},
|
||||
{0x17, "MFM 42500 bpi"},
|
||||
{0x18, "TZ86"},
|
||||
{0x19, "DLT 10GB"},
|
||||
{0x1a, "DLT 20GB"},
|
||||
{0x1b, "DLT 35GB"},
|
||||
{0x1c, "QIC-385M"},
|
||||
{0x1d, "QIC-410M"},
|
||||
{0x1e, "QIC-1000C"},
|
||||
{0x1f, "QIC-2100C"},
|
||||
{0x20, "QIC-6GB"},
|
||||
{0x21, "QIC-20GB"},
|
||||
{0x22, "QIC-2GB"},
|
||||
{0x23, "QIC-875"},
|
||||
{0x24, "DDS-2"},
|
||||
{0x25, "DDS-3"},
|
||||
{0x26, "DDS-4 or QIC-4GB"},
|
||||
{0x27, "Exabyte Mammoth"},
|
||||
{0x28, "Exabyte Mammoth-2"},
|
||||
{0x29, "QIC-3080MC"},
|
||||
{0x30, "AIT-1 or MLR3"},
|
||||
{0x31, "AIT-2"},
|
||||
{0x33, "SLR6"},
|
||||
{0x34, "SLR100"},
|
||||
{0x40, "DLT1 40 GB, or Ultrium"},
|
||||
{0x41, "DLT 40GB"},
|
||||
{0x45, "QIC-3095-MC (TR-4)"},
|
||||
{0x47, "TR-5"},
|
||||
{0x80, "DLT 15GB uncomp. or Ecrix"},
|
||||
{0x81, "DLT 15GB compressed"},
|
||||
{0x82, "DLT 20GB uncompressed"},
|
||||
{0x83, "DLT 20GB compressed"},
|
||||
{0x84, "DLT 35GB uncompressed"},
|
||||
{0x85, "DLT 35GB compressed"},
|
||||
{0x86, "DLT1 40 GB uncompressed"},
|
||||
{0x87, "DLT1 40 GB compressed"},
|
||||
{0x88, "DLT 40GB uncompressed"},
|
||||
{0x89, "DLT 40GB compressed"},
|
||||
{0x8c, "EXB-8505 compressed"},
|
||||
{0x90, "EXB-8205 compressed"}
|
||||
};
|
||||
|
||||
#define NBR_DENSITIES (sizeof(density_tbl) / sizeof(struct densities))
|
||||
|
||||
static struct booleans {
|
||||
char *name;
|
||||
unsigned long bitmask;
|
||||
char *expl;
|
||||
} boolean_tbl[] = {
|
||||
{"buffer-writes", MT_ST_BUFFER_WRITES, "buffered writes"},
|
||||
{"async-writes", MT_ST_ASYNC_WRITES, "asynchronous writes"},
|
||||
{"read-ahead", MT_ST_READ_AHEAD, "read-ahead for fixed block size"},
|
||||
{"debug", MT_ST_DEBUGGING, "debugging (if compiled into driver)"},
|
||||
{"two-fms", MT_ST_TWO_FM, "write two filemarks when file closed"},
|
||||
{"fast-eod", MT_ST_FAST_MTEOM, "space directly to eod (and lose file number)"},
|
||||
{"auto-lock", MT_ST_AUTO_LOCK, "automatically lock/unlock drive door"},
|
||||
{"def-writes", MT_ST_DEF_WRITES, "the block size and density are for writes"},
|
||||
{"can-bsr", MT_ST_CAN_BSR, "drive can space backwards well"},
|
||||
{"no-blklimits", MT_ST_NO_BLKLIMS, "drive doesn't support read block limits"},
|
||||
{"can-partitions",MT_ST_CAN_PARTITIONS,"drive can handle partitioned tapes"},
|
||||
{"scsi2logical", MT_ST_SCSI2LOGICAL, "logical block addresses used with SCSI-2"},
|
||||
{"no-wait", MT_ST_NOWAIT, "immediate mode for rewind, etc."},
|
||||
#ifdef MT_ST_SYSV
|
||||
{"sysv", MT_ST_SYSV, "enable the SystemV semantics"},
|
||||
#endif
|
||||
{NULL, 0}};
|
||||
|
||||
static char *tape_name; /* The tape name for messages */
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int mtfd, cmd_code, i, argn, len, oflags;
|
||||
char *cmdstr;
|
||||
cmdef_tr *comp, *comp2;
|
||||
|
||||
for (argn=1; argn < argc; argn++)
|
||||
if (*argv[argn] == '-')
|
||||
switch (*(argv[argn] + 1)) {
|
||||
case 'f':
|
||||
case 't':
|
||||
argn += 1;
|
||||
if (argn >= argc) {
|
||||
usage(0);
|
||||
exit(1);
|
||||
}
|
||||
tape_name = argv[argn];
|
||||
break;
|
||||
case 'h':
|
||||
usage(1);
|
||||
exit(0);
|
||||
break;
|
||||
case 'v':
|
||||
printf("mt-st v. %s\n", VERSION);
|
||||
exit(0);
|
||||
break;
|
||||
case '-':
|
||||
if (*(argv[argn] + 1) == '-' &&
|
||||
*(argv[argn] + 2) == 'v') {
|
||||
printf("mt-st v. %s\n", VERSION);
|
||||
exit(0);
|
||||
}
|
||||
/* Fall through */
|
||||
default:
|
||||
usage(0);
|
||||
exit(1);
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
if (tape_name == NULL && (tape_name = getenv("TAPE")) == NULL)
|
||||
tape_name = DEFTAPE;
|
||||
|
||||
if (argn >= argc ) {
|
||||
usage(0);
|
||||
exit(1);
|
||||
}
|
||||
cmdstr = argv[argn++];
|
||||
|
||||
len = strlen(cmdstr);
|
||||
for (comp = cmds; comp->cmd_name != NULL; comp++)
|
||||
if (strncmp(cmdstr, comp->cmd_name, len) == 0)
|
||||
break;
|
||||
if (comp->cmd_name == NULL) {
|
||||
fprintf(stderr, "mt: unknown command \"%s\"\n", cmdstr);
|
||||
usage(1);
|
||||
exit(1);
|
||||
}
|
||||
if (len != strlen(comp->cmd_name)) {
|
||||
for (comp2 = comp + 1; comp2->cmd_name != NULL; comp2++)
|
||||
if (strncmp(cmdstr, comp2->cmd_name, len) == 0)
|
||||
break;
|
||||
if (comp2->cmd_name != NULL) {
|
||||
fprintf(stderr, "mt: ambiguous command \"%s\"\n", cmdstr);
|
||||
usage(1);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (comp->arg_cnt != MULTIPLE_ARGS && comp->arg_cnt < argc - argn) {
|
||||
fprintf(stderr, "mt: too many arguments for the command '%s'.\n",
|
||||
comp->cmd_name);
|
||||
exit(1);
|
||||
}
|
||||
cmd_code = comp->cmd_code;
|
||||
|
||||
if (comp->cmd_fdtype != NO_FD) {
|
||||
oflags = comp->cmd_fdtype == FD_RDONLY ? O_RDONLY : O_RDWR;
|
||||
if ((comp->error_tests & ET_ONLINE) == 0)
|
||||
oflags |= O_NONBLOCK;
|
||||
if ((mtfd = open(tape_name, oflags)) < 0) {
|
||||
perror(tape_name);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
mtfd = (-1);
|
||||
|
||||
if (comp->cmd_function != NULL) {
|
||||
i = comp->cmd_function(mtfd, comp, argc - argn,
|
||||
(argc - argn > 0 ? argv + argn : NULL));
|
||||
if (i) {
|
||||
if (errno == ENOSYS)
|
||||
fprintf(stderr, "mt: Command not supported by this kernel.\n");
|
||||
else if (comp->error_tests != 0)
|
||||
test_error(mtfd, comp);
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "mt: Internal error: command without function.\n");
|
||||
i = 1;
|
||||
}
|
||||
|
||||
if (mtfd >= 0)
|
||||
close(mtfd);
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
usage(int explain)
|
||||
{
|
||||
int ind;
|
||||
char line[100];
|
||||
|
||||
fprintf(stderr, "usage: mt [-v] [--version] [-h] [ -f device ] command [ count ]\n");
|
||||
if (explain) {
|
||||
for (ind=0; cmds[ind].cmd_name != NULL; ) {
|
||||
if (ind == 0)
|
||||
strcpy(line, "commands: ");
|
||||
else
|
||||
strcpy(line, " ");
|
||||
for ( ; cmds[ind].cmd_name != NULL; ind++) {
|
||||
strcat(line, cmds[ind].cmd_name);
|
||||
if (cmds[ind+1].cmd_name != NULL)
|
||||
strcat(line, ", ");
|
||||
else
|
||||
strcat(line, ".");
|
||||
if (strlen(line) >= 70 || cmds[ind+1].cmd_name == NULL) {
|
||||
fprintf(stderr, "%s\n", line);
|
||||
ind++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Do a command that simply feeds an argument to the MTIOCTOP ioctl */
|
||||
static int
|
||||
do_standard(int mtfd, cmdef_tr *cmd, int argc, char **argv)
|
||||
{
|
||||
struct mtop mt_com;
|
||||
|
||||
mt_com.mt_op = cmd->cmd_code;
|
||||
mt_com.mt_count = (argc > 0 ? strtol(*argv, NULL, 0) : 1);
|
||||
mt_com.mt_count |= cmd->cmd_count_bits;
|
||||
if (mt_com.mt_count < 0) {
|
||||
fprintf(stderr, "mt: negative repeat count\n");
|
||||
return 1;
|
||||
}
|
||||
if (ioctl(mtfd, MTIOCTOP, (char *)&mt_com) < 0) {
|
||||
perror(tape_name);
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* The the drive buffering and other things with this (highly overloaded)
|
||||
ioctl function. (See also do_options below.) */
|
||||
static int
|
||||
do_drvbuffer(int mtfd, cmdef_tr *cmd, int argc, char **argv)
|
||||
{
|
||||
struct mtop mt_com;
|
||||
|
||||
mt_com.mt_op = MTSETDRVBUFFER;
|
||||
mt_com.mt_count = (argc > 0 ? strtol(*argv, NULL, 0) : 1);
|
||||
if ((cmd->cmd_count_bits & MT_ST_OPTIONS) == MT_ST_DEF_OPTIONS)
|
||||
mt_com.mt_count &= 0xfffff;
|
||||
#ifdef MT_ST_TIMEOUTS
|
||||
else if ((cmd->cmd_count_bits & MT_ST_OPTIONS) == MT_ST_TIMEOUTS)
|
||||
mt_com.mt_count &= 0x7ffffff;
|
||||
#endif
|
||||
else
|
||||
mt_com.mt_count &= 0xfffffff;
|
||||
mt_com.mt_count |= cmd->cmd_count_bits;
|
||||
if (ioctl(mtfd, MTIOCTOP, (char *)&mt_com) < 0) {
|
||||
perror(tape_name);
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Set the tape driver options */
|
||||
static int
|
||||
do_options(int mtfd, cmdef_tr *cmd, int argc, char **argv)
|
||||
{
|
||||
int i, an, len;
|
||||
struct mtop mt_com;
|
||||
|
||||
mt_com.mt_op = MTSETDRVBUFFER;
|
||||
if (argc == 0)
|
||||
mt_com.mt_count = 0;
|
||||
else if (isdigit(**argv))
|
||||
mt_com.mt_count = strtol(*argv, NULL, 0) & ~MT_ST_OPTIONS;
|
||||
else
|
||||
for (an = 0, mt_com.mt_count = 0; an < argc; an++) {
|
||||
len = strlen(argv[an]);
|
||||
for (i=0; boolean_tbl[i].name != NULL; i++)
|
||||
if (!strncmp(boolean_tbl[i].name, argv[an], len)) {
|
||||
mt_com.mt_count |= boolean_tbl[i].bitmask;
|
||||
break;
|
||||
}
|
||||
if (boolean_tbl[i].name == NULL) {
|
||||
fprintf(stderr, "Illegal property name '%s'.\n", argv[an]);
|
||||
fprintf(stderr, "The implemented property names are:\n");
|
||||
for (i=0; boolean_tbl[i].name != NULL; i++)
|
||||
fprintf(stderr, " %9s -> %s\n", boolean_tbl[i].name,
|
||||
boolean_tbl[i].expl);
|
||||
return 1;
|
||||
}
|
||||
if (len != strlen(boolean_tbl[i].name))
|
||||
for (i++ ; boolean_tbl[i].name != NULL; i++)
|
||||
if (!strncmp(boolean_tbl[i].name, argv[an], len)) {
|
||||
fprintf(stderr, "Property name '%s' ambiguous.\n",
|
||||
argv[an]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
switch (cmd->cmd_code) {
|
||||
case DO_BOOLEANS:
|
||||
mt_com.mt_count |= MT_ST_BOOLEANS;
|
||||
break;
|
||||
case SET_BOOLEANS:
|
||||
mt_com.mt_count |= MT_ST_SETBOOLEANS;
|
||||
break;
|
||||
case CLEAR_BOOLEANS:
|
||||
mt_com.mt_count |= MT_ST_CLEARBOOLEANS;
|
||||
break;
|
||||
}
|
||||
if (ioctl(mtfd, MTIOCTOP, (char *)&mt_com) < 0) {
|
||||
perror(tape_name);
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Tell where the tape is */
|
||||
static int
|
||||
do_tell(int mtfd, cmdef_tr *cmd, int argc, char **argv)
|
||||
{
|
||||
struct mtpos mt_pos;
|
||||
|
||||
if (ioctl(mtfd, MTIOCPOS, (char *)&mt_pos) < 0) {
|
||||
perror(tape_name);
|
||||
return 2;
|
||||
}
|
||||
printf("At block %ld.\n", mt_pos.mt_blkno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Position the tape to a specific location within a specified partition */
|
||||
static int
|
||||
do_partseek(int mtfd, cmdef_tr *cmd, int argc, char **argv)
|
||||
{
|
||||
struct mtop mt_com;
|
||||
|
||||
mt_com.mt_op = MTSETPART;
|
||||
mt_com.mt_count = (argc > 0 ? strtol(*argv, NULL, 0) : 0);
|
||||
if (ioctl(mtfd, MTIOCTOP, (char *)&mt_com) < 0) {
|
||||
perror(tape_name);
|
||||
return 2;
|
||||
}
|
||||
mt_com.mt_op = MTSEEK;
|
||||
mt_com.mt_count = (argc > 1 ? strtol(argv[1], NULL, 0) : 0);
|
||||
if (ioctl(mtfd, MTIOCTOP, (char *)&mt_com) < 0) {
|
||||
perror(tape_name);
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Position to start of file n. This might be implemented more intelligently
|
||||
some day. */
|
||||
static int
|
||||
do_asf(int mtfd, cmdef_tr *cmd, int argc, char **argv)
|
||||
{
|
||||
struct mtop mt_com;
|
||||
|
||||
mt_com.mt_op = MTREW;
|
||||
mt_com.mt_count = 1;
|
||||
if (ioctl(mtfd, MTIOCTOP, (char *)&mt_com) < 0) {
|
||||
perror(tape_name);
|
||||
return 2;
|
||||
}
|
||||
mt_com.mt_count = (argc > 0 ? strtol(*argv, NULL, 0) : 0);
|
||||
if (mt_com.mt_count > 0) {
|
||||
mt_com.mt_op = MTFSF;
|
||||
if (ioctl(mtfd, MTIOCTOP, (char *)&mt_com) < 0) {
|
||||
perror(tape_name);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*** Decipher the status ***/
|
||||
|
||||
static int
|
||||
do_status(int mtfd, cmdef_tr *cmd, int argc, char **argv)
|
||||
{
|
||||
struct mtget status;
|
||||
int dens, i;
|
||||
char *type, *density;
|
||||
|
||||
if (ioctl(mtfd, MTIOCGET, (char *)&status) < 0) {
|
||||
perror(tape_name);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (status.mt_type == MT_ISSCSI1)
|
||||
type = "SCSI 1";
|
||||
else if (status.mt_type == MT_ISSCSI2)
|
||||
type = "SCSI 2";
|
||||
else if (status.mt_type == MT_ISONSTREAM_SC)
|
||||
type = "OnStream SC-, DI-, DP-, or USB";
|
||||
else
|
||||
type = NULL;
|
||||
if (type == NULL) {
|
||||
if (status.mt_type & 0x800000)
|
||||
printf ("qic-117 drive type = 0x%05lx\n", status.mt_type & 0x1ffff);
|
||||
else if (status.mt_type == 0)
|
||||
printf("IDE-Tape (type code 0) ?\n");
|
||||
else
|
||||
printf("Unknown tape drive type (type code %ld)\n", status.mt_type);
|
||||
printf("File number=%d, block number=%d.\n",
|
||||
status.mt_fileno, status.mt_blkno);
|
||||
printf("mt_resid: %ld, mt_erreg: 0x%lx\n",
|
||||
status.mt_resid, status.mt_erreg);
|
||||
printf("mt_dsreg: 0x%lx, mt_gstat: 0x%lx\n",
|
||||
status.mt_dsreg, status.mt_gstat);
|
||||
}
|
||||
else {
|
||||
printf("%s tape drive:\n", type);
|
||||
if (status.mt_type == MT_ISSCSI2)
|
||||
printf("File number=%d, block number=%d, partition=%ld.\n",
|
||||
status.mt_fileno, status.mt_blkno, (status.mt_resid & 0xff));
|
||||
else
|
||||
printf("File number=%d, block number=%d.\n",
|
||||
status.mt_fileno, status.mt_blkno);
|
||||
if (status.mt_type == MT_ISSCSI1 ||
|
||||
status.mt_type == MT_ISSCSI2 ||
|
||||
status.mt_type == MT_ISONSTREAM_SC) {
|
||||
dens = (status.mt_dsreg & MT_ST_DENSITY_MASK) >> MT_ST_DENSITY_SHIFT;
|
||||
density = "no translation";
|
||||
for (i=0; i < NBR_DENSITIES; i++)
|
||||
if (density_tbl[i].code == dens) {
|
||||
density = density_tbl[i].name;
|
||||
break;
|
||||
}
|
||||
printf("Tape block size %ld bytes. Density code 0x%x (%s).\n",
|
||||
((status.mt_dsreg & MT_ST_BLKSIZE_MASK) >> MT_ST_BLKSIZE_SHIFT),
|
||||
dens, density);
|
||||
|
||||
printf("Soft error count since last status=%ld\n",
|
||||
(status.mt_erreg & MT_ST_SOFTERR_MASK) >> MT_ST_SOFTERR_SHIFT);
|
||||
}
|
||||
}
|
||||
|
||||
printf("General status bits on (%lx):\n", status.mt_gstat);
|
||||
if (GMT_EOF(status.mt_gstat))
|
||||
printf(" EOF");
|
||||
if (GMT_BOT(status.mt_gstat))
|
||||
printf(" BOT");
|
||||
if (GMT_EOT(status.mt_gstat))
|
||||
printf(" EOT");
|
||||
if (GMT_SM(status.mt_gstat))
|
||||
printf(" SM");
|
||||
if (GMT_EOD(status.mt_gstat))
|
||||
printf(" EOD");
|
||||
if (GMT_WR_PROT(status.mt_gstat))
|
||||
printf(" WR_PROT");
|
||||
if (GMT_ONLINE(status.mt_gstat))
|
||||
printf(" ONLINE");
|
||||
if (GMT_D_6250(status.mt_gstat))
|
||||
printf(" D_6250");
|
||||
if (GMT_D_1600(status.mt_gstat))
|
||||
printf(" D_1600");
|
||||
if (GMT_D_800(status.mt_gstat))
|
||||
printf(" D_800");
|
||||
if (GMT_DR_OPEN(status.mt_gstat))
|
||||
printf(" DR_OPEN");
|
||||
if (GMT_IM_REP_EN(status.mt_gstat))
|
||||
printf(" IM_REP_EN");
|
||||
if (GMT_CLN(status.mt_gstat))
|
||||
printf(" CLN");
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Print a list of possible density codes */
|
||||
static int
|
||||
print_densities(int fd, cmdef_tr *cmd, int argc, char **argv)
|
||||
{
|
||||
int i, offset;
|
||||
|
||||
printf("Some SCSI tape density codes:\ncode explanation code explanation\n");
|
||||
offset = (NBR_DENSITIES + 1) / 2;
|
||||
for (i=0; i < offset; i++) {
|
||||
printf("0x%02x %-28s", density_tbl[i].code, density_tbl[i].name);
|
||||
if (i + offset < NBR_DENSITIES)
|
||||
printf(" 0x%02x %s\n", density_tbl[i + offset].code, density_tbl[i + offset].name);
|
||||
else
|
||||
printf("\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Try to find out why the command failed */
|
||||
static void
|
||||
test_error(int mtfd, cmdef_tr *cmd)
|
||||
{
|
||||
struct mtget status;
|
||||
|
||||
if (ioctl(mtfd, MTIOCGET, (char *)&status) < 0)
|
||||
return;
|
||||
|
||||
if (status.mt_type != MT_ISSCSI1 && status.mt_type != MT_ISSCSI2)
|
||||
return;
|
||||
|
||||
if ((cmd->error_tests & ET_ONLINE) && !GMT_ONLINE(status.mt_gstat))
|
||||
fprintf(stderr, "mt: The device is offline (not powered on, no tape ?).\n");
|
||||
if ((cmd->error_tests & ET_WPROT) && !GMT_WR_PROT(status.mt_gstat))
|
||||
fprintf(stderr, "mt: The tape is write-protected.\n");
|
||||
}
|
||||
|
||||
379
mtio.h
Normal file
379
mtio.h
Normal file
@@ -0,0 +1,379 @@
|
||||
/*
|
||||
* linux/mtio.h header file for Linux. Written by H. Bergman
|
||||
*
|
||||
* Modified for special ioctls provided by zftape in September 1997
|
||||
* by C.-J. Heine.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_MTIO_H
|
||||
#define _LINUX_MTIO_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/qic117.h>
|
||||
|
||||
/*
|
||||
* Structures and definitions for mag tape io control commands
|
||||
*/
|
||||
|
||||
/* structure for MTIOCTOP - mag tape op command */
|
||||
struct mtop {
|
||||
short mt_op; /* operations defined below */
|
||||
int mt_count; /* how many of them */
|
||||
};
|
||||
|
||||
/* Magnetic Tape operations [Not all operations supported by all drivers]: */
|
||||
#define MTRESET 0 /* +reset drive in case of problems */
|
||||
#define MTFSF 1 /* forward space over FileMark,
|
||||
* position at first record of next file
|
||||
*/
|
||||
#define MTBSF 2 /* backward space FileMark (position before FM) */
|
||||
#define MTFSR 3 /* forward space record */
|
||||
#define MTBSR 4 /* backward space record */
|
||||
#define MTWEOF 5 /* write an end-of-file record (mark) */
|
||||
#define MTREW 6 /* rewind */
|
||||
#define MTOFFL 7 /* rewind and put the drive offline (eject?) */
|
||||
#define MTNOP 8 /* no op, set status only (read with MTIOCGET) */
|
||||
#define MTRETEN 9 /* retension tape */
|
||||
#define MTBSFM 10 /* +backward space FileMark, position at FM */
|
||||
#define MTFSFM 11 /* +forward space FileMark, position at FM */
|
||||
#define MTEOM 12 /* goto end of recorded media (for appending files).
|
||||
* MTEOM positions after the last FM, ready for
|
||||
* appending another file.
|
||||
*/
|
||||
#define MTERASE 13 /* erase tape -- be careful! */
|
||||
|
||||
#define MTRAS1 14 /* run self test 1 (nondestructive) */
|
||||
#define MTRAS2 15 /* run self test 2 (destructive) */
|
||||
#define MTRAS3 16 /* reserved for self test 3 */
|
||||
|
||||
#define MTSETBLK 20 /* set block length (SCSI) */
|
||||
#define MTSETDENSITY 21 /* set tape density (SCSI) */
|
||||
#define MTSEEK 22 /* seek to block (Tandberg, etc.) */
|
||||
#define MTTELL 23 /* tell block (Tandberg, etc.) */
|
||||
#define MTSETDRVBUFFER 24 /* set the drive buffering according to SCSI-2 */
|
||||
/* ordinary buffered operation with code 1 */
|
||||
#define MTFSS 25 /* space forward over setmarks */
|
||||
#define MTBSS 26 /* space backward over setmarks */
|
||||
#define MTWSM 27 /* write setmarks */
|
||||
|
||||
#define MTLOCK 28 /* lock the drive door */
|
||||
#define MTUNLOCK 29 /* unlock the drive door */
|
||||
#define MTLOAD 30 /* execute the SCSI load command */
|
||||
#define MTUNLOAD 31 /* execute the SCSI unload command */
|
||||
#define MTCOMPRESSION 32/* control compression with SCSI mode page 15 */
|
||||
#define MTSETPART 33 /* Change the active tape partition */
|
||||
#define MTMKPART 34 /* Format the tape with one or two partitions */
|
||||
|
||||
/* structure for MTIOCGET - mag tape get status command */
|
||||
|
||||
struct mtget {
|
||||
long mt_type; /* type of magtape device */
|
||||
long mt_resid; /* residual count: (not sure)
|
||||
* number of bytes ignored, or
|
||||
* number of files not skipped, or
|
||||
* number of records not skipped.
|
||||
*/
|
||||
/* the following registers are device dependent */
|
||||
long mt_dsreg; /* status register */
|
||||
long mt_gstat; /* generic (device independent) status */
|
||||
long mt_erreg; /* error register */
|
||||
/* The next two fields are not always used */
|
||||
__kernel_daddr_t mt_fileno; /* number of current file on tape */
|
||||
__kernel_daddr_t mt_blkno; /* current block number */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Constants for mt_type. Not all of these are supported,
|
||||
* and these are not all of the ones that are supported.
|
||||
*/
|
||||
#define MT_ISUNKNOWN 0x01
|
||||
#define MT_ISQIC02 0x02 /* Generic QIC-02 tape streamer */
|
||||
#define MT_ISWT5150 0x03 /* Wangtek 5150EQ, QIC-150, QIC-02 */
|
||||
#define MT_ISARCHIVE_5945L2 0x04 /* Archive 5945L-2, QIC-24, QIC-02? */
|
||||
#define MT_ISCMSJ500 0x05 /* CMS Jumbo 500 (QIC-02?) */
|
||||
#define MT_ISTDC3610 0x06 /* Tandberg 6310, QIC-24 */
|
||||
#define MT_ISARCHIVE_VP60I 0x07 /* Archive VP60i, QIC-02 */
|
||||
#define MT_ISARCHIVE_2150L 0x08 /* Archive Viper 2150L */
|
||||
#define MT_ISARCHIVE_2060L 0x09 /* Archive Viper 2060L */
|
||||
#define MT_ISARCHIVESC499 0x0A /* Archive SC-499 QIC-36 controller */
|
||||
#define MT_ISQIC02_ALL_FEATURES 0x0F /* Generic QIC-02 with all features */
|
||||
#define MT_ISWT5099EEN24 0x11 /* Wangtek 5099-een24, 60MB, QIC-24 */
|
||||
#define MT_ISTEAC_MT2ST 0x12 /* Teac MT-2ST 155mb drive, Teac DC-1 card (Wangtek type) */
|
||||
#define MT_ISEVEREX_FT40A 0x32 /* Everex FT40A (QIC-40) */
|
||||
#define MT_ISDDS1 0x51 /* DDS device without partitions */
|
||||
#define MT_ISDDS2 0x52 /* DDS device with partitions */
|
||||
#define MT_ISONSTREAM_SC 0x61 /* OnStream SCSI tape drives (SC-x0)
|
||||
and SCSI emulated (DI, DP, USB) */
|
||||
#define MT_ISSCSI1 0x71 /* Generic ANSI SCSI-1 tape unit */
|
||||
#define MT_ISSCSI2 0x72 /* Generic ANSI SCSI-2 tape unit */
|
||||
|
||||
/* QIC-40/80/3010/3020 ftape supported drives.
|
||||
* 20bit vendor ID + 0x800000 (see ftape-vendors.h)
|
||||
*/
|
||||
#define MT_ISFTAPE_UNKNOWN 0x800000 /* obsolete */
|
||||
#define MT_ISFTAPE_FLAG 0x800000
|
||||
|
||||
struct mt_tape_info {
|
||||
long t_type; /* device type id (mt_type) */
|
||||
char *t_name; /* descriptive name */
|
||||
};
|
||||
|
||||
#define MT_TAPE_INFO { \
|
||||
{MT_ISUNKNOWN, "Unknown type of tape device"}, \
|
||||
{MT_ISQIC02, "Generic QIC-02 tape streamer"}, \
|
||||
{MT_ISWT5150, "Wangtek 5150, QIC-150"}, \
|
||||
{MT_ISARCHIVE_5945L2, "Archive 5945L-2"}, \
|
||||
{MT_ISCMSJ500, "CMS Jumbo 500"}, \
|
||||
{MT_ISTDC3610, "Tandberg TDC 3610, QIC-24"}, \
|
||||
{MT_ISARCHIVE_VP60I, "Archive VP60i, QIC-02"}, \
|
||||
{MT_ISARCHIVE_2150L, "Archive Viper 2150L"}, \
|
||||
{MT_ISARCHIVE_2060L, "Archive Viper 2060L"}, \
|
||||
{MT_ISARCHIVESC499, "Archive SC-499 QIC-36 controller"}, \
|
||||
{MT_ISQIC02_ALL_FEATURES, "Generic QIC-02 tape, all features"}, \
|
||||
{MT_ISWT5099EEN24, "Wangtek 5099-een24, 60MB"}, \
|
||||
{MT_ISTEAC_MT2ST, "Teac MT-2ST 155mb data cassette drive"}, \
|
||||
{MT_ISEVEREX_FT40A, "Everex FT40A, QIC-40"}, \
|
||||
{MT_ISONSTREAM_SC, "OnStream SC-, DI-, DP-, or USB tape drive"}, \
|
||||
{MT_ISSCSI1, "Generic SCSI-1 tape"}, \
|
||||
{MT_ISSCSI2, "Generic SCSI-2 tape"}, \
|
||||
{0, NULL} \
|
||||
}
|
||||
|
||||
|
||||
/* structure for MTIOCPOS - mag tape get position command */
|
||||
|
||||
struct mtpos {
|
||||
long mt_blkno; /* current block number */
|
||||
};
|
||||
|
||||
|
||||
/* structure for MTIOCGETCONFIG/MTIOCSETCONFIG primarily intended
|
||||
* as an interim solution for QIC-02 until DDI is fully implemented.
|
||||
*/
|
||||
struct mtconfiginfo {
|
||||
long mt_type; /* drive type */
|
||||
long ifc_type; /* interface card type */
|
||||
unsigned short irqnr; /* IRQ number to use */
|
||||
unsigned short dmanr; /* DMA channel to use */
|
||||
unsigned short port; /* IO port base address */
|
||||
|
||||
unsigned long debug; /* debugging flags */
|
||||
|
||||
unsigned have_dens:1;
|
||||
unsigned have_bsf:1;
|
||||
unsigned have_fsr:1;
|
||||
unsigned have_bsr:1;
|
||||
unsigned have_eod:1;
|
||||
unsigned have_seek:1;
|
||||
unsigned have_tell:1;
|
||||
unsigned have_ras1:1;
|
||||
unsigned have_ras2:1;
|
||||
unsigned have_ras3:1;
|
||||
unsigned have_qfa:1;
|
||||
|
||||
unsigned pad1:5;
|
||||
char reserved[10];
|
||||
};
|
||||
|
||||
/* structure for MTIOCVOLINFO, query information about the volume
|
||||
* currently positioned at (zftape)
|
||||
*/
|
||||
struct mtvolinfo {
|
||||
unsigned int mt_volno; /* vol-number */
|
||||
unsigned int mt_blksz; /* blocksize used when recording */
|
||||
unsigned int mt_rawsize; /* raw tape space consumed, in kb */
|
||||
unsigned int mt_size; /* volume size after decompression, in kb */
|
||||
unsigned int mt_cmpr:1; /* this volume has been compressed */
|
||||
};
|
||||
|
||||
/* raw access to a floppy drive, read and write an arbitrary segment.
|
||||
* For ftape/zftape to support formatting etc.
|
||||
*/
|
||||
#define MT_FT_RD_SINGLE 0
|
||||
#define MT_FT_RD_AHEAD 1
|
||||
#define MT_FT_WR_ASYNC 0 /* start tape only when all buffers are full */
|
||||
#define MT_FT_WR_MULTI 1 /* start tape, continue until buffers are empty */
|
||||
#define MT_FT_WR_SINGLE 2 /* write a single segment and stop afterwards */
|
||||
#define MT_FT_WR_DELETE 3 /* write deleted data marks, one segment at time */
|
||||
|
||||
struct mtftseg
|
||||
{
|
||||
unsigned mt_segno; /* the segment to read or write */
|
||||
unsigned mt_mode; /* modes for read/write (sync/async etc.) */
|
||||
int mt_result; /* result of r/w request, not of the ioctl */
|
||||
void *mt_data; /* User space buffer: must be 29kb */
|
||||
};
|
||||
|
||||
/* get tape capacity (ftape/zftape)
|
||||
*/
|
||||
struct mttapesize {
|
||||
unsigned long mt_capacity; /* entire, uncompressed capacity
|
||||
* of a cartridge
|
||||
*/
|
||||
unsigned long mt_used; /* what has been used so far, raw
|
||||
* uncompressed amount
|
||||
*/
|
||||
};
|
||||
|
||||
/* possible values of the ftfmt_op field
|
||||
*/
|
||||
#define FTFMT_SET_PARMS 1 /* set software parms */
|
||||
#define FTFMT_GET_PARMS 2 /* get software parms */
|
||||
#define FTFMT_FORMAT_TRACK 3 /* start formatting a tape track */
|
||||
#define FTFMT_STATUS 4 /* monitor formatting a tape track */
|
||||
#define FTFMT_VERIFY 5 /* verify the given segment */
|
||||
|
||||
struct ftfmtparms {
|
||||
unsigned char ft_qicstd; /* QIC-40/QIC-80/QIC-3010/QIC-3020 */
|
||||
unsigned char ft_fmtcode; /* Refer to the QIC specs */
|
||||
unsigned char ft_fhm; /* floppy head max */
|
||||
unsigned char ft_ftm; /* floppy track max */
|
||||
unsigned short ft_spt; /* segments per track */
|
||||
unsigned short ft_tpc; /* tracks per cartridge */
|
||||
};
|
||||
|
||||
struct ftfmttrack {
|
||||
unsigned int ft_track; /* track to format */
|
||||
unsigned char ft_gap3; /* size of gap3, for FORMAT_TRK */
|
||||
};
|
||||
|
||||
struct ftfmtstatus {
|
||||
unsigned int ft_segment; /* segment currently being formatted */
|
||||
};
|
||||
|
||||
struct ftfmtverify {
|
||||
unsigned int ft_segment; /* segment to verify */
|
||||
unsigned long ft_bsm; /* bsm as result of VERIFY cmd */
|
||||
};
|
||||
|
||||
struct mtftformat {
|
||||
unsigned int fmt_op; /* operation to perform */
|
||||
union fmt_arg {
|
||||
struct ftfmtparms fmt_parms; /* format parameters */
|
||||
struct ftfmttrack fmt_track; /* ctrl while formatting */
|
||||
struct ftfmtstatus fmt_status;
|
||||
struct ftfmtverify fmt_verify; /* for verifying */
|
||||
} fmt_arg;
|
||||
};
|
||||
|
||||
struct mtftcmd {
|
||||
unsigned int ft_wait_before; /* timeout to wait for drive to get ready
|
||||
* before command is sent. Milliseconds
|
||||
*/
|
||||
qic117_cmd_t ft_cmd; /* command to send */
|
||||
unsigned char ft_parm_cnt; /* zero: no parm is sent. */
|
||||
unsigned char ft_parms[3]; /* parameter(s) to send to
|
||||
* the drive. The parms are nibbles
|
||||
* driver sends cmd + 2 step pulses */
|
||||
unsigned int ft_result_bits; /* if non zero, number of bits
|
||||
* returned by the tape drive
|
||||
*/
|
||||
unsigned int ft_result; /* the result returned by the tape drive*/
|
||||
unsigned int ft_wait_after; /* timeout to wait for drive to get ready
|
||||
* after command is sent. 0: don't wait */
|
||||
int ft_status; /* status returned by ready wait
|
||||
* undefined if timeout was 0.
|
||||
*/
|
||||
int ft_error; /* error code if error status was set by
|
||||
* command
|
||||
*/
|
||||
};
|
||||
|
||||
/* mag tape io control commands */
|
||||
#define MTIOCTOP _IOW('m', 1, struct mtop) /* do a mag tape op */
|
||||
#define MTIOCGET _IOR('m', 2, struct mtget) /* get tape status */
|
||||
#define MTIOCPOS _IOR('m', 3, struct mtpos) /* get tape position */
|
||||
|
||||
/* The next two are used by the QIC-02 driver for runtime reconfiguration.
|
||||
* See tpqic02.h for struct mtconfiginfo.
|
||||
*/
|
||||
#define MTIOCGETCONFIG _IOR('m', 4, struct mtconfiginfo) /* get tape config */
|
||||
#define MTIOCSETCONFIG _IOW('m', 5, struct mtconfiginfo) /* set tape config */
|
||||
|
||||
/* the next six are used by the floppy ftape drivers and its frontends
|
||||
* sorry, but MTIOCTOP commands are write only.
|
||||
*/
|
||||
#define MTIOCRDFTSEG _IOWR('m', 6, struct mtftseg) /* read a segment */
|
||||
#define MTIOCWRFTSEG _IOWR('m', 7, struct mtftseg) /* write a segment */
|
||||
#define MTIOCVOLINFO _IOR('m', 8, struct mtvolinfo) /* info about volume */
|
||||
#define MTIOCGETSIZE _IOR('m', 9, struct mttapesize)/* get cartridge size*/
|
||||
#define MTIOCFTFORMAT _IOWR('m', 10, struct mtftformat) /* format ftape */
|
||||
#define MTIOCFTCMD _IOWR('m', 11, struct mtftcmd) /* send QIC-117 cmd */
|
||||
|
||||
/* Generic Mag Tape (device independent) status macros for examining
|
||||
* mt_gstat -- HP-UX compatible.
|
||||
* There is room for more generic status bits here, but I don't
|
||||
* know which of them are reserved. At least three or so should
|
||||
* be added to make this really useful.
|
||||
*/
|
||||
#define GMT_EOF(x) ((x) & 0x80000000)
|
||||
#define GMT_BOT(x) ((x) & 0x40000000)
|
||||
#define GMT_EOT(x) ((x) & 0x20000000)
|
||||
#define GMT_SM(x) ((x) & 0x10000000) /* DDS setmark */
|
||||
#define GMT_EOD(x) ((x) & 0x08000000) /* DDS EOD */
|
||||
#define GMT_WR_PROT(x) ((x) & 0x04000000)
|
||||
/* #define GMT_ ? ((x) & 0x02000000) */
|
||||
#define GMT_ONLINE(x) ((x) & 0x01000000)
|
||||
#define GMT_D_6250(x) ((x) & 0x00800000)
|
||||
#define GMT_D_1600(x) ((x) & 0x00400000)
|
||||
#define GMT_D_800(x) ((x) & 0x00200000)
|
||||
/* #define GMT_ ? ((x) & 0x00100000) */
|
||||
/* #define GMT_ ? ((x) & 0x00080000) */
|
||||
#define GMT_DR_OPEN(x) ((x) & 0x00040000) /* door open (no tape) */
|
||||
/* #define GMT_ ? ((x) & 0x00020000) */
|
||||
#define GMT_IM_REP_EN(x) ((x) & 0x00010000) /* immediate report mode */
|
||||
#define GMT_CLN(x) ((x) & 0x00008000) /* cleaning requested */
|
||||
/* 15 generic status bits unused */
|
||||
|
||||
|
||||
/* SCSI-tape specific definitions */
|
||||
/* Bitfield shifts in the status */
|
||||
#define MT_ST_BLKSIZE_SHIFT 0
|
||||
#define MT_ST_BLKSIZE_MASK 0xffffff
|
||||
#define MT_ST_DENSITY_SHIFT 24
|
||||
#define MT_ST_DENSITY_MASK 0xff000000
|
||||
|
||||
#define MT_ST_SOFTERR_SHIFT 0
|
||||
#define MT_ST_SOFTERR_MASK 0xffff
|
||||
|
||||
/* Bitfields for the MTSETDRVBUFFER ioctl */
|
||||
#define MT_ST_OPTIONS 0xf0000000
|
||||
#define MT_ST_BOOLEANS 0x10000000
|
||||
#define MT_ST_SETBOOLEANS 0x30000000
|
||||
#define MT_ST_CLEARBOOLEANS 0x40000000
|
||||
#define MT_ST_WRITE_THRESHOLD 0x20000000
|
||||
#define MT_ST_DEF_BLKSIZE 0x50000000
|
||||
#define MT_ST_DEF_OPTIONS 0x60000000
|
||||
#define MT_ST_TIMEOUTS 0x70000000
|
||||
#define MT_ST_SET_TIMEOUT (MT_ST_TIMEOUTS | 0x000000)
|
||||
#define MT_ST_SET_LONG_TIMEOUT (MT_ST_TIMEOUTS | 0x100000)
|
||||
#define MT_ST_SET_CLN 0x80000000
|
||||
|
||||
#define MT_ST_BUFFER_WRITES 0x1
|
||||
#define MT_ST_ASYNC_WRITES 0x2
|
||||
#define MT_ST_READ_AHEAD 0x4
|
||||
#define MT_ST_DEBUGGING 0x8
|
||||
#define MT_ST_TWO_FM 0x10
|
||||
#define MT_ST_FAST_MTEOM 0x20
|
||||
#define MT_ST_AUTO_LOCK 0x40
|
||||
#define MT_ST_DEF_WRITES 0x80
|
||||
#define MT_ST_CAN_BSR 0x100
|
||||
#define MT_ST_NO_BLKLIMS 0x200
|
||||
#define MT_ST_CAN_PARTITIONS 0x400
|
||||
#define MT_ST_SCSI2LOGICAL 0x800
|
||||
#define MT_ST_SYSV 0x1000
|
||||
#define MT_ST_NOWAIT 0x2000
|
||||
|
||||
/* The mode parameters to be controlled. Parameter chosen with bits 20-28 */
|
||||
#define MT_ST_CLEAR_DEFAULT 0xfffff
|
||||
#define MT_ST_DEF_DENSITY (MT_ST_DEF_OPTIONS | 0x100000)
|
||||
#define MT_ST_DEF_COMPRESSION (MT_ST_DEF_OPTIONS | 0x200000)
|
||||
#define MT_ST_DEF_DRVBUFFER (MT_ST_DEF_OPTIONS | 0x300000)
|
||||
|
||||
/* The offset for the arguments for the special HP changer load command. */
|
||||
#define MT_ST_HPLOADER_OFFSET 10000
|
||||
|
||||
#endif /* _LINUX_MTIO_H */
|
||||
290
qic117.h
Normal file
290
qic117.h
Normal file
@@ -0,0 +1,290 @@
|
||||
#ifndef _QIC117_H
|
||||
#define _QIC117_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 1993-1996 Bas Laarhoven,
|
||||
* (C) 1997 Claus-Justus Heine.
|
||||
|
||||
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.
|
||||
|
||||
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; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*
|
||||
* $Source: /homes/cvs/ftape-stacked/include/linux/qic117.h,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:19:32 $
|
||||
*
|
||||
* This file contains QIC-117 spec. related definitions for the
|
||||
* QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux.
|
||||
*
|
||||
* These data were taken from the Quarter-Inch Cartridge
|
||||
* Drive Standards, Inc. document titled:
|
||||
* `Common Command Set Interface Specification for Flexible
|
||||
* Disk Controller Based Minicartridge Tape Drives'
|
||||
* document QIC-117 Revision J, 28 Aug 96.
|
||||
* For more information, contact:
|
||||
* Quarter-Inch Cartridge Drive Standards, Inc.
|
||||
* 311 East Carrillo Street
|
||||
* Santa Barbara, California 93101
|
||||
* Telephone (805) 963-3853
|
||||
* Fax (805) 962-1541
|
||||
* WWW http://www.qic.org
|
||||
*
|
||||
* Current QIC standard revisions (of interest) are:
|
||||
* QIC-40-MC, Rev. M, 2 Sep 92.
|
||||
* QIC-80-MC, Rev. N, 20 Mar 96.
|
||||
* QIC-80-MC, Rev. K, 15 Dec 94.
|
||||
* QIC-113, Rev. G, 15 Jun 95.
|
||||
* QIC-117, Rev. J, 28 Aug 96.
|
||||
* QIC-122, Rev. B, 6 Mar 91.
|
||||
* QIC-130, Rev. C, 2 Sep 92.
|
||||
* QIC-3010-MC, Rev. F, 14 Jun 95.
|
||||
* QIC-3020-MC, Rev. G, 31 Aug 95.
|
||||
* QIC-CRF3, Rev. B, 15 Jun 95.
|
||||
* */
|
||||
|
||||
/*
|
||||
* QIC-117 common command set rev. J.
|
||||
* These commands are sent to the tape unit
|
||||
* as number of pulses over the step line.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
QIC_NO_COMMAND = 0,
|
||||
QIC_RESET = 1,
|
||||
QIC_REPORT_NEXT_BIT = 2,
|
||||
QIC_PAUSE = 3,
|
||||
QIC_MICRO_STEP_PAUSE = 4,
|
||||
QIC_ALTERNATE_TIMEOUT = 5,
|
||||
QIC_REPORT_DRIVE_STATUS = 6,
|
||||
QIC_REPORT_ERROR_CODE = 7,
|
||||
QIC_REPORT_DRIVE_CONFIGURATION = 8,
|
||||
QIC_REPORT_ROM_VERSION = 9,
|
||||
QIC_LOGICAL_FORWARD = 10,
|
||||
QIC_PHYSICAL_REVERSE = 11,
|
||||
QIC_PHYSICAL_FORWARD = 12,
|
||||
QIC_SEEK_HEAD_TO_TRACK = 13,
|
||||
QIC_SEEK_LOAD_POINT = 14,
|
||||
QIC_ENTER_FORMAT_MODE = 15,
|
||||
QIC_WRITE_REFERENCE_BURST = 16,
|
||||
QIC_ENTER_VERIFY_MODE = 17,
|
||||
QIC_STOP_TAPE = 18,
|
||||
/* commands 19-20: reserved */
|
||||
QIC_MICRO_STEP_HEAD_UP = 21,
|
||||
QIC_MICRO_STEP_HEAD_DOWN = 22,
|
||||
QIC_SOFT_SELECT = 23,
|
||||
QIC_SOFT_DESELECT = 24,
|
||||
QIC_SKIP_REVERSE = 25,
|
||||
QIC_SKIP_FORWARD = 26,
|
||||
QIC_SELECT_RATE = 27,
|
||||
/* command 27, in ccs2: Select Rate or Format */
|
||||
QIC_ENTER_DIAGNOSTIC_1 = 28,
|
||||
QIC_ENTER_DIAGNOSTIC_2 = 29,
|
||||
QIC_ENTER_PRIMARY_MODE = 30,
|
||||
/* command 31: vendor unique */
|
||||
QIC_REPORT_VENDOR_ID = 32,
|
||||
QIC_REPORT_TAPE_STATUS = 33,
|
||||
QIC_SKIP_EXTENDED_REVERSE = 34,
|
||||
QIC_SKIP_EXTENDED_FORWARD = 35,
|
||||
QIC_CALIBRATE_TAPE_LENGTH = 36,
|
||||
QIC_REPORT_FORMAT_SEGMENTS = 37,
|
||||
QIC_SET_FORMAT_SEGMENTS = 38,
|
||||
/* commands 39-45: reserved */
|
||||
QIC_PHANTOM_SELECT = 46,
|
||||
QIC_PHANTOM_DESELECT = 47
|
||||
} qic117_cmd_t;
|
||||
|
||||
typedef enum {
|
||||
discretional = 0, required, ccs1, ccs2
|
||||
} qic_compatibility;
|
||||
|
||||
typedef enum {
|
||||
unused, mode, motion, report
|
||||
} command_types;
|
||||
|
||||
struct qic117_command_table {
|
||||
char *name;
|
||||
__u8 mask;
|
||||
__u8 state;
|
||||
__u8 cmd_type;
|
||||
__u8 non_intr;
|
||||
__u8 level;
|
||||
};
|
||||
|
||||
#define QIC117_COMMANDS {\
|
||||
/* command mask state cmd_type */\
|
||||
/* | name | | | non_intr */\
|
||||
/* | | | | | | level */\
|
||||
/* 0*/ {NULL, 0x00, 0x00, mode, 0, discretional},\
|
||||
/* 1*/ {"soft reset", 0x00, 0x00, motion, 1, required},\
|
||||
/* 2*/ {"report next bit", 0x00, 0x00, report, 0, required},\
|
||||
/* 3*/ {"pause", 0x36, 0x24, motion, 1, required},\
|
||||
/* 4*/ {"micro step pause", 0x36, 0x24, motion, 1, required},\
|
||||
/* 5*/ {"alternate command timeout", 0x00, 0x00, mode, 0, required},\
|
||||
/* 6*/ {"report drive status", 0x00, 0x00, report, 0, required},\
|
||||
/* 7*/ {"report error code", 0x01, 0x01, report, 0, required},\
|
||||
/* 8*/ {"report drive configuration",0x00, 0x00, report, 0, required},\
|
||||
/* 9*/ {"report rom version", 0x00, 0x00, report, 0, required},\
|
||||
/*10*/ {"logical forward", 0x37, 0x25, motion, 0, required},\
|
||||
/*11*/ {"physical reverse", 0x17, 0x05, motion, 0, required},\
|
||||
/*12*/ {"physical forward", 0x17, 0x05, motion, 0, required},\
|
||||
/*13*/ {"seek head to track", 0x37, 0x25, motion, 0, required},\
|
||||
/*14*/ {"seek load point", 0x17, 0x05, motion, 1, required},\
|
||||
/*15*/ {"enter format mode", 0x1f, 0x05, mode, 0, required},\
|
||||
/*16*/ {"write reference burst", 0x1f, 0x05, motion, 1, required},\
|
||||
/*17*/ {"enter verify mode", 0x37, 0x25, mode, 0, required},\
|
||||
/*18*/ {"stop tape", 0x00, 0x00, motion, 1, required},\
|
||||
/*19*/ {"reserved (19)", 0x00, 0x00, unused, 0, discretional},\
|
||||
/*20*/ {"reserved (20)", 0x00, 0x00, unused, 0, discretional},\
|
||||
/*21*/ {"micro step head up", 0x02, 0x00, motion, 0, required},\
|
||||
/*22*/ {"micro step head down", 0x02, 0x00, motion, 0, required},\
|
||||
/*23*/ {"soft select", 0x00, 0x00, mode, 0, discretional},\
|
||||
/*24*/ {"soft deselect", 0x00, 0x00, mode, 0, discretional},\
|
||||
/*25*/ {"skip segments reverse", 0x36, 0x24, motion, 1, required},\
|
||||
/*26*/ {"skip segments forward", 0x36, 0x24, motion, 1, required},\
|
||||
/*27*/ {"select rate or format", 0x03, 0x01, mode, 0, required /* [ccs2] */},\
|
||||
/*28*/ {"enter diag mode 1", 0x00, 0x00, mode, 0, discretional},\
|
||||
/*29*/ {"enter diag mode 2", 0x00, 0x00, mode, 0, discretional},\
|
||||
/*30*/ {"enter primary mode", 0x00, 0x00, mode, 0, required},\
|
||||
/*31*/ {"vendor unique (31)", 0x00, 0x00, unused, 0, discretional},\
|
||||
/*32*/ {"report vendor id", 0x00, 0x00, report, 0, required},\
|
||||
/*33*/ {"report tape status", 0x04, 0x04, report, 0, ccs1},\
|
||||
/*34*/ {"skip extended reverse", 0x36, 0x24, motion, 1, ccs1},\
|
||||
/*35*/ {"skip extended forward", 0x36, 0x24, motion, 1, ccs1},\
|
||||
/*36*/ {"calibrate tape length", 0x17, 0x05, motion, 1, ccs2},\
|
||||
/*37*/ {"report format segments", 0x17, 0x05, report, 0, ccs2},\
|
||||
/*38*/ {"set format segments", 0x17, 0x05, mode, 0, ccs2},\
|
||||
/*39*/ {"reserved (39)", 0x00, 0x00, unused, 0, discretional},\
|
||||
/*40*/ {"vendor unique (40)", 0x00, 0x00, unused, 0, discretional},\
|
||||
/*41*/ {"vendor unique (41)", 0x00, 0x00, unused, 0, discretional},\
|
||||
/*42*/ {"vendor unique (42)", 0x00, 0x00, unused, 0, discretional},\
|
||||
/*43*/ {"vendor unique (43)", 0x00, 0x00, unused, 0, discretional},\
|
||||
/*44*/ {"vendor unique (44)", 0x00, 0x00, unused, 0, discretional},\
|
||||
/*45*/ {"vendor unique (45)", 0x00, 0x00, unused, 0, discretional},\
|
||||
/*46*/ {"phantom select", 0x00, 0x00, mode, 0, discretional},\
|
||||
/*47*/ {"phantom deselect", 0x00, 0x00, mode, 0, discretional},\
|
||||
}
|
||||
|
||||
/*
|
||||
* Status bits returned by QIC_REPORT_DRIVE_STATUS
|
||||
*/
|
||||
|
||||
#define QIC_STATUS_READY 0x01 /* Drive is ready or idle. */
|
||||
#define QIC_STATUS_ERROR 0x02 /* Error detected, must read
|
||||
error code to clear this */
|
||||
#define QIC_STATUS_CARTRIDGE_PRESENT 0x04 /* Tape is present */
|
||||
#define QIC_STATUS_WRITE_PROTECT 0x08 /* Tape is write protected */
|
||||
#define QIC_STATUS_NEW_CARTRIDGE 0x10 /* New cartridge inserted, must
|
||||
read error status to clear. */
|
||||
#define QIC_STATUS_REFERENCED 0x20 /* Cartridge appears to have been
|
||||
formatted. */
|
||||
#define QIC_STATUS_AT_BOT 0x40 /* Cartridge is at physical
|
||||
beginning of tape. */
|
||||
#define QIC_STATUS_AT_EOT 0x80 /* Cartridge is at physical end
|
||||
of tape. */
|
||||
/*
|
||||
* Status bits returned by QIC_REPORT_DRIVE_CONFIGURATION
|
||||
*/
|
||||
|
||||
#define QIC_CONFIG_RATE_MASK 0x18
|
||||
#define QIC_CONFIG_RATE_SHIFT 3
|
||||
#define QIC_CONFIG_RATE_250 0
|
||||
#define QIC_CONFIG_RATE_500 2
|
||||
#define QIC_CONFIG_RATE_1000 3
|
||||
#define QIC_CONFIG_RATE_2000 1
|
||||
#define QIC_CONFIG_RATE_4000 0 /* since QIC-117 Rev. J */
|
||||
|
||||
#define QIC_CONFIG_LONG 0x40 /* Extra Length Tape Detected */
|
||||
#define QIC_CONFIG_80 0x80 /* QIC-80 detected. */
|
||||
|
||||
/*
|
||||
* Status bits returned by QIC_REPORT_TAPE_STATUS
|
||||
*/
|
||||
|
||||
#define QIC_TAPE_STD_MASK 0x0f
|
||||
#define QIC_TAPE_QIC40 0x01
|
||||
#define QIC_TAPE_QIC80 0x02
|
||||
#define QIC_TAPE_QIC3020 0x03
|
||||
#define QIC_TAPE_QIC3010 0x04
|
||||
|
||||
#define QIC_TAPE_LEN_MASK 0x70
|
||||
#define QIC_TAPE_205FT 0x10
|
||||
#define QIC_TAPE_307FT 0x20
|
||||
#define QIC_TAPE_VARIABLE 0x30
|
||||
#define QIC_TAPE_1100FT 0x40
|
||||
#define QIC_TAPE_FLEX 0x60
|
||||
|
||||
#define QIC_TAPE_WIDE 0x80
|
||||
|
||||
/* Define a value (in feet) slightly higher than
|
||||
* the possible maximum tape length.
|
||||
*/
|
||||
#define QIC_TOP_TAPE_LEN 1500
|
||||
|
||||
/*
|
||||
* Errors: List of error codes, and their severity.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
char *message; /* Text describing the error. */
|
||||
unsigned int fatal:1; /* Non-zero if the error is fatal. */
|
||||
} ftape_error;
|
||||
|
||||
#define QIC117_ERRORS {\
|
||||
/* 0*/ { "No error", 0, },\
|
||||
/* 1*/ { "Command Received while Drive Not Ready", 0, },\
|
||||
/* 2*/ { "Cartridge Not Present or Removed", 1, },\
|
||||
/* 3*/ { "Motor Speed Error (not within 1%)", 1, },\
|
||||
/* 4*/ { "Motor Speed Fault (jammed, or gross speed error", 1, },\
|
||||
/* 5*/ { "Cartridge Write Protected", 1, },\
|
||||
/* 6*/ { "Undefined or Reserved Command Code", 1, },\
|
||||
/* 7*/ { "Illegal Track Address Specified for Seek", 1, },\
|
||||
/* 8*/ { "Illegal Command in Report Subcontext", 0, },\
|
||||
/* 9*/ { "Illegal Entry into a Diagnostic Mode", 1, },\
|
||||
/*10*/ { "Broken Tape Detected (based on hole sensor)", 1, },\
|
||||
/*11*/ { "Warning--Read Gain Setting Error", 1, },\
|
||||
/*12*/ { "Command Received While Error Status Pending (obs)", 1, },\
|
||||
/*13*/ { "Command Received While New Cartridge Pending", 1, },\
|
||||
/*14*/ { "Command Illegal or Undefined in Primary Mode", 1, },\
|
||||
/*15*/ { "Command Illegal or Undefined in Format Mode", 1, },\
|
||||
/*16*/ { "Command Illegal or Undefined in Verify Mode", 1, },\
|
||||
/*17*/ { "Logical Forward Not at Logical BOT or no Format Segments in Format Mode", 1, },\
|
||||
/*18*/ { "Logical EOT Before All Segments generated", 1, },\
|
||||
/*19*/ { "Command Illegal When Cartridge Not Referenced", 1, },\
|
||||
/*20*/ { "Self-Diagnostic Failed (cannot be cleared)", 1, },\
|
||||
/*21*/ { "Warning EEPROM Not Initialized, Defaults Set", 1, },\
|
||||
/*22*/ { "EEPROM Corrupted or Hardware Failure", 1, },\
|
||||
/*23*/ { "Motion Time-out Error", 1, },\
|
||||
/*24*/ { "Data Segment Too Long -- Logical Forward or Pause", 1, },\
|
||||
/*25*/ { "Transmit Overrun (obs)", 1, },\
|
||||
/*26*/ { "Power On Reset Occurred", 0, },\
|
||||
/*27*/ { "Software Reset Occurred", 0, },\
|
||||
/*28*/ { "Diagnostic Mode 1 Error", 1, },\
|
||||
/*29*/ { "Diagnostic Mode 2 Error", 1, },\
|
||||
/*30*/ { "Command Received During Non-Interruptible Process", 1, },\
|
||||
/*31*/ { "Rate or Format Selection Error", 1, },\
|
||||
/*32*/ { "Illegal Command While in High Speed Mode", 1, },\
|
||||
/*33*/ { "Illegal Seek Segment Value", 1, },\
|
||||
/*34*/ { "Invalid Media", 1, },\
|
||||
/*35*/ { "Head Positioning Failure", 1, },\
|
||||
/*36*/ { "Write Reference Burst Failure", 1, },\
|
||||
/*37*/ { "Prom Code Missing", 1, },\
|
||||
/*38*/ { "Invalid Format", 1, },\
|
||||
/*39*/ { "EOT/BOT System Failure", 1, },\
|
||||
/*40*/ { "Prom A Checksum Error", 1, },\
|
||||
/*41*/ { "Drive Wakeup Reset Occurred", 1, },\
|
||||
/*42*/ { "Prom B Checksum Error", 1, },\
|
||||
/*43*/ { "Illegal Entry into Format Mode", 1, },\
|
||||
}
|
||||
|
||||
#endif /* _QIC117_H */
|
||||
262
stinit.8
Normal file
262
stinit.8
Normal file
@@ -0,0 +1,262 @@
|
||||
.TH STINIT 8 "November 2001" \" -*- nroff -*-
|
||||
.SH NAME
|
||||
stinit \- initialize SCSI magnetic tape drives
|
||||
.SH SYNOPSIS
|
||||
.B stinit
|
||||
[\-f conf-file] [\-h] [-p] [-r] [-v] [devices...]
|
||||
.SH DESCRIPTION
|
||||
This manual page documents the tape control program
|
||||
.BR stinit
|
||||
can used to initialize SCSI tape drive modes at system startup, after
|
||||
loading the tape driver as module, or after introduction of new device
|
||||
to the SCSI subsystem at run-time. The initialization is performed by
|
||||
sending ioctl commands to the drive. The commands are defined in a
|
||||
text file that is indexed using the inquiry data the drive returns
|
||||
(manufacturer, device, revision). Values for all of the general and
|
||||
mode-specific SCSI tape parameters up to Linux version 2.4.15 can be
|
||||
initialized.
|
||||
.PP
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.I \-f conf-file
|
||||
Specifies the name of the text file containing the definitions for
|
||||
different tape drive types. By default
|
||||
.B stinit
|
||||
tries to find the definition file
|
||||
.I stinit.def
|
||||
or
|
||||
.I /etc/stinit.def
|
||||
(in this order).
|
||||
.TP
|
||||
.I \-h
|
||||
Print the usage information.
|
||||
.TP
|
||||
.I \-p
|
||||
The definition file is parsed but no tape drive initialization is
|
||||
attempted. This option can be used for testing the integrity of a
|
||||
definition file after changes have been made.
|
||||
.TP
|
||||
.I \-r
|
||||
Rewind every device being initialized.
|
||||
.TP
|
||||
.I \-v
|
||||
The more -v options (currently up to two), the more verbose output.
|
||||
.TP
|
||||
.I \-\-version
|
||||
Print the program version.
|
||||
.PP
|
||||
.SH THE DEVICES BEING INITIALIZED
|
||||
If the program is started without arguments, it tries to find all
|
||||
accessible SCSI tape devices and the device files for the different
|
||||
modes of the devices. The tape drives are searched in the scanning
|
||||
order of the kernel and searching is stopped at the first non-existing
|
||||
tape. All of the found devices are initialized if a matching
|
||||
description is found from the parameter file. Note that a mode for a
|
||||
device is not initialized if the corresponding device file is not
|
||||
found even if a matching description for the mode exists. The
|
||||
non-rewind device is preferred over the auto-rewind device for each
|
||||
mode. If the directory
|
||||
.I /dev/tapes
|
||||
is found, the devfs filesystem is assumed to be mounted on /dev. Otherwise,
|
||||
the directories
|
||||
.I /dev/scsi
|
||||
and
|
||||
.I /dev
|
||||
are scanned for device files.
|
||||
.PP
|
||||
SCSI tape drives can be initialized selectively using program
|
||||
arguments. A numeric argument specifies the number of the tape drive
|
||||
in the scanning order of the kernel. A file name specifies that the
|
||||
device corresponding to this name is to be initialized. If the file name
|
||||
is given without the directory specification, the program searches for
|
||||
the name in the device directories
|
||||
.I
|
||||
/dev/scsi
|
||||
and
|
||||
.I /dev.
|
||||
Only full path names are supported with devfs.
|
||||
.PP
|
||||
.SH THE CONFIGURATION FILE
|
||||
The configuration file is a simple text file that contains
|
||||
descriptions of tape drives and the corresponding initialization
|
||||
parameters. The parameter definition blocks are delimited by
|
||||
.I {}.
|
||||
Specification of the drive description is restarted after each
|
||||
parameter definition block.
|
||||
.PP
|
||||
The drive descriptions and the parameter definitions consist of pairs
|
||||
.I name = value.
|
||||
The value is either a numeric parameter, a string not containing
|
||||
blanks, or a quoted string. If the
|
||||
.I =value
|
||||
-part is omitted, the value
|
||||
.I
|
||||
"1"
|
||||
is used. If the character
|
||||
.I #
|
||||
is found from an input line, the rest of the line is discarded. This
|
||||
allows use of comments in the definition file. The following example
|
||||
contains definitions for one type of tape drives:
|
||||
.PP
|
||||
.RS
|
||||
.nf
|
||||
# The XY dat
|
||||
manufacturer=XY-COMPANY model = "UVW DRIVE" {
|
||||
scsi2logical=1 # Common definitions for all modes
|
||||
can-bsr can-partitions auto-lock
|
||||
# Definition of modes
|
||||
mode1 blocksize=0 compression=1
|
||||
mode2 blocksize=1024 compression=1
|
||||
mode3 blocksize=0 compression=0
|
||||
mode4 blocksize = 1024 compression=0 }
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
The devices are identified using zero or more of the following
|
||||
keywords corresponding to the data returned by the tape device as
|
||||
response to the SCSI INQUIRY command. The matches are case-sensitive
|
||||
and performed up to the length defined in the configuration file
|
||||
(permitting use of partial matches).
|
||||
.IP manufacturer=
|
||||
This keyword specifies the string that must match the vendor
|
||||
identification returned by the device.
|
||||
.IP model=
|
||||
This keyword defines the string that must match the
|
||||
.B product identification
|
||||
returned by the device.
|
||||
.IP revision=
|
||||
This keyword matched the string that must match the
|
||||
.B product revision level
|
||||
returned by the device.
|
||||
.PP
|
||||
All of the matching initializations are collected in the order they
|
||||
are defined in the file. This means that common parameters can be
|
||||
defined for all devices using zero keywords for a definition
|
||||
block. Another consequence is that, for instance, some parameters can
|
||||
be easily given different values for a specific firmware revision without
|
||||
repeating the parameters common to all revisions.
|
||||
.PP
|
||||
The tape parameters are defined using the following keywords. More
|
||||
thorough description of the parameters can be found from the
|
||||
.I st(4)
|
||||
man page (not up to date when this is written) or from the file
|
||||
.I drivers/scsi/README.st
|
||||
in the Linux kernel source tree. The keywords are matched using only
|
||||
the first characters. The part of the keywords not used in matching is
|
||||
enclosed by []. The numeric values may be specified either in decimal
|
||||
notation or hexadecimal notation (using the prefix 0x).
|
||||
.IP drive-[buffering]=value
|
||||
The drive's buffering parameter is set to
|
||||
.I value.
|
||||
This parameter if common for all modes.
|
||||
.IP cleaning
|
||||
The cleaning request notifying parameter is set to
|
||||
.I value
|
||||
.IP no-w[ait]
|
||||
The immediate mode is used with commands like rewind if
|
||||
.I value
|
||||
is non-zero (i.e., the driver does not wait for the command to finish).
|
||||
.IP mode=value
|
||||
This keyword starts definition of tape mode
|
||||
.I value.
|
||||
The number of the mode must be between 1 and 4.
|
||||
.IP disab[led]=value
|
||||
This mode is disabled for this device if
|
||||
.I value
|
||||
is non-zero. Can be used if some mode defined in a more general
|
||||
definition should be disabled by a more specific definition for some
|
||||
device (for example, for a device with buggy firmware level).
|
||||
.IP block[size]=value
|
||||
The default tape block size is set to
|
||||
.I value.
|
||||
bytes. The block size zero means variable block mode.
|
||||
.IP dens[ity]=value
|
||||
The tape density code is set to
|
||||
.I value.
|
||||
.IP buff[ering]=value
|
||||
The buffered writes by the driver in fixed block mode are enabled if
|
||||
.I value
|
||||
is non-zero.
|
||||
.IP async[-writes]=value
|
||||
Asynchronous writes by the driver are enabled if
|
||||
.I value
|
||||
is non-zero.
|
||||
.IP read[-ahead]=value
|
||||
Read-ahead by the driver in fixed block mode is allowed if
|
||||
.I value
|
||||
is non-zero.
|
||||
.IP two[-fms]=value
|
||||
Two filemarks are written when a file being written to is closed if
|
||||
.I value
|
||||
is non-zero. By default, one filemark is written.
|
||||
.IP comp[ression]=value
|
||||
Compression of the data by the drive is enabled if
|
||||
.I value
|
||||
is non-zero. Note that the tape driver can't enable compression for
|
||||
all drives that can compress data. Note also that some drives define
|
||||
compression using density codes.
|
||||
.IP auto[-lock]=value
|
||||
The tape drive door is locked automatically when the device file is
|
||||
opened if
|
||||
.I value
|
||||
is non-zero.
|
||||
.IP fast[-eom]=value
|
||||
The MTEOM command is performed using the SCSI command that spaces
|
||||
directly to the end of medium if
|
||||
.I value
|
||||
is non-zero. The drawback is that the file number in the status
|
||||
becomes invalid. By default, spacing to end of medium is performed by
|
||||
spacing over filemarks until end of medium is detected and the file
|
||||
number remains valid.
|
||||
.IP can-b[sr]=value
|
||||
Backspacing over records is used by the driver when repositioning
|
||||
the tape when read-ahead is enabled if
|
||||
.I value
|
||||
is non-zero.
|
||||
.IP noblk[limits]=value
|
||||
The tape driver does not use the READ BLOCK LIMITS SCSI command when
|
||||
the device is being opened if
|
||||
.I value
|
||||
is non-zero. This is for the drives that do not support this SCSI
|
||||
command.
|
||||
.IP can-p[artitions]=value
|
||||
The support for tape partitions is enabled if
|
||||
.I value
|
||||
is non-zero.
|
||||
.IP scsi2[logical]=value
|
||||
Logical block addresses are used in the MTSEEK and MTIOCPOS
|
||||
commands if
|
||||
.I value
|
||||
is non-zero. The default is to use the device-specific addresses.
|
||||
.IP defs-for-w[rites]=value
|
||||
The parameters defining the tape format (density, block size, etc.)
|
||||
are forced when writing starts at the beginning of a tape if
|
||||
.I value
|
||||
is non-zero. The default is to change there parameters each time the
|
||||
device is opened at the beginning of a tape (or the mode is changed in
|
||||
the middle of a tape).
|
||||
.IP timeout
|
||||
The normal timeout for the device is set to
|
||||
.I value
|
||||
seconds.
|
||||
.IP long-time[out]
|
||||
The long timeout for the device is set to
|
||||
.I value
|
||||
seconds.
|
||||
.SH RETURN VALUE
|
||||
The program exits with value one if the command line is incorrect, the
|
||||
definition file is not found, or option -p is given and parsing the
|
||||
definition file fails. In all other cases the return value is
|
||||
zero (i.e., failing of initialization is not currently signaled by
|
||||
the return value).
|
||||
.SH RESTRICTIONS
|
||||
With the exception of the -p option, the program can be used only by
|
||||
the superuser. This is because the program uses ioctls allowed only
|
||||
for the superuser.
|
||||
.SH AUTHOR
|
||||
The program is written by Kai Makisara <Kai.Makisara@metla.fi>.
|
||||
.SH COPYRIGHT
|
||||
The program and the manual page are copyrighted by Kai Makisara, 1998-2001.
|
||||
They can be distributed according to the GNU Copyleft.
|
||||
.SH SEE ALSO
|
||||
st(4) mt(1)
|
||||
895
stinit.c
Normal file
895
stinit.c
Normal file
@@ -0,0 +1,895 @@
|
||||
/* This program initializes Linux SCSI tape drives using the
|
||||
inquiry data from the devices and a text database.
|
||||
|
||||
Copyright 1996-2001 by Kai M<>kisara (email Kai.Makisara@metla.fi)
|
||||
Distribution of this program is allowed according to the
|
||||
GNU Public Licence.
|
||||
|
||||
Last modified: Thu Nov 8 21:13:48 2001 by makisara@kai.makisara.local
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char rcsid[] = "$Id: /usr2/users/makisara/src/sys/mt-st-0.7/stinit.c at Thu Nov 8 21:13:48 2001 by makisara@kai.makisara.local$";
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <linux/major.h>
|
||||
|
||||
#include "mtio.h"
|
||||
|
||||
#ifndef FALSE
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#endif
|
||||
#define SKIP_WHITE(p) for ( ; *p == ' ' || *p == '\t'; p++)
|
||||
|
||||
#define VERSION "0.7"
|
||||
|
||||
typedef struct _modepar_tr {
|
||||
int defined;
|
||||
int blocksize;
|
||||
int density;
|
||||
int buffer_writes;
|
||||
int async_writes;
|
||||
int read_ahead;
|
||||
int two_fm;
|
||||
int compression;
|
||||
int auto_lock;
|
||||
int fast_eod;
|
||||
int can_bsr;
|
||||
int no_blklimits;
|
||||
int can_partitions;
|
||||
int scsi2logical;
|
||||
int sysv;
|
||||
int defs_for_writes;
|
||||
} modepar_tr;
|
||||
|
||||
typedef struct _devdef_tr {
|
||||
int do_rewind;
|
||||
int drive_buffering;
|
||||
int timeout;
|
||||
int long_timeout;
|
||||
int cleaning;
|
||||
int nowait;
|
||||
modepar_tr modedefs[4];
|
||||
} devdef_tr;
|
||||
|
||||
|
||||
#define DEFMAX 2048
|
||||
#define LINEMAX 256
|
||||
|
||||
#define MAX_TAPES 32
|
||||
#define NBR_MODES 4
|
||||
|
||||
|
||||
static int verbose = 0;
|
||||
|
||||
/* The device directories being searched */
|
||||
typedef struct
|
||||
{
|
||||
const char *dir;
|
||||
int selective_scan;
|
||||
} devdir;
|
||||
static devdir devdirs[] = { {"/dev/scsi", 0}, {"/dev", 1}, {NULL, 0}};
|
||||
|
||||
#define DEVFS_PATH "/dev/tapes"
|
||||
#define DEVFS_TAPEFMT DEVFS_PATH "/tape%d"
|
||||
|
||||
/* The partial names of the tape devices being included in the
|
||||
search in selective scan */
|
||||
static char *tape_name_bases[] = {
|
||||
"st", "nst", "rmt", "nrmt", "tape", NULL};
|
||||
|
||||
/* The list of standard definition files being searched */
|
||||
static char *std_databases[] = {
|
||||
"/etc/stinit.def",
|
||||
NULL};
|
||||
|
||||
static FILE *
|
||||
open_database(char *base)
|
||||
{
|
||||
int i;
|
||||
FILE *f;
|
||||
|
||||
if (base != NULL) {
|
||||
if ((f = fopen(base, "r")) == NULL)
|
||||
fprintf(stderr, "stinit: Can't find SCSI tape database '%s'.\n",
|
||||
base);
|
||||
return f;
|
||||
}
|
||||
|
||||
for (i=0; std_databases[i] != NULL; i++) {
|
||||
if (verbose > 1)
|
||||
fprintf(stderr, "Trying to open database '%s'.\n", std_databases[i]);
|
||||
if ((f = fopen(std_databases[i], "r")) != NULL) {
|
||||
if (verbose > 1)
|
||||
fprintf(stderr, "Open succeeded.\n");
|
||||
return f;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "Can't find the tape characteristics database.\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
find_string(char *s, char *target, char *buf, int buflen)
|
||||
{
|
||||
int have_arg;
|
||||
char *cp, *cp2, c, *argp;
|
||||
|
||||
if (buf != NULL && buflen > 0)
|
||||
*buf = '\0';
|
||||
|
||||
for ( ; *s != '\0'; ) {
|
||||
SKIP_WHITE(s);
|
||||
if (isalpha(*s)) {
|
||||
for (cp=s ; isalnum(*cp) || *cp == '-'; cp++)
|
||||
;
|
||||
cp2 = cp;
|
||||
SKIP_WHITE(cp);
|
||||
if (*cp == '=') {
|
||||
cp++;
|
||||
SKIP_WHITE(cp);
|
||||
if (*cp == '"') {
|
||||
cp++;
|
||||
for (cp2=cp; *cp2 != '"' && *cp2 != '\0'; cp2++)
|
||||
;
|
||||
}
|
||||
else
|
||||
for (cp2=cp+1; isalnum(*cp2) || *cp2 == '-'; cp2++)
|
||||
;
|
||||
if (cp2 == '\0')
|
||||
return NULL;
|
||||
have_arg = TRUE;
|
||||
argp = cp;
|
||||
}
|
||||
else {
|
||||
have_arg = FALSE;
|
||||
argp = "1";
|
||||
}
|
||||
|
||||
if (!strncmp(target, s, strlen(target))) {
|
||||
c = *cp2;
|
||||
*cp2 = '\0';
|
||||
if (buf == NULL)
|
||||
buf = strdup(argp);
|
||||
else {
|
||||
if (strlen(argp) < buflen)
|
||||
strcpy(buf, argp);
|
||||
else {
|
||||
strncpy(buf, argp, buflen);
|
||||
buf[buflen - 1] = '\0';
|
||||
}
|
||||
}
|
||||
if (have_arg && c == '"')
|
||||
cp2++;
|
||||
else
|
||||
*cp2 = c;
|
||||
if (*cp2 != '\0')
|
||||
memmove(s, cp2, strlen(cp2) + 1);
|
||||
else
|
||||
*s = '\0';
|
||||
return buf;
|
||||
}
|
||||
s = cp2;
|
||||
}
|
||||
else
|
||||
for ( ; *s != '\0' && *s != ' ' && *s != '\t'; s++)
|
||||
;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
next_block(FILE *dbf, char *buf, int buflen, int limiter)
|
||||
{
|
||||
int len;
|
||||
char *cp, *bp;
|
||||
static char lbuf[LINEMAX];
|
||||
|
||||
if (limiter == 0) { /* Restart */
|
||||
rewind(dbf);
|
||||
lbuf[0] = '\0';
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
for (len = 0 ; ; ) {
|
||||
bp = buf + len;
|
||||
if ((cp = strchr(lbuf, limiter)) != NULL) {
|
||||
*cp = '\0';
|
||||
strcpy(bp, lbuf);
|
||||
cp++;
|
||||
SKIP_WHITE(cp);
|
||||
memmove(lbuf, cp, strlen(cp) + 1);
|
||||
return TRUE;
|
||||
}
|
||||
if (len + strlen(lbuf) >= DEFMAX) {
|
||||
fprintf(stderr, "Too long definition: '%s'\n", buf);
|
||||
return FALSE;
|
||||
}
|
||||
cp = lbuf;
|
||||
SKIP_WHITE(cp);
|
||||
strcpy(bp, cp);
|
||||
strcat(bp, " ");
|
||||
len += strlen(cp) + 1;
|
||||
if (fgets(lbuf, LINEMAX, dbf) == NULL)
|
||||
return FALSE;
|
||||
if ((cp = strchr(lbuf, '#')) != NULL)
|
||||
*cp = '\0';
|
||||
else
|
||||
lbuf[strlen(lbuf) - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
find_pars(FILE *dbf, char *company, char *product, char *rev, devdef_tr *defs,
|
||||
int parse_only)
|
||||
{
|
||||
int i, mode, modes_defined, errors;
|
||||
char line[LINEMAX], defstr[DEFMAX], comdef[DEFMAX];
|
||||
char tmpcomp[LINEMAX], tmpprod[LINEMAX], tmprev[LINEMAX], *cp, c, *t;
|
||||
char *nextdef, *curdef, *comptr;
|
||||
static int call_nbr = 0;
|
||||
|
||||
call_nbr++;
|
||||
defs->drive_buffering = (-1);
|
||||
defs->timeout = (-1);
|
||||
defs->long_timeout = (-1);
|
||||
defs->cleaning = (-1);
|
||||
defs->nowait = (-1);
|
||||
for (i=0; i < NBR_MODES; i++) {
|
||||
defs->modedefs[i].defined = FALSE;
|
||||
defs->modedefs[i].blocksize = (-1);
|
||||
defs->modedefs[i].density = (-1);
|
||||
defs->modedefs[i].buffer_writes = (-1);
|
||||
defs->modedefs[i].async_writes = (-1);
|
||||
defs->modedefs[i].read_ahead = (-1);
|
||||
defs->modedefs[i].two_fm = (-1);
|
||||
defs->modedefs[i].compression = (-1);
|
||||
defs->modedefs[i].auto_lock = (-1);
|
||||
defs->modedefs[i].fast_eod = (-1);
|
||||
defs->modedefs[i].can_bsr = (-1);
|
||||
defs->modedefs[i].no_blklimits = (-1);
|
||||
defs->modedefs[i].can_partitions = (-1);
|
||||
defs->modedefs[i].scsi2logical = (-1);
|
||||
defs->modedefs[i].sysv = (-1);
|
||||
defs->modedefs[i].defs_for_writes = (-1);
|
||||
}
|
||||
next_block(dbf, NULL, 0, 0);
|
||||
|
||||
/* Find matching inquiry block */
|
||||
for (errors=0 ; ; ) {
|
||||
|
||||
if (!next_block(dbf, defstr, DEFMAX, '{'))
|
||||
break;
|
||||
|
||||
find_string(defstr, "manuf", tmpcomp, LINEMAX);
|
||||
find_string(defstr, "model", tmpprod, LINEMAX);
|
||||
find_string(defstr, "rev", tmprev, LINEMAX);
|
||||
|
||||
if (!next_block(dbf, defstr, DEFMAX, '}')) {
|
||||
fprintf(stderr,
|
||||
"End of definition block not found for ('%s', '%s', '%s').\n",
|
||||
tmpcomp, tmpprod, tmprev);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!parse_only) {
|
||||
if (tmpcomp[0] != '\0' &&
|
||||
strncmp(company, tmpcomp, strlen(tmpcomp)))
|
||||
continue;
|
||||
if (tmpprod[0] != '\0' &&
|
||||
strncmp(product, tmpprod, strlen(tmpprod)))
|
||||
continue;
|
||||
if (tmprev[0] != '\0' &&
|
||||
strncmp(rev, tmprev, strlen(tmprev)))
|
||||
continue;
|
||||
}
|
||||
else if (verbose > 0)
|
||||
printf("\nParsing modes for ('%s', '%s', '%s').\n",
|
||||
tmpcomp, tmpprod, tmprev);
|
||||
|
||||
/* Block found, get the characteristics */
|
||||
for (nextdef=defstr; *nextdef != '\0' &&
|
||||
(*nextdef != 'm' || strncmp(nextdef, "mode", 2)); nextdef++)
|
||||
;
|
||||
c = *nextdef;
|
||||
*nextdef = '\0';
|
||||
strcpy(comdef, defstr);
|
||||
*nextdef = c;
|
||||
comptr = comdef;
|
||||
SKIP_WHITE(comptr);
|
||||
|
||||
for ( ; *nextdef != '\0'; ) {
|
||||
curdef = nextdef;
|
||||
SKIP_WHITE(curdef);
|
||||
for (nextdef++ ; *nextdef != '\0' &&
|
||||
(*nextdef != 'm' || strncmp(nextdef, "mode", 2)); nextdef++)
|
||||
;
|
||||
c = *nextdef;
|
||||
*nextdef = '\0';
|
||||
|
||||
mode = strtol(curdef + 4, &cp, 0) - 1;
|
||||
if (mode < 0 || mode >= NBR_MODES) {
|
||||
fprintf(stderr,
|
||||
"Illegal mode for ('%s', '%s', '%s'):\n'%s'\n",
|
||||
tmpcomp, tmpprod, tmprev, curdef);
|
||||
*nextdef = c;
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
|
||||
strcpy(defstr, comptr);
|
||||
strcat(defstr, cp);
|
||||
*nextdef = c;
|
||||
|
||||
if (verbose > 1)
|
||||
fprintf(stderr, "Mode %d definition: %s\n", mode + 1, defstr);
|
||||
|
||||
if ((t = find_string(defstr, "disab", line, LINEMAX)) != NULL &&
|
||||
strtol(t, NULL, 0) != 0) {
|
||||
defs->modedefs[mode].defined = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((t = find_string(defstr, "drive-", line, LINEMAX)) != NULL)
|
||||
defs->drive_buffering = strtol(t, NULL, 0);
|
||||
if ((t = find_string(defstr, "timeout", line, LINEMAX)) != NULL)
|
||||
defs->timeout = strtol(t, NULL, 0);
|
||||
if ((t = find_string(defstr, "long-time", line, LINEMAX)) != NULL)
|
||||
defs->long_timeout = strtol(t, NULL, 0);
|
||||
if ((t = find_string(defstr, "clean", line, LINEMAX)) != NULL)
|
||||
defs->cleaning = strtol(t, NULL, 0);
|
||||
if ((t = find_string(defstr, "no-w", line, LINEMAX)) != NULL)
|
||||
defs->nowait = strtol(t, NULL, 0);
|
||||
|
||||
defs->modedefs[mode].defined = TRUE;
|
||||
if ((t = find_string(defstr, "block", line, LINEMAX)) != NULL)
|
||||
defs->modedefs[mode].blocksize = strtol(t, NULL, 0);
|
||||
if ((t = find_string(defstr, "dens", line, LINEMAX)) != NULL)
|
||||
defs->modedefs[mode].density = strtol(t, NULL, 0);
|
||||
if ((t = find_string(defstr, "buff", line, LINEMAX)) != NULL)
|
||||
defs->modedefs[mode].buffer_writes = strtol(t, NULL, 0);
|
||||
if ((t = find_string(defstr, "async", line, LINEMAX)) != NULL)
|
||||
defs->modedefs[mode].async_writes = strtol(t, NULL, 0);
|
||||
if ((t = find_string(defstr, "read", line, LINEMAX)) != NULL)
|
||||
defs->modedefs[mode].read_ahead = strtol(t, NULL, 0);
|
||||
if ((t = find_string(defstr, "two", line, LINEMAX)) != NULL)
|
||||
defs->modedefs[mode].two_fm = strtol(t, NULL, 0);
|
||||
if ((t = find_string(defstr, "comp", line, LINEMAX)) != NULL)
|
||||
defs->modedefs[mode].compression = strtol(t, NULL, 0);
|
||||
if ((t = find_string(defstr, "auto", line, LINEMAX)) != NULL)
|
||||
defs->modedefs[mode].auto_lock = strtol(t, NULL, 0);
|
||||
if ((t = find_string(defstr, "fast", line, LINEMAX)) != NULL)
|
||||
defs->modedefs[mode].fast_eod = strtol(t, NULL, 0);
|
||||
if ((t = find_string(defstr, "can-b", line, LINEMAX)) != NULL)
|
||||
defs->modedefs[mode].can_bsr = strtol(t, NULL, 0);
|
||||
if ((t = find_string(defstr, "noblk", line, LINEMAX)) != NULL)
|
||||
defs->modedefs[mode].no_blklimits = strtol(t, NULL, 0);
|
||||
if ((t = find_string(defstr, "can-p", line, LINEMAX)) != NULL)
|
||||
defs->modedefs[mode].can_partitions = strtol(t, NULL, 0);
|
||||
if ((t = find_string(defstr, "scsi2", line, LINEMAX)) != NULL)
|
||||
defs->modedefs[mode].scsi2logical = strtol(t, NULL, 0);
|
||||
if ((t = find_string(defstr, "sysv", line, LINEMAX)) != NULL)
|
||||
defs->modedefs[mode].sysv = strtol(t, NULL, 0);
|
||||
if ((t = find_string(defstr, "defs-for-w", line, LINEMAX)) != NULL)
|
||||
defs->modedefs[mode].defs_for_writes = strtol(t, NULL, 0);
|
||||
|
||||
for (t=defstr; *t == ' ' || *t == '\t'; t++)
|
||||
;
|
||||
if (*t != '\0' && call_nbr <= 1) {
|
||||
fprintf(stderr,
|
||||
"Warning: errors in definition for ('%s', '%s', '%s'):\n%s\n",
|
||||
tmpcomp, tmpprod, tmprev, defstr);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parse_only) {
|
||||
if (verbose > 0)
|
||||
printf("\n");
|
||||
printf("Definition parse completed. ");
|
||||
if (errors) {
|
||||
printf("Errors found!\n");
|
||||
return FALSE;
|
||||
}
|
||||
else {
|
||||
printf("No errors found.\n");
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i=modes_defined=0; i < NBR_MODES; i++)
|
||||
if (defs->modedefs[i].defined)
|
||||
modes_defined++;
|
||||
if (modes_defined == 0) {
|
||||
fprintf(stderr,
|
||||
"Warning: No modes in definition for ('%s', '%s', '%s').\n",
|
||||
tmpcomp, tmpprod, tmprev);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
if (modes_defined)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
#define INQUIRY 0x12
|
||||
|
||||
#ifndef SCSI_IOCTL_SEND_COMMAND
|
||||
#define SCSI_IOCTL_SEND_COMMAND 1
|
||||
#endif
|
||||
#define IOCTL_HEADER_LENGTH 8
|
||||
|
||||
static int
|
||||
do_inquiry(char *tname, char *company, char *product, char *rev, int print_non_found)
|
||||
{
|
||||
int fn;
|
||||
int result, *ip, i;
|
||||
#define BUFLEN 256
|
||||
unsigned char buffer[BUFLEN], *cmd;
|
||||
|
||||
if ((fn = open(tname, O_RDONLY | O_NONBLOCK)) < 0) {
|
||||
if (print_non_found || verbose > 0) {
|
||||
if (errno == ENXIO)
|
||||
fprintf(stderr, "Device '%s' not found by kernel.\n", tname);
|
||||
else
|
||||
fprintf(stderr, "Can't open tape device '%s' (errno %d).\n",
|
||||
tname, errno);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
memset(buffer, 0, BUFLEN);
|
||||
ip = (int *)&(buffer[0]);
|
||||
*ip = 0;
|
||||
*(ip+1) = BUFLEN - 13;
|
||||
|
||||
cmd = &(buffer[8]);
|
||||
cmd[0] = INQUIRY;
|
||||
cmd[4] = 200;
|
||||
|
||||
result = ioctl(fn, SCSI_IOCTL_SEND_COMMAND, buffer);
|
||||
if (result) {
|
||||
close(fn);
|
||||
fprintf(stderr,
|
||||
"The SCSI INQUIRY for device '%s' failed (power off?).\n",
|
||||
tname);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
memcpy(company, buffer + IOCTL_HEADER_LENGTH + 8, 8);
|
||||
for (i=8; i > 0 && company[i-1] == ' '; i--)
|
||||
;
|
||||
company[i] = '\0';
|
||||
memcpy(product, buffer + IOCTL_HEADER_LENGTH + 16, 16);
|
||||
for (i=16; i > 0 && product[i-1] == ' '; i--)
|
||||
;
|
||||
product[i] = '\0';
|
||||
memcpy(rev, buffer + IOCTL_HEADER_LENGTH + 32, 4);
|
||||
for (i=4; i > 0 && rev[i-1] == ' '; i--)
|
||||
;
|
||||
rev[i] = '\0';
|
||||
|
||||
close(fn);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
tapenum(char *name)
|
||||
{
|
||||
int dev;
|
||||
struct dirent *dent;
|
||||
DIR *dirp;
|
||||
char tmpname[PATH_MAX];
|
||||
const char *dn;
|
||||
const devdir *dvd;
|
||||
struct stat statbuf;
|
||||
|
||||
if (strchr(name, '/') != NULL) { /* Complete name */
|
||||
if (stat(name, &statbuf) != 0) {
|
||||
fprintf(stderr, "Can't stat '%s'.\n", name);
|
||||
return (-1);
|
||||
}
|
||||
if (!S_ISCHR(statbuf.st_mode) ||
|
||||
major(statbuf.st_rdev) != SCSI_TAPE_MAJOR)
|
||||
return (-1);
|
||||
dev = minor(statbuf.st_rdev) & 31;
|
||||
return dev;
|
||||
}
|
||||
else { /* Search from the device directories */
|
||||
for (dvd=devdirs; dvd->dir != NULL; dvd++) {
|
||||
dn = dvd->dir;
|
||||
if ((dirp = opendir(dn)) == NULL)
|
||||
continue;
|
||||
|
||||
for ( ; (dent = readdir(dirp)) != NULL; )
|
||||
if (!strcmp(dent->d_name, name)) {
|
||||
strcpy(tmpname, dn);
|
||||
strcat(tmpname, "/");
|
||||
strcat(tmpname, dent->d_name);
|
||||
if (stat(tmpname, &statbuf) != 0) {
|
||||
fprintf(stderr, "Can't stat '%s'.\n", tmpname);
|
||||
continue;
|
||||
}
|
||||
if (!S_ISCHR(statbuf.st_mode) ||
|
||||
major(statbuf.st_rdev) != SCSI_TAPE_MAJOR)
|
||||
continue;
|
||||
dev = minor(statbuf.st_rdev) & 31;
|
||||
closedir(dirp);
|
||||
return dev;
|
||||
}
|
||||
closedir(dirp);
|
||||
}
|
||||
}
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
accept_tape_name(char *name)
|
||||
{
|
||||
char **npp;
|
||||
|
||||
for (npp=tape_name_bases; *npp; npp++)
|
||||
if (!strncmp(name, *npp, strlen(*npp)))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
find_devfiles(int tapeno, char **names)
|
||||
{
|
||||
int dev, mode, found;
|
||||
int non_rew[NBR_MODES];
|
||||
struct dirent *dent;
|
||||
DIR *dirp;
|
||||
char tmpname[PATH_MAX], devname[PATH_MAX];
|
||||
const char *dn;
|
||||
const devdir *dvd;
|
||||
devdir tmpdevdirs[2];
|
||||
struct stat statbuf;
|
||||
|
||||
for (found=0; found < NBR_MODES; found++) {
|
||||
*names[found] = '\0';
|
||||
non_rew[found] = FALSE;
|
||||
}
|
||||
|
||||
dvd = devdirs;
|
||||
strcpy(tmpname, DEVFS_PATH);
|
||||
if (!stat(tmpname, &statbuf)) {
|
||||
if (S_ISDIR(statbuf.st_mode)) { /* Assume devfs, one directory for each tape */
|
||||
sprintf(devname, DEVFS_TAPEFMT, tapeno);
|
||||
tmpdevdirs[0].dir = devname;
|
||||
tmpdevdirs[0].selective_scan = FALSE;
|
||||
tmpdevdirs[1].dir = NULL;
|
||||
dvd = &tmpdevdirs[0];
|
||||
}
|
||||
}
|
||||
|
||||
for (found=0; found < NBR_MODES && dvd->dir != NULL; dvd++) {
|
||||
dn = dvd->dir;
|
||||
if ((dirp = opendir(dn)) == NULL)
|
||||
continue;
|
||||
|
||||
for ( ; (dent = readdir(dirp)) != NULL; ) {
|
||||
if (!strcmp (dent->d_name, ".") || !strcmp (dent->d_name, ".."))
|
||||
continue;
|
||||
/* Ignore non-tape devices to avoid loading all the modules */
|
||||
if (dvd->selective_scan && !accept_tape_name(dent->d_name))
|
||||
continue;
|
||||
strcpy(tmpname, dn);
|
||||
strcat(tmpname, "/");
|
||||
strcat(tmpname, dent->d_name);
|
||||
if (stat(tmpname, &statbuf) != 0) {
|
||||
fprintf(stderr, "Can't stat '%s'.\n", tmpname);
|
||||
continue;
|
||||
}
|
||||
if (!S_ISCHR(statbuf.st_mode) || major(statbuf.st_rdev) !=
|
||||
SCSI_TAPE_MAJOR)
|
||||
continue;
|
||||
dev = minor(statbuf.st_rdev);
|
||||
if ((dev & 31) != tapeno)
|
||||
continue;
|
||||
mode = (dev & 127) >> 5;
|
||||
if (non_rew[mode])
|
||||
continue;
|
||||
if (*names[mode] == '\0')
|
||||
found++;
|
||||
strcpy(names[mode], tmpname);
|
||||
non_rew[mode] = (dev & 128) != 0;
|
||||
}
|
||||
closedir(dirp);
|
||||
}
|
||||
|
||||
return (found > 0);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
set_defs(devdef_tr *defs, char **fnames)
|
||||
{
|
||||
int i, tape;
|
||||
int clear_set[2];
|
||||
struct mtop op;
|
||||
|
||||
for (i=0; i < NBR_MODES; i++) {
|
||||
if (*fnames[i] == '\0' || !defs->modedefs[i].defined)
|
||||
continue;
|
||||
|
||||
if ((tape = open(fnames[i], O_RDONLY | O_NONBLOCK)) < 0) {
|
||||
fprintf(stderr, "Can't open the tape device '%s' for mode %d.\n",
|
||||
fnames[i], i);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
if (defs->do_rewind) {
|
||||
op.mt_op = MTREW;
|
||||
op.mt_count = 1;
|
||||
ioctl(tape, MTIOCTOP, &op); /* Don't worry about result */
|
||||
}
|
||||
|
||||
if (defs->drive_buffering >= 0) {
|
||||
op.mt_op = MTSETDRVBUFFER;
|
||||
op.mt_count = MT_ST_DEF_DRVBUFFER | defs->drive_buffering;
|
||||
if (ioctl(tape, MTIOCTOP, &op) != 0) {
|
||||
fprintf(stderr, "Can't set drive buffering to %d.\n",
|
||||
defs->drive_buffering);
|
||||
}
|
||||
}
|
||||
|
||||
if (defs->timeout >= 0) {
|
||||
op.mt_op = MTSETDRVBUFFER;
|
||||
op.mt_count = MT_ST_SET_TIMEOUT | defs->timeout;
|
||||
if (ioctl(tape, MTIOCTOP, &op) != 0) {
|
||||
fprintf(stderr, "Can't set device timeout %d s.\n",
|
||||
defs->timeout);
|
||||
}
|
||||
}
|
||||
|
||||
if (defs->long_timeout >= 0) {
|
||||
op.mt_op = MTSETDRVBUFFER;
|
||||
op.mt_count = MT_ST_SET_LONG_TIMEOUT | defs->long_timeout;
|
||||
if (ioctl(tape, MTIOCTOP, &op) != 0) {
|
||||
fprintf(stderr, "Can't set device long timeout %d s.\n",
|
||||
defs->long_timeout);
|
||||
}
|
||||
}
|
||||
|
||||
if (defs->cleaning >= 0) {
|
||||
op.mt_op = MTSETDRVBUFFER;
|
||||
op.mt_count = MT_ST_SET_CLN | defs->cleaning;
|
||||
if (ioctl(tape, MTIOCTOP, &op) != 0) {
|
||||
fprintf(stderr, "Can't set cleaning request parameter to %x\n",
|
||||
defs->cleaning);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
op.mt_op = MTSETDRVBUFFER;
|
||||
|
||||
clear_set[0] = clear_set[1] = 0;
|
||||
if (defs->nowait >= 0)
|
||||
clear_set[defs->nowait != 0] |= MT_ST_NOWAIT;
|
||||
if (defs->modedefs[i].buffer_writes >= 0)
|
||||
clear_set[defs->modedefs[i].buffer_writes != 0] |= MT_ST_BUFFER_WRITES;
|
||||
if (defs->modedefs[i].async_writes >= 0)
|
||||
clear_set[defs->modedefs[i].async_writes != 0] |= MT_ST_ASYNC_WRITES;
|
||||
if (defs->modedefs[i].read_ahead >= 0)
|
||||
clear_set[defs->modedefs[i].read_ahead != 0] |= MT_ST_READ_AHEAD;
|
||||
if (defs->modedefs[i].two_fm >= 0)
|
||||
clear_set[defs->modedefs[i].two_fm != 0] |= MT_ST_TWO_FM;
|
||||
if (defs->modedefs[i].fast_eod >= 0)
|
||||
clear_set[defs->modedefs[i].fast_eod != 0] |= MT_ST_FAST_MTEOM;
|
||||
if (defs->modedefs[i].auto_lock >= 0)
|
||||
clear_set[defs->modedefs[i].auto_lock != 0] |= MT_ST_AUTO_LOCK;
|
||||
if (defs->modedefs[i].can_bsr >= 0)
|
||||
clear_set[defs->modedefs[i].can_bsr != 0] |= MT_ST_CAN_BSR;
|
||||
if (defs->modedefs[i].no_blklimits >= 0)
|
||||
clear_set[defs->modedefs[i].no_blklimits != 0] |= MT_ST_NO_BLKLIMS;
|
||||
if (defs->modedefs[i].can_partitions >= 0)
|
||||
clear_set[defs->modedefs[i].can_partitions != 0] |= MT_ST_CAN_PARTITIONS;
|
||||
if (defs->modedefs[i].scsi2logical >= 0)
|
||||
clear_set[defs->modedefs[i].scsi2logical != 0] |= MT_ST_SCSI2LOGICAL;
|
||||
if (defs->modedefs[i].sysv >= 0)
|
||||
clear_set[defs->modedefs[i].sysv != 0] |= MT_ST_SYSV;
|
||||
if (defs->modedefs[i].defs_for_writes >= 0)
|
||||
clear_set[defs->modedefs[i].defs_for_writes != 0] |= MT_ST_DEF_WRITES;
|
||||
|
||||
if (clear_set[0] != 0) {
|
||||
op.mt_count = MT_ST_CLEARBOOLEANS | clear_set[0];
|
||||
if (ioctl(tape, MTIOCTOP, &op) != 0) {
|
||||
fprintf(stderr, "Can't clear the tape options (bits 0x%x, mode %d).\n",
|
||||
clear_set[0], i);
|
||||
}
|
||||
}
|
||||
if (clear_set[1] != 0) {
|
||||
op.mt_count = MT_ST_SETBOOLEANS | clear_set[1];
|
||||
if (ioctl(tape, MTIOCTOP, &op) != 0) {
|
||||
fprintf(stderr, "Can't set the tape options (bits 0x%x, mode %d).\n",
|
||||
clear_set[1], i);
|
||||
}
|
||||
}
|
||||
|
||||
if (defs->modedefs[i].blocksize >= 0) {
|
||||
op.mt_count = MT_ST_DEF_BLKSIZE | defs->modedefs[i].blocksize;
|
||||
if (ioctl(tape, MTIOCTOP, &op) != 0) {
|
||||
fprintf(stderr, "Can't set blocksize %d for mode %d.\n",
|
||||
defs->modedefs[i].blocksize, i);
|
||||
}
|
||||
}
|
||||
if (defs->modedefs[i].density >= 0) {
|
||||
op.mt_count = MT_ST_DEF_DENSITY | defs->modedefs[i].density;
|
||||
if (ioctl(tape, MTIOCTOP, &op) != 0) {
|
||||
fprintf(stderr, "Can't set density %x for mode %d.\n",
|
||||
defs->modedefs[i].density, i);
|
||||
}
|
||||
}
|
||||
if (defs->modedefs[i].compression >= 0) {
|
||||
op.mt_count = MT_ST_DEF_COMPRESSION | defs->modedefs[i].compression;
|
||||
if (ioctl(tape, MTIOCTOP, &op) != 0) {
|
||||
fprintf(stderr, "Can't set compression %d for mode %d.\n",
|
||||
defs->modedefs[i].compression, i);
|
||||
}
|
||||
}
|
||||
|
||||
close(tape);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
define_tape(int tapeno, FILE *dbf, devdef_tr *defptr, int print_non_found)
|
||||
{
|
||||
int i;
|
||||
char company[10], product[20], rev[5], *tname, *fnames[NBR_MODES];
|
||||
|
||||
if (verbose > 0)
|
||||
printf("\nstinit, processing tape %d\n", tapeno);
|
||||
|
||||
if ((fnames[0] = calloc(NBR_MODES, PATH_MAX)) == NULL) {
|
||||
fprintf(stderr, "Can't allocate name buffers.\n");
|
||||
return FALSE;
|
||||
}
|
||||
for (i=1; i < NBR_MODES; i++)
|
||||
fnames[i] = fnames[i-1] + PATH_MAX;
|
||||
|
||||
if (!find_devfiles(tapeno, fnames) ||
|
||||
*fnames[0] == '\0') {
|
||||
fprintf(stderr, "Can't find any device files for tape %d.\n", tapeno);
|
||||
free(fnames[0]);
|
||||
return FALSE;
|
||||
}
|
||||
if (verbose > 1)
|
||||
for (i=0; i < NBR_MODES; i++)
|
||||
printf("Mode %d, name '%s'\n", i, fnames[i]);
|
||||
|
||||
tname = fnames[0];
|
||||
if (!do_inquiry(tname, company, product, rev, print_non_found)) {
|
||||
free(fnames[0]);
|
||||
return FALSE;
|
||||
}
|
||||
if (verbose > 0)
|
||||
printf("The manufacturer is '%s', product is '%s', and revision '%s'.\n",
|
||||
company, product, rev);
|
||||
|
||||
if (!find_pars(dbf, company, product, rev, defptr, FALSE)) {
|
||||
fprintf(stderr, "Can't find defaults for tape number %d.\n", tapeno);
|
||||
free(fnames[0]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!set_defs(defptr, fnames)) {
|
||||
free(fnames[0]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
free(fnames[0]);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static char
|
||||
usage(int retval)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: stinit [-h] [-v] [-f dbname] [-p] [drivename_or_number ...]\n");
|
||||
exit(retval);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
FILE *dbf = NULL;
|
||||
int argn;
|
||||
int tapeno, parse_only = FALSE;
|
||||
char *dbname = NULL;
|
||||
devdef_tr defs;
|
||||
|
||||
defs.do_rewind = FALSE;
|
||||
for (argn=1; argn < argc && *argv[argn] == '-'; argn++) {
|
||||
if (*(argv[argn] + 1) == 'v')
|
||||
verbose++;
|
||||
else if (*(argv[argn] + 1) == 'p')
|
||||
parse_only = TRUE;
|
||||
else if (*(argv[argn] + 1) == 'h')
|
||||
usage(0);
|
||||
else if (*(argv[argn] + 1) == 'r')
|
||||
defs.do_rewind = TRUE;
|
||||
else if (*(argv[argn] + 1) == 'f') {
|
||||
argn += 1;
|
||||
if (argn >= argc)
|
||||
usage(1);
|
||||
dbname = argv[argn];
|
||||
}
|
||||
else if (*(argv[argn] + 1) == '-' &&
|
||||
*(argv[argn] + 2) == 'v') {
|
||||
printf("stinit v. %s\n", VERSION);
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
else
|
||||
usage(1);
|
||||
}
|
||||
|
||||
if ((dbf = open_database(dbname)) == NULL)
|
||||
return 1;
|
||||
|
||||
if (parse_only) {
|
||||
if (argc > argn)
|
||||
fprintf(stderr, "Extra arguments on command line ignored.\n");
|
||||
if (!find_pars(dbf, "xyz", "xyz", "xyz", &defs, TRUE))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (argc > argn) { /* Initialize specific drives */
|
||||
for ( ; argn < argc; argn++) {
|
||||
if (*argv[argn] == '-') {
|
||||
usage(1);
|
||||
return 1; /* Never executed but makes gcc happy */
|
||||
}
|
||||
else if (isdigit(*argv[argn]))
|
||||
tapeno = strtol(argv[argn], NULL, 0);
|
||||
else if ((tapeno = tapenum(argv[argn])) < 0) {
|
||||
fprintf(stderr, "Can't find tape number for name '%s'.\n",
|
||||
argv[argn]);
|
||||
continue;
|
||||
}
|
||||
if (!define_tape(tapeno, dbf, &defs, TRUE))
|
||||
fprintf(stderr, "Definition for '%s' failed.\n", argv[argn]);
|
||||
}
|
||||
}
|
||||
else { /* Initialize all SCSI tapes */
|
||||
for (tapeno=0; tapeno < MAX_TAPES; tapeno++)
|
||||
if (!define_tape(tapeno, dbf, &defs, FALSE)) {
|
||||
fprintf(stderr, "Initialized %d tape device%s.\n",
|
||||
tapeno, (tapeno != 1 ? "s" : ""));
|
||||
return 0; /* Process tapes until failure */
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
58
stinit.def.examples
Normal file
58
stinit.def.examples
Normal file
@@ -0,0 +1,58 @@
|
||||
# This file contains example definitions for different kinds of tape
|
||||
# devices. If the user agrees with the definitions, they can be used
|
||||
# in the definition file stinit.def by changing the manufacturer and
|
||||
# model fields to correspond the real tape device being defined.
|
||||
|
||||
# The common definitions that can usually be used
|
||||
{buffer-writes read-ahead async-writes scsi2logical=1}
|
||||
|
||||
# A non-compressing DAT (DDS-1)
|
||||
# The manufacturer, model, and revision strings can be obtained,
|
||||
# from the file /proc/scsi/scsi (cat /proc/scsi/scsi).
|
||||
manufacturer=XYZ model = "UVW1" {
|
||||
scsi2logical=1 can-bsr can-partitions auto-lock
|
||||
mode1 blocksize=0
|
||||
mode2 blocksize=1024 }
|
||||
|
||||
# A compressing DAT (DDS-1-DC or DDS-[234])
|
||||
manufacturer=XYZ model = "UVW2" {
|
||||
can-bsr can-partitions auto-lock
|
||||
mode1 blocksize=0 compression=1
|
||||
mode2 blocksize=1024 compression=1
|
||||
mode3 blocksize=0 compression=0
|
||||
mode4 blocksize = 1024 compression=0 }
|
||||
|
||||
# A QIC-150 drive
|
||||
manufacturer=XYZ model="UVW3" {
|
||||
scsi2logical=0
|
||||
mode1 # blocksize=512 defined by drive
|
||||
}
|
||||
|
||||
# A QIC-320/525 drive
|
||||
manufacturer=XYZ model="UVW4" {
|
||||
defs-for-writes
|
||||
mode1 blocksize=0 density=0x11 # QIC-320
|
||||
mode2 blocksize=1024 density=0x11 # QIC-320
|
||||
mode3 blocksize=512 density=0x10 # QIC-150
|
||||
}
|
||||
|
||||
|
||||
# Exabyte 8505 and other similar 8 mm helical scan driver
|
||||
manufacturer=XYZ model = "UVW5" {
|
||||
can-bsr auto-lock
|
||||
cleaning=0x080821
|
||||
mode1 blocksize=0 density=0x8c # 8500 density, compressing
|
||||
mode2 blocksize=0 density=0x15 # 8500 density, no compression
|
||||
mode3 blocksize=0 density=0x90 # 8200 density, compressing
|
||||
mode4 blocksize=0 density=0x14 # 8200 density, no compression
|
||||
}
|
||||
|
||||
# A reel-to-reel tape with 6250/1600/800 bpi densities
|
||||
manufacturer=XYZ model = "UVW6" {
|
||||
can-bsr two-fms
|
||||
scsi2logical=0
|
||||
mode1 blocksize=0 density=3 # 6250 bpi
|
||||
mode2 blocksize=0 density=11 # 1600 bpi
|
||||
mode3 blocksize=0 density=1 # 800 bpi
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user