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:
Jeff Garzik 2006-12-03 22:22:41 -05:00
parent 2b5f6dcce5
commit d916faace3
74 changed files with 0 additions and 20278 deletions

View file

@ -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

View file

@ -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

View file

@ -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>

View file

@ -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)

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -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.

View file

@ -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/

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 */
/******************************************************************************/

View file

@ -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

View file

@ -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 */

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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 */

View file

@ -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(&current->pending.signal, _DONT_BLOCK) &&
!(sigtestsetmask(&current->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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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_ */

View file

@ -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;
}

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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) */

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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 */

View file

@ -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);

View file

@ -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);
}

View file

@ -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(&current->pending.signal, sig_mask)) { \
TRACE_ABORT(-EINTR, \
ft_t_warn, \
"interrupted by non-blockable signal"); \
}
#endif /* _FTAPE_TRACING_H */

View file

@ -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);
}
}

View file

@ -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 */

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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(&current->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 (&current->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(&current->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(&current->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(&current->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(&current->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(&current->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);

View file

@ -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

View file

@ -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;
}

View file

@ -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 */

View file

@ -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;
}

View file

@ -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 */

View file

@ -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;
}

View file

@ -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 */

View file

@ -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 */
}

View file

@ -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 */

View file

@ -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);

View file

@ -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

View file

@ -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 */

View file

@ -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 */

View file

@ -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

View file

@ -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