mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-08 22:23:18 +00:00
Remove long-unmaintained ftape driver subsystem.
It's bitrotten, long unmaintained, long hidden under BROKEN_ON_SMP, etc. As scheduled in feature-removal-schedule.txt, and ack'd several times on lkml. Signed-off-by: Jeff Garzik <jeff@garzik.org>
This commit is contained in:
parent
2b5f6dcce5
commit
d916faace3
@ -104,8 +104,6 @@ firmware_class/
|
||||
- request_firmware() hotplug interface info.
|
||||
floppy.txt
|
||||
- notes and driver options for the floppy disk driver.
|
||||
ftape.txt
|
||||
- notes about the floppy tape device driver.
|
||||
hayes-esp.txt
|
||||
- info on using the Hayes ESP serial driver.
|
||||
highuid.txt
|
||||
|
@ -234,14 +234,6 @@ Who: Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
---------------------------
|
||||
|
||||
What: ftape
|
||||
When: 2.6.20
|
||||
Why: Orphaned for ages. SMP bugs long unfixed. Few users left
|
||||
in the world.
|
||||
Who: Jeff Garzik <jeff@garzik.org>
|
||||
|
||||
---------------------------
|
||||
|
||||
What: IPv4 only connection tracking/NAT/helpers
|
||||
When: 2.6.22
|
||||
Why: The new layer 3 independant connection tracking replaces the old
|
||||
|
@ -1,307 +0,0 @@
|
||||
Intro
|
||||
=====
|
||||
|
||||
This file describes some issues involved when using the "ftape"
|
||||
floppy tape device driver that comes with the Linux kernel.
|
||||
|
||||
ftape has a home page at
|
||||
|
||||
http://ftape.dot-heine.de/
|
||||
|
||||
which contains further information about ftape. Please cross check
|
||||
this WWW address against the address given (if any) in the MAINTAINERS
|
||||
file located in the top level directory of the Linux kernel source
|
||||
tree.
|
||||
|
||||
NOTE: This is an unmaintained set of drivers, and it is not guaranteed to work.
|
||||
If you are interested in taking over maintenance, contact Claus-Justus Heine
|
||||
<ch@dot-heine.de>, the former maintainer.
|
||||
|
||||
Contents
|
||||
========
|
||||
|
||||
A minus 1: Ftape documentation
|
||||
|
||||
A. Changes
|
||||
1. Goal
|
||||
2. I/O Block Size
|
||||
3. Write Access when not at EOD (End Of Data) or BOT (Begin Of Tape)
|
||||
4. Formatting
|
||||
5. Interchanging cartridges with other operating systems
|
||||
|
||||
B. Debugging Output
|
||||
1. Introduction
|
||||
2. Tuning the debugging output
|
||||
|
||||
C. Boot and load time configuration
|
||||
1. Setting boot time parameters
|
||||
2. Module load time parameters
|
||||
3. Ftape boot- and load time options
|
||||
4. Example kernel parameter setting
|
||||
5. Example module parameter setting
|
||||
|
||||
D. Support and contacts
|
||||
|
||||
*******************************************************************************
|
||||
|
||||
A minus 1. Ftape documentation
|
||||
==============================
|
||||
|
||||
Unluckily, the ftape-HOWTO is out of date. This really needs to be
|
||||
changed. Up to date documentation as well as recent development
|
||||
versions of ftape and useful links to related topics can be found at
|
||||
the ftape home page at
|
||||
|
||||
http://ftape.dot-heine.de/
|
||||
|
||||
*******************************************************************************
|
||||
|
||||
A. Changes
|
||||
==========
|
||||
|
||||
1. Goal
|
||||
~~~~
|
||||
The goal of all that incompatibilities was to give ftape an interface
|
||||
that resembles the interface provided by SCSI tape drives as close
|
||||
as possible. Thus any Unix backup program that is known to work
|
||||
with SCSI tape drives should also work.
|
||||
|
||||
The concept of a fixed block size for read/write transfers is
|
||||
rather unrelated to this SCSI tape compatibility at the file system
|
||||
interface level. It developed out of a feature of zftape, a
|
||||
block wise user transparent on-the-fly compression. That compression
|
||||
support will not be dropped in future releases for compatibility
|
||||
reasons with previous releases of zftape.
|
||||
|
||||
2. I/O Block Size
|
||||
~~~~~~~~~~~~~~
|
||||
The block size defaults to 10k which is the default block size of
|
||||
GNU tar.
|
||||
|
||||
The block size can be tuned either during kernel configuration or
|
||||
at runtime with the MTIOCTOP ioctl using the MTSETBLK operation
|
||||
(i.e. do "mt -f /dev/qft0" setblk #BLKSZ). A block size of 0
|
||||
switches to variable block size mode i.e. "mt setblk 0" switches
|
||||
off the block size restriction. However, this disables zftape's
|
||||
built in on-the-fly compression which doesn't work with variable
|
||||
block size mode.
|
||||
|
||||
The BLKSZ parameter must be given as a byte count and must be a
|
||||
multiple of 32k or 0, i.e. use "mt setblk 32768" to switch to a
|
||||
block size of 32k.
|
||||
|
||||
The typical symptom of a block size mismatch is an "invalid
|
||||
argument" error message.
|
||||
|
||||
3. Write Access when not at EOD (End Of Data) or BOT (Begin Of Tape)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
zftape (the file system interface of ftape-3.x) denies write access
|
||||
to the tape cartridge when it isn't positioned either at BOT or
|
||||
EOD.
|
||||
|
||||
4. Formatting
|
||||
~~~~~~~~~~
|
||||
ftape DOES support formatting of floppy tape cartridges. You need the
|
||||
`ftformat' program that is shipped with the modules version of ftape.
|
||||
Please get the latest version of ftape from
|
||||
|
||||
ftp://sunsite.unc.edu/pub/Linux/kernel/tapes
|
||||
|
||||
or from the ftape home page at
|
||||
|
||||
http://ftape.dot-heine.de/
|
||||
|
||||
`ftformat' is contained in the `./contrib/' subdirectory of that
|
||||
separate ftape package.
|
||||
|
||||
5. Interchanging cartridges with other operating systems
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The internal emulation of Unix tape device file marks has changed
|
||||
completely. ftape now uses the volume table segment as specified
|
||||
by the QIC-40/80/3010/3020/113 standards to emulate file marks. As
|
||||
a consequence there is limited support to interchange cartridges
|
||||
with other operating systems.
|
||||
|
||||
To be more precise: ftape will detect volumes written by other OS's
|
||||
programs and other OS's programs will detect volumes written by
|
||||
ftape.
|
||||
|
||||
However, it isn't possible to extract the data dumped to the tape
|
||||
by some MSDOS program with ftape. This exceeds the scope of a
|
||||
kernel device driver. If you need such functionality, then go ahead
|
||||
and write a user space utility that is able to do that. ftape already
|
||||
provides all kernel level support necessary to do that.
|
||||
|
||||
*******************************************************************************
|
||||
|
||||
B. Debugging Output
|
||||
================
|
||||
|
||||
1. Introduction
|
||||
~~~~~~~~~~~~
|
||||
The ftape driver can be very noisy in that is can print lots of
|
||||
debugging messages to the kernel log files and the system console.
|
||||
While this is useful for debugging it might be annoying during
|
||||
normal use and enlarges the size of the driver by several kilobytes.
|
||||
|
||||
To reduce the size of the driver you can trim the maximal amount of
|
||||
debugging information available during kernel configuration. Please
|
||||
refer to the kernel configuration script and its on-line help
|
||||
functionality.
|
||||
|
||||
The amount of debugging output maps to the "tracing" boot time
|
||||
option and the "ft_tracing" modules option as follows:
|
||||
|
||||
0 bugs
|
||||
1 + errors (with call-stack dump)
|
||||
2 + warnings
|
||||
3 + information
|
||||
4 + more information
|
||||
5 + program flow
|
||||
6 + fdc/dma info
|
||||
7 + data flow
|
||||
8 + everything else
|
||||
|
||||
2. Tuning the debugging output
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
To reduce the amount of debugging output printed to the system
|
||||
console you can
|
||||
|
||||
i) trim the debugging output at run-time with
|
||||
|
||||
mt -f /dev/nqft0 setdensity #DBGLVL
|
||||
|
||||
where "#DBGLVL" is a number between 0 and 9
|
||||
|
||||
ii) trim the debugging output at module load time with
|
||||
|
||||
modprobe ftape ft_tracing=#DBGLVL
|
||||
|
||||
Of course, this applies only if you have configured ftape to be
|
||||
compiled as a module.
|
||||
|
||||
iii) trim the debugging output during system boot time. Add the
|
||||
following to the kernel command line:
|
||||
|
||||
ftape=#DBGLVL,tracing
|
||||
|
||||
Please refer also to the next section if you don't know how to
|
||||
set boot time parameters.
|
||||
|
||||
*******************************************************************************
|
||||
|
||||
C. Boot and load time configuration
|
||||
================================
|
||||
|
||||
1. Setting boot time parameters
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Assuming that you use lilo, the LI)nux LO)ader, boot time kernel
|
||||
parameters can be set by adding a line
|
||||
|
||||
append some_kernel_boot_time_parameter
|
||||
|
||||
to `/etc/lilo.conf' or at real boot time by typing in the options
|
||||
at the prompt provided by LILO. I can't give you advice on how to
|
||||
specify those parameters with other loaders as I don't use them.
|
||||
|
||||
For ftape, each "some_kernel_boot_time_parameter" looks like
|
||||
"ftape=value,option". As an example, the debugging output can be
|
||||
increased with
|
||||
|
||||
ftape=4,tracing
|
||||
|
||||
NOTE: the value precedes the option name.
|
||||
|
||||
2. Module load time parameters
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Module parameters can be specified either directly when invoking
|
||||
the program 'modprobe' at the shell prompt:
|
||||
|
||||
modprobe ftape ft_tracing=4
|
||||
|
||||
or by editing the file `/etc/modprobe.conf' in which case they take
|
||||
effect each time when the module is loaded with `modprobe' (please
|
||||
refer to the respective manual pages). Thus, you should add a line
|
||||
|
||||
options ftape ft_tracing=4
|
||||
|
||||
to `/etc/modprobe.conf` if you intend to increase the debugging
|
||||
output of the driver.
|
||||
|
||||
|
||||
3. Ftape boot- and load time options
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
i. Controlling the amount of debugging output
|
||||
DBGLVL has to be replaced by a number between 0 and 8.
|
||||
|
||||
module | kernel command line
|
||||
-----------------------|----------------------
|
||||
ft_tracing=DBGLVL | ftape=DBGLVL,tracing
|
||||
|
||||
ii. Hardware setup
|
||||
BASE is the base address of your floppy disk controller,
|
||||
IRQ and DMA give its interrupt and DMA channel, respectively.
|
||||
BOOL is an integer, "0" means "no"; any other value means
|
||||
"yes". You don't need to specify anything if connecting your tape
|
||||
drive to the standard floppy disk controller. All of these
|
||||
values have reasonable defaults. The defaults can be modified
|
||||
during kernel configuration, i.e. while running "make config",
|
||||
"make menuconfig" or "make xconfig" in the top level directory
|
||||
of the Linux kernel source tree. Please refer also to the on
|
||||
line documentation provided during that kernel configuration
|
||||
process.
|
||||
|
||||
ft_probe_fc10 is set to a non-zero value if you wish for ftape to
|
||||
probe for a Colorado FC-10 or FC-20 controller.
|
||||
|
||||
ft_mach2 is set to a non-zero value if you wish for ftape to probe
|
||||
for a Mountain MACH-2 controller.
|
||||
|
||||
module | kernel command line
|
||||
-----------------------|----------------------
|
||||
ft_fdc_base=BASE | ftape=BASE,ioport
|
||||
ft_fdc_irq=IRQ | ftape=IRQ,irq
|
||||
ft_fdc_dma=DMA | ftape=DMA,dma
|
||||
ft_probe_fc10=BOOL | ftape=BOOL,fc10
|
||||
ft_mach2=BOOL | ftape=BOOL,mach2
|
||||
ft_fdc_threshold=THR | ftape=THR,threshold
|
||||
ft_fdc_rate_limit=RATE | ftape=RATE,datarate
|
||||
|
||||
4. Example kernel parameter setting
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
To configure ftape to probe for a Colorado FC-10/FC-20 controller
|
||||
and to increase the amount of debugging output a little bit, add
|
||||
the following line to `/etc/lilo.conf':
|
||||
|
||||
append ftape=1,fc10 ftape=4,tracing
|
||||
|
||||
5. Example module parameter setting
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
To do the same, but with ftape compiled as a loadable kernel
|
||||
module, add the following line to `/etc/modprobe.conf':
|
||||
|
||||
options ftape ft_probe_fc10=1 ft_tracing=4
|
||||
|
||||
*******************************************************************************
|
||||
|
||||
D. Support and contacts
|
||||
====================
|
||||
|
||||
Ftape is distributed under the GNU General Public License. There is
|
||||
absolutely no warranty for this software. However, you can reach
|
||||
the current maintainer of the ftape package under the email address
|
||||
given in the MAINTAINERS file which is located in the top level
|
||||
directory of the Linux kernel source tree. There you'll find also
|
||||
the relevant mailing list to use as a discussion forum and the web
|
||||
page to query for the most recent documentation, related work and
|
||||
development versions of ftape.
|
||||
|
||||
Changelog:
|
||||
==========
|
||||
|
||||
~1996: Original Document
|
||||
|
||||
10-24-2004: General cleanup and updating, noting additional module options.
|
||||
James Nelson <james4765@gmail.com>
|
@ -557,9 +557,6 @@ and is between 256 and 4096 characters. It is defined in the file
|
||||
floppy= [HW]
|
||||
See Documentation/floppy.txt.
|
||||
|
||||
ftape= [HW] Floppy Tape subsystem debugging options.
|
||||
See Documentation/ftape.txt.
|
||||
|
||||
gamecon.map[2|3]=
|
||||
[HW,JOY] Multisystem joystick and NES/SNES/PSX pad
|
||||
support via parallel port (up to 5 devices per port)
|
||||
|
@ -1166,11 +1166,6 @@ P: David Howells
|
||||
M: dhowells@redhat.com
|
||||
S: Maintained
|
||||
|
||||
FTAPE/QIC-117
|
||||
L: linux-tape@vger.kernel.org
|
||||
W: http://sourceforge.net/projects/ftape
|
||||
S: Orphan
|
||||
|
||||
FUSE: FILESYSTEM IN USERSPACE
|
||||
P: Miklos Szeredi
|
||||
M: miklos@szeredi.hu
|
||||
|
@ -855,39 +855,6 @@ config TANBAC_TB0219
|
||||
depends TANBAC_TB022X
|
||||
select GPIO_VR41XX
|
||||
|
||||
menu "Ftape, the floppy tape device driver"
|
||||
|
||||
config FTAPE
|
||||
tristate "Ftape (QIC-80/Travan) support"
|
||||
depends on BROKEN_ON_SMP && (ALPHA || X86)
|
||||
---help---
|
||||
If you have a tape drive that is connected to your floppy
|
||||
controller, say Y here.
|
||||
|
||||
Some tape drives (like the Seagate "Tape Store 3200" or the Iomega
|
||||
"Ditto 3200" or the Exabyte "Eagle TR-3") come with a "high speed"
|
||||
controller of their own. These drives (and their companion
|
||||
controllers) are also supported if you say Y here.
|
||||
|
||||
If you have a special controller (such as the CMS FC-10, FC-20,
|
||||
Mountain Mach-II, or any controller that is based on the Intel 82078
|
||||
FDC like the high speed controllers by Seagate and Exabyte and
|
||||
Iomega's "Ditto Dash") you must configure it by selecting the
|
||||
appropriate entries from the "Floppy tape controllers" sub-menu
|
||||
below and possibly modify the default values for the IRQ and DMA
|
||||
channel and the IO base in ftape's configuration menu.
|
||||
|
||||
If you want to use your floppy tape drive on a PCI-bus based system,
|
||||
please read the file <file:drivers/char/ftape/README.PCI>.
|
||||
|
||||
The ftape kernel driver is also available as a runtime loadable
|
||||
module. To compile this driver as a module, choose M here: the
|
||||
module will be called ftape.
|
||||
|
||||
source "drivers/char/ftape/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
source "drivers/char/agp/Kconfig"
|
||||
|
||||
source "drivers/char/drm/Kconfig"
|
||||
|
@ -78,7 +78,6 @@ obj-$(CONFIG_TOSHIBA) += toshiba.o
|
||||
obj-$(CONFIG_I8K) += i8k.o
|
||||
obj-$(CONFIG_DS1620) += ds1620.o
|
||||
obj-$(CONFIG_HW_RANDOM) += hw_random/
|
||||
obj-$(CONFIG_FTAPE) += ftape/
|
||||
obj-$(CONFIG_COBALT_LCD) += lcd.o
|
||||
obj-$(CONFIG_PPDEV) += ppdev.o
|
||||
obj-$(CONFIG_NWBUTTON) += nwbutton.o
|
||||
|
@ -1,330 +0,0 @@
|
||||
#
|
||||
# Ftape configuration
|
||||
#
|
||||
config ZFTAPE
|
||||
tristate "Zftape, the VFS interface"
|
||||
depends on FTAPE
|
||||
---help---
|
||||
Normally, you want to say Y or M. DON'T say N here or you
|
||||
WON'T BE ABLE TO USE YOUR FLOPPY TAPE DRIVE.
|
||||
|
||||
The ftape module itself no longer contains the routines necessary
|
||||
to interface with the kernel VFS layer (i.e. to actually write data
|
||||
to and read data from the tape drive). Instead the file system
|
||||
interface (i.e. the hardware independent part of the driver) has
|
||||
been moved to a separate module.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called zftape.
|
||||
|
||||
Regardless of whether you say Y or M here, an additional runtime
|
||||
loadable module called `zft-compressor' which contains code to
|
||||
support user transparent on-the-fly compression based on Ross
|
||||
William's lzrw3 algorithm will be produced. If you have enabled the
|
||||
kernel module loader (i.e. have said Y to "Kernel module loader
|
||||
support", above) then `zft-compressor' will be loaded
|
||||
automatically by zftape when needed.
|
||||
|
||||
Despite its name, zftape does NOT use compression by default.
|
||||
|
||||
config ZFT_DFLT_BLK_SZ
|
||||
int "Default block size"
|
||||
depends on ZFTAPE
|
||||
default "10240"
|
||||
---help---
|
||||
If unsure leave this at its default value, i.e. 10240. Note that
|
||||
you specify only the default block size here. The block size can be
|
||||
changed at run time using the MTSETBLK tape operation with the
|
||||
MTIOCTOP ioctl (i.e. with "mt -f /dev/qft0 setblk #BLKSZ" from the
|
||||
shell command line).
|
||||
|
||||
The probably most striking difference between zftape and previous
|
||||
versions of ftape is the fact that all data must be written or read
|
||||
in multiples of a fixed block size. The block size defaults to
|
||||
10240 which is what GNU tar uses. The values for the block size
|
||||
should be either 1 or multiples of 1024 up to a maximum value of
|
||||
63488 (i.e. 62 K). If you specify `1' then zftape's builtin
|
||||
compression will be disabled.
|
||||
|
||||
Reasonable values are `10240' (GNU tar's default block size),
|
||||
`5120' (afio's default block size), `32768' (default block size some
|
||||
backup programs assume for SCSI tape drives) or `1' (no restriction
|
||||
on block size, but disables builtin compression).
|
||||
|
||||
comment "The compressor will be built as a module only!"
|
||||
depends on FTAPE && ZFTAPE
|
||||
|
||||
config ZFT_COMPRESSOR
|
||||
tristate
|
||||
depends on FTAPE!=n && ZFTAPE!=n
|
||||
default m
|
||||
|
||||
config FT_NR_BUFFERS
|
||||
int "Number of ftape buffers (EXPERIMENTAL)"
|
||||
depends on FTAPE && EXPERIMENTAL
|
||||
default "3"
|
||||
help
|
||||
Please leave this at `3' unless you REALLY know what you are doing.
|
||||
It is not necessary to change this value. Values below 3 make the
|
||||
proper use of ftape impossible, values greater than 3 are a waste of
|
||||
memory. You can change the amount of DMA memory used by ftape at
|
||||
runtime with "mt -f /dev/qft0 setdrvbuffer #NUMBUFFERS". Each buffer
|
||||
wastes 32 KB of memory. Please note that this memory cannot be
|
||||
swapped out.
|
||||
|
||||
config FT_PROC_FS
|
||||
bool "Enable procfs status report (+2kb)"
|
||||
depends on FTAPE && PROC_FS
|
||||
---help---
|
||||
Optional. Saying Y will result in creation of a directory
|
||||
`/proc/ftape' under the /proc file system. The files can be viewed
|
||||
with your favorite pager (i.e. use "more /proc/ftape/history" or
|
||||
"less /proc/ftape/history" or simply "cat /proc/ftape/history"). The
|
||||
file will contain some status information about the inserted
|
||||
cartridge, the kernel driver, your tape drive, the floppy disk
|
||||
controller and the error history for the most recent use of the
|
||||
kernel driver. Saying Y will enlarge the size of the ftape driver
|
||||
by approximately 2 KB.
|
||||
|
||||
WARNING: When compiling ftape as a module (i.e. saying M to "Floppy
|
||||
tape drive") it is dangerous to use ftape's /proc file system
|
||||
interface. Accessing `/proc/ftape' while the module is unloaded will
|
||||
result in a kernel Oops. This cannot be fixed from inside ftape.
|
||||
|
||||
choice
|
||||
prompt "Debugging output"
|
||||
depends on FTAPE
|
||||
default FT_NORMAL_DEBUG
|
||||
|
||||
config FT_NORMAL_DEBUG
|
||||
bool "Normal"
|
||||
---help---
|
||||
This option controls the amount of debugging output the ftape driver
|
||||
is ABLE to produce; it does not increase or diminish the debugging
|
||||
level itself. If unsure, leave this at its default setting,
|
||||
i.e. choose "Normal".
|
||||
|
||||
Ftape can print lots of debugging messages to the system console
|
||||
resp. kernel log files. Reducing the amount of possible debugging
|
||||
output reduces the size of the kernel module by some KB, so it might
|
||||
be a good idea to use "None" for emergency boot floppies.
|
||||
|
||||
If you want to save memory then the following strategy is
|
||||
recommended: leave this option at its default setting "Normal" until
|
||||
you know that the driver works as expected, afterwards reconfigure
|
||||
the kernel, this time specifying "Reduced" or "None" and recompile
|
||||
and install the kernel as usual. Note that choosing "Excessive"
|
||||
debugging output does not increase the amount of debugging output
|
||||
printed to the console but only makes it possible to produce
|
||||
"Excessive" debugging output.
|
||||
|
||||
Please read <file:Documentation/ftape.txt> for a short description
|
||||
how to control the amount of debugging output.
|
||||
|
||||
config FT_FULL_DEBUG
|
||||
bool "Excessive"
|
||||
help
|
||||
Extremely verbose output for driver debugging purposes.
|
||||
|
||||
config FT_NO_TRACE
|
||||
bool "Reduced"
|
||||
help
|
||||
Reduced tape driver debugging output.
|
||||
|
||||
config FT_NO_TRACE_AT_ALL
|
||||
bool "None"
|
||||
help
|
||||
Suppress all debugging output from the tape drive.
|
||||
|
||||
endchoice
|
||||
|
||||
comment "Hardware configuration"
|
||||
depends on FTAPE
|
||||
|
||||
choice
|
||||
prompt "Floppy tape controllers"
|
||||
depends on FTAPE
|
||||
default FT_STD_FDC
|
||||
|
||||
config FT_STD_FDC
|
||||
bool "Standard"
|
||||
---help---
|
||||
Only change this setting if you have a special controller. If you
|
||||
didn't plug any add-on card into your computer system but just
|
||||
plugged the floppy tape cable into the already existing floppy drive
|
||||
controller then you don't want to change the default setting,
|
||||
i.e. choose "Standard".
|
||||
|
||||
Choose "MACH-2" if you have a Mountain Mach-2 controller.
|
||||
Choose "FC-10/FC-20" if you have a Colorado FC-10 or FC-20
|
||||
controller.
|
||||
Choose "Alt/82078" if you have another controller that is located at
|
||||
an IO base address different from the standard floppy drive
|
||||
controller's base address of `0x3f0', or uses an IRQ (interrupt)
|
||||
channel different from `6', or a DMA channel different from
|
||||
`2'. This is necessary for any controller card that is based on
|
||||
Intel's 82078 FDC such as Seagate's, Exabyte's and Iomega's "high
|
||||
speed" controllers.
|
||||
|
||||
If you choose something other than "Standard" then please make
|
||||
sure that the settings for the IO base address and the IRQ and DMA
|
||||
channel in the configuration menus below are correct. Use the manual
|
||||
of your tape drive to determine the correct settings!
|
||||
|
||||
If you are already successfully using your tape drive with another
|
||||
operating system then you definitely should use the same settings
|
||||
for the IO base, the IRQ and DMA channel that have proven to work
|
||||
with that other OS.
|
||||
|
||||
Note that this menu lets you specify only the default setting for
|
||||
the hardware setup. The hardware configuration can be changed at
|
||||
boot time (when ftape is compiled into the kernel, i.e. if you
|
||||
have said Y to "Floppy tape drive") or module load time (i.e. if you
|
||||
have said M to "Floppy tape drive").
|
||||
|
||||
Please read also the file <file:Documentation/ftape.txt> which
|
||||
contains a short description of the parameters that can be set at
|
||||
boot or load time. If you want to use your floppy tape drive on a
|
||||
PCI-bus based system, please read the file
|
||||
<file:drivers/char/ftape/README.PCI>.
|
||||
|
||||
config FT_MACH2
|
||||
bool "MACH-2"
|
||||
|
||||
config FT_PROBE_FC10
|
||||
bool "FC-10/FC-20"
|
||||
|
||||
config FT_ALT_FDC
|
||||
bool "Alt/82078"
|
||||
|
||||
endchoice
|
||||
|
||||
comment "Consult the manuals of your tape drive for the correct settings!"
|
||||
depends on FTAPE && !FT_STD_FDC
|
||||
|
||||
config FT_FDC_BASE
|
||||
hex "IO base of the floppy disk controller"
|
||||
depends on FTAPE && !FT_STD_FDC
|
||||
default "0"
|
||||
---help---
|
||||
You don't need to specify a value if the following default
|
||||
settings for the base IO address are correct:
|
||||
<<< MACH-2 : 0x1E0 >>>
|
||||
<<< FC-10/FC-20: 0x180 >>>
|
||||
<<< Secondary : 0x370 >>>
|
||||
Secondary refers to a secondary FDC controller like the "high speed"
|
||||
controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash.
|
||||
Please make sure that the setting for the IO base address
|
||||
specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR
|
||||
CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already
|
||||
successfully using the tape drive with another operating system then
|
||||
you definitely should use the same settings for the IO base that has
|
||||
proven to work with that other OS.
|
||||
|
||||
Note that this menu lets you specify only the default setting for
|
||||
the IO base. The hardware configuration can be changed at boot time
|
||||
(when ftape is compiled into the kernel, i.e. if you specified Y to
|
||||
"Floppy tape drive") or module load time (i.e. if you have said M to
|
||||
"Floppy tape drive").
|
||||
|
||||
Please read also the file <file:Documentation/ftape.txt> which
|
||||
contains a short description of the parameters that can be set at
|
||||
boot or load time.
|
||||
|
||||
config FT_FDC_IRQ
|
||||
int "IRQ channel of the floppy disk controller"
|
||||
depends on FTAPE && !FT_STD_FDC
|
||||
default "0"
|
||||
---help---
|
||||
You don't need to specify a value if the following default
|
||||
settings for the interrupt channel are correct:
|
||||
<<< MACH-2 : 6 >>>
|
||||
<<< FC-10/FC-20: 9 >>>
|
||||
<<< Secondary : 6 >>>
|
||||
Secondary refers to secondary a FDC controller like the "high speed"
|
||||
controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash.
|
||||
Please make sure that the setting for the IO base address
|
||||
specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR
|
||||
CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already
|
||||
successfully using the tape drive with another operating system then
|
||||
you definitely should use the same settings for the IO base that has
|
||||
proven to work with that other OS.
|
||||
|
||||
Note that this menu lets you specify only the default setting for
|
||||
the IRQ channel. The hardware configuration can be changed at boot
|
||||
time (when ftape is compiled into the kernel, i.e. if you said Y to
|
||||
"Floppy tape drive") or module load time (i.e. if you said M to
|
||||
"Floppy tape drive").
|
||||
|
||||
Please read also the file <file:Documentation/ftape.txt> which
|
||||
contains a short description of the parameters that can be set at
|
||||
boot or load time.
|
||||
|
||||
config FT_FDC_DMA
|
||||
int "DMA channel of the floppy disk controller"
|
||||
depends on FTAPE && !FT_STD_FDC
|
||||
default "0"
|
||||
---help---
|
||||
You don't need to specify a value if the following default
|
||||
settings for the DMA channel are correct:
|
||||
<<< MACH-2 : 2 >>>
|
||||
<<< FC-10/FC-20: 3 >>>
|
||||
<<< Secondary : 2 >>>
|
||||
Secondary refers to a secondary FDC controller like the "high speed"
|
||||
controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash.
|
||||
Please make sure that the setting for the IO base address
|
||||
specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR
|
||||
CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already
|
||||
successfully using the tape drive with another operating system then
|
||||
you definitely should use the same settings for the IO base that has
|
||||
proven to work with that other OS.
|
||||
|
||||
Note that this menu lets you specify only the default setting for
|
||||
the DMA channel. The hardware configuration can be changed at boot
|
||||
time (when ftape is compiled into the kernel, i.e. if you said Y to
|
||||
"Floppy tape drive") or module load time (i.e. if you said M to
|
||||
"Floppy tape drive").
|
||||
|
||||
Please read also the file <file:Documentation/ftape.txt> which
|
||||
contains a short description of the parameters that can be set at
|
||||
boot or load time.
|
||||
|
||||
config FT_FDC_THR
|
||||
int "Default FIFO threshold (EXPERIMENTAL)"
|
||||
depends on FTAPE && EXPERIMENTAL
|
||||
default "8"
|
||||
help
|
||||
Set the FIFO threshold of the FDC. If this is higher the DMA
|
||||
controller may serve the FDC after a higher latency time. If this is
|
||||
lower, fewer DMA transfers occur leading to less bus contention.
|
||||
You may try to tune this if ftape annoys you with "reduced data
|
||||
rate because of excessive overrun errors" messages. However, this
|
||||
doesn't seem to have too much effect.
|
||||
|
||||
If unsure, don't touch the initial value, i.e. leave it at "8".
|
||||
|
||||
config FT_FDC_MAX_RATE
|
||||
int "Maximal data rate to use (EXPERIMENTAL)"
|
||||
depends on FTAPE && EXPERIMENTAL
|
||||
default "2000"
|
||||
---help---
|
||||
With some motherboard/FDC combinations ftape will not be able to
|
||||
run your FDC/tape drive combination at the highest available
|
||||
speed. If this is the case you'll encounter "reduced data rate
|
||||
because of excessive overrun errors" messages and lots of retries
|
||||
before ftape finally decides to reduce the data rate.
|
||||
|
||||
In this case it might be desirable to tell ftape beforehand that
|
||||
it need not try to run the tape drive at the highest available
|
||||
speed. If unsure, leave this disabled, i.e. leave it at 2000
|
||||
bits/sec.
|
||||
|
||||
config FT_ALPHA_CLOCK
|
||||
int "CPU clock frequency of your DEC Alpha" if ALPHA
|
||||
depends on FTAPE
|
||||
default "0"
|
||||
help
|
||||
On some DEC Alpha machines the CPU clock frequency cannot be
|
||||
determined automatically, so you need to specify it here ONLY if
|
||||
running a DEC Alpha, otherwise this setting has no effect.
|
||||
|
@ -1,28 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 1997 Claus 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/ftape/Makefile,v $
|
||||
# $Revision: 1.4 $
|
||||
# $Date: 1997/10/05 19:17:56 $
|
||||
#
|
||||
# Makefile for the QIC-40/80/3010/3020 floppy-tape driver for
|
||||
# Linux.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_FTAPE) += lowlevel/
|
||||
obj-$(CONFIG_ZFTAPE) += zftape/
|
||||
obj-$(CONFIG_ZFT_COMPRESSOR) += compressor/
|
@ -1,81 +0,0 @@
|
||||
Some notes for ftape users with PCI motherboards:
|
||||
=================================================
|
||||
|
||||
The problem:
|
||||
------------
|
||||
|
||||
There have been some problem reports from people using PCI-bus based
|
||||
systems getting overrun errors.
|
||||
I wasn't able to reproduce these until I ran ftape on a Intel Plato
|
||||
(Premiere PCI II) motherboard with bios version 1.00.08AX1.
|
||||
It turned out that if GAT (Guaranteed Access Timing) is enabled (?)
|
||||
ftape gets a lot of overrun errors.
|
||||
The problem disappears when disabling GAT in the bios.
|
||||
Note that Intel removed this setting (permanently disabled) from the
|
||||
1.00.10AX1 bios !
|
||||
|
||||
It looks like that if GAT is enabled there are often large periods
|
||||
(greater than 120 us !??) on the ISA bus that the DMA controller cannot
|
||||
service the floppy disk controller.
|
||||
I cannot imagine this being acceptable in a decent PCI implementation.
|
||||
Maybe this is a `feature' of the chipset. I can only speculate why
|
||||
Intel choose to remove the option from the latest Bios...
|
||||
|
||||
The lesson of this all is that there may be other motherboard
|
||||
implementations having the same of similar problems.
|
||||
If you experience a lot of overrun errors during a backup to tape,
|
||||
see if there is some setting in the Bios that may influence the
|
||||
bus timing.
|
||||
|
||||
I judge this a hardware problem and not a limitation of ftape ;-)
|
||||
My DOS backup software seems to be suffering from the same problems
|
||||
and even refuses to run at 1 Mbps !
|
||||
Ftape will reduce the data-rate from 1 Mbps to 500 Kbps if the number
|
||||
of overrun errors on a track exceeds a threshold.
|
||||
|
||||
|
||||
Possible solutions:
|
||||
-------------------
|
||||
|
||||
Some of the problems were solved by upgrading the (flash) bios.
|
||||
Other suggest that it has to do with the FDC being on the PCI
|
||||
bus, but that is not the case with the Intel Premiere II boards.
|
||||
[If upgrading the bios doesn't solve the problem you could try
|
||||
a floppy disk controller on the isa-bus].
|
||||
|
||||
Here is a list of systems and recommended BIOS settings:
|
||||
|
||||
|
||||
Intel Premiere PCI (Revenge):
|
||||
|
||||
Bios version 1.00.09.AF2 is reported to work.
|
||||
|
||||
|
||||
|
||||
Intel Premiere PCI II (Plato):
|
||||
|
||||
Bios version 1.00.10.AX1 and version 11 beta are ok.
|
||||
If using version 1.00.08.AX1, GAT must be disabled !
|
||||
|
||||
|
||||
|
||||
ASUS PCI/I-SP3G:
|
||||
|
||||
Preferred settings: ISA-GAT-mode : disabled
|
||||
DMA-linebuffer-mode : standard
|
||||
ISA-masterbuffer-mode : standard
|
||||
|
||||
|
||||
DELL Dimension XPS P90
|
||||
|
||||
Bios version A2 is reported to be broken, while bios version A5 works.
|
||||
You can get a flash bios upgrade from http://www.dell.com
|
||||
|
||||
|
||||
To see if you're having the GAT problem, try making a backup
|
||||
under DOS. If it's very slow and often repositions you're
|
||||
probably having this problem.
|
||||
|
||||
--//--
|
||||
LocalWords: ftape PCI bios GAT ISA DMA chipset Mbps Kbps FDC isa AF ok ASUS
|
||||
LocalWords: SP linebuffer masterbuffer XPS http www com
|
@ -1,966 +0,0 @@
|
||||
Hey, Emacs, we're -*-Text-*- mode!
|
||||
|
||||
===== Release notes for ftape-3.04d 25/11/97 =====
|
||||
- The correct pre-processor statement for "else if" is "#elif" not
|
||||
"elsif".
|
||||
- Need to call zft_reset_position() when overwriting cartridges
|
||||
previously written with ftape-2.x, sftape, or ancient
|
||||
(pre-ftape-3.x) versions of zftape.
|
||||
|
||||
===== Release notes for ftape-3.04c 16/11/97 =====
|
||||
- fdc_probe() was calling DUMPREGS with a result length of "1" which
|
||||
was just fine. Undo previous change.
|
||||
|
||||
===== Release notes for ftape-3.04b 14/11/97 =====
|
||||
|
||||
- patches/2.x.x/floppy.c.diff was somewhat broken, releasing i/o
|
||||
regions it never had allocated.
|
||||
- fdc_probe() was calling DUMPREGS with a result length of "1" instead
|
||||
of "10"
|
||||
- Writing deleted data marks if the first segents on track zero are
|
||||
should work now.
|
||||
- ftformat should now be able to handle those cases where the tape
|
||||
drive sets the read only status bit (QIC-40/80 cartridges with
|
||||
QIC-3010/3020 tape drives) because the header segment is damaged.
|
||||
- the MTIOCFTCMD ioctl may now be issued by the superuser ONLY.
|
||||
|
||||
===== Release notes for ftape-3.04a 12/11/97 =====
|
||||
- Fix an "infinite loop can't be killed by signal" bug in
|
||||
ftape_get_drive_status(). Only relevant when trying to access
|
||||
buggy/misconfigured hardware
|
||||
- Try to compensate a bug in the HP Colorado T3000's firmware: it
|
||||
doesn't set the write protect bit for QIC80/QIC40 cartridges.
|
||||
|
||||
===== Release notes for ftape-3.04 06/11/97 =====
|
||||
- If positioning with fast seeking fails fall back to a slow seek
|
||||
before giving up.
|
||||
- (nearly) no retries on "no data errors" when verifying after
|
||||
formatting. Improved tuning of the bad sector map after formatting.
|
||||
- the directory layout has changed again to allow for easier kernel
|
||||
integration
|
||||
- Module parameter "ftape_tracing" now is called "ft_tracing" because
|
||||
the "ftape_tracing" variable has the version checksum attached to it.
|
||||
- `/proc/ftape' interface for 2.0.* kernels. `/proc/ftape' no longer
|
||||
is a directory but a file that contains all the information formerly
|
||||
provided in separate files under the `/proc/ftape/' directory.
|
||||
- Most of the configuration options have been prefixed by "CONFIG_FT_"
|
||||
in preparation of the kernel inclusion. The Makefiles under
|
||||
"./ftape/" should be directly usable by the kernel.
|
||||
- The MODVERSIONS stuff is now auto-detected.
|
||||
- Broke backslashed multi line options in MCONFIG into separate lines
|
||||
using GNU-make's "+=" feature.
|
||||
- The html and dvi version of the manual is now installed under
|
||||
'/usr/doc/ftape` with 'make install`
|
||||
- New SMP define in MCONFIG. ftape works with SMP if this is defined.
|
||||
- attempt to cope with "excessive overrun errors" by gradually
|
||||
increasing FDC FIFO threshold. But this doesn't seem to have too
|
||||
much an effect.
|
||||
- New load time configuration parameter "ft_fdc_rate_limit". If you
|
||||
encounter too many overrun errors with a 2Mb controller then you
|
||||
might want to set this to 1000.
|
||||
- overrun errors on the last sector in a segment sometimes result in
|
||||
a zero DMA residue. Dunno why, but compensate for it.
|
||||
- there were still fdc_read() timeout errors. I think I have fixed it
|
||||
now, please FIXME.
|
||||
- Sometimes ftape_write() failed to re-start the tape drive when a
|
||||
segment without a good sector was reached ("wait for empty segment
|
||||
failed"). This is fixed. Especially important for > QIC-3010.
|
||||
- sftape (aka ftape-2.x) has vanished. I didn't work on it for
|
||||
ages. It is probably still possible to use the old code with
|
||||
ftape-3.04, if one really needs it (BUT RECOMPILE IT)
|
||||
- zftape no longer alters the contents of already existing volume
|
||||
table entries, which makes it possible to fill in missing fields,
|
||||
like time stamps using some user space program.
|
||||
- ./contrib/vtblc/ contains such a program.
|
||||
- new perl script ./contrib/scripts/listtape that list the contents of a
|
||||
floppy tape cartridge parsing the output of "mt volinfo" + "mt fsf"
|
||||
- the MTWEOF implementation has changed a little bit (after I had a
|
||||
look at amanda). Calling MTWEOF while the tape is still held open
|
||||
after writing something to the tape now will terminate the current
|
||||
volume, and start a new one at the current position.
|
||||
- the volume table maintained by zftape now is a doubly linked list
|
||||
that grows dynamically as needed.
|
||||
|
||||
formatting floppy tape cartridges
|
||||
---------------------------------
|
||||
* there is a new user space formatting program that does most of the
|
||||
dirty work in user space (auto-detect, computing the sector
|
||||
coordinates, adjusting time stamps and statistics). It has a
|
||||
simple command line interface.
|
||||
* ftape-format.o has vanished, it has been folded into the low level
|
||||
ftape.o module, and the ioctl interface into zftape.o. Most of the
|
||||
complicated stuff has been moved to user space, so there was no
|
||||
need for a separate module anymore.
|
||||
* there is a new ioctl MTIOCFTCMD that sends a bare QIC-117 command
|
||||
to the tape drive.
|
||||
* there is a new mmap() feature to map the dma buffers into user
|
||||
space to be used by the user level formatting program.
|
||||
* Formatting of yet unformatted or totally degaussed cartridges
|
||||
should be possible now. FIXME.
|
||||
|
||||
===== Release notes for ftape-3.03b, <forgot the exact date> ====
|
||||
|
||||
ftape-3.03b was released as a beta release only. Its main new feature
|
||||
was support of the DITTO-2GB drive. This was made possible by reverse
|
||||
engineering done by <fill in his name> after Iomega failed to support
|
||||
ftape. Although they had promised to do so (this makes me feel a bit
|
||||
sad and uncomfortable about Iomega).
|
||||
|
||||
===== Release notes for ftape-3.03a, 22/05/97 ====
|
||||
|
||||
- Finally fixed auto-un-loading of modules for kernels > 2.1.18
|
||||
- Add an "uninstall" target to the Makefile
|
||||
- removed the kdtime hack
|
||||
- texi2www didn't properly set the back-reference from a footnote back
|
||||
to the regular text.
|
||||
|
||||
zftape specific
|
||||
---------------
|
||||
* hide the old compression map volume. Taper doesn't accept the
|
||||
presence of non-Taper volumes and Taper-written volume on the same
|
||||
tape.
|
||||
* EOD (End Of Data) handling was still broken: the expected behavior
|
||||
is to return a zero byte count at the first attempt to read past
|
||||
EOD, return a zero byte count at the second attempt to read past
|
||||
EOD and THEN return -EIO.
|
||||
|
||||
ftape-format specific
|
||||
---------------------
|
||||
* Detection of QIC-40 cartridges in select_tape_format() was broken
|
||||
and made it impossible to format QIC-3010/3020 cartridges.
|
||||
* There are strange "TR-1 Extra" cartridges out there which weren't
|
||||
detected properly because the don't strictly conform to the
|
||||
QIC-80, Rev. N, spec.
|
||||
|
||||
===== Release notes for ftape-3.03, 30/04/97 =====
|
||||
|
||||
- Removed kernel integration code from the package. I plan to provide
|
||||
a package that can be integrated into the stock kernel separately
|
||||
(hopefully soon).
|
||||
As a result, a simple `make' command now will build everything.
|
||||
- ALL compile time configuration options have been moved to the file
|
||||
`MCONFIG'.
|
||||
- Quite a few `low level' changes to allow formatting of cartridges.
|
||||
- formatting is implemented as a separate module `ftape-format.o'. The
|
||||
modified `mt' program contains sample code that shows how to use it.
|
||||
- The VFS interface has been moved from the `ftape.o' module to the
|
||||
high level modules `zftape.o' resp. `sftape.o'. `ftape.o' contains
|
||||
the hardware support only.
|
||||
- A bit of /proc support for kernels > 2.1.28
|
||||
- Moved documentation to Doc subdir. INSTALL now contains some real
|
||||
installation notes.
|
||||
- `install' target in Makefile.
|
||||
|
||||
zftape specific:
|
||||
----------------
|
||||
|
||||
- zftape works for large cartridges now ( > 2^31 bytes)
|
||||
- MTIOCVOLINFO and MTIOCGETSIZE now return the size in KILOBYTES,
|
||||
NO LONGER in bytes.
|
||||
|
||||
- permissions for write access to a cartridge have changed:
|
||||
* zftape now also takes the file access mode into account
|
||||
* zftape no longer allows writing in the middle of the recorded
|
||||
media. The tape has to be positioned at BOT or EOD for write
|
||||
access.
|
||||
|
||||
- MTBSF has changed. It used to position at the beginning of the
|
||||
previous file when called with count 1. This was different from the
|
||||
expected behavior for other Un*x tape drivers (i.e. SCSI). MTBSF
|
||||
with count 1 should merely position at the beginning of the current
|
||||
volume. Fixed. As a result, `tar --verify' now produces the desired
|
||||
result: it verifies the last written volume, not the pre-last
|
||||
written volume.
|
||||
|
||||
- The compression map has vanished --> no need for `mt erase' any
|
||||
more. Fast seeking in a compressed volume is still be possible, but
|
||||
takes slightly longer. As a side effect, you may experience an
|
||||
additional volume showing up in front of all others for old
|
||||
cartridges. This is the tape volume that holds the compression map.
|
||||
|
||||
- The compression support for zftape has been moved to a separate
|
||||
module `zft-compressor'. DON'T forget to load it before trying to
|
||||
read back compressed volumes. The stock `zftape.o' module probes for
|
||||
the module `zft-compressor' using the kerneld message channel; you
|
||||
have to install `zft-compressor.o' in a place where modprobe can
|
||||
find it if you want to use this.
|
||||
|
||||
- New experimental feature that tries to get the broken down GMT time
|
||||
from user space via a kernel daemon message channel. You need to
|
||||
compile and start the `kdtime' daemon contained in the contrib
|
||||
directory to use it. Needed (?) for time stamps in the header
|
||||
segments and the volume table.
|
||||
|
||||
- variable block size mode via MTSETBLK 0
|
||||
|
||||
- keep modules locked in memory after the block size has been changed
|
||||
|
||||
sftape specific:
|
||||
----------------
|
||||
|
||||
- end of tape handling should be fixed, i.e. multi volume archives
|
||||
written with `afio' can be read back now.
|
||||
|
||||
|
||||
===== Release notes for ftape-3.02a, 09/01/97 =====
|
||||
|
||||
No big news:
|
||||
- call zft_init() resp. sft_init() when compiling the entire stuff
|
||||
into the kernel image.
|
||||
- fix bug in ftape-setup.c when NO_TRACE_AT_ALL was defined.
|
||||
- fix bug in sftape-eof.c/zftape-eof.c for old kernels (1.2.*)
|
||||
- add support for new module interface for recent kernels
|
||||
|
||||
===== Release notes for ftape-3.02, 16/12/96 =====
|
||||
- Fixed the `FDC unlock command failed' bug in fdc-io.c. When the FIFO
|
||||
was already locked when ftape was loaded, ftape failed to unlock it.
|
||||
- Fixed compilation of `contrib/gnumt'. It now finds `mtio.h' even if
|
||||
ftape is NOT included into the kernel source tree.
|
||||
- fc-10.c: include <asm/io.h> for inb() and outb().
|
||||
- ftape/sftape/zftape: all global variable now have either a `ftape_',
|
||||
a `ft_', `sft_', `zft_' or `qic_' prefix to prevent name clashes
|
||||
with other parts of the kernel when including ftape into the kernel
|
||||
source tree.
|
||||
- Kerneld support has changed. `ftape' now searches for a module
|
||||
`ftape-frontend' when none of the frontend (`sftape' or `zftape') is
|
||||
loaded. Please refer to the `Installation/Loading ftape' section of
|
||||
the TeXinfo manual.
|
||||
- Add load resp. boot-time configuration of ftape. There are now
|
||||
variables ft_fdc_base, ft_fdc_dma and ft_fdc_irq corresponding to
|
||||
the former FDC_BASE etc. compile time definitions. One can also use
|
||||
the kernel command line parameters to configure the driver if it is
|
||||
compiled into the kernel. Also, the FC-10/FC-20 support is load-time
|
||||
configurable now as well as the MACH-II hack (ft_probe_fc10,
|
||||
resp. ft_mach2). Please refer to the section `Installation/Configure
|
||||
ftape' of the TeXinfo manual.
|
||||
- I removed the MODVERSIONS option from `Makefile.module'. Let me alone
|
||||
with ftape and MODVERSIONS unless you include the ftape sources into
|
||||
the kernel source tree.
|
||||
- new vendors in `vendors.h':
|
||||
* HP Colorado T3000
|
||||
* ComByte DoublePlay (including a bug fix for their broken
|
||||
formatting software, thanks to whraven@njackn.com)
|
||||
* Iomega DITTO 2GIG. NOTE: this drive cannot work with ftape because
|
||||
the logical data layout of the cartridges used by this drive does
|
||||
NOT conform to the QIC standards, it is a special Iomega specific
|
||||
format. I've sent mail to Iomega but didn't receive an answer
|
||||
yet. If you want this drive to be supported by ftape, ask Iomega
|
||||
to give me information about it.
|
||||
- zftape:
|
||||
* re-introduced the MTIOC_ZFTAPE_GETBLKSZ ioctl for compatibility
|
||||
with zftape 1.06a and earlier. Please don't use it when writing
|
||||
new software, use the MTIOCVOLINFO ioctl instead.
|
||||
* Major overhaul of the code that updates the header segments. Never
|
||||
change the tape label unless erasing the tape. Thus we almost
|
||||
never need to write the header segments, unless we would modify
|
||||
the bad sector map which isn't done yet. Updating of volume table
|
||||
and compression map more secure now although it takes a bit
|
||||
longer.
|
||||
* Fixed bug when aborting a write operation with a signal: zftape
|
||||
now finishes the current volume (i.e. writes an eof marker) at the
|
||||
current position. It didn't before which led to somehow *strange*
|
||||
behavior in this cases.
|
||||
* Keep module locked in memory when using it with the non-rewinding
|
||||
devices and the tape is not logical at BOT. Needed for kerneld
|
||||
support.
|
||||
- sftape:
|
||||
* Keep module locked in memory when using it with the non-rewinding
|
||||
devices and the tape is not logical at BOT. Needed for kerneld
|
||||
support.
|
||||
|
||||
===== Release notes for ftape-3.01, 14/11/96 =====
|
||||
|
||||
- Fixed silly bugs in ftape-3.00:
|
||||
* MAKEDEV.ftape: major device number must be 27, not 23
|
||||
* sftape/sftape-read.c: sftape_read_header_segments() called
|
||||
itself recursively instead of calling ftape_read_header_segment()
|
||||
* zftape/qic-vtbl.h: conversion of ftape's file marks to zftape's
|
||||
internal volume table was broken.
|
||||
* patches/2.x.x/linux-2.0.21.dif: my RCS (resp. CVS) system replaced
|
||||
the `$Revison:' etc. macros in the `ftape.h' concerning part of the
|
||||
patch :-( Fixed.
|
||||
* info/ftape.info: Fixed misspellings (`cp' <-> `cp -r' etc.)
|
||||
* when ftape/sftape or ftape/zftape was compiled into the kernel the
|
||||
variable ftape_status was declared twice. Fixed.
|
||||
* removed reference to undeclared variable kernel_version when not
|
||||
compiling as module
|
||||
* fixed a bug introduced by the use of bit-fields for some flags
|
||||
(i.e. write_protected, no_cartridge, formatted)
|
||||
* flag `header_read' is now reset correctly to zero when tape is
|
||||
removed.
|
||||
- fixed a bug in sftape/sftape-eof.c that was already in the original
|
||||
ftape code. MTFSF/BSF was not handled correctly when positioned
|
||||
right before the file mark (think of tar)
|
||||
- Changed TRACE macros (following a suggestion of Marcin Dalecki) to use
|
||||
the predefined __FUNCTION__ macro of GCC. Spares about 4k of code.
|
||||
- added new vendor id for Iomega DITTO 2GIG
|
||||
- fixed a bug already present in zftape-1.06 when aborting a write
|
||||
with a signal: we now finish the current volume at that
|
||||
position. Header segments remain NOT up to date until an explicit call
|
||||
to MTREW or MTOFFL is done.
|
||||
|
||||
===== Release notes for ftape-3.00, 14/10/96 =====
|
||||
|
||||
- Merged ftape with zftape. There are three modules now:
|
||||
ftape for the hardware support, sftape for the implementation of the
|
||||
original ftape eof mark stuff and zftape that implements zftape's way
|
||||
of handling things (compression, volume table, tape blocks of
|
||||
constant length)
|
||||
- Documentation in TeXinfo format in the `info' subdirectory.
|
||||
- New ioctls for zftape. See zftape/zftape.h
|
||||
- Dummy formatting ioctl for ftape. See ftape.h
|
||||
- Kernel patch files for the 2.*.* series to include ftape-3.00 in the
|
||||
kernel source tree. These includes a kernel compatible Config.in
|
||||
script and fairly large online information for the kernel configure
|
||||
script.
|
||||
- Support for compiling with Linux-1.2.13.
|
||||
- Modified GNU mt from their cpio package that can handle the new
|
||||
ioctls.
|
||||
- ftape/sftape/zftape is kerneld save now!
|
||||
|
||||
Notes on sftape:
|
||||
- sftape implements the eof handling code of the original ftape. If
|
||||
you like to stick with the original ftape stuff, you have to use
|
||||
this module, not zftape.
|
||||
- sftape is kerneld save, unlike the original ftape.
|
||||
- we keep the entire header segment now in memory, so no need to read
|
||||
it before updating the header segments. Additional memory
|
||||
consumption: 256 bytes.
|
||||
|
||||
Notes for zftape:
|
||||
- zftape has support for tapes with format code 6 now, which use a
|
||||
slightly different volume table format compared with other floppy
|
||||
tapes.
|
||||
- new ioctls for zftape. Have a look at zftape/zftape.h
|
||||
- The internal volume table representation has changed for zftape. Old
|
||||
cartridges are converted automatically.
|
||||
- zftape no longer uses compression map segments, which have vanished
|
||||
from the QIC specs, but creates volume table entry that reserves
|
||||
enough space for the compression map.
|
||||
- zftape is kerneld save now.
|
||||
- we keep the entire header segment now in memory, so no need to read
|
||||
it before updating the header segments. Additional memory
|
||||
consumption: 256 bytes.
|
||||
|
||||
Notes for contrib/gnumt:
|
||||
- modified mt from the GNU cpio package that supports all the new
|
||||
ioctls of zftape.
|
||||
Notes for contrib/swapout:
|
||||
- This contains the swapout.c program that was written by Kai
|
||||
Harrekilde-Pederson. I simply added a Makefile.
|
||||
|
||||
===== Release notes for ftape-2.10, 14/10/96 =====
|
||||
|
||||
The ftape maintainer has changed.
|
||||
Kai Harrekilde-Petersen <khp@dolphinics.no>
|
||||
has resigned from maintaining ftape, and I,
|
||||
Claus-Justus Heine <claus@momo.math.rwth-aachen.de>,
|
||||
have taken over.
|
||||
|
||||
- Added support for tapes with `format code 6', i.e. QIC-3020 tapes
|
||||
with more than 2^16 segments.
|
||||
- merged changes made by Bas Laarhoven with ftape-2.09. Refer
|
||||
to his release notes below. I've included them into this
|
||||
file unchanged for your reference.
|
||||
- disabled call stack back trace for now. This new feature
|
||||
introduced by the interim release 2.0.x still seems to
|
||||
be buggy.
|
||||
- Tried to minimize differences between the ftape version
|
||||
to be included into the kernel source tree and the standalone
|
||||
module version.
|
||||
- Reintroduced support for Linux-1.2.13. Please refer to the
|
||||
Install-guide.
|
||||
|
||||
===== Release notes for ftape-2.09, 16/06/96 =====
|
||||
|
||||
There aren't any really big news in this release, mostly just that I
|
||||
(the maintainer) have changed my email address (due to a new job). My
|
||||
new address is <khp@dolphinics.no>
|
||||
|
||||
- The CLK_48MHZ and FDC_82078SL options has gone (all 2Mbps cards seem
|
||||
to use a 48MHz oscillator anyway and I haven't heard of an 'SL
|
||||
chip out there).
|
||||
- The S82078B has been `downgraded' to i82077AA compability.
|
||||
- TESTING option revived. Right now, it'll enable the (seriously broken)
|
||||
2Mbps code. If you enable it, you'll experience a tape drive that's
|
||||
*really* out to lunch!
|
||||
- Some (bold) changes in the init code. Please notify me if they
|
||||
break things for you.
|
||||
|
||||
===== Release notes for ftape-2.08, 14/03/96 =====
|
||||
|
||||
If you correct a problem with ftape, please send your patch to
|
||||
khp@dolphinics.no too.
|
||||
|
||||
- Updated to reflect that NR_MEM_LISTS is gone in 1.3.74
|
||||
- Teac 700 added to list of known drives.
|
||||
- The registered device name is now "ft" rather than "ftape".
|
||||
|
||||
===== Release notes for ftape-2.07a, 14/03/96 =====
|
||||
|
||||
Bugfixes by Marcin Dalecki <dalecki@namu03.gwdg.de>:
|
||||
- In the last release it just compiled against 1.3.70;
|
||||
now the params to request_irq() and free_irq are() are fixed, so it also
|
||||
works in 1.3.73 :-)
|
||||
- Support for modules is now correct for newer kernels.
|
||||
|
||||
===== Release notes for ftape-2.07, 04/03/96 =====
|
||||
|
||||
|
||||
- ftape updated to compile against 1.3.70.
|
||||
- Iomega 700 and Wangtek 3200 recognised.
|
||||
|
||||
|
||||
===== Release notes for ftape-2.06b, 13/02/96 =====
|
||||
|
||||
Another simple bugfix version.
|
||||
|
||||
- Jumbo 700 recognised.
|
||||
- Typo in vendors.h fixed.
|
||||
|
||||
|
||||
===== Release notes for ftape-2.06a, 10/02/96 =====
|
||||
|
||||
This release is a simple bugfix version.
|
||||
|
||||
- Linux/SMP: ftape *should* work.
|
||||
- FC-10/20: Only accepts IRQs 3-7, or 9. If IRQ 9, properly tell the card
|
||||
to use IRQ 2. Thanks to Greg Crider (gcrider@iclnet.org) for finding and
|
||||
locating this bug and testing the patch.
|
||||
- Insight drive recognised correctly again.
|
||||
- Motor-on wakeup version of the Iomega 250 drive added
|
||||
|
||||
|
||||
===== Release notes for ftape-2.06, 28/01/96 =====
|
||||
|
||||
Special thanks go to Neal Friedman and Steven Sorbom for their
|
||||
help in producing and testing this release.
|
||||
|
||||
I have continued to clean up the code, with an eye towards inclusion
|
||||
of ftape in Linus' official kernel (In fact, as I type this, I am
|
||||
running on a kernel with ftape support statically linked). I have
|
||||
test-compiled ftape against my 1.2.13 tree without problems.
|
||||
Hopefully, everything should be OK for the v1.2.x people.
|
||||
|
||||
WARNING! Alan Cox has mailed me that ftape does *NOT* work with
|
||||
Linux/SMP. If you try to run ftape under Linux/SMP, it will cause a
|
||||
kernel deadlock (which is worse than a panic).
|
||||
|
||||
- QIC-3020/TR-3: 1Mbps support works. Neal is capable of reading and
|
||||
writing data to a tape. ftape will automatically detect the type of
|
||||
tape (e.g. TR-3 vs QIC-80) and move the fdc in and out of
|
||||
"perpendicular mode" as necessary.
|
||||
- 2Mbps support is disabled by default, since it is not fully
|
||||
debugged. If you are adventurous, remove -DFDC_82078SL in the
|
||||
Makefile and see what happens :-)
|
||||
- fdc detection: silly bugs removed (Only 2Mbps fdcs were affected)
|
||||
and added detection of the National Semiconductors PC8744 fdc chip
|
||||
(used in the PC873xx "super-IO" chips).
|
||||
- Removed warning about incompatible types when compiling with Linux
|
||||
1.2.x.
|
||||
- README.PCI updated with info about the DELL Dimension XPS P90.
|
||||
- Connor TST3200R added to detected drives.
|
||||
- `swapout' utility added to distribution. It will dirty 5Meg of
|
||||
memory, trying to swap out other programs. Just say `make swapout'
|
||||
to build it. ftape will do this automatically Real Soon Now (ie:
|
||||
when I have found out which kernel memory alloc function to call).
|
||||
|
||||
|
||||
===== Release notes for ftape-2.05, 08/01/96 =====
|
||||
|
||||
- For v1.2.x Kernels, you must apply the patch linux-1.2/ksyms.patch to
|
||||
the kernel and rebuild it (it adds the __get_dma_pages symbol to
|
||||
ksyms.c).
|
||||
- Included new asm-i386/io.h file from v1.3.x kernel series, to enable
|
||||
gcc v.2.7.[12] to compile v1.2.x kernels (linux-1.2/io.h).
|
||||
- Module versions: If you wish to compile ftape as a versioned module,
|
||||
you must first compile your kernel with CONFIG_MODVERSIONS=y.
|
||||
Otherwise, you will get complaints that <linux/modversions.h> does not
|
||||
exist (if that happens, a `touch modversions.h' will help you out).
|
||||
- CLK_48MHZ: new define in the Makefile (default: non-zero). If you have
|
||||
a tape controller card that uses the i82078(-1) chip, but cannot get
|
||||
it to work with ftape, try set it to 0 (and please report this).
|
||||
- QIC-3010/3020: Complete support is still missing, but will hopefully
|
||||
come soon. Steven Sorbom has kindly provided me with hints about
|
||||
this. Writing of QIC-3020 tapes definitely does NOT work (do not try
|
||||
it! - the drive will not be in "perpendicular mode" and this will ruin
|
||||
the formatting info on the tape).
|
||||
- ftape_num_buffers is out of fashion: use NR_BUFFERS instead (and
|
||||
recompile if you want to change it :-).
|
||||
|
||||
|
||||
===== Release notes for ftape-2.04, 01/01/96 =====
|
||||
|
||||
This version by Kai Harrekilde-Petersen <khp@dolphinics.no>
|
||||
|
||||
- ALERT! Support for Kernels earlier then v1.1.85 is about to go away.
|
||||
I intend to clean up some of the code (getting rid of an annoyingly
|
||||
large numbers of #ifdef mostly), which means that support for
|
||||
pre-1.1.85 kernels must go as well.
|
||||
- NR_FTAPE_BUFFERS is gone; You can instead select the number of dma
|
||||
buffers by saying `insmod ftape.o ftape_num_buffer=<n>' instead.
|
||||
- Configure script gone. ftape will now automagically determine your
|
||||
kernel version by /usr/include/linux/version.h instead.
|
||||
- CONFIG_MODVERSIONS now work. All combinations of versioned /
|
||||
unversioned kernel and ftape module works (at least with my 1.3.52
|
||||
kernel).
|
||||
- If you have problems with inserting ftape into an old (1.2.x)
|
||||
kernel (e.g. insmod says "1.2.8 does not match 1.2.8), recompile
|
||||
your modules utilities with your new compiler.
|
||||
- Reveal TB1400 drive added to vendors.h
|
||||
- Support for the i82078-1 (2Mbps) chip is coming along. The
|
||||
biggest problem is that I don't have such a card, which makes
|
||||
testing / debugging somewhat problematic. The second biggest
|
||||
problem is that I do not have the QIC-3010/3020 standards either.
|
||||
Status right now is that the chip is detected, and it should be
|
||||
possible to put it into 2Mbps mode. However, I do not know what
|
||||
"extras" are needed to complete the support. Although putting the
|
||||
i82078 into 1Mbps mode ought to work out of the box, it doesn't
|
||||
(right now, ftape complains about id am errors).
|
||||
|
||||
|
||||
===== Release notes for ftape-2.04beta5, 29/12/95 =====
|
||||
|
||||
Bas offline linux-tape
|
||||
----------------------
|
||||
For reasons only known to the majordomo mail list processor, Bas was
|
||||
kicked off the linux-tape list sometime during the summer. Being
|
||||
overworked at his for-pay job, he didn't notice it much. Instead I
|
||||
(Kai, khp@dolphinics.no) has worked on ftape to produce the 2.04(beta)
|
||||
version.
|
||||
|
||||
zftape
|
||||
------
|
||||
Note that there exists a much improved version of ftape, written by
|
||||
Claus-Justus Heine <claus@willi.math.rwth-aachen.de> which is named
|
||||
zftape, which conforms to the QIC-80 specs on how to mark backups, and
|
||||
is capable of doing automatic compression. However, zftape makes
|
||||
substantial changes to ftape, and I (Kai) have therefore declined to
|
||||
integrate zftape into ftape. Hopefully, this will happen soon.
|
||||
|
||||
CONFIG_QIC117 removed from the kernel
|
||||
-------------------------------------
|
||||
The biggest change of all is that ftape now will allocate its dma
|
||||
buffers when it is inserted. The means that the CONFIG_QIC117 option
|
||||
has disappeared from the Linux kernel as of v1.3.34. If you have an
|
||||
earlier kernel, simply answer 'no' to the question will do the trick
|
||||
(if you get complains about __get_free_pages() missing, contact the
|
||||
linux-tape mailing list).
|
||||
|
||||
Note that ftape-2.04beta will work equally well on kernels with and
|
||||
without `ftape support'. The only catch is, that you will waste
|
||||
around 96-128Kb of precious DMA'able memory on a box that has ftape
|
||||
support compiled in.
|
||||
|
||||
Now for the real changes:
|
||||
|
||||
- FC-20 can now use DMA channels 1, 2, and 3. Thanks to Daniel
|
||||
Cohen, catman@wpi.edu.
|
||||
- ftape no longer requires a (gigantic) 96Kb buffer to be statically
|
||||
allocated by the kernel.
|
||||
- Added new Iomega drive (8882) to vendors.h
|
||||
- -fno-strength-reduce added to Makefile, since GCC is broken.
|
||||
- i82078-1 (2Mbps) FDC support started.
|
||||
|
||||
|
||||
===== Release notes for ftape-2.03b, 27/05/95 =====
|
||||
|
||||
- Prevented verify_area to return error if called with zero length.
|
||||
- Fixed a bug in flush_buffers that caused too much padding to be
|
||||
written when a final segment had bad sectors.
|
||||
- Increased maximum fast-seek overshoot value from 5 to 10 segments.
|
||||
- Breaking loop after 5 retries when positioning fails.
|
||||
- Fixed wrong calculation of tape length for QIC-3010 and QIC-3020
|
||||
tapes (densities were swapped).
|
||||
- Fixed wrong calculation of overshoot on seek_forward: Wrong sign
|
||||
of error.
|
||||
- Suppress (false) error message due to new tape loaded.
|
||||
- Added two new CMS drives (11c3 and 11c5) to vendors.h.
|
||||
|
||||
|
||||
===== Release notes for ftape-2.03a, 09/05/95 =====
|
||||
|
||||
- Fixed display of old error (even if already cleared) in ftape_open.
|
||||
- Improved tape length detection, ioctls would fail for 425 ft tapes.
|
||||
Until the tape length is calculated with data from the header
|
||||
segment, we'll use worst-case values.
|
||||
- Clear eof_mark after rewinding ioctls.
|
||||
- Fixed wrong version message (2.03 had 2.02g id).
|
||||
- Fixed bug that caused the fdc to be reset very frequently.
|
||||
This shouldn't affect normal operation but the timing of the
|
||||
report routines has changed again and that may cause problems.
|
||||
We'll just have to find out....
|
||||
- Implemented correct write precompensation setting for QIC-3010/3020.
|
||||
- Cleaned up fdc_interrupt_wait routine. Hope it still works :-)
|
||||
- Finally removed (already disabled) special eof mark handling for
|
||||
gnu tar.
|
||||
- Changed order of get_dma_residue and disable_dma in fdc-isr.c
|
||||
because the current order would fail on at least one system.
|
||||
We're back to the original order again, hope (and expect) this
|
||||
doesn't break any other system.
|
||||
|
||||
|
||||
===== Release notes for ftape-2.03, 07/05/95 =====
|
||||
|
||||
(Changes refer to the first ftape-2.02 release)
|
||||
|
||||
Support for wide and extended length tapes
|
||||
------------------------------------------
|
||||
The Conner TSM 420 and 850 drives are reported to be working.
|
||||
I haven't received any reports about other brands; the TSM 420
|
||||
and 850 seem to be the most widely used wide drives.
|
||||
Extended length tapes (425 ft) with normal QIC-80 drives
|
||||
are operating too (At least I've had no reports stating otherwise).
|
||||
_Not_ yet completely supported (although they may work) are
|
||||
QIC-3020 drives and 2 Mbps floppy disk controllers won't work at
|
||||
the highest speed.
|
||||
If someone is kind enough to send me one of these, I'll include
|
||||
support for it too ;-)
|
||||
|
||||
Easier configuration
|
||||
--------------------
|
||||
Problems due to wrong settings in the Makefile are prevented
|
||||
by using a configuration script that sets the necessary (kernel
|
||||
version dependent) compile time options.
|
||||
This kernel version is now determined from the sources found
|
||||
at /usr/src/linux, or if not found, the old way using
|
||||
/proc/version.
|
||||
Versioned modules will be used automatically when supported
|
||||
by- and configured in- the kernel.
|
||||
Note that the current modules code (1.1.87) is still broken
|
||||
and _needs_ the fix included in the insmod directory.
|
||||
Please don't send me any more Oops reports caused by insmod :-(
|
||||
|
||||
Reduced module size
|
||||
-------------------
|
||||
The standard module size is much reduced and some compile time
|
||||
options can even reduce it further. (I don't recommend this
|
||||
for normal use but it can be handy for rescue diskettes)
|
||||
|
||||
Option: Approx. module size:
|
||||
|
||||
<standard> 150 Kb
|
||||
NO_TRACE 125 Kb
|
||||
NO_TRACE_AT_ALL 67 Kb
|
||||
|
||||
|
||||
Much improved driver interruption
|
||||
---------------------------------
|
||||
Most possible loops have been broken and signal detection
|
||||
has been improved.
|
||||
In most cases the driver can be aborted by ^C (SIGINT) and
|
||||
SIGKILL (kill -9) will generate be a sure kill.
|
||||
(Note that aborting a tape operation may damage the last
|
||||
data written to tape)
|
||||
|
||||
Improved error recovery
|
||||
-----------------------
|
||||
Ftape now returns an error (ENODATA) to the application if
|
||||
a segment proves to be unrecoverable and then skips the
|
||||
bad segment.
|
||||
This causes most applications to continue to work (tar
|
||||
and afio) loosing only a small amount (up to 29 Kb) of data.
|
||||
Retried read operations will now be done slightly off-track
|
||||
to improve the chance of success. Serious head off-track
|
||||
errors will be detected.
|
||||
|
||||
FC-10 and FC-20 controllers
|
||||
---------------------------
|
||||
Ftape now supports both the old CMS FC-10 and the newer FC-20
|
||||
controllers.
|
||||
Because the operation of these cards is still undocumented,
|
||||
thus far they will only work with the default settings (See
|
||||
Makefile). Any feed-back on how to use them with other settings
|
||||
will be welcome !
|
||||
Compilation will fail if one changes the settings to illegal
|
||||
values.
|
||||
|
||||
Kernels and compilers
|
||||
---------------------
|
||||
Ftape is currently being developed using the 2.5.8 compiler.
|
||||
The older 2.4.5 probably works too (Set option in Makefile!).
|
||||
I have no experience with any later compilers nor Elf support.
|
||||
Any information on this is welcome.
|
||||
The latest kernel I have tested ftape with is 1.2.6.
|
||||
|
||||
Compression
|
||||
-----------
|
||||
An impressive collection of changes for ftape including
|
||||
on-the-fly compression is still lying on my desk.
|
||||
If 2.03 proves to be reliable I might start integrating these
|
||||
but as usual, I'm short in time :-(
|
||||
|
||||
Formatting
|
||||
----------
|
||||
There is still no way to format tapes under Linux. As far as
|
||||
I know all attempts to write such a program have died now.
|
||||
Since formatted tapes are rather common now, I think all we
|
||||
need is a utility that writes a worst case pattern and verifies
|
||||
that with the drive put in verify mode, reducing margins.
|
||||
Any takers ?
|
||||
|
||||
Furthermore
|
||||
-----------
|
||||
Cleaned up messages.
|
||||
Prepared to support multiple tape drives on one fdc.
|
||||
Thanks to all the people who sent bug reports and helped me
|
||||
improve the driver. Without trying to be complete I'll mention
|
||||
Gary Anderson (without his accurate reports and unreliable
|
||||
hardware there wouldn't be a 2.03), Stefan Kneifel (FC-20),
|
||||
Robert Broughton (FC-20, you were almost there ;-), Bjorn
|
||||
Ekwall (for the versioned modules and buggy insmod ;-), Peter
|
||||
Fox, Christopher Oliver, Ralph Whittaker and not the least
|
||||
Linus Torvalds (for Linux and keeping me busy because of
|
||||
changes to the kernel ;-)
|
||||
Thanks to anyone I forgot, for the bug reports, the ftape
|
||||
bashing and the mental support...
|
||||
|
||||
|
||||
That's it for now. Have Fun,
|
||||
|
||||
Bas.
|
||||
|
||||
|
||||
===== Release notes for ftape-2.02g, 06/05/95 =====
|
||||
|
||||
- Added extra test to break read-id loop with signal.
|
||||
- Changed rewind code to handle negative overshoot for drives
|
||||
that take very long to start or stop.
|
||||
- Let use of get/set i/o-regions depend on kernel version.
|
||||
- Changed code to use a more general test for conditional
|
||||
compilations depending on kernel version.
|
||||
- Improved micro-step functionality to go off-track only
|
||||
while reading (id & data).
|
||||
- Added failure on tape-not-referenced bit in ftape_command.
|
||||
- Added FOREVER option to read-wait routine.
|
||||
- Changed read-id to use shorter timeout causing smaller
|
||||
rewinds on timeout.
|
||||
- Made kernel-interface functions static.
|
||||
|
||||
|
||||
===== Release notes for ftape-2.02f, 03/05/95 =====
|
||||
|
||||
- Added support for dual tape drives on my system, extended Configure
|
||||
script to detect host 'dodo'.
|
||||
- Log media defect in history if ecc failed and no data was returned.
|
||||
- Fixed Configure script that was failing for kernel versions with
|
||||
double digit version or revision numbers.
|
||||
|
||||
|
||||
===== Release notes for ftape-2.02e, 01/05/95 =====
|
||||
|
||||
- Fixed reposition loop at logical eot (failing read_id).
|
||||
- Fixed 34 segment offset when rewinding.
|
||||
- Added fast seek capability for more than 255 segments.
|
||||
- Fixed wrong busy result from ftape_command causing reverse
|
||||
seek to fail.
|
||||
- Added breakout from infinite rewind loop (if something fails).
|
||||
|
||||
|
||||
===== Release notes for ftape-2.02d, 30/04/95 =====
|
||||
|
||||
- Improved abortion on signals: Interrupt will make a graceful
|
||||
exit, Kill will be less nice and should be used if everything
|
||||
else fails.
|
||||
- Included check for tape-head off track.
|
||||
- Implemented exit from tape-start loop.
|
||||
- Added kernel io-port registration.
|
||||
- Implemented skip of failing segment (ENODATA) on ecc failure.
|
||||
This allows afio and tar to continue when the tape is damaged.
|
||||
- Made distinction between drive names with different codes.
|
||||
|
||||
|
||||
===== Release notes for ftape-2.02c, 22/04/95 =====
|
||||
|
||||
- Fixed too tight command queueing after tape stop/pause command
|
||||
issued from within interrupt service routine (Showed as timeout
|
||||
on Acknowledge errors during retries on some systems)
|
||||
- Tried to fix timeouts when using 425 ft tape because the extended
|
||||
length doesn't seem to be detected by the hardware.
|
||||
We now use the format code from the header segment so adjust the
|
||||
timing after reading the header segment.
|
||||
- Fixed some messages stating 'unexpected something...' being not
|
||||
unexpected anymore.
|
||||
- Started preparations for merge of dynamic buffer allocation and
|
||||
compression code.
|
||||
- Changed some debug messages to include relevant segment information
|
||||
at level 4.
|
||||
- Included early bail-out when drive offline, preventing a lot of
|
||||
false messages.
|
||||
- Moved ftape_parameter_xxx() offsets into function instead of in calls.
|
||||
- Removed 'weird, drive busy but no data' error when caused by
|
||||
an error during a read-id.
|
||||
- Improved 'timeout on acknowledge' diagnostics.
|
||||
- Moved MODULE option into Configure.
|
||||
- Reduced code size when no tracing at all was set (Claus Heine).
|
||||
- No longer log error code 0 (no error) as an error.
|
||||
|
||||
|
||||
===== Release notes for ftape-2.02b, 09/04/95 =====
|
||||
|
||||
- Relaxed timing for status operation and displaying
|
||||
abnormal results. Hopefully this shows what's going
|
||||
wrong with the Conner TSM850R drives.
|
||||
- Created script for configuration, using version number
|
||||
of kernel source if available, otherwise /proc/version.
|
||||
- Fixed conditionals in kernel-interface.c.
|
||||
- Removed unavoidable TRACE output.
|
||||
|
||||
|
||||
===== Release notes for ftape-2.02a, 01/04/95 =====
|
||||
|
||||
- Implemented `new-style' (versioned) modules support for new
|
||||
kernels.
|
||||
- Reduced size of module by moving static data to bss.
|
||||
- Now using version number of kernel source instead of running
|
||||
kernel for kernel versions >= 1.1.82
|
||||
- Added feedback on drive speeds to vendor information.
|
||||
- Included fixed insmod sources to distribution (Let's hope
|
||||
the modules distribution get fixed soon :-/).
|
||||
|
||||
Note that I haven't yet implemented any of the code extension I
|
||||
received. I hope to find some time to do this soon.
|
||||
|
||||
|
||||
===== Release notes for ftape-2.02, 15/01/95 =====
|
||||
|
||||
|
||||
- Fixed failing repositioning when overshoot was incremented.
|
||||
- Fixed rate selection: Because of a deficiency in the QIC-117
|
||||
specification one cannot distinguish between a not implemented
|
||||
and a failing command. Therefor we now try to find out if the
|
||||
drive does support this command before usage.
|
||||
- Fixed error retry using wrong offset in fdc-isr.
|
||||
- Improved retry code to retry only once on a single no-data
|
||||
error in a segment.
|
||||
- Validate sector number extracted from eof mark because an
|
||||
invalid file mark (due to ???) could cause kernel panic.
|
||||
- Split ftape-io.c into ftape-io.c and ftape-ctl.c files.
|
||||
- Corrected too high media error count after writing to
|
||||
a bad tape.
|
||||
- Added #include <asm/segment.h> again because old kernel versions
|
||||
need it.
|
||||
- Fixed fdc not being disabled when open failed because no tape
|
||||
drive was found.
|
||||
- Fixed problem with soft error in sector 32 (shift operator with
|
||||
shiftcount 32 is not defined).
|
||||
|
||||
|
||||
===== Release notes for ftape-2.01, 08/01/95 =====
|
||||
|
||||
|
||||
- Removed TESTING setting from distributed Makefile.
|
||||
- Fixed `mt asf' failure: Rewind was deferred to close which
|
||||
overruled the fsf ioctl.
|
||||
- Prevented non-interruptible commands being interrupted.
|
||||
- Added missing timeout.pause setting.
|
||||
- Maximum tape speed read from drive type information table.
|
||||
If the information is not in the table (0) the drive will
|
||||
determine the speed itself and put a message in the logfile.
|
||||
This information should then be added to the table in the
|
||||
vendors.h file (and reported to me).
|
||||
- Added call to ftape_init_drive after soft reset for those
|
||||
(antique) drives that don't do an implicit seek_load_point
|
||||
after a reset or power up.
|
||||
- Don't try to set data rate if reset failed.
|
||||
- Prevent update of seek variables when starting from the
|
||||
beginning or the end of the tape.
|
||||
- Fixed wrong adjustment of overshoot in seek_forward().
|
||||
- Added sync to Makefile (again).
|
||||
- Added code to diagnose timer problems (calibr.c).
|
||||
- Replaced time differences by timediff calls.
|
||||
- Removed reference to do_floppy from object for recent kernels.
|
||||
- Fixed wrong display of 'failing dma controller' message.
|
||||
- Removed various no longer used #include statements.
|
||||
- Added max. tape speed value to vendor-struct.
|
||||
- Changed ftape-command to check pre-conditions and wait
|
||||
if needed.
|
||||
- Further updated qic117.h to rev G.
|
||||
- Combined command name table and restrictions table to one.
|
||||
Extended this table with some new fields.
|
||||
- Increased timeout on Ack timer value and included code to
|
||||
report out of spec behaviour.
|
||||
- Increased rewind timeout margin to calculated + 20%.
|
||||
- Improved data rate selection so it won't fail on some
|
||||
older (pre standard) drives.
|
||||
- Changed initialisation code so drive will be rewound if the
|
||||
driver is reloaded and the tape is not at bot.
|
||||
- Moved some of the flush operations from close to the ioctls.
|
||||
- Added exit code value to failing verify area message.
|
||||
- Loop until tape halted in smart-stop.
|
||||
- Fast seek handled specially if located at bot or eot.
|
||||
- Being more conservative on overshoot value.
|
||||
|
||||
|
||||
===== Release notes for ftape-2.00, 31/12/94 =====
|
||||
|
||||
The Install-guide is completely rewritten and now also includes
|
||||
some information on how to use the driver. If you're either new
|
||||
to ftape or new to Unix tape devices make sure to read it !
|
||||
|
||||
If you own a pci system and experience problems with the
|
||||
ftape driver make sure to read the README.PCI file. It contains
|
||||
some hints on how to fix your hardware.
|
||||
|
||||
For anybody who hasn't noticed: The version number of the
|
||||
driver has been incremented (The latest released version has
|
||||
been version 1.14d).
|
||||
This has been done for two major reasons:
|
||||
|
||||
o A new (better) error recovery scheme is implemented.
|
||||
o Support for new drive types has been added.
|
||||
|
||||
All these improvements/changes will probably include a couple
|
||||
of new (and old?) bugs. If you encounter any problems that you think
|
||||
I'm not yet aware of, feel free to send a report to <bas@vimec.nl>.
|
||||
I recommend keeping a version of ftape-1.14d available, just
|
||||
in case ;-)
|
||||
|
||||
This version should work with all kernel versions from 1.0.9 up
|
||||
to 1.1.72 (and probably earlier and later versions too).
|
||||
|
||||
|
||||
Major new features:
|
||||
|
||||
- Better handling of tapes with defects: When a sector repeatedly
|
||||
(SOFT_RETRIES in ftape.h) cannot be written to or read from it is
|
||||
marked as an hard error and gets skipped.
|
||||
The error correction code can handle up to three of these hard
|
||||
errors provided there are no other errors in that segment (32 Kb).
|
||||
|
||||
- Allows writing to tapes with defects (although the risk of loosing
|
||||
data increases !)
|
||||
Look for the media-defects entry printed with the statistics when
|
||||
the tape is closed. A non-zero value here shows a bad tape.
|
||||
[the actual count is wrong (too high), this is a known bug].
|
||||
|
||||
- Use of backup header segment if first one is failing.
|
||||
|
||||
- Support for extended length tapes with QIC-80: both 425 and 1100 ft.
|
||||
0.25 inch tapes are now recognized and handled.
|
||||
|
||||
- Support for new QIC-80 drives with 8 mm `wide' tapes (e.g. Conner
|
||||
TSM 420).
|
||||
|
||||
- Support for new QIC-3010 and QIC-3020 drives (experimental) with
|
||||
both 0.25 inch and 8 mm tapes.
|
||||
|
||||
Some minor features were added, a couple of small bugs were fixed and
|
||||
probably some new ones introduced ;-).
|
||||
|
||||
[lseek() didn't make it into this version]
|
||||
|
||||
Have fun,
|
||||
|
||||
Bas.
|
||||
----
|
||||
LocalWords: ftape MCONFIG mt VFS zftape resp sftape proc subdir MTIOCVOLINFO
|
||||
LocalWords: MTIOCGETSIZE BOT EOD MTBSF zft kerneld modprobe kdtime contrib TR
|
||||
LocalWords: MTSETBLK afio uninstall texi www EIO QIC init sft eof aka dma GB
|
||||
LocalWords: SIGKILL MTIOCFTCMD mmap Iomega FDC fdc io gnumt mtio fc asm inb
|
||||
LocalWords: outb ft qic frontend TeXinfo irq mach MODVERSIONS CONFIG html dvi
|
||||
LocalWords: usr doc SMP Mb Dunno FIXME vtblc perl listtape volinfo fsf MTWEOF
|
||||
LocalWords: amanda degaussed ComByte DoublePlay whraven njackn com MTIOC vtbl
|
||||
LocalWords: GETBLKSZ MAKEDEV zftape's linux dif CVS Revison cp MTREW MTOFFL
|
||||
LocalWords: MTFSF BSF Marcin Dalecki GCC Config cpio swapout Kai Harrekilde
|
||||
LocalWords: Pederson khp dolphinics Justus claus momo rwth aachen Laarhoven
|
@ -1,31 +0,0 @@
|
||||
#
|
||||
# Copyright (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/ftape/compressor/Makefile,v $
|
||||
# $Revision: 1.1 $
|
||||
# $Date: 1997/10/05 19:12:28 $
|
||||
#
|
||||
# Makefile for the optional compressor for th zftape VFS
|
||||
# interface to the QIC-40/80/3010/3020 floppy-tape driver for
|
||||
# Linux.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_ZFT_COMPRESSOR) += zft-compressor.o
|
||||
|
||||
zft-compressor-objs := zftape-compress.o lzrw3.o
|
||||
|
||||
CFLAGS_lzrw3.o := -O6 -funroll-all-loops
|
@ -1,743 +0,0 @@
|
||||
/*
|
||||
* $Source: /homes/cvs/ftape-stacked/ftape/compressor/lzrw3.c,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 1997/10/05 19:12:29 $
|
||||
*
|
||||
* Implementation of Ross Williams lzrw3 algorithm. Adaption for zftape.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../compressor/lzrw3.h" /* Defines single exported function "compress". */
|
||||
|
||||
/******************************************************************************/
|
||||
/* */
|
||||
/* LZRW3.C */
|
||||
/* */
|
||||
/******************************************************************************/
|
||||
/* */
|
||||
/* Author : Ross Williams. */
|
||||
/* Date : 30-Jun-1991. */
|
||||
/* Release : 1. */
|
||||
/* */
|
||||
/******************************************************************************/
|
||||
/* */
|
||||
/* This file contains an implementation of the LZRW3 data compression */
|
||||
/* algorithm in C. */
|
||||
/* */
|
||||
/* The algorithm is a general purpose compression algorithm that runs fast */
|
||||
/* and gives reasonable compression. The algorithm is a member of the Lempel */
|
||||
/* Ziv family of algorithms and bases its compression on the presence in the */
|
||||
/* data of repeated substrings. */
|
||||
/* */
|
||||
/* This algorithm is unpatented and the code is public domain. As the */
|
||||
/* algorithm is based on the LZ77 class of algorithms, it is unlikely to be */
|
||||
/* the subject of a patent challenge. */
|
||||
/* */
|
||||
/* Unlike the LZRW1 and LZRW1-A algorithms, the LZRW3 algorithm is */
|
||||
/* deterministic and is guaranteed to yield the same compressed */
|
||||
/* representation for a given file each time it is run. */
|
||||
/* */
|
||||
/* The LZRW3 algorithm was originally designed and implemented */
|
||||
/* by Ross Williams on 31-Dec-1990. */
|
||||
/* */
|
||||
/* Here are the results of applying this code, compiled under THINK C 4.0 */
|
||||
/* and running on a Mac-SE (8MHz 68000), to the standard calgary corpus. */
|
||||
/* */
|
||||
/* +----------------------------------------------------------------+ */
|
||||
/* | DATA COMPRESSION TEST | */
|
||||
/* | ===================== | */
|
||||
/* | Time of run : Sun 30-Jun-1991 09:31PM | */
|
||||
/* | Timing accuracy : One part in 100 | */
|
||||
/* | Context length : 262144 bytes (= 256.0000K) | */
|
||||
/* | Test suite : Calgary Corpus Suite | */
|
||||
/* | Files in suite : 14 | */
|
||||
/* | Algorithm : LZRW3 | */
|
||||
/* | Note: All averages are calculated from the un-rounded values. | */
|
||||
/* +----------------------------------------------------------------+ */
|
||||
/* | File Name Length CxB ComLen %Remn Bits Com K/s Dec K/s | */
|
||||
/* | ---------- ------ --- ------ ----- ---- ------- ------- | */
|
||||
/* | rpus:Bib.D 111261 1 55033 49.5 3.96 19.46 32.27 | */
|
||||
/* | us:Book1.D 768771 3 467962 60.9 4.87 17.03 31.07 | */
|
||||
/* | us:Book2.D 610856 3 317102 51.9 4.15 19.39 34.15 | */
|
||||
/* | rpus:Geo.D 102400 1 82424 80.5 6.44 11.65 18.18 | */
|
||||
/* | pus:News.D 377109 2 205670 54.5 4.36 17.14 27.47 | */
|
||||
/* | pus:Obj1.D 21504 1 13027 60.6 4.85 13.40 18.95 | */
|
||||
/* | pus:Obj2.D 246814 1 116286 47.1 3.77 19.31 30.10 | */
|
||||
/* | s:Paper1.D 53161 1 27522 51.8 4.14 18.60 31.15 | */
|
||||
/* | s:Paper2.D 82199 1 45160 54.9 4.40 18.45 32.84 | */
|
||||
/* | rpus:Pic.D 513216 2 122388 23.8 1.91 35.29 51.05 | */
|
||||
/* | us:Progc.D 39611 1 19669 49.7 3.97 18.87 30.64 | */
|
||||
/* | us:Progl.D 71646 1 28247 39.4 3.15 24.34 40.66 | */
|
||||
/* | us:Progp.D 49379 1 19377 39.2 3.14 23.91 39.23 | */
|
||||
/* | us:Trans.D 93695 1 33481 35.7 2.86 25.48 40.37 | */
|
||||
/* +----------------------------------------------------------------+ */
|
||||
/* | Average 224401 1 110953 50.0 4.00 20.17 32.72 | */
|
||||
/* +----------------------------------------------------------------+ */
|
||||
/* */
|
||||
/******************************************************************************/
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/* The following structure is returned by the "compress" function below when */
|
||||
/* the user asks the function to return identifying information. */
|
||||
/* The most important field in the record is the working memory field which */
|
||||
/* tells the calling program how much working memory should be passed to */
|
||||
/* "compress" when it is called to perform a compression or decompression. */
|
||||
/* LZRW3 uses the same amount of memory during compression and decompression. */
|
||||
/* For more information on this structure see "compress.h". */
|
||||
|
||||
#define U(X) ((ULONG) X)
|
||||
#define SIZE_P_BYTE (U(sizeof(UBYTE *)))
|
||||
#define SIZE_WORD (U(sizeof(UWORD )))
|
||||
#define ALIGNMENT_FUDGE (U(16))
|
||||
#define MEM_REQ ( U(4096)*(SIZE_P_BYTE) + ALIGNMENT_FUDGE )
|
||||
|
||||
static struct compress_identity identity =
|
||||
{
|
||||
U(0x032DDEA8), /* Algorithm identification number. */
|
||||
MEM_REQ, /* Working memory (bytes) required. */
|
||||
"LZRW3", /* Name of algorithm. */
|
||||
"1.0", /* Version number of algorithm. */
|
||||
"31-Dec-1990", /* Date of algorithm. */
|
||||
"Public Domain", /* Copyright notice. */
|
||||
"Ross N. Williams", /* Author of algorithm. */
|
||||
"Renaissance Software", /* Affiliation of author. */
|
||||
"Public Domain" /* Vendor of algorithm. */
|
||||
};
|
||||
|
||||
LOCAL void compress_compress (UBYTE *,UBYTE *,ULONG,UBYTE *, LONG *);
|
||||
LOCAL void compress_decompress(UBYTE *,UBYTE *,LONG, UBYTE *, ULONG *);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/* This function is the only function exported by this module. */
|
||||
/* Depending on its first parameter, the function can be requested to */
|
||||
/* compress a block of memory, decompress a block of memory, or to identify */
|
||||
/* itself. For more information, see the specification file "compress.h". */
|
||||
|
||||
EXPORT void lzrw3_compress(
|
||||
UWORD action, /* Action to be performed. */
|
||||
UBYTE *wrk_mem, /* Address of working memory we can use.*/
|
||||
UBYTE *src_adr, /* Address of input data. */
|
||||
LONG src_len, /* Length of input data. */
|
||||
UBYTE *dst_adr, /* Address to put output data. */
|
||||
void *p_dst_len /* Address of longword for length of output data.*/
|
||||
)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case COMPRESS_ACTION_IDENTITY:
|
||||
*((struct compress_identity **)p_dst_len)= &identity;
|
||||
break;
|
||||
case COMPRESS_ACTION_COMPRESS:
|
||||
compress_compress(wrk_mem,src_adr,src_len,dst_adr,(LONG *)p_dst_len);
|
||||
break;
|
||||
case COMPRESS_ACTION_DECOMPRESS:
|
||||
compress_decompress(wrk_mem,src_adr,src_len,dst_adr,(LONG *)p_dst_len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* */
|
||||
/* BRIEF DESCRIPTION OF THE LZRW3 ALGORITHM */
|
||||
/* ======================================== */
|
||||
/* The LZRW3 algorithm is identical to the LZRW1-A algorithm except that */
|
||||
/* instead of transmitting history offsets, it transmits hash table indexes. */
|
||||
/* In order to decode the indexes, the decompressor must maintain an */
|
||||
/* identical hash table. Copy items are straightforward:when the decompressor */
|
||||
/* receives a copy item, it simply looks up the hash table to translate the */
|
||||
/* index into a pointer into the data already decompressed. To update the */
|
||||
/* hash table, it replaces the same table entry with a pointer to the start */
|
||||
/* of the newly decoded phrase. The tricky part is with literal items, for at */
|
||||
/* the time that the decompressor receives a literal item the decompressor */
|
||||
/* does not have the three bytes in the Ziv (that the compressor has) to */
|
||||
/* perform the three-byte hash. To solve this problem, in LZRW3, both the */
|
||||
/* compressor and decompressor are wired up so that they "buffer" these */
|
||||
/* literals and update their hash tables only when three bytes are available. */
|
||||
/* This makes the maximum buffering 2 bytes. */
|
||||
/* */
|
||||
/* Replacement of offsets by hash table indexes yields a few percent extra */
|
||||
/* compression at the cost of some speed. LZRW3 is slower than LZRW1, LZRW1-A */
|
||||
/* and LZRW2, but yields better compression. */
|
||||
/* */
|
||||
/* Extra compression could be obtained by using a hash table of depth two. */
|
||||
/* However, increasing the depth above one incurs a significant decrease in */
|
||||
/* compression speed which was not considered worthwhile. Another reason for */
|
||||
/* keeping the depth down to one was to allow easy comparison with the */
|
||||
/* LZRW1-A and LZRW2 algorithms so as to demonstrate the exact effect of the */
|
||||
/* use of direct hash indexes. */
|
||||
/* */
|
||||
/* +---+ */
|
||||
/* |___|4095 */
|
||||
/* |___| */
|
||||
/* +---------------------*_|<---+ /----+---\ */
|
||||
/* | |___| +---|Hash | */
|
||||
/* | |___| |Function| */
|
||||
/* | |___| \--------/ */
|
||||
/* | |___|0 ^ */
|
||||
/* | +---+ | */
|
||||
/* | Hash +-----+ */
|
||||
/* | Table | */
|
||||
/* | --- */
|
||||
/* v ^^^ */
|
||||
/* +-------------------------------------|----------------+ */
|
||||
/* |||||||||||||||||||||||||||||||||||||||||||||||||||||||| */
|
||||
/* +-------------------------------------|----------------+ */
|
||||
/* | |1......18| | */
|
||||
/* |<------- Lempel=History ------------>|<--Ziv-->| | */
|
||||
/* | (=bytes already processed) |<-Still to go-->| */
|
||||
/* |<-------------------- INPUT BLOCK ------------------->| */
|
||||
/* */
|
||||
/* The diagram above for LZRW3 looks almost identical to the diagram for */
|
||||
/* LZRW1. The difference is that in LZRW3, the compressor transmits hash */
|
||||
/* table indices instead of Lempel offsets. For this to work, the */
|
||||
/* decompressor must maintain a hash table as well as the compressor and both */
|
||||
/* compressor and decompressor must "buffer" literals, as the decompressor */
|
||||
/* cannot hash phrases commencing with a literal until another two bytes have */
|
||||
/* arrived. */
|
||||
/* */
|
||||
/* LZRW3 Algorithm Execution Summary */
|
||||
/* --------------------------------- */
|
||||
/* 1. Hash the first three bytes of the Ziv to yield a hash table index h. */
|
||||
/* 2. Look up the hash table yielding history pointer p. */
|
||||
/* 3. Match where p points with the Ziv. If there is a match of three or */
|
||||
/* more bytes, code those bytes (in the Ziv) as a copy item, otherwise */
|
||||
/* code the next byte in the Ziv as a literal item. */
|
||||
/* 4. Update the hash table as possible subject to the constraint that only */
|
||||
/* phrases commencing three bytes back from the Ziv can be hashed and */
|
||||
/* entered into the hash table. (This enables the decompressor to keep */
|
||||
/* pace). See the description and code for more details. */
|
||||
/* */
|
||||
/******************************************************************************/
|
||||
/* */
|
||||
/* DEFINITION OF COMPRESSED FILE FORMAT */
|
||||
/* ==================================== */
|
||||
/* * A compressed file consists of a COPY FLAG followed by a REMAINDER. */
|
||||
/* * The copy flag CF uses up four bytes with the first byte being the */
|
||||
/* least significant. */
|
||||
/* * If CF=1, then the compressed file represents the remainder of the file */
|
||||
/* exactly. Otherwise CF=0 and the remainder of the file consists of zero */
|
||||
/* or more GROUPS, each of which represents one or more bytes. */
|
||||
/* * Each group consists of two bytes of CONTROL information followed by */
|
||||
/* sixteen ITEMs except for the last group which can contain from one */
|
||||
/* to sixteen items. */
|
||||
/* * An item can be either a LITERAL item or a COPY item. */
|
||||
/* * Each item corresponds to a bit in the control bytes. */
|
||||
/* * The first control byte corresponds to the first 8 items in the group */
|
||||
/* with bit 0 corresponding to the first item in the group and bit 7 to */
|
||||
/* the eighth item in the group. */
|
||||
/* * The second control byte corresponds to the second 8 items in the group */
|
||||
/* with bit 0 corresponding to the ninth item in the group and bit 7 to */
|
||||
/* the sixteenth item in the group. */
|
||||
/* * A zero bit in a control word means that the corresponding item is a */
|
||||
/* literal item. A one bit corresponds to a copy item. */
|
||||
/* * A literal item consists of a single byte which represents itself. */
|
||||
/* * A copy item consists of two bytes that represent from 3 to 18 bytes. */
|
||||
/* * The first byte in a copy item will be denoted C1. */
|
||||
/* * The second byte in a copy item will be denoted C2. */
|
||||
/* * Bits will be selected using square brackets. */
|
||||
/* For example: C1[0..3] is the low nibble of the first control byte. */
|
||||
/* of copy item C1. */
|
||||
/* * The LENGTH of a copy item is defined to be C1[0..3]+3 which is a number */
|
||||
/* in the range [3,18]. */
|
||||
/* * The INDEX of a copy item is defined to be C1[4..7]*256+C2[0..8] which */
|
||||
/* is a number in the range [0,4095]. */
|
||||
/* * A copy item represents the sequence of bytes */
|
||||
/* text[POS-OFFSET..POS-OFFSET+LENGTH-1] where */
|
||||
/* text is the entire text of the uncompressed string. */
|
||||
/* POS is the index in the text of the character following the */
|
||||
/* string represented by all the items preceeding the item */
|
||||
/* being defined. */
|
||||
/* OFFSET is obtained from INDEX by looking up the hash table. */
|
||||
/* */
|
||||
/******************************************************************************/
|
||||
|
||||
/* The following #define defines the length of the copy flag that appears at */
|
||||
/* the start of the compressed file. The value of four bytes was chosen */
|
||||
/* because the fast_copy routine on my Macintosh runs faster if the source */
|
||||
/* and destination blocks are relatively longword aligned. */
|
||||
/* The actual flag data appears in the first byte. The rest are zeroed so as */
|
||||
/* to normalize the compressed representation (i.e. not non-deterministic). */
|
||||
#define FLAG_BYTES 4
|
||||
|
||||
/* The following #defines define the meaning of the values of the copy */
|
||||
/* flag at the start of the compressed file. */
|
||||
#define FLAG_COMPRESS 0 /* Signals that output was result of compression. */
|
||||
#define FLAG_COPY 1 /* Signals that output was simply copied over. */
|
||||
|
||||
/* The 68000 microprocessor (on which this algorithm was originally developed */
|
||||
/* is fussy about non-aligned arrays of words. To avoid these problems the */
|
||||
/* following macro can be used to "waste" from 0 to 3 bytes so as to align */
|
||||
/* the argument pointer. */
|
||||
#define ULONG_ALIGN_UP(X) ((((ULONG)X)+sizeof(ULONG)-1)&~(sizeof(ULONG)-1))
|
||||
|
||||
|
||||
/* The following constant defines the maximum length of an uncompressed item. */
|
||||
/* This definition must not be changed; its value is hardwired into the code. */
|
||||
/* The longest number of bytes that can be spanned by a single item is 18 */
|
||||
/* for the longest copy item. */
|
||||
#define MAX_RAW_ITEM (18)
|
||||
|
||||
/* The following constant defines the maximum length of an uncompressed group.*/
|
||||
/* This definition must not be changed; its value is hardwired into the code. */
|
||||
/* A group contains at most 16 items which explains this definition. */
|
||||
#define MAX_RAW_GROUP (16*MAX_RAW_ITEM)
|
||||
|
||||
/* The following constant defines the maximum length of a compressed group. */
|
||||
/* This definition must not be changed; its value is hardwired into the code. */
|
||||
/* A compressed group consists of two control bytes followed by up to 16 */
|
||||
/* compressed items each of which can have a maximum length of two bytes. */
|
||||
#define MAX_CMP_GROUP (2+16*2)
|
||||
|
||||
/* The following constant defines the number of entries in the hash table. */
|
||||
/* This definition must not be changed; its value is hardwired into the code. */
|
||||
#define HASH_TABLE_LENGTH (4096)
|
||||
|
||||
/* LZRW3, unlike LZRW1(-A), must initialize its hash table so as to enable */
|
||||
/* the compressor and decompressor to stay in step maintaining identical hash */
|
||||
/* tables. In an early version of the algorithm, the tables were simply */
|
||||
/* initialized to zero and a check for zero was included just before the */
|
||||
/* matching code. However, this test costs time. A better solution is to */
|
||||
/* initialize all the entries in the hash table to point to a constant */
|
||||
/* string. The decompressor does the same. This solution requires no extra */
|
||||
/* test. The contents of the string do not matter so long as the string is */
|
||||
/* the same for the compressor and decompressor and contains at least */
|
||||
/* MAX_RAW_ITEM bytes. I chose consecutive decimal digits because they do not */
|
||||
/* have white space problems (e.g. there is no chance that the compiler will */
|
||||
/* replace more than one space by a TAB) and because they make the length of */
|
||||
/* the string obvious by inspection. */
|
||||
#define START_STRING_18 ((UBYTE *) "123456789012345678")
|
||||
|
||||
/* In this algorithm, hash values have to be calculated at more than one */
|
||||
/* point. The following macro neatens the code up for this. */
|
||||
#define HASH(PTR) \
|
||||
(((40543*(((*(PTR))<<8)^((*((PTR)+1))<<4)^(*((PTR)+2))))>>4) & 0xFFF)
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/* Input : Hand over the required amount of working memory in p_wrk_mem. */
|
||||
/* Input : Specify input block using p_src_first and src_len. */
|
||||
/* Input : Point p_dst_first to the start of the output zone (OZ). */
|
||||
/* Input : Point p_dst_len to a ULONG to receive the output length. */
|
||||
/* Input : Input block and output zone must not overlap. */
|
||||
/* Output : Length of output block written to *p_dst_len. */
|
||||
/* Output : Output block in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. May */
|
||||
/* Output : write in OZ=Mem[p_dst_first..p_dst_first+src_len+MAX_CMP_GROUP-1].*/
|
||||
/* Output : Upon completion guaranteed *p_dst_len<=src_len+FLAG_BYTES. */
|
||||
LOCAL void compress_compress(UBYTE *p_wrk_mem,
|
||||
UBYTE *p_src_first, ULONG src_len,
|
||||
UBYTE *p_dst_first, LONG *p_dst_len)
|
||||
{
|
||||
/* p_src and p_dst step through the source and destination blocks. */
|
||||
register UBYTE *p_src = p_src_first;
|
||||
register UBYTE *p_dst = p_dst_first;
|
||||
|
||||
/* The following variables are never modified and are used in the */
|
||||
/* calculations that determine when the main loop terminates. */
|
||||
UBYTE *p_src_post = p_src_first+src_len;
|
||||
UBYTE *p_dst_post = p_dst_first+src_len;
|
||||
UBYTE *p_src_max1 = p_src_first+src_len-MAX_RAW_ITEM;
|
||||
UBYTE *p_src_max16 = p_src_first+src_len-MAX_RAW_ITEM*16;
|
||||
|
||||
/* The variables 'p_control' and 'control' are used to buffer control bits. */
|
||||
/* Before each group is processed, the next two bytes of the output block */
|
||||
/* are set aside for the control word for the group about to be processed. */
|
||||
/* 'p_control' is set to point to the first byte of that word. Meanwhile, */
|
||||
/* 'control' buffers the control bits being generated during the processing */
|
||||
/* of the group. Instead of having a counter to keep track of how many items */
|
||||
/* have been processed (=the number of bits in the control word), at the */
|
||||
/* start of each group, the top word of 'control' is filled with 1 bits. */
|
||||
/* As 'control' is shifted for each item, the 1 bits in the top word are */
|
||||
/* absorbed or destroyed. When they all run out (i.e. when the top word is */
|
||||
/* all zero bits, we know that we are at the end of a group. */
|
||||
# define TOPWORD 0xFFFF0000
|
||||
UBYTE *p_control;
|
||||
register ULONG control=TOPWORD;
|
||||
|
||||
/* THe variable 'hash' always points to the first element of the hash table. */
|
||||
UBYTE **hash= (UBYTE **) ULONG_ALIGN_UP(p_wrk_mem);
|
||||
|
||||
/* The following two variables represent the literal buffer. p_h1 points to */
|
||||
/* the hash table entry corresponding to the youngest literal. p_h2 points */
|
||||
/* to the hash table entry corresponding to the second youngest literal. */
|
||||
/* Note: p_h1=0=>p_h2=0 because zero values denote absence of a pending */
|
||||
/* literal. The variables are initialized to zero meaning an empty "buffer". */
|
||||
UBYTE **p_h1=NULL;
|
||||
UBYTE **p_h2=NULL;
|
||||
|
||||
/* To start, we write the flag bytes. Being optimistic, we set the flag to */
|
||||
/* FLAG_COMPRESS. The remaining flag bytes are zeroed so as to keep the */
|
||||
/* algorithm deterministic. */
|
||||
*p_dst++=FLAG_COMPRESS;
|
||||
{UWORD i; for (i=2;i<=FLAG_BYTES;i++) *p_dst++=0;}
|
||||
|
||||
/* Reserve the first word of output as the control word for the first group. */
|
||||
/* Note: This is undone at the end if the input block is empty. */
|
||||
p_control=p_dst; p_dst+=2;
|
||||
|
||||
/* Initialize all elements of the hash table to point to a constant string. */
|
||||
/* Use of an unrolled loop speeds this up considerably. */
|
||||
{UWORD i; UBYTE **p_h=hash;
|
||||
# define ZH *p_h++=START_STRING_18
|
||||
for (i=0;i<256;i++) /* 256=HASH_TABLE_LENGTH/16. */
|
||||
{ZH;ZH;ZH;ZH;
|
||||
ZH;ZH;ZH;ZH;
|
||||
ZH;ZH;ZH;ZH;
|
||||
ZH;ZH;ZH;ZH;}
|
||||
}
|
||||
|
||||
/* The main loop processes either 1 or 16 items per iteration. As its */
|
||||
/* termination logic is complicated, I have opted for an infinite loop */
|
||||
/* structure containing 'break' and 'goto' statements. */
|
||||
while (TRUE)
|
||||
{/* Begin main processing loop. */
|
||||
|
||||
/* Note: All the variables here except unroll should be defined within */
|
||||
/* the inner loop. Unfortunately the loop hasn't got a block. */
|
||||
register UBYTE *p; /* Scans through targ phrase during matching. */
|
||||
register UBYTE *p_ziv= NULL ; /* Points to first byte of current Ziv. */
|
||||
register UWORD unroll; /* Loop counter for unrolled inner loop. */
|
||||
register UWORD index; /* Index of current hash table entry. */
|
||||
register UBYTE **p_h0 = NULL ; /* Pointer to current hash table entry. */
|
||||
|
||||
/* Test for overrun and jump to overrun code if necessary. */
|
||||
if (p_dst>p_dst_post)
|
||||
goto overrun;
|
||||
|
||||
/* The following cascade of if statements efficiently catches and deals */
|
||||
/* with varying degrees of closeness to the end of the input block. */
|
||||
/* When we get very close to the end, we stop updating the table and */
|
||||
/* code the remaining bytes as literals. This makes the code simpler. */
|
||||
unroll=16;
|
||||
if (p_src>p_src_max16)
|
||||
{
|
||||
unroll=1;
|
||||
if (p_src>p_src_max1)
|
||||
{
|
||||
if (p_src==p_src_post)
|
||||
break;
|
||||
else
|
||||
goto literal;
|
||||
}
|
||||
}
|
||||
|
||||
/* This inner unrolled loop processes 'unroll' (whose value is either 1 */
|
||||
/* or 16) items. I have chosen to implement this loop with labels and */
|
||||
/* gotos to heighten the ease with which the loop may be implemented with */
|
||||
/* a single decrement and branch instruction in assembly language and */
|
||||
/* also because the labels act as highly readable place markers. */
|
||||
/* (Also because we jump into the loop for endgame literals (see above)). */
|
||||
|
||||
begin_unrolled_loop:
|
||||
|
||||
/* To process the next phrase, we hash the next three bytes and use */
|
||||
/* the resultant hash table index to look up the hash table. A pointer */
|
||||
/* to the entry is stored in p_h0 so as to avoid an array lookup. The */
|
||||
/* hash table entry *p_h0 is looked up yielding a pointer p to a */
|
||||
/* potential match of the Ziv in the history. */
|
||||
index=HASH(p_src);
|
||||
p_h0=&hash[index];
|
||||
p=*p_h0;
|
||||
|
||||
/* Having looked up the candidate position, we are in a position to */
|
||||
/* attempt a match. The match loop has been unrolled using the PS */
|
||||
/* macro so that failure within the first three bytes automatically */
|
||||
/* results in the literal branch being taken. The coding is simple. */
|
||||
/* p_ziv saves p_src so we can let p_src wander. */
|
||||
# define PS *p++!=*p_src++
|
||||
p_ziv=p_src;
|
||||
if (PS || PS || PS)
|
||||
{
|
||||
/* Literal. */
|
||||
|
||||
/* Code the literal byte as itself and a zero control bit. */
|
||||
p_src=p_ziv; literal: *p_dst++=*p_src++; control&=0xFFFEFFFF;
|
||||
|
||||
/* We have just coded a literal. If we had two pending ones, that */
|
||||
/* makes three and we can update the hash table. */
|
||||
if (p_h2!=0)
|
||||
{*p_h2=p_ziv-2;}
|
||||
|
||||
/* In any case, rotate the hash table pointers for next time. */
|
||||
p_h2=p_h1; p_h1=p_h0;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Copy */
|
||||
|
||||
/* Match up to 15 remaining bytes using an unrolled loop and code. */
|
||||
#if 0
|
||||
PS || PS || PS || PS || PS || PS || PS || PS ||
|
||||
PS || PS || PS || PS || PS || PS || PS || p_src++;
|
||||
#else
|
||||
if (
|
||||
!( PS || PS || PS || PS || PS || PS || PS || PS ||
|
||||
PS || PS || PS || PS || PS || PS || PS )
|
||||
) p_src++;
|
||||
#endif
|
||||
*p_dst++=((index&0xF00)>>4)|(--p_src-p_ziv-3);
|
||||
*p_dst++=index&0xFF;
|
||||
|
||||
/* As we have just coded three bytes, we are now in a position to */
|
||||
/* update the hash table with the literal bytes that were pending */
|
||||
/* upon the arrival of extra context bytes. */
|
||||
if (p_h1!=0)
|
||||
{
|
||||
if (p_h2)
|
||||
{*p_h2=p_ziv-2; p_h2=NULL;}
|
||||
*p_h1=p_ziv-1; p_h1=NULL;
|
||||
}
|
||||
|
||||
/* In any case, we can update the hash table based on the current */
|
||||
/* position as we just coded at least three bytes in a copy items. */
|
||||
*p_h0=p_ziv;
|
||||
|
||||
}
|
||||
control>>=1;
|
||||
|
||||
/* This loop is all set up for a decrement and jump instruction! */
|
||||
#ifndef linux
|
||||
` end_unrolled_loop: if (--unroll) goto begin_unrolled_loop;
|
||||
#else
|
||||
/* end_unrolled_loop: */ if (--unroll) goto begin_unrolled_loop;
|
||||
#endif
|
||||
|
||||
/* At this point it will nearly always be the end of a group in which */
|
||||
/* case, we have to do some control-word processing. However, near the */
|
||||
/* end of the input block, the inner unrolled loop is only executed once. */
|
||||
/* This necessitates the 'if' test. */
|
||||
if ((control&TOPWORD)==0)
|
||||
{
|
||||
/* Write the control word to the place we saved for it in the output. */
|
||||
*p_control++= control &0xFF;
|
||||
*p_control = (control>>8) &0xFF;
|
||||
|
||||
/* Reserve the next word in the output block for the control word */
|
||||
/* for the group about to be processed. */
|
||||
p_control=p_dst; p_dst+=2;
|
||||
|
||||
/* Reset the control bits buffer. */
|
||||
control=TOPWORD;
|
||||
}
|
||||
|
||||
} /* End main processing loop. */
|
||||
|
||||
/* After the main processing loop has executed, all the input bytes have */
|
||||
/* been processed. However, the control word has still to be written to the */
|
||||
/* word reserved for it in the output at the start of the most recent group. */
|
||||
/* Before writing, the control word has to be shifted so that all the bits */
|
||||
/* are in the right place. The "empty" bit positions are filled with 1s */
|
||||
/* which partially fill the top word. */
|
||||
while(control&TOPWORD) control>>=1;
|
||||
*p_control++= control &0xFF;
|
||||
*p_control++=(control>>8) &0xFF;
|
||||
|
||||
/* If the last group contained no items, delete the control word too. */
|
||||
if (p_control==p_dst) p_dst-=2;
|
||||
|
||||
/* Write the length of the output block to the dst_len parameter and return. */
|
||||
*p_dst_len=p_dst-p_dst_first;
|
||||
return;
|
||||
|
||||
/* Jump here as soon as an overrun is detected. An overrun is defined to */
|
||||
/* have occurred if p_dst>p_dst_first+src_len. That is, the moment the */
|
||||
/* length of the output written so far exceeds the length of the input block.*/
|
||||
/* The algorithm checks for overruns at least at the end of each group */
|
||||
/* which means that the maximum overrun is MAX_CMP_GROUP bytes. */
|
||||
/* Once an overrun occurs, the only thing to do is to set the copy flag and */
|
||||
/* copy the input over. */
|
||||
overrun:
|
||||
#if 0
|
||||
*p_dst_first=FLAG_COPY;
|
||||
fast_copy(p_src_first,p_dst_first+FLAG_BYTES,src_len);
|
||||
*p_dst_len=src_len+FLAG_BYTES;
|
||||
#else
|
||||
fast_copy(p_src_first,p_dst_first,src_len);
|
||||
*p_dst_len= -src_len; /* return a negative number to indicate uncompressed data */
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/* Input : Hand over the required amount of working memory in p_wrk_mem. */
|
||||
/* Input : Specify input block using p_src_first and src_len. */
|
||||
/* Input : Point p_dst_first to the start of the output zone. */
|
||||
/* Input : Point p_dst_len to a ULONG to receive the output length. */
|
||||
/* Input : Input block and output zone must not overlap. User knows */
|
||||
/* Input : upperbound on output block length from earlier compression. */
|
||||
/* Input : In any case, maximum expansion possible is nine times. */
|
||||
/* Output : Length of output block written to *p_dst_len. */
|
||||
/* Output : Output block in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. */
|
||||
/* Output : Writes only in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. */
|
||||
LOCAL void compress_decompress( UBYTE *p_wrk_mem,
|
||||
UBYTE *p_src_first, LONG src_len,
|
||||
UBYTE *p_dst_first, ULONG *p_dst_len)
|
||||
{
|
||||
/* Byte pointers p_src and p_dst scan through the input and output blocks. */
|
||||
register UBYTE *p_src = p_src_first+FLAG_BYTES;
|
||||
register UBYTE *p_dst = p_dst_first;
|
||||
/* we need to avoid a SEGV when trying to uncompress corrupt data */
|
||||
register UBYTE *p_dst_post = p_dst_first + *p_dst_len;
|
||||
|
||||
/* The following two variables are never modified and are used to control */
|
||||
/* the main loop. */
|
||||
UBYTE *p_src_post = p_src_first+src_len;
|
||||
UBYTE *p_src_max16 = p_src_first+src_len-(MAX_CMP_GROUP-2);
|
||||
|
||||
/* The hash table is the only resident of the working memory. The hash table */
|
||||
/* contains HASH_TABLE_LENGTH=4096 pointers to positions in the history. To */
|
||||
/* keep Macintoshes happy, it is longword aligned. */
|
||||
UBYTE **hash = (UBYTE **) ULONG_ALIGN_UP(p_wrk_mem);
|
||||
|
||||
/* The variable 'control' is used to buffer the control bits which appear in */
|
||||
/* groups of 16 bits (control words) at the start of each compressed group. */
|
||||
/* When each group is read, bit 16 of the register is set to one. Whenever */
|
||||
/* a new bit is needed, the register is shifted right. When the value of the */
|
||||
/* register becomes 1, we know that we have reached the end of a group. */
|
||||
/* Initializing the register to 1 thus instructs the code to follow that it */
|
||||
/* should read a new control word immediately. */
|
||||
register ULONG control=1;
|
||||
|
||||
/* The value of 'literals' is always in the range 0..3. It is the number of */
|
||||
/* consecutive literal items just seen. We have to record this number so as */
|
||||
/* to know when to update the hash table. When literals gets to 3, there */
|
||||
/* have been three consecutive literals and we can update at the position of */
|
||||
/* the oldest of the three. */
|
||||
register UWORD literals=0;
|
||||
|
||||
/* Check the leading copy flag to see if the compressor chose to use a copy */
|
||||
/* operation instead of a compression operation. If a copy operation was */
|
||||
/* used, then all we need to do is copy the data over, set the output length */
|
||||
/* and return. */
|
||||
#if 0
|
||||
if (*p_src_first==FLAG_COPY)
|
||||
{
|
||||
fast_copy(p_src_first+FLAG_BYTES,p_dst_first,src_len-FLAG_BYTES);
|
||||
*p_dst_len=src_len-FLAG_BYTES;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if ( src_len < 0 )
|
||||
{
|
||||
fast_copy(p_src_first,p_dst_first,-src_len );
|
||||
*p_dst_len = (ULONG)-src_len;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Initialize all elements of the hash table to point to a constant string. */
|
||||
/* Use of an unrolled loop speeds this up considerably. */
|
||||
{UWORD i; UBYTE **p_h=hash;
|
||||
# define ZJ *p_h++=START_STRING_18
|
||||
for (i=0;i<256;i++) /* 256=HASH_TABLE_LENGTH/16. */
|
||||
{ZJ;ZJ;ZJ;ZJ;
|
||||
ZJ;ZJ;ZJ;ZJ;
|
||||
ZJ;ZJ;ZJ;ZJ;
|
||||
ZJ;ZJ;ZJ;ZJ;}
|
||||
}
|
||||
|
||||
/* The outer loop processes either 1 or 16 items per iteration depending on */
|
||||
/* how close p_src is to the end of the input block. */
|
||||
while (p_src!=p_src_post)
|
||||
{/* Start of outer loop */
|
||||
|
||||
register UWORD unroll; /* Counts unrolled loop executions. */
|
||||
|
||||
/* When 'control' has the value 1, it means that the 16 buffered control */
|
||||
/* bits that were read in at the start of the current group have all been */
|
||||
/* shifted out and that all that is left is the 1 bit that was injected */
|
||||
/* into bit 16 at the start of the current group. When we reach the end */
|
||||
/* of a group, we have to load a new control word and inject a new 1 bit. */
|
||||
if (control==1)
|
||||
{
|
||||
control=0x10000|*p_src++;
|
||||
control|=(*p_src++)<<8;
|
||||
}
|
||||
|
||||
/* If it is possible that we are within 16 groups from the end of the */
|
||||
/* input, execute the unrolled loop only once, else process a whole group */
|
||||
/* of 16 items by looping 16 times. */
|
||||
unroll= p_src<=p_src_max16 ? 16 : 1;
|
||||
|
||||
/* This inner loop processes one phrase (item) per iteration. */
|
||||
while (unroll--)
|
||||
{ /* Begin unrolled inner loop. */
|
||||
|
||||
/* Process a literal or copy item depending on the next control bit. */
|
||||
if (control&1)
|
||||
{
|
||||
/* Copy item. */
|
||||
|
||||
register UBYTE *p; /* Points to place from which to copy. */
|
||||
register UWORD lenmt; /* Length of copy item minus three. */
|
||||
register UBYTE **p_hte; /* Pointer to current hash table entry.*/
|
||||
register UBYTE *p_ziv=p_dst; /* Pointer to start of current Ziv. */
|
||||
|
||||
/* Read and dismantle the copy word. Work out from where to copy. */
|
||||
lenmt=*p_src++;
|
||||
p_hte=&hash[((lenmt&0xF0)<<4)|*p_src++];
|
||||
p=*p_hte;
|
||||
lenmt&=0xF;
|
||||
|
||||
/* Now perform the copy using a half unrolled loop. */
|
||||
*p_dst++=*p++;
|
||||
*p_dst++=*p++;
|
||||
*p_dst++=*p++;
|
||||
while (lenmt--)
|
||||
*p_dst++=*p++;
|
||||
|
||||
/* Because we have just received 3 or more bytes in a copy item */
|
||||
/* (whose bytes we have just installed in the output), we are now */
|
||||
/* in a position to flush all the pending literal hashings that had */
|
||||
/* been postponed for lack of bytes. */
|
||||
if (literals>0)
|
||||
{
|
||||
register UBYTE *r=p_ziv-literals;
|
||||
hash[HASH(r)]=r;
|
||||
if (literals==2)
|
||||
{r++; hash[HASH(r)]=r;}
|
||||
literals=0;
|
||||
}
|
||||
|
||||
/* In any case, we can immediately update the hash table with the */
|
||||
/* current position. We don't need to do a HASH(...) to work out */
|
||||
/* where to put the pointer, as the compressor just told us!!! */
|
||||
*p_hte=p_ziv;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Literal item. */
|
||||
|
||||
/* Copy over the literal byte. */
|
||||
*p_dst++=*p_src++;
|
||||
|
||||
/* If we now have three literals waiting to be hashed into the hash */
|
||||
/* table, we can do one of them now (because there are three). */
|
||||
if (++literals == 3)
|
||||
{register UBYTE *p=p_dst-3; hash[HASH(p)]=p; literals=2;}
|
||||
}
|
||||
|
||||
/* Shift the control buffer so the next control bit is in bit 0. */
|
||||
control>>=1;
|
||||
#if 1
|
||||
if (p_dst > p_dst_post)
|
||||
{
|
||||
/* Shit: we tried to decompress corrupt data */
|
||||
*p_dst_len = 0;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
} /* End unrolled inner loop. */
|
||||
|
||||
} /* End of outer loop */
|
||||
|
||||
/* Write the length of the decompressed data before returning. */
|
||||
*p_dst_len=p_dst-p_dst_first;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* End of LZRW3.C */
|
||||
/******************************************************************************/
|
@ -1,253 +0,0 @@
|
||||
#ifndef _LZRW3_H
|
||||
#define _LZRW3_H
|
||||
/*
|
||||
* $Source: /homes/cvs/ftape-stacked/ftape/compressor/lzrw3.h,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 1997/10/05 19:12:30 $
|
||||
*
|
||||
* include files for lzrw3. Only slighty modified from the original
|
||||
* version. Assembles the three include files compress.h, port.h and
|
||||
* fastcopy.h from the original lzrw3 package.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
/******************************************************************************/
|
||||
/* */
|
||||
/* COMPRESS.H */
|
||||
/* */
|
||||
/******************************************************************************/
|
||||
/* */
|
||||
/* Author : Ross Williams. */
|
||||
/* Date : December 1989. */
|
||||
/* */
|
||||
/* This header file defines the interface to a set of functions called */
|
||||
/* 'compress', each member of which implements a particular data compression */
|
||||
/* algorithm. */
|
||||
/* */
|
||||
/* Normally in C programming, for each .H file, there is a corresponding .C */
|
||||
/* file that implements the functions promised in the .H file. */
|
||||
/* Here, there are many .C files corresponding to this header file. */
|
||||
/* Each comforming implementation file contains a single function */
|
||||
/* called 'compress' that implements a single data compression */
|
||||
/* algorithm that conforms with the interface specified in this header file. */
|
||||
/* Only one algorithm can be linked in at a time in this organization. */
|
||||
/* */
|
||||
/******************************************************************************/
|
||||
/* */
|
||||
/* DEFINITION OF FUNCTION COMPRESS */
|
||||
/* =============================== */
|
||||
/* */
|
||||
/* Summary of Function Compress */
|
||||
/* ---------------------------- */
|
||||
/* The action that 'compress' takes depends on its first argument called */
|
||||
/* 'action'. The function provides three actions: */
|
||||
/* */
|
||||
/* - Return information about the algorithm. */
|
||||
/* - Compress a block of memory. */
|
||||
/* - Decompress a block of memory. */
|
||||
/* */
|
||||
/* Parameters */
|
||||
/* ---------- */
|
||||
/* See the formal C definition later for a description of the parameters. */
|
||||
/* */
|
||||
/* Constants */
|
||||
/* --------- */
|
||||
/* COMPRESS_OVERRUN: The constant COMPRESS_OVERRUN defines by how many bytes */
|
||||
/* an algorithm is allowed to expand a block during a compression operation. */
|
||||
/* */
|
||||
/* Although compression algorithms usually compress data, there will always */
|
||||
/* be data that a given compressor will expand (this can be proven). */
|
||||
/* Fortunately, the degree of expansion can be limited to a single bit, by */
|
||||
/* copying over the input data if the data gets bigger during compression. */
|
||||
/* To allow for this possibility, the first bit of a compressed */
|
||||
/* representation can be used as a flag indicating whether the */
|
||||
/* input data was copied over, or truly compressed. In practice, the first */
|
||||
/* byte would be used to store this bit so as to maintain byte alignment. */
|
||||
/* */
|
||||
/* Unfortunately, in general, the only way to tell if an algorithm will */
|
||||
/* expand a particular block of data is to run the algorithm on the data. */
|
||||
/* If the algorithm does not continuously monitor how many output bytes it */
|
||||
/* has written, it might write an output block far larger than the input */
|
||||
/* block before realizing that it has done so. */
|
||||
/* On the other hand, continuous checks on output length are inefficient. */
|
||||
/* */
|
||||
/* To cater for all these problems, this interface definition: */
|
||||
/* > Allows a compression algorithm to return an output block that is up to */
|
||||
/* COMPRESS_OVERRUN bytes longer than the input block. */
|
||||
/* > Allows a compression algorithm to write up to COMPRESS_OVERRUN bytes */
|
||||
/* more than the length of the input block to the memory of the output */
|
||||
/* block regardless of the length of the output block eventually returned. */
|
||||
/* This allows an algorithm to overrun the length of the input block in the */
|
||||
/* output block by up to COMPRESS_OVERRUN bytes between expansion checks. */
|
||||
/* */
|
||||
/* The problem does not arise for decompression. */
|
||||
/* */
|
||||
/* Identity Action */
|
||||
/* --------------- */
|
||||
/* > action must be COMPRESS_ACTION_IDENTITY. */
|
||||
/* > p_dst_len must point to a longword to receive a longword address. */
|
||||
/* > The value of the other parameters does not matter. */
|
||||
/* > After execution, the longword that p_dst_len points to will be a pointer */
|
||||
/* to a structure of type compress_identity. */
|
||||
/* Thus, for example, after the call, (*p_dst_len)->memory will return the */
|
||||
/* number of bytes of working memory that the algorithm requires to run. */
|
||||
/* > The values of the identity structure returned are fixed constant */
|
||||
/* attributes of the algorithm and must not vary from call to call. */
|
||||
/* */
|
||||
/* Common Requirements for Compression and Decompression Actions */
|
||||
/* ------------------------------------------------------------- */
|
||||
/* > wrk_mem must point to an unused block of memory of a length specified in */
|
||||
/* the algorithm's identity block. The identity block can be obtained by */
|
||||
/* making a separate call to compress, specifying the identity action. */
|
||||
/* > The INPUT BLOCK is defined to be Memory[src_addr,src_addr+src_len-1]. */
|
||||
/* > dst_len will be used to denote *p_dst_len. */
|
||||
/* > dst_len is not read by compress, only written. */
|
||||
/* > The value of dst_len is defined only upon termination. */
|
||||
/* > The OUTPUT BLOCK is defined to be Memory[dst_addr,dst_addr+dst_len-1]. */
|
||||
/* */
|
||||
/* Compression Action */
|
||||
/* ------------------ */
|
||||
/* > action must be COMPRESS_ACTION_COMPRESS. */
|
||||
/* > src_len must be in the range [0,COMPRESS_MAX_ORG]. */
|
||||
/* > The OUTPUT ZONE is defined to be */
|
||||
/* Memory[dst_addr,dst_addr+src_len-1+COMPRESS_OVERRUN]. */
|
||||
/* > The function can modify any part of the output zone regardless of the */
|
||||
/* final length of the output block. */
|
||||
/* > The input block and the output zone must not overlap. */
|
||||
/* > dst_len will be in the range [0,src_len+COMPRESS_OVERRUN]. */
|
||||
/* > dst_len will be in the range [0,COMPRESS_MAX_COM] (from prev fact). */
|
||||
/* > The output block will consist of a representation of the input block. */
|
||||
/* */
|
||||
/* Decompression Action */
|
||||
/* -------------------- */
|
||||
/* > action must be COMPRESS_ACTION_DECOMPRESS. */
|
||||
/* > The input block must be the result of an earlier compression operation. */
|
||||
/* > If the previous fact is true, the following facts must also be true: */
|
||||
/* > src_len will be in the range [0,COMPRESS_MAX_COM]. */
|
||||
/* > dst_len will be in the range [0,COMPRESS_MAX_ORG]. */
|
||||
/* > The input and output blocks must not overlap. */
|
||||
/* > Only the output block is modified. */
|
||||
/* > Upon termination, the output block will consist of the bytes contained */
|
||||
/* in the input block passed to the earlier compression operation. */
|
||||
/* */
|
||||
/******************************************************************************/
|
||||
|
||||
/******************************************************************************/
|
||||
/* */
|
||||
/* PORT.H */
|
||||
/* */
|
||||
/******************************************************************************/
|
||||
/* */
|
||||
/* This module contains macro definitions and types that are likely to */
|
||||
/* change between computers. */
|
||||
/* */
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef DONE_PORT /* Only do this if not previously done. */
|
||||
|
||||
#ifdef THINK_C
|
||||
#define UBYTE unsigned char /* Unsigned byte */
|
||||
#define UWORD unsigned int /* Unsigned word (2 bytes) */
|
||||
#define ULONG unsigned long /* Unsigned word (4 bytes) */
|
||||
#define BOOL unsigned char /* Boolean */
|
||||
#define FOPEN_BINARY_READ "rb" /* Mode string for binary reading. */
|
||||
#define FOPEN_BINARY_WRITE "wb" /* Mode string for binary writing. */
|
||||
#define FOPEN_TEXT_APPEND "a" /* Mode string for text appending. */
|
||||
#define REAL double /* USed for floating point stuff. */
|
||||
#endif
|
||||
#if defined(LINUX) || defined(linux)
|
||||
#define UBYTE __u8 /* Unsigned byte */
|
||||
#define UWORD __u16 /* Unsigned word (2 bytes) */
|
||||
#define ULONG __u32 /* Unsigned word (4 bytes) */
|
||||
#define LONG __s32 /* Signed word (4 bytes) */
|
||||
#define BOOL is not used here /* Boolean */
|
||||
#define FOPEN_BINARY_READ not used /* Mode string for binary reading. */
|
||||
#define FOPEN_BINARY_WRITE not used /* Mode string for binary writing. */
|
||||
#define FOPEN_TEXT_APPEND not used /* Mode string for text appending. */
|
||||
#define REAL not used /* USed for floating point stuff. */
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define DONE_PORT /* Don't do all this again. */
|
||||
#define MALLOC_FAIL NULL /* Failure status from malloc() */
|
||||
#define LOCAL static /* For non-exported routines. */
|
||||
#define EXPORT /* Signals exported function. */
|
||||
#define then /* Useful for aligning ifs. */
|
||||
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
/* End of PORT.H */
|
||||
/******************************************************************************/
|
||||
|
||||
#define COMPRESS_ACTION_IDENTITY 0
|
||||
#define COMPRESS_ACTION_COMPRESS 1
|
||||
#define COMPRESS_ACTION_DECOMPRESS 2
|
||||
|
||||
#define COMPRESS_OVERRUN 1024
|
||||
#define COMPRESS_MAX_COM 0x70000000
|
||||
#define COMPRESS_MAX_ORG (COMPRESS_MAX_COM-COMPRESS_OVERRUN)
|
||||
|
||||
#define COMPRESS_MAX_STRLEN 255
|
||||
|
||||
/* The following structure provides information about the algorithm. */
|
||||
/* > The top bit of id must be zero. The remaining bits must be chosen by */
|
||||
/* the author of the algorithm by tossing a coin 31 times. */
|
||||
/* > The amount of memory requested by the algorithm is specified in bytes */
|
||||
/* and must be in the range [0,0x70000000]. */
|
||||
/* > All strings s must be such that strlen(s)<=COMPRESS_MAX_STRLEN. */
|
||||
struct compress_identity
|
||||
{
|
||||
ULONG id; /* Identifying number of algorithm. */
|
||||
ULONG memory; /* Number of bytes of working memory required. */
|
||||
|
||||
char *name; /* Name of algorithm. */
|
||||
char *version; /* Version number. */
|
||||
char *date; /* Date of release of this version. */
|
||||
char *copyright; /* Copyright message. */
|
||||
|
||||
char *author; /* Author of algorithm. */
|
||||
char *affiliation; /* Affiliation of author. */
|
||||
char *vendor; /* Where the algorithm can be obtained. */
|
||||
};
|
||||
|
||||
void lzrw3_compress( /* Single function interface to compression algorithm. */
|
||||
UWORD action, /* Action to be performed. */
|
||||
UBYTE *wrk_mem, /* Working memory temporarily given to routine to use. */
|
||||
UBYTE *src_adr, /* Address of input data. */
|
||||
LONG src_len, /* Length of input data. */
|
||||
UBYTE *dst_adr, /* Address of output data. */
|
||||
void *p_dst_len /* Pointer to a longword where routine will write: */
|
||||
/* If action=..IDENTITY => Adr of id structure. */
|
||||
/* If action=..COMPRESS => Length of output data. */
|
||||
/* If action=..DECOMPRESS => Length of output data. */
|
||||
);
|
||||
|
||||
/******************************************************************************/
|
||||
/* End of COMPRESS.H */
|
||||
/******************************************************************************/
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/* fast_copy.h */
|
||||
/******************************************************************************/
|
||||
|
||||
/* This function copies a block of memory very quickly. */
|
||||
/* The exact speed depends on the relative alignment of the blocks of memory. */
|
||||
/* PRE : 0<=src_len<=(2^32)-1 . */
|
||||
/* PRE : Source and destination blocks must not overlap. */
|
||||
/* POST : MEM[dst_adr,dst_adr+src_len-1]=MEM[src_adr,src_adr+src_len-1]. */
|
||||
/* POST : MEM[dst_adr,dst_adr+src_len-1] is the only memory changed. */
|
||||
|
||||
#define fast_copy(src,dst,len) memcpy(dst,src,len)
|
||||
|
||||
/******************************************************************************/
|
||||
/* End of fast_copy.h */
|
||||
/******************************************************************************/
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,83 +0,0 @@
|
||||
#ifndef _ZFTAPE_COMPRESS_H
|
||||
#define _ZFTAPE_COMPRESS_H
|
||||
/*
|
||||
* Copyright (c) 1994-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/ftape/compressor/zftape-compress.h,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 1997/10/05 19:12:32 $
|
||||
*
|
||||
* This file contains macros and definitions for zftape's
|
||||
* builtin compression code.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../zftape/zftape-buffers.h"
|
||||
#include "../zftape/zftape-vtbl.h"
|
||||
#include "../compressor/lzrw3.h"
|
||||
|
||||
/* CMPR_WRK_MEM_SIZE gives the size of the compression wrk_mem */
|
||||
/* I got these out of lzrw3.c */
|
||||
#define U(X) ((__u32) X)
|
||||
#define SIZE_P_BYTE (U(sizeof(__u8 *)))
|
||||
#define ALIGNMENT_FUDGE (U(16))
|
||||
|
||||
#define CMPR_WRK_MEM_SIZE (U(4096)*(SIZE_P_BYTE) + ALIGNMENT_FUDGE)
|
||||
|
||||
/* the maximum number of bytes the size of the "compressed" data can
|
||||
* exceed the uncompressed data. As it is quite useless to compress
|
||||
* data twice it is sometimes the case that it is more efficient to
|
||||
* copy a block of data but to feed it to the "compression"
|
||||
* algorithm. In this case there are some flag bytes or the like
|
||||
* proceding the "compressed" data. THAT MUST NOT BE THE CASE for the
|
||||
* algorithm we use for this driver. Instead, the high bit 15 of
|
||||
* compressed_size:
|
||||
*
|
||||
* compressed_size = ftape_compress()
|
||||
*
|
||||
* must be set in such a case.
|
||||
*
|
||||
* Nevertheless, it might also be as for lzrw3 that there is an
|
||||
* "intermediate" overrun that exceeds the amount of the compressed
|
||||
* data that is actually produced. During the algorithm we need in the
|
||||
* worst case MAX_CMP_GROUP bytes more than the input-size.
|
||||
*/
|
||||
#define MAX_CMP_GROUP (2+16*2) /* from lzrw3.c */
|
||||
|
||||
#define CMPR_OVERRUN MAX_CMP_GROUP /* during compression */
|
||||
|
||||
/****************************************************/
|
||||
|
||||
#define CMPR_BUFFER_SIZE (MAX_BLOCK_SIZE + CMPR_OVERRUN)
|
||||
|
||||
/* the compression map stores the byte offset compressed blocks within
|
||||
* the current volume for catridges with format code 2,3 and 5
|
||||
* (and old versions of zftape) and the offset measured in kilobytes for
|
||||
* format code 4 and 6. This gives us a possible max. size of a
|
||||
* compressed volume of 1024*4GIG which should be enough.
|
||||
*/
|
||||
typedef __u32 CmprMap;
|
||||
|
||||
/* globals
|
||||
*/
|
||||
|
||||
/* exported functions
|
||||
*/
|
||||
|
||||
#endif /* _ZFTAPE_COMPRESS_H */
|
@ -1,43 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 1996, 1997 Clau-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/ftape/lowlevel/Makefile,v $
|
||||
# $Revision: 1.4 $
|
||||
# $Date: 1997/10/07 09:26:02 $
|
||||
#
|
||||
# Makefile for the lowlevel part QIC-40/80/3010/3020 floppy-tape
|
||||
# driver for Linux.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_FTAPE) += ftape.o
|
||||
|
||||
ftape-objs := ftape-init.o fdc-io.o fdc-isr.o \
|
||||
ftape-bsm.o ftape-ctl.o ftape-read.o ftape-rw.o \
|
||||
ftape-write.o ftape-io.o ftape-calibr.o ftape-ecc.o fc-10.o \
|
||||
ftape-buffer.o ftape-format.o ftape_syms.o
|
||||
|
||||
ifeq ($(CONFIG_FTAPE),y)
|
||||
ftape-objs += ftape-setup.o
|
||||
endif
|
||||
|
||||
ifndef CONFIG_FT_NO_TRACE_AT_ALL
|
||||
ftape-objs += ftape-tracing.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_FT_PROC_FS),y)
|
||||
ftape-objs += ftape-proc.o
|
||||
endif
|
@ -1,175 +0,0 @@
|
||||
/*
|
||||
*
|
||||
|
||||
Copyright (C) 1993,1994 Jon Tombs.
|
||||
|
||||
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.
|
||||
|
||||
The entire guts of this program was written by dosemu, modified to
|
||||
record reads and writes to the ports in the 0x180-0x188 address space,
|
||||
while running the CMS program TAPE.EXE V2.0.5 supplied with the drive.
|
||||
|
||||
Modified to use an array of addresses and generally cleaned up (made
|
||||
much shorter) 4 June 94, dosemu isn't that good at writing short code it
|
||||
would seem :-). Made independent of 0x180, but I doubt it will work
|
||||
at any other address.
|
||||
|
||||
Modified for distribution with ftape source. 21 June 94, SJL.
|
||||
|
||||
Modifications on 20 October 95, by Daniel Cohen (catman@wpi.edu):
|
||||
Modified to support different DMA, IRQ, and IO Ports. Borland's
|
||||
Turbo Debugger in virtual 8086 mode (TD386.EXE with hardware breakpoints
|
||||
provided by the TDH386.SYS Device Driver) was used on the CMS program
|
||||
TAPE V4.0.5. I set breakpoints on I/O to ports 0x180-0x187. Note that
|
||||
CMS's program will not successfully configure the tape drive if you set
|
||||
breakpoints on IO Reads, but you can set them on IO Writes without problems.
|
||||
Known problems:
|
||||
- You can not use DMA Channels 5 or 7.
|
||||
|
||||
Modification on 29 January 96, by Daniel Cohen (catman@wpi.edu):
|
||||
Modified to only accept IRQs 3 - 7, or 9. Since we can only send a 3 bit
|
||||
number representing the IRQ to the card, special handling is required when
|
||||
IRQ 9 is selected. IRQ 2 and 9 are the same, and we should request IRQ 9
|
||||
from the kernel while telling the card to use IRQ 2. Thanks to Greg
|
||||
Crider (gcrider@iclnet.org) for finding and locating this bug, as well as
|
||||
testing the patch.
|
||||
|
||||
Modification on 11 December 96, by Claus Heine (claus@momo.math.rwth-aachen.de):
|
||||
Modified a little to use variahle ft_fdc_base, ft_fdc_irq, ft_fdc_dma
|
||||
instead of preprocessor symbols. Thus we can compile this into the module
|
||||
or kernel and let the user specify the options as command line arguments.
|
||||
|
||||
*
|
||||
* $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fc-10.c,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:18:04 $
|
||||
*
|
||||
* This file contains code for the CMS FC-10/FC-20 card.
|
||||
*/
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <linux/ftape.h>
|
||||
#include "../lowlevel/ftape-tracing.h"
|
||||
#include "../lowlevel/fdc-io.h"
|
||||
#include "../lowlevel/fc-10.h"
|
||||
|
||||
static __u16 inbs_magic[] = {
|
||||
0x3, 0x3, 0x0, 0x4, 0x7, 0x2, 0x5, 0x3, 0x1, 0x4,
|
||||
0x3, 0x5, 0x2, 0x0, 0x3, 0x7, 0x4, 0x2,
|
||||
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7
|
||||
};
|
||||
|
||||
static __u16 fc10_ports[] = {
|
||||
0x180, 0x210, 0x2A0, 0x300, 0x330, 0x340, 0x370
|
||||
};
|
||||
|
||||
int fc10_enable(void)
|
||||
{
|
||||
int i;
|
||||
__u8 cardConfig = 0x00;
|
||||
__u8 x;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
/* This code will only work if the FC-10 (or FC-20) is set to
|
||||
* use DMA channels 1, 2, or 3. DMA channels 5 and 7 seem to be
|
||||
* initialized by the same command as channels 1 and 3, respectively.
|
||||
*/
|
||||
if (ft_fdc_dma > 3) {
|
||||
TRACE_ABORT(0, ft_t_err,
|
||||
"Error: The FC-10/20 must be set to use DMA channels 1, 2, or 3!");
|
||||
}
|
||||
/* Only allow the FC-10/20 to use IRQ 3-7, or 9. Note that CMS's program
|
||||
* only accepts IRQ's 2-7, but in linux, IRQ 2 is the same as IRQ 9.
|
||||
*/
|
||||
if (ft_fdc_irq < 3 || ft_fdc_irq == 8 || ft_fdc_irq > 9) {
|
||||
TRACE_ABORT(0, ft_t_err,
|
||||
"Error: The FC-10/20 must be set to use IRQ levels 3 - 7, or 9!\n"
|
||||
KERN_INFO "Note: IRQ 9 is the same as IRQ 2");
|
||||
}
|
||||
/* Clear state machine ???
|
||||
*/
|
||||
for (i = 0; i < NR_ITEMS(inbs_magic); i++) {
|
||||
inb(ft_fdc_base + inbs_magic[i]);
|
||||
}
|
||||
outb(0x0, ft_fdc_base);
|
||||
|
||||
x = inb(ft_fdc_base);
|
||||
if (x == 0x13 || x == 0x93) {
|
||||
for (i = 1; i < 8; i++) {
|
||||
if (inb(ft_fdc_base + i) != x) {
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
outb(0x8, ft_fdc_base);
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (inb(ft_fdc_base + i) != 0x0) {
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
}
|
||||
outb(0x10, ft_fdc_base);
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (inb(ft_fdc_base + i) != 0xff) {
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Okay, we found a FC-10 card ! ???
|
||||
*/
|
||||
outb(0x0, fdc.ccr);
|
||||
|
||||
/* Clear state machine again ???
|
||||
*/
|
||||
for (i = 0; i < NR_ITEMS(inbs_magic); i++) {
|
||||
inb(ft_fdc_base + inbs_magic[i]);
|
||||
}
|
||||
/* Send io port */
|
||||
for (i = 0; i < NR_ITEMS(fc10_ports); i++)
|
||||
if (ft_fdc_base == fc10_ports[i])
|
||||
cardConfig = i + 1;
|
||||
if (cardConfig == 0) {
|
||||
TRACE_EXIT 0; /* Invalid I/O Port */
|
||||
}
|
||||
/* and IRQ - If using IRQ 9, tell the FC card it is actually IRQ 2 */
|
||||
if (ft_fdc_irq != 9)
|
||||
cardConfig |= ft_fdc_irq << 3;
|
||||
else
|
||||
cardConfig |= 2 << 3;
|
||||
|
||||
/* and finally DMA Channel */
|
||||
cardConfig |= ft_fdc_dma << 6;
|
||||
outb(cardConfig, ft_fdc_base); /* DMA [2 bits]/IRQ [3 bits]/BASE [3 bits] */
|
||||
|
||||
/* Enable FC-10 ???
|
||||
*/
|
||||
outb(0, fdc.ccr);
|
||||
outb(0, fdc.dor2);
|
||||
outb(FDC_DMA_MODE /* 8 */, fdc.dor);
|
||||
outb(FDC_DMA_MODE /* 8 */, fdc.dor);
|
||||
outb(1, fdc.dor2);
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* cH: why the hell should this be necessary? This is done
|
||||
* by fdc_reset()!!!
|
||||
*
|
||||
*************************************/
|
||||
/* Initialize fdc, select drive B:
|
||||
*/
|
||||
outb(FDC_DMA_MODE, fdc.dor); /* assert reset, dma & irq enabled */
|
||||
/* 0x08 */
|
||||
outb(FDC_DMA_MODE|FDC_RESET_NOT, fdc.dor); /* release reset */
|
||||
/* 0x08 | 0x04 = 0x0c */
|
||||
outb(FDC_DMA_MODE|FDC_RESET_NOT|FDC_MOTOR_1|FTAPE_SEL_B, fdc.dor);
|
||||
/* 0x08 | 0x04 | 0x20 | 0x01 = 0x2d */
|
||||
/* select drive 1 */ /* why not drive 0 ???? */
|
||||
TRACE_EXIT (x == 0x93) ? 2 : 1;
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
#ifndef _FC_10_H
|
||||
#define _FC_10_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 1994-1996 Bas Laarhoven.
|
||||
|
||||
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/ftape/lowlevel/fc-10.h,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 1997/09/19 09:05:22 $
|
||||
*
|
||||
* This file contains definitions for the FC-10 code
|
||||
* of the QIC-40/80 floppy-tape driver for Linux.
|
||||
*/
|
||||
|
||||
/*
|
||||
* fc-10.c defined global vars.
|
||||
*/
|
||||
|
||||
/*
|
||||
* fc-10.c defined global functions.
|
||||
*/
|
||||
extern int fc10_enable(void);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,252 +0,0 @@
|
||||
#ifndef _FDC_IO_H
|
||||
#define _FDC_IO_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 1993-1996 Bas Laarhoven,
|
||||
* (C) 1996-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/ftape/lowlevel/fdc-io.h,v $
|
||||
* $Revision: 1.3 $
|
||||
* $Date: 1997/10/05 19:18:06 $
|
||||
*
|
||||
* This file contains the declarations for the low level
|
||||
* functions that communicate with the floppy disk controller,
|
||||
* for the QIC-40/80/3010/3020 floppy-tape driver "ftape" for
|
||||
* Linux.
|
||||
*/
|
||||
|
||||
#include <linux/fdreg.h>
|
||||
|
||||
#include "../lowlevel/ftape-bsm.h"
|
||||
|
||||
#define FDC_SK_BIT (0x20)
|
||||
#define FDC_MT_BIT (0x80)
|
||||
|
||||
#define FDC_READ (FD_READ & ~(FDC_SK_BIT | FDC_MT_BIT))
|
||||
#define FDC_WRITE (FD_WRITE & ~FDC_MT_BIT)
|
||||
#define FDC_READ_DELETED (0x4c)
|
||||
#define FDC_WRITE_DELETED (0x49)
|
||||
#define FDC_VERIFY (0x56)
|
||||
#define FDC_READID (0x4a)
|
||||
#define FDC_SENSED (0x04)
|
||||
#define FDC_SENSEI (FD_SENSEI)
|
||||
#define FDC_FORMAT (FD_FORMAT)
|
||||
#define FDC_RECAL (FD_RECALIBRATE)
|
||||
#define FDC_SEEK (FD_SEEK)
|
||||
#define FDC_SPECIFY (FD_SPECIFY)
|
||||
#define FDC_RECALIBR (FD_RECALIBRATE)
|
||||
#define FDC_VERSION (FD_VERSION)
|
||||
#define FDC_PERPEND (FD_PERPENDICULAR)
|
||||
#define FDC_DUMPREGS (FD_DUMPREGS)
|
||||
#define FDC_LOCK (FD_LOCK)
|
||||
#define FDC_UNLOCK (FD_UNLOCK)
|
||||
#define FDC_CONFIGURE (FD_CONFIGURE)
|
||||
#define FDC_DRIVE_SPEC (0x8e) /* i82078 has this (any others?) */
|
||||
#define FDC_PARTID (0x18) /* i82078 has this */
|
||||
#define FDC_SAVE (0x2e) /* i82078 has this (any others?) */
|
||||
#define FDC_RESTORE (0x4e) /* i82078 has this (any others?) */
|
||||
|
||||
#define FDC_STATUS_MASK (STATUS_BUSY | STATUS_DMA | STATUS_DIR | STATUS_READY)
|
||||
#define FDC_DATA_READY (STATUS_READY)
|
||||
#define FDC_DATA_OUTPUT (STATUS_DIR)
|
||||
#define FDC_DATA_READY_MASK (STATUS_READY | STATUS_DIR)
|
||||
#define FDC_DATA_OUT_READY (STATUS_READY | STATUS_DIR)
|
||||
#define FDC_DATA_IN_READY (STATUS_READY)
|
||||
#define FDC_BUSY (STATUS_BUSY)
|
||||
#define FDC_CLK48_BIT (0x80)
|
||||
#define FDC_SEL3V_BIT (0x40)
|
||||
|
||||
#define ST0_INT_MASK (ST0_INTR)
|
||||
#define FDC_INT_NORMAL (ST0_INTR & 0x00)
|
||||
#define FDC_INT_ABNORMAL (ST0_INTR & 0x40)
|
||||
#define FDC_INT_INVALID (ST0_INTR & 0x80)
|
||||
#define FDC_INT_READYCH (ST0_INTR & 0xC0)
|
||||
#define ST0_SEEK_END (ST0_SE)
|
||||
#define ST3_TRACK_0 (ST3_TZ)
|
||||
|
||||
#define FDC_RESET_NOT (0x04)
|
||||
#define FDC_DMA_MODE (0x08)
|
||||
#define FDC_MOTOR_0 (0x10)
|
||||
#define FDC_MOTOR_1 (0x20)
|
||||
|
||||
typedef struct {
|
||||
void (**hook) (void); /* our wedge into the isr */
|
||||
enum {
|
||||
no_fdc, i8272, i82077, i82077AA, fc10,
|
||||
i82078, i82078_1
|
||||
} type; /* FDC type */
|
||||
unsigned int irq; /* FDC irq nr */
|
||||
unsigned int dma; /* FDC dma channel nr */
|
||||
__u16 sra; /* Status register A (PS/2 only) */
|
||||
__u16 srb; /* Status register B (PS/2 only) */
|
||||
__u16 dor; /* Digital output register */
|
||||
__u16 tdr; /* Tape Drive Register (82077SL-1 &
|
||||
82078 only) */
|
||||
__u16 msr; /* Main Status Register */
|
||||
__u16 dsr; /* Datarate Select Register (8207x only) */
|
||||
__u16 fifo; /* Data register / Fifo on 8207x */
|
||||
__u16 dir; /* Digital Input Register */
|
||||
__u16 ccr; /* Configuration Control Register */
|
||||
__u16 dor2; /* Alternate dor on MACH-2 controller,
|
||||
also used with FC-10, meaning unknown */
|
||||
} fdc_config_info;
|
||||
|
||||
typedef enum {
|
||||
fdc_data_rate_250 = 2,
|
||||
fdc_data_rate_300 = 1, /* any fdc in default configuration */
|
||||
fdc_data_rate_500 = 0,
|
||||
fdc_data_rate_1000 = 3,
|
||||
fdc_data_rate_2000 = 1, /* i82078-1: when using Data Rate Table #2 */
|
||||
} fdc_data_rate_type;
|
||||
|
||||
typedef enum {
|
||||
fdc_idle = 0,
|
||||
fdc_reading_data = FDC_READ,
|
||||
fdc_seeking = FDC_SEEK,
|
||||
fdc_writing_data = FDC_WRITE,
|
||||
fdc_deleting = FDC_WRITE_DELETED,
|
||||
fdc_reading_id = FDC_READID,
|
||||
fdc_recalibrating = FDC_RECAL,
|
||||
fdc_formatting = FDC_FORMAT,
|
||||
fdc_verifying = FDC_VERIFY
|
||||
} fdc_mode_enum;
|
||||
|
||||
typedef enum {
|
||||
waiting = 0,
|
||||
reading,
|
||||
writing,
|
||||
formatting,
|
||||
verifying,
|
||||
deleting,
|
||||
done,
|
||||
error,
|
||||
mmapped,
|
||||
} buffer_state_enum;
|
||||
|
||||
typedef struct {
|
||||
__u8 *address;
|
||||
volatile buffer_state_enum status;
|
||||
volatile __u8 *ptr;
|
||||
volatile unsigned int bytes;
|
||||
volatile unsigned int segment_id;
|
||||
|
||||
/* bitmap for remainder of segment not yet handled.
|
||||
* one bit set for each bad sector that must be skipped.
|
||||
*/
|
||||
volatile SectorMap bad_sector_map;
|
||||
|
||||
/* bitmap with bad data blocks in data buffer.
|
||||
* the errors in this map may be retried.
|
||||
*/
|
||||
volatile SectorMap soft_error_map;
|
||||
|
||||
/* bitmap with bad data blocks in data buffer
|
||||
* the errors in this map may not be retried.
|
||||
*/
|
||||
volatile SectorMap hard_error_map;
|
||||
|
||||
/* retry counter for soft errors.
|
||||
*/
|
||||
volatile int retry;
|
||||
|
||||
/* sectors to skip on retry ???
|
||||
*/
|
||||
volatile unsigned int skip;
|
||||
|
||||
/* nr of data blocks in data buffer
|
||||
*/
|
||||
volatile unsigned int data_offset;
|
||||
|
||||
/* offset in segment for first sector to be handled.
|
||||
*/
|
||||
volatile unsigned int sector_offset;
|
||||
|
||||
/* size of cluster of good sectors to be handled.
|
||||
*/
|
||||
volatile unsigned int sector_count;
|
||||
|
||||
/* size of remaining part of segment to be handled.
|
||||
*/
|
||||
volatile unsigned int remaining;
|
||||
|
||||
/* points to next segment (contiguous) to be handled,
|
||||
* or is zero if no read-ahead is allowed.
|
||||
*/
|
||||
volatile unsigned int next_segment;
|
||||
|
||||
/* flag being set if deleted data was read.
|
||||
*/
|
||||
volatile int deleted;
|
||||
|
||||
/* floppy coordinates of first sector in segment */
|
||||
volatile __u8 head;
|
||||
volatile __u8 cyl;
|
||||
volatile __u8 sect;
|
||||
|
||||
/* gap to use when formatting */
|
||||
__u8 gap3;
|
||||
/* flag set when buffer is mmaped */
|
||||
int mmapped;
|
||||
} buffer_struct;
|
||||
|
||||
/*
|
||||
* fdc-io.c defined public variables
|
||||
*/
|
||||
extern volatile fdc_mode_enum fdc_mode;
|
||||
extern int fdc_setup_error; /* outdated ??? */
|
||||
extern wait_queue_head_t ftape_wait_intr;
|
||||
extern volatile int ftape_current_cylinder; /* track nr FDC thinks we're on */
|
||||
extern volatile __u8 fdc_head; /* FDC head */
|
||||
extern volatile __u8 fdc_cyl; /* FDC track */
|
||||
extern volatile __u8 fdc_sect; /* FDC sector */
|
||||
extern fdc_config_info fdc; /* FDC hardware configuration */
|
||||
|
||||
extern unsigned int ft_fdc_base;
|
||||
extern unsigned int ft_fdc_irq;
|
||||
extern unsigned int ft_fdc_dma;
|
||||
extern unsigned int ft_fdc_threshold;
|
||||
extern unsigned int ft_fdc_rate_limit;
|
||||
extern int ft_probe_fc10;
|
||||
extern int ft_mach2;
|
||||
/*
|
||||
* fdc-io.c defined public functions
|
||||
*/
|
||||
extern void fdc_catch_stray_interrupts(int count);
|
||||
extern int fdc_ready_wait(unsigned int timeout);
|
||||
extern int fdc_command(const __u8 * cmd_data, int cmd_len);
|
||||
extern int fdc_result(__u8 * res_data, int res_len);
|
||||
extern int fdc_interrupt_wait(unsigned int time);
|
||||
extern int fdc_seek(int track);
|
||||
extern int fdc_sense_drive_status(int *st3);
|
||||
extern void fdc_motor(int motor);
|
||||
extern void fdc_reset(void);
|
||||
extern void fdc_disable(void);
|
||||
extern int fdc_fifo_threshold(__u8 threshold,
|
||||
int *fifo_state, int *lock_state, int *fifo_thr);
|
||||
extern void fdc_wait_calibrate(void);
|
||||
extern int fdc_sense_interrupt_status(int *st0, int *current_cylinder);
|
||||
extern void fdc_save_drive_specs(void);
|
||||
extern void fdc_restore_drive_specs(void);
|
||||
extern int fdc_set_data_rate(int rate);
|
||||
extern void fdc_set_write_precomp(int precomp);
|
||||
extern int fdc_release_irq_and_dma(void);
|
||||
extern void fdc_release_regions(void);
|
||||
extern int fdc_init(void);
|
||||
extern int fdc_setup_read_write(buffer_struct * buff, __u8 operation);
|
||||
extern int fdc_setup_formatting(buffer_struct * buff);
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,55 +0,0 @@
|
||||
#ifndef _FDC_ISR_H
|
||||
#define _FDC_ISR_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 1993-1996 Bas Laarhoven,
|
||||
* (C) 1996-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/ftape/lowlevel/fdc-isr.h,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:18:07 $
|
||||
*
|
||||
* This file declares the global variables necessary to
|
||||
* synchronize the interrupt service routine (isr) with the
|
||||
* remainder of the QIC-40/80/3010/3020 floppy-tape driver
|
||||
* "ftape" for Linux.
|
||||
*/
|
||||
|
||||
/*
|
||||
* fdc-isr.c defined public variables
|
||||
*/
|
||||
extern volatile int ft_expected_stray_interrupts; /* masks stray interrupts */
|
||||
extern volatile int ft_seek_completed; /* flag set by isr */
|
||||
extern volatile int ft_interrupt_seen; /* flag set by isr */
|
||||
extern volatile int ft_hide_interrupt; /* flag set by isr */
|
||||
|
||||
/*
|
||||
* fdc-io.c defined public functions
|
||||
*/
|
||||
extern void fdc_isr(void);
|
||||
|
||||
/*
|
||||
* A kernel hook that steals one interrupt from the floppy
|
||||
* driver (Should be fixed when the new fdc driver gets ready)
|
||||
* See the linux kernel source files:
|
||||
* drivers/block/floppy.c & drivers/block/blk.h
|
||||
* for the details.
|
||||
*/
|
||||
extern void (*do_floppy) (void);
|
||||
|
||||
#endif
|
@ -1,491 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1994-1996 Bas Laarhoven,
|
||||
* (C) 1996-1997 Claus 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/ftape/lowlevel/ftape-bsm.c,v $
|
||||
* $Revision: 1.3 $
|
||||
* $Date: 1997/10/05 19:15:15 $
|
||||
*
|
||||
* This file contains the bad-sector map handling code for
|
||||
* the QIC-117 floppy tape driver for Linux.
|
||||
* QIC-40, QIC-80, QIC-3010 and QIC-3020 maps are implemented.
|
||||
*/
|
||||
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <linux/ftape.h>
|
||||
#include "../lowlevel/ftape-tracing.h"
|
||||
#include "../lowlevel/ftape-bsm.h"
|
||||
#include "../lowlevel/ftape-ctl.h"
|
||||
#include "../lowlevel/ftape-rw.h"
|
||||
|
||||
/* Global vars.
|
||||
*/
|
||||
|
||||
/* Local vars.
|
||||
*/
|
||||
static __u8 *bad_sector_map;
|
||||
static SectorCount *bsm_hash_ptr;
|
||||
|
||||
typedef enum {
|
||||
forward, backward
|
||||
} mode_type;
|
||||
|
||||
#if 0
|
||||
static void ftape_put_bad_sector_entry(int segment_id, SectorMap new_map);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* fix_tape converts a normal QIC-80 tape into a 'wide' tape.
|
||||
* For testing purposes only !
|
||||
*/
|
||||
void fix_tape(__u8 * buffer, ft_format_type new_code)
|
||||
{
|
||||
static __u8 list[BAD_SECTOR_MAP_SIZE];
|
||||
SectorMap *src_ptr = (SectorMap *) list;
|
||||
__u8 *dst_ptr = bad_sector_map;
|
||||
SectorMap map;
|
||||
unsigned int sector = 1;
|
||||
int i;
|
||||
|
||||
if (format_code != fmt_var && format_code != fmt_big) {
|
||||
memcpy(list, bad_sector_map, sizeof(list));
|
||||
memset(bad_sector_map, 0, sizeof(bad_sector_map));
|
||||
while ((__u8 *) src_ptr - list < sizeof(list)) {
|
||||
map = *src_ptr++;
|
||||
if (map == EMPTY_SEGMENT) {
|
||||
*(SectorMap *) dst_ptr = 0x800000 + sector;
|
||||
dst_ptr += 3;
|
||||
sector += SECTORS_PER_SEGMENT;
|
||||
} else {
|
||||
for (i = 0; i < SECTORS_PER_SEGMENT; ++i) {
|
||||
if (map & 1) {
|
||||
*(SewctorMap *) dst_ptr = sector;
|
||||
dst_ptr += 3;
|
||||
}
|
||||
map >>= 1;
|
||||
++sector;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
bad_sector_map_changed = 1;
|
||||
*(buffer + 4) = new_code; /* put new format code */
|
||||
if (format_code != fmt_var && new_code == fmt_big) {
|
||||
PUT4(buffer, FT_6_HSEG_1, (__u32)GET2(buffer, 6));
|
||||
PUT4(buffer, FT_6_HSEG_2, (__u32)GET2(buffer, 8));
|
||||
PUT4(buffer, FT_6_FRST_SEG, (__u32)GET2(buffer, 10));
|
||||
PUT4(buffer, FT_6_LAST_SEG, (__u32)GET2(buffer, 12));
|
||||
memset(buffer+6, '\0', 8);
|
||||
}
|
||||
format_code = new_code;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* given buffer that contains a header segment, find the end of
|
||||
* of the bsm list
|
||||
*/
|
||||
__u8 * ftape_find_end_of_bsm_list(__u8 * address)
|
||||
{
|
||||
__u8 *ptr = address + FT_HEADER_END; /* start of bsm list */
|
||||
__u8 *limit = address + FT_SEGMENT_SIZE;
|
||||
while (ptr + 2 < limit) {
|
||||
if (ptr[0] || ptr[1] || ptr[2]) {
|
||||
ptr += 3;
|
||||
} else {
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void put_sector(SectorCount *ptr, unsigned int sector)
|
||||
{
|
||||
ptr->bytes[0] = sector & 0xff;
|
||||
sector >>= 8;
|
||||
ptr->bytes[1] = sector & 0xff;
|
||||
sector >>= 8;
|
||||
ptr->bytes[2] = sector & 0xff;
|
||||
}
|
||||
|
||||
static inline unsigned int get_sector(SectorCount *ptr)
|
||||
{
|
||||
#if 1
|
||||
unsigned int sector;
|
||||
|
||||
sector = ptr->bytes[0];
|
||||
sector += ptr->bytes[1] << 8;
|
||||
sector += ptr->bytes[2] << 16;
|
||||
|
||||
return sector;
|
||||
#else
|
||||
/* GET4 gets the next four bytes in Intel little endian order
|
||||
* and converts them to host byte order and handles unaligned
|
||||
* access.
|
||||
*/
|
||||
return (GET4(ptr, 0) & 0x00ffffff); /* back to host byte order */
|
||||
#endif
|
||||
}
|
||||
|
||||
static void bsm_debug_fake(void)
|
||||
{
|
||||
/* for testing of bad sector handling at end of tape
|
||||
*/
|
||||
#if 0
|
||||
ftape_put_bad_sector_entry(segments_per_track * tracks_per_tape - 3,
|
||||
0x000003e0;
|
||||
ftape_put_bad_sector_entry(segments_per_track * tracks_per_tape - 2,
|
||||
0xff3fffff;
|
||||
ftape_put_bad_sector_entry(segments_per_track * tracks_per_tape - 1,
|
||||
0xffffe000;
|
||||
#endif
|
||||
/* Enable to test bad sector handling
|
||||
*/
|
||||
#if 0
|
||||
ftape_put_bad_sector_entry(30, 0xfffffffe)
|
||||
ftape_put_bad_sector_entry(32, 0x7fffffff);
|
||||
ftape_put_bad_sector_entry(34, 0xfffeffff);
|
||||
ftape_put_bad_sector_entry(36, 0x55555555);
|
||||
ftape_put_bad_sector_entry(38, 0xffffffff);
|
||||
ftape_put_bad_sector_entry(50, 0xffff0000);
|
||||
ftape_put_bad_sector_entry(51, 0xffffffff);
|
||||
ftape_put_bad_sector_entry(52, 0xffffffff);
|
||||
ftape_put_bad_sector_entry(53, 0x0000ffff);
|
||||
#endif
|
||||
/* Enable when testing multiple volume tar dumps.
|
||||
*/
|
||||
#if 0
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = ft_first_data_segment;
|
||||
i <= ft_last_data_segment - 7; ++i) {
|
||||
ftape_put_bad_sector_entry(i, EMPTY_SEGMENT);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Enable when testing bit positions in *_error_map
|
||||
*/
|
||||
#if 0
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = first_data_segment; i <= last_data_segment; ++i) {
|
||||
ftape_put_bad_sector_entry(i,
|
||||
ftape_get_bad_sector_entry(i)
|
||||
| 0x00ff00ff);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void print_bad_sector_map(void)
|
||||
{
|
||||
unsigned int good_sectors;
|
||||
unsigned int total_bad = 0;
|
||||
int i;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (ft_format_code == fmt_big ||
|
||||
ft_format_code == fmt_var ||
|
||||
ft_format_code == fmt_1100ft) {
|
||||
SectorCount *ptr = (SectorCount *)bad_sector_map;
|
||||
unsigned int sector;
|
||||
__u16 *ptr16;
|
||||
|
||||
while((sector = get_sector(ptr++)) != 0) {
|
||||
if ((ft_format_code == fmt_big ||
|
||||
ft_format_code == fmt_var) &&
|
||||
sector & 0x800000) {
|
||||
total_bad += FT_SECTORS_PER_SEGMENT - 3;
|
||||
TRACE(ft_t_noise, "bad segment at sector: %6d",
|
||||
sector & 0x7fffff);
|
||||
} else {
|
||||
++total_bad;
|
||||
TRACE(ft_t_noise, "bad sector: %6d", sector);
|
||||
}
|
||||
}
|
||||
/* Display old ftape's end-of-file marks
|
||||
*/
|
||||
ptr16 = (__u16*)ptr;
|
||||
while ((sector = get_unaligned(ptr16++)) != 0) {
|
||||
TRACE(ft_t_noise, "Old ftape eof mark: %4d/%2d",
|
||||
sector, get_unaligned(ptr16++));
|
||||
}
|
||||
} else { /* fixed size format */
|
||||
for (i = ft_first_data_segment;
|
||||
i < (int)(ft_segments_per_track * ft_tracks_per_tape); ++i) {
|
||||
SectorMap map = ((SectorMap *) bad_sector_map)[i];
|
||||
|
||||
if (map) {
|
||||
TRACE(ft_t_noise,
|
||||
"bsm for segment %4d: 0x%08x", i, (unsigned int)map);
|
||||
total_bad += ((map == EMPTY_SEGMENT)
|
||||
? FT_SECTORS_PER_SEGMENT - 3
|
||||
: count_ones(map));
|
||||
}
|
||||
}
|
||||
}
|
||||
good_sectors =
|
||||
((ft_segments_per_track * ft_tracks_per_tape - ft_first_data_segment)
|
||||
* (FT_SECTORS_PER_SEGMENT - 3)) - total_bad;
|
||||
TRACE(ft_t_info, "%d Kb usable on this tape", good_sectors);
|
||||
if (total_bad == 0) {
|
||||
TRACE(ft_t_info,
|
||||
"WARNING: this tape has no bad blocks registered !");
|
||||
} else {
|
||||
TRACE(ft_t_info, "%d bad sectors", total_bad);
|
||||
}
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
|
||||
void ftape_extract_bad_sector_map(__u8 * buffer)
|
||||
{
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
/* Fill the bad sector map with the contents of buffer.
|
||||
*/
|
||||
if (ft_format_code == fmt_var || ft_format_code == fmt_big) {
|
||||
/* QIC-3010/3020 and wide QIC-80 tapes no longer have a failed
|
||||
* sector log but use this area to extend the bad sector map.
|
||||
*/
|
||||
bad_sector_map = &buffer[FT_HEADER_END];
|
||||
} else {
|
||||
/* non-wide QIC-80 tapes have a failed sector log area that
|
||||
* mustn't be included in the bad sector map.
|
||||
*/
|
||||
bad_sector_map = &buffer[FT_FSL + FT_FSL_SIZE];
|
||||
}
|
||||
if (ft_format_code == fmt_1100ft ||
|
||||
ft_format_code == fmt_var ||
|
||||
ft_format_code == fmt_big) {
|
||||
bsm_hash_ptr = (SectorCount *)bad_sector_map;
|
||||
} else {
|
||||
bsm_hash_ptr = NULL;
|
||||
}
|
||||
bsm_debug_fake();
|
||||
if (TRACE_LEVEL >= ft_t_info) {
|
||||
print_bad_sector_map();
|
||||
}
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
static inline SectorMap cvt2map(unsigned int sector)
|
||||
{
|
||||
return 1 << (((sector & 0x7fffff) - 1) % FT_SECTORS_PER_SEGMENT);
|
||||
}
|
||||
|
||||
static inline int cvt2segment(unsigned int sector)
|
||||
{
|
||||
return ((sector & 0x7fffff) - 1) / FT_SECTORS_PER_SEGMENT;
|
||||
}
|
||||
|
||||
static int forward_seek_entry(int segment_id,
|
||||
SectorCount **ptr,
|
||||
SectorMap *map)
|
||||
{
|
||||
unsigned int sector;
|
||||
int segment;
|
||||
|
||||
do {
|
||||
sector = get_sector((*ptr)++);
|
||||
segment = cvt2segment(sector);
|
||||
} while (sector != 0 && segment < segment_id);
|
||||
(*ptr) --; /* point to first sector >= segment_id */
|
||||
/* Get all sectors in segment_id
|
||||
*/
|
||||
if (sector == 0 || segment != segment_id) {
|
||||
*map = 0;
|
||||
return 0;
|
||||
} else if ((sector & 0x800000) &&
|
||||
(ft_format_code == fmt_var || ft_format_code == fmt_big)) {
|
||||
*map = EMPTY_SEGMENT;
|
||||
return FT_SECTORS_PER_SEGMENT;
|
||||
} else {
|
||||
int count = 1;
|
||||
SectorCount *tmp_ptr = (*ptr) + 1;
|
||||
|
||||
*map = cvt2map(sector);
|
||||
while ((sector = get_sector(tmp_ptr++)) != 0 &&
|
||||
(segment = cvt2segment(sector)) == segment_id) {
|
||||
*map |= cvt2map(sector);
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
static int backwards_seek_entry(int segment_id,
|
||||
SectorCount **ptr,
|
||||
SectorMap *map)
|
||||
{
|
||||
unsigned int sector;
|
||||
int segment; /* max unsigned int */
|
||||
|
||||
if (*ptr <= (SectorCount *)bad_sector_map) {
|
||||
*map = 0;
|
||||
return 0;
|
||||
}
|
||||
do {
|
||||
sector = get_sector(--(*ptr));
|
||||
segment = cvt2segment(sector);
|
||||
} while (*ptr > (SectorCount *)bad_sector_map && segment > segment_id);
|
||||
if (segment > segment_id) { /* at start of list, no entry found */
|
||||
*map = 0;
|
||||
return 0;
|
||||
} else if (segment < segment_id) {
|
||||
/* before smaller entry, adjust for overshoot */
|
||||
(*ptr) ++;
|
||||
*map = 0;
|
||||
return 0;
|
||||
} else if ((sector & 0x800000) &&
|
||||
(ft_format_code == fmt_big || ft_format_code == fmt_var)) {
|
||||
*map = EMPTY_SEGMENT;
|
||||
return FT_SECTORS_PER_SEGMENT;
|
||||
} else { /* get all sectors in segment_id */
|
||||
int count = 1;
|
||||
|
||||
*map = cvt2map(sector);
|
||||
while(*ptr > (SectorCount *)bad_sector_map) {
|
||||
sector = get_sector(--(*ptr));
|
||||
segment = cvt2segment(sector);
|
||||
if (segment != segment_id) {
|
||||
break;
|
||||
}
|
||||
*map |= cvt2map(sector);
|
||||
++count;
|
||||
}
|
||||
if (segment < segment_id) {
|
||||
(*ptr) ++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void ftape_put_bad_sector_entry(int segment_id, SectorMap new_map)
|
||||
{
|
||||
SectorCount *ptr = (SectorCount *)bad_sector_map;
|
||||
int count;
|
||||
int new_count;
|
||||
SectorMap map;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
if (ft_format_code == fmt_1100ft ||
|
||||
ft_format_code == fmt_var ||
|
||||
ft_format_code == fmt_big) {
|
||||
count = forward_seek_entry(segment_id, &ptr, &map);
|
||||
new_count = count_ones(new_map);
|
||||
/* If format code == 4 put empty segment instead of 32
|
||||
* bad sectors.
|
||||
*/
|
||||
if (ft_format_code == fmt_var || ft_format_code == fmt_big) {
|
||||
if (new_count == FT_SECTORS_PER_SEGMENT) {
|
||||
new_count = 1;
|
||||
}
|
||||
if (count == FT_SECTORS_PER_SEGMENT) {
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
if (count != new_count) {
|
||||
/* insert (or delete if < 0) new_count - count
|
||||
* entries. Move trailing part of list
|
||||
* including terminating 0.
|
||||
*/
|
||||
SectorCount *hi_ptr = ptr;
|
||||
|
||||
do {
|
||||
} while (get_sector(hi_ptr++) != 0);
|
||||
/* Note: ptr is of type byte *, and each bad sector
|
||||
* consumes 3 bytes.
|
||||
*/
|
||||
memmove(ptr + new_count, ptr + count,
|
||||
(size_t)(hi_ptr - (ptr + count))*sizeof(SectorCount));
|
||||
}
|
||||
TRACE(ft_t_noise, "putting map 0x%08x at %p, segment %d",
|
||||
(unsigned int)new_map, ptr, segment_id);
|
||||
if (new_count == 1 && new_map == EMPTY_SEGMENT) {
|
||||
put_sector(ptr++, (0x800001 +
|
||||
segment_id *
|
||||
FT_SECTORS_PER_SEGMENT));
|
||||
} else {
|
||||
int i = 0;
|
||||
|
||||
while (new_map) {
|
||||
if (new_map & 1) {
|
||||
put_sector(ptr++,
|
||||
1 + segment_id *
|
||||
FT_SECTORS_PER_SEGMENT + i);
|
||||
}
|
||||
++i;
|
||||
new_map >>= 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
((SectorMap *) bad_sector_map)[segment_id] = new_map;
|
||||
}
|
||||
TRACE_EXIT;
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
SectorMap ftape_get_bad_sector_entry(int segment_id)
|
||||
{
|
||||
if (ft_used_header_segment == -1) {
|
||||
/* When reading header segment we'll need a blank map.
|
||||
*/
|
||||
return 0;
|
||||
} else if (bsm_hash_ptr != NULL) {
|
||||
/* Invariants:
|
||||
* map - mask value returned on last call.
|
||||
* bsm_hash_ptr - points to first sector greater or equal to
|
||||
* first sector in last_referenced segment.
|
||||
* last_referenced - segment id used in the last call,
|
||||
* sector and map belong to this id.
|
||||
* This code is designed for sequential access and retries.
|
||||
* For true random access it may have to be redesigned.
|
||||
*/
|
||||
static int last_reference = -1;
|
||||
static SectorMap map;
|
||||
|
||||
if (segment_id > last_reference) {
|
||||
/* Skip all sectors before segment_id
|
||||
*/
|
||||
forward_seek_entry(segment_id, &bsm_hash_ptr, &map);
|
||||
} else if (segment_id < last_reference) {
|
||||
/* Skip backwards until begin of buffer or
|
||||
* first sector in segment_id
|
||||
*/
|
||||
backwards_seek_entry(segment_id, &bsm_hash_ptr, &map);
|
||||
} /* segment_id == last_reference : keep map */
|
||||
last_reference = segment_id;
|
||||
return map;
|
||||
} else {
|
||||
return ((SectorMap *) bad_sector_map)[segment_id];
|
||||
}
|
||||
}
|
||||
|
||||
/* This is simply here to prevent us from overwriting other kernel
|
||||
* data. Writes will result in NULL Pointer dereference.
|
||||
*/
|
||||
void ftape_init_bsm(void)
|
||||
{
|
||||
bad_sector_map = NULL;
|
||||
bsm_hash_ptr = NULL;
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
#ifndef _FTAPE_BSM_H
|
||||
#define _FTAPE_BSM_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 1994-1996 Bas Laarhoven,
|
||||
* (C) 1996-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/ftape/lowlevel/ftape-bsm.h,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:18:07 $
|
||||
*
|
||||
* This file contains definitions for the bad sector map handling
|
||||
* routines for the QIC-117 floppy-tape driver for Linux.
|
||||
*/
|
||||
|
||||
#include <linux/ftape.h>
|
||||
#include <linux/ftape-header-segment.h>
|
||||
|
||||
#define EMPTY_SEGMENT (0xffffffff)
|
||||
#define FAKE_SEGMENT (0xfffffffe)
|
||||
|
||||
/* maximum (format code 4) bad sector map size (bytes).
|
||||
*/
|
||||
#define BAD_SECTOR_MAP_SIZE (29 * SECTOR_SIZE - 256)
|
||||
|
||||
/* format code 4 bad sector entry, ftape uses this
|
||||
* internally for all format codes
|
||||
*/
|
||||
typedef __u32 SectorMap;
|
||||
/* variable and 1100 ft bad sector map entry. These three bytes represent
|
||||
* a single sector address measured from BOT.
|
||||
*/
|
||||
typedef struct NewSectorMap {
|
||||
__u8 bytes[3];
|
||||
} SectorCount;
|
||||
|
||||
|
||||
/*
|
||||
* ftape-bsm.c defined global vars.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ftape-bsm.c defined global functions.
|
||||
*/
|
||||
extern void update_bad_sector_map(__u8 * buffer);
|
||||
extern void ftape_extract_bad_sector_map(__u8 * buffer);
|
||||
extern SectorMap ftape_get_bad_sector_entry(int segment_id);
|
||||
extern __u8 *ftape_find_end_of_bsm_list(__u8 * address);
|
||||
extern void ftape_init_bsm(void);
|
||||
|
||||
#endif
|
@ -1,130 +0,0 @@
|
||||
/*
|
||||
* Copyright (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/ftape/lowlevel/ftape-buffer.c,v $
|
||||
* $Revision: 1.3 $
|
||||
* $Date: 1997/10/16 23:33:11 $
|
||||
*
|
||||
* This file contains the allocator/dealloctor for ftape's dynamic dma
|
||||
* buffer.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/mman.h>
|
||||
#include <asm/dma.h>
|
||||
|
||||
#include <linux/ftape.h>
|
||||
#include "../lowlevel/ftape-rw.h"
|
||||
#include "../lowlevel/ftape-read.h"
|
||||
#include "../lowlevel/ftape-tracing.h"
|
||||
#include "../lowlevel/ftape-buffer.h"
|
||||
|
||||
/* DMA'able memory allocation stuff.
|
||||
*/
|
||||
|
||||
static inline void *dmaalloc(size_t size)
|
||||
{
|
||||
unsigned long addr;
|
||||
|
||||
if (size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
addr = __get_dma_pages(GFP_KERNEL, get_order(size));
|
||||
if (addr) {
|
||||
struct page *page;
|
||||
|
||||
for (page = virt_to_page(addr); page < virt_to_page(addr+size); page++)
|
||||
SetPageReserved(page);
|
||||
}
|
||||
return (void *)addr;
|
||||
}
|
||||
|
||||
static inline void dmafree(void *addr, size_t size)
|
||||
{
|
||||
if (size > 0) {
|
||||
struct page *page;
|
||||
|
||||
for (page = virt_to_page((unsigned long)addr);
|
||||
page < virt_to_page((unsigned long)addr+size); page++)
|
||||
ClearPageReserved(page);
|
||||
free_pages((unsigned long) addr, get_order(size));
|
||||
}
|
||||
}
|
||||
|
||||
static int add_one_buffer(void)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (ft_nr_buffers >= FT_MAX_NR_BUFFERS) {
|
||||
TRACE_EXIT -ENOMEM;
|
||||
}
|
||||
ft_buffer[ft_nr_buffers] = kmalloc(sizeof(buffer_struct), GFP_KERNEL);
|
||||
if (ft_buffer[ft_nr_buffers] == NULL) {
|
||||
TRACE_EXIT -ENOMEM;
|
||||
}
|
||||
memset(ft_buffer[ft_nr_buffers], 0, sizeof(buffer_struct));
|
||||
ft_buffer[ft_nr_buffers]->address = dmaalloc(FT_BUFF_SIZE);
|
||||
if (ft_buffer[ft_nr_buffers]->address == NULL) {
|
||||
kfree(ft_buffer[ft_nr_buffers]);
|
||||
ft_buffer[ft_nr_buffers] = NULL;
|
||||
TRACE_EXIT -ENOMEM;
|
||||
}
|
||||
ft_nr_buffers ++;
|
||||
TRACE(ft_t_info, "buffer nr #%d @ %p, dma area @ %p",
|
||||
ft_nr_buffers,
|
||||
ft_buffer[ft_nr_buffers-1],
|
||||
ft_buffer[ft_nr_buffers-1]->address);
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
static void del_one_buffer(void)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
if (ft_nr_buffers > 0) {
|
||||
TRACE(ft_t_info, "releasing buffer nr #%d @ %p, dma area @ %p",
|
||||
ft_nr_buffers,
|
||||
ft_buffer[ft_nr_buffers-1],
|
||||
ft_buffer[ft_nr_buffers-1]->address);
|
||||
ft_nr_buffers --;
|
||||
dmafree(ft_buffer[ft_nr_buffers]->address, FT_BUFF_SIZE);
|
||||
kfree(ft_buffer[ft_nr_buffers]);
|
||||
ft_buffer[ft_nr_buffers] = NULL;
|
||||
}
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
int ftape_set_nr_buffers(int cnt)
|
||||
{
|
||||
int delta = cnt - ft_nr_buffers;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (delta > 0) {
|
||||
while (delta--) {
|
||||
if (add_one_buffer() < 0) {
|
||||
TRACE_EXIT -ENOMEM;
|
||||
}
|
||||
}
|
||||
} else if (delta < 0) {
|
||||
while (delta++) {
|
||||
del_one_buffer();
|
||||
}
|
||||
}
|
||||
ftape_zap_read_buffers();
|
||||
TRACE_EXIT 0;
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
#ifndef _FTAPE_BUFFER_H
|
||||
#define _FTAPE_BUFFER_H
|
||||
|
||||
/*
|
||||
* Copyright (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/ftape/lowlevel/ftape-buffer.h,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:18:08 $
|
||||
*
|
||||
* This file contains the allocator/dealloctor for ftape's dynamic dma
|
||||
* buffer.
|
||||
*/
|
||||
|
||||
extern int ftape_set_nr_buffers(int cnt);
|
||||
|
||||
#endif
|
@ -1,275 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1993-1996 Bas Laarhoven.
|
||||
|
||||
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/ftape/lowlevel/ftape-calibr.c,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:18:08 $
|
||||
*
|
||||
* GP calibration routine for processor speed dependent
|
||||
* functions.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/io.h>
|
||||
#if defined(__alpha__)
|
||||
# include <asm/hwrpb.h>
|
||||
#elif defined(__x86_64__)
|
||||
# include <asm/msr.h>
|
||||
# include <asm/timex.h>
|
||||
#elif defined(__i386__)
|
||||
# include <linux/timex.h>
|
||||
#endif
|
||||
#include <linux/ftape.h>
|
||||
#include "../lowlevel/ftape-tracing.h"
|
||||
#include "../lowlevel/ftape-calibr.h"
|
||||
#include "../lowlevel/fdc-io.h"
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
#if !defined(__alpha__) && !defined(__i386__) && !defined(__x86_64__)
|
||||
# error Ftape is not implemented for this architecture!
|
||||
#endif
|
||||
|
||||
#if defined(__alpha__) || defined(__x86_64__)
|
||||
static unsigned long ps_per_cycle = 0;
|
||||
#endif
|
||||
|
||||
static spinlock_t calibr_lock;
|
||||
|
||||
/*
|
||||
* Note: On Intel PCs, the clock ticks at 100 Hz (HZ==100) which is
|
||||
* too slow for certain timeouts (and that clock doesn't even tick
|
||||
* when interrupts are disabled). For that reason, the 8254 timer is
|
||||
* used directly to implement fine-grained timeouts. However, on
|
||||
* Alpha PCs, the 8254 is *not* used to implement the clock tick
|
||||
* (which is 1024 Hz, normally) and the 8254 timer runs at some
|
||||
* "random" frequency (it seems to run at 18Hz, but it's not safe to
|
||||
* rely on this value). Instead, we use the Alpha's "rpcc"
|
||||
* instruction to read cycle counts. As this is a 32 bit counter,
|
||||
* it will overflow only once per 30 seconds (on a 200MHz machine),
|
||||
* which is plenty.
|
||||
*/
|
||||
|
||||
unsigned int ftape_timestamp(void)
|
||||
{
|
||||
#if defined(__alpha__)
|
||||
unsigned long r;
|
||||
|
||||
asm volatile ("rpcc %0" : "=r" (r));
|
||||
return r;
|
||||
#elif defined(__x86_64__)
|
||||
unsigned long r;
|
||||
rdtscl(r);
|
||||
return r;
|
||||
#elif defined(__i386__)
|
||||
|
||||
/*
|
||||
* Note that there is some time between counter underflowing and jiffies
|
||||
* increasing, so the code below won't always give correct output.
|
||||
* -Vojtech
|
||||
*/
|
||||
|
||||
unsigned long flags;
|
||||
__u16 lo;
|
||||
__u16 hi;
|
||||
|
||||
spin_lock_irqsave(&calibr_lock, flags);
|
||||
outb_p(0x00, 0x43); /* latch the count ASAP */
|
||||
lo = inb_p(0x40); /* read the latched count */
|
||||
lo |= inb(0x40) << 8;
|
||||
hi = jiffies;
|
||||
spin_unlock_irqrestore(&calibr_lock, flags);
|
||||
return ((hi + 1) * (unsigned int) LATCH) - lo; /* downcounter ! */
|
||||
#endif
|
||||
}
|
||||
|
||||
static unsigned int short_ftape_timestamp(void)
|
||||
{
|
||||
#if defined(__alpha__) || defined(__x86_64__)
|
||||
return ftape_timestamp();
|
||||
#elif defined(__i386__)
|
||||
unsigned int count;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&calibr_lock, flags);
|
||||
outb_p(0x00, 0x43); /* latch the count ASAP */
|
||||
count = inb_p(0x40); /* read the latched count */
|
||||
count |= inb(0x40) << 8;
|
||||
spin_unlock_irqrestore(&calibr_lock, flags);
|
||||
return (LATCH - count); /* normal: downcounter */
|
||||
#endif
|
||||
}
|
||||
|
||||
static unsigned int diff(unsigned int t0, unsigned int t1)
|
||||
{
|
||||
#if defined(__alpha__) || defined(__x86_64__)
|
||||
return (t1 - t0);
|
||||
#elif defined(__i386__)
|
||||
/*
|
||||
* This is tricky: to work for both short and full ftape_timestamps
|
||||
* we'll have to discriminate between these.
|
||||
* If it _looks_ like short stamps with wrapping around we'll
|
||||
* asume it are. This will generate a small error if it really
|
||||
* was a (very large) delta from full ftape_timestamps.
|
||||
*/
|
||||
return (t1 <= t0 && t0 <= LATCH) ? t1 + LATCH - t0 : t1 - t0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static unsigned int usecs(unsigned int count)
|
||||
{
|
||||
#if defined(__alpha__) || defined(__x86_64__)
|
||||
return (ps_per_cycle * count) / 1000000UL;
|
||||
#elif defined(__i386__)
|
||||
return (10000 * count) / ((CLOCK_TICK_RATE + 50) / 100);
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned int ftape_timediff(unsigned int t0, unsigned int t1)
|
||||
{
|
||||
/*
|
||||
* Calculate difference in usec for ftape_timestamp results t0 & t1.
|
||||
* Note that on the i386 platform with short time-stamps, the
|
||||
* maximum allowed timespan is 1/HZ or we'll lose ticks!
|
||||
*/
|
||||
return usecs(diff(t0, t1));
|
||||
}
|
||||
|
||||
/* To get an indication of the I/O performance,
|
||||
* measure the duration of the inb() function.
|
||||
*/
|
||||
static void time_inb(void)
|
||||
{
|
||||
int i;
|
||||
int t0, t1;
|
||||
unsigned long flags;
|
||||
int status;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
spin_lock_irqsave(&calibr_lock, flags);
|
||||
t0 = short_ftape_timestamp();
|
||||
for (i = 0; i < 1000; ++i) {
|
||||
status = inb(fdc.msr);
|
||||
}
|
||||
t1 = short_ftape_timestamp();
|
||||
spin_unlock_irqrestore(&calibr_lock, flags);
|
||||
TRACE(ft_t_info, "inb() duration: %d nsec", ftape_timediff(t0, t1));
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
static void init_clock(void)
|
||||
{
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
#if defined(__x86_64__)
|
||||
ps_per_cycle = 1000000000UL / cpu_khz;
|
||||
#elif defined(__alpha__)
|
||||
extern struct hwrpb_struct *hwrpb;
|
||||
ps_per_cycle = (1000*1000*1000*1000UL) / hwrpb->cycle_freq;
|
||||
#endif
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Input: function taking int count as parameter.
|
||||
* pointers to calculated calibration variables.
|
||||
*/
|
||||
void ftape_calibrate(char *name,
|
||||
void (*fun) (unsigned int),
|
||||
unsigned int *calibr_count,
|
||||
unsigned int *calibr_time)
|
||||
{
|
||||
static int first_time = 1;
|
||||
int i;
|
||||
unsigned int tc = 0;
|
||||
unsigned int count;
|
||||
unsigned int time;
|
||||
#if defined(__i386__)
|
||||
unsigned int old_tc = 0;
|
||||
unsigned int old_count = 1;
|
||||
unsigned int old_time = 1;
|
||||
#endif
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (first_time) { /* get idea of I/O performance */
|
||||
init_clock();
|
||||
time_inb();
|
||||
first_time = 0;
|
||||
}
|
||||
/* value of timeout must be set so that on very slow systems
|
||||
* it will give a time less than one jiffy, and on
|
||||
* very fast systems it'll give reasonable precision.
|
||||
*/
|
||||
|
||||
count = 40;
|
||||
for (i = 0; i < 15; ++i) {
|
||||
unsigned int t0;
|
||||
unsigned int t1;
|
||||
unsigned int once;
|
||||
unsigned int multiple;
|
||||
unsigned long flags;
|
||||
|
||||
*calibr_count =
|
||||
*calibr_time = count; /* set TC to 1 */
|
||||
spin_lock_irqsave(&calibr_lock, flags);
|
||||
fun(0); /* dummy, get code into cache */
|
||||
t0 = short_ftape_timestamp();
|
||||
fun(0); /* overhead + one test */
|
||||
t1 = short_ftape_timestamp();
|
||||
once = diff(t0, t1);
|
||||
t0 = short_ftape_timestamp();
|
||||
fun(count); /* overhead + count tests */
|
||||
t1 = short_ftape_timestamp();
|
||||
multiple = diff(t0, t1);
|
||||
spin_unlock_irqrestore(&calibr_lock, flags);
|
||||
time = ftape_timediff(0, multiple - once);
|
||||
tc = (1000 * time) / (count - 1);
|
||||
TRACE(ft_t_any, "once:%3d us,%6d times:%6d us, TC:%5d ns",
|
||||
usecs(once), count - 1, usecs(multiple), tc);
|
||||
#if defined(__alpha__) || defined(__x86_64__)
|
||||
/*
|
||||
* Increase the calibration count exponentially until the
|
||||
* calibration time exceeds 100 ms.
|
||||
*/
|
||||
if (time >= 100*1000) {
|
||||
break;
|
||||
}
|
||||
#elif defined(__i386__)
|
||||
/*
|
||||
* increase the count until the resulting time nears 2/HZ,
|
||||
* then the tc will drop sharply because we lose LATCH counts.
|
||||
*/
|
||||
if (tc <= old_tc / 2) {
|
||||
time = old_time;
|
||||
count = old_count;
|
||||
break;
|
||||
}
|
||||
old_tc = tc;
|
||||
old_count = count;
|
||||
old_time = time;
|
||||
#endif
|
||||
count *= 2;
|
||||
}
|
||||
*calibr_count = count - 1;
|
||||
*calibr_time = time;
|
||||
TRACE(ft_t_info, "TC for `%s()' = %d nsec (at %d counts)",
|
||||
name, (1000 * *calibr_time) / *calibr_count, *calibr_count);
|
||||
TRACE_EXIT;
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
#ifndef _FTAPE_CALIBR_H
|
||||
#define _FTAPE_CALIBR_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 1993-1996 Bas Laarhoven.
|
||||
|
||||
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/ftape/lowlevel/ftape-calibr.h,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 1997/09/19 09:05:26 $
|
||||
*
|
||||
* This file contains a gp calibration routine for
|
||||
* hardware dependent timeout functions.
|
||||
*/
|
||||
|
||||
extern void ftape_calibrate(char *name,
|
||||
void (*fun) (unsigned int),
|
||||
unsigned int *calibr_count,
|
||||
unsigned int *calibr_time);
|
||||
extern unsigned int ftape_timestamp(void);
|
||||
extern unsigned int ftape_timediff(unsigned int t0, unsigned int t1);
|
||||
|
||||
#endif /* _FTAPE_CALIBR_H */
|
@ -1,896 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1993-1996 Bas Laarhoven,
|
||||
* 1996-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/ftape/lowlevel/ftape-ctl.c,v $
|
||||
* $Revision: 1.4 $
|
||||
* $Date: 1997/11/11 14:37:44 $
|
||||
*
|
||||
* This file contains the non-read/write ftape functions for the
|
||||
* QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/mman.h>
|
||||
|
||||
#include <linux/ftape.h>
|
||||
#include <linux/qic117.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/* ease porting between pre-2.4.x and later kernels */
|
||||
#define vma_get_pgoff(v) ((v)->vm_pgoff)
|
||||
|
||||
#include "../lowlevel/ftape-tracing.h"
|
||||
#include "../lowlevel/ftape-io.h"
|
||||
#include "../lowlevel/ftape-ctl.h"
|
||||
#include "../lowlevel/ftape-write.h"
|
||||
#include "../lowlevel/ftape-read.h"
|
||||
#include "../lowlevel/ftape-rw.h"
|
||||
#include "../lowlevel/ftape-bsm.h"
|
||||
|
||||
/* Global vars.
|
||||
*/
|
||||
ftape_info ftape_status = {
|
||||
/* vendor information */
|
||||
{ 0, }, /* drive type */
|
||||
/* data rates */
|
||||
500, /* used data rate */
|
||||
500, /* drive max rate */
|
||||
500, /* fdc max rate */
|
||||
/* drive selection, either FTAPE_SEL_A/B/C/D */
|
||||
-1, /* drive selection */
|
||||
/* flags set after decode the drive and tape status */
|
||||
0, /* formatted */
|
||||
1, /* no tape */
|
||||
1, /* write protected */
|
||||
1, /* new tape */
|
||||
/* values of last queried drive/tape status and error */
|
||||
{{0,}}, /* last error code */
|
||||
{{0,}}, /* drive status, configuration, tape status */
|
||||
/* cartridge geometry */
|
||||
20, /* tracks_per_tape */
|
||||
102, /* segments_per_track */
|
||||
/* location of header segments, etc. */
|
||||
-1, /* used_header_segment */
|
||||
-1, /* header_segment_1 */
|
||||
-1, /* header_segment_2 */
|
||||
-1, /* first_data_segment */
|
||||
-1, /* last_data_segment */
|
||||
/* the format code as stored in the header segment */
|
||||
fmt_normal, /* format code */
|
||||
/* the default for the qic std: unknown */
|
||||
-1,
|
||||
/* is tape running? */
|
||||
idle, /* runner_state */
|
||||
/* is tape reading/writing/verifying/formatting/deleting */
|
||||
idle, /* driver state */
|
||||
/* flags fatal hardware error */
|
||||
1, /* failure */
|
||||
/* history record */
|
||||
{ 0, } /* history record */
|
||||
};
|
||||
|
||||
int ftape_segments_per_head = 1020;
|
||||
int ftape_segments_per_cylinder = 4;
|
||||
int ftape_init_drive_needed = 1; /* need to be global for ftape_reset_drive()
|
||||
* in ftape-io.c
|
||||
*/
|
||||
|
||||
/* Local vars.
|
||||
*/
|
||||
static const vendor_struct vendors[] = QIC117_VENDORS;
|
||||
static const wakeup_method methods[] = WAKEUP_METHODS;
|
||||
|
||||
const ftape_info *ftape_get_status(void)
|
||||
{
|
||||
#if defined(STATUS_PARANOYA)
|
||||
static ftape_info get_status;
|
||||
|
||||
get_status = ftape_status;
|
||||
return &get_status;
|
||||
#else
|
||||
return &ftape_status; /* maybe return only a copy of it to assure
|
||||
* read only access
|
||||
*/
|
||||
#endif
|
||||
}
|
||||
|
||||
static int ftape_not_operational(int status)
|
||||
{
|
||||
/* return true if status indicates tape can not be used.
|
||||
*/
|
||||
return ((status ^ QIC_STATUS_CARTRIDGE_PRESENT) &
|
||||
(QIC_STATUS_ERROR |
|
||||
QIC_STATUS_CARTRIDGE_PRESENT |
|
||||
QIC_STATUS_NEW_CARTRIDGE));
|
||||
}
|
||||
|
||||
int ftape_seek_to_eot(void)
|
||||
{
|
||||
int status;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
TRACE_CATCH(ftape_ready_wait(ftape_timeout.pause, &status),);
|
||||
while ((status & QIC_STATUS_AT_EOT) == 0) {
|
||||
if (ftape_not_operational(status)) {
|
||||
TRACE_EXIT -EIO;
|
||||
}
|
||||
TRACE_CATCH(ftape_command_wait(QIC_PHYSICAL_FORWARD,
|
||||
ftape_timeout.rewind,&status),);
|
||||
}
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
int ftape_seek_to_bot(void)
|
||||
{
|
||||
int status;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
TRACE_CATCH(ftape_ready_wait(ftape_timeout.pause, &status),);
|
||||
while ((status & QIC_STATUS_AT_BOT) == 0) {
|
||||
if (ftape_not_operational(status)) {
|
||||
TRACE_EXIT -EIO;
|
||||
}
|
||||
TRACE_CATCH(ftape_command_wait(QIC_PHYSICAL_REVERSE,
|
||||
ftape_timeout.rewind,&status),);
|
||||
}
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
static int ftape_new_cartridge(void)
|
||||
{
|
||||
ft_location.track = -1; /* force seek on first access */
|
||||
ftape_zap_read_buffers();
|
||||
ftape_zap_write_buffers();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ftape_abort_operation(void)
|
||||
{
|
||||
int result = 0;
|
||||
int status;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (ft_runner_status == running) {
|
||||
TRACE(ft_t_noise, "aborting runner, waiting");
|
||||
|
||||
ft_runner_status = do_abort;
|
||||
/* set timeout so that the tape will run to logical EOT
|
||||
* if we missed the last sector and there are no queue pulses.
|
||||
*/
|
||||
result = ftape_dumb_stop();
|
||||
}
|
||||
if (ft_runner_status != idle) {
|
||||
if (ft_runner_status == do_abort) {
|
||||
TRACE(ft_t_noise, "forcing runner abort");
|
||||
}
|
||||
TRACE(ft_t_noise, "stopping tape");
|
||||
result = ftape_stop_tape(&status);
|
||||
ft_location.known = 0;
|
||||
ft_runner_status = idle;
|
||||
}
|
||||
ftape_reset_buffer();
|
||||
ftape_zap_read_buffers();
|
||||
ftape_set_state(idle);
|
||||
TRACE_EXIT result;
|
||||
}
|
||||
|
||||
static int lookup_vendor_id(unsigned int vendor_id)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (vendors[i].vendor_id != vendor_id) {
|
||||
if (++i >= NR_ITEMS(vendors)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static void ftape_detach_drive(void)
|
||||
{
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
TRACE(ft_t_flow, "disabling tape drive and fdc");
|
||||
ftape_put_drive_to_sleep(ft_drive_type.wake_up);
|
||||
fdc_catch_stray_interrupts(1); /* one always comes */
|
||||
fdc_disable();
|
||||
fdc_release_irq_and_dma();
|
||||
fdc_release_regions();
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
static void clear_history(void)
|
||||
{
|
||||
ft_history.used = 0;
|
||||
ft_history.id_am_errors =
|
||||
ft_history.id_crc_errors =
|
||||
ft_history.data_am_errors =
|
||||
ft_history.data_crc_errors =
|
||||
ft_history.overrun_errors =
|
||||
ft_history.no_data_errors =
|
||||
ft_history.retries =
|
||||
ft_history.crc_errors =
|
||||
ft_history.crc_failures =
|
||||
ft_history.ecc_failures =
|
||||
ft_history.corrected =
|
||||
ft_history.defects =
|
||||
ft_history.rewinds = 0;
|
||||
}
|
||||
|
||||
static int ftape_activate_drive(vendor_struct * drive_type)
|
||||
{
|
||||
int result = 0;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
/* If we already know the drive type, wake it up.
|
||||
* Else try to find out what kind of drive is attached.
|
||||
*/
|
||||
if (drive_type->wake_up != unknown_wake_up) {
|
||||
TRACE(ft_t_flow, "enabling tape drive and fdc");
|
||||
result = ftape_wakeup_drive(drive_type->wake_up);
|
||||
if (result < 0) {
|
||||
TRACE(ft_t_err, "known wakeup method failed");
|
||||
}
|
||||
} else {
|
||||
wake_up_types method;
|
||||
const ft_trace_t old_tracing = TRACE_LEVEL;
|
||||
if (TRACE_LEVEL < ft_t_flow) {
|
||||
SET_TRACE_LEVEL(ft_t_bug);
|
||||
}
|
||||
|
||||
/* Try to awaken the drive using all known methods.
|
||||
* Lower tracing for a while.
|
||||
*/
|
||||
for (method=no_wake_up; method < NR_ITEMS(methods); ++method) {
|
||||
drive_type->wake_up = method;
|
||||
#ifdef CONFIG_FT_TWO_DRIVES
|
||||
/* Test setup for dual drive configuration.
|
||||
* /dev/rft2 uses mountain wakeup
|
||||
* /dev/rft3 uses colorado wakeup
|
||||
* Other systems will use the normal scheme.
|
||||
*/
|
||||
if ((ft_drive_sel < 2) ||
|
||||
(ft_drive_sel == 2 && method == FT_WAKE_UP_1) ||
|
||||
(ft_drive_sel == 3 && method == FT_WAKE_UP_2)) {
|
||||
result=ftape_wakeup_drive(drive_type->wake_up);
|
||||
} else {
|
||||
result = -EIO;
|
||||
}
|
||||
#else
|
||||
result = ftape_wakeup_drive(drive_type->wake_up);
|
||||
#endif
|
||||
if (result >= 0) {
|
||||
TRACE(ft_t_warn, "drive wakeup method: %s",
|
||||
methods[drive_type->wake_up].name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
SET_TRACE_LEVEL(old_tracing);
|
||||
|
||||
if (method >= NR_ITEMS(methods)) {
|
||||
/* no response at all, cannot open this drive */
|
||||
drive_type->wake_up = unknown_wake_up;
|
||||
TRACE(ft_t_err, "no tape drive found !");
|
||||
result = -ENODEV;
|
||||
}
|
||||
}
|
||||
TRACE_EXIT result;
|
||||
}
|
||||
|
||||
static int ftape_get_drive_status(void)
|
||||
{
|
||||
int result;
|
||||
int status;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
ft_no_tape = ft_write_protected = 0;
|
||||
/* Tape drive is activated now.
|
||||
* First clear error status if present.
|
||||
*/
|
||||
do {
|
||||
result = ftape_ready_wait(ftape_timeout.reset, &status);
|
||||
if (result < 0) {
|
||||
if (result == -ETIME) {
|
||||
TRACE(ft_t_err, "ftape_ready_wait timeout");
|
||||
} else if (result == -EINTR) {
|
||||
TRACE(ft_t_err, "ftape_ready_wait aborted");
|
||||
} else {
|
||||
TRACE(ft_t_err, "ftape_ready_wait failed");
|
||||
}
|
||||
TRACE_EXIT -EIO;
|
||||
}
|
||||
/* Clear error condition (drive is ready !)
|
||||
*/
|
||||
if (status & QIC_STATUS_ERROR) {
|
||||
unsigned int error;
|
||||
qic117_cmd_t command;
|
||||
|
||||
TRACE(ft_t_err, "error status set");
|
||||
result = ftape_report_error(&error, &command, 1);
|
||||
if (result < 0) {
|
||||
TRACE(ft_t_err,
|
||||
"report_error_code failed: %d", result);
|
||||
/* hope it's working next time */
|
||||
ftape_reset_drive();
|
||||
TRACE_EXIT -EIO;
|
||||
} else if (error != 0) {
|
||||
TRACE(ft_t_noise, "error code : %d", error);
|
||||
TRACE(ft_t_noise, "error command: %d", command);
|
||||
}
|
||||
}
|
||||
if (status & QIC_STATUS_NEW_CARTRIDGE) {
|
||||
unsigned int error;
|
||||
qic117_cmd_t command;
|
||||
const ft_trace_t old_tracing = TRACE_LEVEL;
|
||||
SET_TRACE_LEVEL(ft_t_bug);
|
||||
|
||||
/* Undocumented feature: Must clear (not present!)
|
||||
* error here or we'll fail later.
|
||||
*/
|
||||
ftape_report_error(&error, &command, 1);
|
||||
|
||||
SET_TRACE_LEVEL(old_tracing);
|
||||
TRACE(ft_t_info, "status: new cartridge");
|
||||
ft_new_tape = 1;
|
||||
} else {
|
||||
ft_new_tape = 0;
|
||||
}
|
||||
FT_SIGNAL_EXIT(_DONT_BLOCK);
|
||||
} while (status & QIC_STATUS_ERROR);
|
||||
|
||||
ft_no_tape = !(status & QIC_STATUS_CARTRIDGE_PRESENT);
|
||||
ft_write_protected = (status & QIC_STATUS_WRITE_PROTECT) != 0;
|
||||
if (ft_no_tape) {
|
||||
TRACE(ft_t_warn, "no cartridge present");
|
||||
} else {
|
||||
if (ft_write_protected) {
|
||||
TRACE(ft_t_noise, "Write protected cartridge");
|
||||
}
|
||||
}
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
static void ftape_log_vendor_id(void)
|
||||
{
|
||||
int vendor_index;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
ftape_report_vendor_id(&ft_drive_type.vendor_id);
|
||||
vendor_index = lookup_vendor_id(ft_drive_type.vendor_id);
|
||||
if (ft_drive_type.vendor_id == UNKNOWN_VENDOR &&
|
||||
ft_drive_type.wake_up == wake_up_colorado) {
|
||||
vendor_index = 0;
|
||||
/* hack to get rid of all this mail */
|
||||
ft_drive_type.vendor_id = 0;
|
||||
}
|
||||
if (vendor_index < 0) {
|
||||
/* Unknown vendor id, first time opening device. The
|
||||
* drive_type remains set to type found at wakeup
|
||||
* time, this will probably keep the driver operating
|
||||
* for this new vendor.
|
||||
*/
|
||||
TRACE(ft_t_warn, "\n"
|
||||
KERN_INFO "============ unknown vendor id ===========\n"
|
||||
KERN_INFO "A new, yet unsupported tape drive is found\n"
|
||||
KERN_INFO "Please report the following values:\n"
|
||||
KERN_INFO " Vendor id : 0x%04x\n"
|
||||
KERN_INFO " Wakeup method : %s\n"
|
||||
KERN_INFO "And a description of your tape drive\n"
|
||||
KERN_INFO "to "THE_FTAPE_MAINTAINER"\n"
|
||||
KERN_INFO "==========================================",
|
||||
ft_drive_type.vendor_id,
|
||||
methods[ft_drive_type.wake_up].name);
|
||||
ft_drive_type.speed = 0; /* unknown */
|
||||
} else {
|
||||
ft_drive_type.name = vendors[vendor_index].name;
|
||||
ft_drive_type.speed = vendors[vendor_index].speed;
|
||||
TRACE(ft_t_info, "tape drive type: %s", ft_drive_type.name);
|
||||
/* scan all methods for this vendor_id in table */
|
||||
while(ft_drive_type.wake_up != vendors[vendor_index].wake_up) {
|
||||
if (vendor_index < NR_ITEMS(vendors) - 1 &&
|
||||
vendors[vendor_index + 1].vendor_id
|
||||
==
|
||||
ft_drive_type.vendor_id) {
|
||||
++vendor_index;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ft_drive_type.wake_up != vendors[vendor_index].wake_up) {
|
||||
TRACE(ft_t_warn, "\n"
|
||||
KERN_INFO "==========================================\n"
|
||||
KERN_INFO "wakeup type mismatch:\n"
|
||||
KERN_INFO "found: %s, expected: %s\n"
|
||||
KERN_INFO "please report this to "THE_FTAPE_MAINTAINER"\n"
|
||||
KERN_INFO "==========================================",
|
||||
methods[ft_drive_type.wake_up].name,
|
||||
methods[vendors[vendor_index].wake_up].name);
|
||||
}
|
||||
}
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
void ftape_calc_timeouts(unsigned int qic_std,
|
||||
unsigned int data_rate,
|
||||
unsigned int tape_len)
|
||||
{
|
||||
int speed; /* deci-ips ! */
|
||||
int ff_speed;
|
||||
int length;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
/* tape transport speed
|
||||
* data rate: QIC-40 QIC-80 QIC-3010 QIC-3020
|
||||
*
|
||||
* 250 Kbps 25 ips n/a n/a n/a
|
||||
* 500 Kbps 50 ips 34 ips 22.6 ips n/a
|
||||
* 1 Mbps n/a 68 ips 45.2 ips 22.6 ips
|
||||
* 2 Mbps n/a n/a n/a 45.2 ips
|
||||
*
|
||||
* fast tape transport speed is at least 68 ips.
|
||||
*/
|
||||
switch (qic_std) {
|
||||
case QIC_TAPE_QIC40:
|
||||
speed = (data_rate == 250) ? 250 : 500;
|
||||
break;
|
||||
case QIC_TAPE_QIC80:
|
||||
speed = (data_rate == 500) ? 340 : 680;
|
||||
break;
|
||||
case QIC_TAPE_QIC3010:
|
||||
speed = (data_rate == 500) ? 226 : 452;
|
||||
break;
|
||||
case QIC_TAPE_QIC3020:
|
||||
speed = (data_rate == 1000) ? 226 : 452;
|
||||
break;
|
||||
default:
|
||||
TRACE(ft_t_bug, "Unknown qic_std (bug) ?");
|
||||
speed = 500;
|
||||
break;
|
||||
}
|
||||
if (ft_drive_type.speed == 0) {
|
||||
unsigned long t0;
|
||||
static int dt = 0; /* keep gcc from complaining */
|
||||
static int first_time = 1;
|
||||
|
||||
/* Measure the time it takes to wind to EOT and back to BOT.
|
||||
* If the tape length is known, calculate the rewind speed.
|
||||
* Else keep the time value for calculation of the rewind
|
||||
* speed later on, when the length _is_ known.
|
||||
* Ask for a report only when length and speed are both known.
|
||||
*/
|
||||
if (first_time) {
|
||||
ftape_seek_to_bot();
|
||||
t0 = jiffies;
|
||||
ftape_seek_to_eot();
|
||||
ftape_seek_to_bot();
|
||||
dt = (int) (((jiffies - t0) * FT_USPT) / 1000);
|
||||
if (dt < 1) {
|
||||
dt = 1; /* prevent div by zero on failures */
|
||||
}
|
||||
first_time = 0;
|
||||
TRACE(ft_t_info,
|
||||
"trying to determine seek timeout, got %d msec",
|
||||
dt);
|
||||
}
|
||||
if (tape_len != 0) {
|
||||
ft_drive_type.speed =
|
||||
(2 * 12 * tape_len * 1000) / dt;
|
||||
TRACE(ft_t_warn, "\n"
|
||||
KERN_INFO "==========================================\n"
|
||||
KERN_INFO "drive type: %s\n"
|
||||
KERN_INFO "delta time = %d ms, length = %d ft\n"
|
||||
KERN_INFO "has a maximum tape speed of %d ips\n"
|
||||
KERN_INFO "please report this to "THE_FTAPE_MAINTAINER"\n"
|
||||
KERN_INFO "==========================================",
|
||||
ft_drive_type.name, dt, tape_len,
|
||||
ft_drive_type.speed);
|
||||
}
|
||||
}
|
||||
/* Handle unknown length tapes as very long ones. We'll
|
||||
* determine the actual length from a header segment later.
|
||||
* This is normal for all modern (Wide,TR1/2/3) formats.
|
||||
*/
|
||||
if (tape_len <= 0) {
|
||||
TRACE(ft_t_noise,
|
||||
"Unknown tape length, using maximal timeouts");
|
||||
length = QIC_TOP_TAPE_LEN; /* use worst case values */
|
||||
} else {
|
||||
length = tape_len; /* use actual values */
|
||||
}
|
||||
if (ft_drive_type.speed == 0) {
|
||||
ff_speed = speed;
|
||||
} else {
|
||||
ff_speed = ft_drive_type.speed;
|
||||
}
|
||||
/* time to go from bot to eot at normal speed (data rate):
|
||||
* time = (1+delta) * length (ft) * 12 (inch/ft) / speed (ips)
|
||||
* delta = 10 % for seek speed, 20 % for rewind speed.
|
||||
*/
|
||||
ftape_timeout.seek = (length * 132 * FT_SECOND) / speed;
|
||||
ftape_timeout.rewind = (length * 144 * FT_SECOND) / (10 * ff_speed);
|
||||
ftape_timeout.reset = 20 * FT_SECOND + ftape_timeout.rewind;
|
||||
TRACE(ft_t_noise, "timeouts for speed = %d, length = %d\n"
|
||||
KERN_INFO "seek timeout : %d sec\n"
|
||||
KERN_INFO "rewind timeout: %d sec\n"
|
||||
KERN_INFO "reset timeout : %d sec",
|
||||
speed, length,
|
||||
(ftape_timeout.seek + 500) / 1000,
|
||||
(ftape_timeout.rewind + 500) / 1000,
|
||||
(ftape_timeout.reset + 500) / 1000);
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
/* This function calibrates the datarate (i.e. determines the maximal
|
||||
* usable data rate) and sets the global variable ft_qic_std to qic_std
|
||||
*
|
||||
*/
|
||||
int ftape_calibrate_data_rate(unsigned int qic_std)
|
||||
{
|
||||
int rate = ft_fdc_rate_limit;
|
||||
int result;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
ft_qic_std = qic_std;
|
||||
|
||||
if (ft_qic_std == -1) {
|
||||
TRACE_ABORT(-EIO, ft_t_err,
|
||||
"Unable to determine data rate if QIC standard is unknown");
|
||||
}
|
||||
|
||||
/* Select highest rate supported by both fdc and drive.
|
||||
* Start with highest rate supported by the fdc.
|
||||
*/
|
||||
while (fdc_set_data_rate(rate) < 0 && rate > 250) {
|
||||
rate /= 2;
|
||||
}
|
||||
TRACE(ft_t_info,
|
||||
"Highest FDC supported data rate: %d Kbps", rate);
|
||||
ft_fdc_max_rate = rate;
|
||||
do {
|
||||
result = ftape_set_data_rate(rate, ft_qic_std);
|
||||
} while (result == -EINVAL && (rate /= 2) > 250);
|
||||
if (result < 0) {
|
||||
TRACE_ABORT(-EIO, ft_t_err, "set datarate failed");
|
||||
}
|
||||
ft_data_rate = rate;
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
static int ftape_init_drive(void)
|
||||
{
|
||||
int status;
|
||||
qic_model model;
|
||||
unsigned int qic_std;
|
||||
unsigned int data_rate;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
ftape_init_drive_needed = 0; /* don't retry if this fails ? */
|
||||
TRACE_CATCH(ftape_report_raw_drive_status(&status),);
|
||||
if (status & QIC_STATUS_CARTRIDGE_PRESENT) {
|
||||
if (!(status & QIC_STATUS_AT_BOT)) {
|
||||
/* Antique drives will get here after a soft reset,
|
||||
* modern ones only if the driver is loaded when the
|
||||
* tape wasn't rewound properly.
|
||||
*/
|
||||
/* Tape should be at bot if new cartridge ! */
|
||||
ftape_seek_to_bot();
|
||||
}
|
||||
if (!(status & QIC_STATUS_REFERENCED)) {
|
||||
TRACE(ft_t_flow, "starting seek_load_point");
|
||||
TRACE_CATCH(ftape_command_wait(QIC_SEEK_LOAD_POINT,
|
||||
ftape_timeout.reset,
|
||||
&status),);
|
||||
}
|
||||
}
|
||||
ft_formatted = (status & QIC_STATUS_REFERENCED) != 0;
|
||||
if (!ft_formatted) {
|
||||
TRACE(ft_t_warn, "Warning: tape is not formatted !");
|
||||
}
|
||||
|
||||
/* report configuration aborts when ftape_tape_len == -1
|
||||
* unknown qic_std is okay if not formatted.
|
||||
*/
|
||||
TRACE_CATCH(ftape_report_configuration(&model,
|
||||
&data_rate,
|
||||
&qic_std,
|
||||
&ftape_tape_len),);
|
||||
|
||||
/* Maybe add the following to the /proc entry
|
||||
*/
|
||||
TRACE(ft_t_info, "%s drive @ %d Kbps",
|
||||
(model == prehistoric) ? "prehistoric" :
|
||||
((model == pre_qic117c) ? "pre QIC-117C" :
|
||||
((model == post_qic117b) ? "post QIC-117B" :
|
||||
"post QIC-117D")), data_rate);
|
||||
|
||||
if (ft_formatted) {
|
||||
/* initialize ft_used_data_rate to maximum value
|
||||
* and set ft_qic_std
|
||||
*/
|
||||
TRACE_CATCH(ftape_calibrate_data_rate(qic_std),);
|
||||
if (ftape_tape_len == 0) {
|
||||
TRACE(ft_t_info, "unknown length QIC-%s tape",
|
||||
(ft_qic_std == QIC_TAPE_QIC40) ? "40" :
|
||||
((ft_qic_std == QIC_TAPE_QIC80) ? "80" :
|
||||
((ft_qic_std == QIC_TAPE_QIC3010)
|
||||
? "3010" : "3020")));
|
||||
} else {
|
||||
TRACE(ft_t_info, "%d ft. QIC-%s tape", ftape_tape_len,
|
||||
(ft_qic_std == QIC_TAPE_QIC40) ? "40" :
|
||||
((ft_qic_std == QIC_TAPE_QIC80) ? "80" :
|
||||
((ft_qic_std == QIC_TAPE_QIC3010)
|
||||
? "3010" : "3020")));
|
||||
}
|
||||
ftape_calc_timeouts(ft_qic_std, ft_data_rate, ftape_tape_len);
|
||||
/* soft write-protect QIC-40/QIC-80 cartridges used with a
|
||||
* Colorado T3000 drive. Buggy hardware!
|
||||
*/
|
||||
if ((ft_drive_type.vendor_id == 0x011c6) &&
|
||||
((ft_qic_std == QIC_TAPE_QIC40 ||
|
||||
ft_qic_std == QIC_TAPE_QIC80) &&
|
||||
!ft_write_protected)) {
|
||||
TRACE(ft_t_warn, "\n"
|
||||
KERN_INFO "The famous Colorado T3000 bug:\n"
|
||||
KERN_INFO "%s drives can't write QIC40 and QIC80\n"
|
||||
KERN_INFO "cartridges but don't set the write-protect flag!",
|
||||
ft_drive_type.name);
|
||||
ft_write_protected = 1;
|
||||
}
|
||||
} else {
|
||||
/* Doesn't make too much sense to set the data rate
|
||||
* because we don't know what to use for the write
|
||||
* precompensation.
|
||||
* Need to do this again when formatting the cartridge.
|
||||
*/
|
||||
ft_data_rate = data_rate;
|
||||
ftape_calc_timeouts(QIC_TAPE_QIC40,
|
||||
data_rate,
|
||||
ftape_tape_len);
|
||||
}
|
||||
ftape_new_cartridge();
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
static void ftape_munmap(void)
|
||||
{
|
||||
int i;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
for (i = 0; i < ft_nr_buffers; i++) {
|
||||
ft_buffer[i]->mmapped = 0;
|
||||
}
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
/* Map the dma buffers into the virtual address range given by vma.
|
||||
* We only check the caller doesn't map non-existent buffers. We
|
||||
* don't check for multiple mappings.
|
||||
*/
|
||||
int ftape_mmap(struct vm_area_struct *vma)
|
||||
{
|
||||
int num_buffers;
|
||||
int i;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (ft_failure) {
|
||||
TRACE_EXIT -ENODEV;
|
||||
}
|
||||
if (!(vma->vm_flags & (VM_READ|VM_WRITE))) {
|
||||
TRACE_ABORT(-EINVAL, ft_t_err, "Undefined mmap() access");
|
||||
}
|
||||
if (vma_get_pgoff(vma) != 0) {
|
||||
TRACE_ABORT(-EINVAL, ft_t_err, "page offset must be 0");
|
||||
}
|
||||
if ((vma->vm_end - vma->vm_start) % FT_BUFF_SIZE != 0) {
|
||||
TRACE_ABORT(-EINVAL, ft_t_err,
|
||||
"size = %ld, should be a multiple of %d",
|
||||
vma->vm_end - vma->vm_start,
|
||||
FT_BUFF_SIZE);
|
||||
}
|
||||
num_buffers = (vma->vm_end - vma->vm_start) / FT_BUFF_SIZE;
|
||||
if (num_buffers > ft_nr_buffers) {
|
||||
TRACE_ABORT(-EINVAL,
|
||||
ft_t_err, "size = %ld, should be less than %d",
|
||||
vma->vm_end - vma->vm_start,
|
||||
ft_nr_buffers * FT_BUFF_SIZE);
|
||||
}
|
||||
if (ft_driver_state != idle) {
|
||||
/* this also clears the buffer states
|
||||
*/
|
||||
ftape_abort_operation();
|
||||
} else {
|
||||
ftape_reset_buffer();
|
||||
}
|
||||
for (i = 0; i < num_buffers; i++) {
|
||||
unsigned long pfn;
|
||||
|
||||
pfn = virt_to_phys(ft_buffer[i]->address) >> PAGE_SHIFT;
|
||||
TRACE_CATCH(remap_pfn_range(vma, vma->vm_start +
|
||||
i * FT_BUFF_SIZE,
|
||||
pfn,
|
||||
FT_BUFF_SIZE,
|
||||
vma->vm_page_prot),
|
||||
_res = -EAGAIN);
|
||||
TRACE(ft_t_noise, "remapped dma buffer @ %p to location @ %p",
|
||||
ft_buffer[i]->address,
|
||||
(void *)(vma->vm_start + i * FT_BUFF_SIZE));
|
||||
}
|
||||
for (i = 0; i < num_buffers; i++) {
|
||||
memset(ft_buffer[i]->address, 0xAA, FT_BUFF_SIZE);
|
||||
ft_buffer[i]->mmapped++;
|
||||
}
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
static void ftape_init_driver(void); /* forward declaration */
|
||||
|
||||
/* OPEN routine called by kernel-interface code
|
||||
*/
|
||||
int ftape_enable(int drive_selection)
|
||||
{
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
if (ft_drive_sel == -1 || ft_drive_sel != drive_selection) {
|
||||
/* Other selection than last time
|
||||
*/
|
||||
ftape_init_driver();
|
||||
}
|
||||
ft_drive_sel = FTAPE_SEL(drive_selection);
|
||||
ft_failure = 0;
|
||||
TRACE_CATCH(fdc_init(),); /* init & detect fdc */
|
||||
TRACE_CATCH(ftape_activate_drive(&ft_drive_type),
|
||||
fdc_disable();
|
||||
fdc_release_irq_and_dma();
|
||||
fdc_release_regions());
|
||||
TRACE_CATCH(ftape_get_drive_status(), ftape_detach_drive());
|
||||
if (ft_drive_type.vendor_id == UNKNOWN_VENDOR) {
|
||||
ftape_log_vendor_id();
|
||||
}
|
||||
if (ft_new_tape) {
|
||||
ftape_init_drive_needed = 1;
|
||||
}
|
||||
if (!ft_no_tape && ftape_init_drive_needed) {
|
||||
TRACE_CATCH(ftape_init_drive(), ftape_detach_drive());
|
||||
}
|
||||
ftape_munmap(); /* clear the mmap flag */
|
||||
clear_history();
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
/* release routine called by the high level interface modules
|
||||
* zftape or sftape.
|
||||
*/
|
||||
void ftape_disable(void)
|
||||
{
|
||||
int i;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
for (i = 0; i < ft_nr_buffers; i++) {
|
||||
if (ft_buffer[i]->mmapped) {
|
||||
TRACE(ft_t_noise, "first byte of buffer %d: 0x%02x",
|
||||
i, *ft_buffer[i]->address);
|
||||
}
|
||||
}
|
||||
if (sigtestsetmask(¤t->pending.signal, _DONT_BLOCK) &&
|
||||
!(sigtestsetmask(¤t->pending.signal, _NEVER_BLOCK)) &&
|
||||
ftape_tape_running) {
|
||||
TRACE(ft_t_warn,
|
||||
"Interrupted by fatal signal and tape still running");
|
||||
ftape_dumb_stop();
|
||||
ftape_abort_operation(); /* it's annoying */
|
||||
} else {
|
||||
ftape_set_state(idle);
|
||||
}
|
||||
ftape_detach_drive();
|
||||
if (ft_history.used) {
|
||||
TRACE(ft_t_info, "== Non-fatal errors this run: ==");
|
||||
TRACE(ft_t_info, "fdc isr statistics:\n"
|
||||
KERN_INFO " id_am_errors : %3d\n"
|
||||
KERN_INFO " id_crc_errors : %3d\n"
|
||||
KERN_INFO " data_am_errors : %3d\n"
|
||||
KERN_INFO " data_crc_errors : %3d\n"
|
||||
KERN_INFO " overrun_errors : %3d\n"
|
||||
KERN_INFO " no_data_errors : %3d\n"
|
||||
KERN_INFO " retries : %3d",
|
||||
ft_history.id_am_errors, ft_history.id_crc_errors,
|
||||
ft_history.data_am_errors, ft_history.data_crc_errors,
|
||||
ft_history.overrun_errors, ft_history.no_data_errors,
|
||||
ft_history.retries);
|
||||
if (ft_history.used & 1) {
|
||||
TRACE(ft_t_info, "ecc statistics:\n"
|
||||
KERN_INFO " crc_errors : %3d\n"
|
||||
KERN_INFO " crc_failures : %3d\n"
|
||||
KERN_INFO " ecc_failures : %3d\n"
|
||||
KERN_INFO " sectors corrected: %3d",
|
||||
ft_history.crc_errors, ft_history.crc_failures,
|
||||
ft_history.ecc_failures, ft_history.corrected);
|
||||
}
|
||||
if (ft_history.defects > 0) {
|
||||
TRACE(ft_t_warn, "Warning: %d media defects!",
|
||||
ft_history.defects);
|
||||
}
|
||||
if (ft_history.rewinds > 0) {
|
||||
TRACE(ft_t_info, "tape motion statistics:\n"
|
||||
KERN_INFO "repositions : %3d",
|
||||
ft_history.rewinds);
|
||||
}
|
||||
}
|
||||
ft_failure = 1;
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
static void ftape_init_driver(void)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
ft_drive_type.vendor_id = UNKNOWN_VENDOR;
|
||||
ft_drive_type.speed = 0;
|
||||
ft_drive_type.wake_up = unknown_wake_up;
|
||||
ft_drive_type.name = "Unknown";
|
||||
|
||||
ftape_timeout.seek = 650 * FT_SECOND;
|
||||
ftape_timeout.reset = 670 * FT_SECOND;
|
||||
ftape_timeout.rewind = 650 * FT_SECOND;
|
||||
ftape_timeout.head_seek = 15 * FT_SECOND;
|
||||
ftape_timeout.stop = 5 * FT_SECOND;
|
||||
ftape_timeout.pause = 16 * FT_SECOND;
|
||||
|
||||
ft_qic_std = -1;
|
||||
ftape_tape_len = 0; /* unknown */
|
||||
ftape_current_command = 0;
|
||||
ftape_current_cylinder = -1;
|
||||
|
||||
ft_segments_per_track = 102;
|
||||
ftape_segments_per_head = 1020;
|
||||
ftape_segments_per_cylinder = 4;
|
||||
ft_tracks_per_tape = 20;
|
||||
|
||||
ft_failure = 1;
|
||||
|
||||
ft_formatted = 0;
|
||||
ft_no_tape = 1;
|
||||
ft_write_protected = 1;
|
||||
ft_new_tape = 1;
|
||||
|
||||
ft_driver_state = idle;
|
||||
|
||||
ft_data_rate =
|
||||
ft_fdc_max_rate = 500;
|
||||
ft_drive_max_rate = 0; /* triggers set_rate_test() */
|
||||
|
||||
ftape_init_drive_needed = 1;
|
||||
|
||||
ft_header_segment_1 = -1;
|
||||
ft_header_segment_2 = -1;
|
||||
ft_used_header_segment = -1;
|
||||
ft_first_data_segment = -1;
|
||||
ft_last_data_segment = -1;
|
||||
|
||||
ft_location.track = -1;
|
||||
ft_location.known = 0;
|
||||
|
||||
ftape_tape_running = 0;
|
||||
ftape_might_be_off_track = 1;
|
||||
|
||||
ftape_new_cartridge(); /* init some tape related variables */
|
||||
ftape_init_bsm();
|
||||
TRACE_EXIT;
|
||||
}
|
@ -1,162 +0,0 @@
|
||||
#ifndef _FTAPE_CTL_H
|
||||
#define _FTAPE_CTL_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 1993-1996 Bas Laarhoven,
|
||||
* (C) 1996-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/ftape/lowlevel/ftape-ctl.h,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:18:09 $
|
||||
*
|
||||
* This file contains the non-standard IOCTL related definitions
|
||||
* for the QIC-40/80/3010/3020 floppy-tape driver "ftape" for
|
||||
* Linux.
|
||||
*/
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/mtio.h>
|
||||
#include <linux/ftape-vendors.h>
|
||||
|
||||
#include "../lowlevel/ftape-rw.h"
|
||||
#include <linux/ftape-header-segment.h>
|
||||
|
||||
typedef struct {
|
||||
int used; /* any reading or writing done */
|
||||
/* isr statistics */
|
||||
unsigned int id_am_errors; /* id address mark not found */
|
||||
unsigned int id_crc_errors; /* crc error in id address mark */
|
||||
unsigned int data_am_errors; /* data address mark not found */
|
||||
unsigned int data_crc_errors; /* crc error in data field */
|
||||
unsigned int overrun_errors; /* fdc access timing problem */
|
||||
unsigned int no_data_errors; /* sector not found */
|
||||
unsigned int retries; /* number of tape retries */
|
||||
/* ecc statistics */
|
||||
unsigned int crc_errors; /* crc error in data */
|
||||
unsigned int crc_failures; /* bad data without crc error */
|
||||
unsigned int ecc_failures; /* failed to correct */
|
||||
unsigned int corrected; /* total sectors corrected */
|
||||
/* general statistics */
|
||||
unsigned int rewinds; /* number of tape rewinds */
|
||||
unsigned int defects; /* bad sectors due to media defects */
|
||||
} history_record;
|
||||
|
||||
/* this structure contains * ALL * information that we want
|
||||
* our child modules to know about, but don't want them to
|
||||
* modify.
|
||||
*/
|
||||
typedef struct {
|
||||
/* vendor information */
|
||||
vendor_struct fti_drive_type;
|
||||
/* data rates */
|
||||
unsigned int fti_used_data_rate;
|
||||
unsigned int fti_drive_max_rate;
|
||||
unsigned int fti_fdc_max_rate;
|
||||
/* drive selection, either FTAPE_SEL_A/B/C/D */
|
||||
int fti_drive_sel;
|
||||
/* flags set after decode the drive and tape status */
|
||||
unsigned int fti_formatted :1;
|
||||
unsigned int fti_no_tape :1;
|
||||
unsigned int fti_write_protected:1;
|
||||
unsigned int fti_new_tape :1;
|
||||
/* values of last queried drive/tape status and error */
|
||||
ft_drive_error fti_last_error;
|
||||
ft_drive_status fti_last_status;
|
||||
/* cartridge geometry */
|
||||
unsigned int fti_tracks_per_tape;
|
||||
unsigned int fti_segments_per_track;
|
||||
/* location of header segments, etc. */
|
||||
int fti_used_header_segment;
|
||||
int fti_header_segment_1;
|
||||
int fti_header_segment_2;
|
||||
int fti_first_data_segment;
|
||||
int fti_last_data_segment;
|
||||
/* the format code as stored in the header segment */
|
||||
ft_format_type fti_format_code;
|
||||
/* the following is the sole reason for the ftape_set_status() call */
|
||||
unsigned int fti_qic_std;
|
||||
/* is tape running? */
|
||||
volatile enum runner_status_enum fti_runner_status;
|
||||
/* is tape reading/writing/verifying/formatting/deleting */
|
||||
buffer_state_enum fti_state;
|
||||
/* flags fatal hardware error */
|
||||
unsigned int fti_failure:1;
|
||||
/* history record */
|
||||
history_record fti_history;
|
||||
} ftape_info;
|
||||
|
||||
/* vendor information */
|
||||
#define ft_drive_type ftape_status.fti_drive_type
|
||||
/* data rates */
|
||||
#define ft_data_rate ftape_status.fti_used_data_rate
|
||||
#define ft_drive_max_rate ftape_status.fti_drive_max_rate
|
||||
#define ft_fdc_max_rate ftape_status.fti_fdc_max_rate
|
||||
/* drive selection, either FTAPE_SEL_A/B/C/D */
|
||||
#define ft_drive_sel ftape_status.fti_drive_sel
|
||||
/* flags set after decode the drive and tape status */
|
||||
#define ft_formatted ftape_status.fti_formatted
|
||||
#define ft_no_tape ftape_status.fti_no_tape
|
||||
#define ft_write_protected ftape_status.fti_write_protected
|
||||
#define ft_new_tape ftape_status.fti_new_tape
|
||||
/* values of last queried drive/tape status and error */
|
||||
#define ft_last_error ftape_status.fti_last_error
|
||||
#define ft_last_status ftape_status.fti_last_status
|
||||
/* cartridge geometry */
|
||||
#define ft_tracks_per_tape ftape_status.fti_tracks_per_tape
|
||||
#define ft_segments_per_track ftape_status.fti_segments_per_track
|
||||
/* the format code as stored in the header segment */
|
||||
#define ft_format_code ftape_status.fti_format_code
|
||||
/* the qic status as returned by report drive configuration */
|
||||
#define ft_qic_std ftape_status.fti_qic_std
|
||||
#define ft_used_header_segment ftape_status.fti_used_header_segment
|
||||
#define ft_header_segment_1 ftape_status.fti_header_segment_1
|
||||
#define ft_header_segment_2 ftape_status.fti_header_segment_2
|
||||
#define ft_first_data_segment ftape_status.fti_first_data_segment
|
||||
#define ft_last_data_segment ftape_status.fti_last_data_segment
|
||||
/* is tape running? */
|
||||
#define ft_runner_status ftape_status.fti_runner_status
|
||||
/* is tape reading/writing/verifying/formatting/deleting */
|
||||
#define ft_driver_state ftape_status.fti_state
|
||||
/* flags fatal hardware error */
|
||||
#define ft_failure ftape_status.fti_failure
|
||||
/* history record */
|
||||
#define ft_history ftape_status.fti_history
|
||||
|
||||
/*
|
||||
* ftape-ctl.c defined global vars.
|
||||
*/
|
||||
extern ftape_info ftape_status;
|
||||
extern int ftape_segments_per_head;
|
||||
extern int ftape_segments_per_cylinder;
|
||||
extern int ftape_init_drive_needed;
|
||||
|
||||
/*
|
||||
* ftape-ctl.c defined global functions.
|
||||
*/
|
||||
extern int ftape_mmap(struct vm_area_struct *vma);
|
||||
extern int ftape_enable(int drive_selection);
|
||||
extern void ftape_disable(void);
|
||||
extern int ftape_seek_to_bot(void);
|
||||
extern int ftape_seek_to_eot(void);
|
||||
extern int ftape_abort_operation(void);
|
||||
extern void ftape_calc_timeouts(unsigned int qic_std,
|
||||
unsigned int data_rate,
|
||||
unsigned int tape_len);
|
||||
extern int ftape_calibrate_data_rate(unsigned int qic_std);
|
||||
extern const ftape_info *ftape_get_status(void);
|
||||
#endif
|
@ -1,853 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1993 Ning and David Mosberger.
|
||||
|
||||
This is based on code originally written by Bas Laarhoven (bas@vimec.nl)
|
||||
and David L. Brown, Jr., and incorporates improvements suggested by
|
||||
Kai Harrekilde-Petersen.
|
||||
|
||||
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/ftape/lowlevel/ftape-ecc.c,v $
|
||||
* $Revision: 1.3 $
|
||||
* $Date: 1997/10/05 19:18:10 $
|
||||
*
|
||||
* This file contains the Reed-Solomon error correction code
|
||||
* for the QIC-40/80 floppy-tape driver for Linux.
|
||||
*/
|
||||
|
||||
#include <linux/ftape.h>
|
||||
|
||||
#include "../lowlevel/ftape-tracing.h"
|
||||
#include "../lowlevel/ftape-ecc.h"
|
||||
|
||||
/* Machines that are big-endian should define macro BIG_ENDIAN.
|
||||
* Unfortunately, there doesn't appear to be a standard include file
|
||||
* that works for all OSs.
|
||||
*/
|
||||
|
||||
#if defined(__sparc__) || defined(__hppa)
|
||||
#define BIG_ENDIAN
|
||||
#endif /* __sparc__ || __hppa */
|
||||
|
||||
#if defined(__mips__)
|
||||
#error Find a smart way to determine the Endianness of the MIPS CPU
|
||||
#endif
|
||||
|
||||
/* Notice: to minimize the potential for confusion, we use r to
|
||||
* denote the independent variable of the polynomials in the
|
||||
* Galois Field GF(2^8). We reserve x for polynomials that
|
||||
* that have coefficients in GF(2^8).
|
||||
*
|
||||
* The Galois Field in which coefficient arithmetic is performed are
|
||||
* the polynomials over Z_2 (i.e., 0 and 1) modulo the irreducible
|
||||
* polynomial f(r), where f(r)=r^8 + r^7 + r^2 + r + 1. A polynomial
|
||||
* is represented as a byte with the MSB as the coefficient of r^7 and
|
||||
* the LSB as the coefficient of r^0. For example, the binary
|
||||
* representation of f(x) is 0x187 (of course, this doesn't fit into 8
|
||||
* bits). In this field, the polynomial r is a primitive element.
|
||||
* That is, r^i with i in 0,...,255 enumerates all elements in the
|
||||
* field.
|
||||
*
|
||||
* The generator polynomial for the QIC-80 ECC is
|
||||
*
|
||||
* g(x) = x^3 + r^105*x^2 + r^105*x + 1
|
||||
*
|
||||
* which can be factored into:
|
||||
*
|
||||
* g(x) = (x-r^-1)(x-r^0)(x-r^1)
|
||||
*
|
||||
* the byte representation of the coefficients are:
|
||||
*
|
||||
* r^105 = 0xc0
|
||||
* r^-1 = 0xc3
|
||||
* r^0 = 0x01
|
||||
* r^1 = 0x02
|
||||
*
|
||||
* Notice that r^-1 = r^254 as exponent arithmetic is performed
|
||||
* modulo 2^8-1 = 255.
|
||||
*
|
||||
* For more information on Galois Fields and Reed-Solomon codes, refer
|
||||
* to any good book. I found _An Introduction to Error Correcting
|
||||
* Codes with Applications_ by S. A. Vanstone and P. C. van Oorschot
|
||||
* to be a good introduction into the former. _CODING THEORY: The
|
||||
* Essentials_ I found very useful for its concise description of
|
||||
* Reed-Solomon encoding/decoding.
|
||||
*
|
||||
*/
|
||||
|
||||
typedef __u8 Matrix[3][3];
|
||||
|
||||
/*
|
||||
* gfpow[] is defined such that gfpow[i] returns r^i if
|
||||
* i is in the range [0..255].
|
||||
*/
|
||||
static const __u8 gfpow[] =
|
||||
{
|
||||
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
|
||||
0x87, 0x89, 0x95, 0xad, 0xdd, 0x3d, 0x7a, 0xf4,
|
||||
0x6f, 0xde, 0x3b, 0x76, 0xec, 0x5f, 0xbe, 0xfb,
|
||||
0x71, 0xe2, 0x43, 0x86, 0x8b, 0x91, 0xa5, 0xcd,
|
||||
0x1d, 0x3a, 0x74, 0xe8, 0x57, 0xae, 0xdb, 0x31,
|
||||
0x62, 0xc4, 0x0f, 0x1e, 0x3c, 0x78, 0xf0, 0x67,
|
||||
0xce, 0x1b, 0x36, 0x6c, 0xd8, 0x37, 0x6e, 0xdc,
|
||||
0x3f, 0x7e, 0xfc, 0x7f, 0xfe, 0x7b, 0xf6, 0x6b,
|
||||
0xd6, 0x2b, 0x56, 0xac, 0xdf, 0x39, 0x72, 0xe4,
|
||||
0x4f, 0x9e, 0xbb, 0xf1, 0x65, 0xca, 0x13, 0x26,
|
||||
0x4c, 0x98, 0xb7, 0xe9, 0x55, 0xaa, 0xd3, 0x21,
|
||||
0x42, 0x84, 0x8f, 0x99, 0xb5, 0xed, 0x5d, 0xba,
|
||||
0xf3, 0x61, 0xc2, 0x03, 0x06, 0x0c, 0x18, 0x30,
|
||||
0x60, 0xc0, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0,
|
||||
0x47, 0x8e, 0x9b, 0xb1, 0xe5, 0x4d, 0x9a, 0xb3,
|
||||
0xe1, 0x45, 0x8a, 0x93, 0xa1, 0xc5, 0x0d, 0x1a,
|
||||
0x34, 0x68, 0xd0, 0x27, 0x4e, 0x9c, 0xbf, 0xf9,
|
||||
0x75, 0xea, 0x53, 0xa6, 0xcb, 0x11, 0x22, 0x44,
|
||||
0x88, 0x97, 0xa9, 0xd5, 0x2d, 0x5a, 0xb4, 0xef,
|
||||
0x59, 0xb2, 0xe3, 0x41, 0x82, 0x83, 0x81, 0x85,
|
||||
0x8d, 0x9d, 0xbd, 0xfd, 0x7d, 0xfa, 0x73, 0xe6,
|
||||
0x4b, 0x96, 0xab, 0xd1, 0x25, 0x4a, 0x94, 0xaf,
|
||||
0xd9, 0x35, 0x6a, 0xd4, 0x2f, 0x5e, 0xbc, 0xff,
|
||||
0x79, 0xf2, 0x63, 0xc6, 0x0b, 0x16, 0x2c, 0x58,
|
||||
0xb0, 0xe7, 0x49, 0x92, 0xa3, 0xc1, 0x05, 0x0a,
|
||||
0x14, 0x28, 0x50, 0xa0, 0xc7, 0x09, 0x12, 0x24,
|
||||
0x48, 0x90, 0xa7, 0xc9, 0x15, 0x2a, 0x54, 0xa8,
|
||||
0xd7, 0x29, 0x52, 0xa4, 0xcf, 0x19, 0x32, 0x64,
|
||||
0xc8, 0x17, 0x2e, 0x5c, 0xb8, 0xf7, 0x69, 0xd2,
|
||||
0x23, 0x46, 0x8c, 0x9f, 0xb9, 0xf5, 0x6d, 0xda,
|
||||
0x33, 0x66, 0xcc, 0x1f, 0x3e, 0x7c, 0xf8, 0x77,
|
||||
0xee, 0x5b, 0xb6, 0xeb, 0x51, 0xa2, 0xc3, 0x01
|
||||
};
|
||||
|
||||
/*
|
||||
* This is a log table. That is, gflog[r^i] returns i (modulo f(r)).
|
||||
* gflog[0] is undefined and the first element is therefore not valid.
|
||||
*/
|
||||
static const __u8 gflog[256] =
|
||||
{
|
||||
0xff, 0x00, 0x01, 0x63, 0x02, 0xc6, 0x64, 0x6a,
|
||||
0x03, 0xcd, 0xc7, 0xbc, 0x65, 0x7e, 0x6b, 0x2a,
|
||||
0x04, 0x8d, 0xce, 0x4e, 0xc8, 0xd4, 0xbd, 0xe1,
|
||||
0x66, 0xdd, 0x7f, 0x31, 0x6c, 0x20, 0x2b, 0xf3,
|
||||
0x05, 0x57, 0x8e, 0xe8, 0xcf, 0xac, 0x4f, 0x83,
|
||||
0xc9, 0xd9, 0xd5, 0x41, 0xbe, 0x94, 0xe2, 0xb4,
|
||||
0x67, 0x27, 0xde, 0xf0, 0x80, 0xb1, 0x32, 0x35,
|
||||
0x6d, 0x45, 0x21, 0x12, 0x2c, 0x0d, 0xf4, 0x38,
|
||||
0x06, 0x9b, 0x58, 0x1a, 0x8f, 0x79, 0xe9, 0x70,
|
||||
0xd0, 0xc2, 0xad, 0xa8, 0x50, 0x75, 0x84, 0x48,
|
||||
0xca, 0xfc, 0xda, 0x8a, 0xd6, 0x54, 0x42, 0x24,
|
||||
0xbf, 0x98, 0x95, 0xf9, 0xe3, 0x5e, 0xb5, 0x15,
|
||||
0x68, 0x61, 0x28, 0xba, 0xdf, 0x4c, 0xf1, 0x2f,
|
||||
0x81, 0xe6, 0xb2, 0x3f, 0x33, 0xee, 0x36, 0x10,
|
||||
0x6e, 0x18, 0x46, 0xa6, 0x22, 0x88, 0x13, 0xf7,
|
||||
0x2d, 0xb8, 0x0e, 0x3d, 0xf5, 0xa4, 0x39, 0x3b,
|
||||
0x07, 0x9e, 0x9c, 0x9d, 0x59, 0x9f, 0x1b, 0x08,
|
||||
0x90, 0x09, 0x7a, 0x1c, 0xea, 0xa0, 0x71, 0x5a,
|
||||
0xd1, 0x1d, 0xc3, 0x7b, 0xae, 0x0a, 0xa9, 0x91,
|
||||
0x51, 0x5b, 0x76, 0x72, 0x85, 0xa1, 0x49, 0xeb,
|
||||
0xcb, 0x7c, 0xfd, 0xc4, 0xdb, 0x1e, 0x8b, 0xd2,
|
||||
0xd7, 0x92, 0x55, 0xaa, 0x43, 0x0b, 0x25, 0xaf,
|
||||
0xc0, 0x73, 0x99, 0x77, 0x96, 0x5c, 0xfa, 0x52,
|
||||
0xe4, 0xec, 0x5f, 0x4a, 0xb6, 0xa2, 0x16, 0x86,
|
||||
0x69, 0xc5, 0x62, 0xfe, 0x29, 0x7d, 0xbb, 0xcc,
|
||||
0xe0, 0xd3, 0x4d, 0x8c, 0xf2, 0x1f, 0x30, 0xdc,
|
||||
0x82, 0xab, 0xe7, 0x56, 0xb3, 0x93, 0x40, 0xd8,
|
||||
0x34, 0xb0, 0xef, 0x26, 0x37, 0x0c, 0x11, 0x44,
|
||||
0x6f, 0x78, 0x19, 0x9a, 0x47, 0x74, 0xa7, 0xc1,
|
||||
0x23, 0x53, 0x89, 0xfb, 0x14, 0x5d, 0xf8, 0x97,
|
||||
0x2e, 0x4b, 0xb9, 0x60, 0x0f, 0xed, 0x3e, 0xe5,
|
||||
0xf6, 0x87, 0xa5, 0x17, 0x3a, 0xa3, 0x3c, 0xb7
|
||||
};
|
||||
|
||||
/* This is a multiplication table for the factor 0xc0 (i.e., r^105 (mod f(r)).
|
||||
* gfmul_c0[f] returns r^105 * f(r) (modulo f(r)).
|
||||
*/
|
||||
static const __u8 gfmul_c0[256] =
|
||||
{
|
||||
0x00, 0xc0, 0x07, 0xc7, 0x0e, 0xce, 0x09, 0xc9,
|
||||
0x1c, 0xdc, 0x1b, 0xdb, 0x12, 0xd2, 0x15, 0xd5,
|
||||
0x38, 0xf8, 0x3f, 0xff, 0x36, 0xf6, 0x31, 0xf1,
|
||||
0x24, 0xe4, 0x23, 0xe3, 0x2a, 0xea, 0x2d, 0xed,
|
||||
0x70, 0xb0, 0x77, 0xb7, 0x7e, 0xbe, 0x79, 0xb9,
|
||||
0x6c, 0xac, 0x6b, 0xab, 0x62, 0xa2, 0x65, 0xa5,
|
||||
0x48, 0x88, 0x4f, 0x8f, 0x46, 0x86, 0x41, 0x81,
|
||||
0x54, 0x94, 0x53, 0x93, 0x5a, 0x9a, 0x5d, 0x9d,
|
||||
0xe0, 0x20, 0xe7, 0x27, 0xee, 0x2e, 0xe9, 0x29,
|
||||
0xfc, 0x3c, 0xfb, 0x3b, 0xf2, 0x32, 0xf5, 0x35,
|
||||
0xd8, 0x18, 0xdf, 0x1f, 0xd6, 0x16, 0xd1, 0x11,
|
||||
0xc4, 0x04, 0xc3, 0x03, 0xca, 0x0a, 0xcd, 0x0d,
|
||||
0x90, 0x50, 0x97, 0x57, 0x9e, 0x5e, 0x99, 0x59,
|
||||
0x8c, 0x4c, 0x8b, 0x4b, 0x82, 0x42, 0x85, 0x45,
|
||||
0xa8, 0x68, 0xaf, 0x6f, 0xa6, 0x66, 0xa1, 0x61,
|
||||
0xb4, 0x74, 0xb3, 0x73, 0xba, 0x7a, 0xbd, 0x7d,
|
||||
0x47, 0x87, 0x40, 0x80, 0x49, 0x89, 0x4e, 0x8e,
|
||||
0x5b, 0x9b, 0x5c, 0x9c, 0x55, 0x95, 0x52, 0x92,
|
||||
0x7f, 0xbf, 0x78, 0xb8, 0x71, 0xb1, 0x76, 0xb6,
|
||||
0x63, 0xa3, 0x64, 0xa4, 0x6d, 0xad, 0x6a, 0xaa,
|
||||
0x37, 0xf7, 0x30, 0xf0, 0x39, 0xf9, 0x3e, 0xfe,
|
||||
0x2b, 0xeb, 0x2c, 0xec, 0x25, 0xe5, 0x22, 0xe2,
|
||||
0x0f, 0xcf, 0x08, 0xc8, 0x01, 0xc1, 0x06, 0xc6,
|
||||
0x13, 0xd3, 0x14, 0xd4, 0x1d, 0xdd, 0x1a, 0xda,
|
||||
0xa7, 0x67, 0xa0, 0x60, 0xa9, 0x69, 0xae, 0x6e,
|
||||
0xbb, 0x7b, 0xbc, 0x7c, 0xb5, 0x75, 0xb2, 0x72,
|
||||
0x9f, 0x5f, 0x98, 0x58, 0x91, 0x51, 0x96, 0x56,
|
||||
0x83, 0x43, 0x84, 0x44, 0x8d, 0x4d, 0x8a, 0x4a,
|
||||
0xd7, 0x17, 0xd0, 0x10, 0xd9, 0x19, 0xde, 0x1e,
|
||||
0xcb, 0x0b, 0xcc, 0x0c, 0xc5, 0x05, 0xc2, 0x02,
|
||||
0xef, 0x2f, 0xe8, 0x28, 0xe1, 0x21, 0xe6, 0x26,
|
||||
0xf3, 0x33, 0xf4, 0x34, 0xfd, 0x3d, 0xfa, 0x3a
|
||||
};
|
||||
|
||||
|
||||
/* Returns V modulo 255 provided V is in the range -255,-254,...,509.
|
||||
*/
|
||||
static inline __u8 mod255(int v)
|
||||
{
|
||||
if (v > 0) {
|
||||
if (v < 255) {
|
||||
return v;
|
||||
} else {
|
||||
return v - 255;
|
||||
}
|
||||
} else {
|
||||
return v + 255;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Add two numbers in the field. Addition in this field is equivalent
|
||||
* to a bit-wise exclusive OR operation---subtraction is therefore
|
||||
* identical to addition.
|
||||
*/
|
||||
static inline __u8 gfadd(__u8 a, __u8 b)
|
||||
{
|
||||
return a ^ b;
|
||||
}
|
||||
|
||||
|
||||
/* Add two vectors of numbers in the field. Each byte in A and B gets
|
||||
* added individually.
|
||||
*/
|
||||
static inline unsigned long gfadd_long(unsigned long a, unsigned long b)
|
||||
{
|
||||
return a ^ b;
|
||||
}
|
||||
|
||||
|
||||
/* Multiply two numbers in the field:
|
||||
*/
|
||||
static inline __u8 gfmul(__u8 a, __u8 b)
|
||||
{
|
||||
if (a && b) {
|
||||
return gfpow[mod255(gflog[a] + gflog[b])];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Just like gfmul, except we have already looked up the log of the
|
||||
* second number.
|
||||
*/
|
||||
static inline __u8 gfmul_exp(__u8 a, int b)
|
||||
{
|
||||
if (a) {
|
||||
return gfpow[mod255(gflog[a] + b)];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Just like gfmul_exp, except that A is a vector of numbers. That
|
||||
* is, each byte in A gets multiplied by gfpow[mod255(B)].
|
||||
*/
|
||||
static inline unsigned long gfmul_exp_long(unsigned long a, int b)
|
||||
{
|
||||
__u8 t;
|
||||
|
||||
if (sizeof(long) == 4) {
|
||||
return (
|
||||
((t = (__u32)a >> 24 & 0xff) ?
|
||||
(((__u32) gfpow[mod255(gflog[t] + b)]) << 24) : 0) |
|
||||
((t = (__u32)a >> 16 & 0xff) ?
|
||||
(((__u32) gfpow[mod255(gflog[t] + b)]) << 16) : 0) |
|
||||
((t = (__u32)a >> 8 & 0xff) ?
|
||||
(((__u32) gfpow[mod255(gflog[t] + b)]) << 8) : 0) |
|
||||
((t = (__u32)a >> 0 & 0xff) ?
|
||||
(((__u32) gfpow[mod255(gflog[t] + b)]) << 0) : 0));
|
||||
} else if (sizeof(long) == 8) {
|
||||
return (
|
||||
((t = (__u64)a >> 56 & 0xff) ?
|
||||
(((__u64) gfpow[mod255(gflog[t] + b)]) << 56) : 0) |
|
||||
((t = (__u64)a >> 48 & 0xff) ?
|
||||
(((__u64) gfpow[mod255(gflog[t] + b)]) << 48) : 0) |
|
||||
((t = (__u64)a >> 40 & 0xff) ?
|
||||
(((__u64) gfpow[mod255(gflog[t] + b)]) << 40) : 0) |
|
||||
((t = (__u64)a >> 32 & 0xff) ?
|
||||
(((__u64) gfpow[mod255(gflog[t] + b)]) << 32) : 0) |
|
||||
((t = (__u64)a >> 24 & 0xff) ?
|
||||
(((__u64) gfpow[mod255(gflog[t] + b)]) << 24) : 0) |
|
||||
((t = (__u64)a >> 16 & 0xff) ?
|
||||
(((__u64) gfpow[mod255(gflog[t] + b)]) << 16) : 0) |
|
||||
((t = (__u64)a >> 8 & 0xff) ?
|
||||
(((__u64) gfpow[mod255(gflog[t] + b)]) << 8) : 0) |
|
||||
((t = (__u64)a >> 0 & 0xff) ?
|
||||
(((__u64) gfpow[mod255(gflog[t] + b)]) << 0) : 0));
|
||||
} else {
|
||||
TRACE_FUN(ft_t_any);
|
||||
TRACE_ABORT(-1, ft_t_err, "Error: size of long is %d bytes",
|
||||
(int)sizeof(long));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Divide two numbers in the field. Returns a/b (modulo f(x)).
|
||||
*/
|
||||
static inline __u8 gfdiv(__u8 a, __u8 b)
|
||||
{
|
||||
if (!b) {
|
||||
TRACE_FUN(ft_t_any);
|
||||
TRACE_ABORT(0xff, ft_t_bug, "Error: division by zero");
|
||||
} else if (a == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return gfpow[mod255(gflog[a] - gflog[b])];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* The following functions return the inverse of the matrix of the
|
||||
* linear system that needs to be solved to determine the error
|
||||
* magnitudes. The first deals with matrices of rank 3, while the
|
||||
* second deals with matrices of rank 2. The error indices are passed
|
||||
* in arguments L0,..,L2 (0=first sector, 31=last sector). The error
|
||||
* indices must be sorted in ascending order, i.e., L0<L1<L2.
|
||||
*
|
||||
* The linear system that needs to be solved for the error magnitudes
|
||||
* is A * b = s, where s is the known vector of syndromes, b is the
|
||||
* vector of error magnitudes and A in the ORDER=3 case:
|
||||
*
|
||||
* A_3 = {{1/r^L[0], 1/r^L[1], 1/r^L[2]},
|
||||
* { 1, 1, 1},
|
||||
* { r^L[0], r^L[1], r^L[2]}}
|
||||
*/
|
||||
static inline int gfinv3(__u8 l0,
|
||||
__u8 l1,
|
||||
__u8 l2,
|
||||
Matrix Ainv)
|
||||
{
|
||||
__u8 det;
|
||||
__u8 t20, t10, t21, t12, t01, t02;
|
||||
int log_det;
|
||||
|
||||
/* compute some intermediate results: */
|
||||
t20 = gfpow[l2 - l0]; /* t20 = r^l2/r^l0 */
|
||||
t10 = gfpow[l1 - l0]; /* t10 = r^l1/r^l0 */
|
||||
t21 = gfpow[l2 - l1]; /* t21 = r^l2/r^l1 */
|
||||
t12 = gfpow[l1 - l2 + 255]; /* t12 = r^l1/r^l2 */
|
||||
t01 = gfpow[l0 - l1 + 255]; /* t01 = r^l0/r^l1 */
|
||||
t02 = gfpow[l0 - l2 + 255]; /* t02 = r^l0/r^l2 */
|
||||
/* Calculate the determinant of matrix A_3^-1 (sometimes
|
||||
* called the Vandermonde determinant):
|
||||
*/
|
||||
det = gfadd(t20, gfadd(t10, gfadd(t21, gfadd(t12, gfadd(t01, t02)))));
|
||||
if (!det) {
|
||||
TRACE_FUN(ft_t_any);
|
||||
TRACE_ABORT(0, ft_t_err,
|
||||
"Inversion failed (3 CRC errors, >0 CRC failures)");
|
||||
}
|
||||
log_det = 255 - gflog[det];
|
||||
|
||||
/* Now, calculate all of the coefficients:
|
||||
*/
|
||||
Ainv[0][0]= gfmul_exp(gfadd(gfpow[l1], gfpow[l2]), log_det);
|
||||
Ainv[0][1]= gfmul_exp(gfadd(t21, t12), log_det);
|
||||
Ainv[0][2]= gfmul_exp(gfadd(gfpow[255 - l1], gfpow[255 - l2]),log_det);
|
||||
|
||||
Ainv[1][0]= gfmul_exp(gfadd(gfpow[l0], gfpow[l2]), log_det);
|
||||
Ainv[1][1]= gfmul_exp(gfadd(t20, t02), log_det);
|
||||
Ainv[1][2]= gfmul_exp(gfadd(gfpow[255 - l0], gfpow[255 - l2]),log_det);
|
||||
|
||||
Ainv[2][0]= gfmul_exp(gfadd(gfpow[l0], gfpow[l1]), log_det);
|
||||
Ainv[2][1]= gfmul_exp(gfadd(t10, t01), log_det);
|
||||
Ainv[2][2]= gfmul_exp(gfadd(gfpow[255 - l0], gfpow[255 - l1]),log_det);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static inline int gfinv2(__u8 l0, __u8 l1, Matrix Ainv)
|
||||
{
|
||||
__u8 det;
|
||||
__u8 t1, t2;
|
||||
int log_det;
|
||||
|
||||
t1 = gfpow[255 - l0];
|
||||
t2 = gfpow[255 - l1];
|
||||
det = gfadd(t1, t2);
|
||||
if (!det) {
|
||||
TRACE_FUN(ft_t_any);
|
||||
TRACE_ABORT(0, ft_t_err,
|
||||
"Inversion failed (2 CRC errors, >0 CRC failures)");
|
||||
}
|
||||
log_det = 255 - gflog[det];
|
||||
|
||||
/* Now, calculate all of the coefficients:
|
||||
*/
|
||||
Ainv[0][0] = Ainv[1][0] = gfpow[log_det];
|
||||
|
||||
Ainv[0][1] = gfmul_exp(t2, log_det);
|
||||
Ainv[1][1] = gfmul_exp(t1, log_det);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Multiply matrix A by vector S and return result in vector B. M is
|
||||
* assumed to be of order NxN, S and B of order Nx1.
|
||||
*/
|
||||
static inline void gfmat_mul(int n, Matrix A,
|
||||
__u8 *s, __u8 *b)
|
||||
{
|
||||
int i, j;
|
||||
__u8 dot_prod;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
dot_prod = 0;
|
||||
for (j = 0; j < n; ++j) {
|
||||
dot_prod = gfadd(dot_prod, gfmul(A[i][j], s[j]));
|
||||
}
|
||||
b[i] = dot_prod;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* The Reed Solomon ECC codes are computed over the N-th byte of each
|
||||
* block, where N=SECTOR_SIZE. There are up to 29 blocks of data, and
|
||||
* 3 blocks of ECC. The blocks are stored contiguously in memory. A
|
||||
* segment, consequently, is assumed to have at least 4 blocks: one or
|
||||
* more data blocks plus three ECC blocks.
|
||||
*
|
||||
* Notice: In QIC-80 speak, a CRC error is a sector with an incorrect
|
||||
* CRC. A CRC failure is a sector with incorrect data, but
|
||||
* a valid CRC. In the error control literature, the former
|
||||
* is usually called "erasure", the latter "error."
|
||||
*/
|
||||
/* Compute the parity bytes for C columns of data, where C is the
|
||||
* number of bytes that fit into a long integer. We use a linear
|
||||
* feed-back register to do this. The parity bytes P[0], P[STRIDE],
|
||||
* P[2*STRIDE] are computed such that:
|
||||
*
|
||||
* x^k * p(x) + m(x) = 0 (modulo g(x))
|
||||
*
|
||||
* where k = NBLOCKS,
|
||||
* p(x) = P[0] + P[STRIDE]*x + P[2*STRIDE]*x^2, and
|
||||
* m(x) = sum_{i=0}^k m_i*x^i.
|
||||
* m_i = DATA[i*SECTOR_SIZE]
|
||||
*/
|
||||
static inline void set_parity(unsigned long *data,
|
||||
int nblocks,
|
||||
unsigned long *p,
|
||||
int stride)
|
||||
{
|
||||
unsigned long p0, p1, p2, t1, t2, *end;
|
||||
|
||||
end = data + nblocks * (FT_SECTOR_SIZE / sizeof(long));
|
||||
p0 = p1 = p2 = 0;
|
||||
while (data < end) {
|
||||
/* The new parity bytes p0_i, p1_i, p2_i are computed
|
||||
* from the old values p0_{i-1}, p1_{i-1}, p2_{i-1}
|
||||
* recursively as:
|
||||
*
|
||||
* p0_i = p1_{i-1} + r^105 * (m_{i-1} - p0_{i-1})
|
||||
* p1_i = p2_{i-1} + r^105 * (m_{i-1} - p0_{i-1})
|
||||
* p2_i = (m_{i-1} - p0_{i-1})
|
||||
*
|
||||
* With the initial condition: p0_0 = p1_0 = p2_0 = 0.
|
||||
*/
|
||||
t1 = gfadd_long(*data, p0);
|
||||
/*
|
||||
* Multiply each byte in t1 by 0xc0:
|
||||
*/
|
||||
if (sizeof(long) == 4) {
|
||||
t2= (((__u32) gfmul_c0[(__u32)t1 >> 24 & 0xff]) << 24 |
|
||||
((__u32) gfmul_c0[(__u32)t1 >> 16 & 0xff]) << 16 |
|
||||
((__u32) gfmul_c0[(__u32)t1 >> 8 & 0xff]) << 8 |
|
||||
((__u32) gfmul_c0[(__u32)t1 >> 0 & 0xff]) << 0);
|
||||
} else if (sizeof(long) == 8) {
|
||||
t2= (((__u64) gfmul_c0[(__u64)t1 >> 56 & 0xff]) << 56 |
|
||||
((__u64) gfmul_c0[(__u64)t1 >> 48 & 0xff]) << 48 |
|
||||
((__u64) gfmul_c0[(__u64)t1 >> 40 & 0xff]) << 40 |
|
||||
((__u64) gfmul_c0[(__u64)t1 >> 32 & 0xff]) << 32 |
|
||||
((__u64) gfmul_c0[(__u64)t1 >> 24 & 0xff]) << 24 |
|
||||
((__u64) gfmul_c0[(__u64)t1 >> 16 & 0xff]) << 16 |
|
||||
((__u64) gfmul_c0[(__u64)t1 >> 8 & 0xff]) << 8 |
|
||||
((__u64) gfmul_c0[(__u64)t1 >> 0 & 0xff]) << 0);
|
||||
} else {
|
||||
TRACE_FUN(ft_t_any);
|
||||
TRACE(ft_t_err, "Error: long is of size %d",
|
||||
(int) sizeof(long));
|
||||
TRACE_EXIT;
|
||||
}
|
||||
p0 = gfadd_long(t2, p1);
|
||||
p1 = gfadd_long(t2, p2);
|
||||
p2 = t1;
|
||||
data += FT_SECTOR_SIZE / sizeof(long);
|
||||
}
|
||||
*p = p0;
|
||||
p += stride;
|
||||
*p = p1;
|
||||
p += stride;
|
||||
*p = p2;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Compute the 3 syndrome values. DATA should point to the first byte
|
||||
* of the column for which the syndromes are desired. The syndromes
|
||||
* are computed over the first NBLOCKS of rows. The three bytes will
|
||||
* be placed in S[0], S[1], and S[2].
|
||||
*
|
||||
* S[i] is the value of the "message" polynomial m(x) evaluated at the
|
||||
* i-th root of the generator polynomial g(x).
|
||||
*
|
||||
* As g(x)=(x-r^-1)(x-1)(x-r^1) we evaluate the message polynomial at
|
||||
* x=r^-1 to get S[0], at x=r^0=1 to get S[1], and at x=r to get S[2].
|
||||
* This could be done directly and efficiently via the Horner scheme.
|
||||
* However, it would require multiplication tables for the factors
|
||||
* r^-1 (0xc3) and r (0x02). The following scheme does not require
|
||||
* any multiplication tables beyond what's needed for set_parity()
|
||||
* anyway and is slightly faster if there are no errors and slightly
|
||||
* slower if there are errors. The latter is hopefully the infrequent
|
||||
* case.
|
||||
*
|
||||
* To understand the alternative algorithm, notice that set_parity(m,
|
||||
* k, p) computes parity bytes such that:
|
||||
*
|
||||
* x^k * p(x) = m(x) (modulo g(x)).
|
||||
*
|
||||
* That is, to evaluate m(r^m), where r^m is a root of g(x), we can
|
||||
* simply evaluate (r^m)^k*p(r^m). Also, notice that p is 0 if and
|
||||
* only if s is zero. That is, if all parity bytes are 0, we know
|
||||
* there is no error in the data and consequently there is no need to
|
||||
* compute s(x) at all! In all other cases, we compute s(x) from p(x)
|
||||
* by evaluating (r^m)^k*p(r^m) for m=-1, m=0, and m=1. The p(x)
|
||||
* polynomial is evaluated via the Horner scheme.
|
||||
*/
|
||||
static int compute_syndromes(unsigned long *data, int nblocks, unsigned long *s)
|
||||
{
|
||||
unsigned long p[3];
|
||||
|
||||
set_parity(data, nblocks, p, 1);
|
||||
if (p[0] | p[1] | p[2]) {
|
||||
/* Some of the checked columns do not have a zero
|
||||
* syndrome. For simplicity, we compute the syndromes
|
||||
* for all columns that we have computed the
|
||||
* remainders for.
|
||||
*/
|
||||
s[0] = gfmul_exp_long(
|
||||
gfadd_long(p[0],
|
||||
gfmul_exp_long(
|
||||
gfadd_long(p[1],
|
||||
gfmul_exp_long(p[2], -1)),
|
||||
-1)),
|
||||
-nblocks);
|
||||
s[1] = gfadd_long(gfadd_long(p[2], p[1]), p[0]);
|
||||
s[2] = gfmul_exp_long(
|
||||
gfadd_long(p[0],
|
||||
gfmul_exp_long(
|
||||
gfadd_long(p[1],
|
||||
gfmul_exp_long(p[2], 1)),
|
||||
1)),
|
||||
nblocks);
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Correct the block in the column pointed to by DATA. There are NBAD
|
||||
* CRC errors and their indices are in BAD_LOC[0], up to
|
||||
* BAD_LOC[NBAD-1]. If NBAD>1, Ainv holds the inverse of the matrix
|
||||
* of the linear system that needs to be solved to determine the error
|
||||
* magnitudes. S[0], S[1], and S[2] are the syndrome values. If row
|
||||
* j gets corrected, then bit j will be set in CORRECTION_MAP.
|
||||
*/
|
||||
static inline int correct_block(__u8 *data, int nblocks,
|
||||
int nbad, int *bad_loc, Matrix Ainv,
|
||||
__u8 *s,
|
||||
SectorMap * correction_map)
|
||||
{
|
||||
int ncorrected = 0;
|
||||
int i;
|
||||
__u8 t1, t2;
|
||||
__u8 c0, c1, c2; /* check bytes */
|
||||
__u8 error_mag[3], log_error_mag;
|
||||
__u8 *dp, l, e;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
switch (nbad) {
|
||||
case 0:
|
||||
/* might have a CRC failure: */
|
||||
if (s[0] == 0) {
|
||||
/* more than one error */
|
||||
TRACE_ABORT(-1, ft_t_err,
|
||||
"ECC failed (0 CRC errors, >1 CRC failures)");
|
||||
}
|
||||
t1 = gfdiv(s[1], s[0]);
|
||||
if ((bad_loc[nbad++] = gflog[t1]) >= nblocks) {
|
||||
TRACE(ft_t_err,
|
||||
"ECC failed (0 CRC errors, >1 CRC failures)");
|
||||
TRACE_ABORT(-1, ft_t_err,
|
||||
"attempt to correct data at %d", bad_loc[0]);
|
||||
}
|
||||
error_mag[0] = s[1];
|
||||
break;
|
||||
case 1:
|
||||
t1 = gfadd(gfmul_exp(s[1], bad_loc[0]), s[2]);
|
||||
t2 = gfadd(gfmul_exp(s[0], bad_loc[0]), s[1]);
|
||||
if (t1 == 0 && t2 == 0) {
|
||||
/* one erasure, no error: */
|
||||
Ainv[0][0] = gfpow[bad_loc[0]];
|
||||
} else if (t1 == 0 || t2 == 0) {
|
||||
/* one erasure and more than one error: */
|
||||
TRACE_ABORT(-1, ft_t_err,
|
||||
"ECC failed (1 erasure, >1 error)");
|
||||
} else {
|
||||
/* one erasure, one error: */
|
||||
if ((bad_loc[nbad++] = gflog[gfdiv(t1, t2)])
|
||||
>= nblocks) {
|
||||
TRACE(ft_t_err, "ECC failed "
|
||||
"(1 CRC errors, >1 CRC failures)");
|
||||
TRACE_ABORT(-1, ft_t_err,
|
||||
"attempt to correct data at %d",
|
||||
bad_loc[1]);
|
||||
}
|
||||
if (!gfinv2(bad_loc[0], bad_loc[1], Ainv)) {
|
||||
/* inversion failed---must have more
|
||||
* than one error
|
||||
*/
|
||||
TRACE_EXIT -1;
|
||||
}
|
||||
}
|
||||
/* FALL THROUGH TO ERROR MAGNITUDE COMPUTATION:
|
||||
*/
|
||||
case 2:
|
||||
case 3:
|
||||
/* compute error magnitudes: */
|
||||
gfmat_mul(nbad, Ainv, s, error_mag);
|
||||
break;
|
||||
|
||||
default:
|
||||
TRACE_ABORT(-1, ft_t_err,
|
||||
"Internal Error: number of CRC errors > 3");
|
||||
}
|
||||
|
||||
/* Perform correction by adding ERROR_MAG[i] to the byte at
|
||||
* offset BAD_LOC[i]. Also add the value of the computed
|
||||
* error polynomial to the syndrome values. If the correction
|
||||
* was successful, the resulting check bytes should be zero
|
||||
* (i.e., the corrected data is a valid code word).
|
||||
*/
|
||||
c0 = s[0];
|
||||
c1 = s[1];
|
||||
c2 = s[2];
|
||||
for (i = 0; i < nbad; ++i) {
|
||||
e = error_mag[i];
|
||||
if (e) {
|
||||
/* correct the byte at offset L by magnitude E: */
|
||||
l = bad_loc[i];
|
||||
dp = &data[l * FT_SECTOR_SIZE];
|
||||
*dp = gfadd(*dp, e);
|
||||
*correction_map |= 1 << l;
|
||||
++ncorrected;
|
||||
|
||||
log_error_mag = gflog[e];
|
||||
c0 = gfadd(c0, gfpow[mod255(log_error_mag - l)]);
|
||||
c1 = gfadd(c1, e);
|
||||
c2 = gfadd(c2, gfpow[mod255(log_error_mag + l)]);
|
||||
}
|
||||
}
|
||||
if (c0 || c1 || c2) {
|
||||
TRACE_ABORT(-1, ft_t_err,
|
||||
"ECC self-check failed, too many errors");
|
||||
}
|
||||
TRACE_EXIT ncorrected;
|
||||
}
|
||||
|
||||
|
||||
#if defined(ECC_SANITY_CHECK) || defined(ECC_PARANOID)
|
||||
|
||||
/* Perform a sanity check on the computed parity bytes:
|
||||
*/
|
||||
static int sanity_check(unsigned long *data, int nblocks)
|
||||
{
|
||||
TRACE_FUN(ft_t_any);
|
||||
unsigned long s[3];
|
||||
|
||||
if (!compute_syndromes(data, nblocks, s)) {
|
||||
TRACE_ABORT(0, ft_bug,
|
||||
"Internal Error: syndrome self-check failed");
|
||||
}
|
||||
TRACE_EXIT 1;
|
||||
}
|
||||
|
||||
#endif /* defined(ECC_SANITY_CHECK) || defined(ECC_PARANOID) */
|
||||
|
||||
/* Compute the parity for an entire segment of data.
|
||||
*/
|
||||
int ftape_ecc_set_segment_parity(struct memory_segment *mseg)
|
||||
{
|
||||
int i;
|
||||
__u8 *parity_bytes;
|
||||
|
||||
parity_bytes = &mseg->data[(mseg->blocks - 3) * FT_SECTOR_SIZE];
|
||||
for (i = 0; i < FT_SECTOR_SIZE; i += sizeof(long)) {
|
||||
set_parity((unsigned long *) &mseg->data[i], mseg->blocks - 3,
|
||||
(unsigned long *) &parity_bytes[i],
|
||||
FT_SECTOR_SIZE / sizeof(long));
|
||||
#ifdef ECC_PARANOID
|
||||
if (!sanity_check((unsigned long *) &mseg->data[i],
|
||||
mseg->blocks)) {
|
||||
return -1;
|
||||
}
|
||||
#endif /* ECC_PARANOID */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Checks and corrects (if possible) the segment MSEG. Returns one of
|
||||
* ECC_OK, ECC_CORRECTED, and ECC_FAILED.
|
||||
*/
|
||||
int ftape_ecc_correct_data(struct memory_segment *mseg)
|
||||
{
|
||||
int col, i, result;
|
||||
int ncorrected = 0;
|
||||
int nerasures = 0; /* # of erasures (CRC errors) */
|
||||
int erasure_loc[3]; /* erasure locations */
|
||||
unsigned long ss[3];
|
||||
__u8 s[3];
|
||||
Matrix Ainv;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
mseg->corrected = 0;
|
||||
|
||||
/* find first column that has non-zero syndromes: */
|
||||
for (col = 0; col < FT_SECTOR_SIZE; col += sizeof(long)) {
|
||||
if (!compute_syndromes((unsigned long *) &mseg->data[col],
|
||||
mseg->blocks, ss)) {
|
||||
/* something is wrong---have to fix things */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (col >= FT_SECTOR_SIZE) {
|
||||
/* all syndromes are ok, therefore nothing to correct */
|
||||
TRACE_EXIT ECC_OK;
|
||||
}
|
||||
/* count the number of CRC errors if there were any: */
|
||||
if (mseg->read_bad) {
|
||||
for (i = 0; i < mseg->blocks; i++) {
|
||||
if (BAD_CHECK(mseg->read_bad, i)) {
|
||||
if (nerasures >= 3) {
|
||||
/* this is too much for ECC */
|
||||
TRACE_ABORT(ECC_FAILED, ft_t_err,
|
||||
"ECC failed (>3 CRC errors)");
|
||||
} /* if */
|
||||
erasure_loc[nerasures++] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If there are at least 2 CRC errors, determine inverse of matrix
|
||||
* of linear system to be solved:
|
||||
*/
|
||||
switch (nerasures) {
|
||||
case 2:
|
||||
if (!gfinv2(erasure_loc[0], erasure_loc[1], Ainv)) {
|
||||
TRACE_EXIT ECC_FAILED;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (!gfinv3(erasure_loc[0], erasure_loc[1],
|
||||
erasure_loc[2], Ainv)) {
|
||||
TRACE_EXIT ECC_FAILED;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* this is not an error condition... */
|
||||
break;
|
||||
}
|
||||
|
||||
do {
|
||||
for (i = 0; i < sizeof(long); ++i) {
|
||||
s[0] = ss[0];
|
||||
s[1] = ss[1];
|
||||
s[2] = ss[2];
|
||||
if (s[0] | s[1] | s[2]) {
|
||||
#ifdef BIG_ENDIAN
|
||||
result = correct_block(
|
||||
&mseg->data[col + sizeof(long) - 1 - i],
|
||||
mseg->blocks,
|
||||
nerasures,
|
||||
erasure_loc,
|
||||
Ainv,
|
||||
s,
|
||||
&mseg->corrected);
|
||||
#else
|
||||
result = correct_block(&mseg->data[col + i],
|
||||
mseg->blocks,
|
||||
nerasures,
|
||||
erasure_loc,
|
||||
Ainv,
|
||||
s,
|
||||
&mseg->corrected);
|
||||
#endif
|
||||
if (result < 0) {
|
||||
TRACE_EXIT ECC_FAILED;
|
||||
}
|
||||
ncorrected += result;
|
||||
}
|
||||
ss[0] >>= 8;
|
||||
ss[1] >>= 8;
|
||||
ss[2] >>= 8;
|
||||
}
|
||||
|
||||
#ifdef ECC_SANITY_CHECK
|
||||
if (!sanity_check((unsigned long *) &mseg->data[col],
|
||||
mseg->blocks)) {
|
||||
TRACE_EXIT ECC_FAILED;
|
||||
}
|
||||
#endif /* ECC_SANITY_CHECK */
|
||||
|
||||
/* find next column with non-zero syndromes: */
|
||||
while ((col += sizeof(long)) < FT_SECTOR_SIZE) {
|
||||
if (!compute_syndromes((unsigned long *)
|
||||
&mseg->data[col], mseg->blocks, ss)) {
|
||||
/* something is wrong---have to fix things */
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (col < FT_SECTOR_SIZE);
|
||||
if (ncorrected && nerasures == 0) {
|
||||
TRACE(ft_t_warn, "block contained error not caught by CRC");
|
||||
}
|
||||
TRACE((ncorrected > 0) ? ft_t_noise : ft_t_any, "number of corrections: %d", ncorrected);
|
||||
TRACE_EXIT ncorrected ? ECC_CORRECTED : ECC_OK;
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
#ifndef _FTAPE_ECC_H_
|
||||
#define _FTAPE_ECC_H_
|
||||
|
||||
/*
|
||||
* Copyright (C) 1993 Ning and David Mosberger.
|
||||
* Original:
|
||||
* Copyright (C) 1993 Bas Laarhoven.
|
||||
* Copyright (C) 1992 David L. Brown, Jr.
|
||||
|
||||
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/ftape/lowlevel/ftape-ecc.h,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:18:11 $
|
||||
*
|
||||
* This file contains the definitions for the
|
||||
* Reed-Solomon error correction code
|
||||
* for the QIC-40/80 tape streamer device driver.
|
||||
*/
|
||||
|
||||
#include "../lowlevel/ftape-bsm.h"
|
||||
|
||||
#define BAD_CLEAR(entry) ((entry)=0)
|
||||
#define BAD_SET(entry,sector) ((entry)|=(1<<(sector)))
|
||||
#define BAD_CHECK(entry,sector) ((entry)&(1<<(sector)))
|
||||
|
||||
/*
|
||||
* Return values for ecc_correct_data:
|
||||
*/
|
||||
enum {
|
||||
ECC_OK, /* Data was correct. */
|
||||
ECC_CORRECTED, /* Correctable error in data. */
|
||||
ECC_FAILED, /* Could not correct data. */
|
||||
};
|
||||
|
||||
/*
|
||||
* Representation of an in memory segment. MARKED_BAD lists the
|
||||
* sectors that were marked bad during formatting. If the N-th sector
|
||||
* in a segment is marked bad, bit 1<<N will be set in MARKED_BAD.
|
||||
* The sectors should be read in from the disk and packed, as if the
|
||||
* bad sectors were not there, and the segment just contained fewer
|
||||
* sectors. READ_SECTORS is a bitmap of errors encountered while
|
||||
* reading the data. These offsets are relative to the packed data.
|
||||
* BLOCKS is a count of the sectors not marked bad. This is just to
|
||||
* prevent having to count the zero bits in MARKED_BAD each time this
|
||||
* is needed. DATA is the actual sector packed data from (or to) the
|
||||
* tape.
|
||||
*/
|
||||
struct memory_segment {
|
||||
SectorMap marked_bad;
|
||||
SectorMap read_bad;
|
||||
int blocks;
|
||||
__u8 *data;
|
||||
SectorMap corrected;
|
||||
};
|
||||
|
||||
/*
|
||||
* ecc.c defined global variables:
|
||||
*/
|
||||
#ifdef TEST
|
||||
extern int ftape_ecc_tracing;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ecc.c defined global functions:
|
||||
*/
|
||||
extern int ftape_ecc_correct_data(struct memory_segment *data);
|
||||
extern int ftape_ecc_set_segment_parity(struct memory_segment *data);
|
||||
|
||||
#endif /* _FTAPE_ECC_H_ */
|
@ -1,344 +0,0 @@
|
||||
/*
|
||||
* Copyright (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/ftape/lowlevel/ftape-format.c,v $
|
||||
* $Revision: 1.2.4.1 $
|
||||
* $Date: 1997/11/14 16:05:39 $
|
||||
*
|
||||
* This file contains the code to support formatting of floppy
|
||||
* tape cartridges with the QIC-40/80/3010/3020 floppy-tape
|
||||
* driver "ftape" for Linux.
|
||||
*/
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
#include <linux/ftape.h>
|
||||
#include <linux/qic117.h>
|
||||
#include "../lowlevel/ftape-tracing.h"
|
||||
#include "../lowlevel/ftape-io.h"
|
||||
#include "../lowlevel/ftape-ctl.h"
|
||||
#include "../lowlevel/ftape-rw.h"
|
||||
#include "../lowlevel/ftape-ecc.h"
|
||||
#include "../lowlevel/ftape-bsm.h"
|
||||
#include "../lowlevel/ftape-format.h"
|
||||
|
||||
#if defined(TESTING)
|
||||
#define FT_FMT_SEGS_PER_BUF 50
|
||||
#else
|
||||
#define FT_FMT_SEGS_PER_BUF (FT_BUFF_SIZE/(4*FT_SECTORS_PER_SEGMENT))
|
||||
#endif
|
||||
|
||||
static spinlock_t ftape_format_lock;
|
||||
|
||||
/*
|
||||
* first segment of the new buffer
|
||||
*/
|
||||
static int switch_segment;
|
||||
|
||||
/*
|
||||
* at most 256 segments fit into one 32 kb buffer. Even TR-1 cartridges have
|
||||
* more than this many segments per track, so better be careful.
|
||||
*
|
||||
* buffer_struct *buff: buffer to store the formatting coordinates in
|
||||
* int start: starting segment for this buffer.
|
||||
* int spt: segments per track
|
||||
*
|
||||
* Note: segment ids are relative to the start of the track here.
|
||||
*/
|
||||
static void setup_format_buffer(buffer_struct *buff, int start, int spt,
|
||||
__u8 gap3)
|
||||
{
|
||||
int to_do = spt - start;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (to_do > FT_FMT_SEGS_PER_BUF) {
|
||||
to_do = FT_FMT_SEGS_PER_BUF;
|
||||
}
|
||||
buff->ptr = buff->address;
|
||||
buff->remaining = to_do * FT_SECTORS_PER_SEGMENT; /* # sectors */
|
||||
buff->bytes = buff->remaining * 4; /* need 4 bytes per sector */
|
||||
buff->gap3 = gap3;
|
||||
buff->segment_id = start;
|
||||
buff->next_segment = start + to_do;
|
||||
if (buff->next_segment >= spt) {
|
||||
buff->next_segment = 0; /* 0 means: stop runner */
|
||||
}
|
||||
buff->status = waiting; /* tells the isr that it can use
|
||||
* this buffer
|
||||
*/
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* start formatting a new track.
|
||||
*/
|
||||
int ftape_format_track(const unsigned int track, const __u8 gap3)
|
||||
{
|
||||
unsigned long flags;
|
||||
buffer_struct *tail, *head;
|
||||
int status;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
TRACE_CATCH(ftape_ready_wait(ftape_timeout.pause, &status),);
|
||||
if (track & 1) {
|
||||
if (!(status & QIC_STATUS_AT_EOT)) {
|
||||
TRACE_CATCH(ftape_seek_to_eot(),);
|
||||
}
|
||||
} else {
|
||||
if (!(status & QIC_STATUS_AT_BOT)) {
|
||||
TRACE_CATCH(ftape_seek_to_bot(),);
|
||||
}
|
||||
}
|
||||
ftape_abort_operation(); /* this sets ft_head = ft_tail = 0 */
|
||||
ftape_set_state(formatting);
|
||||
|
||||
TRACE(ft_t_noise,
|
||||
"Formatting track %d, logical: from segment %d to %d",
|
||||
track, track * ft_segments_per_track,
|
||||
(track + 1) * ft_segments_per_track - 1);
|
||||
|
||||
/*
|
||||
* initialize the buffer switching protocol for this track
|
||||
*/
|
||||
head = ftape_get_buffer(ft_queue_head); /* tape isn't running yet */
|
||||
tail = ftape_get_buffer(ft_queue_tail); /* tape isn't running yet */
|
||||
switch_segment = 0;
|
||||
do {
|
||||
FT_SIGNAL_EXIT(_DONT_BLOCK);
|
||||
setup_format_buffer(tail, switch_segment,
|
||||
ft_segments_per_track, gap3);
|
||||
switch_segment = tail->next_segment;
|
||||
} while ((switch_segment != 0) &&
|
||||
((tail = ftape_next_buffer(ft_queue_tail)) != head));
|
||||
/* go */
|
||||
head->status = formatting;
|
||||
TRACE_CATCH(ftape_seek_head_to_track(track),);
|
||||
TRACE_CATCH(ftape_command(QIC_LOGICAL_FORWARD),);
|
||||
spin_lock_irqsave(&ftape_format_lock, flags);
|
||||
TRACE_CATCH(fdc_setup_formatting(head), restore_flags(flags));
|
||||
spin_unlock_irqrestore(&ftape_format_lock, flags);
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
/* return segment id of segment currently being formatted and do the
|
||||
* buffer switching stuff.
|
||||
*/
|
||||
int ftape_format_status(unsigned int *segment_id)
|
||||
{
|
||||
buffer_struct *tail = ftape_get_buffer(ft_queue_tail);
|
||||
int result;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
while (switch_segment != 0 &&
|
||||
ftape_get_buffer(ft_queue_head) != tail) {
|
||||
FT_SIGNAL_EXIT(_DONT_BLOCK);
|
||||
/* need more buffers, first wait for empty buffer
|
||||
*/
|
||||
TRACE_CATCH(ftape_wait_segment(formatting),);
|
||||
/* don't worry for gap3. If we ever hit this piece of code,
|
||||
* then all buffer already have the correct gap3 set!
|
||||
*/
|
||||
setup_format_buffer(tail, switch_segment,
|
||||
ft_segments_per_track, tail->gap3);
|
||||
switch_segment = tail->next_segment;
|
||||
if (switch_segment != 0) {
|
||||
tail = ftape_next_buffer(ft_queue_tail);
|
||||
}
|
||||
}
|
||||
/* should runner stop ?
|
||||
*/
|
||||
if (ft_runner_status == aborting || ft_runner_status == do_abort) {
|
||||
buffer_struct *head = ftape_get_buffer(ft_queue_head);
|
||||
TRACE(ft_t_warn, "Error formatting segment %d",
|
||||
ftape_get_buffer(ft_queue_head)->segment_id);
|
||||
(void)ftape_abort_operation();
|
||||
TRACE_EXIT (head->status != error) ? -EAGAIN : -EIO;
|
||||
}
|
||||
/*
|
||||
* don't care if the timer expires, this is just kind of a
|
||||
* "select" operation that lets the calling process sleep
|
||||
* until something has happened
|
||||
*/
|
||||
if (fdc_interrupt_wait(5 * FT_SECOND) < 0) {
|
||||
TRACE(ft_t_noise, "End of track %d at segment %d",
|
||||
ft_location.track,
|
||||
ftape_get_buffer(ft_queue_head)->segment_id);
|
||||
result = 1; /* end of track, unlock module */
|
||||
} else {
|
||||
result = 0;
|
||||
}
|
||||
/*
|
||||
* the calling process should use the seg id to determine
|
||||
* which parts of the dma buffers can be safely overwritten
|
||||
* with new data.
|
||||
*/
|
||||
*segment_id = ftape_get_buffer(ft_queue_head)->segment_id;
|
||||
/*
|
||||
* Internally we start counting segment ids from the start of
|
||||
* each track when formatting, but externally we keep them
|
||||
* relative to the start of the tape:
|
||||
*/
|
||||
*segment_id += ft_location.track * ft_segments_per_track;
|
||||
TRACE_EXIT result;
|
||||
}
|
||||
|
||||
/*
|
||||
* The segment id is relative to the start of the tape
|
||||
*/
|
||||
int ftape_verify_segment(const unsigned int segment_id, SectorMap *bsm)
|
||||
{
|
||||
int result;
|
||||
int verify_done = 0;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
TRACE(ft_t_noise, "Verifying segment %d", segment_id);
|
||||
|
||||
if (ft_driver_state != verifying) {
|
||||
TRACE(ft_t_noise, "calling ftape_abort_operation");
|
||||
if (ftape_abort_operation() < 0) {
|
||||
TRACE(ft_t_err, "ftape_abort_operation failed");
|
||||
TRACE_EXIT -EIO;
|
||||
}
|
||||
}
|
||||
*bsm = 0x00000000;
|
||||
ftape_set_state(verifying);
|
||||
for (;;) {
|
||||
buffer_struct *tail;
|
||||
/*
|
||||
* Allow escape from this loop on signal
|
||||
*/
|
||||
FT_SIGNAL_EXIT(_DONT_BLOCK);
|
||||
/*
|
||||
* Search all full buffers for the first matching the
|
||||
* wanted segment. Clear other buffers on the fly.
|
||||
*/
|
||||
tail = ftape_get_buffer(ft_queue_tail);
|
||||
while (!verify_done && tail->status == done) {
|
||||
/*
|
||||
* Allow escape from this loop on signal !
|
||||
*/
|
||||
FT_SIGNAL_EXIT(_DONT_BLOCK);
|
||||
if (tail->segment_id == segment_id) {
|
||||
/* If out buffer is already full,
|
||||
* return its contents.
|
||||
*/
|
||||
TRACE(ft_t_flow, "found segment in cache: %d",
|
||||
segment_id);
|
||||
if ((tail->soft_error_map |
|
||||
tail->hard_error_map) != 0) {
|
||||
TRACE(ft_t_info,"bsm[%d] = 0x%08lx",
|
||||
segment_id,
|
||||
(unsigned long)
|
||||
(tail->soft_error_map |
|
||||
tail->hard_error_map));
|
||||
*bsm = (tail->soft_error_map |
|
||||
tail->hard_error_map);
|
||||
}
|
||||
verify_done = 1;
|
||||
} else {
|
||||
TRACE(ft_t_flow,"zapping segment in cache: %d",
|
||||
tail->segment_id);
|
||||
}
|
||||
tail->status = waiting;
|
||||
tail = ftape_next_buffer(ft_queue_tail);
|
||||
}
|
||||
if (!verify_done && tail->status == verifying) {
|
||||
if (tail->segment_id == segment_id) {
|
||||
switch(ftape_wait_segment(verifying)) {
|
||||
case 0:
|
||||
break;
|
||||
case -EINTR:
|
||||
TRACE_ABORT(-EINTR, ft_t_warn,
|
||||
"interrupted by "
|
||||
"non-blockable signal");
|
||||
break;
|
||||
default:
|
||||
ftape_abort_operation();
|
||||
ftape_set_state(verifying);
|
||||
/* be picky */
|
||||
TRACE_ABORT(-EIO, ft_t_warn,
|
||||
"wait_segment failed");
|
||||
}
|
||||
} else {
|
||||
/* We're reading the wrong segment,
|
||||
* stop runner.
|
||||
*/
|
||||
TRACE(ft_t_noise, "verifying wrong segment");
|
||||
ftape_abort_operation();
|
||||
ftape_set_state(verifying);
|
||||
}
|
||||
}
|
||||
/* should runner stop ?
|
||||
*/
|
||||
if (ft_runner_status == aborting) {
|
||||
buffer_struct *head = ftape_get_buffer(ft_queue_head);
|
||||
if (head->status == error ||
|
||||
head->status == verifying) {
|
||||
/* no data or overrun error */
|
||||
head->status = waiting;
|
||||
}
|
||||
TRACE_CATCH(ftape_dumb_stop(),);
|
||||
} else {
|
||||
/* If just passed last segment on tape: wait
|
||||
* for BOT or EOT mark. Sets ft_runner_status to
|
||||
* idle if at lEOT and successful
|
||||
*/
|
||||
TRACE_CATCH(ftape_handle_logical_eot(),);
|
||||
}
|
||||
if (verify_done) {
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
/* Now at least one buffer is idle!
|
||||
* Restart runner & tape if needed.
|
||||
*/
|
||||
/* We could optimize the following a little bit. We know that
|
||||
* the bad sector map is empty.
|
||||
*/
|
||||
tail = ftape_get_buffer(ft_queue_tail);
|
||||
if (tail->status == waiting) {
|
||||
buffer_struct *head = ftape_get_buffer(ft_queue_head);
|
||||
|
||||
ftape_setup_new_segment(head, segment_id, -1);
|
||||
ftape_calc_next_cluster(head);
|
||||
if (ft_runner_status == idle) {
|
||||
result = ftape_start_tape(segment_id,
|
||||
head->sector_offset);
|
||||
switch(result) {
|
||||
case 0:
|
||||
break;
|
||||
case -ETIME:
|
||||
case -EINTR:
|
||||
TRACE_ABORT(result, ft_t_err, "Error: "
|
||||
"segment %d unreachable",
|
||||
segment_id);
|
||||
break;
|
||||
default:
|
||||
*bsm = EMPTY_SEGMENT;
|
||||
TRACE_EXIT 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
head->status = verifying;
|
||||
fdc_setup_read_write(head, FDC_VERIFY);
|
||||
}
|
||||
}
|
||||
/* not reached */
|
||||
TRACE_EXIT -EIO;
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
#ifndef _FTAPE_FORMAT_H
|
||||
#define _FTAPE_FORMAT_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 1996-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/ftape/lowlevel/ftape-format.h,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:18:13 $
|
||||
*
|
||||
* This file contains the low level definitions for the
|
||||
* formatting support for the QIC-40/80/3010/3020 floppy-tape
|
||||
* driver "ftape" for Linux.
|
||||
*/
|
||||
|
||||
#ifdef __KERNEL__
|
||||
extern int ftape_format_track(const unsigned int track, const __u8 gap3);
|
||||
extern int ftape_format_status(unsigned int *segment_id);
|
||||
extern int ftape_verify_segment(const unsigned int segment_id, SectorMap *bsm);
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif
|
@ -1,160 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1993-1996 Bas Laarhoven,
|
||||
* (C) 1996-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.
|
||||
|
||||
*
|
||||
* This file contains the code that interfaces the kernel
|
||||
* for the QIC-40/80/3010/3020 floppy-tape driver for Linux.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/major.h>
|
||||
|
||||
#include <linux/ftape.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/qic117.h>
|
||||
#ifdef CONFIG_ZFTAPE
|
||||
#include <linux/zftape.h>
|
||||
#endif
|
||||
|
||||
#include "../lowlevel/ftape-init.h"
|
||||
#include "../lowlevel/ftape-io.h"
|
||||
#include "../lowlevel/ftape-read.h"
|
||||
#include "../lowlevel/ftape-write.h"
|
||||
#include "../lowlevel/ftape-ctl.h"
|
||||
#include "../lowlevel/ftape-rw.h"
|
||||
#include "../lowlevel/fdc-io.h"
|
||||
#include "../lowlevel/ftape-buffer.h"
|
||||
#include "../lowlevel/ftape-proc.h"
|
||||
#include "../lowlevel/ftape-tracing.h"
|
||||
|
||||
|
||||
#if defined(MODULE) && !defined(CONFIG_FT_NO_TRACE_AT_ALL)
|
||||
static int ft_tracing = -1;
|
||||
#endif
|
||||
|
||||
|
||||
/* Called by modules package when installing the driver
|
||||
* or by kernel during the initialization phase
|
||||
*/
|
||||
static int __init ftape_init(void)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
#ifdef MODULE
|
||||
#ifndef CONFIG_FT_NO_TRACE_AT_ALL
|
||||
if (ft_tracing != -1) {
|
||||
ftape_tracing = ft_tracing;
|
||||
}
|
||||
#endif
|
||||
printk(KERN_INFO FTAPE_VERSION "\n");
|
||||
if (TRACE_LEVEL >= ft_t_info) {
|
||||
printk(
|
||||
KERN_INFO "(c) 1993-1996 Bas Laarhoven (bas@vimec.nl)\n"
|
||||
KERN_INFO "(c) 1995-1996 Kai Harrekilde-Petersen (khp@dolphinics.no)\n"
|
||||
KERN_INFO "(c) 1996-1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)\n"
|
||||
KERN_INFO "QIC-117 driver for QIC-40/80/3010/3020 floppy tape drives\n");
|
||||
}
|
||||
#else /* !MODULE */
|
||||
/* print a short no-nonsense boot message */
|
||||
printk(KERN_INFO FTAPE_VERSION "\n");
|
||||
#endif /* MODULE */
|
||||
TRACE(ft_t_info, "installing QIC-117 floppy tape hardware drive ... ");
|
||||
TRACE(ft_t_info, "ftape_init @ 0x%p", ftape_init);
|
||||
/* Allocate the DMA buffers. They are deallocated at cleanup() time.
|
||||
*/
|
||||
#ifdef TESTING
|
||||
#ifdef MODULE
|
||||
while (ftape_set_nr_buffers(CONFIG_FT_NR_BUFFERS) < 0) {
|
||||
ftape_sleep(FT_SECOND/20);
|
||||
if (signal_pending(current)) {
|
||||
(void)ftape_set_nr_buffers(0);
|
||||
TRACE(ft_t_bug,
|
||||
"Killed by signal while allocating buffers.");
|
||||
TRACE_ABORT(-EINTR,
|
||||
ft_t_bug, "Free up memory and retry");
|
||||
}
|
||||
}
|
||||
#else
|
||||
TRACE_CATCH(ftape_set_nr_buffers(CONFIG_FT_NR_BUFFERS),
|
||||
(void)ftape_set_nr_buffers(0));
|
||||
#endif
|
||||
#else
|
||||
TRACE_CATCH(ftape_set_nr_buffers(CONFIG_FT_NR_BUFFERS),
|
||||
(void)ftape_set_nr_buffers(0));
|
||||
#endif
|
||||
ft_drive_sel = -1;
|
||||
ft_failure = 1; /* inhibit any operation but open */
|
||||
ftape_udelay_calibrate(); /* must be before fdc_wait_calibrate ! */
|
||||
fdc_wait_calibrate();
|
||||
#if defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS)
|
||||
(void)ftape_proc_init();
|
||||
#endif
|
||||
#ifdef CONFIG_ZFTAPE
|
||||
(void)zft_init();
|
||||
#endif
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
module_param(ft_fdc_base, uint, 0);
|
||||
MODULE_PARM_DESC(ft_fdc_base, "Base address of FDC controller.");
|
||||
module_param(ft_fdc_irq, uint, 0);
|
||||
MODULE_PARM_DESC(ft_fdc_irq, "IRQ (interrupt channel) to use.");
|
||||
module_param(ft_fdc_dma, uint, 0);
|
||||
MODULE_PARM_DESC(ft_fdc_dma, "DMA channel to use.");
|
||||
module_param(ft_fdc_threshold, uint, 0);
|
||||
MODULE_PARM_DESC(ft_fdc_threshold, "Threshold of the FDC Fifo.");
|
||||
module_param(ft_fdc_rate_limit, uint, 0);
|
||||
MODULE_PARM_DESC(ft_fdc_rate_limit, "Maximal data rate for FDC.");
|
||||
module_param(ft_probe_fc10, bool, 0);
|
||||
MODULE_PARM_DESC(ft_probe_fc10,
|
||||
"If non-zero, probe for a Colorado FC-10/FC-20 controller.");
|
||||
module_param(ft_mach2, bool, 0);
|
||||
MODULE_PARM_DESC(ft_mach2,
|
||||
"If non-zero, probe for a Mountain MACH-2 controller.");
|
||||
#if defined(MODULE) && !defined(CONFIG_FT_NO_TRACE_AT_ALL)
|
||||
module_param(ft_tracing, int, 0644);
|
||||
MODULE_PARM_DESC(ft_tracing,
|
||||
"Amount of debugging output, 0 <= tracing <= 8, default 3.");
|
||||
#endif
|
||||
|
||||
MODULE_AUTHOR(
|
||||
"(c) 1993-1996 Bas Laarhoven (bas@vimec.nl), "
|
||||
"(c) 1995-1996 Kai Harrekilde-Petersen (khp@dolphinics.no), "
|
||||
"(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)");
|
||||
MODULE_DESCRIPTION(
|
||||
"QIC-117 driver for QIC-40/80/3010/3020 floppy tape drives.");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static void __exit ftape_exit(void)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
#if defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS)
|
||||
ftape_proc_destroy();
|
||||
#endif
|
||||
(void)ftape_set_nr_buffers(0);
|
||||
printk(KERN_INFO "ftape: unloaded.\n");
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
module_init(ftape_init);
|
||||
module_exit(ftape_exit);
|
@ -1,43 +0,0 @@
|
||||
#ifndef _FTAPE_INIT_H
|
||||
#define _FTAPE_INIT_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 1993-1996 Bas Laarhoven,
|
||||
* (C) 1996-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/ftape/lowlevel/ftape-init.h,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:18:16 $
|
||||
*
|
||||
* This file contains the definitions for the interface to
|
||||
* the Linux kernel for floppy tape driver ftape.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/signal.h>
|
||||
|
||||
#define _NEVER_BLOCK (sigmask(SIGKILL) | sigmask(SIGSTOP))
|
||||
#define _DONT_BLOCK (_NEVER_BLOCK | sigmask(SIGINT))
|
||||
#define _DO_BLOCK (sigmask(SIGPIPE))
|
||||
|
||||
#ifndef QIC117_TAPE_MAJOR
|
||||
#define QIC117_TAPE_MAJOR 27
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,992 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1993-1996 Bas Laarhoven,
|
||||
* (C) 1996 Kai Harrekilde-Petersen,
|
||||
* (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/ftape/lowlevel/ftape-io.c,v $
|
||||
* $Revision: 1.4 $
|
||||
* $Date: 1997/11/11 14:02:36 $
|
||||
*
|
||||
* This file contains the general control functions for the
|
||||
* QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mm.h>
|
||||
#include <asm/system.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/mtio.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <linux/ftape.h>
|
||||
#include <linux/qic117.h>
|
||||
#include "../lowlevel/ftape-tracing.h"
|
||||
#include "../lowlevel/fdc-io.h"
|
||||
#include "../lowlevel/ftape-io.h"
|
||||
#include "../lowlevel/ftape-ctl.h"
|
||||
#include "../lowlevel/ftape-rw.h"
|
||||
#include "../lowlevel/ftape-write.h"
|
||||
#include "../lowlevel/ftape-read.h"
|
||||
#include "../lowlevel/ftape-init.h"
|
||||
#include "../lowlevel/ftape-calibr.h"
|
||||
|
||||
/* Global vars.
|
||||
*/
|
||||
/* NOTE: sectors start numbering at 1, all others at 0 ! */
|
||||
ft_timeout_table ftape_timeout;
|
||||
unsigned int ftape_tape_len;
|
||||
volatile qic117_cmd_t ftape_current_command;
|
||||
const struct qic117_command_table qic117_cmds[] = QIC117_COMMANDS;
|
||||
int ftape_might_be_off_track;
|
||||
|
||||
/* Local vars.
|
||||
*/
|
||||
static int diagnostic_mode;
|
||||
static unsigned int ftape_udelay_count;
|
||||
static unsigned int ftape_udelay_time;
|
||||
|
||||
void ftape_udelay(unsigned int usecs)
|
||||
{
|
||||
volatile int count = (ftape_udelay_count * usecs +
|
||||
ftape_udelay_count - 1) / ftape_udelay_time;
|
||||
volatile int i;
|
||||
|
||||
while (count-- > 0) {
|
||||
for (i = 0; i < 20; ++i);
|
||||
}
|
||||
}
|
||||
|
||||
void ftape_udelay_calibrate(void)
|
||||
{
|
||||
ftape_calibrate("ftape_udelay",
|
||||
ftape_udelay, &ftape_udelay_count, &ftape_udelay_time);
|
||||
}
|
||||
|
||||
/* Delay (msec) routine.
|
||||
*/
|
||||
void ftape_sleep(unsigned int time)
|
||||
{
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
time *= 1000; /* msecs -> usecs */
|
||||
if (time < FT_USPT) {
|
||||
/* Time too small for scheduler, do a busy wait ! */
|
||||
ftape_udelay(time);
|
||||
} else {
|
||||
long timeout;
|
||||
unsigned long flags;
|
||||
unsigned int ticks = (time + FT_USPT - 1) / FT_USPT;
|
||||
|
||||
TRACE(ft_t_any, "%d msec, %d ticks", time/1000, ticks);
|
||||
timeout = ticks;
|
||||
save_flags(flags);
|
||||
sti();
|
||||
msleep_interruptible(jiffies_to_msecs(timeout));
|
||||
/* Mmm. Isn't current->blocked == 0xffffffff ?
|
||||
*/
|
||||
if (signal_pending(current)) {
|
||||
TRACE(ft_t_err, "awoken by non-blocked signal :-(");
|
||||
}
|
||||
restore_flags(flags);
|
||||
}
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
/* send a command or parameter to the drive
|
||||
* Generates # of step pulses.
|
||||
*/
|
||||
static inline int ft_send_to_drive(int arg)
|
||||
{
|
||||
/* Always wait for a command_timeout period to separate
|
||||
* individuals commands and/or parameters.
|
||||
*/
|
||||
ftape_sleep(3 * FT_MILLISECOND);
|
||||
/* Keep cylinder nr within range, step towards home if possible.
|
||||
*/
|
||||
if (ftape_current_cylinder >= arg) {
|
||||
return fdc_seek(ftape_current_cylinder - arg);
|
||||
} else {
|
||||
return fdc_seek(ftape_current_cylinder + arg);
|
||||
}
|
||||
}
|
||||
|
||||
/* forward */ int ftape_report_raw_drive_status(int *status);
|
||||
|
||||
static int ft_check_cmd_restrictions(qic117_cmd_t command)
|
||||
{
|
||||
int status = -1;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
TRACE(ft_t_flow, "%s", qic117_cmds[command].name);
|
||||
/* A new motion command during an uninterruptible (motion)
|
||||
* command requires a ready status before the new command can
|
||||
* be issued. Otherwise a new motion command needs to be
|
||||
* checked against required status.
|
||||
*/
|
||||
if (qic117_cmds[command].cmd_type == motion &&
|
||||
qic117_cmds[ftape_current_command].non_intr) {
|
||||
ftape_report_raw_drive_status(&status);
|
||||
if ((status & QIC_STATUS_READY) == 0) {
|
||||
TRACE(ft_t_noise,
|
||||
"motion cmd (%d) during non-intr cmd (%d)",
|
||||
command, ftape_current_command);
|
||||
TRACE(ft_t_noise, "waiting until drive gets ready");
|
||||
ftape_ready_wait(ftape_timeout.seek,
|
||||
&status);
|
||||
}
|
||||
}
|
||||
if (qic117_cmds[command].mask != 0) {
|
||||
__u8 difference;
|
||||
/* Some commands do require a certain status:
|
||||
*/
|
||||
if (status == -1) { /* not yet set */
|
||||
ftape_report_raw_drive_status(&status);
|
||||
}
|
||||
difference = ((status ^ qic117_cmds[command].state) &
|
||||
qic117_cmds[command].mask);
|
||||
/* Wait until the drive gets
|
||||
* ready. This may last forever if
|
||||
* the drive never gets ready...
|
||||
*/
|
||||
while ((difference & QIC_STATUS_READY) != 0) {
|
||||
TRACE(ft_t_noise, "command %d issued while not ready",
|
||||
command);
|
||||
TRACE(ft_t_noise, "waiting until drive gets ready");
|
||||
if (ftape_ready_wait(ftape_timeout.seek,
|
||||
&status) == -EINTR) {
|
||||
/* Bail out on signal !
|
||||
*/
|
||||
TRACE_ABORT(-EINTR, ft_t_warn,
|
||||
"interrupted by non-blockable signal");
|
||||
}
|
||||
difference = ((status ^ qic117_cmds[command].state) &
|
||||
qic117_cmds[command].mask);
|
||||
}
|
||||
while ((difference & QIC_STATUS_ERROR) != 0) {
|
||||
int err;
|
||||
qic117_cmd_t cmd;
|
||||
|
||||
TRACE(ft_t_noise,
|
||||
"command %d issued while error pending",
|
||||
command);
|
||||
TRACE(ft_t_noise, "clearing error status");
|
||||
ftape_report_error(&err, &cmd, 1);
|
||||
ftape_report_raw_drive_status(&status);
|
||||
difference = ((status ^ qic117_cmds[command].state) &
|
||||
qic117_cmds[command].mask);
|
||||
if ((difference & QIC_STATUS_ERROR) != 0) {
|
||||
/* Bail out on fatal signal !
|
||||
*/
|
||||
FT_SIGNAL_EXIT(_NEVER_BLOCK);
|
||||
}
|
||||
}
|
||||
if (difference) {
|
||||
/* Any remaining difference can't be solved
|
||||
* here.
|
||||
*/
|
||||
if (difference & (QIC_STATUS_CARTRIDGE_PRESENT |
|
||||
QIC_STATUS_NEW_CARTRIDGE |
|
||||
QIC_STATUS_REFERENCED)) {
|
||||
TRACE(ft_t_warn,
|
||||
"Fatal: tape removed or reinserted !");
|
||||
ft_failure = 1;
|
||||
} else {
|
||||
TRACE(ft_t_err, "wrong state: 0x%02x should be: 0x%02x",
|
||||
status & qic117_cmds[command].mask,
|
||||
qic117_cmds[command].state);
|
||||
}
|
||||
TRACE_EXIT -EIO;
|
||||
}
|
||||
if (~status & QIC_STATUS_READY & qic117_cmds[command].mask) {
|
||||
TRACE_ABORT(-EBUSY, ft_t_err, "Bad: still busy!");
|
||||
}
|
||||
}
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
/* Issue a tape command:
|
||||
*/
|
||||
int ftape_command(qic117_cmd_t command)
|
||||
{
|
||||
int result = 0;
|
||||
static int level;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
if ((unsigned int)command > NR_ITEMS(qic117_cmds)) {
|
||||
/* This is a bug we'll want to know about too.
|
||||
*/
|
||||
TRACE_ABORT(-EIO, ft_t_bug, "bug - bad command: %d", command);
|
||||
}
|
||||
if (++level > 5) { /* This is a bug we'll want to know about. */
|
||||
--level;
|
||||
TRACE_ABORT(-EIO, ft_t_bug, "bug - recursion for command: %d",
|
||||
command);
|
||||
}
|
||||
/* disable logging and restriction check for some commands,
|
||||
* check all other commands that have a prescribed starting
|
||||
* status.
|
||||
*/
|
||||
if (diagnostic_mode) {
|
||||
TRACE(ft_t_flow, "diagnostic command %d", command);
|
||||
} else if (command == QIC_REPORT_DRIVE_STATUS ||
|
||||
command == QIC_REPORT_NEXT_BIT) {
|
||||
TRACE(ft_t_any, "%s", qic117_cmds[command].name);
|
||||
} else {
|
||||
TRACE_CATCH(ft_check_cmd_restrictions(command), --level);
|
||||
}
|
||||
/* Now all conditions are met or result was < 0.
|
||||
*/
|
||||
result = ft_send_to_drive((unsigned int)command);
|
||||
if (qic117_cmds[command].cmd_type == motion &&
|
||||
command != QIC_LOGICAL_FORWARD && command != QIC_STOP_TAPE) {
|
||||
ft_location.known = 0;
|
||||
}
|
||||
ftape_current_command = command;
|
||||
--level;
|
||||
TRACE_EXIT result;
|
||||
}
|
||||
|
||||
/* Send a tape command parameter:
|
||||
* Generates command # of step pulses.
|
||||
* Skips tape-status call !
|
||||
*/
|
||||
int ftape_parameter(unsigned int parameter)
|
||||
{
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
TRACE(ft_t_flow, "called with parameter = %d", parameter);
|
||||
TRACE_EXIT ft_send_to_drive(parameter + 2);
|
||||
}
|
||||
|
||||
/* Wait for the drive to get ready.
|
||||
* timeout time in milli-seconds
|
||||
* Returned status is valid if result != -EIO
|
||||
*
|
||||
* Should we allow to be killed by SIGINT? (^C)
|
||||
* Would be nice at least for large timeouts.
|
||||
*/
|
||||
int ftape_ready_wait(unsigned int timeout, int *status)
|
||||
{
|
||||
unsigned long t0;
|
||||
unsigned int poll_delay;
|
||||
int signal_retries;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
/* the following ** REALLY ** reduces the system load when
|
||||
* e.g. one simply rewinds or retensions. The tape is slow
|
||||
* anyway. It is really not necessary to detect error
|
||||
* conditions with 1/10 seconds granularity
|
||||
*
|
||||
* On my AMD 133MHZ 486: 100 ms: 23% system load
|
||||
* 1 sec: 5%
|
||||
* 5 sec: 0.6%, yeah
|
||||
*/
|
||||
if (timeout <= FT_SECOND) {
|
||||
poll_delay = 100 * FT_MILLISECOND;
|
||||
signal_retries = 20; /* two seconds */
|
||||
} else if (timeout < 20 * FT_SECOND) {
|
||||
TRACE(ft_t_flow, "setting poll delay to 1 second");
|
||||
poll_delay = FT_SECOND;
|
||||
signal_retries = 2; /* two seconds */
|
||||
} else {
|
||||
TRACE(ft_t_flow, "setting poll delay to 5 seconds");
|
||||
poll_delay = 5 * FT_SECOND;
|
||||
signal_retries = 1; /* five seconds */
|
||||
}
|
||||
for (;;) {
|
||||
t0 = jiffies;
|
||||
TRACE_CATCH(ftape_report_raw_drive_status(status),);
|
||||
if (*status & QIC_STATUS_READY) {
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
if (!signal_retries--) {
|
||||
FT_SIGNAL_EXIT(_NEVER_BLOCK);
|
||||
}
|
||||
if ((int)timeout >= 0) {
|
||||
/* this will fail when jiffies wraps around about
|
||||
* once every year :-)
|
||||
*/
|
||||
timeout -= ((jiffies - t0) * FT_SECOND) / HZ;
|
||||
if (timeout <= 0) {
|
||||
TRACE_ABORT(-ETIME, ft_t_err, "timeout");
|
||||
}
|
||||
ftape_sleep(poll_delay);
|
||||
timeout -= poll_delay;
|
||||
} else {
|
||||
ftape_sleep(poll_delay);
|
||||
}
|
||||
}
|
||||
TRACE_EXIT -ETIME;
|
||||
}
|
||||
|
||||
/* Issue command and wait up to timeout milli seconds for drive ready
|
||||
*/
|
||||
int ftape_command_wait(qic117_cmd_t command, unsigned int timeout, int *status)
|
||||
{
|
||||
int result;
|
||||
|
||||
/* Drive should be ready, issue command
|
||||
*/
|
||||
result = ftape_command(command);
|
||||
if (result >= 0) {
|
||||
result = ftape_ready_wait(timeout, status);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int ftape_parameter_wait(unsigned int parm, unsigned int timeout, int *status)
|
||||
{
|
||||
int result;
|
||||
|
||||
/* Drive should be ready, issue command
|
||||
*/
|
||||
result = ftape_parameter(parm);
|
||||
if (result >= 0) {
|
||||
result = ftape_ready_wait(timeout, status);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
* Report operations
|
||||
*/
|
||||
|
||||
/* Query the drive about its status. The command is sent and
|
||||
result_length bits of status are returned (2 extra bits are read
|
||||
for start and stop). */
|
||||
|
||||
int ftape_report_operation(int *status,
|
||||
qic117_cmd_t command,
|
||||
int result_length)
|
||||
{
|
||||
int i, st3;
|
||||
unsigned int t0;
|
||||
unsigned int dt;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
TRACE_CATCH(ftape_command(command),);
|
||||
t0 = ftape_timestamp();
|
||||
i = 0;
|
||||
do {
|
||||
++i;
|
||||
ftape_sleep(3 * FT_MILLISECOND); /* see remark below */
|
||||
TRACE_CATCH(fdc_sense_drive_status(&st3),);
|
||||
dt = ftape_timediff(t0, ftape_timestamp());
|
||||
/* Ack should be asserted within Ttimout + Tack = 6 msec.
|
||||
* Looks like some drives fail to do this so extend this
|
||||
* period to 300 msec.
|
||||
*/
|
||||
} while (!(st3 & ST3_TRACK_0) && dt < 300000);
|
||||
if (!(st3 & ST3_TRACK_0)) {
|
||||
TRACE(ft_t_err,
|
||||
"No acknowledge after %u msec. (%i iter)", dt / 1000, i);
|
||||
TRACE_ABORT(-EIO, ft_t_err, "timeout on Acknowledge");
|
||||
}
|
||||
/* dt may be larger than expected because of other tasks
|
||||
* scheduled while we were sleeping.
|
||||
*/
|
||||
if (i > 1 && dt > 6000) {
|
||||
TRACE(ft_t_err, "Acknowledge after %u msec. (%i iter)",
|
||||
dt / 1000, i);
|
||||
}
|
||||
*status = 0;
|
||||
for (i = 0; i < result_length + 1; i++) {
|
||||
TRACE_CATCH(ftape_command(QIC_REPORT_NEXT_BIT),);
|
||||
TRACE_CATCH(fdc_sense_drive_status(&st3),);
|
||||
if (i < result_length) {
|
||||
*status |= ((st3 & ST3_TRACK_0) ? 1 : 0) << i;
|
||||
} else if ((st3 & ST3_TRACK_0) == 0) {
|
||||
TRACE_ABORT(-EIO, ft_t_err, "missing status stop bit");
|
||||
}
|
||||
}
|
||||
/* this command will put track zero and index back into normal state */
|
||||
(void)ftape_command(QIC_REPORT_NEXT_BIT);
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
/* Report the current drive status. */
|
||||
|
||||
int ftape_report_raw_drive_status(int *status)
|
||||
{
|
||||
int result;
|
||||
int count = 0;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
do {
|
||||
result = ftape_report_operation(status,
|
||||
QIC_REPORT_DRIVE_STATUS, 8);
|
||||
} while (result < 0 && ++count <= 3);
|
||||
if (result < 0) {
|
||||
TRACE_ABORT(-EIO, ft_t_err,
|
||||
"report_operation failed after %d trials", count);
|
||||
}
|
||||
if ((*status & 0xff) == 0xff) {
|
||||
TRACE_ABORT(-EIO, ft_t_err,
|
||||
"impossible drive status 0xff");
|
||||
}
|
||||
if (*status & QIC_STATUS_READY) {
|
||||
ftape_current_command = QIC_NO_COMMAND; /* completed */
|
||||
}
|
||||
ft_last_status.status.drive_status = (__u8)(*status & 0xff);
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
int ftape_report_drive_status(int *status)
|
||||
{
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
TRACE_CATCH(ftape_report_raw_drive_status(status),);
|
||||
if (*status & QIC_STATUS_NEW_CARTRIDGE ||
|
||||
!(*status & QIC_STATUS_CARTRIDGE_PRESENT)) {
|
||||
ft_failure = 1; /* will inhibit further operations */
|
||||
TRACE_EXIT -EIO;
|
||||
}
|
||||
if (*status & QIC_STATUS_READY && *status & QIC_STATUS_ERROR) {
|
||||
/* Let caller handle all errors */
|
||||
TRACE_ABORT(1, ft_t_warn, "warning: error status set!");
|
||||
}
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
int ftape_report_error(unsigned int *error,
|
||||
qic117_cmd_t *command, int report)
|
||||
{
|
||||
static const ftape_error ftape_errors[] = QIC117_ERRORS;
|
||||
int code;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
TRACE_CATCH(ftape_report_operation(&code, QIC_REPORT_ERROR_CODE, 16),);
|
||||
*error = (unsigned int)(code & 0xff);
|
||||
*command = (qic117_cmd_t)((code>>8)&0xff);
|
||||
/* remember hardware status, maybe useful for status ioctls
|
||||
*/
|
||||
ft_last_error.error.command = (__u8)*command;
|
||||
ft_last_error.error.error = (__u8)*error;
|
||||
if (!report) {
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
if (*error == 0) {
|
||||
TRACE_ABORT(0, ft_t_info, "No error");
|
||||
}
|
||||
TRACE(ft_t_info, "errorcode: %d", *error);
|
||||
if (*error < NR_ITEMS(ftape_errors)) {
|
||||
TRACE(ft_t_noise, "%sFatal ERROR:",
|
||||
(ftape_errors[*error].fatal ? "" : "Non-"));
|
||||
TRACE(ft_t_noise, "%s ...", ftape_errors[*error].message);
|
||||
} else {
|
||||
TRACE(ft_t_noise, "Unknown ERROR !");
|
||||
}
|
||||
if ((unsigned int)*command < NR_ITEMS(qic117_cmds) &&
|
||||
qic117_cmds[*command].name != NULL) {
|
||||
TRACE(ft_t_noise, "... caused by command \'%s\'",
|
||||
qic117_cmds[*command].name);
|
||||
} else {
|
||||
TRACE(ft_t_noise, "... caused by unknown command %d",
|
||||
*command);
|
||||
}
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
int ftape_report_configuration(qic_model *model,
|
||||
unsigned int *rate,
|
||||
int *qic_std,
|
||||
int *tape_len)
|
||||
{
|
||||
int result;
|
||||
int config;
|
||||
int status;
|
||||
static const unsigned int qic_rates[ 4] = { 250, 2000, 500, 1000 };
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
result = ftape_report_operation(&config,
|
||||
QIC_REPORT_DRIVE_CONFIGURATION, 8);
|
||||
if (result < 0) {
|
||||
ft_last_status.status.drive_config = (__u8)0x00;
|
||||
*model = prehistoric;
|
||||
*rate = 500;
|
||||
*qic_std = QIC_TAPE_QIC40;
|
||||
*tape_len = 205;
|
||||
TRACE_EXIT 0;
|
||||
} else {
|
||||
ft_last_status.status.drive_config = (__u8)(config & 0xff);
|
||||
}
|
||||
*rate = qic_rates[(config & QIC_CONFIG_RATE_MASK) >> QIC_CONFIG_RATE_SHIFT];
|
||||
result = ftape_report_operation(&status, QIC_REPORT_TAPE_STATUS, 8);
|
||||
if (result < 0) {
|
||||
ft_last_status.status.tape_status = (__u8)0x00;
|
||||
/* pre- QIC117 rev C spec. drive, QIC_CONFIG_80 bit is valid.
|
||||
*/
|
||||
*qic_std = (config & QIC_CONFIG_80) ?
|
||||
QIC_TAPE_QIC80 : QIC_TAPE_QIC40;
|
||||
/* ?? how's about 425ft tapes? */
|
||||
*tape_len = (config & QIC_CONFIG_LONG) ? 307 : 0;
|
||||
*model = pre_qic117c;
|
||||
result = 0;
|
||||
} else {
|
||||
ft_last_status.status.tape_status = (__u8)(status & 0xff);
|
||||
*model = post_qic117b;
|
||||
TRACE(ft_t_any, "report tape status result = %02x", status);
|
||||
/* post- QIC117 rev C spec. drive, QIC_CONFIG_80 bit is
|
||||
* invalid.
|
||||
*/
|
||||
switch (status & QIC_TAPE_STD_MASK) {
|
||||
case QIC_TAPE_QIC40:
|
||||
case QIC_TAPE_QIC80:
|
||||
case QIC_TAPE_QIC3020:
|
||||
case QIC_TAPE_QIC3010:
|
||||
*qic_std = status & QIC_TAPE_STD_MASK;
|
||||
break;
|
||||
default:
|
||||
*qic_std = -1;
|
||||
break;
|
||||
}
|
||||
switch (status & QIC_TAPE_LEN_MASK) {
|
||||
case QIC_TAPE_205FT:
|
||||
/* 205 or 425+ ft 550 Oe tape */
|
||||
*tape_len = 0;
|
||||
break;
|
||||
case QIC_TAPE_307FT:
|
||||
/* 307.5 ft 550 Oe Extended Length (XL) tape */
|
||||
*tape_len = 307;
|
||||
break;
|
||||
case QIC_TAPE_VARIABLE:
|
||||
/* Variable length 550 Oe tape */
|
||||
*tape_len = 0;
|
||||
break;
|
||||
case QIC_TAPE_1100FT:
|
||||
/* 1100 ft 550 Oe tape */
|
||||
*tape_len = 1100;
|
||||
break;
|
||||
case QIC_TAPE_FLEX:
|
||||
/* Variable length 900 Oe tape */
|
||||
*tape_len = 0;
|
||||
break;
|
||||
default:
|
||||
*tape_len = -1;
|
||||
break;
|
||||
}
|
||||
if (*qic_std == -1 || *tape_len == -1) {
|
||||
TRACE(ft_t_any,
|
||||
"post qic-117b spec drive with unknown tape");
|
||||
}
|
||||
result = *tape_len == -1 ? -EIO : 0;
|
||||
if (status & QIC_TAPE_WIDE) {
|
||||
switch (*qic_std) {
|
||||
case QIC_TAPE_QIC80:
|
||||
TRACE(ft_t_info, "TR-1 tape detected");
|
||||
break;
|
||||
case QIC_TAPE_QIC3010:
|
||||
TRACE(ft_t_info, "TR-2 tape detected");
|
||||
break;
|
||||
case QIC_TAPE_QIC3020:
|
||||
TRACE(ft_t_info, "TR-3 tape detected");
|
||||
break;
|
||||
default:
|
||||
TRACE(ft_t_warn,
|
||||
"Unknown Travan tape type detected");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
TRACE_EXIT (result < 0) ? -EIO : 0;
|
||||
}
|
||||
|
||||
static int ftape_report_rom_version(int *version)
|
||||
{
|
||||
|
||||
if (ftape_report_operation(version, QIC_REPORT_ROM_VERSION, 8) < 0) {
|
||||
return -EIO;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ftape_report_vendor_id(unsigned int *id)
|
||||
{
|
||||
int result;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
/* We'll try to get a vendor id from the drive. First
|
||||
* according to the QIC-117 spec, a 16-bit id is requested.
|
||||
* If that fails we'll try an 8-bit version, otherwise we'll
|
||||
* try an undocumented query.
|
||||
*/
|
||||
result = ftape_report_operation((int *) id, QIC_REPORT_VENDOR_ID, 16);
|
||||
if (result < 0) {
|
||||
result = ftape_report_operation((int *) id,
|
||||
QIC_REPORT_VENDOR_ID, 8);
|
||||
if (result < 0) {
|
||||
/* The following is an undocumented call found
|
||||
* in the CMS code.
|
||||
*/
|
||||
result = ftape_report_operation((int *) id, 24, 8);
|
||||
if (result < 0) {
|
||||
*id = UNKNOWN_VENDOR;
|
||||
} else {
|
||||
TRACE(ft_t_noise, "got old 8 bit id: %04x",
|
||||
*id);
|
||||
*id |= 0x20000;
|
||||
}
|
||||
} else {
|
||||
TRACE(ft_t_noise, "got 8 bit id: %04x", *id);
|
||||
*id |= 0x10000;
|
||||
}
|
||||
} else {
|
||||
TRACE(ft_t_noise, "got 16 bit id: %04x", *id);
|
||||
}
|
||||
if (*id == 0x0047) {
|
||||
int version;
|
||||
int sign;
|
||||
|
||||
if (ftape_report_rom_version(&version) < 0) {
|
||||
TRACE(ft_t_bug, "report rom version failed");
|
||||
TRACE_EXIT;
|
||||
}
|
||||
TRACE(ft_t_noise, "CMS rom version: %d", version);
|
||||
ftape_command(QIC_ENTER_DIAGNOSTIC_1);
|
||||
ftape_command(QIC_ENTER_DIAGNOSTIC_1);
|
||||
diagnostic_mode = 1;
|
||||
if (ftape_report_operation(&sign, 9, 8) < 0) {
|
||||
unsigned int error;
|
||||
qic117_cmd_t command;
|
||||
|
||||
ftape_report_error(&error, &command, 1);
|
||||
ftape_command(QIC_ENTER_PRIMARY_MODE);
|
||||
diagnostic_mode = 0;
|
||||
TRACE_EXIT; /* failure ! */
|
||||
} else {
|
||||
TRACE(ft_t_noise, "CMS signature: %02x", sign);
|
||||
}
|
||||
if (sign == 0xa5) {
|
||||
result = ftape_report_operation(&sign, 37, 8);
|
||||
if (result < 0) {
|
||||
if (version >= 63) {
|
||||
*id = 0x8880;
|
||||
TRACE(ft_t_noise,
|
||||
"This is an Iomega drive !");
|
||||
} else {
|
||||
*id = 0x0047;
|
||||
TRACE(ft_t_noise,
|
||||
"This is a real CMS drive !");
|
||||
}
|
||||
} else {
|
||||
*id = 0x0047;
|
||||
TRACE(ft_t_noise, "CMS status: %d", sign);
|
||||
}
|
||||
} else {
|
||||
*id = UNKNOWN_VENDOR;
|
||||
}
|
||||
ftape_command(QIC_ENTER_PRIMARY_MODE);
|
||||
diagnostic_mode = 0;
|
||||
}
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
static int qic_rate_code(unsigned int rate)
|
||||
{
|
||||
switch (rate) {
|
||||
case 250:
|
||||
return QIC_CONFIG_RATE_250;
|
||||
case 500:
|
||||
return QIC_CONFIG_RATE_500;
|
||||
case 1000:
|
||||
return QIC_CONFIG_RATE_1000;
|
||||
case 2000:
|
||||
return QIC_CONFIG_RATE_2000;
|
||||
default:
|
||||
return QIC_CONFIG_RATE_500;
|
||||
}
|
||||
}
|
||||
|
||||
static int ftape_set_rate_test(unsigned int *max_rate)
|
||||
{
|
||||
unsigned int error;
|
||||
qic117_cmd_t command;
|
||||
int status;
|
||||
int supported = 0;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
/* Check if the drive does support the select rate command
|
||||
* by testing all different settings. If any one is accepted
|
||||
* we assume the command is supported, else not.
|
||||
*/
|
||||
for (*max_rate = 2000; *max_rate >= 250; *max_rate /= 2) {
|
||||
if (ftape_command(QIC_SELECT_RATE) < 0) {
|
||||
continue;
|
||||
}
|
||||
if (ftape_parameter_wait(qic_rate_code(*max_rate),
|
||||
1 * FT_SECOND, &status) < 0) {
|
||||
continue;
|
||||
}
|
||||
if (status & QIC_STATUS_ERROR) {
|
||||
ftape_report_error(&error, &command, 0);
|
||||
continue;
|
||||
}
|
||||
supported = 1; /* did accept a request */
|
||||
break;
|
||||
}
|
||||
TRACE(ft_t_noise, "Select Rate command is%s supported",
|
||||
supported ? "" : " not");
|
||||
TRACE_EXIT supported;
|
||||
}
|
||||
|
||||
int ftape_set_data_rate(unsigned int new_rate /* Kbps */, unsigned int qic_std)
|
||||
{
|
||||
int status;
|
||||
int result = 0;
|
||||
unsigned int data_rate = new_rate;
|
||||
static int supported;
|
||||
int rate_changed = 0;
|
||||
qic_model dummy_model;
|
||||
unsigned int dummy_qic_std, dummy_tape_len;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
if (ft_drive_max_rate == 0) { /* first time */
|
||||
supported = ftape_set_rate_test(&ft_drive_max_rate);
|
||||
}
|
||||
if (supported) {
|
||||
ftape_command(QIC_SELECT_RATE);
|
||||
result = ftape_parameter_wait(qic_rate_code(new_rate),
|
||||
1 * FT_SECOND, &status);
|
||||
if (result >= 0 && !(status & QIC_STATUS_ERROR)) {
|
||||
rate_changed = 1;
|
||||
}
|
||||
}
|
||||
TRACE_CATCH(result = ftape_report_configuration(&dummy_model,
|
||||
&data_rate,
|
||||
&dummy_qic_std,
|
||||
&dummy_tape_len),);
|
||||
if (data_rate != new_rate) {
|
||||
if (!supported) {
|
||||
TRACE(ft_t_warn, "Rate change not supported!");
|
||||
} else if (rate_changed) {
|
||||
TRACE(ft_t_warn, "Requested: %d, got %d",
|
||||
new_rate, data_rate);
|
||||
} else {
|
||||
TRACE(ft_t_warn, "Rate change failed!");
|
||||
}
|
||||
result = -EINVAL;
|
||||
}
|
||||
/*
|
||||
* Set data rate and write precompensation as specified:
|
||||
*
|
||||
* | QIC-40/80 | QIC-3010/3020
|
||||
* rate | precomp | precomp
|
||||
* ----------+-------------+--------------
|
||||
* 250 Kbps. | 250 ns. | 0 ns.
|
||||
* 500 Kbps. | 125 ns. | 0 ns.
|
||||
* 1 Mbps. | 42 ns. | 0 ns.
|
||||
* 2 Mbps | N/A | 0 ns.
|
||||
*/
|
||||
if ((qic_std == QIC_TAPE_QIC40 && data_rate > 500) ||
|
||||
(qic_std == QIC_TAPE_QIC80 && data_rate > 1000)) {
|
||||
TRACE_ABORT(-EINVAL,
|
||||
ft_t_warn, "Datarate too high for QIC-mode");
|
||||
}
|
||||
TRACE_CATCH(fdc_set_data_rate(data_rate),_res = -EINVAL);
|
||||
ft_data_rate = data_rate;
|
||||
if (qic_std == QIC_TAPE_QIC40 || qic_std == QIC_TAPE_QIC80) {
|
||||
switch (data_rate) {
|
||||
case 250:
|
||||
fdc_set_write_precomp(250);
|
||||
break;
|
||||
default:
|
||||
case 500:
|
||||
fdc_set_write_precomp(125);
|
||||
break;
|
||||
case 1000:
|
||||
fdc_set_write_precomp(42);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
fdc_set_write_precomp(0);
|
||||
}
|
||||
TRACE_EXIT result;
|
||||
}
|
||||
|
||||
/* The next two functions are used to cope with excessive overrun errors
|
||||
*/
|
||||
int ftape_increase_threshold(void)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (fdc.type < i82077 || ft_fdc_threshold >= 12) {
|
||||
TRACE_ABORT(-EIO, ft_t_err, "cannot increase fifo threshold");
|
||||
}
|
||||
if (fdc_fifo_threshold(++ft_fdc_threshold, NULL, NULL, NULL) < 0) {
|
||||
TRACE(ft_t_err, "cannot increase fifo threshold");
|
||||
ft_fdc_threshold --;
|
||||
fdc_reset();
|
||||
}
|
||||
TRACE(ft_t_info, "New FIFO threshold: %d", ft_fdc_threshold);
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
int ftape_half_data_rate(void)
|
||||
{
|
||||
if (ft_data_rate < 500) {
|
||||
return -1;
|
||||
}
|
||||
if (ftape_set_data_rate(ft_data_rate / 2, ft_qic_std) < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
ftape_calc_timeouts(ft_qic_std, ft_data_rate, ftape_tape_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Seek the head to the specified track.
|
||||
*/
|
||||
int ftape_seek_head_to_track(unsigned int track)
|
||||
{
|
||||
int status;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
ft_location.track = -1; /* remains set in case of error */
|
||||
if (track >= ft_tracks_per_tape) {
|
||||
TRACE_ABORT(-EINVAL, ft_t_bug, "track out of bounds");
|
||||
}
|
||||
TRACE(ft_t_flow, "seeking track %d", track);
|
||||
TRACE_CATCH(ftape_command(QIC_SEEK_HEAD_TO_TRACK),);
|
||||
TRACE_CATCH(ftape_parameter_wait(track, ftape_timeout.head_seek,
|
||||
&status),);
|
||||
ft_location.track = track;
|
||||
ftape_might_be_off_track = 0;
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
int ftape_wakeup_drive(wake_up_types method)
|
||||
{
|
||||
int status;
|
||||
int motor_on = 0;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
switch (method) {
|
||||
case wake_up_colorado:
|
||||
TRACE_CATCH(ftape_command(QIC_PHANTOM_SELECT),);
|
||||
TRACE_CATCH(ftape_parameter(0 /* ft_drive_sel ?? */),);
|
||||
break;
|
||||
case wake_up_mountain:
|
||||
TRACE_CATCH(ftape_command(QIC_SOFT_SELECT),);
|
||||
ftape_sleep(FT_MILLISECOND); /* NEEDED */
|
||||
TRACE_CATCH(ftape_parameter(18),);
|
||||
break;
|
||||
case wake_up_insight:
|
||||
ftape_sleep(100 * FT_MILLISECOND);
|
||||
motor_on = 1;
|
||||
fdc_motor(motor_on); /* enable is done by motor-on */
|
||||
case no_wake_up:
|
||||
break;
|
||||
default:
|
||||
TRACE_EXIT -ENODEV; /* unknown wakeup method */
|
||||
break;
|
||||
}
|
||||
/* If wakeup succeeded we shouldn't get an error here..
|
||||
*/
|
||||
TRACE_CATCH(ftape_report_raw_drive_status(&status),
|
||||
if (motor_on) {
|
||||
fdc_motor(0);
|
||||
});
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
int ftape_put_drive_to_sleep(wake_up_types method)
|
||||
{
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
switch (method) {
|
||||
case wake_up_colorado:
|
||||
TRACE_CATCH(ftape_command(QIC_PHANTOM_DESELECT),);
|
||||
break;
|
||||
case wake_up_mountain:
|
||||
TRACE_CATCH(ftape_command(QIC_SOFT_DESELECT),);
|
||||
break;
|
||||
case wake_up_insight:
|
||||
fdc_motor(0); /* enable is done by motor-on */
|
||||
case no_wake_up: /* no wakeup / no sleep ! */
|
||||
break;
|
||||
default:
|
||||
TRACE_EXIT -ENODEV; /* unknown wakeup method */
|
||||
}
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
int ftape_reset_drive(void)
|
||||
{
|
||||
int result = 0;
|
||||
int status;
|
||||
unsigned int err_code;
|
||||
qic117_cmd_t err_command;
|
||||
int i;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
/* We want to re-establish contact with our drive. Fire a
|
||||
* number of reset commands (single step pulses) and pray for
|
||||
* success.
|
||||
*/
|
||||
for (i = 0; i < 2; ++i) {
|
||||
TRACE(ft_t_flow, "Resetting fdc");
|
||||
fdc_reset();
|
||||
ftape_sleep(10 * FT_MILLISECOND);
|
||||
TRACE(ft_t_flow, "Reset command to drive");
|
||||
result = ftape_command(QIC_RESET);
|
||||
if (result == 0) {
|
||||
ftape_sleep(1 * FT_SECOND); /* drive not
|
||||
* accessible
|
||||
* during 1 second
|
||||
*/
|
||||
TRACE(ft_t_flow, "Re-selecting drive");
|
||||
|
||||
/* Strange, the QIC-117 specs don't mention
|
||||
* this but the drive gets deselected after a
|
||||
* soft reset ! So we need to enable it
|
||||
* again.
|
||||
*/
|
||||
if (ftape_wakeup_drive(ft_drive_type.wake_up) < 0) {
|
||||
TRACE(ft_t_err, "Wakeup failed !");
|
||||
}
|
||||
TRACE(ft_t_flow, "Waiting until drive gets ready");
|
||||
result= ftape_ready_wait(ftape_timeout.reset, &status);
|
||||
if (result == 0 && (status & QIC_STATUS_ERROR)) {
|
||||
result = ftape_report_error(&err_code,
|
||||
&err_command, 1);
|
||||
if (result == 0 && err_code == 27) {
|
||||
/* Okay, drive saw reset
|
||||
* command and responded as it
|
||||
* should
|
||||
*/
|
||||
break;
|
||||
} else {
|
||||
result = -EIO;
|
||||
}
|
||||
} else {
|
||||
result = -EIO;
|
||||
}
|
||||
}
|
||||
FT_SIGNAL_EXIT(_DONT_BLOCK);
|
||||
}
|
||||
if (result != 0) {
|
||||
TRACE(ft_t_err, "General failure to reset tape drive");
|
||||
} else {
|
||||
/* Restore correct settings: keep original rate
|
||||
*/
|
||||
ftape_set_data_rate(ft_data_rate, ft_qic_std);
|
||||
}
|
||||
ftape_init_drive_needed = 1;
|
||||
TRACE_EXIT result;
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
#ifndef _FTAPE_IO_H
|
||||
#define _FTAPE_IO_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/ftape/lowlevel/ftape-io.h,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:18:18 $
|
||||
*
|
||||
* This file contains definitions for the glue part of the
|
||||
* QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux.
|
||||
*/
|
||||
|
||||
#include <linux/qic117.h>
|
||||
#include <linux/ftape-vendors.h>
|
||||
|
||||
typedef struct {
|
||||
unsigned int seek;
|
||||
unsigned int reset;
|
||||
unsigned int rewind;
|
||||
unsigned int head_seek;
|
||||
unsigned int stop;
|
||||
unsigned int pause;
|
||||
} ft_timeout_table;
|
||||
|
||||
typedef enum {
|
||||
prehistoric, pre_qic117c, post_qic117b, post_qic117d
|
||||
} qic_model;
|
||||
|
||||
/*
|
||||
* ftape-io.c defined global vars.
|
||||
*/
|
||||
extern ft_timeout_table ftape_timeout;
|
||||
extern unsigned int ftape_tape_len;
|
||||
extern volatile qic117_cmd_t ftape_current_command;
|
||||
extern const struct qic117_command_table qic117_cmds[];
|
||||
extern int ftape_might_be_off_track;
|
||||
|
||||
/*
|
||||
* ftape-io.c defined global functions.
|
||||
*/
|
||||
extern void ftape_udelay(unsigned int usecs);
|
||||
extern void ftape_udelay_calibrate(void);
|
||||
extern void ftape_sleep(unsigned int time);
|
||||
extern void ftape_report_vendor_id(unsigned int *id);
|
||||
extern int ftape_command(qic117_cmd_t command);
|
||||
extern int ftape_command_wait(qic117_cmd_t command,
|
||||
unsigned int timeout,
|
||||
int *status);
|
||||
extern int ftape_parameter(unsigned int parameter);
|
||||
extern int ftape_report_operation(int *status,
|
||||
qic117_cmd_t command,
|
||||
int result_length);
|
||||
extern int ftape_report_configuration(qic_model *model,
|
||||
unsigned int *rate,
|
||||
int *qic_std,
|
||||
int *tape_len);
|
||||
extern int ftape_report_drive_status(int *status);
|
||||
extern int ftape_report_raw_drive_status(int *status);
|
||||
extern int ftape_report_status(int *status);
|
||||
extern int ftape_ready_wait(unsigned int timeout, int *status);
|
||||
extern int ftape_seek_head_to_track(unsigned int track);
|
||||
extern int ftape_set_data_rate(unsigned int new_rate, unsigned int qic_std);
|
||||
extern int ftape_report_error(unsigned int *error,
|
||||
qic117_cmd_t *command,
|
||||
int report);
|
||||
extern int ftape_reset_drive(void);
|
||||
extern int ftape_put_drive_to_sleep(wake_up_types method);
|
||||
extern int ftape_wakeup_drive(wake_up_types method);
|
||||
extern int ftape_increase_threshold(void);
|
||||
extern int ftape_half_data_rate(void);
|
||||
|
||||
#endif
|
@ -1,214 +0,0 @@
|
||||
/*
|
||||
* Copyright (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/ftape/lowlevel/ftape-proc.c,v $
|
||||
* $Revision: 1.11 $
|
||||
* $Date: 1997/10/24 14:47:37 $
|
||||
*
|
||||
* This file contains the procfs interface for the
|
||||
* QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux.
|
||||
|
||||
* Old code removed, switched to dynamic proc entry.
|
||||
*/
|
||||
|
||||
|
||||
#if defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS)
|
||||
|
||||
#include <linux/proc_fs.h>
|
||||
|
||||
#include <linux/ftape.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/qic117.h>
|
||||
|
||||
#include "../lowlevel/ftape-io.h"
|
||||
#include "../lowlevel/ftape-ctl.h"
|
||||
#include "../lowlevel/ftape-proc.h"
|
||||
#include "../lowlevel/ftape-tracing.h"
|
||||
|
||||
static size_t get_driver_info(char *buf)
|
||||
{
|
||||
const char *debug_level[] = { "bugs" ,
|
||||
"errors",
|
||||
"warnings",
|
||||
"informational",
|
||||
"noisy",
|
||||
"program flow",
|
||||
"fdc and dma",
|
||||
"data flow",
|
||||
"anything" };
|
||||
|
||||
return sprintf(buf,
|
||||
"version : %s\n"
|
||||
"used data rate: %d kbit/sec\n"
|
||||
"dma memory : %d kb\n"
|
||||
"debug messages: %s\n",
|
||||
FTAPE_VERSION,
|
||||
ft_data_rate,
|
||||
FT_BUFF_SIZE * ft_nr_buffers >> 10,
|
||||
debug_level[TRACE_LEVEL]);
|
||||
}
|
||||
|
||||
static size_t get_tapedrive_info(char *buf)
|
||||
{
|
||||
return sprintf(buf,
|
||||
"vendor id : 0x%04x\n"
|
||||
"drive name: %s\n"
|
||||
"wind speed: %d ips\n"
|
||||
"wakeup : %s\n"
|
||||
"max. rate : %d kbit/sec\n",
|
||||
ft_drive_type.vendor_id,
|
||||
ft_drive_type.name,
|
||||
ft_drive_type.speed,
|
||||
((ft_drive_type.wake_up == no_wake_up)
|
||||
? "No wakeup needed" :
|
||||
((ft_drive_type.wake_up == wake_up_colorado)
|
||||
? "Colorado" :
|
||||
((ft_drive_type.wake_up == wake_up_mountain)
|
||||
? "Mountain" :
|
||||
((ft_drive_type.wake_up == wake_up_insight)
|
||||
? "Motor on" :
|
||||
"Unknown")))),
|
||||
ft_drive_max_rate);
|
||||
}
|
||||
|
||||
static size_t get_cartridge_info(char *buf)
|
||||
{
|
||||
if (ftape_init_drive_needed) {
|
||||
return sprintf(buf, "uninitialized\n");
|
||||
}
|
||||
if (ft_no_tape) {
|
||||
return sprintf(buf, "no cartridge inserted\n");
|
||||
}
|
||||
return sprintf(buf,
|
||||
"segments : %5d\n"
|
||||
"tracks : %5d\n"
|
||||
"length : %5dft\n"
|
||||
"formatted : %3s\n"
|
||||
"writable : %3s\n"
|
||||
"QIC spec. : QIC-%s\n"
|
||||
"fmt-code : %1d\n",
|
||||
ft_segments_per_track,
|
||||
ft_tracks_per_tape,
|
||||
ftape_tape_len,
|
||||
(ft_formatted == 1) ? "yes" : "no",
|
||||
(ft_write_protected == 1) ? "no" : "yes",
|
||||
((ft_qic_std == QIC_TAPE_QIC40) ? "40" :
|
||||
((ft_qic_std == QIC_TAPE_QIC80) ? "80" :
|
||||
((ft_qic_std == QIC_TAPE_QIC3010) ? "3010" :
|
||||
((ft_qic_std == QIC_TAPE_QIC3020) ? "3020" :
|
||||
"???")))),
|
||||
ft_format_code);
|
||||
}
|
||||
|
||||
static size_t get_controller_info(char *buf)
|
||||
{
|
||||
const char *fdc_name[] = { "no fdc",
|
||||
"i8272",
|
||||
"i82077",
|
||||
"i82077AA",
|
||||
"Colorado FC-10 or FC-20",
|
||||
"i82078",
|
||||
"i82078_1" };
|
||||
|
||||
return sprintf(buf,
|
||||
"FDC type : %s\n"
|
||||
"FDC base : 0x%03x\n"
|
||||
"FDC irq : %d\n"
|
||||
"FDC dma : %d\n"
|
||||
"FDC thr. : %d\n"
|
||||
"max. rate : %d kbit/sec\n",
|
||||
ft_mach2 ? "Mountain MACH-2" : fdc_name[fdc.type],
|
||||
fdc.sra, fdc.irq, fdc.dma,
|
||||
ft_fdc_threshold, ft_fdc_max_rate);
|
||||
}
|
||||
|
||||
static size_t get_history_info(char *buf)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
len = sprintf(buf,
|
||||
"\nFDC isr statistics\n"
|
||||
" id_am_errors : %3d\n"
|
||||
" id_crc_errors : %3d\n"
|
||||
" data_am_errors : %3d\n"
|
||||
" data_crc_errors : %3d\n"
|
||||
" overrun_errors : %3d\n"
|
||||
" no_data_errors : %3d\n"
|
||||
" retries : %3d\n",
|
||||
ft_history.id_am_errors, ft_history.id_crc_errors,
|
||||
ft_history.data_am_errors, ft_history.data_crc_errors,
|
||||
ft_history.overrun_errors, ft_history.no_data_errors,
|
||||
ft_history.retries);
|
||||
len += sprintf(buf + len,
|
||||
"\nECC statistics\n"
|
||||
" crc_errors : %3d\n"
|
||||
" crc_failures : %3d\n"
|
||||
" ecc_failures : %3d\n"
|
||||
" sectors corrected: %3d\n",
|
||||
ft_history.crc_errors, ft_history.crc_failures,
|
||||
ft_history.ecc_failures, ft_history.corrected);
|
||||
len += sprintf(buf + len,
|
||||
"\ntape quality statistics\n"
|
||||
" media defects : %3d\n",
|
||||
ft_history.defects);
|
||||
len += sprintf(buf + len,
|
||||
"\ntape motion statistics\n"
|
||||
" repositions : %3d\n",
|
||||
ft_history.rewinds);
|
||||
return len;
|
||||
}
|
||||
|
||||
static int ftape_read_proc(char *page, char **start, off_t off,
|
||||
int count, int *eof, void *data)
|
||||
{
|
||||
char *ptr = page;
|
||||
size_t len;
|
||||
|
||||
ptr += sprintf(ptr, "Kernel Driver\n\n");
|
||||
ptr += get_driver_info(ptr);
|
||||
ptr += sprintf(ptr, "\nTape Drive\n\n");
|
||||
ptr += get_tapedrive_info(ptr);
|
||||
ptr += sprintf(ptr, "\nFDC Controller\n\n");
|
||||
ptr += get_controller_info(ptr);
|
||||
ptr += sprintf(ptr, "\nTape Cartridge\n\n");
|
||||
ptr += get_cartridge_info(ptr);
|
||||
ptr += sprintf(ptr, "\nHistory Record\n\n");
|
||||
ptr += get_history_info(ptr);
|
||||
|
||||
len = strlen(page);
|
||||
*start = NULL;
|
||||
if (off+count >= len) {
|
||||
*eof = 1;
|
||||
} else {
|
||||
*eof = 0;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int __init ftape_proc_init(void)
|
||||
{
|
||||
return create_proc_read_entry("ftape", 0, &proc_root,
|
||||
ftape_read_proc, NULL) != NULL;
|
||||
}
|
||||
|
||||
void ftape_proc_destroy(void)
|
||||
{
|
||||
remove_proc_entry("ftape", &proc_root);
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS) */
|
@ -1,35 +0,0 @@
|
||||
#ifndef _FTAPE_PROC_H
|
||||
#define _FTAPE_PROC_H
|
||||
|
||||
/*
|
||||
* Copyright (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/ftape/lowlevel/ftape-proc.h,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:18:20 $
|
||||
*
|
||||
* This file contains definitions for the procfs interface of the
|
||||
* QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux.
|
||||
*/
|
||||
|
||||
#include <linux/proc_fs.h>
|
||||
|
||||
extern int ftape_proc_init(void);
|
||||
extern void ftape_proc_destroy(void);
|
||||
|
||||
#endif
|
@ -1,621 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1993-1996 Bas Laarhoven,
|
||||
* (C) 1996-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/ftape/lowlevel/ftape-read.c,v $
|
||||
* $Revision: 1.6 $
|
||||
* $Date: 1997/10/21 14:39:22 $
|
||||
*
|
||||
* This file contains the reading code
|
||||
* for the QIC-117 floppy-tape driver for Linux.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <linux/ftape.h>
|
||||
#include <linux/qic117.h>
|
||||
#include "../lowlevel/ftape-tracing.h"
|
||||
#include "../lowlevel/ftape-read.h"
|
||||
#include "../lowlevel/ftape-io.h"
|
||||
#include "../lowlevel/ftape-ctl.h"
|
||||
#include "../lowlevel/ftape-rw.h"
|
||||
#include "../lowlevel/ftape-write.h"
|
||||
#include "../lowlevel/ftape-ecc.h"
|
||||
#include "../lowlevel/ftape-bsm.h"
|
||||
|
||||
/* Global vars.
|
||||
*/
|
||||
|
||||
/* Local vars.
|
||||
*/
|
||||
|
||||
void ftape_zap_read_buffers(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ft_nr_buffers; ++i) {
|
||||
/* changed to "fit" with dynamic allocation of tape_buffer. --khp */
|
||||
ft_buffer[i]->status = waiting;
|
||||
ft_buffer[i]->bytes = 0;
|
||||
ft_buffer[i]->skip = 0;
|
||||
ft_buffer[i]->retry = 0;
|
||||
}
|
||||
/* ftape_reset_buffer(); */
|
||||
}
|
||||
|
||||
static SectorMap convert_sector_map(buffer_struct * buff)
|
||||
{
|
||||
int i = 0;
|
||||
SectorMap bad_map = ftape_get_bad_sector_entry(buff->segment_id);
|
||||
SectorMap src_map = buff->soft_error_map | buff->hard_error_map;
|
||||
SectorMap dst_map = 0;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
if (bad_map || src_map) {
|
||||
TRACE(ft_t_flow, "bad_map = 0x%08lx", (long) bad_map);
|
||||
TRACE(ft_t_flow, "src_map = 0x%08lx", (long) src_map);
|
||||
}
|
||||
while (bad_map) {
|
||||
while ((bad_map & 1) == 0) {
|
||||
if (src_map & 1) {
|
||||
dst_map |= (1 << i);
|
||||
}
|
||||
src_map >>= 1;
|
||||
bad_map >>= 1;
|
||||
++i;
|
||||
}
|
||||
/* (bad_map & 1) == 1 */
|
||||
src_map >>= 1;
|
||||
bad_map >>= 1;
|
||||
}
|
||||
if (src_map) {
|
||||
dst_map |= (src_map << i);
|
||||
}
|
||||
if (dst_map) {
|
||||
TRACE(ft_t_flow, "dst_map = 0x%08lx", (long) dst_map);
|
||||
}
|
||||
TRACE_EXIT dst_map;
|
||||
}
|
||||
|
||||
static int correct_and_copy_fraction(buffer_struct *buff, __u8 * destination,
|
||||
int start, int size)
|
||||
{
|
||||
struct memory_segment mseg;
|
||||
int result;
|
||||
SectorMap read_bad;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
mseg.read_bad = convert_sector_map(buff);
|
||||
mseg.marked_bad = 0; /* not used... */
|
||||
mseg.blocks = buff->bytes / FT_SECTOR_SIZE;
|
||||
mseg.data = buff->address;
|
||||
/* If there are no data sectors we can skip this segment.
|
||||
*/
|
||||
if (mseg.blocks <= 3) {
|
||||
TRACE_ABORT(0, ft_t_noise, "empty segment");
|
||||
}
|
||||
read_bad = mseg.read_bad;
|
||||
ft_history.crc_errors += count_ones(read_bad);
|
||||
result = ftape_ecc_correct_data(&mseg);
|
||||
if (read_bad != 0 || mseg.corrected != 0) {
|
||||
TRACE(ft_t_noise, "crc error map: 0x%08lx", (unsigned long)read_bad);
|
||||
TRACE(ft_t_noise, "corrected map: 0x%08lx", (unsigned long)mseg.corrected);
|
||||
ft_history.corrected += count_ones(mseg.corrected);
|
||||
}
|
||||
if (result == ECC_CORRECTED || result == ECC_OK) {
|
||||
if (result == ECC_CORRECTED) {
|
||||
TRACE(ft_t_info, "ecc corrected segment: %d", buff->segment_id);
|
||||
}
|
||||
if(start < 0) {
|
||||
start= 0;
|
||||
}
|
||||
if((start+size) > ((mseg.blocks - 3) * FT_SECTOR_SIZE)) {
|
||||
size = (mseg.blocks - 3) * FT_SECTOR_SIZE - start;
|
||||
}
|
||||
if (size < 0) {
|
||||
size= 0;
|
||||
}
|
||||
if(size > 0) {
|
||||
memcpy(destination + start, mseg.data + start, size);
|
||||
}
|
||||
if ((read_bad ^ mseg.corrected) & mseg.corrected) {
|
||||
/* sectors corrected without crc errors set */
|
||||
ft_history.crc_failures++;
|
||||
}
|
||||
TRACE_EXIT size; /* (mseg.blocks - 3) * FT_SECTOR_SIZE; */
|
||||
} else {
|
||||
ft_history.ecc_failures++;
|
||||
TRACE_ABORT(-EAGAIN,
|
||||
ft_t_err, "ecc failure on segment %d",
|
||||
buff->segment_id);
|
||||
}
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
/* Read given segment into buffer at address.
|
||||
*/
|
||||
int ftape_read_segment_fraction(const int segment_id,
|
||||
void *address,
|
||||
const ft_read_mode_t read_mode,
|
||||
const int start,
|
||||
const int size)
|
||||
{
|
||||
int result = 0;
|
||||
int retry = 0;
|
||||
int bytes_read = 0;
|
||||
int read_done = 0;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
ft_history.used |= 1;
|
||||
TRACE(ft_t_data_flow, "segment_id = %d", segment_id);
|
||||
if (ft_driver_state != reading) {
|
||||
TRACE(ft_t_noise, "calling ftape_abort_operation");
|
||||
TRACE_CATCH(ftape_abort_operation(),);
|
||||
ftape_set_state(reading);
|
||||
}
|
||||
for(;;) {
|
||||
buffer_struct *tail;
|
||||
/* Allow escape from this loop on signal !
|
||||
*/
|
||||
FT_SIGNAL_EXIT(_DONT_BLOCK);
|
||||
/* Search all full buffers for the first matching the
|
||||
* wanted segment. Clear other buffers on the fly.
|
||||
*/
|
||||
tail = ftape_get_buffer(ft_queue_tail);
|
||||
while (!read_done && tail->status == done) {
|
||||
/* Allow escape from this loop on signal !
|
||||
*/
|
||||
FT_SIGNAL_EXIT(_DONT_BLOCK);
|
||||
if (tail->segment_id == segment_id) {
|
||||
/* If out buffer is already full,
|
||||
* return its contents.
|
||||
*/
|
||||
TRACE(ft_t_flow, "found segment in cache: %d",
|
||||
segment_id);
|
||||
if (tail->deleted) {
|
||||
/* Return a value that
|
||||
* read_header_segment
|
||||
* understands. As this
|
||||
* should only occur when
|
||||
* searching for the header
|
||||
* segments it shouldn't be
|
||||
* misinterpreted elsewhere.
|
||||
*/
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
result = correct_and_copy_fraction(
|
||||
tail,
|
||||
address,
|
||||
start,
|
||||
size);
|
||||
TRACE(ft_t_flow, "segment contains (bytes): %d",
|
||||
result);
|
||||
if (result < 0) {
|
||||
if (result != -EAGAIN) {
|
||||
TRACE_EXIT result;
|
||||
}
|
||||
/* keep read_done == 0, will
|
||||
* trigger
|
||||
* ftape_abort_operation
|
||||
* because reading wrong
|
||||
* segment.
|
||||
*/
|
||||
TRACE(ft_t_err, "ecc failed, retry");
|
||||
++retry;
|
||||
} else {
|
||||
read_done = 1;
|
||||
bytes_read = result;
|
||||
}
|
||||
} else {
|
||||
TRACE(ft_t_flow,"zapping segment in cache: %d",
|
||||
tail->segment_id);
|
||||
}
|
||||
tail->status = waiting;
|
||||
tail = ftape_next_buffer(ft_queue_tail);
|
||||
}
|
||||
if (!read_done && tail->status == reading) {
|
||||
if (tail->segment_id == segment_id) {
|
||||
switch(ftape_wait_segment(reading)) {
|
||||
case 0:
|
||||
break;
|
||||
case -EINTR:
|
||||
TRACE_ABORT(-EINTR, ft_t_warn,
|
||||
"interrupted by "
|
||||
"non-blockable signal");
|
||||
break;
|
||||
default:
|
||||
TRACE(ft_t_noise,
|
||||
"wait_segment failed");
|
||||
ftape_abort_operation();
|
||||
ftape_set_state(reading);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* We're reading the wrong segment,
|
||||
* stop runner.
|
||||
*/
|
||||
TRACE(ft_t_noise, "reading wrong segment");
|
||||
ftape_abort_operation();
|
||||
ftape_set_state(reading);
|
||||
}
|
||||
}
|
||||
/* should runner stop ?
|
||||
*/
|
||||
if (ft_runner_status == aborting) {
|
||||
buffer_struct *head = ftape_get_buffer(ft_queue_head);
|
||||
switch(head->status) {
|
||||
case error:
|
||||
ft_history.defects +=
|
||||
count_ones(head->hard_error_map);
|
||||
case reading:
|
||||
head->status = waiting;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
TRACE_CATCH(ftape_dumb_stop(),);
|
||||
} else {
|
||||
/* If just passed last segment on tape: wait
|
||||
* for BOT or EOT mark. Sets ft_runner_status to
|
||||
* idle if at lEOT and successful
|
||||
*/
|
||||
TRACE_CATCH(ftape_handle_logical_eot(),);
|
||||
}
|
||||
/* If we got a segment: quit, or else retry up to limit.
|
||||
*
|
||||
* If segment to read is empty, do not start runner for it,
|
||||
* but wait for next read call.
|
||||
*/
|
||||
if (read_done ||
|
||||
ftape_get_bad_sector_entry(segment_id) == EMPTY_SEGMENT ) {
|
||||
/* bytes_read = 0; should still be zero */
|
||||
TRACE_EXIT bytes_read;
|
||||
|
||||
}
|
||||
if (retry > FT_RETRIES_ON_ECC_ERROR) {
|
||||
ft_history.defects++;
|
||||
TRACE_ABORT(-ENODATA, ft_t_err,
|
||||
"too many retries on ecc failure");
|
||||
}
|
||||
/* Now at least one buffer is empty !
|
||||
* Restart runner & tape if needed.
|
||||
*/
|
||||
TRACE(ft_t_any, "head: %d, tail: %d, ft_runner_status: %d",
|
||||
ftape_buffer_id(ft_queue_head),
|
||||
ftape_buffer_id(ft_queue_tail),
|
||||
ft_runner_status);
|
||||
TRACE(ft_t_any, "buffer[].status, [head]: %d, [tail]: %d",
|
||||
ftape_get_buffer(ft_queue_head)->status,
|
||||
ftape_get_buffer(ft_queue_tail)->status);
|
||||
tail = ftape_get_buffer(ft_queue_tail);
|
||||
if (tail->status == waiting) {
|
||||
buffer_struct *head = ftape_get_buffer(ft_queue_head);
|
||||
|
||||
ftape_setup_new_segment(head, segment_id, -1);
|
||||
if (read_mode == FT_RD_SINGLE) {
|
||||
/* disable read-ahead */
|
||||
head->next_segment = 0;
|
||||
}
|
||||
ftape_calc_next_cluster(head);
|
||||
if (ft_runner_status == idle) {
|
||||
result = ftape_start_tape(segment_id,
|
||||
head->sector_offset);
|
||||
if (result < 0) {
|
||||
TRACE_ABORT(result, ft_t_err, "Error: "
|
||||
"segment %d unreachable",
|
||||
segment_id);
|
||||
}
|
||||
}
|
||||
head->status = reading;
|
||||
fdc_setup_read_write(head, FDC_READ);
|
||||
}
|
||||
}
|
||||
/* not reached */
|
||||
TRACE_EXIT -EIO;
|
||||
}
|
||||
|
||||
int ftape_read_header_segment(__u8 *address)
|
||||
{
|
||||
int result;
|
||||
int header_segment;
|
||||
int first_failed = 0;
|
||||
int status;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
ft_used_header_segment = -1;
|
||||
TRACE_CATCH(ftape_report_drive_status(&status),);
|
||||
TRACE(ft_t_flow, "reading...");
|
||||
/* We're looking for the first header segment.
|
||||
* A header segment cannot contain bad sectors, therefor at the
|
||||
* tape start, segments with bad sectors are (according to QIC-40/80)
|
||||
* written with deleted data marks and must be skipped.
|
||||
*/
|
||||
memset(address, '\0', (FT_SECTORS_PER_SEGMENT - 3) * FT_SECTOR_SIZE);
|
||||
result = 0;
|
||||
#define HEADER_SEGMENT_BOUNDARY 68 /* why not 42? */
|
||||
for (header_segment = 0;
|
||||
header_segment < HEADER_SEGMENT_BOUNDARY && result == 0;
|
||||
++header_segment) {
|
||||
/* Set no read-ahead, the isr will force read-ahead whenever
|
||||
* it encounters deleted data !
|
||||
*/
|
||||
result = ftape_read_segment(header_segment,
|
||||
address,
|
||||
FT_RD_SINGLE);
|
||||
if (result < 0 && !first_failed) {
|
||||
TRACE(ft_t_err, "header segment damaged, trying backup");
|
||||
first_failed = 1;
|
||||
result = 0; /* force read of next (backup) segment */
|
||||
}
|
||||
}
|
||||
if (result < 0 || header_segment >= HEADER_SEGMENT_BOUNDARY) {
|
||||
TRACE_ABORT(-EIO, ft_t_err,
|
||||
"no readable header segment found");
|
||||
}
|
||||
TRACE_CATCH(ftape_abort_operation(),);
|
||||
ft_used_header_segment = header_segment;
|
||||
result = ftape_decode_header_segment(address);
|
||||
TRACE_EXIT result;
|
||||
}
|
||||
|
||||
int ftape_decode_header_segment(__u8 *address)
|
||||
{
|
||||
unsigned int max_floppy_side;
|
||||
unsigned int max_floppy_track;
|
||||
unsigned int max_floppy_sector;
|
||||
unsigned int new_tape_len;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (GET4(address, FT_SIGNATURE) == FT_D2G_MAGIC) {
|
||||
/* Ditto 2GB header segment. They encrypt the bad sector map.
|
||||
* We decrypt it and store them in normal format.
|
||||
* I hope this is correct.
|
||||
*/
|
||||
int i;
|
||||
TRACE(ft_t_warn,
|
||||
"Found Ditto 2GB tape, "
|
||||
"trying to decrypt bad sector map");
|
||||
for (i=256; i < 29 * FT_SECTOR_SIZE; i++) {
|
||||
address[i] = ~(address[i] - (i&0xff));
|
||||
}
|
||||
PUT4(address, 0,FT_HSEG_MAGIC);
|
||||
} else if (GET4(address, FT_SIGNATURE) != FT_HSEG_MAGIC) {
|
||||
TRACE_ABORT(-EIO, ft_t_err,
|
||||
"wrong signature in header segment");
|
||||
}
|
||||
ft_format_code = (ft_format_type) address[FT_FMT_CODE];
|
||||
if (ft_format_code != fmt_big) {
|
||||
ft_header_segment_1 = GET2(address, FT_HSEG_1);
|
||||
ft_header_segment_2 = GET2(address, FT_HSEG_2);
|
||||
ft_first_data_segment = GET2(address, FT_FRST_SEG);
|
||||
ft_last_data_segment = GET2(address, FT_LAST_SEG);
|
||||
} else {
|
||||
ft_header_segment_1 = GET4(address, FT_6_HSEG_1);
|
||||
ft_header_segment_2 = GET4(address, FT_6_HSEG_2);
|
||||
ft_first_data_segment = GET4(address, FT_6_FRST_SEG);
|
||||
ft_last_data_segment = GET4(address, FT_6_LAST_SEG);
|
||||
}
|
||||
TRACE(ft_t_noise, "first data segment: %d", ft_first_data_segment);
|
||||
TRACE(ft_t_noise, "last data segment: %d", ft_last_data_segment);
|
||||
TRACE(ft_t_noise, "header segments are %d and %d",
|
||||
ft_header_segment_1, ft_header_segment_2);
|
||||
|
||||
/* Verify tape parameters...
|
||||
* QIC-40/80 spec: tape_parameters:
|
||||
*
|
||||
* segments-per-track segments_per_track
|
||||
* tracks-per-cartridge tracks_per_tape
|
||||
* max-floppy-side (segments_per_track *
|
||||
* tracks_per_tape - 1) /
|
||||
* ftape_segments_per_head
|
||||
* max-floppy-track ftape_segments_per_head /
|
||||
* ftape_segments_per_cylinder - 1
|
||||
* max-floppy-sector ftape_segments_per_cylinder *
|
||||
* FT_SECTORS_PER_SEGMENT
|
||||
*/
|
||||
ft_segments_per_track = GET2(address, FT_SPT);
|
||||
ft_tracks_per_tape = address[FT_TPC];
|
||||
max_floppy_side = address[FT_FHM];
|
||||
max_floppy_track = address[FT_FTM];
|
||||
max_floppy_sector = address[FT_FSM];
|
||||
TRACE(ft_t_noise, "(fmt/spt/tpc/fhm/ftm/fsm) = %d/%d/%d/%d/%d/%d",
|
||||
ft_format_code, ft_segments_per_track, ft_tracks_per_tape,
|
||||
max_floppy_side, max_floppy_track, max_floppy_sector);
|
||||
new_tape_len = ftape_tape_len;
|
||||
switch (ft_format_code) {
|
||||
case fmt_425ft:
|
||||
new_tape_len = 425;
|
||||
break;
|
||||
case fmt_normal:
|
||||
if (ftape_tape_len == 0) { /* otherwise 307 ft */
|
||||
new_tape_len = 205;
|
||||
}
|
||||
break;
|
||||
case fmt_1100ft:
|
||||
new_tape_len = 1100;
|
||||
break;
|
||||
case fmt_var:{
|
||||
int segments_per_1000_inch = 1; /* non-zero default for switch */
|
||||
switch (ft_qic_std) {
|
||||
case QIC_TAPE_QIC40:
|
||||
segments_per_1000_inch = 332;
|
||||
break;
|
||||
case QIC_TAPE_QIC80:
|
||||
segments_per_1000_inch = 488;
|
||||
break;
|
||||
case QIC_TAPE_QIC3010:
|
||||
segments_per_1000_inch = 730;
|
||||
break;
|
||||
case QIC_TAPE_QIC3020:
|
||||
segments_per_1000_inch = 1430;
|
||||
break;
|
||||
}
|
||||
new_tape_len = (1000 * ft_segments_per_track +
|
||||
(segments_per_1000_inch - 1)) / segments_per_1000_inch;
|
||||
break;
|
||||
}
|
||||
case fmt_big:{
|
||||
int segments_per_1000_inch = 1; /* non-zero default for switch */
|
||||
switch (ft_qic_std) {
|
||||
case QIC_TAPE_QIC40:
|
||||
segments_per_1000_inch = 332;
|
||||
break;
|
||||
case QIC_TAPE_QIC80:
|
||||
segments_per_1000_inch = 488;
|
||||
break;
|
||||
case QIC_TAPE_QIC3010:
|
||||
segments_per_1000_inch = 730;
|
||||
break;
|
||||
case QIC_TAPE_QIC3020:
|
||||
segments_per_1000_inch = 1430;
|
||||
break;
|
||||
default:
|
||||
TRACE_ABORT(-EIO, ft_t_bug,
|
||||
"%x QIC-standard with fmt-code %d, please report",
|
||||
ft_qic_std, ft_format_code);
|
||||
}
|
||||
new_tape_len = ((1000 * ft_segments_per_track +
|
||||
(segments_per_1000_inch - 1)) /
|
||||
segments_per_1000_inch);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
TRACE_ABORT(-EIO, ft_t_err,
|
||||
"unknown tape format, please report !");
|
||||
}
|
||||
if (new_tape_len != ftape_tape_len) {
|
||||
ftape_tape_len = new_tape_len;
|
||||
TRACE(ft_t_info, "calculated tape length is %d ft",
|
||||
ftape_tape_len);
|
||||
ftape_calc_timeouts(ft_qic_std, ft_data_rate, ftape_tape_len);
|
||||
}
|
||||
if (ft_segments_per_track == 0 && ft_tracks_per_tape == 0 &&
|
||||
max_floppy_side == 0 && max_floppy_track == 0 &&
|
||||
max_floppy_sector == 0) {
|
||||
/* QIC-40 Rev E and earlier has no values in the header.
|
||||
*/
|
||||
ft_segments_per_track = 68;
|
||||
ft_tracks_per_tape = 20;
|
||||
max_floppy_side = 1;
|
||||
max_floppy_track = 169;
|
||||
max_floppy_sector = 128;
|
||||
}
|
||||
/* This test will compensate for the wrong parameter on tapes
|
||||
* formatted by Conner software.
|
||||
*/
|
||||
if (ft_segments_per_track == 150 &&
|
||||
ft_tracks_per_tape == 28 &&
|
||||
max_floppy_side == 7 &&
|
||||
max_floppy_track == 149 &&
|
||||
max_floppy_sector == 128) {
|
||||
TRACE(ft_t_info, "the famous CONNER bug: max_floppy_side off by one !");
|
||||
max_floppy_side = 6;
|
||||
}
|
||||
/* These tests will compensate for the wrong parameter on tapes
|
||||
* formatted by ComByte Windows software.
|
||||
*
|
||||
* First, for 205 foot tapes
|
||||
*/
|
||||
if (ft_segments_per_track == 100 &&
|
||||
ft_tracks_per_tape == 28 &&
|
||||
max_floppy_side == 9 &&
|
||||
max_floppy_track == 149 &&
|
||||
max_floppy_sector == 128) {
|
||||
TRACE(ft_t_info, "the ComByte bug: max_floppy_side incorrect!");
|
||||
max_floppy_side = 4;
|
||||
}
|
||||
/* Next, for 307 foot tapes. */
|
||||
if (ft_segments_per_track == 150 &&
|
||||
ft_tracks_per_tape == 28 &&
|
||||
max_floppy_side == 9 &&
|
||||
max_floppy_track == 149 &&
|
||||
max_floppy_sector == 128) {
|
||||
TRACE(ft_t_info, "the ComByte bug: max_floppy_side incorrect!");
|
||||
max_floppy_side = 6;
|
||||
}
|
||||
/* This test will compensate for the wrong parameter on tapes
|
||||
* formatted by Colorado Windows software.
|
||||
*/
|
||||
if (ft_segments_per_track == 150 &&
|
||||
ft_tracks_per_tape == 28 &&
|
||||
max_floppy_side == 6 &&
|
||||
max_floppy_track == 150 &&
|
||||
max_floppy_sector == 128) {
|
||||
TRACE(ft_t_info, "the famous Colorado bug: max_floppy_track off by one !");
|
||||
max_floppy_track = 149;
|
||||
}
|
||||
ftape_segments_per_head = ((max_floppy_sector/FT_SECTORS_PER_SEGMENT) *
|
||||
(max_floppy_track + 1));
|
||||
/* This test will compensate for some bug reported by Dima
|
||||
* Brodsky. Seems to be a Colorado bug, either. (freebee
|
||||
* Imation tape shipped together with Colorado T3000
|
||||
*/
|
||||
if ((ft_format_code == fmt_var || ft_format_code == fmt_big) &&
|
||||
ft_tracks_per_tape == 50 &&
|
||||
max_floppy_side == 54 &&
|
||||
max_floppy_track == 255 &&
|
||||
max_floppy_sector == 128) {
|
||||
TRACE(ft_t_info, "the famous ??? bug: max_floppy_track off by one !");
|
||||
max_floppy_track = 254;
|
||||
}
|
||||
/*
|
||||
* Verify drive_configuration with tape parameters
|
||||
*/
|
||||
if (ftape_segments_per_head == 0 || ftape_segments_per_cylinder == 0 ||
|
||||
((ft_segments_per_track * ft_tracks_per_tape - 1) / ftape_segments_per_head
|
||||
!= max_floppy_side) ||
|
||||
(ftape_segments_per_head / ftape_segments_per_cylinder - 1 != max_floppy_track) ||
|
||||
(ftape_segments_per_cylinder * FT_SECTORS_PER_SEGMENT != max_floppy_sector)
|
||||
#ifdef TESTING
|
||||
|| ((ft_format_code == fmt_var || ft_format_code == fmt_big) &&
|
||||
(max_floppy_track != 254 || max_floppy_sector != 128))
|
||||
#endif
|
||||
) {
|
||||
char segperheadz = ftape_segments_per_head ? ' ' : '?';
|
||||
char segpercylz = ftape_segments_per_cylinder ? ' ' : '?';
|
||||
TRACE(ft_t_err,"Tape parameters inconsistency, please report");
|
||||
TRACE(ft_t_err, "reported = %d/%d/%d/%d/%d/%d",
|
||||
ft_format_code,
|
||||
ft_segments_per_track,
|
||||
ft_tracks_per_tape,
|
||||
max_floppy_side,
|
||||
max_floppy_track,
|
||||
max_floppy_sector);
|
||||
TRACE(ft_t_err, "required = %d/%d/%d/%d%c/%d%c/%d",
|
||||
ft_format_code,
|
||||
ft_segments_per_track,
|
||||
ft_tracks_per_tape,
|
||||
ftape_segments_per_head ?
|
||||
((ft_segments_per_track * ft_tracks_per_tape -1) /
|
||||
ftape_segments_per_head ) :
|
||||
(ft_segments_per_track * ft_tracks_per_tape -1),
|
||||
segperheadz,
|
||||
ftape_segments_per_cylinder ?
|
||||
(ftape_segments_per_head /
|
||||
ftape_segments_per_cylinder - 1 ) :
|
||||
ftape_segments_per_head - 1,
|
||||
segpercylz,
|
||||
(ftape_segments_per_cylinder * FT_SECTORS_PER_SEGMENT));
|
||||
TRACE_EXIT -EIO;
|
||||
}
|
||||
ftape_extract_bad_sector_map(address);
|
||||
TRACE_EXIT 0;
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
#ifndef _FTAPE_READ_H
|
||||
#define _FTAPE_READ_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 1994-1996 Bas Laarhoven,
|
||||
* (C) 1996-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/ftape/lowlevel/ftape-read.h,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:18:22 $
|
||||
*
|
||||
* This file contains the definitions for the read functions
|
||||
* for the QIC-117 floppy-tape driver for Linux.
|
||||
*
|
||||
*/
|
||||
|
||||
/* ftape-read.c defined global functions.
|
||||
*/
|
||||
typedef enum {
|
||||
FT_RD_SINGLE = 0,
|
||||
FT_RD_AHEAD = 1,
|
||||
} ft_read_mode_t;
|
||||
|
||||
extern int ftape_read_header_segment(__u8 *address);
|
||||
extern int ftape_decode_header_segment(__u8 *address);
|
||||
extern int ftape_read_segment_fraction(const int segment,
|
||||
void *address,
|
||||
const ft_read_mode_t read_mode,
|
||||
const int start,
|
||||
const int size);
|
||||
#define ftape_read_segment(segment, address, read_mode) \
|
||||
ftape_read_segment_fraction(segment, address, read_mode, \
|
||||
0, FT_SEGMENT_SIZE)
|
||||
extern void ftape_zap_read_buffers(void);
|
||||
|
||||
#endif /* _FTAPE_READ_H */
|
File diff suppressed because it is too large
Load Diff
@ -1,111 +0,0 @@
|
||||
#ifndef _FTAPE_RW_H
|
||||
#define _FTAPE_RW_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 1993-1996 Bas Laarhoven,
|
||||
* (C) 1996-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/ftape/lowlevel/ftape-rw.h,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:18:25 $
|
||||
*
|
||||
* This file contains the definitions for the read and write
|
||||
* functions for the QIC-117 floppy-tape driver for Linux.
|
||||
*
|
||||
* Claus-Justus Heine (1996/09/20): Add definition of format code 6
|
||||
* Claus-Justus Heine (1996/10/04): Changed GET/PUT macros to cast to (__u8 *)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../lowlevel/fdc-io.h"
|
||||
#include "../lowlevel/ftape-init.h"
|
||||
#include "../lowlevel/ftape-bsm.h"
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#define GET2(address, offset) get_unaligned((__u16*)((__u8 *)address + offset))
|
||||
#define GET4(address, offset) get_unaligned((__u32*)((__u8 *)address + offset))
|
||||
#define GET8(address, offset) get_unaligned((__u64*)((__u8 *)address + offset))
|
||||
#define PUT2(address, offset , value) put_unaligned((value), (__u16*)((__u8 *)address + offset))
|
||||
#define PUT4(address, offset , value) put_unaligned((value), (__u32*)((__u8 *)address + offset))
|
||||
#define PUT8(address, offset , value) put_unaligned((value), (__u64*)((__u8 *)address + offset))
|
||||
|
||||
enum runner_status_enum {
|
||||
idle = 0,
|
||||
running,
|
||||
do_abort,
|
||||
aborting,
|
||||
logical_eot,
|
||||
end_of_tape,
|
||||
};
|
||||
|
||||
typedef enum ft_buffer_queue {
|
||||
ft_queue_head = 0,
|
||||
ft_queue_tail = 1
|
||||
} ft_buffer_queue_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
int track; /* tape head position */
|
||||
volatile int segment; /* current segment */
|
||||
volatile int sector; /* sector offset within current segment */
|
||||
volatile unsigned int bot; /* logical begin of track */
|
||||
volatile unsigned int eot; /* logical end of track */
|
||||
volatile unsigned int known; /* validates bot, segment, sector */
|
||||
} location_record;
|
||||
|
||||
/* Count nr of 1's in pattern.
|
||||
*/
|
||||
static inline int count_ones(unsigned long mask)
|
||||
{
|
||||
int bits;
|
||||
|
||||
for (bits = 0; mask != 0; mask >>= 1) {
|
||||
if (mask & 1) {
|
||||
++bits;
|
||||
}
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
#define FT_MAX_NR_BUFFERS 16 /* arbitrary value */
|
||||
/* ftape-rw.c defined global vars.
|
||||
*/
|
||||
extern buffer_struct *ft_buffer[FT_MAX_NR_BUFFERS];
|
||||
extern int ft_nr_buffers;
|
||||
extern location_record ft_location;
|
||||
extern volatile int ftape_tape_running;
|
||||
|
||||
/* ftape-rw.c defined global functions.
|
||||
*/
|
||||
extern int ftape_setup_new_segment(buffer_struct * buff,
|
||||
int segment_id,
|
||||
int offset);
|
||||
extern int ftape_calc_next_cluster(buffer_struct * buff);
|
||||
extern buffer_struct *ftape_next_buffer (ft_buffer_queue_t pos);
|
||||
extern buffer_struct *ftape_get_buffer (ft_buffer_queue_t pos);
|
||||
extern int ftape_buffer_id (ft_buffer_queue_t pos);
|
||||
extern void ftape_reset_buffer(void);
|
||||
extern void ftape_tape_parameters(__u8 drive_configuration);
|
||||
extern int ftape_wait_segment(buffer_state_enum state);
|
||||
extern int ftape_dumb_stop(void);
|
||||
extern int ftape_start_tape(int segment_id, int offset);
|
||||
extern int ftape_stop_tape(int *pstatus);
|
||||
extern int ftape_handle_logical_eot(void);
|
||||
extern buffer_state_enum ftape_set_state(buffer_state_enum new_state);
|
||||
#endif /* _FTAPE_RW_H */
|
@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1996, 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/ftape/lowlevel/ftape-setup.c,v $
|
||||
* $Revision: 1.7 $
|
||||
* $Date: 1997/10/10 09:57:06 $
|
||||
*
|
||||
* This file contains the code for processing the kernel command
|
||||
* line options for the QIC-40/80/3010/3020 floppy-tape driver
|
||||
* "ftape" for Linux.
|
||||
*/
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <linux/ftape.h>
|
||||
#include <linux/init.h>
|
||||
#include "../lowlevel/ftape-tracing.h"
|
||||
#include "../lowlevel/fdc-io.h"
|
||||
|
||||
static struct param_table {
|
||||
const char *name;
|
||||
int *var;
|
||||
int def_param;
|
||||
int min;
|
||||
int max;
|
||||
} config_params[] __initdata = {
|
||||
#ifndef CONFIG_FT_NO_TRACE_AT_ALL
|
||||
{ "tracing", &ftape_tracing, 3, ft_t_bug, ft_t_any},
|
||||
#endif
|
||||
{ "ioport", &ft_fdc_base, CONFIG_FT_FDC_BASE, 0x0, 0xfff},
|
||||
{ "irq", &ft_fdc_irq, CONFIG_FT_FDC_IRQ, 2, 15},
|
||||
{ "dma", &ft_fdc_dma, CONFIG_FT_FDC_DMA, 0, 3},
|
||||
{ "threshold", &ft_fdc_threshold, CONFIG_FT_FDC_THR, 1, 16},
|
||||
{ "datarate", &ft_fdc_rate_limit, CONFIG_FT_FDC_MAX_RATE, 500, 2000},
|
||||
{ "fc10", &ft_probe_fc10, CONFIG_FT_PROBE_FC10, 0, 1},
|
||||
{ "mach2", &ft_mach2, CONFIG_FT_MACH2, 0, 1}
|
||||
};
|
||||
|
||||
static int __init ftape_setup(char *str)
|
||||
{
|
||||
int i;
|
||||
int param;
|
||||
int ints[2];
|
||||
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
str = get_options(str, ARRAY_SIZE(ints), ints);
|
||||
if (str) {
|
||||
for (i=0; i < NR_ITEMS(config_params); i++) {
|
||||
if (strcmp(str,config_params[i].name) == 0){
|
||||
if (ints[0]) {
|
||||
param = ints[1];
|
||||
} else {
|
||||
param = config_params[i].def_param;
|
||||
}
|
||||
if (param < config_params[i].min ||
|
||||
param > config_params[i].max) {
|
||||
TRACE(ft_t_err,
|
||||
"parameter %s out of range %d ... %d",
|
||||
config_params[i].name,
|
||||
config_params[i].min,
|
||||
config_params[i].max);
|
||||
goto out;
|
||||
}
|
||||
if(config_params[i].var) {
|
||||
TRACE(ft_t_info, "%s=%d", str, param);
|
||||
*config_params[i].var = param;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (str) {
|
||||
TRACE(ft_t_err, "unknown ftape option [%s]", str);
|
||||
|
||||
TRACE(ft_t_err, "allowed options are:");
|
||||
for (i=0; i < NR_ITEMS(config_params); i++) {
|
||||
TRACE(ft_t_err, " %s",config_params[i].name);
|
||||
}
|
||||
} else {
|
||||
TRACE(ft_t_err, "botched ftape option");
|
||||
}
|
||||
out:
|
||||
TRACE_EXIT 1;
|
||||
}
|
||||
|
||||
__setup("ftape=", ftape_setup);
|
@ -1,118 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1993-1996 Bas Laarhoven,
|
||||
* (C) 1996-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/ftape/lowlevel/ftape-tracing.c,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:18:27 $
|
||||
*
|
||||
* This file contains the reading code
|
||||
* for the QIC-117 floppy-tape driver for Linux.
|
||||
*/
|
||||
|
||||
#include <linux/ftape.h>
|
||||
#include "../lowlevel/ftape-tracing.h"
|
||||
|
||||
/* Global vars.
|
||||
*/
|
||||
/* tracing
|
||||
* set it to: to log :
|
||||
* 0 bugs
|
||||
* 1 + errors
|
||||
* 2 + warnings
|
||||
* 3 + information
|
||||
* 4 + more information
|
||||
* 5 + program flow
|
||||
* 6 + fdc/dma info
|
||||
* 7 + data flow
|
||||
* 8 + everything else
|
||||
*/
|
||||
ft_trace_t ftape_tracing = ft_t_info; /* Default level: information and up */
|
||||
int ftape_function_nest_level;
|
||||
|
||||
/* Local vars.
|
||||
*/
|
||||
static __u8 trace_id;
|
||||
static char spacing[] = "* ";
|
||||
|
||||
void ftape_trace_call(const char *file, const char *name)
|
||||
{
|
||||
char *indent;
|
||||
|
||||
/* Since printk seems not to work with "%*s" format
|
||||
* we'll use this work-around.
|
||||
*/
|
||||
if (ftape_function_nest_level < 0) {
|
||||
printk(KERN_INFO "function nest level (%d) < 0\n",
|
||||
ftape_function_nest_level);
|
||||
ftape_function_nest_level = 0;
|
||||
}
|
||||
if (ftape_function_nest_level < sizeof(spacing)) {
|
||||
indent = (spacing +
|
||||
sizeof(spacing) - 1 -
|
||||
ftape_function_nest_level);
|
||||
} else {
|
||||
indent = spacing;
|
||||
}
|
||||
printk(KERN_INFO "[%03d]%s+%s (%s)\n",
|
||||
(int) trace_id++, indent, file, name);
|
||||
}
|
||||
|
||||
void ftape_trace_exit(const char *file, const char *name)
|
||||
{
|
||||
char *indent;
|
||||
|
||||
/* Since printk seems not to work with "%*s" format
|
||||
* we'll use this work-around.
|
||||
*/
|
||||
if (ftape_function_nest_level < 0) {
|
||||
printk(KERN_INFO "function nest level (%d) < 0\n", ftape_function_nest_level);
|
||||
ftape_function_nest_level = 0;
|
||||
}
|
||||
if (ftape_function_nest_level < sizeof(spacing)) {
|
||||
indent = (spacing +
|
||||
sizeof(spacing) - 1 -
|
||||
ftape_function_nest_level);
|
||||
} else {
|
||||
indent = spacing;
|
||||
}
|
||||
printk(KERN_INFO "[%03d]%s-%s (%s)\n",
|
||||
(int) trace_id++, indent, file, name);
|
||||
}
|
||||
|
||||
void ftape_trace_log(const char *file, const char *function)
|
||||
{
|
||||
char *indent;
|
||||
|
||||
/* Since printk seems not to work with "%*s" format
|
||||
* we'll use this work-around.
|
||||
*/
|
||||
if (ftape_function_nest_level < 0) {
|
||||
printk(KERN_INFO "function nest level (%d) < 0\n", ftape_function_nest_level);
|
||||
ftape_function_nest_level = 0;
|
||||
}
|
||||
if (ftape_function_nest_level < sizeof(spacing)) {
|
||||
indent = (spacing +
|
||||
sizeof(spacing) - 1 -
|
||||
ftape_function_nest_level);
|
||||
} else {
|
||||
indent = spacing;
|
||||
}
|
||||
printk(KERN_INFO "[%03d]%s%s (%s) - ",
|
||||
(int) trace_id++, indent, file, function);
|
||||
}
|
@ -1,179 +0,0 @@
|
||||
#ifndef _FTAPE_TRACING_H
|
||||
#define _FTAPE_TRACING_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 1994-1996 Bas Laarhoven,
|
||||
* (C) 1996-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/ftape/lowlevel/ftape-tracing.h,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:18:28 $
|
||||
*
|
||||
* This file contains definitions that eases the debugging of the
|
||||
* QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
/*
|
||||
* Be very careful with TRACE_EXIT and TRACE_ABORT.
|
||||
*
|
||||
* if (something) TRACE_EXIT error;
|
||||
*
|
||||
* will NOT work. Use
|
||||
*
|
||||
* if (something) {
|
||||
* TRACE_EXIT error;
|
||||
* }
|
||||
*
|
||||
* instead. Maybe a bit dangerous, but save lots of lines of code.
|
||||
*/
|
||||
|
||||
#define LL_X "%d/%d KB"
|
||||
#define LL(x) (unsigned int)((__u64)(x)>>10), (unsigned int)((x)&1023)
|
||||
|
||||
typedef enum {
|
||||
ft_t_nil = -1,
|
||||
ft_t_bug,
|
||||
ft_t_err,
|
||||
ft_t_warn,
|
||||
ft_t_info,
|
||||
ft_t_noise,
|
||||
ft_t_flow,
|
||||
ft_t_fdc_dma,
|
||||
ft_t_data_flow,
|
||||
ft_t_any
|
||||
} ft_trace_t;
|
||||
|
||||
#ifdef CONFIG_FT_NO_TRACE_AT_ALL
|
||||
/* the compiler will optimize away most TRACE() macros
|
||||
*/
|
||||
#define FT_TRACE_TOP_LEVEL ft_t_bug
|
||||
#define TRACE_FUN(level) do {} while(0)
|
||||
#define TRACE_EXIT return
|
||||
#define TRACE(l, m, i...) \
|
||||
{ \
|
||||
if ((ft_trace_t)(l) == FT_TRACE_TOP_LEVEL) { \
|
||||
printk(KERN_INFO"ftape%s(%s):\n" \
|
||||
KERN_INFO m".\n" ,__FILE__, __FUNCTION__ , ##i); \
|
||||
} \
|
||||
}
|
||||
#define SET_TRACE_LEVEL(l) if ((l) == (l)) do {} while(0)
|
||||
#define TRACE_LEVEL FT_TRACE_TOP_LEVEL
|
||||
|
||||
#else
|
||||
|
||||
#ifdef CONFIG_FT_NO_TRACE
|
||||
/* the compiler will optimize away many TRACE() macros
|
||||
* the ftape_simple_trace_call() function simply increments
|
||||
* the function nest level.
|
||||
*/
|
||||
#define FT_TRACE_TOP_LEVEL ft_t_warn
|
||||
#define TRACE_FUN(level) ftape_function_nest_level++
|
||||
#define TRACE_EXIT ftape_function_nest_level--; return
|
||||
|
||||
#else
|
||||
#ifdef CONFIG_FT_FULL_DEBUG
|
||||
#define FT_TRACE_TOP_LEVEL ft_t_any
|
||||
#else
|
||||
#define FT_TRACE_TOP_LEVEL ft_t_flow
|
||||
#endif
|
||||
#define TRACE_FUN(level) \
|
||||
const ft_trace_t _tracing = level; \
|
||||
if (ftape_tracing >= (ft_trace_t)(level) && \
|
||||
(ft_trace_t)(level) <= FT_TRACE_TOP_LEVEL) \
|
||||
ftape_trace_call(__FILE__, __FUNCTION__); \
|
||||
ftape_function_nest_level ++;
|
||||
|
||||
#define TRACE_EXIT \
|
||||
--ftape_function_nest_level; \
|
||||
if (ftape_tracing >= (ft_trace_t)(_tracing) && \
|
||||
(ft_trace_t)(_tracing) <= FT_TRACE_TOP_LEVEL) \
|
||||
ftape_trace_exit(__FILE__, __FUNCTION__); \
|
||||
return
|
||||
|
||||
#endif
|
||||
|
||||
#define TRACE(l, m, i...) \
|
||||
{ \
|
||||
if (ftape_tracing >= (ft_trace_t)(l) && \
|
||||
(ft_trace_t)(l) <= FT_TRACE_TOP_LEVEL) { \
|
||||
ftape_trace_log(__FILE__, __FUNCTION__); \
|
||||
printk(m".\n" ,##i); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SET_TRACE_LEVEL(l) \
|
||||
{ \
|
||||
if ((ft_trace_t)(l) <= FT_TRACE_TOP_LEVEL) { \
|
||||
ftape_tracing = (ft_trace_t)(l); \
|
||||
} else { \
|
||||
ftape_tracing = FT_TRACE_TOP_LEVEL; \
|
||||
} \
|
||||
}
|
||||
#define TRACE_LEVEL \
|
||||
((ftape_tracing <= FT_TRACE_TOP_LEVEL) ? ftape_tracing : FT_TRACE_TOP_LEVEL)
|
||||
|
||||
|
||||
/* Global variables declared in tracing.c
|
||||
*/
|
||||
extern ft_trace_t ftape_tracing; /* sets default level */
|
||||
extern int ftape_function_nest_level;
|
||||
|
||||
/* Global functions declared in tracing.c
|
||||
*/
|
||||
extern void ftape_trace_call(const char *file, const char *name);
|
||||
extern void ftape_trace_exit(const char *file, const char *name);
|
||||
extern void ftape_trace_log (const char *file, const char *name);
|
||||
|
||||
#endif /* !defined(CONFIG_FT_NO_TRACE_AT_ALL) */
|
||||
|
||||
/*
|
||||
* Abort with a message.
|
||||
*/
|
||||
#define TRACE_ABORT(res, i...) \
|
||||
{ \
|
||||
TRACE(i); \
|
||||
TRACE_EXIT res; \
|
||||
}
|
||||
|
||||
/* The following transforms the common "if(result < 0) ... " into a
|
||||
* one-liner.
|
||||
*/
|
||||
#define _TRACE_CATCH(level, fun, action) \
|
||||
{ \
|
||||
int _res = (fun); \
|
||||
if (_res < 0) { \
|
||||
do { action /* */ ; } while(0); \
|
||||
TRACE_ABORT(_res, level, "%s failed: %d", #fun, _res); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define TRACE_CATCH(fun, fail) _TRACE_CATCH(ft_t_err, fun, fail)
|
||||
|
||||
/* Abort the current function when signalled. This doesn't belong here,
|
||||
* but rather into ftape-rw.h (maybe)
|
||||
*/
|
||||
#define FT_SIGNAL_EXIT(sig_mask) \
|
||||
if (sigtestsetmask(¤t->pending.signal, sig_mask)) { \
|
||||
TRACE_ABORT(-EINTR, \
|
||||
ft_t_warn, \
|
||||
"interrupted by non-blockable signal"); \
|
||||
}
|
||||
|
||||
#endif /* _FTAPE_TRACING_H */
|
@ -1,336 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1993-1995 Bas Laarhoven,
|
||||
* (C) 1996-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/ftape/lowlevel/ftape-write.c,v $
|
||||
* $Revision: 1.3.4.1 $
|
||||
* $Date: 1997/11/14 18:07:04 $
|
||||
*
|
||||
* This file contains the writing code
|
||||
* for the QIC-117 floppy-tape driver for Linux.
|
||||
*/
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <linux/ftape.h>
|
||||
#include <linux/qic117.h>
|
||||
#include "../lowlevel/ftape-tracing.h"
|
||||
#include "../lowlevel/ftape-write.h"
|
||||
#include "../lowlevel/ftape-read.h"
|
||||
#include "../lowlevel/ftape-io.h"
|
||||
#include "../lowlevel/ftape-ctl.h"
|
||||
#include "../lowlevel/ftape-rw.h"
|
||||
#include "../lowlevel/ftape-ecc.h"
|
||||
#include "../lowlevel/ftape-bsm.h"
|
||||
#include "../lowlevel/fdc-isr.h"
|
||||
|
||||
/* Global vars.
|
||||
*/
|
||||
|
||||
/* Local vars.
|
||||
*/
|
||||
static int last_write_failed;
|
||||
|
||||
void ftape_zap_write_buffers(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ft_nr_buffers; ++i) {
|
||||
ft_buffer[i]->status = done;
|
||||
}
|
||||
ftape_reset_buffer();
|
||||
}
|
||||
|
||||
static int copy_and_gen_ecc(void *destination,
|
||||
const void *source,
|
||||
const SectorMap bad_sector_map)
|
||||
{
|
||||
int result;
|
||||
struct memory_segment mseg;
|
||||
int bads = count_ones(bad_sector_map);
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
if (bads > 0) {
|
||||
TRACE(ft_t_noise, "bad sectors in map: %d", bads);
|
||||
}
|
||||
if (bads + 3 >= FT_SECTORS_PER_SEGMENT) {
|
||||
TRACE(ft_t_noise, "empty segment");
|
||||
mseg.blocks = 0; /* skip entire segment */
|
||||
result = 0; /* nothing written */
|
||||
} else {
|
||||
mseg.blocks = FT_SECTORS_PER_SEGMENT - bads;
|
||||
mseg.data = destination;
|
||||
memcpy(mseg.data, source, (mseg.blocks - 3) * FT_SECTOR_SIZE);
|
||||
result = ftape_ecc_set_segment_parity(&mseg);
|
||||
if (result < 0) {
|
||||
TRACE(ft_t_err, "ecc_set_segment_parity failed");
|
||||
} else {
|
||||
result = (mseg.blocks - 3) * FT_SECTOR_SIZE;
|
||||
}
|
||||
}
|
||||
TRACE_EXIT result;
|
||||
}
|
||||
|
||||
|
||||
int ftape_start_writing(const ft_write_mode_t mode)
|
||||
{
|
||||
buffer_struct *head = ftape_get_buffer(ft_queue_head);
|
||||
int segment_id = head->segment_id;
|
||||
int result;
|
||||
buffer_state_enum wanted_state = (mode == FT_WR_DELETE
|
||||
? deleting
|
||||
: writing);
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if ((ft_driver_state != wanted_state) || head->status != waiting) {
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
ftape_setup_new_segment(head, segment_id, 1);
|
||||
if (mode == FT_WR_SINGLE) {
|
||||
/* stop tape instead of pause */
|
||||
head->next_segment = 0;
|
||||
}
|
||||
ftape_calc_next_cluster(head); /* prepare */
|
||||
head->status = ft_driver_state; /* either writing or deleting */
|
||||
if (ft_runner_status == idle) {
|
||||
TRACE(ft_t_noise,
|
||||
"starting runner for segment %d", segment_id);
|
||||
TRACE_CATCH(ftape_start_tape(segment_id,head->sector_offset),);
|
||||
} else {
|
||||
TRACE(ft_t_noise, "runner not idle, not starting tape");
|
||||
}
|
||||
/* go */
|
||||
result = fdc_setup_read_write(head, (mode == FT_WR_DELETE
|
||||
? FDC_WRITE_DELETED : FDC_WRITE));
|
||||
ftape_set_state(wanted_state); /* should not be necessary */
|
||||
TRACE_EXIT result;
|
||||
}
|
||||
|
||||
/* Wait until all data is actually written to tape.
|
||||
*
|
||||
* There is a problem: when the tape runs into logical EOT, then this
|
||||
* failes. We need to restart the runner in this case.
|
||||
*/
|
||||
int ftape_loop_until_writes_done(void)
|
||||
{
|
||||
buffer_struct *head;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
while ((ft_driver_state == writing || ft_driver_state == deleting) &&
|
||||
ftape_get_buffer(ft_queue_head)->status != done) {
|
||||
/* set the runner status to idle if at lEOT */
|
||||
TRACE_CATCH(ftape_handle_logical_eot(), last_write_failed = 1);
|
||||
/* restart the tape if necessary */
|
||||
if (ft_runner_status == idle) {
|
||||
TRACE(ft_t_noise, "runner is idle, restarting");
|
||||
if (ft_driver_state == deleting) {
|
||||
TRACE_CATCH(ftape_start_writing(FT_WR_DELETE),
|
||||
last_write_failed = 1);
|
||||
} else {
|
||||
TRACE_CATCH(ftape_start_writing(FT_WR_MULTI),
|
||||
last_write_failed = 1);
|
||||
}
|
||||
}
|
||||
TRACE(ft_t_noise, "tail: %d, head: %d",
|
||||
ftape_buffer_id(ft_queue_tail),
|
||||
ftape_buffer_id(ft_queue_head));
|
||||
TRACE_CATCH(fdc_interrupt_wait(5 * FT_SECOND),
|
||||
last_write_failed = 1);
|
||||
head = ftape_get_buffer(ft_queue_head);
|
||||
if (head->status == error) {
|
||||
/* Allow escape from loop when signaled !
|
||||
*/
|
||||
FT_SIGNAL_EXIT(_DONT_BLOCK);
|
||||
if (head->hard_error_map != 0) {
|
||||
/* Implement hard write error recovery here
|
||||
*/
|
||||
}
|
||||
/* retry this one */
|
||||
head->status = waiting;
|
||||
if (ft_runner_status == aborting) {
|
||||
ftape_dumb_stop();
|
||||
}
|
||||
if (ft_runner_status != idle) {
|
||||
TRACE_ABORT(-EIO, ft_t_err,
|
||||
"unexpected state: "
|
||||
"ft_runner_status != idle");
|
||||
}
|
||||
ftape_start_writing(ft_driver_state == deleting
|
||||
? FT_WR_MULTI : FT_WR_DELETE);
|
||||
}
|
||||
TRACE(ft_t_noise, "looping until writes done");
|
||||
}
|
||||
ftape_set_state(idle);
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
/* Write given segment from buffer at address to tape.
|
||||
*/
|
||||
static int write_segment(const int segment_id,
|
||||
const void *address,
|
||||
const ft_write_mode_t write_mode)
|
||||
{
|
||||
int bytes_written = 0;
|
||||
buffer_struct *tail;
|
||||
buffer_state_enum wanted_state = (write_mode == FT_WR_DELETE
|
||||
? deleting : writing);
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
TRACE(ft_t_noise, "segment_id = %d", segment_id);
|
||||
if (ft_driver_state != wanted_state) {
|
||||
if (ft_driver_state == deleting ||
|
||||
wanted_state == deleting) {
|
||||
TRACE_CATCH(ftape_loop_until_writes_done(),);
|
||||
}
|
||||
TRACE(ft_t_noise, "calling ftape_abort_operation");
|
||||
TRACE_CATCH(ftape_abort_operation(),);
|
||||
ftape_zap_write_buffers();
|
||||
ftape_set_state(wanted_state);
|
||||
}
|
||||
/* if all buffers full we'll have to wait...
|
||||
*/
|
||||
ftape_wait_segment(wanted_state);
|
||||
tail = ftape_get_buffer(ft_queue_tail);
|
||||
switch(tail->status) {
|
||||
case done:
|
||||
ft_history.defects += count_ones(tail->hard_error_map);
|
||||
break;
|
||||
case waiting:
|
||||
/* this could happen with multiple EMPTY_SEGMENTs, but
|
||||
* shouldn't happen any more as we re-start the runner even
|
||||
* with an empty segment.
|
||||
*/
|
||||
bytes_written = -EAGAIN;
|
||||
break;
|
||||
case error:
|
||||
/* setup for a retry
|
||||
*/
|
||||
tail->status = waiting;
|
||||
bytes_written = -EAGAIN; /* force retry */
|
||||
if (tail->hard_error_map != 0) {
|
||||
TRACE(ft_t_warn,
|
||||
"warning: %d hard error(s) in written segment",
|
||||
count_ones(tail->hard_error_map));
|
||||
TRACE(ft_t_noise, "hard_error_map = 0x%08lx",
|
||||
(long)tail->hard_error_map);
|
||||
/* Implement hard write error recovery here
|
||||
*/
|
||||
}
|
||||
break;
|
||||
default:
|
||||
TRACE_ABORT(-EIO, ft_t_err,
|
||||
"wait for empty segment failed, tail status: %d",
|
||||
tail->status);
|
||||
}
|
||||
/* should runner stop ?
|
||||
*/
|
||||
if (ft_runner_status == aborting) {
|
||||
buffer_struct *head = ftape_get_buffer(ft_queue_head);
|
||||
if (head->status == wanted_state) {
|
||||
head->status = done; /* ???? */
|
||||
}
|
||||
/* don't call abort_operation(), we don't want to zap
|
||||
* the dma buffers
|
||||
*/
|
||||
TRACE_CATCH(ftape_dumb_stop(),);
|
||||
} else {
|
||||
/* If just passed last segment on tape: wait for BOT
|
||||
* or EOT mark. Sets ft_runner_status to idle if at lEOT
|
||||
* and successful
|
||||
*/
|
||||
TRACE_CATCH(ftape_handle_logical_eot(),);
|
||||
}
|
||||
if (tail->status == done) {
|
||||
/* now at least one buffer is empty, fill it with our
|
||||
* data. skip bad sectors and generate ecc.
|
||||
* copy_and_gen_ecc return nr of bytes written, range
|
||||
* 0..29 Kb inclusive!
|
||||
*
|
||||
* Empty segments are handled inside coyp_and_gen_ecc()
|
||||
*/
|
||||
if (write_mode != FT_WR_DELETE) {
|
||||
TRACE_CATCH(bytes_written = copy_and_gen_ecc(
|
||||
tail->address, address,
|
||||
ftape_get_bad_sector_entry(segment_id)),);
|
||||
}
|
||||
tail->segment_id = segment_id;
|
||||
tail->status = waiting;
|
||||
tail = ftape_next_buffer(ft_queue_tail);
|
||||
}
|
||||
/* Start tape only if all buffers full or flush mode.
|
||||
* This will give higher probability of streaming.
|
||||
*/
|
||||
if (ft_runner_status != running &&
|
||||
((tail->status == waiting &&
|
||||
ftape_get_buffer(ft_queue_head) == tail) ||
|
||||
write_mode != FT_WR_ASYNC)) {
|
||||
TRACE_CATCH(ftape_start_writing(write_mode),);
|
||||
}
|
||||
TRACE_EXIT bytes_written;
|
||||
}
|
||||
|
||||
/* Write as much as fits from buffer to the given segment on tape
|
||||
* and handle retries.
|
||||
* Return the number of bytes written (>= 0), or:
|
||||
* -EIO write failed
|
||||
* -EINTR interrupted by signal
|
||||
* -ENOSPC device full
|
||||
*/
|
||||
int ftape_write_segment(const int segment_id,
|
||||
const void *buffer,
|
||||
const ft_write_mode_t flush)
|
||||
{
|
||||
int retry = 0;
|
||||
int result;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
ft_history.used |= 2;
|
||||
if (segment_id >= ft_tracks_per_tape*ft_segments_per_track) {
|
||||
/* tape full */
|
||||
TRACE_ABORT(-ENOSPC, ft_t_err,
|
||||
"invalid segment id: %d (max %d)",
|
||||
segment_id,
|
||||
ft_tracks_per_tape * ft_segments_per_track -1);
|
||||
}
|
||||
for (;;) {
|
||||
if ((result = write_segment(segment_id, buffer, flush)) >= 0) {
|
||||
if (result == 0) { /* empty segment */
|
||||
TRACE(ft_t_noise,
|
||||
"empty segment, nothing written");
|
||||
}
|
||||
TRACE_EXIT result;
|
||||
}
|
||||
if (result == -EAGAIN) {
|
||||
if (++retry > 100) { /* give up */
|
||||
TRACE_ABORT(-EIO, ft_t_err,
|
||||
"write failed, >100 retries in segment");
|
||||
}
|
||||
TRACE(ft_t_warn, "write error, retry %d (%d)",
|
||||
retry,
|
||||
ftape_get_buffer(ft_queue_tail)->segment_id);
|
||||
} else {
|
||||
TRACE_ABORT(result, ft_t_err,
|
||||
"write_segment failed, error: %d", result);
|
||||
}
|
||||
/* Allow escape from loop when signaled !
|
||||
*/
|
||||
FT_SIGNAL_EXIT(_DONT_BLOCK);
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
#ifndef _FTAPE_WRITE_H
|
||||
#define _FTAPE_WRITE_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 1994-1995 Bas Laarhoven,
|
||||
* (C) 1996-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/ftape/lowlevel/ftape-write.h,v $
|
||||
$Author: claus $
|
||||
*
|
||||
$Revision: 1.2 $
|
||||
$Date: 1997/10/05 19:18:30 $
|
||||
$State: Exp $
|
||||
*
|
||||
* This file contains the definitions for the write functions
|
||||
* for the QIC-117 floppy-tape driver for Linux.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* ftape-write.c defined global functions.
|
||||
*/
|
||||
typedef enum {
|
||||
FT_WR_ASYNC = 0, /* start tape only when all buffers are full */
|
||||
FT_WR_MULTI = 1, /* start tape, but don't necessarily stop */
|
||||
FT_WR_SINGLE = 2, /* write a single segment and stop afterwards */
|
||||
FT_WR_DELETE = 3 /* write deleted data marks */
|
||||
} ft_write_mode_t;
|
||||
|
||||
extern int ftape_start_writing(const ft_write_mode_t mode);
|
||||
extern int ftape_write_segment(const int segment,
|
||||
const void *address,
|
||||
const ft_write_mode_t flushing);
|
||||
extern void ftape_zap_write_buffers(void);
|
||||
extern int ftape_loop_until_writes_done(void);
|
||||
|
||||
#endif /* _FTAPE_WRITE_H */
|
||||
|
@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1996-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/ftape/lowlevel/ftape_syms.c,v $
|
||||
* $Revision: 1.4 $
|
||||
* $Date: 1997/10/17 00:03:51 $
|
||||
*
|
||||
* This file contains the symbols that the ftape low level
|
||||
* part of the QIC-40/80/3010/3020 floppy-tape driver "ftape"
|
||||
* exports to its high level clients
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/ftape.h>
|
||||
#include "../lowlevel/ftape-tracing.h"
|
||||
#include "../lowlevel/ftape-init.h"
|
||||
#include "../lowlevel/fdc-io.h"
|
||||
#include "../lowlevel/ftape-read.h"
|
||||
#include "../lowlevel/ftape-write.h"
|
||||
#include "../lowlevel/ftape-io.h"
|
||||
#include "../lowlevel/ftape-ctl.h"
|
||||
#include "../lowlevel/ftape-rw.h"
|
||||
#include "../lowlevel/ftape-bsm.h"
|
||||
#include "../lowlevel/ftape-buffer.h"
|
||||
#include "../lowlevel/ftape-format.h"
|
||||
|
||||
/* bad sector handling from ftape-bsm.c */
|
||||
EXPORT_SYMBOL(ftape_get_bad_sector_entry);
|
||||
EXPORT_SYMBOL(ftape_find_end_of_bsm_list);
|
||||
/* from ftape-rw.c */
|
||||
EXPORT_SYMBOL(ftape_set_state);
|
||||
/* from ftape-ctl.c */
|
||||
EXPORT_SYMBOL(ftape_seek_to_bot);
|
||||
EXPORT_SYMBOL(ftape_seek_to_eot);
|
||||
EXPORT_SYMBOL(ftape_abort_operation);
|
||||
EXPORT_SYMBOL(ftape_get_status);
|
||||
EXPORT_SYMBOL(ftape_enable);
|
||||
EXPORT_SYMBOL(ftape_disable);
|
||||
EXPORT_SYMBOL(ftape_mmap);
|
||||
EXPORT_SYMBOL(ftape_calibrate_data_rate);
|
||||
/* from ftape-io.c */
|
||||
EXPORT_SYMBOL(ftape_reset_drive);
|
||||
EXPORT_SYMBOL(ftape_command);
|
||||
EXPORT_SYMBOL(ftape_parameter);
|
||||
EXPORT_SYMBOL(ftape_ready_wait);
|
||||
EXPORT_SYMBOL(ftape_report_operation);
|
||||
EXPORT_SYMBOL(ftape_report_error);
|
||||
/* from ftape-read.c */
|
||||
EXPORT_SYMBOL(ftape_read_segment_fraction);
|
||||
EXPORT_SYMBOL(ftape_zap_read_buffers);
|
||||
EXPORT_SYMBOL(ftape_read_header_segment);
|
||||
EXPORT_SYMBOL(ftape_decode_header_segment);
|
||||
/* from ftape-write.c */
|
||||
EXPORT_SYMBOL(ftape_write_segment);
|
||||
EXPORT_SYMBOL(ftape_start_writing);
|
||||
EXPORT_SYMBOL(ftape_loop_until_writes_done);
|
||||
/* from ftape-buffer.h */
|
||||
EXPORT_SYMBOL(ftape_set_nr_buffers);
|
||||
/* from ftape-format.h */
|
||||
EXPORT_SYMBOL(ftape_format_track);
|
||||
EXPORT_SYMBOL(ftape_format_status);
|
||||
EXPORT_SYMBOL(ftape_verify_segment);
|
||||
/* from tracing.c */
|
||||
#ifndef CONFIG_FT_NO_TRACE_AT_ALL
|
||||
EXPORT_SYMBOL(ftape_tracing);
|
||||
EXPORT_SYMBOL(ftape_function_nest_level);
|
||||
EXPORT_SYMBOL(ftape_trace_call);
|
||||
EXPORT_SYMBOL(ftape_trace_exit);
|
||||
EXPORT_SYMBOL(ftape_trace_log);
|
||||
#endif
|
||||
|
@ -1,36 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 1996, 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/ftape/zftape/Makefile,v $
|
||||
# $Revision: 1.4 $
|
||||
# $Date: 1997/10/05 19:18:58 $
|
||||
#
|
||||
# Makefile for the QIC-40/80/3010/3020 zftape interface VFS to
|
||||
# ftape
|
||||
#
|
||||
|
||||
|
||||
# ZFT_OBSOLETE - enable the MTIOC_ZFTAPE_GETBLKSZ ioctl. You should
|
||||
# leave this enabled for compatibility with taper.
|
||||
|
||||
obj-$(CONFIG_ZFTAPE) += zftape.o
|
||||
|
||||
zftape-objs := zftape-rw.o zftape-ctl.o zftape-read.o \
|
||||
zftape-write.o zftape-vtbl.o zftape-eof.o \
|
||||
zftape-init.o zftape-buffers.o zftape_syms.o
|
||||
|
||||
EXTRA_CFLAGS := -DZFT_OBSOLETE
|
@ -1,149 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1995-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/ftape/zftape/zftape-buffers.c,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:18:59 $
|
||||
*
|
||||
* This file contains the dynamic buffer allocation routines
|
||||
* of zftape
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <linux/zftape.h>
|
||||
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "../zftape/zftape-init.h"
|
||||
#include "../zftape/zftape-eof.h"
|
||||
#include "../zftape/zftape-ctl.h"
|
||||
#include "../zftape/zftape-write.h"
|
||||
#include "../zftape/zftape-read.h"
|
||||
#include "../zftape/zftape-rw.h"
|
||||
#include "../zftape/zftape-vtbl.h"
|
||||
|
||||
/* global variables
|
||||
*/
|
||||
|
||||
/* local varibales
|
||||
*/
|
||||
static unsigned int used_memory;
|
||||
static unsigned int peak_memory;
|
||||
|
||||
void zft_memory_stats(void)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
TRACE(ft_t_noise, "Memory usage (vmalloc allocations):\n"
|
||||
KERN_INFO "total allocated: %d\n"
|
||||
KERN_INFO "peak allocation: %d",
|
||||
used_memory, peak_memory);
|
||||
peak_memory = used_memory;
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
int zft_vcalloc_once(void *new, size_t size)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
if (zft_vmalloc_once(new, size) < 0) {
|
||||
TRACE_EXIT -ENOMEM;
|
||||
}
|
||||
memset(*(void **)new, '\0', size);
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
int zft_vmalloc_once(void *new, size_t size)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (*(void **)new != NULL || size == 0) {
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
if ((*(void **)new = vmalloc(size)) == NULL) {
|
||||
TRACE_EXIT -ENOMEM;
|
||||
}
|
||||
used_memory += size;
|
||||
if (peak_memory < used_memory) {
|
||||
peak_memory = used_memory;
|
||||
}
|
||||
TRACE_ABORT(0, ft_t_noise,
|
||||
"allocated buffer @ %p, %zd bytes", *(void **)new, size);
|
||||
}
|
||||
int zft_vmalloc_always(void *new, size_t size)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
zft_vfree(new, size);
|
||||
TRACE_EXIT zft_vmalloc_once(new, size);
|
||||
}
|
||||
void zft_vfree(void *old, size_t size)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (*(void **)old) {
|
||||
vfree(*(void **)old);
|
||||
used_memory -= size;
|
||||
TRACE(ft_t_noise, "released buffer @ %p, %zd bytes",
|
||||
*(void **)old, size);
|
||||
*(void **)old = NULL;
|
||||
}
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
void *zft_kmalloc(size_t size)
|
||||
{
|
||||
void *new;
|
||||
|
||||
while ((new = kmalloc(size, GFP_KERNEL)) == NULL) {
|
||||
msleep_interruptible(100);
|
||||
}
|
||||
memset(new, 0, size);
|
||||
used_memory += size;
|
||||
if (peak_memory < used_memory) {
|
||||
peak_memory = used_memory;
|
||||
}
|
||||
return new;
|
||||
}
|
||||
|
||||
void zft_kfree(void *old, size_t size)
|
||||
{
|
||||
kfree(old);
|
||||
used_memory -= size;
|
||||
}
|
||||
|
||||
/* there are some more buffers that are allocated on demand.
|
||||
* cleanup_module() calles this function to be sure to have released
|
||||
* them
|
||||
*/
|
||||
void zft_uninit_mem(void)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
zft_vfree(&zft_hseg_buf, FT_SEGMENT_SIZE);
|
||||
zft_vfree(&zft_deblock_buf, FT_SEGMENT_SIZE); zft_deblock_segment = -1;
|
||||
zft_free_vtbl();
|
||||
if (zft_cmpr_lock(0 /* don't load */) == 0) {
|
||||
(*zft_cmpr_ops->cleanup)();
|
||||
(*zft_cmpr_ops->reset)(); /* unlock it again */
|
||||
}
|
||||
zft_memory_stats();
|
||||
TRACE_EXIT;
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
#ifndef _FTAPE_DYNMEM_H
|
||||
#define _FTAPE_DYNMEM_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995-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/ftape/zftape/zftape-buffers.h,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:18:59 $
|
||||
*
|
||||
* memory allocation routines.
|
||||
*
|
||||
*/
|
||||
|
||||
/* we do not allocate all of the really large buffer memory before
|
||||
* someone tries to open the drive. ftape_open() may fail with
|
||||
* -ENOMEM, but that's better having 200k of vmalloced memory which
|
||||
* cannot be swapped out.
|
||||
*/
|
||||
|
||||
extern void zft_memory_stats(void);
|
||||
extern int zft_vmalloc_once(void *new, size_t size);
|
||||
extern int zft_vcalloc_once(void *new, size_t size);
|
||||
extern int zft_vmalloc_always(void *new, size_t size);
|
||||
extern void zft_vfree(void *old, size_t size);
|
||||
extern void *zft_kmalloc(size_t size);
|
||||
extern void zft_kfree(void *old, size_t size);
|
||||
|
||||
/* called by cleanup_module()
|
||||
*/
|
||||
extern void zft_uninit_mem(void);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,58 +0,0 @@
|
||||
#ifndef _ZFTAPE_CTL_H
|
||||
#define _ZFTAPE_CTL_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 1996, 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/ftape/zftape/zftape-ctl.h,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:19:02 $
|
||||
*
|
||||
* This file contains the non-standard IOCTL related definitions
|
||||
* for the QIC-40/80 floppy-tape driver for Linux.
|
||||
*/
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/mtio.h>
|
||||
|
||||
#include "../zftape/zftape-rw.h"
|
||||
|
||||
#ifdef CONFIG_ZFTAPE_MODULE
|
||||
#define ftape_status (*zft_status)
|
||||
#endif
|
||||
|
||||
extern int zft_offline;
|
||||
extern int zft_mt_compression;
|
||||
extern int zft_write_protected;
|
||||
extern int zft_header_read;
|
||||
extern unsigned int zft_unit;
|
||||
extern int zft_resid;
|
||||
|
||||
extern void zft_reset_position(zft_position *pos);
|
||||
extern int zft_check_write_access(zft_position *pos);
|
||||
extern int zft_def_idle_state(void);
|
||||
|
||||
/* hooks for the VFS interface
|
||||
*/
|
||||
extern int _zft_open(unsigned int dev_minor, unsigned int access_mode);
|
||||
extern int _zft_close(void);
|
||||
extern int _zft_ioctl(unsigned int command, void __user *arg);
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -1,199 +0,0 @@
|
||||
/*
|
||||
* I use these routines just to decide when I have to fake a
|
||||
* volume-table to preserve compatibility to original ftape.
|
||||
*/
|
||||
/*
|
||||
* Copyright (C) 1994-1995 Bas Laarhoven.
|
||||
*
|
||||
* Modified for zftape 1996, 1997 Claus 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/ftape/zftape/zftape-eof.c,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:19:02 $
|
||||
*
|
||||
* This file contains the eof mark handling code
|
||||
* for the QIC-40/80 floppy-tape driver for Linux.
|
||||
*/
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
#include <linux/zftape.h>
|
||||
|
||||
#include "../zftape/zftape-init.h"
|
||||
#include "../zftape/zftape-rw.h"
|
||||
#include "../zftape/zftape-eof.h"
|
||||
|
||||
/* Global vars.
|
||||
*/
|
||||
|
||||
/* a copy of the failed sector log from the header segment.
|
||||
*/
|
||||
eof_mark_union *zft_eof_map;
|
||||
|
||||
/* number of eof marks (entries in bad sector log) on tape.
|
||||
*/
|
||||
int zft_nr_eof_marks = -1;
|
||||
|
||||
|
||||
/* Local vars.
|
||||
*/
|
||||
|
||||
static char linux_tape_label[] = "Linux raw format V";
|
||||
enum {
|
||||
min_fmt_version = 1, max_fmt_version = 2
|
||||
};
|
||||
static unsigned ftape_fmt_version = 0;
|
||||
|
||||
|
||||
/* Ftape (mis)uses the bad sector log to record end-of-file marks.
|
||||
* Initially (when the tape is erased) all entries in the bad sector
|
||||
* log are added to the tape's bad sector map. The bad sector log then
|
||||
* is cleared.
|
||||
*
|
||||
* The bad sector log normally contains entries of the form:
|
||||
* even 16-bit word: segment number of bad sector
|
||||
* odd 16-bit word: encoded date
|
||||
* There can be a total of 448 entries (1792 bytes).
|
||||
*
|
||||
* My guess is that no program is using this bad sector log (the *
|
||||
* format seems useless as there is no indication of the bad sector
|
||||
* itself, only the segment) However, if any program does use the bad
|
||||
* sector log, the format used by ftape will let the program think
|
||||
* there are some bad sectors and no harm is done.
|
||||
*
|
||||
* The eof mark entries that ftape stores in the bad sector log: even
|
||||
* 16-bit word: segment number of eof mark odd 16-bit word: sector
|
||||
* number of eof mark [1..32]
|
||||
*
|
||||
* The zft_eof_map as maintained is a sorted list of eof mark entries.
|
||||
*
|
||||
*
|
||||
* The tape name field in the header segments is used to store a linux
|
||||
* tape identification string and a version number. This way the tape
|
||||
* can be recognized as a Linux raw format tape when using tools under
|
||||
* other OS's.
|
||||
*
|
||||
* 'Wide' QIC tapes (format code 4) don't have a failed sector list
|
||||
* anymore. That space is used for the (longer) bad sector map that
|
||||
* now is a variable length list too. We now store our end-of-file
|
||||
* marker list after the bad-sector-map on tape. The list is delimited
|
||||
* by a (__u32) 0 entry.
|
||||
*/
|
||||
|
||||
int zft_ftape_validate_label(char *label)
|
||||
{
|
||||
static char tmp_label[45];
|
||||
int result = 0;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
memcpy(tmp_label, label, FT_LABEL_SZ);
|
||||
tmp_label[FT_LABEL_SZ] = '\0';
|
||||
TRACE(ft_t_noise, "tape label = `%s'", tmp_label);
|
||||
ftape_fmt_version = 0;
|
||||
if (memcmp(label, linux_tape_label, strlen(linux_tape_label)) == 0) {
|
||||
int pos = strlen(linux_tape_label);
|
||||
while (label[pos] >= '0' && label[pos] <= '9') {
|
||||
ftape_fmt_version *= 10;
|
||||
ftape_fmt_version = label[ pos++] - '0';
|
||||
}
|
||||
result = (ftape_fmt_version >= min_fmt_version &&
|
||||
ftape_fmt_version <= max_fmt_version);
|
||||
}
|
||||
TRACE(ft_t_noise, "format version = %d", ftape_fmt_version);
|
||||
TRACE_EXIT result;
|
||||
}
|
||||
|
||||
static __u8 * find_end_of_eof_list(__u8 * ptr, __u8 * limit)
|
||||
{
|
||||
while (ptr + 3 < limit) {
|
||||
|
||||
if (get_unaligned((__u32*)ptr)) {
|
||||
ptr += sizeof(__u32);
|
||||
} else {
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void zft_ftape_extract_file_marks(__u8* address)
|
||||
{
|
||||
int i;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
zft_eof_map = NULL;
|
||||
if (ft_format_code == fmt_var || ft_format_code == fmt_big) {
|
||||
__u8* end;
|
||||
__u8* start = ftape_find_end_of_bsm_list(address);
|
||||
|
||||
zft_nr_eof_marks = 0;
|
||||
if (start) {
|
||||
start += 3; /* skip end of list mark */
|
||||
end = find_end_of_eof_list(start,
|
||||
address + FT_SEGMENT_SIZE);
|
||||
if (end && end - start <= FT_FSL_SIZE) {
|
||||
zft_nr_eof_marks = ((end - start) /
|
||||
sizeof(eof_mark_union));
|
||||
zft_eof_map = (eof_mark_union *)start;
|
||||
} else {
|
||||
TRACE(ft_t_err,
|
||||
"EOF Mark List is too long or damaged!");
|
||||
}
|
||||
} else {
|
||||
TRACE(ft_t_err,
|
||||
"Bad Sector List is too long or damaged !");
|
||||
}
|
||||
} else {
|
||||
zft_eof_map = (eof_mark_union *)&address[FT_FSL];
|
||||
zft_nr_eof_marks = GET2(address, FT_FSL_CNT);
|
||||
}
|
||||
TRACE(ft_t_noise, "number of file marks: %d", zft_nr_eof_marks);
|
||||
if (ftape_fmt_version == 1) {
|
||||
TRACE(ft_t_info, "swapping version 1 fields");
|
||||
/* version 1 format uses swapped sector and segment
|
||||
* fields, correct that !
|
||||
*/
|
||||
for (i = 0; i < zft_nr_eof_marks; ++i) {
|
||||
__u16 tmp = GET2(&zft_eof_map[i].mark.segment,0);
|
||||
PUT2(&zft_eof_map[i].mark.segment, 0,
|
||||
GET2(&zft_eof_map[i].mark.date,0));
|
||||
PUT2(&zft_eof_map[i].mark.date, 0, tmp);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < zft_nr_eof_marks; ++i) {
|
||||
TRACE(ft_t_noise, "eof mark: %5d/%2d",
|
||||
GET2(&zft_eof_map[i].mark.segment, 0),
|
||||
GET2(&zft_eof_map[i].mark.date,0));
|
||||
}
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
void zft_clear_ftape_file_marks(void)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
/* Clear failed sector log: remove all tape marks. We
|
||||
* don't use old ftape-style EOF-marks.
|
||||
*/
|
||||
TRACE(ft_t_info, "Clearing old ftape's eof map");
|
||||
memset(zft_eof_map, 0, zft_nr_eof_marks * sizeof(__u32));
|
||||
zft_nr_eof_marks = 0;
|
||||
PUT2(zft_hseg_buf, FT_FSL_CNT, 0); /* nr of eof-marks */
|
||||
zft_header_changed = 1;
|
||||
zft_update_label(zft_hseg_buf);
|
||||
TRACE_EXIT;
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
#ifndef _ZFTAPE_EOF_H
|
||||
#define _ZFTAPE_EOF_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 1994-1995 Bas Laarhoven.
|
||||
* adaptaed for zftape 1996, 1997 by Claus 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/ftape/zftape/zftape-eof.h,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:19:03 $
|
||||
*
|
||||
* Definitions and declarations for the end of file markers
|
||||
* for the QIC-40/80 floppy-tape driver for Linux.
|
||||
*/
|
||||
|
||||
#include <linux/ftape-header-segment.h>
|
||||
#include "../zftape/zftape-buffers.h"
|
||||
/* failed sector log size (only used if format code != 4).
|
||||
*/
|
||||
|
||||
typedef union {
|
||||
ft_fsl_entry mark;
|
||||
__u32 entry;
|
||||
} eof_mark_union;
|
||||
|
||||
/* ftape-eof.c defined global vars.
|
||||
*/
|
||||
extern int zft_nr_eof_marks;
|
||||
extern eof_mark_union *zft_eof_map;
|
||||
|
||||
/* ftape-eof.c defined global functions.
|
||||
*/
|
||||
extern void zft_ftape_extract_file_marks(__u8* address);
|
||||
extern int zft_ftape_validate_label(char* label);
|
||||
extern void zft_clear_ftape_file_marks(void);
|
||||
|
||||
#endif
|
@ -1,377 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1996, 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.
|
||||
|
||||
*
|
||||
* This file contains the code that registers the zftape frontend
|
||||
* to the ftape floppy tape driver for Linux
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/slab.h>
|
||||
#ifdef CONFIG_KMOD
|
||||
#include <linux/kmod.h>
|
||||
#endif
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/smp_lock.h>
|
||||
|
||||
#include <linux/zftape.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#include "../zftape/zftape-init.h"
|
||||
#include "../zftape/zftape-read.h"
|
||||
#include "../zftape/zftape-write.h"
|
||||
#include "../zftape/zftape-ctl.h"
|
||||
#include "../zftape/zftape-buffers.h"
|
||||
|
||||
MODULE_AUTHOR("(c) 1996, 1997 Claus-Justus Heine "
|
||||
"(claus@momo.math.rwth-aachen.de)");
|
||||
MODULE_DESCRIPTION(ZFTAPE_VERSION " - "
|
||||
"VFS interface for the Linux floppy tape driver. "
|
||||
"Support for QIC-113 compatible volume table "
|
||||
"and builtin compression (lzrw3 algorithm)");
|
||||
MODULE_SUPPORTED_DEVICE("char-major-27");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/* Global vars.
|
||||
*/
|
||||
struct zft_cmpr_ops *zft_cmpr_ops = NULL;
|
||||
const ftape_info *zft_status;
|
||||
|
||||
/* Local vars.
|
||||
*/
|
||||
static unsigned long busy_flag;
|
||||
|
||||
static sigset_t orig_sigmask;
|
||||
|
||||
/* the interface to the kernel vfs layer
|
||||
*/
|
||||
|
||||
/* Note about llseek():
|
||||
*
|
||||
* st.c and tpqic.c update fp->f_pos but don't implment llseek() and
|
||||
* initialize the llseek component of the file_ops struct with NULL.
|
||||
* This means that the user will get the default seek, but the tape
|
||||
* device will not respect the new position, but happily read from the
|
||||
* old position. Think a zftape specific llseek() function would be
|
||||
* better, returning -ESPIPE. TODO.
|
||||
*/
|
||||
|
||||
static int zft_open (struct inode *ino, struct file *filep);
|
||||
static int zft_close(struct inode *ino, struct file *filep);
|
||||
static int zft_ioctl(struct inode *ino, struct file *filep,
|
||||
unsigned int command, unsigned long arg);
|
||||
static int zft_mmap(struct file *filep, struct vm_area_struct *vma);
|
||||
static ssize_t zft_read (struct file *fp, char __user *buff,
|
||||
size_t req_len, loff_t *ppos);
|
||||
static ssize_t zft_write(struct file *fp, const char __user *buff,
|
||||
size_t req_len, loff_t *ppos);
|
||||
|
||||
static const struct file_operations zft_cdev =
|
||||
{
|
||||
.owner = THIS_MODULE,
|
||||
.read = zft_read,
|
||||
.write = zft_write,
|
||||
.ioctl = zft_ioctl,
|
||||
.mmap = zft_mmap,
|
||||
.open = zft_open,
|
||||
.release = zft_close,
|
||||
};
|
||||
|
||||
static struct class *zft_class;
|
||||
|
||||
/* Open floppy tape device
|
||||
*/
|
||||
static int zft_open(struct inode *ino, struct file *filep)
|
||||
{
|
||||
int result;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
nonseekable_open(ino, filep);
|
||||
TRACE(ft_t_flow, "called for minor %d", iminor(ino));
|
||||
if ( test_and_set_bit(0,&busy_flag) ) {
|
||||
TRACE_ABORT(-EBUSY, ft_t_warn, "failed: already busy");
|
||||
}
|
||||
if ((iminor(ino) & ~(ZFT_MINOR_OP_MASK | FTAPE_NO_REWIND))
|
||||
>
|
||||
FTAPE_SEL_D) {
|
||||
clear_bit(0,&busy_flag);
|
||||
TRACE_ABORT(-ENXIO, ft_t_err, "failed: invalid unit nr");
|
||||
}
|
||||
orig_sigmask = current->blocked;
|
||||
sigfillset(¤t->blocked);
|
||||
result = _zft_open(iminor(ino), filep->f_flags & O_ACCMODE);
|
||||
if (result < 0) {
|
||||
current->blocked = orig_sigmask; /* restore mask */
|
||||
clear_bit(0,&busy_flag);
|
||||
TRACE_ABORT(result, ft_t_err, "_ftape_open failed");
|
||||
} else {
|
||||
/* Mask signals that will disturb proper operation of the
|
||||
* program that is calling.
|
||||
*/
|
||||
current->blocked = orig_sigmask;
|
||||
sigaddsetmask (¤t->blocked, _DO_BLOCK);
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Close floppy tape device
|
||||
*/
|
||||
static int zft_close(struct inode *ino, struct file *filep)
|
||||
{
|
||||
int result;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if ( !test_bit(0,&busy_flag) || iminor(ino) != zft_unit) {
|
||||
TRACE(ft_t_err, "failed: not busy or wrong unit");
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
sigfillset(¤t->blocked);
|
||||
result = _zft_close();
|
||||
if (result < 0) {
|
||||
TRACE(ft_t_err, "_zft_close failed");
|
||||
}
|
||||
current->blocked = orig_sigmask; /* restore before open state */
|
||||
clear_bit(0,&busy_flag);
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
/* Ioctl for floppy tape device
|
||||
*/
|
||||
static int zft_ioctl(struct inode *ino, struct file *filep,
|
||||
unsigned int command, unsigned long arg)
|
||||
{
|
||||
int result = -EIO;
|
||||
sigset_t old_sigmask;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if ( !test_bit(0,&busy_flag) || iminor(ino) != zft_unit || ft_failure) {
|
||||
TRACE_ABORT(-EIO, ft_t_err,
|
||||
"failed: not busy, failure or wrong unit");
|
||||
}
|
||||
old_sigmask = current->blocked; /* save mask */
|
||||
sigfillset(¤t->blocked);
|
||||
/* This will work as long as sizeof(void *) == sizeof(long) */
|
||||
result = _zft_ioctl(command, (void __user *) arg);
|
||||
current->blocked = old_sigmask; /* restore mask */
|
||||
TRACE_EXIT result;
|
||||
}
|
||||
|
||||
/* Ioctl for floppy tape device
|
||||
*/
|
||||
static int zft_mmap(struct file *filep, struct vm_area_struct *vma)
|
||||
{
|
||||
int result = -EIO;
|
||||
sigset_t old_sigmask;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if ( !test_bit(0,&busy_flag) ||
|
||||
iminor(filep->f_dentry->d_inode) != zft_unit ||
|
||||
ft_failure)
|
||||
{
|
||||
TRACE_ABORT(-EIO, ft_t_err,
|
||||
"failed: not busy, failure or wrong unit");
|
||||
}
|
||||
old_sigmask = current->blocked; /* save mask */
|
||||
sigfillset(¤t->blocked);
|
||||
if ((result = ftape_mmap(vma)) >= 0) {
|
||||
#ifndef MSYNC_BUG_WAS_FIXED
|
||||
static struct vm_operations_struct dummy = { NULL, };
|
||||
vma->vm_ops = &dummy;
|
||||
#endif
|
||||
}
|
||||
current->blocked = old_sigmask; /* restore mask */
|
||||
TRACE_EXIT result;
|
||||
}
|
||||
|
||||
/* Read from floppy tape device
|
||||
*/
|
||||
static ssize_t zft_read(struct file *fp, char __user *buff,
|
||||
size_t req_len, loff_t *ppos)
|
||||
{
|
||||
int result = -EIO;
|
||||
sigset_t old_sigmask;
|
||||
struct inode *ino = fp->f_dentry->d_inode;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
TRACE(ft_t_data_flow, "called with count: %ld", (unsigned long)req_len);
|
||||
if (!test_bit(0,&busy_flag) || iminor(ino) != zft_unit || ft_failure) {
|
||||
TRACE_ABORT(-EIO, ft_t_err,
|
||||
"failed: not busy, failure or wrong unit");
|
||||
}
|
||||
old_sigmask = current->blocked; /* save mask */
|
||||
sigfillset(¤t->blocked);
|
||||
result = _zft_read(buff, req_len);
|
||||
current->blocked = old_sigmask; /* restore mask */
|
||||
TRACE(ft_t_data_flow, "return with count: %d", result);
|
||||
TRACE_EXIT result;
|
||||
}
|
||||
|
||||
/* Write to tape device
|
||||
*/
|
||||
static ssize_t zft_write(struct file *fp, const char __user *buff,
|
||||
size_t req_len, loff_t *ppos)
|
||||
{
|
||||
int result = -EIO;
|
||||
sigset_t old_sigmask;
|
||||
struct inode *ino = fp->f_dentry->d_inode;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
TRACE(ft_t_flow, "called with count: %ld", (unsigned long)req_len);
|
||||
if (!test_bit(0,&busy_flag) || iminor(ino) != zft_unit || ft_failure) {
|
||||
TRACE_ABORT(-EIO, ft_t_err,
|
||||
"failed: not busy, failure or wrong unit");
|
||||
}
|
||||
old_sigmask = current->blocked; /* save mask */
|
||||
sigfillset(¤t->blocked);
|
||||
result = _zft_write(buff, req_len);
|
||||
current->blocked = old_sigmask; /* restore mask */
|
||||
TRACE(ft_t_data_flow, "return with count: %d", result);
|
||||
TRACE_EXIT result;
|
||||
}
|
||||
|
||||
/* END OF VFS INTERFACE
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/* driver/module initialization
|
||||
*/
|
||||
|
||||
/* the compression module has to call this function to hook into the zftape
|
||||
* code
|
||||
*/
|
||||
int zft_cmpr_register(struct zft_cmpr_ops *new_ops)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (zft_cmpr_ops != NULL) {
|
||||
TRACE_EXIT -EBUSY;
|
||||
} else {
|
||||
zft_cmpr_ops = new_ops;
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* lock the zft-compressor() module.
|
||||
*/
|
||||
int zft_cmpr_lock(int try_to_load)
|
||||
{
|
||||
if (zft_cmpr_ops == NULL) {
|
||||
#ifdef CONFIG_KMOD
|
||||
if (try_to_load) {
|
||||
request_module("zft-compressor");
|
||||
if (zft_cmpr_ops == NULL) {
|
||||
return -ENOSYS;
|
||||
}
|
||||
} else {
|
||||
return -ENOSYS;
|
||||
}
|
||||
#else
|
||||
return -ENOSYS;
|
||||
#endif
|
||||
}
|
||||
(*zft_cmpr_ops->lock)();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ZFT_COMPRESSOR
|
||||
extern int zft_compressor_init(void);
|
||||
#endif
|
||||
|
||||
/* Called by modules package when installing the driver or by kernel
|
||||
* during the initialization phase
|
||||
*/
|
||||
int __init zft_init(void)
|
||||
{
|
||||
int i;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
#ifdef MODULE
|
||||
printk(KERN_INFO ZFTAPE_VERSION "\n");
|
||||
if (TRACE_LEVEL >= ft_t_info) {
|
||||
printk(
|
||||
KERN_INFO
|
||||
"(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)\n"
|
||||
KERN_INFO
|
||||
"vfs interface for ftape floppy tape driver.\n"
|
||||
KERN_INFO
|
||||
"Support for QIC-113 compatible volume table, dynamic memory allocation\n"
|
||||
KERN_INFO
|
||||
"and builtin compression (lzrw3 algorithm).\n");
|
||||
}
|
||||
#else /* !MODULE */
|
||||
/* print a short no-nonsense boot message */
|
||||
printk(KERN_INFO ZFTAPE_VERSION "\n");
|
||||
#endif /* MODULE */
|
||||
TRACE(ft_t_info, "zft_init @ 0x%p", zft_init);
|
||||
TRACE(ft_t_info,
|
||||
"installing zftape VFS interface for ftape driver ...");
|
||||
TRACE_CATCH(register_chrdev(QIC117_TAPE_MAJOR, "zft", &zft_cdev),);
|
||||
|
||||
zft_class = class_create(THIS_MODULE, "zft");
|
||||
for (i = 0; i < 4; i++) {
|
||||
class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i), NULL, "qft%i", i);
|
||||
class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 4), NULL, "nqft%i", i);
|
||||
class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 16), NULL, "zqft%i", i);
|
||||
class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 20), NULL, "nzqft%i", i);
|
||||
class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 32), NULL, "rawqft%i", i);
|
||||
class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 36), NULL, "nrawrawqft%i", i);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ZFT_COMPRESSOR
|
||||
(void)zft_compressor_init();
|
||||
#endif
|
||||
zft_status = ftape_get_status(); /* fetch global data of ftape
|
||||
* hardware driver
|
||||
*/
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
|
||||
/* Called by modules package when removing the driver
|
||||
*/
|
||||
static void zft_exit(void)
|
||||
{
|
||||
int i;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (unregister_chrdev(QIC117_TAPE_MAJOR, "zft") != 0) {
|
||||
TRACE(ft_t_warn, "failed");
|
||||
} else {
|
||||
TRACE(ft_t_info, "successful");
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i));
|
||||
class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 4));
|
||||
class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 16));
|
||||
class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 20));
|
||||
class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 32));
|
||||
class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 36));
|
||||
}
|
||||
class_destroy(zft_class);
|
||||
zft_uninit_mem(); /* release remaining memory, if any */
|
||||
printk(KERN_INFO "zftape successfully unloaded.\n");
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
module_init(zft_init);
|
||||
module_exit(zft_exit);
|
@ -1,77 +0,0 @@
|
||||
#ifndef _ZFTAPE_INIT_H
|
||||
#define _ZFTAPE_INIT_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 1996, 1997 Claus 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/ftape/zftape/zftape-init.h,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:19:05 $
|
||||
*
|
||||
* This file contains definitions and macro for the vfs
|
||||
* interface defined by zftape
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/ftape-header-segment.h>
|
||||
|
||||
#include "../lowlevel/ftape-tracing.h"
|
||||
#include "../lowlevel/ftape-ctl.h"
|
||||
#include "../lowlevel/ftape-read.h"
|
||||
#include "../lowlevel/ftape-write.h"
|
||||
#include "../lowlevel/ftape-bsm.h"
|
||||
#include "../lowlevel/ftape-io.h"
|
||||
#include "../lowlevel/ftape-buffer.h"
|
||||
#include "../lowlevel/ftape-format.h"
|
||||
|
||||
#include "../zftape/zftape-rw.h"
|
||||
|
||||
#ifdef MODULE
|
||||
#define ftape_status (*zft_status)
|
||||
#endif
|
||||
|
||||
extern const ftape_info *zft_status; /* needed for zftape-vtbl.h */
|
||||
|
||||
#include "../zftape/zftape-vtbl.h"
|
||||
|
||||
struct zft_cmpr_ops {
|
||||
int (*write)(int *write_cnt,
|
||||
__u8 *dst_buf, const int seg_sz,
|
||||
const __u8 __user *src_buf, const int req_len,
|
||||
const zft_position *pos, const zft_volinfo *volume);
|
||||
int (*read)(int *read_cnt,
|
||||
__u8 __user *dst_buf, const int req_len,
|
||||
const __u8 *src_buf, const int seg_sz,
|
||||
const zft_position *pos, const zft_volinfo *volume);
|
||||
int (*seek)(unsigned int new_block_pos,
|
||||
zft_position *pos, const zft_volinfo *volume,
|
||||
__u8 *buffer);
|
||||
void (*lock) (void);
|
||||
void (*reset) (void);
|
||||
void (*cleanup)(void);
|
||||
};
|
||||
|
||||
extern struct zft_cmpr_ops *zft_cmpr_ops;
|
||||
/* zftape-init.c defined global functions.
|
||||
*/
|
||||
extern int zft_cmpr_register(struct zft_cmpr_ops *new_ops);
|
||||
extern int zft_cmpr_lock(int try_to_load);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1,377 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1996, 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/ftape/zftape/zftape-read.c,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:19:06 $
|
||||
*
|
||||
* This file contains the high level reading code
|
||||
* for the QIC-117 floppy-tape driver for Linux.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <linux/zftape.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include "../zftape/zftape-init.h"
|
||||
#include "../zftape/zftape-eof.h"
|
||||
#include "../zftape/zftape-ctl.h"
|
||||
#include "../zftape/zftape-write.h"
|
||||
#include "../zftape/zftape-read.h"
|
||||
#include "../zftape/zftape-rw.h"
|
||||
#include "../zftape/zftape-vtbl.h"
|
||||
|
||||
/* Global vars.
|
||||
*/
|
||||
int zft_just_before_eof;
|
||||
|
||||
/* Local vars.
|
||||
*/
|
||||
static int buf_len_rd;
|
||||
|
||||
void zft_zap_read_buffers(void)
|
||||
{
|
||||
buf_len_rd = 0;
|
||||
}
|
||||
|
||||
int zft_read_header_segments(void)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
zft_header_read = 0;
|
||||
TRACE_CATCH(zft_vmalloc_once(&zft_hseg_buf, FT_SEGMENT_SIZE),);
|
||||
TRACE_CATCH(ftape_read_header_segment(zft_hseg_buf),);
|
||||
TRACE(ft_t_info, "Segments written since first format: %d",
|
||||
(int)GET4(zft_hseg_buf, FT_SEG_CNT));
|
||||
zft_qic113 = (ft_format_code != fmt_normal &&
|
||||
ft_format_code != fmt_1100ft &&
|
||||
ft_format_code != fmt_425ft);
|
||||
TRACE(ft_t_info, "ft_first_data_segment: %d, ft_last_data_segment: %d",
|
||||
ft_first_data_segment, ft_last_data_segment);
|
||||
zft_capacity = zft_get_capacity();
|
||||
zft_old_ftape = zft_ftape_validate_label(&zft_hseg_buf[FT_LABEL]);
|
||||
if (zft_old_ftape) {
|
||||
TRACE(ft_t_info,
|
||||
"Found old ftaped tape, emulating eof marks, entering read-only mode");
|
||||
zft_ftape_extract_file_marks(zft_hseg_buf);
|
||||
TRACE_CATCH(zft_fake_volume_headers(zft_eof_map,
|
||||
zft_nr_eof_marks),);
|
||||
} else {
|
||||
/* the specs say that the volume table must be
|
||||
* initialized with zeroes during formatting, so it
|
||||
* MUST be readable, i.e. contain vaid ECC
|
||||
* information.
|
||||
*/
|
||||
TRACE_CATCH(ftape_read_segment(ft_first_data_segment,
|
||||
zft_deblock_buf,
|
||||
FT_RD_SINGLE),);
|
||||
TRACE_CATCH(zft_extract_volume_headers(zft_deblock_buf),);
|
||||
}
|
||||
zft_header_read = 1;
|
||||
zft_set_flags(zft_unit);
|
||||
zft_reset_position(&zft_pos);
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
int zft_fetch_segment_fraction(const unsigned int segment, void *buffer,
|
||||
const ft_read_mode_t read_mode,
|
||||
const unsigned int start,
|
||||
const unsigned int size)
|
||||
{
|
||||
int seg_sz;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (segment == zft_deblock_segment) {
|
||||
TRACE(ft_t_data_flow,
|
||||
"re-using segment %d already in deblock buffer",
|
||||
segment);
|
||||
seg_sz = zft_get_seg_sz(segment);
|
||||
if (start > seg_sz) {
|
||||
TRACE_ABORT(-EINVAL, ft_t_bug,
|
||||
"trying to read beyond end of segment:\n"
|
||||
KERN_INFO "seg_sz : %d\n"
|
||||
KERN_INFO "start : %d\n"
|
||||
KERN_INFO "segment: %d",
|
||||
seg_sz, start, segment);
|
||||
}
|
||||
if ((start + size) > seg_sz) {
|
||||
TRACE_EXIT seg_sz - start;
|
||||
}
|
||||
TRACE_EXIT size;
|
||||
}
|
||||
seg_sz = ftape_read_segment_fraction(segment, buffer, read_mode,
|
||||
start, size);
|
||||
TRACE(ft_t_data_flow, "segment %d, result %d", segment, seg_sz);
|
||||
if ((int)seg_sz >= 0 && start == 0 && size == FT_SEGMENT_SIZE) {
|
||||
/* this implicitly assumes that we are always called with
|
||||
* buffer == zft_deblock_buf
|
||||
*/
|
||||
zft_deblock_segment = segment;
|
||||
} else {
|
||||
zft_deblock_segment = -1;
|
||||
}
|
||||
TRACE_EXIT seg_sz;
|
||||
}
|
||||
|
||||
/*
|
||||
* out:
|
||||
*
|
||||
* int *read_cnt: the number of bytes we removed from the
|
||||
* zft_deblock_buf (result)
|
||||
*
|
||||
* int *to_do : the remaining size of the read-request. Is changed.
|
||||
*
|
||||
* in:
|
||||
*
|
||||
* char *buff : buff is the address of the upper part of the user
|
||||
* buffer, that hasn't been filled with data yet.
|
||||
* int buf_pos_read: copy of buf_pos_rd
|
||||
* int buf_len_read: copy of buf_len_rd
|
||||
* char *zft_deblock_buf: ftape_zft_deblock_buf
|
||||
*
|
||||
* returns the amount of data actually copied to the user-buffer
|
||||
*
|
||||
* to_do MUST NOT SHRINK except to indicate an EOT. In this case to_do
|
||||
* has to be set to 0. We cannot return -ENOSPC, because we return the
|
||||
* amount of data actually * copied to the user-buffer
|
||||
*/
|
||||
static int zft_simple_read (int *read_cnt,
|
||||
__u8 __user *dst_buf,
|
||||
const int to_do,
|
||||
const __u8 *src_buf,
|
||||
const int seg_sz,
|
||||
const zft_position *pos,
|
||||
const zft_volinfo *volume)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (seg_sz - pos->seg_byte_pos < to_do) {
|
||||
*read_cnt = seg_sz - pos->seg_byte_pos;
|
||||
} else {
|
||||
*read_cnt = to_do;
|
||||
}
|
||||
if (copy_to_user(dst_buf,
|
||||
src_buf + pos->seg_byte_pos, *read_cnt) != 0) {
|
||||
TRACE_EXIT -EFAULT;
|
||||
}
|
||||
TRACE(ft_t_noise, "nr bytes just read: %d", *read_cnt);
|
||||
TRACE_EXIT *read_cnt;
|
||||
}
|
||||
|
||||
/* req_len: gets clipped due to EOT of EOF.
|
||||
* req_clipped: is a flag indicating whether req_len was clipped or not
|
||||
* volume: contains information on current volume (blk_sz etc.)
|
||||
*/
|
||||
static int check_read_access(int *req_len,
|
||||
const zft_volinfo **volume,
|
||||
int *req_clipped,
|
||||
const zft_position *pos)
|
||||
{
|
||||
static __s64 remaining;
|
||||
static int eod;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (zft_io_state != zft_reading) {
|
||||
if (zft_offline) { /* offline includes no_tape */
|
||||
TRACE_ABORT(-ENXIO, ft_t_warn,
|
||||
"tape is offline or no cartridge");
|
||||
}
|
||||
if (!ft_formatted) {
|
||||
TRACE_ABORT(-EACCES,
|
||||
ft_t_warn, "tape is not formatted");
|
||||
}
|
||||
/* now enter defined state, read header segment if not
|
||||
* already done and flush write buffers
|
||||
*/
|
||||
TRACE_CATCH(zft_def_idle_state(),);
|
||||
zft_io_state = zft_reading;
|
||||
if (zft_tape_at_eod(pos)) {
|
||||
eod = 1;
|
||||
TRACE_EXIT 1;
|
||||
}
|
||||
eod = 0;
|
||||
*volume = zft_find_volume(pos->seg_pos);
|
||||
/* get the space left until EOF */
|
||||
remaining = zft_check_for_eof(*volume, pos);
|
||||
buf_len_rd = 0;
|
||||
TRACE(ft_t_noise, "remaining: " LL_X ", vol_no: %d",
|
||||
LL(remaining), (*volume)->count);
|
||||
} else if (zft_tape_at_eod(pos)) {
|
||||
if (++eod > 2) {
|
||||
TRACE_EXIT -EIO; /* st.c also returns -EIO */
|
||||
} else {
|
||||
TRACE_EXIT 1;
|
||||
}
|
||||
}
|
||||
if ((*req_len % (*volume)->blk_sz) != 0) {
|
||||
/* this message is informational only. The user gets the
|
||||
* proper return value
|
||||
*/
|
||||
TRACE_ABORT(-EINVAL, ft_t_info,
|
||||
"req_len %d not a multiple of block size %d",
|
||||
*req_len, (*volume)->blk_sz);
|
||||
}
|
||||
/* As GNU tar doesn't accept partial read counts when the
|
||||
* multiple volume flag is set, we make sure to return the
|
||||
* requested amount of data. Except, of course, at the end of
|
||||
* the tape or file mark.
|
||||
*/
|
||||
remaining -= *req_len;
|
||||
if (remaining <= 0) {
|
||||
TRACE(ft_t_noise,
|
||||
"clipped request from %d to %d.",
|
||||
*req_len, (int)(*req_len + remaining));
|
||||
*req_len += remaining;
|
||||
*req_clipped = 1;
|
||||
} else {
|
||||
*req_clipped = 0;
|
||||
}
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
/* this_segs_size: the current segment's size.
|
||||
* buff: the USER-SPACE buffer provided by the calling function.
|
||||
* req_len: how much data should be read at most.
|
||||
* volume: contains information on current volume (blk_sz etc.)
|
||||
*/
|
||||
static int empty_deblock_buf(__u8 __user *usr_buf, const int req_len,
|
||||
const __u8 *src_buf, const int seg_sz,
|
||||
zft_position *pos,
|
||||
const zft_volinfo *volume)
|
||||
{
|
||||
int cnt;
|
||||
int result = 0;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
TRACE(ft_t_data_flow, "this_segs_size: %d", seg_sz);
|
||||
if (zft_use_compression && volume->use_compression) {
|
||||
TRACE_CATCH(zft_cmpr_lock(1 /* try to load */),);
|
||||
TRACE_CATCH(result= (*zft_cmpr_ops->read)(&cnt,
|
||||
usr_buf, req_len,
|
||||
src_buf, seg_sz,
|
||||
pos, volume),);
|
||||
} else {
|
||||
TRACE_CATCH(result= zft_simple_read (&cnt,
|
||||
usr_buf, req_len,
|
||||
src_buf, seg_sz,
|
||||
pos, volume),);
|
||||
}
|
||||
pos->volume_pos += result;
|
||||
pos->tape_pos += cnt;
|
||||
pos->seg_byte_pos += cnt;
|
||||
buf_len_rd -= cnt; /* remaining bytes in buffer */
|
||||
TRACE(ft_t_data_flow, "buf_len_rd: %d, cnt: %d", buf_len_rd, cnt);
|
||||
if(pos->seg_byte_pos >= seg_sz) {
|
||||
pos->seg_pos++;
|
||||
pos->seg_byte_pos = 0;
|
||||
}
|
||||
TRACE(ft_t_data_flow, "bytes moved out of deblock-buffer: %d", cnt);
|
||||
TRACE_EXIT result;
|
||||
}
|
||||
|
||||
|
||||
/* note: we store the segment id of the segment that is inside the
|
||||
* deblock buffer. This spares a lot of ftape_read_segment()s when we
|
||||
* use small block-sizes. The block-size may be 1kb (SECTOR_SIZE). In
|
||||
* this case a MTFSR 28 maybe still inside the same segment.
|
||||
*/
|
||||
int _zft_read(char __user *buff, int req_len)
|
||||
{
|
||||
int req_clipped;
|
||||
int result = 0;
|
||||
int bytes_read = 0;
|
||||
static unsigned int seg_sz = 0;
|
||||
static const zft_volinfo *volume = NULL;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
zft_resid = req_len;
|
||||
result = check_read_access(&req_len, &volume,
|
||||
&req_clipped, &zft_pos);
|
||||
switch(result) {
|
||||
case 0:
|
||||
break; /* nothing special */
|
||||
case 1:
|
||||
TRACE(ft_t_noise, "EOD reached");
|
||||
TRACE_EXIT 0; /* EOD */
|
||||
default:
|
||||
TRACE_ABORT(result, ft_t_noise,
|
||||
"check_read_access() failed with result %d",
|
||||
result);
|
||||
TRACE_EXIT result;
|
||||
}
|
||||
while (req_len > 0) {
|
||||
/* Allow escape from this loop on signal !
|
||||
*/
|
||||
FT_SIGNAL_EXIT(_DONT_BLOCK);
|
||||
/* buf_len_rd == 0 means that we need to read a new
|
||||
* segment.
|
||||
*/
|
||||
if (buf_len_rd == 0) {
|
||||
while((result = zft_fetch_segment(zft_pos.seg_pos,
|
||||
zft_deblock_buf,
|
||||
FT_RD_AHEAD)) == 0) {
|
||||
zft_pos.seg_pos ++;
|
||||
zft_pos.seg_byte_pos = 0;
|
||||
}
|
||||
if (result < 0) {
|
||||
zft_resid -= bytes_read;
|
||||
TRACE_ABORT(result, ft_t_noise,
|
||||
"zft_fetch_segment(): %d",
|
||||
result);
|
||||
}
|
||||
seg_sz = result;
|
||||
buf_len_rd = seg_sz - zft_pos.seg_byte_pos;
|
||||
}
|
||||
TRACE_CATCH(result = empty_deblock_buf(buff,
|
||||
req_len,
|
||||
zft_deblock_buf,
|
||||
seg_sz,
|
||||
&zft_pos,
|
||||
volume),
|
||||
zft_resid -= bytes_read);
|
||||
TRACE(ft_t_data_flow, "bytes just read: %d", result);
|
||||
bytes_read += result; /* what we got so far */
|
||||
buff += result; /* index in user-buffer */
|
||||
req_len -= result; /* what's left from req_len */
|
||||
} /* while (req_len > 0) */
|
||||
if (req_clipped) {
|
||||
TRACE(ft_t_data_flow,
|
||||
"maybe partial count because of eof mark");
|
||||
if (zft_just_before_eof && bytes_read == 0) {
|
||||
/* req_len was > 0, but user didn't get
|
||||
* anything the user has read in the eof-mark
|
||||
*/
|
||||
zft_move_past_eof(&zft_pos);
|
||||
ftape_abort_operation();
|
||||
} else {
|
||||
/* don't skip to the next file before the user
|
||||
* tried to read a second time past EOF Just
|
||||
* mark that we are at EOF and maybe decrement
|
||||
* zft_seg_pos to stay in the same volume;
|
||||
*/
|
||||
zft_just_before_eof = 1;
|
||||
zft_position_before_eof(&zft_pos, volume);
|
||||
TRACE(ft_t_noise, "just before eof");
|
||||
}
|
||||
}
|
||||
zft_resid -= result; /* for MTSTATUS */
|
||||
TRACE_EXIT bytes_read;
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
#ifndef _ZFTAPE_READ_H
|
||||
#define _ZFTAPE_READ_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 1996, 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/ftape/zftape/zftape-read.h,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:19:07 $
|
||||
*
|
||||
* This file contains the definitions for the read functions
|
||||
* for the zftape driver for Linux.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../lowlevel/ftape-read.h"
|
||||
|
||||
/* ftape-read.c defined global vars.
|
||||
*/
|
||||
extern int zft_just_before_eof;
|
||||
|
||||
/* ftape-read.c defined global functions.
|
||||
*/
|
||||
extern void zft_zap_read_buffers(void);
|
||||
extern int zft_read_header_segments(void);
|
||||
extern int zft_fetch_segment_fraction(const unsigned int segment,
|
||||
void *buffer,
|
||||
const ft_read_mode_t read_mode,
|
||||
const unsigned int start,
|
||||
const unsigned int size);
|
||||
#define zft_fetch_segment(segment, address, read_mode) \
|
||||
zft_fetch_segment_fraction(segment, address, read_mode, \
|
||||
0, FT_SEGMENT_SIZE)
|
||||
/* hook for the VFS interface
|
||||
*/
|
||||
extern int _zft_read(char __user *buff, int req_len);
|
||||
|
||||
#endif /* _ZFTAPE_READ_H */
|
@ -1,375 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1996, 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/ftape/zftape/zftape-rw.c,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:19:08 $
|
||||
*
|
||||
* This file contains some common code for the r/w code for
|
||||
* zftape.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <linux/zftape.h>
|
||||
#include "../zftape/zftape-init.h"
|
||||
#include "../zftape/zftape-eof.h"
|
||||
#include "../zftape/zftape-ctl.h"
|
||||
#include "../zftape/zftape-write.h"
|
||||
#include "../zftape/zftape-read.h"
|
||||
#include "../zftape/zftape-rw.h"
|
||||
#include "../zftape/zftape-vtbl.h"
|
||||
|
||||
/* Global vars.
|
||||
*/
|
||||
|
||||
__u8 *zft_deblock_buf;
|
||||
__u8 *zft_hseg_buf;
|
||||
int zft_deblock_segment = -1;
|
||||
zft_status_enum zft_io_state = zft_idle;
|
||||
int zft_header_changed;
|
||||
int zft_qic113; /* conform to old specs. and old zftape */
|
||||
int zft_use_compression;
|
||||
zft_position zft_pos = {
|
||||
-1, /* seg_pos */
|
||||
0, /* seg_byte_pos */
|
||||
0, /* tape_pos */
|
||||
0 /* volume_pos */
|
||||
};
|
||||
unsigned int zft_blk_sz = CONFIG_ZFT_DFLT_BLK_SZ;
|
||||
__s64 zft_capacity;
|
||||
|
||||
unsigned int zft_written_segments;
|
||||
int zft_label_changed;
|
||||
|
||||
/* Local vars.
|
||||
*/
|
||||
|
||||
unsigned int zft_get_seg_sz(unsigned int segment)
|
||||
{
|
||||
int size;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
size = FT_SEGMENT_SIZE -
|
||||
count_ones(ftape_get_bad_sector_entry(segment))*FT_SECTOR_SIZE;
|
||||
if (size > 0) {
|
||||
TRACE_EXIT (unsigned)size;
|
||||
} else {
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ftape_set_flags(). Claus-Justus Heine, 1994/1995
|
||||
*/
|
||||
void zft_set_flags(unsigned minor_unit)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
zft_use_compression = zft_qic_mode = 0;
|
||||
switch (minor_unit & ZFT_MINOR_OP_MASK) {
|
||||
case (ZFT_Q80_MODE | ZFT_ZIP_MODE):
|
||||
case ZFT_ZIP_MODE:
|
||||
zft_use_compression = 1;
|
||||
case 0:
|
||||
case ZFT_Q80_MODE:
|
||||
zft_qic_mode = 1;
|
||||
if (zft_mt_compression) { /* override the default */
|
||||
zft_use_compression = 1;
|
||||
}
|
||||
break;
|
||||
case ZFT_RAW_MODE:
|
||||
TRACE(ft_t_noise, "switching to raw mode");
|
||||
break;
|
||||
default:
|
||||
TRACE(ft_t_warn, "Warning:\n"
|
||||
KERN_INFO "Wrong combination of minor device bits.\n"
|
||||
KERN_INFO "Switching to raw read-only mode.");
|
||||
zft_write_protected = 1;
|
||||
break;
|
||||
}
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
/* computes the segment and byte offset inside the segment
|
||||
* corresponding to tape_pos.
|
||||
*
|
||||
* tape_pos gives the offset in bytes from the beginning of the
|
||||
* ft_first_data_segment *seg_byte_pos is the offset in the current
|
||||
* segment in bytes
|
||||
*
|
||||
* Of, if this routine was called often one should cache the last data
|
||||
* pos it was called with, but actually this is only needed in
|
||||
* ftape_seek_block(), that is, almost never.
|
||||
*/
|
||||
int zft_calc_seg_byte_coord(int *seg_byte_pos, __s64 tape_pos)
|
||||
{
|
||||
int segment;
|
||||
int seg_sz;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (tape_pos == 0) {
|
||||
*seg_byte_pos = 0;
|
||||
segment = ft_first_data_segment;
|
||||
} else {
|
||||
seg_sz = 0;
|
||||
|
||||
for (segment = ft_first_data_segment;
|
||||
((tape_pos > 0) && (segment <= ft_last_data_segment));
|
||||
segment++) {
|
||||
seg_sz = zft_get_seg_sz(segment);
|
||||
tape_pos -= seg_sz;
|
||||
}
|
||||
if(tape_pos >= 0) {
|
||||
/* the case tape_pos > != 0 means that the
|
||||
* argument tape_pos lies beyond the EOT.
|
||||
*/
|
||||
*seg_byte_pos= 0;
|
||||
} else { /* tape_pos < 0 */
|
||||
segment--;
|
||||
*seg_byte_pos= tape_pos + seg_sz;
|
||||
}
|
||||
}
|
||||
TRACE_EXIT(segment);
|
||||
}
|
||||
|
||||
/* ftape_calc_tape_pos().
|
||||
*
|
||||
* computes the offset in bytes from the beginning of the
|
||||
* ft_first_data_segment inverse to ftape_calc_seg_byte_coord
|
||||
*
|
||||
* We should do some caching. But how:
|
||||
*
|
||||
* Each time the header segments are read in, this routine is called
|
||||
* with ft_tracks_per_tape*segments_per_track argumnet. So this should be
|
||||
* the time to reset the cache.
|
||||
*
|
||||
* Also, it might be in the future that the bad sector map gets
|
||||
* changed. -> reset the cache
|
||||
*/
|
||||
static int seg_pos;
|
||||
static __s64 tape_pos;
|
||||
|
||||
__s64 zft_get_capacity(void)
|
||||
{
|
||||
seg_pos = ft_first_data_segment;
|
||||
tape_pos = 0;
|
||||
|
||||
while (seg_pos <= ft_last_data_segment) {
|
||||
tape_pos += zft_get_seg_sz(seg_pos ++);
|
||||
}
|
||||
return tape_pos;
|
||||
}
|
||||
|
||||
__s64 zft_calc_tape_pos(int segment)
|
||||
{
|
||||
int d1, d2, d3;
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
if (segment > ft_last_data_segment) {
|
||||
TRACE_EXIT zft_capacity;
|
||||
}
|
||||
if (segment < ft_first_data_segment) {
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
d2 = segment - seg_pos;
|
||||
if (-d2 > 10) {
|
||||
d1 = segment - ft_first_data_segment;
|
||||
if (-d2 > d1) {
|
||||
tape_pos = 0;
|
||||
seg_pos = ft_first_data_segment;
|
||||
d2 = d1;
|
||||
}
|
||||
}
|
||||
if (d2 > 10) {
|
||||
d3 = ft_last_data_segment - segment;
|
||||
if (d2 > d3) {
|
||||
tape_pos = zft_capacity;
|
||||
seg_pos = ft_last_data_segment + 1;
|
||||
d2 = -d3;
|
||||
}
|
||||
}
|
||||
if (d2 > 0) {
|
||||
while (seg_pos < segment) {
|
||||
tape_pos += zft_get_seg_sz(seg_pos++);
|
||||
}
|
||||
} else {
|
||||
while (seg_pos > segment) {
|
||||
tape_pos -= zft_get_seg_sz(--seg_pos);
|
||||
}
|
||||
}
|
||||
TRACE(ft_t_noise, "new cached pos: %d", seg_pos);
|
||||
|
||||
TRACE_EXIT tape_pos;
|
||||
}
|
||||
|
||||
/* copy Z-label string to buffer, keeps track of the correct offset in
|
||||
* `buffer'
|
||||
*/
|
||||
void zft_update_label(__u8 *buffer)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (strncmp(&buffer[FT_LABEL], ZFTAPE_LABEL,
|
||||
sizeof(ZFTAPE_LABEL)-1) != 0) {
|
||||
TRACE(ft_t_info, "updating label from \"%s\" to \"%s\"",
|
||||
&buffer[FT_LABEL], ZFTAPE_LABEL);
|
||||
strcpy(&buffer[FT_LABEL], ZFTAPE_LABEL);
|
||||
memset(&buffer[FT_LABEL] + sizeof(ZFTAPE_LABEL) - 1, ' ',
|
||||
FT_LABEL_SZ - sizeof(ZFTAPE_LABEL + 1));
|
||||
PUT4(buffer, FT_LABEL_DATE, 0);
|
||||
zft_label_changed = zft_header_changed = 1; /* changed */
|
||||
}
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
int zft_verify_write_segments(unsigned int segment,
|
||||
__u8 *data, size_t size,
|
||||
__u8 *buffer)
|
||||
{
|
||||
int result;
|
||||
__u8 *write_buf;
|
||||
__u8 *src_buf;
|
||||
int single;
|
||||
int seg_pos;
|
||||
int seg_sz;
|
||||
int remaining;
|
||||
ft_write_mode_t write_mode;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
seg_pos = segment;
|
||||
seg_sz = zft_get_seg_sz(seg_pos);
|
||||
src_buf = data;
|
||||
single = size <= seg_sz;
|
||||
remaining = size;
|
||||
do {
|
||||
TRACE(ft_t_noise, "\n"
|
||||
KERN_INFO "remaining: %d\n"
|
||||
KERN_INFO "seg_sz : %d\n"
|
||||
KERN_INFO "segment : %d",
|
||||
remaining, seg_sz, seg_pos);
|
||||
if (remaining == seg_sz) {
|
||||
write_buf = src_buf;
|
||||
write_mode = single ? FT_WR_SINGLE : FT_WR_MULTI;
|
||||
remaining = 0;
|
||||
} else if (remaining > seg_sz) {
|
||||
write_buf = src_buf;
|
||||
write_mode = FT_WR_ASYNC; /* don't start tape */
|
||||
remaining -= seg_sz;
|
||||
} else { /* remaining < seg_sz */
|
||||
write_buf = buffer;
|
||||
memcpy(write_buf, src_buf, remaining);
|
||||
memset(&write_buf[remaining],'\0',seg_sz-remaining);
|
||||
write_mode = single ? FT_WR_SINGLE : FT_WR_MULTI;
|
||||
remaining = 0;
|
||||
}
|
||||
if ((result = ftape_write_segment(seg_pos,
|
||||
write_buf,
|
||||
write_mode)) != seg_sz) {
|
||||
TRACE(ft_t_err, "Error: "
|
||||
"Couldn't write segment %d", seg_pos);
|
||||
TRACE_EXIT result < 0 ? result : -EIO; /* bail out */
|
||||
}
|
||||
zft_written_segments ++;
|
||||
seg_sz = zft_get_seg_sz(++seg_pos);
|
||||
src_buf += result;
|
||||
} while (remaining > 0);
|
||||
if (ftape_get_status()->fti_state == writing) {
|
||||
TRACE_CATCH(ftape_loop_until_writes_done(),);
|
||||
TRACE_CATCH(ftape_abort_operation(),);
|
||||
zft_prevent_flush();
|
||||
}
|
||||
seg_pos = segment;
|
||||
src_buf = data;
|
||||
remaining = size;
|
||||
do {
|
||||
TRACE_CATCH(result = ftape_read_segment(seg_pos, buffer,
|
||||
single ? FT_RD_SINGLE
|
||||
: FT_RD_AHEAD),);
|
||||
if (memcmp(src_buf, buffer,
|
||||
remaining > result ? result : remaining) != 0) {
|
||||
TRACE_ABORT(-EIO, ft_t_err,
|
||||
"Failed to verify written segment %d",
|
||||
seg_pos);
|
||||
}
|
||||
remaining -= result;
|
||||
TRACE(ft_t_noise, "verify successful:\n"
|
||||
KERN_INFO "segment : %d\n"
|
||||
KERN_INFO "segsize : %d\n"
|
||||
KERN_INFO "remaining: %d",
|
||||
seg_pos, result, remaining);
|
||||
src_buf += seg_sz;
|
||||
seg_pos++;
|
||||
} while (remaining > 0);
|
||||
TRACE_EXIT size;
|
||||
}
|
||||
|
||||
|
||||
/* zft_erase(). implemented compression-handling
|
||||
*
|
||||
* calculate the first data-segment when using/not using compression.
|
||||
*
|
||||
* update header-segment and compression-map-segment.
|
||||
*/
|
||||
int zft_erase(void)
|
||||
{
|
||||
int result = 0;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (!zft_header_read) {
|
||||
TRACE_CATCH(zft_vmalloc_once((void **)&zft_hseg_buf,
|
||||
FT_SEGMENT_SIZE),);
|
||||
/* no need to read the vtbl and compression map */
|
||||
TRACE_CATCH(ftape_read_header_segment(zft_hseg_buf),);
|
||||
if ((zft_old_ftape =
|
||||
zft_ftape_validate_label(&zft_hseg_buf[FT_LABEL]))) {
|
||||
zft_ftape_extract_file_marks(zft_hseg_buf);
|
||||
}
|
||||
TRACE(ft_t_noise,
|
||||
"ft_first_data_segment: %d, ft_last_data_segment: %d",
|
||||
ft_first_data_segment, ft_last_data_segment);
|
||||
zft_qic113 = (ft_format_code != fmt_normal &&
|
||||
ft_format_code != fmt_1100ft &&
|
||||
ft_format_code != fmt_425ft);
|
||||
}
|
||||
if (zft_old_ftape) {
|
||||
zft_clear_ftape_file_marks();
|
||||
zft_old_ftape = 0; /* no longer old ftape */
|
||||
}
|
||||
PUT2(zft_hseg_buf, FT_CMAP_START, 0);
|
||||
zft_volume_table_changed = 1;
|
||||
zft_capacity = zft_get_capacity();
|
||||
zft_init_vtbl();
|
||||
/* the rest must be done in ftape_update_header_segments
|
||||
*/
|
||||
zft_header_read = 1;
|
||||
zft_header_changed = 1; /* force update of timestamp */
|
||||
result = zft_update_header_segments();
|
||||
|
||||
ftape_abort_operation();
|
||||
|
||||
zft_reset_position(&zft_pos);
|
||||
zft_set_flags (zft_unit);
|
||||
TRACE_EXIT result;
|
||||
}
|
||||
|
||||
unsigned int zft_get_time(void)
|
||||
{
|
||||
unsigned int date = FT_TIME_STAMP(2097, 11, 30, 23, 59, 59); /* fun */
|
||||
return date;
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
#ifndef _ZFTAPE_RW_H
|
||||
#define _ZFTAPE_RW_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 1996, 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/ftape/zftape/zftape-rw.h,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:19:09 $
|
||||
*
|
||||
* This file contains the definitions for the read and write
|
||||
* functions for the QIC-117 floppy-tape driver for Linux.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../zftape/zftape-buffers.h"
|
||||
|
||||
#define SEGMENTS_PER_TAPE (ft_segments_per_track * ft_tracks_per_tape)
|
||||
|
||||
/* QIC-113 Rev. G says that `a maximum of 63488 raw bytes may be
|
||||
* compressed into a single frame'.
|
||||
* Maybe we should stick to 32kb to make it more `beautiful'
|
||||
*/
|
||||
#define ZFT_MAX_BLK_SZ (62*1024) /* bytes */
|
||||
#if !defined(CONFIG_ZFT_DFLT_BLK_SZ)
|
||||
# define CONFIG_ZFT_DFLT_BLK_SZ (10*1024) /* bytes, default of gnu tar */
|
||||
#elif CONFIG_ZFT_DFLT_BLK_SZ == 0
|
||||
# undef CONFIG_ZFT_DFLT_BLK_SZ
|
||||
# define CONFIG_ZFT_DFLT_BLK_SZ 1
|
||||
#elif (CONFIG_ZFT_DFLT_BLK_SZ % 1024) != 0
|
||||
# error CONFIG_ZFT_DFLT_BLK_SZ must be 1 or a multiple of 1024
|
||||
#endif
|
||||
/* The *optional* compression routines need some overhead per tape
|
||||
* block for their purposes. Instead of asking the actual compression
|
||||
* implementation how much it needs, we restrict this overhead to be
|
||||
* maximal of ZFT_CMPT_OVERHEAD size. We need this for EOT
|
||||
* conditions. The tape is assumed to be logical at EOT when the
|
||||
* distance from the physical EOT is less than
|
||||
* one tape block + ZFT_CMPR_OVERHEAD
|
||||
*/
|
||||
#define ZFT_CMPR_OVERHEAD 16 /* bytes */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
zft_idle = 0,
|
||||
zft_reading,
|
||||
zft_writing,
|
||||
} zft_status_enum;
|
||||
|
||||
typedef struct /* all values measured in bytes */
|
||||
{
|
||||
int seg_pos; /* segment currently positioned at */
|
||||
int seg_byte_pos; /* offset in current segment */
|
||||
__s64 tape_pos; /* real offset from BOT */
|
||||
__s64 volume_pos; /* pos. in uncompressed data stream in
|
||||
* current volume
|
||||
*/
|
||||
} zft_position;
|
||||
|
||||
extern zft_position zft_pos;
|
||||
extern __u8 *zft_deblock_buf;
|
||||
extern __u8 *zft_hseg_buf;
|
||||
extern int zft_deblock_segment;
|
||||
extern zft_status_enum zft_io_state;
|
||||
extern int zft_header_changed;
|
||||
extern int zft_qic113; /* conform to old specs. and old zftape */
|
||||
extern int zft_use_compression;
|
||||
extern unsigned int zft_blk_sz;
|
||||
extern __s64 zft_capacity;
|
||||
extern unsigned int zft_written_segments;
|
||||
extern int zft_label_changed;
|
||||
|
||||
/* zftape-rw.c exported functions
|
||||
*/
|
||||
extern unsigned int zft_get_seg_sz(unsigned int segment);
|
||||
extern void zft_set_flags(unsigned int minor_unit);
|
||||
extern int zft_calc_seg_byte_coord(int *seg_byte_pos, __s64 tape_pos);
|
||||
extern __s64 zft_calc_tape_pos(int segment);
|
||||
extern __s64 zft_get_capacity(void);
|
||||
extern void zft_update_label(__u8 *buffer);
|
||||
extern int zft_erase(void);
|
||||
extern int zft_verify_write_segments(unsigned int segment,
|
||||
__u8 *data, size_t size, __u8 *buffer);
|
||||
extern unsigned int zft_get_time(void);
|
||||
#endif /* _ZFTAPE_RW_H */
|
||||
|
@ -1,757 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1995-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/ftape/zftape/zftape-vtbl.c,v $
|
||||
* $Revision: 1.7.6.1 $
|
||||
* $Date: 1997/11/24 13:48:31 $
|
||||
*
|
||||
* This file defines a volume table as defined in various QIC
|
||||
* standards.
|
||||
*
|
||||
* This is a minimal implementation, just allowing ordinary DOS
|
||||
* :( prgrams to identify the cartridge as used.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/zftape.h>
|
||||
#include "../zftape/zftape-init.h"
|
||||
#include "../zftape/zftape-eof.h"
|
||||
#include "../zftape/zftape-ctl.h"
|
||||
#include "../zftape/zftape-write.h"
|
||||
#include "../zftape/zftape-read.h"
|
||||
#include "../zftape/zftape-rw.h"
|
||||
#include "../zftape/zftape-vtbl.h"
|
||||
|
||||
#define ZFT_CMAP_HACK /* leave this defined to hide the compression map */
|
||||
|
||||
/*
|
||||
* global variables
|
||||
*/
|
||||
int zft_qic_mode = 1; /* use the vtbl */
|
||||
int zft_old_ftape; /* prevents old ftaped tapes to be overwritten */
|
||||
int zft_volume_table_changed; /* for write_header_segments() */
|
||||
|
||||
/*
|
||||
* private variables (only exported for inline functions)
|
||||
*/
|
||||
LIST_HEAD(zft_vtbl);
|
||||
|
||||
/* We could also allocate these dynamically when extracting the volume table
|
||||
* sizeof(zft_volinfo) is about 32 or something close to that
|
||||
*/
|
||||
static zft_volinfo tape_vtbl;
|
||||
static zft_volinfo eot_vtbl;
|
||||
static zft_volinfo *cur_vtbl;
|
||||
|
||||
static inline void zft_new_vtbl_entry(void)
|
||||
{
|
||||
struct list_head *tmp = &zft_last_vtbl->node;
|
||||
zft_volinfo *new = zft_kmalloc(sizeof(zft_volinfo));
|
||||
|
||||
list_add(&new->node, tmp);
|
||||
new->count = zft_eom_vtbl->count ++;
|
||||
}
|
||||
|
||||
void zft_free_vtbl(void)
|
||||
{
|
||||
for (;;) {
|
||||
struct list_head *tmp = zft_vtbl.prev;
|
||||
zft_volinfo *vtbl;
|
||||
|
||||
if (tmp == &zft_vtbl)
|
||||
break;
|
||||
list_del(tmp);
|
||||
vtbl = list_entry(tmp, zft_volinfo, node);
|
||||
zft_kfree(vtbl, sizeof(zft_volinfo));
|
||||
}
|
||||
INIT_LIST_HEAD(&zft_vtbl);
|
||||
cur_vtbl = NULL;
|
||||
}
|
||||
|
||||
/* initialize vtbl, called by ftape_new_cartridge()
|
||||
*/
|
||||
void zft_init_vtbl(void)
|
||||
{
|
||||
zft_volinfo *new;
|
||||
|
||||
zft_free_vtbl();
|
||||
|
||||
/* Create the two dummy vtbl entries
|
||||
*/
|
||||
new = zft_kmalloc(sizeof(zft_volinfo));
|
||||
list_add(&new->node, &zft_vtbl);
|
||||
new = zft_kmalloc(sizeof(zft_volinfo));
|
||||
list_add(&new->node, &zft_vtbl);
|
||||
zft_head_vtbl->end_seg = ft_first_data_segment;
|
||||
zft_head_vtbl->blk_sz = zft_blk_sz;
|
||||
zft_head_vtbl->count = -1;
|
||||
zft_eom_vtbl->start_seg = ft_first_data_segment + 1;
|
||||
zft_eom_vtbl->end_seg = ft_last_data_segment + 1;
|
||||
zft_eom_vtbl->blk_sz = zft_blk_sz;
|
||||
zft_eom_vtbl->count = 0;
|
||||
|
||||
/* Reset the pointer for zft_find_volume()
|
||||
*/
|
||||
cur_vtbl = zft_eom_vtbl;
|
||||
|
||||
/* initialize the dummy vtbl entries for zft_qic_mode == 0
|
||||
*/
|
||||
eot_vtbl.start_seg = ft_last_data_segment + 1;
|
||||
eot_vtbl.end_seg = ft_last_data_segment + 1;
|
||||
eot_vtbl.blk_sz = zft_blk_sz;
|
||||
eot_vtbl.count = -1;
|
||||
tape_vtbl.start_seg = ft_first_data_segment;
|
||||
tape_vtbl.end_seg = ft_last_data_segment;
|
||||
tape_vtbl.blk_sz = zft_blk_sz;
|
||||
tape_vtbl.size = zft_capacity;
|
||||
tape_vtbl.count = 0;
|
||||
}
|
||||
|
||||
/* check for a valid VTBL signature.
|
||||
*/
|
||||
static int vtbl_signature_valid(__u8 signature[4])
|
||||
{
|
||||
const char *vtbl_ids[] = VTBL_IDS; /* valid signatures */
|
||||
int j;
|
||||
|
||||
for (j = 0;
|
||||
(j < NR_ITEMS(vtbl_ids)) && (memcmp(signature, vtbl_ids[j], 4) != 0);
|
||||
j++);
|
||||
return j < NR_ITEMS(vtbl_ids);
|
||||
}
|
||||
|
||||
/* We used to store the block-size of the volume in the volume-label,
|
||||
* using the keyword "blocksize". The blocksize written to the
|
||||
* volume-label is in bytes.
|
||||
*
|
||||
* We use this now only for compatibility with old zftape version. We
|
||||
* store the blocksize directly as binary number in the vendor
|
||||
* extension part of the volume entry.
|
||||
*/
|
||||
static int check_volume_label(const char *label, int *blk_sz)
|
||||
{
|
||||
int valid_format;
|
||||
char *blocksize;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
TRACE(ft_t_noise, "called with \"%s\" / \"%s\"", label, ZFT_VOL_NAME);
|
||||
if (strncmp(label, ZFT_VOL_NAME, strlen(ZFT_VOL_NAME)) != 0) {
|
||||
*blk_sz = 1; /* smallest block size that we allow */
|
||||
valid_format = 0;
|
||||
} else {
|
||||
TRACE(ft_t_noise, "got old style zftape vtbl entry");
|
||||
/* get the default blocksize */
|
||||
/* use the kernel strstr() */
|
||||
blocksize= strstr(label, " blocksize ");
|
||||
if (blocksize) {
|
||||
blocksize += strlen(" blocksize ");
|
||||
for(*blk_sz= 0;
|
||||
*blocksize >= '0' && *blocksize <= '9';
|
||||
blocksize++) {
|
||||
*blk_sz *= 10;
|
||||
*blk_sz += *blocksize - '0';
|
||||
}
|
||||
if (*blk_sz > ZFT_MAX_BLK_SZ) {
|
||||
*blk_sz= 1;
|
||||
valid_format= 0;
|
||||
} else {
|
||||
valid_format = 1;
|
||||
}
|
||||
} else {
|
||||
*blk_sz= 1;
|
||||
valid_format= 0;
|
||||
}
|
||||
}
|
||||
TRACE_EXIT valid_format;
|
||||
}
|
||||
|
||||
/* check for a zftape volume
|
||||
*/
|
||||
static int check_volume(__u8 *entry, zft_volinfo *volume)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if(strncmp(&entry[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG,
|
||||
strlen(ZFTAPE_SIG)) == 0) {
|
||||
TRACE(ft_t_noise, "got new style zftape vtbl entry");
|
||||
volume->blk_sz = GET2(entry, VTBL_EXT+EXT_ZFTAPE_BLKSZ);
|
||||
volume->qic113 = entry[VTBL_EXT+EXT_ZFTAPE_QIC113];
|
||||
TRACE_EXIT 1;
|
||||
} else {
|
||||
TRACE_EXIT check_volume_label(&entry[VTBL_DESC], &volume->blk_sz);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* create zftape specific vtbl entry, the volume bounds are inserted
|
||||
* in the calling function, zft_create_volume_headers()
|
||||
*/
|
||||
static void create_zft_volume(__u8 *entry, zft_volinfo *vtbl)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
memset(entry, 0, VTBL_SIZE);
|
||||
memcpy(&entry[VTBL_SIG], VTBL_ID, 4);
|
||||
sprintf(&entry[VTBL_DESC], ZFT_VOL_NAME" %03d", vtbl->count);
|
||||
entry[VTBL_FLAGS] = (VTBL_FL_NOT_VERIFIED | VTBL_FL_SEG_SPANNING);
|
||||
entry[VTBL_M_NO] = 1; /* multi_cartridge_count */
|
||||
strcpy(&entry[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG);
|
||||
PUT2(entry, VTBL_EXT+EXT_ZFTAPE_BLKSZ, vtbl->blk_sz);
|
||||
if (zft_qic113) {
|
||||
PUT8(entry, VTBL_DATA_SIZE, vtbl->size);
|
||||
entry[VTBL_CMPR] = VTBL_CMPR_UNREG;
|
||||
if (vtbl->use_compression) { /* use compression: */
|
||||
entry[VTBL_CMPR] |= VTBL_CMPR_USED;
|
||||
}
|
||||
entry[VTBL_EXT+EXT_ZFTAPE_QIC113] = 1;
|
||||
} else {
|
||||
PUT4(entry, VTBL_DATA_SIZE, vtbl->size);
|
||||
entry[VTBL_K_CMPR] = VTBL_CMPR_UNREG;
|
||||
if (vtbl->use_compression) { /* use compression: */
|
||||
entry[VTBL_K_CMPR] |= VTBL_CMPR_USED;
|
||||
}
|
||||
}
|
||||
if (ft_format_code == fmt_big) {
|
||||
/* SCSI like vtbl, store the number of used
|
||||
* segments as 4 byte value
|
||||
*/
|
||||
PUT4(entry, VTBL_SCSI_SEGS, vtbl->end_seg-vtbl->start_seg + 1);
|
||||
} else {
|
||||
/* normal, QIC-80MC like vtbl
|
||||
*/
|
||||
PUT2(entry, VTBL_START, vtbl->start_seg);
|
||||
PUT2(entry, VTBL_END, vtbl->end_seg);
|
||||
}
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
/* this one creates the volume headers for each volume. It is assumed
|
||||
* that buffer already contains the old volume-table, so that vtbl
|
||||
* entries without the zft_volume flag set can savely be ignored.
|
||||
*/
|
||||
static void zft_create_volume_headers(__u8 *buffer)
|
||||
{
|
||||
__u8 *entry;
|
||||
struct list_head *tmp;
|
||||
zft_volinfo *vtbl;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
#ifdef ZFT_CMAP_HACK
|
||||
if((strncmp(&buffer[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG,
|
||||
strlen(ZFTAPE_SIG)) == 0) &&
|
||||
buffer[VTBL_EXT+EXT_ZFTAPE_CMAP] != 0) {
|
||||
TRACE(ft_t_noise, "deleting cmap volume");
|
||||
memmove(buffer, buffer + VTBL_SIZE,
|
||||
FT_SEGMENT_SIZE - VTBL_SIZE);
|
||||
}
|
||||
#endif
|
||||
entry = buffer;
|
||||
for (tmp = zft_head_vtbl->node.next;
|
||||
tmp != &zft_eom_vtbl->node;
|
||||
tmp = tmp->next) {
|
||||
vtbl = list_entry(tmp, zft_volinfo, node);
|
||||
/* we now fill in the values only for newly created volumes.
|
||||
*/
|
||||
if (vtbl->new_volume) {
|
||||
create_zft_volume(entry, vtbl);
|
||||
vtbl->new_volume = 0; /* clear the flag */
|
||||
}
|
||||
|
||||
DUMP_VOLINFO(ft_t_noise, &entry[VTBL_DESC], vtbl);
|
||||
entry += VTBL_SIZE;
|
||||
}
|
||||
memset(entry, 0, FT_SEGMENT_SIZE - zft_eom_vtbl->count * VTBL_SIZE);
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
/* write volume table to tape. Calls zft_create_volume_headers()
|
||||
*/
|
||||
int zft_update_volume_table(unsigned int segment)
|
||||
{
|
||||
int result = 0;
|
||||
__u8 *verify_buf = NULL;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
TRACE_CATCH(result = ftape_read_segment(ft_first_data_segment,
|
||||
zft_deblock_buf,
|
||||
FT_RD_SINGLE),);
|
||||
zft_create_volume_headers(zft_deblock_buf);
|
||||
TRACE(ft_t_noise, "writing volume table segment %d", segment);
|
||||
if (zft_vmalloc_once(&verify_buf, FT_SEGMENT_SIZE) == 0) {
|
||||
TRACE_CATCH(zft_verify_write_segments(segment,
|
||||
zft_deblock_buf, result,
|
||||
verify_buf),
|
||||
zft_vfree(&verify_buf, FT_SEGMENT_SIZE));
|
||||
zft_vfree(&verify_buf, FT_SEGMENT_SIZE);
|
||||
} else {
|
||||
TRACE_CATCH(ftape_write_segment(segment, zft_deblock_buf,
|
||||
FT_WR_SINGLE),);
|
||||
}
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
/* non zftape volumes are handled in raw mode. Thus we need to
|
||||
* calculate the raw amount of data contained in those segments.
|
||||
*/
|
||||
static void extract_alien_volume(__u8 *entry, zft_volinfo *vtbl)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
vtbl->size = (zft_calc_tape_pos(zft_last_vtbl->end_seg+1) -
|
||||
zft_calc_tape_pos(zft_last_vtbl->start_seg));
|
||||
vtbl->use_compression = 0;
|
||||
vtbl->qic113 = zft_qic113;
|
||||
if (vtbl->qic113) {
|
||||
TRACE(ft_t_noise,
|
||||
"Fake alien volume's size from " LL_X " to " LL_X,
|
||||
LL(GET8(entry, VTBL_DATA_SIZE)), LL(vtbl->size));
|
||||
} else {
|
||||
TRACE(ft_t_noise,
|
||||
"Fake alien volume's size from %d to " LL_X,
|
||||
(int)GET4(entry, VTBL_DATA_SIZE), LL(vtbl->size));
|
||||
}
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
|
||||
/* extract an zftape specific volume
|
||||
*/
|
||||
static void extract_zft_volume(__u8 *entry, zft_volinfo *vtbl)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (vtbl->qic113) {
|
||||
vtbl->size = GET8(entry, VTBL_DATA_SIZE);
|
||||
vtbl->use_compression =
|
||||
(entry[VTBL_CMPR] & VTBL_CMPR_USED) != 0;
|
||||
} else {
|
||||
vtbl->size = GET4(entry, VTBL_DATA_SIZE);
|
||||
if (entry[VTBL_K_CMPR] & VTBL_CMPR_UNREG) {
|
||||
vtbl->use_compression =
|
||||
(entry[VTBL_K_CMPR] & VTBL_CMPR_USED) != 0;
|
||||
} else if (entry[VTBL_CMPR] & VTBL_CMPR_UNREG) {
|
||||
vtbl->use_compression =
|
||||
(entry[VTBL_CMPR] & VTBL_CMPR_USED) != 0;
|
||||
} else {
|
||||
TRACE(ft_t_warn, "Geeh! There is something wrong:\n"
|
||||
KERN_INFO "QIC compression (Rev = K): %x\n"
|
||||
KERN_INFO "QIC compression (Rev > K): %x",
|
||||
entry[VTBL_K_CMPR], entry[VTBL_CMPR]);
|
||||
}
|
||||
}
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
/* extract the volume table from buffer. "buffer" must already contain
|
||||
* the vtbl-segment
|
||||
*/
|
||||
int zft_extract_volume_headers(__u8 *buffer)
|
||||
{
|
||||
__u8 *entry;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
zft_init_vtbl();
|
||||
entry = buffer;
|
||||
#ifdef ZFT_CMAP_HACK
|
||||
if ((strncmp(&entry[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG,
|
||||
strlen(ZFTAPE_SIG)) == 0) &&
|
||||
entry[VTBL_EXT+EXT_ZFTAPE_CMAP] != 0) {
|
||||
TRACE(ft_t_noise, "ignoring cmap volume");
|
||||
entry += VTBL_SIZE;
|
||||
}
|
||||
#endif
|
||||
/* the end of the vtbl is indicated by an invalid signature
|
||||
*/
|
||||
while (vtbl_signature_valid(&entry[VTBL_SIG]) &&
|
||||
(entry - buffer) < FT_SEGMENT_SIZE) {
|
||||
zft_new_vtbl_entry();
|
||||
if (ft_format_code == fmt_big) {
|
||||
/* SCSI like vtbl, stores only the number of
|
||||
* segments used
|
||||
*/
|
||||
unsigned int num_segments= GET4(entry, VTBL_SCSI_SEGS);
|
||||
zft_last_vtbl->start_seg = zft_eom_vtbl->start_seg;
|
||||
zft_last_vtbl->end_seg =
|
||||
zft_last_vtbl->start_seg + num_segments - 1;
|
||||
} else {
|
||||
/* `normal', QIC-80 like vtbl
|
||||
*/
|
||||
zft_last_vtbl->start_seg = GET2(entry, VTBL_START);
|
||||
zft_last_vtbl->end_seg = GET2(entry, VTBL_END);
|
||||
}
|
||||
zft_eom_vtbl->start_seg = zft_last_vtbl->end_seg + 1;
|
||||
/* check if we created this volume and get the
|
||||
* blk_sz
|
||||
*/
|
||||
zft_last_vtbl->zft_volume = check_volume(entry, zft_last_vtbl);
|
||||
if (zft_last_vtbl->zft_volume == 0) {
|
||||
extract_alien_volume(entry, zft_last_vtbl);
|
||||
} else {
|
||||
extract_zft_volume(entry, zft_last_vtbl);
|
||||
}
|
||||
DUMP_VOLINFO(ft_t_noise, &entry[VTBL_DESC], zft_last_vtbl);
|
||||
entry +=VTBL_SIZE;
|
||||
}
|
||||
#if 0
|
||||
/*
|
||||
* undefine to test end of tape handling
|
||||
*/
|
||||
zft_new_vtbl_entry();
|
||||
zft_last_vtbl->start_seg = zft_eom_vtbl->start_seg;
|
||||
zft_last_vtbl->end_seg = ft_last_data_segment - 10;
|
||||
zft_last_vtbl->blk_sz = zft_blk_sz;
|
||||
zft_last_vtbl->zft_volume = 1;
|
||||
zft_last_vtbl->qic113 = zft_qic113;
|
||||
zft_last_vtbl->size = (zft_calc_tape_pos(zft_last_vtbl->end_seg+1)
|
||||
- zft_calc_tape_pos(zft_last_vtbl->start_seg));
|
||||
#endif
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
/* this functions translates the failed_sector_log, misused as
|
||||
* EOF-marker list, into a virtual volume table. The table mustn't be
|
||||
* written to tape, because this would occupy the first data segment,
|
||||
* which should be the volume table, but is actually the first segment
|
||||
* that is filled with data (when using standard ftape). We assume,
|
||||
* that we get a non-empty failed_sector_log.
|
||||
*/
|
||||
int zft_fake_volume_headers (eof_mark_union *eof_map, int num_failed_sectors)
|
||||
{
|
||||
unsigned int segment, sector;
|
||||
int have_eom = 0;
|
||||
int vol_no;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if ((num_failed_sectors >= 2) &&
|
||||
(GET2(&eof_map[num_failed_sectors - 1].mark.segment, 0)
|
||||
==
|
||||
GET2(&eof_map[num_failed_sectors - 2].mark.segment, 0) + 1) &&
|
||||
(GET2(&eof_map[num_failed_sectors - 1].mark.date, 0) == 1)) {
|
||||
/* this should be eom. We keep the remainder of the
|
||||
* tape as another volume.
|
||||
*/
|
||||
have_eom = 1;
|
||||
}
|
||||
zft_init_vtbl();
|
||||
zft_eom_vtbl->start_seg = ft_first_data_segment;
|
||||
for(vol_no = 0; vol_no < num_failed_sectors - have_eom; vol_no ++) {
|
||||
zft_new_vtbl_entry();
|
||||
|
||||
segment = GET2(&eof_map[vol_no].mark.segment, 0);
|
||||
sector = GET2(&eof_map[vol_no].mark.date, 0);
|
||||
|
||||
zft_last_vtbl->start_seg = zft_eom_vtbl->start_seg;
|
||||
zft_last_vtbl->end_seg = segment;
|
||||
zft_eom_vtbl->start_seg = segment + 1;
|
||||
zft_last_vtbl->blk_sz = 1;
|
||||
zft_last_vtbl->size =
|
||||
(zft_calc_tape_pos(zft_last_vtbl->end_seg)
|
||||
- zft_calc_tape_pos(zft_last_vtbl->start_seg)
|
||||
+ (sector-1) * FT_SECTOR_SIZE);
|
||||
TRACE(ft_t_noise,
|
||||
"failed sector log: segment: %d, sector: %d",
|
||||
segment, sector);
|
||||
DUMP_VOLINFO(ft_t_noise, "Faked volume", zft_last_vtbl);
|
||||
}
|
||||
if (!have_eom) {
|
||||
zft_new_vtbl_entry();
|
||||
zft_last_vtbl->start_seg = zft_eom_vtbl->start_seg;
|
||||
zft_last_vtbl->end_seg = ft_last_data_segment;
|
||||
zft_eom_vtbl->start_seg = ft_last_data_segment + 1;
|
||||
zft_last_vtbl->size = zft_capacity;
|
||||
zft_last_vtbl->size -= zft_calc_tape_pos(zft_last_vtbl->start_seg);
|
||||
zft_last_vtbl->blk_sz = 1;
|
||||
DUMP_VOLINFO(ft_t_noise, "Faked volume",zft_last_vtbl);
|
||||
}
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
/* update the internal volume table
|
||||
*
|
||||
* if before start of last volume: erase all following volumes if
|
||||
* inside a volume: set end of volume to infinity
|
||||
*
|
||||
* this function is intended to be called every time _ftape_write() is
|
||||
* called
|
||||
*
|
||||
* return: 0 if no new volume was created, 1 if a new volume was
|
||||
* created
|
||||
*
|
||||
* NOTE: we don't need to check for zft_mode as ftape_write() does
|
||||
* that already. This function gets never called without accessing
|
||||
* zftape via the *qft* devices
|
||||
*/
|
||||
|
||||
int zft_open_volume(zft_position *pos, int blk_sz, int use_compression)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (!zft_qic_mode) {
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
if (zft_tape_at_lbot(pos)) {
|
||||
zft_init_vtbl();
|
||||
if(zft_old_ftape) {
|
||||
/* clear old ftape's eof marks */
|
||||
zft_clear_ftape_file_marks();
|
||||
zft_old_ftape = 0; /* no longer old ftape */
|
||||
}
|
||||
zft_reset_position(pos);
|
||||
}
|
||||
if (pos->seg_pos != zft_last_vtbl->end_seg + 1) {
|
||||
TRACE_ABORT(-EIO, ft_t_bug,
|
||||
"BUG: seg_pos: %d, zft_last_vtbl->end_seg: %d",
|
||||
pos->seg_pos, zft_last_vtbl->end_seg);
|
||||
}
|
||||
TRACE(ft_t_noise, "create new volume");
|
||||
if (zft_eom_vtbl->count >= ZFT_MAX_VOLUMES) {
|
||||
TRACE_ABORT(-ENOSPC, ft_t_err,
|
||||
"Error: maxmimal number of volumes exhausted "
|
||||
"(maxmimum is %d)", ZFT_MAX_VOLUMES);
|
||||
}
|
||||
zft_new_vtbl_entry();
|
||||
pos->volume_pos = pos->seg_byte_pos = 0;
|
||||
zft_last_vtbl->start_seg = pos->seg_pos;
|
||||
zft_last_vtbl->end_seg = ft_last_data_segment; /* infinity */
|
||||
zft_last_vtbl->blk_sz = blk_sz;
|
||||
zft_last_vtbl->size = zft_capacity;
|
||||
zft_last_vtbl->zft_volume = 1;
|
||||
zft_last_vtbl->use_compression = use_compression;
|
||||
zft_last_vtbl->qic113 = zft_qic113;
|
||||
zft_last_vtbl->new_volume = 1;
|
||||
zft_last_vtbl->open = 1;
|
||||
zft_volume_table_changed = 1;
|
||||
zft_eom_vtbl->start_seg = ft_last_data_segment + 1;
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
/* perform mtfsf, mtbsf, not allowed without zft_qic_mode
|
||||
*/
|
||||
int zft_skip_volumes(int count, zft_position *pos)
|
||||
{
|
||||
const zft_volinfo *vtbl;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
TRACE(ft_t_noise, "count: %d", count);
|
||||
|
||||
vtbl= zft_find_volume(pos->seg_pos);
|
||||
while (count > 0 && vtbl != zft_eom_vtbl) {
|
||||
vtbl = list_entry(vtbl->node.next, zft_volinfo, node);
|
||||
count --;
|
||||
}
|
||||
while (count < 0 && vtbl != zft_first_vtbl) {
|
||||
vtbl = list_entry(vtbl->node.prev, zft_volinfo, node);
|
||||
count ++;
|
||||
}
|
||||
pos->seg_pos = vtbl->start_seg;
|
||||
pos->seg_byte_pos = 0;
|
||||
pos->volume_pos = 0;
|
||||
pos->tape_pos = zft_calc_tape_pos(pos->seg_pos);
|
||||
zft_just_before_eof = vtbl->size == 0;
|
||||
if (zft_cmpr_ops) {
|
||||
(*zft_cmpr_ops->reset)();
|
||||
}
|
||||
zft_deblock_segment = -1; /* no need to keep cache */
|
||||
TRACE(ft_t_noise, "repositioning to:\n"
|
||||
KERN_INFO "zft_seg_pos : %d\n"
|
||||
KERN_INFO "zft_seg_byte_pos : %d\n"
|
||||
KERN_INFO "zft_tape_pos : " LL_X "\n"
|
||||
KERN_INFO "zft_volume_pos : " LL_X "\n"
|
||||
KERN_INFO "file number : %d",
|
||||
pos->seg_pos, pos->seg_byte_pos,
|
||||
LL(pos->tape_pos), LL(pos->volume_pos), vtbl->count);
|
||||
zft_resid = count < 0 ? -count : count;
|
||||
TRACE_EXIT zft_resid ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
/* the following simply returns the raw data position of the EOM
|
||||
* marker, MTIOCSIZE ioctl
|
||||
*/
|
||||
__s64 zft_get_eom_pos(void)
|
||||
{
|
||||
if (zft_qic_mode) {
|
||||
return zft_calc_tape_pos(zft_eom_vtbl->start_seg);
|
||||
} else {
|
||||
/* there is only one volume in raw mode */
|
||||
return zft_capacity;
|
||||
}
|
||||
}
|
||||
|
||||
/* skip to eom, used for MTEOM
|
||||
*/
|
||||
void zft_skip_to_eom(zft_position *pos)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
pos->seg_pos = zft_eom_vtbl->start_seg;
|
||||
pos->seg_byte_pos =
|
||||
pos->volume_pos =
|
||||
zft_just_before_eof = 0;
|
||||
pos->tape_pos = zft_calc_tape_pos(pos->seg_pos);
|
||||
TRACE(ft_t_noise, "ftape positioned to segment %d, data pos " LL_X,
|
||||
pos->seg_pos, LL(pos->tape_pos));
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
/* write an EOF-marker by setting zft_last_vtbl->end_seg to seg_pos.
|
||||
* NOTE: this function assumes that zft_last_vtbl points to a valid
|
||||
* vtbl entry
|
||||
*
|
||||
* NOTE: this routine always positions before the EOF marker
|
||||
*/
|
||||
int zft_close_volume(zft_position *pos)
|
||||
{
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
if (zft_vtbl_empty || !zft_last_vtbl->open) { /* should not happen */
|
||||
TRACE(ft_t_noise, "There are no volumes to finish");
|
||||
TRACE_EXIT -EIO;
|
||||
}
|
||||
if (pos->seg_byte_pos == 0 &&
|
||||
pos->seg_pos != zft_last_vtbl->start_seg) {
|
||||
pos->seg_pos --;
|
||||
pos->seg_byte_pos = zft_get_seg_sz(pos->seg_pos);
|
||||
}
|
||||
zft_last_vtbl->end_seg = pos->seg_pos;
|
||||
zft_last_vtbl->size = pos->volume_pos;
|
||||
zft_volume_table_changed = 1;
|
||||
zft_just_before_eof = 1;
|
||||
zft_eom_vtbl->start_seg = zft_last_vtbl->end_seg + 1;
|
||||
zft_last_vtbl->open = 0; /* closed */
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
/* write count file-marks at current position.
|
||||
*
|
||||
* The tape is positioned after the eof-marker, that is at byte 0 of
|
||||
* the segment following the eof-marker
|
||||
*
|
||||
* this function is only allowed in zft_qic_mode
|
||||
*
|
||||
* Only allowed when tape is at BOT or EOD.
|
||||
*/
|
||||
int zft_weof(unsigned int count, zft_position *pos)
|
||||
{
|
||||
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (!count) { /* write zero EOF marks should be a real no-op */
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
zft_volume_table_changed = 1;
|
||||
if (zft_tape_at_lbot(pos)) {
|
||||
zft_init_vtbl();
|
||||
if(zft_old_ftape) {
|
||||
/* clear old ftape's eof marks */
|
||||
zft_clear_ftape_file_marks();
|
||||
zft_old_ftape = 0; /* no longer old ftape */
|
||||
}
|
||||
}
|
||||
if (zft_last_vtbl->open) {
|
||||
zft_close_volume(pos);
|
||||
zft_move_past_eof(pos);
|
||||
count --;
|
||||
}
|
||||
/* now it's easy, just append eof-marks, that is empty
|
||||
* volumes, to the end of the already recorded media.
|
||||
*/
|
||||
while (count > 0 &&
|
||||
pos->seg_pos <= ft_last_data_segment &&
|
||||
zft_eom_vtbl->count < ZFT_MAX_VOLUMES) {
|
||||
TRACE(ft_t_noise,
|
||||
"Writing zero sized file at segment %d", pos->seg_pos);
|
||||
zft_new_vtbl_entry();
|
||||
zft_last_vtbl->start_seg = pos->seg_pos;
|
||||
zft_last_vtbl->end_seg = pos->seg_pos;
|
||||
zft_last_vtbl->size = 0;
|
||||
zft_last_vtbl->blk_sz = zft_blk_sz;
|
||||
zft_last_vtbl->zft_volume = 1;
|
||||
zft_last_vtbl->use_compression = 0;
|
||||
pos->tape_pos += zft_get_seg_sz(pos->seg_pos);
|
||||
zft_eom_vtbl->start_seg = ++ pos->seg_pos;
|
||||
count --;
|
||||
}
|
||||
if (count > 0) {
|
||||
/* there are two possibilities: end of tape, or the
|
||||
* maximum number of files is exhausted.
|
||||
*/
|
||||
zft_resid = count;
|
||||
TRACE(ft_t_noise,"Number of marks NOT written: %d", zft_resid);
|
||||
if (zft_eom_vtbl->count == ZFT_MAX_VOLUMES) {
|
||||
TRACE_ABORT(-EINVAL, ft_t_warn,
|
||||
"maximum allowed number of files "
|
||||
"exhausted: %d", ZFT_MAX_VOLUMES);
|
||||
} else {
|
||||
TRACE_ABORT(-ENOSPC,
|
||||
ft_t_noise, "reached end of tape");
|
||||
}
|
||||
}
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
const zft_volinfo *zft_find_volume(unsigned int seg_pos)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
TRACE(ft_t_any, "called with seg_pos %d",seg_pos);
|
||||
if (!zft_qic_mode) {
|
||||
if (seg_pos > ft_last_data_segment) {
|
||||
TRACE_EXIT &eot_vtbl;
|
||||
}
|
||||
tape_vtbl.blk_sz = zft_blk_sz;
|
||||
TRACE_EXIT &tape_vtbl;
|
||||
}
|
||||
if (seg_pos < zft_first_vtbl->start_seg) {
|
||||
TRACE_EXIT (cur_vtbl = zft_first_vtbl);
|
||||
}
|
||||
while (seg_pos > cur_vtbl->end_seg) {
|
||||
cur_vtbl = list_entry(cur_vtbl->node.next, zft_volinfo, node);
|
||||
TRACE(ft_t_noise, "%d - %d", cur_vtbl->start_seg, cur_vtbl->end_seg);
|
||||
}
|
||||
while (seg_pos < cur_vtbl->start_seg) {
|
||||
cur_vtbl = list_entry(cur_vtbl->node.prev, zft_volinfo, node);
|
||||
TRACE(ft_t_noise, "%d - %d", cur_vtbl->start_seg, cur_vtbl->end_seg);
|
||||
}
|
||||
if (seg_pos > cur_vtbl->end_seg || seg_pos < cur_vtbl->start_seg) {
|
||||
TRACE(ft_t_bug, "This cannot happen");
|
||||
}
|
||||
DUMP_VOLINFO(ft_t_noise, "", cur_vtbl);
|
||||
TRACE_EXIT cur_vtbl;
|
||||
}
|
||||
|
||||
/* this function really assumes that we are just before eof
|
||||
*/
|
||||
void zft_move_past_eof(zft_position *pos)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
TRACE(ft_t_noise, "old seg. pos: %d", pos->seg_pos);
|
||||
pos->tape_pos += zft_get_seg_sz(pos->seg_pos++) - pos->seg_byte_pos;
|
||||
pos->seg_byte_pos = 0;
|
||||
pos->volume_pos = 0;
|
||||
if (zft_cmpr_ops) {
|
||||
(*zft_cmpr_ops->reset)();
|
||||
}
|
||||
zft_just_before_eof = 0;
|
||||
zft_deblock_segment = -1; /* no need to cache it anymore */
|
||||
TRACE(ft_t_noise, "new seg. pos: %d", pos->seg_pos);
|
||||
TRACE_EXIT;
|
||||
}
|
@ -1,227 +0,0 @@
|
||||
#ifndef _ZFTAPE_VTBL_H
|
||||
#define _ZFTAPE_VTBL_H
|
||||
|
||||
/*
|
||||
* Copyright (c) 1995-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/ftape/zftape/zftape-vtbl.h,v $
|
||||
* $Revision: 1.3 $
|
||||
* $Date: 1997/10/28 14:30:09 $
|
||||
*
|
||||
* This file defines a volume table as defined in the QIC-80
|
||||
* development standards.
|
||||
*/
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
#include "../lowlevel/ftape-tracing.h"
|
||||
|
||||
#include "../zftape/zftape-eof.h"
|
||||
#include "../zftape/zftape-ctl.h"
|
||||
#include "../zftape/zftape-rw.h"
|
||||
|
||||
#define VTBL_SIZE 128 /* bytes */
|
||||
|
||||
/* The following are offsets in the vtbl. */
|
||||
#define VTBL_SIG 0
|
||||
#define VTBL_START 4
|
||||
#define VTBL_END 6
|
||||
#define VTBL_DESC 8
|
||||
#define VTBL_DATE 52
|
||||
#define VTBL_FLAGS 56
|
||||
#define VTBL_FL_VENDOR_SPECIFIC (1<<0)
|
||||
#define VTBL_FL_MUTLI_CARTRIDGE (1<<1)
|
||||
#define VTBL_FL_NOT_VERIFIED (1<<2)
|
||||
#define VTBL_FL_REDIR_INHIBIT (1<<3)
|
||||
#define VTBL_FL_SEG_SPANNING (1<<4)
|
||||
#define VTBL_FL_DIRECTORY_LAST (1<<5)
|
||||
#define VTBL_FL_RESERVED_6 (1<<6)
|
||||
#define VTBL_FL_RESERVED_7 (1<<7)
|
||||
#define VTBL_M_NO 57
|
||||
#define VTBL_EXT 58
|
||||
#define EXT_ZFTAPE_SIG 0
|
||||
#define EXT_ZFTAPE_BLKSZ 10
|
||||
#define EXT_ZFTAPE_CMAP 12
|
||||
#define EXT_ZFTAPE_QIC113 13
|
||||
#define VTBL_PWD 84
|
||||
#define VTBL_DIR_SIZE 92
|
||||
#define VTBL_DATA_SIZE 96
|
||||
#define VTBL_OS_VERSION 104
|
||||
#define VTBL_SRC_DRIVE 106
|
||||
#define VTBL_DEV 122
|
||||
#define VTBL_RESERVED_1 123
|
||||
#define VTBL_CMPR 124
|
||||
#define VTBL_CMPR_UNREG 0x3f
|
||||
#define VTBL_CMPR_USED 0x80
|
||||
#define VTBL_FMT 125
|
||||
#define VTBL_RESERVED_2 126
|
||||
#define VTBL_RESERVED_3 127
|
||||
/* compatibility with pre revision K */
|
||||
#define VTBL_K_CMPR 120
|
||||
|
||||
/* the next is used by QIC-3020 tapes with format code 6 (>2^16
|
||||
* segments) It is specified in QIC-113, Rev. G, Section 5 (SCSI
|
||||
* volume table). The difference is simply, that we only store the
|
||||
* number of segments used, not the starting segment.
|
||||
*/
|
||||
#define VTBL_SCSI_SEGS 4 /* is a 4 byte value */
|
||||
|
||||
/* one vtbl is 128 bytes, that results in a maximum number of
|
||||
* 29*1024/128 = 232 volumes.
|
||||
*/
|
||||
#define ZFT_MAX_VOLUMES (FT_SEGMENT_SIZE/VTBL_SIZE)
|
||||
#define VTBL_ID "VTBL"
|
||||
#define VTBL_IDS { VTBL_ID, "XTBL", "UTID", "EXVT" } /* other valid ids */
|
||||
#define ZFT_VOL_NAME "zftape volume" /* volume label used by me */
|
||||
#define ZFTAPE_SIG "LINUX ZFT"
|
||||
|
||||
/* global variables
|
||||
*/
|
||||
typedef struct zft_internal_vtbl
|
||||
{
|
||||
struct list_head node;
|
||||
int count;
|
||||
unsigned int start_seg; /* 32 bits are enough for now */
|
||||
unsigned int end_seg; /* 32 bits are enough for now */
|
||||
__s64 size; /* uncompressed size */
|
||||
unsigned int blk_sz; /* block size for this volume */
|
||||
unsigned int zft_volume :1; /* zftape created this volume */
|
||||
unsigned int use_compression:1; /* compressed volume */
|
||||
unsigned int qic113 :1; /* layout of compressed block
|
||||
* info and vtbl conforms to
|
||||
* QIC-113, Rev. G
|
||||
*/
|
||||
unsigned int new_volume :1; /* it was created by us, this
|
||||
* run. this allows the
|
||||
* fields that aren't really
|
||||
* used by zftape to be filled
|
||||
* in by some user level
|
||||
* program.
|
||||
*/
|
||||
unsigned int open :1; /* just in progress of being
|
||||
* written
|
||||
*/
|
||||
} zft_volinfo;
|
||||
|
||||
extern struct list_head zft_vtbl;
|
||||
#define zft_head_vtbl list_entry(zft_vtbl.next, zft_volinfo, node)
|
||||
#define zft_eom_vtbl list_entry(zft_vtbl.prev, zft_volinfo, node)
|
||||
#define zft_last_vtbl list_entry(zft_eom_vtbl->node.prev, zft_volinfo, node)
|
||||
#define zft_first_vtbl list_entry(zft_head_vtbl->node.next, zft_volinfo, node)
|
||||
#define zft_vtbl_empty (zft_eom_vtbl->node.prev == &zft_head_vtbl->node)
|
||||
|
||||
#define DUMP_VOLINFO(level, desc, info) \
|
||||
{ \
|
||||
char tmp[21]; \
|
||||
strlcpy(tmp, desc, sizeof(tmp)); \
|
||||
TRACE(level, "Volume %d:\n" \
|
||||
KERN_INFO "description : %s\n" \
|
||||
KERN_INFO "first segment: %d\n" \
|
||||
KERN_INFO "last segment: %d\n" \
|
||||
KERN_INFO "size : " LL_X "\n" \
|
||||
KERN_INFO "block size : %d\n" \
|
||||
KERN_INFO "compression : %d\n" \
|
||||
KERN_INFO "zftape volume: %d\n" \
|
||||
KERN_INFO "QIC-113 conf.: %d", \
|
||||
(info)->count, tmp, (info)->start_seg, (info)->end_seg, \
|
||||
LL((info)->size), (info)->blk_sz, \
|
||||
(info)->use_compression != 0, (info)->zft_volume != 0, \
|
||||
(info)->qic113 != 0); \
|
||||
}
|
||||
|
||||
extern int zft_qic_mode;
|
||||
extern int zft_old_ftape;
|
||||
extern int zft_volume_table_changed;
|
||||
|
||||
/* exported functions */
|
||||
extern void zft_init_vtbl (void);
|
||||
extern void zft_free_vtbl (void);
|
||||
extern int zft_extract_volume_headers(__u8 *buffer);
|
||||
extern int zft_update_volume_table (unsigned int segment);
|
||||
extern int zft_open_volume (zft_position *pos,
|
||||
int blk_sz, int use_compression);
|
||||
extern int zft_close_volume (zft_position *pos);
|
||||
extern const zft_volinfo *zft_find_volume(unsigned int seg_pos);
|
||||
extern int zft_skip_volumes (int count, zft_position *pos);
|
||||
extern __s64 zft_get_eom_pos (void);
|
||||
extern void zft_skip_to_eom (zft_position *pos);
|
||||
extern int zft_fake_volume_headers (eof_mark_union *eof_map,
|
||||
int num_failed_sectors);
|
||||
extern int zft_weof (unsigned int count, zft_position *pos);
|
||||
extern void zft_move_past_eof (zft_position *pos);
|
||||
|
||||
static inline int zft_tape_at_eod (const zft_position *pos);
|
||||
static inline int zft_tape_at_lbot (const zft_position *pos);
|
||||
static inline void zft_position_before_eof (zft_position *pos,
|
||||
const zft_volinfo *volume);
|
||||
static inline __s64 zft_check_for_eof(const zft_volinfo *vtbl,
|
||||
const zft_position *pos);
|
||||
|
||||
/* this function decrements the zft_seg_pos counter if we are right
|
||||
* at the beginning of a segment. This is to handle fsfm/bsfm -- we
|
||||
* need to position before the eof mark. NOTE: zft_tape_pos is not
|
||||
* changed
|
||||
*/
|
||||
static inline void zft_position_before_eof(zft_position *pos,
|
||||
const zft_volinfo *volume)
|
||||
{
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (pos->seg_pos == volume->end_seg + 1 && pos->seg_byte_pos == 0) {
|
||||
pos->seg_pos --;
|
||||
pos->seg_byte_pos = zft_get_seg_sz(pos->seg_pos);
|
||||
}
|
||||
TRACE_EXIT;
|
||||
}
|
||||
|
||||
/* Mmmh. Is the position at the end of the last volume, that is right
|
||||
* before the last EOF mark also logical an EOD condition?
|
||||
*/
|
||||
static inline int zft_tape_at_eod(const zft_position *pos)
|
||||
{
|
||||
TRACE_FUN(ft_t_any);
|
||||
|
||||
if (zft_qic_mode) {
|
||||
TRACE_EXIT (pos->seg_pos >= zft_eom_vtbl->start_seg ||
|
||||
zft_last_vtbl->open);
|
||||
} else {
|
||||
TRACE_EXIT pos->seg_pos > ft_last_data_segment;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int zft_tape_at_lbot(const zft_position *pos)
|
||||
{
|
||||
if (zft_qic_mode) {
|
||||
return (pos->seg_pos <= zft_first_vtbl->start_seg &&
|
||||
pos->volume_pos == 0);
|
||||
} else {
|
||||
return (pos->seg_pos <= ft_first_data_segment &&
|
||||
pos->volume_pos == 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* This one checks for EOF. return remaing space (may be negative)
|
||||
*/
|
||||
static inline __s64 zft_check_for_eof(const zft_volinfo *vtbl,
|
||||
const zft_position *pos)
|
||||
{
|
||||
return (__s64)(vtbl->size - pos->volume_pos);
|
||||
}
|
||||
|
||||
#endif /* _ZFTAPE_VTBL_H */
|
@ -1,483 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1996, 1997 Claus 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/ftape/zftape/zftape-write.c,v $
|
||||
* $Revision: 1.3 $
|
||||
* $Date: 1997/11/06 00:50:29 $
|
||||
*
|
||||
* This file contains the writing code
|
||||
* for the QIC-117 floppy-tape driver for Linux.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <linux/zftape.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include "../zftape/zftape-init.h"
|
||||
#include "../zftape/zftape-eof.h"
|
||||
#include "../zftape/zftape-ctl.h"
|
||||
#include "../zftape/zftape-write.h"
|
||||
#include "../zftape/zftape-read.h"
|
||||
#include "../zftape/zftape-rw.h"
|
||||
#include "../zftape/zftape-vtbl.h"
|
||||
|
||||
/* Global vars.
|
||||
*/
|
||||
|
||||
/* Local vars.
|
||||
*/
|
||||
static int last_write_failed;
|
||||
static int need_flush;
|
||||
|
||||
void zft_prevent_flush(void)
|
||||
{
|
||||
need_flush = 0;
|
||||
}
|
||||
|
||||
static int zft_write_header_segments(__u8* buffer)
|
||||
{
|
||||
int header_1_ok = 0;
|
||||
int header_2_ok = 0;
|
||||
unsigned int time_stamp;
|
||||
TRACE_FUN(ft_t_noise);
|
||||
|
||||
TRACE_CATCH(ftape_abort_operation(),);
|
||||
ftape_seek_to_bot(); /* prevents extra rewind */
|
||||
if (GET4(buffer, 0) != FT_HSEG_MAGIC) {
|
||||
TRACE_ABORT(-EIO, ft_t_err,
|
||||
"wrong header signature found, aborting");
|
||||
}
|
||||
/* Be optimistic: */
|
||||
PUT4(buffer, FT_SEG_CNT,
|
||||
zft_written_segments + GET4(buffer, FT_SEG_CNT) + 2);
|
||||
if ((time_stamp = zft_get_time()) != 0) {
|
||||
PUT4(buffer, FT_WR_DATE, time_stamp);
|
||||
if (zft_label_changed) {
|
||||
PUT4(buffer, FT_LABEL_DATE, time_stamp);
|
||||
}
|
||||
}
|
||||
TRACE(ft_t_noise,
|
||||
"writing first header segment %d", ft_header_segment_1);
|
||||
header_1_ok = zft_verify_write_segments(ft_header_segment_1,
|
||||
buffer, FT_SEGMENT_SIZE,
|
||||
zft_deblock_buf) >= 0;
|
||||
TRACE(ft_t_noise,
|
||||
"writing second header segment %d", ft_header_segment_2);
|
||||
header_2_ok = zft_verify_write_segments(ft_header_segment_2,
|
||||
buffer, FT_SEGMENT_SIZE,
|
||||
zft_deblock_buf) >= 0;
|
||||
if (!header_1_ok) {
|
||||
TRACE(ft_t_warn, "Warning: "
|
||||
"update of first header segment failed");
|
||||
}
|
||||
if (!header_2_ok) {
|
||||
TRACE(ft_t_warn, "Warning: "
|
||||
"update of second header segment failed");
|
||||
}
|
||||
if (!header_1_ok && !header_2_ok) {
|
||||
TRACE_ABORT(-EIO, ft_t_err, "Error: "
|
||||
"update of both header segments failed.");
|
||||
}
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
int zft_update_header_segments(void)
|
||||
{
|
||||
TRACE_FUN(ft_t_noise);
|
||||
|
||||
/* must NOT use zft_write_protected, as it also includes the
|
||||
* file access mode. But we also want to update when soft
|
||||
* write protection is enabled (O_RDONLY)
|
||||
*/
|
||||
if (ft_write_protected || zft_old_ftape) {
|
||||
TRACE_ABORT(0, ft_t_noise, "Tape set read-only: no update");
|
||||
}
|
||||
if (!zft_header_read) {
|
||||
TRACE_ABORT(0, ft_t_noise, "Nothing to update");
|
||||
}
|
||||
if (!zft_header_changed) {
|
||||
zft_header_changed = zft_written_segments > 0;
|
||||
}
|
||||
if (!zft_header_changed && !zft_volume_table_changed) {
|
||||
TRACE_ABORT(0, ft_t_noise, "Nothing to update");
|
||||
}
|
||||
TRACE(ft_t_noise, "Updating header segments");
|
||||
if (ftape_get_status()->fti_state == writing) {
|
||||
TRACE_CATCH(ftape_loop_until_writes_done(),);
|
||||
}
|
||||
TRACE_CATCH(ftape_abort_operation(),);
|
||||
|
||||
zft_deblock_segment = -1; /* invalidate the cache */
|
||||
if (zft_header_changed) {
|
||||
TRACE_CATCH(zft_write_header_segments(zft_hseg_buf),);
|
||||
}
|
||||
if (zft_volume_table_changed) {
|
||||
TRACE_CATCH(zft_update_volume_table(ft_first_data_segment),);
|
||||
}
|
||||
zft_header_changed =
|
||||
zft_volume_table_changed =
|
||||
zft_label_changed =
|
||||
zft_written_segments = 0;
|
||||
TRACE_CATCH(ftape_abort_operation(),);
|
||||
ftape_seek_to_bot();
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
static int read_merge_buffer(int seg_pos, __u8 *buffer, int offset, int seg_sz)
|
||||
{
|
||||
int result = 0;
|
||||
const ft_trace_t old_tracing = TRACE_LEVEL;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (zft_qic_mode) {
|
||||
/* writing in the middle of a volume is NOT allowed
|
||||
*
|
||||
*/
|
||||
TRACE(ft_t_noise, "No need to read a segment");
|
||||
memset(buffer + offset, 0, seg_sz - offset);
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
TRACE(ft_t_any, "waiting");
|
||||
ftape_start_writing(FT_WR_MULTI);
|
||||
TRACE_CATCH(ftape_loop_until_writes_done(),);
|
||||
|
||||
TRACE(ft_t_noise, "trying to read segment %d from offset %d",
|
||||
seg_pos, offset);
|
||||
SET_TRACE_LEVEL(ft_t_bug);
|
||||
result = zft_fetch_segment_fraction(seg_pos, buffer,
|
||||
FT_RD_SINGLE,
|
||||
offset, seg_sz - offset);
|
||||
SET_TRACE_LEVEL(old_tracing);
|
||||
if (result != (seg_sz - offset)) {
|
||||
TRACE(ft_t_noise, "Ignore error: read_segment() result: %d",
|
||||
result);
|
||||
memset(buffer + offset, 0, seg_sz - offset);
|
||||
}
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
/* flush the write buffer to tape and write an eof-marker at the
|
||||
* current position if not in raw mode. This function always
|
||||
* positions the tape before the eof-marker. _ftape_close() should
|
||||
* then advance to the next segment.
|
||||
*
|
||||
* the parameter "finish_volume" describes whether to position before
|
||||
* or after the possibly created file-mark. We always position after
|
||||
* the file-mark when called from ftape_close() and a flush was needed
|
||||
* (that is ftape_write() was the last tape operation before calling
|
||||
* ftape_flush) But we always position before the file-mark when this
|
||||
* function get's called from outside ftape_close()
|
||||
*/
|
||||
int zft_flush_buffers(void)
|
||||
{
|
||||
int result;
|
||||
int data_remaining;
|
||||
int this_segs_size;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
TRACE(ft_t_data_flow,
|
||||
"entered, ftape_state = %d", ftape_get_status()->fti_state);
|
||||
if (ftape_get_status()->fti_state != writing && !need_flush) {
|
||||
TRACE_ABORT(0, ft_t_noise, "no need for flush");
|
||||
}
|
||||
zft_io_state = zft_idle; /* triggers some initializations for the
|
||||
* read and write routines
|
||||
*/
|
||||
if (last_write_failed) {
|
||||
ftape_abort_operation();
|
||||
TRACE_EXIT -EIO;
|
||||
}
|
||||
TRACE(ft_t_noise, "flushing write buffers");
|
||||
this_segs_size = zft_get_seg_sz(zft_pos.seg_pos);
|
||||
if (this_segs_size == zft_pos.seg_byte_pos) {
|
||||
zft_pos.seg_pos ++;
|
||||
data_remaining = zft_pos.seg_byte_pos = 0;
|
||||
} else {
|
||||
data_remaining = zft_pos.seg_byte_pos;
|
||||
}
|
||||
/* If there is any data not written to tape yet, append zero's
|
||||
* up to the end of the sector (if using compression) or merge
|
||||
* it with the data existing on the tape Then write the
|
||||
* segment(s) to tape.
|
||||
*/
|
||||
TRACE(ft_t_noise, "Position:\n"
|
||||
KERN_INFO "seg_pos : %d\n"
|
||||
KERN_INFO "byte pos : %d\n"
|
||||
KERN_INFO "remaining: %d",
|
||||
zft_pos.seg_pos, zft_pos.seg_byte_pos, data_remaining);
|
||||
if (data_remaining > 0) {
|
||||
do {
|
||||
this_segs_size = zft_get_seg_sz(zft_pos.seg_pos);
|
||||
if (this_segs_size > data_remaining) {
|
||||
TRACE_CATCH(read_merge_buffer(zft_pos.seg_pos,
|
||||
zft_deblock_buf,
|
||||
data_remaining,
|
||||
this_segs_size),
|
||||
last_write_failed = 1);
|
||||
}
|
||||
result = ftape_write_segment(zft_pos.seg_pos,
|
||||
zft_deblock_buf,
|
||||
FT_WR_MULTI);
|
||||
if (result != this_segs_size) {
|
||||
TRACE(ft_t_err, "flush buffers failed");
|
||||
zft_pos.tape_pos -= zft_pos.seg_byte_pos;
|
||||
zft_pos.seg_byte_pos = 0;
|
||||
|
||||
last_write_failed = 1;
|
||||
TRACE_EXIT result;
|
||||
}
|
||||
zft_written_segments ++;
|
||||
TRACE(ft_t_data_flow,
|
||||
"flush, moved out buffer: %d", result);
|
||||
/* need next segment for more data (empty segments?)
|
||||
*/
|
||||
if (result < data_remaining) {
|
||||
if (result > 0) {
|
||||
/* move remainder to buffer beginning
|
||||
*/
|
||||
memmove(zft_deblock_buf,
|
||||
zft_deblock_buf + result,
|
||||
FT_SEGMENT_SIZE - result);
|
||||
}
|
||||
}
|
||||
data_remaining -= result;
|
||||
zft_pos.seg_pos ++;
|
||||
} while (data_remaining > 0);
|
||||
TRACE(ft_t_any, "result: %d", result);
|
||||
zft_deblock_segment = --zft_pos.seg_pos;
|
||||
if (data_remaining == 0) { /* first byte next segment */
|
||||
zft_pos.seg_byte_pos = this_segs_size;
|
||||
} else { /* after data previous segment, data_remaining < 0 */
|
||||
zft_pos.seg_byte_pos = data_remaining + result;
|
||||
}
|
||||
} else {
|
||||
TRACE(ft_t_noise, "zft_deblock_buf empty");
|
||||
zft_pos.seg_pos --;
|
||||
zft_pos.seg_byte_pos = zft_get_seg_sz (zft_pos.seg_pos);
|
||||
ftape_start_writing(FT_WR_MULTI);
|
||||
}
|
||||
TRACE(ft_t_any, "waiting");
|
||||
if ((result = ftape_loop_until_writes_done()) < 0) {
|
||||
/* that's really bad. What to to with zft_tape_pos?
|
||||
*/
|
||||
TRACE(ft_t_err, "flush buffers failed");
|
||||
}
|
||||
TRACE(ft_t_any, "zft_seg_pos: %d, zft_seg_byte_pos: %d",
|
||||
zft_pos.seg_pos, zft_pos.seg_byte_pos);
|
||||
last_write_failed =
|
||||
need_flush = 0;
|
||||
TRACE_EXIT result;
|
||||
}
|
||||
|
||||
/* return-value: the number of bytes removed from the user-buffer
|
||||
*
|
||||
* out:
|
||||
* int *write_cnt: how much actually has been moved to the
|
||||
* zft_deblock_buf
|
||||
* int req_len : MUST NOT BE CHANGED, except at EOT, in
|
||||
* which case it may be adjusted
|
||||
* in :
|
||||
* char *buff : the user buffer
|
||||
* int buf_pos_write : copy of buf_len_wr int
|
||||
* this_segs_size : the size in bytes of the actual segment
|
||||
* char
|
||||
* *zft_deblock_buf : zft_deblock_buf
|
||||
*/
|
||||
static int zft_simple_write(int *cnt,
|
||||
__u8 *dst_buf, const int seg_sz,
|
||||
const __u8 __user *src_buf, const int req_len,
|
||||
const zft_position *pos,const zft_volinfo *volume)
|
||||
{
|
||||
int space_left;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
/* volume->size holds the tape capacity while volume is open */
|
||||
if (pos->tape_pos + volume->blk_sz > volume->size) {
|
||||
TRACE_EXIT -ENOSPC;
|
||||
}
|
||||
/* remaining space in this segment, NOT zft_deblock_buf
|
||||
*/
|
||||
space_left = seg_sz - pos->seg_byte_pos;
|
||||
*cnt = req_len < space_left ? req_len : space_left;
|
||||
if (copy_from_user(dst_buf + pos->seg_byte_pos, src_buf, *cnt) != 0) {
|
||||
TRACE_EXIT -EFAULT;
|
||||
}
|
||||
TRACE_EXIT *cnt;
|
||||
}
|
||||
|
||||
static int check_write_access(int req_len,
|
||||
const zft_volinfo **volume,
|
||||
zft_position *pos,
|
||||
const unsigned int blk_sz)
|
||||
{
|
||||
int result;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if ((req_len % zft_blk_sz) != 0) {
|
||||
TRACE_ABORT(-EINVAL, ft_t_info,
|
||||
"write-count %d must be multiple of block-size %d",
|
||||
req_len, blk_sz);
|
||||
}
|
||||
if (zft_io_state == zft_writing) {
|
||||
/* all other error conditions have been checked earlier
|
||||
*/
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
zft_io_state = zft_idle;
|
||||
TRACE_CATCH(zft_check_write_access(pos),);
|
||||
/* If we haven't read the header segment yet, do it now.
|
||||
* This will verify the configuration, get the bad sector
|
||||
* table and read the volume table segment
|
||||
*/
|
||||
if (!zft_header_read) {
|
||||
TRACE_CATCH(zft_read_header_segments(),);
|
||||
}
|
||||
/* fine. Now the tape is either at BOT or at EOD,
|
||||
* Write start of volume now
|
||||
*/
|
||||
TRACE_CATCH(zft_open_volume(pos, blk_sz, zft_use_compression),);
|
||||
*volume = zft_find_volume(pos->seg_pos);
|
||||
DUMP_VOLINFO(ft_t_noise, "", *volume);
|
||||
zft_just_before_eof = 0;
|
||||
/* now merge with old data if necessary */
|
||||
if (!zft_qic_mode && pos->seg_byte_pos != 0){
|
||||
result = zft_fetch_segment(pos->seg_pos,
|
||||
zft_deblock_buf,
|
||||
FT_RD_SINGLE);
|
||||
if (result < 0) {
|
||||
if (result == -EINTR || result == -ENOSPC) {
|
||||
TRACE_EXIT result;
|
||||
}
|
||||
TRACE(ft_t_noise,
|
||||
"ftape_read_segment() result: %d. "
|
||||
"This might be normal when using "
|
||||
"a newly\nformatted tape", result);
|
||||
memset(zft_deblock_buf, '\0', pos->seg_byte_pos);
|
||||
}
|
||||
}
|
||||
zft_io_state = zft_writing;
|
||||
TRACE_EXIT 0;
|
||||
}
|
||||
|
||||
static int fill_deblock_buf(__u8 *dst_buf, const int seg_sz,
|
||||
zft_position *pos, const zft_volinfo *volume,
|
||||
const char __user *usr_buf, const int req_len)
|
||||
{
|
||||
int cnt = 0;
|
||||
int result = 0;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
if (seg_sz == 0) {
|
||||
TRACE_ABORT(0, ft_t_data_flow, "empty segment");
|
||||
}
|
||||
TRACE(ft_t_data_flow, "\n"
|
||||
KERN_INFO "remaining req_len: %d\n"
|
||||
KERN_INFO " buf_pos: %d",
|
||||
req_len, pos->seg_byte_pos);
|
||||
/* zft_deblock_buf will not contain a valid segment any longer */
|
||||
zft_deblock_segment = -1;
|
||||
if (zft_use_compression) {
|
||||
TRACE_CATCH(zft_cmpr_lock(1 /* try to load */),);
|
||||
TRACE_CATCH(result= (*zft_cmpr_ops->write)(&cnt,
|
||||
dst_buf, seg_sz,
|
||||
usr_buf, req_len,
|
||||
pos, volume),);
|
||||
} else {
|
||||
TRACE_CATCH(result= zft_simple_write(&cnt,
|
||||
dst_buf, seg_sz,
|
||||
usr_buf, req_len,
|
||||
pos, volume),);
|
||||
}
|
||||
pos->volume_pos += result;
|
||||
pos->seg_byte_pos += cnt;
|
||||
pos->tape_pos += cnt;
|
||||
TRACE(ft_t_data_flow, "\n"
|
||||
KERN_INFO "removed from user-buffer : %d bytes.\n"
|
||||
KERN_INFO "copied to zft_deblock_buf: %d bytes.\n"
|
||||
KERN_INFO "zft_tape_pos : " LL_X " bytes.",
|
||||
result, cnt, LL(pos->tape_pos));
|
||||
TRACE_EXIT result;
|
||||
}
|
||||
|
||||
|
||||
/* called by the kernel-interface routine "zft_write()"
|
||||
*/
|
||||
int _zft_write(const char __user *buff, int req_len)
|
||||
{
|
||||
int result = 0;
|
||||
int written = 0;
|
||||
int write_cnt;
|
||||
int seg_sz;
|
||||
static const zft_volinfo *volume = NULL;
|
||||
TRACE_FUN(ft_t_flow);
|
||||
|
||||
zft_resid = req_len;
|
||||
last_write_failed = 1; /* reset to 0 when successful */
|
||||
/* check if write is allowed
|
||||
*/
|
||||
TRACE_CATCH(check_write_access(req_len, &volume,&zft_pos,zft_blk_sz),);
|
||||
while (req_len > 0) {
|
||||
/* Allow us to escape from this loop with a signal !
|
||||
*/
|
||||
FT_SIGNAL_EXIT(_DONT_BLOCK);
|
||||
seg_sz = zft_get_seg_sz(zft_pos.seg_pos);
|
||||
if ((write_cnt = fill_deblock_buf(zft_deblock_buf,
|
||||
seg_sz,
|
||||
&zft_pos,
|
||||
volume,
|
||||
buff,
|
||||
req_len)) < 0) {
|
||||
zft_resid -= written;
|
||||
if (write_cnt == -ENOSPC) {
|
||||
/* leave the remainder to flush_buffers()
|
||||
*/
|
||||
TRACE(ft_t_info, "No space left on device");
|
||||
last_write_failed = 0;
|
||||
if (!need_flush) {
|
||||
need_flush = written > 0;
|
||||
}
|
||||
TRACE_EXIT written > 0 ? written : -ENOSPC;
|
||||
} else {
|
||||
TRACE_EXIT result;
|
||||
}
|
||||
}
|
||||
if (zft_pos.seg_byte_pos == seg_sz) {
|
||||
TRACE_CATCH(ftape_write_segment(zft_pos.seg_pos,
|
||||
zft_deblock_buf,
|
||||
FT_WR_ASYNC),
|
||||
zft_resid -= written);
|
||||
zft_written_segments ++;
|
||||
zft_pos.seg_byte_pos = 0;
|
||||
zft_deblock_segment = zft_pos.seg_pos;
|
||||
++zft_pos.seg_pos;
|
||||
}
|
||||
written += write_cnt;
|
||||
buff += write_cnt;
|
||||
req_len -= write_cnt;
|
||||
} /* while (req_len > 0) */
|
||||
TRACE(ft_t_data_flow, "remaining in blocking buffer: %d",
|
||||
zft_pos.seg_byte_pos);
|
||||
TRACE(ft_t_data_flow, "just written bytes: %d", written);
|
||||
last_write_failed = 0;
|
||||
zft_resid -= written;
|
||||
need_flush = need_flush || written > 0;
|
||||
TRACE_EXIT written; /* bytes written */
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
#ifndef _ZFTAPE_WRITE_H
|
||||
#define _ZFTAPE_WRITE_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 1996, 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/ftape/zftape/zftape-write.h,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:19:13 $
|
||||
*
|
||||
* This file contains the definitions for the write functions
|
||||
* for the zftape driver for Linux.
|
||||
*
|
||||
*/
|
||||
|
||||
extern int zft_flush_buffers(void);
|
||||
extern int zft_update_header_segments(void);
|
||||
extern void zft_prevent_flush(void);
|
||||
|
||||
/* hook for the VFS interface
|
||||
*/
|
||||
extern int _zft_write(const char __user *buff, int req_len);
|
||||
#endif /* _ZFTAPE_WRITE_H */
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (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/ftape/zftape/zftape_syms.c,v $
|
||||
* $Revision: 1.3 $
|
||||
* $Date: 1997/10/05 19:19:14 $
|
||||
*
|
||||
* This file contains the symbols that the zftape frontend to
|
||||
* the ftape floppy tape driver exports
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/zftape.h>
|
||||
|
||||
#include "../zftape/zftape-init.h"
|
||||
#include "../zftape/zftape-read.h"
|
||||
#include "../zftape/zftape-buffers.h"
|
||||
#include "../zftape/zftape-ctl.h"
|
||||
|
||||
/* zftape-init.c */
|
||||
EXPORT_SYMBOL(zft_cmpr_register);
|
||||
/* zftape-read.c */
|
||||
EXPORT_SYMBOL(zft_fetch_segment_fraction);
|
||||
/* zftape-buffers.c */
|
||||
EXPORT_SYMBOL(zft_vmalloc_once);
|
||||
EXPORT_SYMBOL(zft_vmalloc_always);
|
||||
EXPORT_SYMBOL(zft_vfree);
|
@ -60,8 +60,6 @@ header-y += fadvise.h
|
||||
header-y += fd.h
|
||||
header-y += fdreg.h
|
||||
header-y += fib_rules.h
|
||||
header-y += ftape-header-segment.h
|
||||
header-y += ftape-vendors.h
|
||||
header-y += fuse.h
|
||||
header-y += futex.h
|
||||
header-y += genetlink.h
|
||||
@ -206,7 +204,6 @@ unifdef-y += fcntl.h
|
||||
unifdef-y += filter.h
|
||||
unifdef-y += flat.h
|
||||
unifdef-y += fs.h
|
||||
unifdef-y += ftape.h
|
||||
unifdef-y += gameport.h
|
||||
unifdef-y += generic_serial.h
|
||||
unifdef-y += genhd.h
|
||||
@ -341,6 +338,5 @@ unifdef-y += wait.h
|
||||
unifdef-y += wanrouter.h
|
||||
unifdef-y += watchdog.h
|
||||
unifdef-y += xfrm.h
|
||||
unifdef-y += zftape.h
|
||||
|
||||
objhdr-y += version.h
|
||||
|
@ -1,122 +0,0 @@
|
||||
#ifndef _FTAPE_HEADER_SEGMENT_H
|
||||
#define _FTAPE_HEADER_SEGMENT_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 1996-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/ftape-header-segment.h,v $
|
||||
* $Revision: 1.2 $
|
||||
* $Date: 1997/10/05 19:19:28 $
|
||||
*
|
||||
* This file defines some offsets into the header segment of a
|
||||
* floppy tape cartridge. For use with the QIC-40/80/3010/3020
|
||||
* floppy-tape driver "ftape" for Linux.
|
||||
*/
|
||||
|
||||
#define FT_SIGNATURE 0 /* must be 0xaa55aa55 */
|
||||
#define FT_FMT_CODE 4
|
||||
#define FT_REV_LEVEL 5 /* only for QIC-80 since. Rev. L (== 0x0c) */
|
||||
#define FT_HSEG_1 6 /* first header segment, except for format code 6 */
|
||||
#define FT_HSEG_2 8 /* second header segment, except for format code 6 */
|
||||
#define FT_FRST_SEG 10 /* first data segment, except for format code 6 */
|
||||
#define FT_LAST_SEG 12 /* last data segment, except for format code 6 */
|
||||
#define FT_FMT_DATE 14 /* date and time of most recent format, see below */
|
||||
#define FT_WR_DATE 18 /* date and time of most recent write or format */
|
||||
#define FT_SPT 24 /* segments per track */
|
||||
#define FT_TPC 26 /* tracks per cartridge */
|
||||
#define FT_FHM 27 /* floppy drive head (maximum of it) */
|
||||
#define FT_FTM 28 /* floppy track max. */
|
||||
#define FT_FSM 29 /* floppy sector max. (128) */
|
||||
#define FT_LABEL 30 /* floppy tape label */
|
||||
#define FT_LABEL_DATE 74 /* date and time the tape label was written */
|
||||
#define FT_LABEL_SZ (FT_LABEL_DATE - FT_LABEL)
|
||||
#define FT_CMAP_START 78 /* starting segment of compression map */
|
||||
#define FT_FMT_ERROR 128 /* must be set to 0xff if remainder gets lost during
|
||||
* tape format
|
||||
*/
|
||||
#define FT_SEG_CNT 130 /* number of seg. written, formatted or verified
|
||||
* through lifetime of tape (why not read?)
|
||||
*/
|
||||
#define FT_INIT_DATE 138 /* date and time of initial tape format */
|
||||
#define FT_FMT_CNT 142 /* number of times tape has been formatted */
|
||||
#define FT_FSL_CNT 144 /* number of segments in failed sector log */
|
||||
#define FT_MK_CODE 146 /* id string of tape manufacturer */
|
||||
#define FT_LOT_CODE 190 /* tape manufacturer lot code */
|
||||
#define FT_6_HSEG_1 234 /* first header segment for format code 6 */
|
||||
#define FT_6_HSEG_2 238 /* second header segment for format code 6 */
|
||||
#define FT_6_FRST_SEG 242 /* first data segment for format code 6 */
|
||||
#define FT_6_LAST_SEG 246 /* last data segment for format code 6 */
|
||||
|
||||
#define FT_FSL 256
|
||||
#define FT_HEADER_END 256 /* space beyond this point:
|
||||
* format codes 2, 3 and 5:
|
||||
* - failed sector log until byte 2047
|
||||
* - bad sector map in the reamining part of segment
|
||||
* format codes 4 and 6:
|
||||
* - bad sector map starts hear
|
||||
*/
|
||||
|
||||
|
||||
/* value to be stored at the FT_SIGNATURE offset
|
||||
*/
|
||||
#define FT_HSEG_MAGIC 0xaa55aa55
|
||||
#define FT_D2G_MAGIC 0x82288228 /* Ditto 2GB */
|
||||
|
||||
/* data and time encoding: */
|
||||
#define FT_YEAR_SHIFT 25
|
||||
#define FT_YEAR_MASK 0xfe000000
|
||||
#define FT_YEAR_0 1970
|
||||
#define FT_YEAR_MAX 127
|
||||
#define FT_YEAR(year) ((((year)-FT_YEAR_0)<<FT_YEAR_SHIFT)&FT_YEAR_MASK)
|
||||
|
||||
#define FT_TIME_SHIFT 0
|
||||
#define FT_TIME_MASK 0x01FFFFFF
|
||||
#define FT_TIME_MAX 0x01ea6dff /* last second of a year */
|
||||
#define FT_TIME(mo,d,h,m,s) \
|
||||
((((s)+60*((m)+60*((h)+24*((d)+31*(mo))))) & FT_TIME_MASK))
|
||||
|
||||
#define FT_TIME_STAMP(y,mo,d,h,m,s) (FT_YEAR(y) | FT_TIME(mo,d,h,m,s))
|
||||
|
||||
/* values for the format code field */
|
||||
typedef enum {
|
||||
fmt_normal = 2, /* QIC-80 post Rev. B 205Ft or 307Ft tape */
|
||||
fmt_1100ft = 3, /* QIC-80 post Rev. B 1100Ft tape */
|
||||
fmt_var = 4, /* QIC-80 post Rev. B variabel length format */
|
||||
fmt_425ft = 5, /* QIC-80 post Rev. B 425Ft tape */
|
||||
fmt_big = 6 /* QIC-3010/3020 variable length tape with more
|
||||
* than 2^16 segments per tape
|
||||
*/
|
||||
} ft_format_type;
|
||||
|
||||
/* definitions for the failed sector log */
|
||||
#define FT_FSL_SIZE (2 * FT_SECTOR_SIZE - FT_HEADER_END)
|
||||
#define FT_FSL_MAX_ENTRIES (FT_FSL_SIZE/sizeof(__u32))
|
||||
|
||||
typedef struct ft_fsl_entry {
|
||||
__u16 segment;
|
||||
__u16 date;
|
||||
} __attribute__ ((packed)) ft_fsl_entry;
|
||||
|
||||
|
||||
/* date encoding for the failed sector log
|
||||
* month: 1..12, day: 1..31, year: 1970..2097
|
||||
*/
|
||||
#define FT_FSL_TIME_STAMP(y,m,d) \
|
||||
(((((y) - FT_YEAR_0)<<9)&0xfe00) | (((m)<<5)&0x01e0) | ((d)&0x001f))
|
||||
|
||||
#endif /* _FTAPE_HEADER_SEGMENT_H */
|
@ -1,137 +0,0 @@
|
||||
#ifndef _FTAPE_VENDORS_H
|
||||
#define _FTAPE_VENDORS_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 1993-1996 Bas Laarhoven,
|
||||
* (C) 1996-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/ftape-vendors.h,v $
|
||||
* $Revision: 1.6 $
|
||||
* $Date: 1997/10/09 15:38:11 $
|
||||
*
|
||||
* This file contains the supported drive types with their
|
||||
* QIC-117 spec. vendor code and drive dependent configuration
|
||||
* information.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
unknown_wake_up = 0,
|
||||
no_wake_up,
|
||||
wake_up_colorado,
|
||||
wake_up_mountain,
|
||||
wake_up_insight,
|
||||
} wake_up_types;
|
||||
|
||||
typedef struct {
|
||||
wake_up_types wake_up; /* see wake_up_types */
|
||||
char *name; /* Text describing the drive */
|
||||
} wakeup_method;
|
||||
|
||||
/* Note: order of entries in WAKEUP_METHODS must be so that a variable
|
||||
* of type wake_up_types can be used as an index in the array.
|
||||
*/
|
||||
#define WAKEUP_METHODS { \
|
||||
{ unknown_wake_up, "Unknown" }, \
|
||||
{ no_wake_up, "None" }, \
|
||||
{ wake_up_colorado, "Colorado" }, \
|
||||
{ wake_up_mountain, "Mountain" }, \
|
||||
{ wake_up_insight, "Motor-on" }, \
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
unsigned int vendor_id; /* vendor id from drive */
|
||||
int speed; /* maximum tape transport speed (ips) */
|
||||
wake_up_types wake_up; /* see wake_up_types */
|
||||
char *name; /* Text describing the drive */
|
||||
} vendor_struct;
|
||||
|
||||
#define UNKNOWN_VENDOR (-1)
|
||||
|
||||
#define QIC117_VENDORS { \
|
||||
/* see _vendor_struct */ \
|
||||
{ 0x00000, 82, wake_up_colorado, "Colorado DJ-10 (old)" }, \
|
||||
{ 0x00047, 90, wake_up_colorado, "Colorado DJ-10/DJ-20" }, \
|
||||
{ 0x011c2, 84, wake_up_colorado, "Colorado 700" }, \
|
||||
{ 0x011c3, 90, wake_up_colorado, "Colorado 1400" }, \
|
||||
{ 0x011c4, 84, wake_up_colorado, "Colorado DJ-10/DJ-20 (new)" }, \
|
||||
{ 0x011c5, 84, wake_up_colorado, "HP Colorado T1000" }, \
|
||||
{ 0x011c6, 90, wake_up_colorado, "HP Colorado T3000" }, \
|
||||
{ 0x00005, 45, wake_up_mountain, "Archive 5580i" }, \
|
||||
{ 0x10005, 50, wake_up_insight, "Insight 80Mb, Irwin 80SX" }, \
|
||||
{ 0x00140, 74, wake_up_mountain, "Archive S.Hornet [Identity/Escom]" }, \
|
||||
{ 0x00146, 72, wake_up_mountain, "Archive 31250Q [Escom]" }, \
|
||||
{ 0x0014a, 100, wake_up_mountain, "Archive XL9250i [Conner/Escom]" }, \
|
||||
{ 0x0014c, 98, wake_up_mountain, "Conner C250MQT" }, \
|
||||
{ 0x0014e, 80, wake_up_mountain, "Conner C250MQ" }, \
|
||||
{ 0x00150, 80, wake_up_mountain, "Conner TSM420R/TST800R" }, \
|
||||
{ 0x00152, 80, wake_up_mountain, "Conner TSM850R" }, \
|
||||
{ 0x00156, 80, wake_up_mountain, "Conner TSM850R/1700R/TST3200R" }, \
|
||||
{ 0x00180, 0, wake_up_mountain, "Summit SE 150" }, \
|
||||
{ 0x00181, 85, wake_up_mountain, "Summit SE 250, Mountain FS8000" }, \
|
||||
{ 0x001c1, 82, no_wake_up, "Wangtek 3040F" }, \
|
||||
{ 0x001c8, 64, no_wake_up, "Wangtek 3080F" }, \
|
||||
{ 0x001c8, 64, wake_up_colorado, "Wangtek 3080F" }, \
|
||||
{ 0x001ca, 67, no_wake_up, "Wangtek 3080F (new)" }, \
|
||||
{ 0x001cc, 77, wake_up_colorado, "Wangtek 3200 / Teac 700" }, \
|
||||
{ 0x001cd, 75, wake_up_colorado, "Reveal TB1400" }, \
|
||||
{ 0x00380, 85, wake_up_colorado, "Exabyte Eagle-96" }, \
|
||||
{ 0x00381, 85, wake_up_colorado, "Exabyte Eagle TR-3" }, \
|
||||
{ 0x00382, 85, wake_up_colorado, "Exabyte Eagle TR-3" }, \
|
||||
{ 0x003ce, 77, wake_up_colorado, "Teac 800" }, \
|
||||
{ 0x003cf, 0, wake_up_colorado, "Teac FT3010TR" }, \
|
||||
{ 0x08880, 64, no_wake_up, "Iomega 250, Ditto 800" }, \
|
||||
{ 0x08880, 64, wake_up_colorado, "Iomega 250, Ditto 800" }, \
|
||||
{ 0x08880, 64, wake_up_insight, "Iomega 250, Ditto 800" }, \
|
||||
{ 0x08881, 80, wake_up_colorado, "Iomega 700" }, \
|
||||
{ 0x08882, 80, wake_up_colorado, "Iomega 3200" }, \
|
||||
{ 0x08883, 80, wake_up_colorado, "Iomega DITTO 2GB" }, \
|
||||
{ 0x00021, 70, no_wake_up, "AIWA CT-803" }, \
|
||||
{ 0x004c0, 80, no_wake_up, "AIWA TD-S1600" }, \
|
||||
{ 0x00021, 0, wake_up_mountain, "COREtape QIC80" }, \
|
||||
{ 0x00441, 0, wake_up_mountain, "ComByte DoublePlay" }, \
|
||||
{ 0x00481, 127, wake_up_mountain, "PERTEC MyTape 800" }, \
|
||||
{ 0x00483, 130, wake_up_mountain, "PERTEC MyTape 3200" }, \
|
||||
{ UNKNOWN_VENDOR, 0, no_wake_up, "unknown" } \
|
||||
}
|
||||
|
||||
#define QIC117_MAKE_CODES { \
|
||||
{ 0, "Unassigned" }, \
|
||||
{ 1, "Alloy Computer Products" }, \
|
||||
{ 2, "3M" }, \
|
||||
{ 3, "Tandberg Data" }, \
|
||||
{ 4, "Colorado" }, \
|
||||
{ 5, "Archive/Conner" }, \
|
||||
{ 6, "Mountain/Summit Memory Systems" }, \
|
||||
{ 7, "Wangtek/Rexon/Tecmar" }, \
|
||||
{ 8, "Sony" }, \
|
||||
{ 9, "Cipher Data Products" }, \
|
||||
{ 10, "Irwin Magnetic Systems" }, \
|
||||
{ 11, "Braemar" }, \
|
||||
{ 12, "Verbatim" }, \
|
||||
{ 13, "Core International" }, \
|
||||
{ 14, "Exabyte" }, \
|
||||
{ 15, "Teac" }, \
|
||||
{ 16, "Gigatek" }, \
|
||||
{ 17, "ComByte" }, \
|
||||
{ 18, "PERTEC Memories" }, \
|
||||
{ 19, "Aiwa" }, \
|
||||
{ 71, "Colorado" }, \
|
||||
{ 546, "Iomega Inc" }, \
|
||||
}
|
||||
|
||||
#endif /* _FTAPE_VENDORS_H */
|
@ -1,201 +0,0 @@
|
||||
#ifndef _FTAPE_H
|
||||
#define _FTAPE_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 1994-1996 Bas Laarhoven,
|
||||
* (C) 1996-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/ftape.h,v $
|
||||
* $Revision: 1.17.6.4 $
|
||||
* $Date: 1997/11/25 01:52:54 $
|
||||
*
|
||||
* This file contains global definitions, typedefs and macro's
|
||||
* for the QIC-40/80/3010/3020 floppy-tape driver for Linux.
|
||||
*/
|
||||
|
||||
#define FTAPE_VERSION "ftape v3.04d 25/11/97"
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mm.h>
|
||||
#endif
|
||||
#include <linux/types.h>
|
||||
#include <linux/mtio.h>
|
||||
|
||||
#define FT_SECTOR(x) (x+1) /* sector offset into real sector */
|
||||
#define FT_SECTOR_SIZE 1024
|
||||
#define FT_SECTORS_PER_SEGMENT 32
|
||||
#define FT_ECC_SECTORS 3
|
||||
#define FT_SEGMENT_SIZE ((FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS) * FT_SECTOR_SIZE)
|
||||
#define FT_BUFF_SIZE (FT_SECTORS_PER_SEGMENT * FT_SECTOR_SIZE)
|
||||
|
||||
/*
|
||||
* bits of the minor device number that define drive selection
|
||||
* methods. Could be used one day to access multiple tape
|
||||
* drives on the same controller.
|
||||
*/
|
||||
#define FTAPE_SEL_A 0
|
||||
#define FTAPE_SEL_B 1
|
||||
#define FTAPE_SEL_C 2
|
||||
#define FTAPE_SEL_D 3
|
||||
#define FTAPE_SEL_MASK 3
|
||||
#define FTAPE_SEL(unit) ((unit) & FTAPE_SEL_MASK)
|
||||
#define FTAPE_NO_REWIND 4 /* mask for minor nr */
|
||||
|
||||
/* the following two may be reported when MTIOCGET is requested ... */
|
||||
typedef union {
|
||||
struct {
|
||||
__u8 error;
|
||||
__u8 command;
|
||||
} error;
|
||||
long space;
|
||||
} ft_drive_error;
|
||||
typedef union {
|
||||
struct {
|
||||
__u8 drive_status;
|
||||
__u8 drive_config;
|
||||
__u8 tape_status;
|
||||
} status;
|
||||
long space;
|
||||
} ft_drive_status;
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define FT_RQM_DELAY 12
|
||||
#define FT_MILLISECOND 1
|
||||
#define FT_SECOND 1000
|
||||
#define FT_FOREVER -1
|
||||
#ifndef HZ
|
||||
#error "HZ undefined."
|
||||
#endif
|
||||
#define FT_USPT (1000000/HZ) /* microseconds per tick */
|
||||
|
||||
/* This defines the number of retries that the driver will allow
|
||||
* before giving up (and letting a higher level handle the error).
|
||||
*/
|
||||
#ifdef TESTING
|
||||
#define FT_SOFT_RETRIES 1 /* number of low level retries */
|
||||
#define FT_RETRIES_ON_ECC_ERROR 3 /* ecc error when correcting segment */
|
||||
#else
|
||||
#define FT_SOFT_RETRIES 6 /* number of low level retries (triple) */
|
||||
#define FT_RETRIES_ON_ECC_ERROR 3 /* ecc error when correcting segment */
|
||||
#endif
|
||||
|
||||
#ifndef THE_FTAPE_MAINTAINER
|
||||
#define THE_FTAPE_MAINTAINER "the ftape maintainer"
|
||||
#endif
|
||||
|
||||
/* Initialize missing configuration parameters.
|
||||
*/
|
||||
#ifndef CONFIG_FT_NR_BUFFERS
|
||||
# define CONFIG_FT_NR_BUFFERS 3
|
||||
#endif
|
||||
#ifndef CONFIG_FT_FDC_THR
|
||||
# define CONFIG_FT_FDC_THR 8
|
||||
#endif
|
||||
#ifndef CONFIG_FT_FDC_MAX_RATE
|
||||
# define CONFIG_FT_FDC_MAX_RATE 2000
|
||||
#endif
|
||||
#ifndef CONFIG_FT_FDC_BASE
|
||||
# define CONFIG_FT_FDC_BASE 0
|
||||
#endif
|
||||
#ifndef CONFIG_FT_FDC_IRQ
|
||||
# define CONFIG_FT_FDC_IRQ 0
|
||||
#endif
|
||||
#ifndef CONFIG_FT_FDC_DMA
|
||||
# define CONFIG_FT_FDC_DMA 0
|
||||
#endif
|
||||
|
||||
/* Turn some booleans into numbers.
|
||||
*/
|
||||
#ifdef CONFIG_FT_PROBE_FC10
|
||||
# undef CONFIG_FT_PROBE_FC10
|
||||
# define CONFIG_FT_PROBE_FC10 1
|
||||
#else
|
||||
# define CONFIG_FT_PROBE_FC10 0
|
||||
#endif
|
||||
#ifdef CONFIG_FT_MACH2
|
||||
# undef CONFIG_FT_MACH2
|
||||
# define CONFIG_FT_MACH2 1
|
||||
#else
|
||||
# define CONFIG_FT_MACH2 0
|
||||
#endif
|
||||
|
||||
/* Insert default settings
|
||||
*/
|
||||
#if CONFIG_FT_PROBE_FC10 == 1
|
||||
# if CONFIG_FT_FDC_BASE == 0
|
||||
# undef CONFIG_FT_FDC_BASE
|
||||
# define CONFIG_FT_FDC_BASE 0x180
|
||||
# endif
|
||||
# if CONFIG_FT_FDC_IRQ == 0
|
||||
# undef CONFIG_FT_FDC_IRQ
|
||||
# define CONFIG_FT_FDC_IRQ 9
|
||||
# endif
|
||||
# if CONFIG_FT_FDC_DMA == 0
|
||||
# undef CONFIG_FT_FDC_DMA
|
||||
# define CONFIG_FT_FDC_DMA 3
|
||||
# endif
|
||||
#elif CONFIG_FT_MACH2 == 1 /* CONFIG_FT_PROBE_FC10 == 1 */
|
||||
# if CONFIG_FT_FDC_BASE == 0
|
||||
# undef CONFIG_FT_FDC_BASE
|
||||
# define CONFIG_FT_FDC_BASE 0x1E0
|
||||
# endif
|
||||
# if CONFIG_FT_FDC_IRQ == 0
|
||||
# undef CONFIG_FT_FDC_IRQ
|
||||
# define CONFIG_FT_FDC_IRQ 6
|
||||
# endif
|
||||
# if CONFIG_FT_FDC_DMA == 0
|
||||
# undef CONFIG_FT_FDC_DMA
|
||||
# define CONFIG_FT_FDC_DMA 2
|
||||
# endif
|
||||
#elif defined(CONFIG_FT_ALT_FDC) /* CONFIG_FT_MACH2 */
|
||||
# if CONFIG_FT_FDC_BASE == 0
|
||||
# undef CONFIG_FT_FDC_BASE
|
||||
# define CONFIG_FT_FDC_BASE 0x370
|
||||
# endif
|
||||
# if CONFIG_FT_FDC_IRQ == 0
|
||||
# undef CONFIG_FT_FDC_IRQ
|
||||
# define CONFIG_FT_FDC_IRQ 6
|
||||
# endif
|
||||
# if CONFIG_FT_FDC_DMA == 0
|
||||
# undef CONFIG_FT_FDC_DMA
|
||||
# define CONFIG_FT_FDC_DMA 2
|
||||
# endif
|
||||
#else /* CONFIG_FT_ALT_FDC */
|
||||
# if CONFIG_FT_FDC_BASE == 0
|
||||
# undef CONFIG_FT_FDC_BASE
|
||||
# define CONFIG_FT_FDC_BASE 0x3f0
|
||||
# endif
|
||||
# if CONFIG_FT_FDC_IRQ == 0
|
||||
# undef CONFIG_FT_FDC_IRQ
|
||||
# define CONFIG_FT_FDC_IRQ 6
|
||||
# endif
|
||||
# if CONFIG_FT_FDC_DMA == 0
|
||||
# undef CONFIG_FT_FDC_DMA
|
||||
# define CONFIG_FT_FDC_DMA 2
|
||||
# endif
|
||||
#endif /* standard FDC */
|
||||
|
||||
/* some useful macro's
|
||||
*/
|
||||
#define NR_ITEMS(x) (int)(sizeof(x)/ sizeof(*x))
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif
|
@ -1,87 +0,0 @@
|
||||
#ifndef _ZFTAPE_H
|
||||
#define _ZFTAPE_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 1996, 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/zftape.h,v $
|
||||
* $Revision: 1.12 $
|
||||
* $Date: 1997/10/21 11:02:37 $
|
||||
*
|
||||
* Special ioctl and other global info for the zftape VFS
|
||||
* interface for the QIC-40/80/3010/3020 floppy-tape driver for
|
||||
* Linux.
|
||||
*/
|
||||
|
||||
#define ZFTAPE_VERSION "zftape for " FTAPE_VERSION
|
||||
|
||||
#include <linux/ftape.h>
|
||||
|
||||
#define ZFTAPE_LABEL "Ftape - The Linux Floppy Tape Project!"
|
||||
|
||||
/* Bits of the minor device number that control the operation mode */
|
||||
#define ZFT_Q80_MODE (1 << 3)
|
||||
#define ZFT_ZIP_MODE (1 << 4)
|
||||
#define ZFT_RAW_MODE (1 << 5)
|
||||
#define ZFT_MINOR_OP_MASK (ZFT_Q80_MODE | \
|
||||
ZFT_ZIP_MODE | \
|
||||
ZFT_RAW_MODE)
|
||||
#define ZFT_MINOR_MASK (FTAPE_SEL_MASK | \
|
||||
ZFT_MINOR_OP_MASK | \
|
||||
FTAPE_NO_REWIND)
|
||||
|
||||
#ifdef ZFT_OBSOLETE
|
||||
struct mtblksz {
|
||||
unsigned int mt_blksz;
|
||||
};
|
||||
#define MTIOC_ZFTAPE_GETBLKSZ _IOR('m', 104, struct mtblksz)
|
||||
#endif
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
extern int zft_init(void);
|
||||
|
||||
static inline __s64 zft_div_blksz(__s64 value, __u32 blk_sz)
|
||||
{
|
||||
if (blk_sz == 1) {
|
||||
return value;
|
||||
} else {
|
||||
return (__s64)(((__u32)(value >> 10) + (blk_sz >> 10) - 1)
|
||||
/ (blk_sz >> 10));
|
||||
}
|
||||
}
|
||||
|
||||
static inline __s64 zft_mul_blksz(__s64 value, __u32 blk_sz)
|
||||
{
|
||||
if (blk_sz == 1) {
|
||||
return value;
|
||||
} else {
|
||||
/* if blk_sz != 1, then it is a multiple of 1024. In
|
||||
* this case, `value' will also fit into 32 bits.
|
||||
*
|
||||
* Actually, this limits the capacity to 42
|
||||
* bits. This is (2^32)*1024, roughly a thousand
|
||||
* times 2GB, or 3 Terabytes. Hopefully this is enough
|
||||
*/
|
||||
return(__s64)(((__u32)(value)*(blk_sz>>10))<<10);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user