diff options
301 files changed, 5435 insertions, 22261 deletions
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index 02457ec9c94f..f08ca9535733 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX @@ -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 diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index f81819364b7a..226ecf2ffd56 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -234,14 +234,6 @@ Who: Jean Delvare <khali@linux-fr.org> --------------------------- -What: ftape -When: 2.6.20 -Why: Orphaned for ages. SMP bugs long unfixed. Few users left - in the world. -Who: Jeff Garzik <jeff@garzik.org> - ---------------------------- - What: IPv4 only connection tracking/NAT/helpers When: 2.6.22 Why: The new layer 3 independant connection tracking replaces the old diff --git a/Documentation/ftape.txt b/Documentation/ftape.txt deleted file mode 100644 index 7d8bb3384031..000000000000 --- a/Documentation/ftape.txt +++ /dev/null @@ -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> diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 67473849f20e..15e4fed127f6 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -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) diff --git a/Documentation/s390/CommonIO b/Documentation/s390/CommonIO index d684a6ac69a8..22f82f21bc60 100644 --- a/Documentation/s390/CommonIO +++ b/Documentation/s390/CommonIO @@ -74,7 +74,7 @@ Command line parameters Note: While already known devices can be added to the list of devices to be ignored, there will be no effect on then. However, if such a device - disappears and then reappeares, it will then be ignored. + disappears and then reappears, it will then be ignored. For example, "echo add 0.0.a000-0.0.accc, 0.0.af00-0.0.afff > /proc/cio_ignore" @@ -82,7 +82,7 @@ Command line parameters devices. The devices can be specified either by bus id (0.0.abcd) or, for 2.4 backward - compatibilty, by the device number in hexadecimal (0xabcd or abcd). + compatibility, by the device number in hexadecimal (0xabcd or abcd). * /proc/s390dbf/cio_*/ (S/390 debug feature) diff --git a/Documentation/s390/Debugging390.txt b/Documentation/s390/Debugging390.txt index 4dd25ee549e9..3f9ddbc23b27 100644 --- a/Documentation/s390/Debugging390.txt +++ b/Documentation/s390/Debugging390.txt @@ -7,7 +7,7 @@ Overview of Document: ===================== -This document is intended to give an good overview of how to debug +This document is intended to give a good overview of how to debug Linux for s/390 & z/Architecture. It isn't intended as a complete reference & not a tutorial on the fundamentals of C & assembly. It doesn't go into 390 IO in any detail. It is intended to complement the documents in the @@ -300,7 +300,7 @@ On z/Architecture our page indexes are now 2k in size but only mess with 2 segment indices each time we mess with a PMD. -3) As z/Architecture supports upto a massive 5-level page table lookup we +3) As z/Architecture supports up to a massive 5-level page table lookup we can only use 3 currently on Linux ( as this is all the generic kernel currently supports ) however this may change in future this allows us to access ( according to my sums ) @@ -502,7 +502,7 @@ Notes: ------ 1) The only requirement is that registers which are used by the callee are saved, e.g. the compiler is perfectly -capible of using r11 for purposes other than a frame a +capable of using r11 for purposes other than a frame a frame pointer if a frame pointer is not needed. 2) In functions with variable arguments e.g. printf the calling procedure is identical to one without variable arguments & the same number of @@ -846,7 +846,7 @@ of time searching for debugging info. The following self explanatory line should instead if the code isn't compiled -g, as it is much faster: objdump --disassemble-all --syms vmlinux > vmlinux.lst -As hard drive space is valuble most of us use the following approach. +As hard drive space is valuable most of us use the following approach. 1) Look at the emitted psw on the console to find the crash address in the kernel. 2) Look at the file System.map ( in the linux directory ) produced when building the kernel to find the closest address less than the current PSW to find the @@ -902,7 +902,7 @@ A. It is a tool for intercepting calls to the kernel & logging them to a file & on the screen. Q. What use is it ? -A. You can used it to find out what files a particular program opens. +A. You can use it to find out what files a particular program opens. @@ -911,7 +911,7 @@ Example 1 If you wanted to know does ping work but didn't have the source strace ping -c 1 127.0.0.1 & then look at the man pages for each of the syscalls below, -( In fact this is sometimes easier than looking at some spagetti +( In fact this is sometimes easier than looking at some spaghetti source which conditionally compiles for several architectures ). Not everything that it throws out needs to make sense immediately. @@ -1037,7 +1037,7 @@ e.g. man strace, man alarm, man socket. Performance Debugging ===================== -gcc is capible of compiling in profiling code just add the -p option +gcc is capable of compiling in profiling code just add the -p option to the CFLAGS, this obviously affects program size & performance. This can be used by the gprof gnu profiling tool or the gcov the gnu code coverage tool ( code coverage is a means of testing @@ -1419,7 +1419,7 @@ On a SMP guest issue a command to all CPUs try prefixing the command with cpu al To issue a command to a particular cpu try cpu <cpu number> e.g. CPU 01 TR I R 2000.3000 If you are running on a guest with several cpus & you have a IO related problem -& cannot follow the flow of code but you know it isnt smp related. +& cannot follow the flow of code but you know it isn't smp related. from the bash prompt issue shutdown -h now or halt. do a Q CPUS to find out how many cpus you have @@ -1602,7 +1602,7 @@ V000FFFD0 00010400 80010802 8001085A 000FFFA0 our 3rd return address is 8001085A as the 04B52002 looks suspiciously like rubbish it is fair to assume that the kernel entry routines -for the sake of optimisation dont set up a backchain. +for the sake of optimisation don't set up a backchain. now look at System.map to see if the addresses make any sense. @@ -1638,11 +1638,11 @@ more useful information. Unlike other bus architectures modern 390 systems do their IO using mostly fibre optics & devices such as tapes & disks can be shared between several mainframes, -also S390 can support upto 65536 devices while a high end PC based system might be choking +also S390 can support up to 65536 devices while a high end PC based system might be choking with around 64. Here is some of the common IO terminology Subchannel: -This is the logical number most IO commands use to talk to an IO device there can be upto +This is the logical number most IO commands use to talk to an IO device there can be up to 0x10000 (65536) of these in a configuration typically there is a few hundred. Under VM for simplicity they are allocated contiguously, however on the native hardware they are not they typically stay consistent between boots provided no new hardware is inserted or removed. @@ -1651,7 +1651,7 @@ HALT SUBCHANNEL,MODIFY SUBCHANNEL,RESUME SUBCHANNEL,START SUBCHANNEL,STORE SUBCH TEST SUBCHANNEL ) we use this as the ID of the device we wish to talk to, the most important of these instructions are START SUBCHANNEL ( to start IO ), TEST SUBCHANNEL ( to check whether the IO completed successfully ), & HALT SUBCHANNEL ( to kill IO ), a subchannel -can have up to 8 channel paths to a device this offers redunancy if one is not available. +can have up to 8 channel paths to a device this offers redundancy if one is not available. Device Number: @@ -1659,7 +1659,7 @@ This number remains static & Is closely tied to the hardware, there are 65536 of also they are made up of a CHPID ( Channel Path ID, the most significant 8 bits ) & another lsb 8 bits. These remain static even if more devices are inserted or removed from the hardware, there is a 1 to 1 mapping between Subchannels & Device Numbers provided -devices arent inserted or removed. +devices aren't inserted or removed. Channel Control Words: CCWS are linked lists of instructions initially pointed to by an operation request block (ORB), @@ -1674,7 +1674,7 @@ concurrently, you check how the IO went on by issuing a TEST SUBCHANNEL at each from which you receive an Interruption response block (IRB). If you get channel & device end status in the IRB without channel checks etc. your IO probably went okay. If you didn't you probably need a doctor to examine the IRB & extended status word etc. -If an error occurs, more sophistocated control units have a facitity known as +If an error occurs, more sophisticated control units have a facility known as concurrent sense this means that if an error occurs Extended sense information will be presented in the Extended status word in the IRB if not you have to issue a subsequent SENSE CCW command after the test subchannel. @@ -1749,7 +1749,7 @@ Interface (OEMI). This byte wide Parallel channel path/bus has parity & data on the "Bus" cable & control lines on the "Tag" cable. These can operate in byte multiplex mode for sharing between several slow devices or burst mode & monopolize the channel for the -whole burst. Upto 256 devices can be addressed on one of these cables. These cables are +whole burst. Up to 256 devices can be addressed on one of these cables. These cables are about one inch in diameter. The maximum unextended length supported by these cables is 125 Meters but this can be extended up to 2km with a fibre optic channel extended such as a 3044. The maximum burst speed supported is 4.5 megabytes per second however @@ -1759,7 +1759,7 @@ One of these paths can be daisy chained to up to 8 control units. ESCON if fibre optic it is also called FICON Was introduced by IBM in 1990. Has 2 fibre optic cables & uses either leds or lasers -for communication at a signaling rate of upto 200 megabits/sec. As 10bits are transferred +for communication at a signaling rate of up to 200 megabits/sec. As 10bits are transferred for every 8 bits info this drops to 160 megabits/sec & to 18.6 Megabytes/sec once control info & CRC are added. ESCON only operates in burst mode. @@ -1767,7 +1767,7 @@ ESCONs typical max cable length is 3km for the led version & 20km for the laser known as XDF ( extended distance facility ). This can be further extended by using an ESCON director which triples the above mentioned ranges. Unlike Bus & Tag as ESCON is serial it uses a packet switching architecture the standard Bus & Tag control protocol -is however present within the packets. Upto 256 devices can be attached to each control +is however present within the packets. Up to 256 devices can be attached to each control unit that uses one of these interfaces. Common 390 Devices include: @@ -2050,7 +2050,7 @@ list test.c:1,10 directory: Adds directories to be searched for source if gdb cannot find the source. -(note it is a bit sensititive about slashes) +(note it is a bit sensitive about slashes) e.g. To add the root of the filesystem to the searchpath do directory // @@ -2152,7 +2152,7 @@ program as if it just crashed on your system, it is usually called core & create current working directory. This is very useful in that a customer can mail a core dump to a technical support department & the technical support department can reconstruct what happened. -Provided the have an identical copy of this program with debugging symbols compiled in & +Provided they have an identical copy of this program with debugging symbols compiled in & the source base of this build is available. In short it is far more useful than something like a crash log could ever hope to be. diff --git a/Documentation/s390/cds.txt b/Documentation/s390/cds.txt index 32a96cc39215..05a2b4f7e38f 100644 --- a/Documentation/s390/cds.txt +++ b/Documentation/s390/cds.txt @@ -98,7 +98,7 @@ The following chapters describe the I/O related interface routines the Linux/390 common device support (CDS) provides to allow for device specific driver implementations on the IBM ESA/390 hardware platform. Those interfaces intend to provide the functionality required by every device driver -implementaion to allow to drive a specific hardware device on the ESA/390 +implementation to allow to drive a specific hardware device on the ESA/390 platform. Some of the interface routines are specific to Linux/390 and some of them can be found on other Linux platforms implementations too. Miscellaneous function prototypes, data declarations, and macro definitions @@ -114,7 +114,7 @@ the ESA/390 architecture has implemented a so called channel subsystem, that provides a unified view of the devices physically attached to the systems. Though the ESA/390 hardware platform knows about a huge variety of different peripheral attachments like disk devices (aka. DASDs), tapes, communication -controllers, etc. they can all by accessed by a well defined access method and +controllers, etc. they can all be accessed by a well defined access method and they are presenting I/O completion a unified way : I/O interruptions. Every single device is uniquely identified to the system by a so called subchannel, where the ESA/390 architecture allows for 64k devices be attached. @@ -338,7 +338,7 @@ DOIO_REPORT_ALL - report all interrupt conditions The ccw_device_start() function returns : 0 - successful completion or request successfully initiated --EBUSY - The device is currently processing a previous I/O request, or ther is +-EBUSY - The device is currently processing a previous I/O request, or there is a status pending at the device. -ENODEV - cdev is invalid, the device is not operational or the ccw_device is not online. @@ -361,7 +361,7 @@ first: -EIO: the common I/O layer terminated the request due to an error state If the concurrent sense flag in the extended status word in the irb is set, the -field irb->scsw.count describes the numer of device specific sense bytes +field irb->scsw.count describes the number of device specific sense bytes available in the extended control word irb->scsw.ecw[0]. No device sensing by the device driver itself is required. @@ -410,7 +410,7 @@ ccw_device_start() must be called disabled and with the ccw device lock held. The device driver is allowed to issue the next ccw_device_start() call from within its interrupt handler already. It is not required to schedule a -bottom-half, unless an non deterministically long running error recovery procedure +bottom-half, unless a non deterministically long running error recovery procedure or similar needs to be scheduled. During I/O processing the Linux/390 generic I/O device driver support has already obtained the IRQ lock, i.e. the handler must not try to obtain it again when calling ccw_device_start() or we end in a @@ -431,7 +431,7 @@ information prior to device-end the device driver urgently relies on. In this case all I/O interruptions are presented to the device driver until final status is recognized. -If a device is able to recover from asynchronosly presented I/O errors, it can +If a device is able to recover from asynchronously presented I/O errors, it can perform overlapping I/O using the DOIO_EARLY_NOTIFICATION flag. While some devices always report channel-end and device-end together, with a single interrupt, others present primary status (channel-end) when the channel is diff --git a/Documentation/s390/crypto/crypto-API.txt b/Documentation/s390/crypto/crypto-API.txt index 41a8b07da05a..71ae6ca9f2c2 100644 --- a/Documentation/s390/crypto/crypto-API.txt +++ b/Documentation/s390/crypto/crypto-API.txt @@ -17,8 +17,8 @@ arch/s390/crypto directory. 2. Probing for availability of MSA ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It should be possible to use Kernels with the z990 crypto implementations both -on machines with MSA available an on those without MSA (pre z990 or z990 -without MSA). Therefore a simple probing mechanisms has been implemented: +on machines with MSA available and on those without MSA (pre z990 or z990 +without MSA). Therefore a simple probing mechanism has been implemented: In the init function of each crypto module the availability of MSA and of the respective crypto algorithm in particular will be tested. If the algorithm is available the module will load and register its algorithm with the crypto API. @@ -26,7 +26,7 @@ available the module will load and register its algorithm with the crypto API. If the respective crypto algorithm is not available, the init function will return -ENOSYS. In that case a fallback to the standard software implementation of the crypto algorithm must be taken ( -> the standard crypto modules are -also build when compiling the kernel). +also built when compiling the kernel). 3. Ensuring z990 crypto module preference diff --git a/Documentation/s390/s390dbf.txt b/Documentation/s390/s390dbf.txt index 000230cd26db..0eb7c58916de 100644 --- a/Documentation/s390/s390dbf.txt +++ b/Documentation/s390/s390dbf.txt @@ -36,7 +36,7 @@ switches to the next debug area. This is done in order to be sure that the records which describe the origin of the exception are not overwritten when a wrap around for the current area occurs. -The debug areas itselve are also ordered in form of a ring buffer. +The debug areas themselves are also ordered in form of a ring buffer. When an exception is thrown in the last debug area, the following debug entries are then written again in the very first area. @@ -55,7 +55,7 @@ The debug logs can be inspected in a live system through entries in the debugfs-filesystem. Under the toplevel directory "s390dbf" there is a directory for each registered component, which is named like the corresponding component. The debugfs normally should be mounted to -/sys/kernel/debug therefore the debug feature can be accessed unter +/sys/kernel/debug therefore the debug feature can be accessed under /sys/kernel/debug/s390dbf. The content of the directories are files which represent different views @@ -87,11 +87,11 @@ There are currently 2 possible triggers, which stop the debug feature globally. The first possibility is to use the "debug_active" sysctl. If set to 1 the debug feature is running. If "debug_active" is set to 0 the debug feature is turned off. -The second trigger which stops the debug feature is an kernel oops. +The second trigger which stops the debug feature is a kernel oops. That prevents the debug feature from overwriting debug information that happened before the oops. After an oops you can reactivate the debug feature by piping 1 to /proc/sys/s390dbf/debug_active. Nevertheless, its not -suggested to use an oopsed kernel in an production environment. +suggested to use an oopsed kernel in a production environment. If you want to disallow the deactivation of the debug feature, you can use the "debug_stoppable" sysctl. If you set "debug_stoppable" to 0 the debug feature cannot be stopped. If the debug feature is already stopped, it diff --git a/MAINTAINERS b/MAINTAINERS index fd3b2ca0c031..5dff26814a06 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -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 diff --git a/arch/i386/kernel/acpi/cstate.c b/arch/i386/kernel/acpi/cstate.c index 20563e52c622..4664b55f623e 100644 --- a/arch/i386/kernel/acpi/cstate.c +++ b/arch/i386/kernel/acpi/cstate.c @@ -11,6 +11,7 @@ #include <linux/init.h> #include <linux/acpi.h> #include <linux/cpu.h> +#include <linux/sched.h> #include <acpi/processor.h> #include <asm/acpi.h> diff --git a/arch/i386/kernel/alternative.c b/arch/i386/kernel/alternative.c index 583c238e17fb..535f9794fba1 100644 --- a/arch/i386/kernel/alternative.c +++ b/arch/i386/kernel/alternative.c @@ -1,4 +1,5 @@ #include <linux/module.h> +#include <linux/sched.h> #include <linux/spinlock.h> #include <linux/list.h> #include <asm/alternative.h> diff --git a/arch/i386/kernel/cpu/mcheck/therm_throt.c b/arch/i386/kernel/cpu/mcheck/therm_throt.c index 2d8703b7ce65..bad8b4420709 100644 --- a/arch/i386/kernel/cpu/mcheck/therm_throt.c +++ b/arch/i386/kernel/cpu/mcheck/therm_throt.c @@ -20,6 +20,7 @@ #include <linux/cpu.h> #include <asm/cpu.h> #include <linux/notifier.h> +#include <linux/jiffies.h> #include <asm/therm_throt.h> /* How long to wait between reporting thermal events */ diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig index c1bc22c6d0d8..aa70dde54228 100644 --- a/arch/m68knommu/Kconfig +++ b/arch/m68knommu/Kconfig @@ -173,7 +173,7 @@ config CLOCK_DIV On many SoC style CPUs the master CPU clock is also used to drive on-chip peripherals. The clock that is distributed to these peripherals is sometimes a fixed ratio of the master clock - frequency. If so then set this to the divider ration of the + frequency. If so then set this to the divider ratio of the master clock to the peripheral clock. If not sure then select 1. config OLDMASK @@ -192,7 +192,7 @@ config PILOT3 Support for the Palm Pilot 1000/5000, Personal/Pro and PalmIII. config XCOPILOT_BUGS - bool " (X)Copilot support" + bool "(X)Copilot support" depends on PILOT3 help Support the bugs of Xcopilot. @@ -216,20 +216,20 @@ config DRAGEN2 Support for the DragenEngine II board. config DIRECT_IO_ACCESS - bool " Allow user to access IO directly" + bool "Allow user to access IO directly" depends on (UCSIMM || UCDIMM || DRAGEN2) help Disable the CPU internal registers protection in user mode, to allow a user application to read/write them. config INIT_LCD - bool " Initialize LCD" + bool "Initialize LCD" depends on (UCSIMM || UCDIMM || DRAGEN2) help Initialize the LCD controller of the 68x328 processor. config MEMORY_RESERVE - int " Memory reservation (MiB)" + int "Memory reservation (MiB)" depends on (UCSIMM || UCDIMM) help Reserve certain memory regions on 68x328 based boards. @@ -409,7 +409,7 @@ config MOD5272 Support for the Netburner MOD-5272 board. config ROMFS_FROM_ROM - bool " ROMFS image not RAM resident" + bool "ROMFS image not RAM resident" depends on (NETtel || SNAPGEAR) help The ROMfs filesystem will stay resident in the FLASH/ROM, not be diff --git a/arch/m68knommu/kernel/process.c b/arch/m68knommu/kernel/process.c index c18a83306953..941955dc3b7c 100644 --- a/arch/m68knommu/kernel/process.c +++ b/arch/m68knommu/kernel/process.c @@ -290,7 +290,7 @@ void dump(struct pt_regs *fp) unsigned char *tp; int i; - printk(KERN_EMERG "\nCURRENT PROCESS:\n\n"); + printk(KERN_EMERG "\n" KERN_EMERG "CURRENT PROCESS:\n" KERN_EMERG "\n"); printk(KERN_EMERG "COMM=%s PID=%d\n", current->comm, current->pid); if (current->mm) { @@ -301,7 +301,8 @@ void dump(struct pt_regs *fp) (int) current->mm->end_data, (int) current->mm->end_data, (int) current->mm->brk); - printk(KERN_EMERG "USER-STACK=%08x KERNEL-STACK=%08x\n\n", + printk(KERN_EMERG "USER-STACK=%08x KERNEL-STACK=%08x\n" + KERN_EMERG "\n", (int) current->mm->start_stack, (int)(((unsigned long) current) + THREAD_SIZE)); } @@ -312,36 +313,35 @@ void dump(struct pt_regs *fp) fp->d0, fp->d1, fp->d2, fp->d3); printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", fp->d4, fp->d5, fp->a0, fp->a1); - printk(KERN_EMERG "\nUSP: %08x TRAPFRAME: %08x\n", (unsigned int) rdusp(), - (unsigned int) fp); + printk(KERN_EMERG "\n" KERN_EMERG "USP: %08x TRAPFRAME: %08x\n", + (unsigned int) rdusp(), (unsigned int) fp); - printk(KERN_EMERG "\nCODE:"); + printk(KERN_EMERG "\n" KERN_EMERG "CODE:"); tp = ((unsigned char *) fp->pc) - 0x20; for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) { if ((i % 0x10) == 0) - printk(KERN_EMERG "\n%08x: ", (int) (tp + i)); - printk(KERN_EMERG "%08x ", (int) *sp++); + printk("\n" KERN_EMERG "%08x: ", (int) (tp + i)); + printk("%08x ", (int) *sp++); } - printk(KERN_EMERG "\n"); + printk("\n" KERN_EMERG "\n"); - printk(KERN_EMERG "\nKERNEL STACK:"); + printk(KERN_EMERG "KERNEL STACK:"); tp = ((unsigned char *) fp) - 0x40; for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) { if ((i % 0x10) == 0) - printk(KERN_EMERG "\n%08x: ", (int) (tp + i)); - printk(KERN_EMERG "%08x ", (int) *sp++); + printk("\n" KERN_EMERG "%08x: ", (int) (tp + i)); + printk("%08x ", (int) *sp++); } - printk(KERN_EMERG "\n"); - printk(KERN_EMERG "\n"); + printk("\n" KERN_EMERG "\n"); - printk(KERN_EMERG "\nUSER STACK:"); + printk(KERN_EMERG "USER STACK:"); tp = (unsigned char *) (rdusp() - 0x10); for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) { if ((i % 0x10) == 0) - printk(KERN_EMERG "\n%08x: ", (int) (tp + i)); - printk(KERN_EMERG "%08x ", (int) *sp++); + printk("\n" KERN_EMERG "%08x: ", (int) (tp + i)); + printk("%08x ", (int) *sp++); } - printk(KERN_EMERG "\n\n"); + printk("\n" KERN_EMERG "\n"); } /* diff --git a/arch/m68knommu/kernel/setup.c b/arch/m68knommu/kernel/setup.c index 7b21959eaeae..9cf2e4d1fc77 100644 --- a/arch/m68knommu/kernel/setup.c +++ b/arch/m68knommu/kernel/setup.c @@ -36,10 +36,7 @@ #include <asm/setup.h> #include <asm/irq.h> #include <asm/machdep.h> - -#ifdef CONFIG_BLK_DEV_INITRD #include <asm/pgtable.h> -#endif unsigned long memory_start; unsigned long memory_end; diff --git a/arch/m68knommu/kernel/sys_m68k.c b/arch/m68knommu/kernel/sys_m68k.c index c3494b8447d1..3265b2d734db 100644 --- a/arch/m68knommu/kernel/sys_m68k.c +++ b/arch/m68knommu/kernel/sys_m68k.c @@ -137,7 +137,7 @@ asmlinkage int old_select(struct sel_arg_struct *arg) asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) { - int version; + int version, ret; version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; @@ -190,6 +190,27 @@ asmlinkage int sys_ipc (uint call, int first, int second, default: return -EINVAL; } + if (call <= SHMCTL) + switch (call) { + case SHMAT: + switch (version) { + default: { + ulong raddr; + ret = do_shmat (first, ptr, second, &raddr); + if (ret) + return ret; + return put_user (raddr, (ulong __user *) third); + } + } + case SHMDT: + return sys_shmdt (ptr); + case SHMGET: + return sys_shmget (first, second, third); + case SHMCTL: + return sys_shmctl (first, second, ptr); + default: + return -ENOSYS; + } return -EINVAL; } diff --git a/arch/m68knommu/kernel/traps.c b/arch/m68knommu/kernel/traps.c index 17649d2543ef..9129b3a5258b 100644 --- a/arch/m68knommu/kernel/traps.c +++ b/arch/m68knommu/kernel/traps.c @@ -127,11 +127,12 @@ void show_stack(struct task_struct *task, unsigned long *stack) if (stack + 1 > endstack) break; if (i % 8 == 0) - printk(KERN_EMERG "\n "); - printk(KERN_EMERG " %08lx", *stack++); + printk("\n" KERN_EMERG " "); + printk(" %08lx", *stack++); } + printk("\n"); - printk(KERN_EMERG "\nCall Trace:"); + printk(KERN_EMERG "Call Trace:"); i = 0; while (stack + 1 <= endstack) { addr = *stack++; @@ -146,12 +147,12 @@ void show_stack(struct task_struct *task, unsigned long *stack) if (((addr >= (unsigned long) &_start) && (addr <= (unsigned long) &_etext))) { if (i % 4 == 0) - printk(KERN_EMERG "\n "); - printk(KERN_EMERG " [<%08lx>]", addr); + printk("\n" KERN_EMERG " "); + printk(" [<%08lx>]", addr); i++; } } - printk(KERN_EMERG "\n"); + printk("\n"); } void bad_super_trap(struct frame *fp) diff --git a/arch/m68knommu/platform/5307/head.S b/arch/m68knommu/platform/5307/head.S index f2edb6498cd9..b9aa0ca29bfb 100644 --- a/arch/m68knommu/platform/5307/head.S +++ b/arch/m68knommu/platform/5307/head.S @@ -64,6 +64,26 @@ negl %d0 /* negate bits */ .endm +#elif defined(CONFIG_M520x) +.macro GET_MEM_SIZE + clrl %d0 + movel MCF_MBAR+MCFSIM_SDCS0, %d2 /* Get SDRAM chip select 0 config */ + andl #0x1f, %d2 /* Get only the chip select size */ + beq 3f /* Check if it is enabled */ + addql #1, %d2 /* Form exponent */ + moveql #1, %d0 + lsll %d2, %d0 /* 2 ^ exponent */ +3: + movel MCF_MBAR+MCFSIM_SDCS1, %d2 /* Get SDRAM chip select 1 config */ + andl #0x1f, %d2 /* Get only the chip select size */ + beq 4f /* Check if it is enabled */ + addql #1, %d2 /* Form exponent */ + moveql #1, %d1 + lsll %d2, %d1 /* 2 ^ exponent */ + addl %d1, %d0 /* Total size of SDRAM in d0 */ +4: +.endm + #else #error "ERROR: I don't know how to probe your boards memory size?" #endif diff --git a/arch/m68knommu/platform/68360/head-ram.S b/arch/m68knommu/platform/68360/head-ram.S index 2ea51479f13a..2ef06242398b 100644 --- a/arch/m68knommu/platform/68360/head-ram.S +++ b/arch/m68knommu/platform/68360/head-ram.S @@ -25,6 +25,7 @@ .global _periph_base #define RAMEND (CONFIG_RAMBASE + CONFIG_RAMSIZE) +#define ROMEND (CONFIG_ROMBASE + CONFIG_ROMSIZE) #define REGB 0x1000 #define PEPAR (_dprbase + REGB + 0x0016) @@ -175,7 +176,7 @@ configure_chip_select_0: move.l %d0, BR0 configure_chip_select_1: - move.l #__rom_end, %d0 + move.l #ROMEND, %d0 subi.l #__rom_start, %d0 subq.l #0x01, %d0 eori.l #SIM_OR_MASK, %d0 diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 245b81bc7157..583d9ff0a571 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -33,9 +33,6 @@ config GENERIC_CALIBRATE_DELAY config GENERIC_TIME def_bool y -config GENERIC_BUST_SPINLOCK - bool - mainmenu "Linux Kernel Configuration" config S390 @@ -181,7 +178,7 @@ config PACK_STACK config SMALL_STACK bool "Use 4kb/8kb for kernel stack instead of 8kb/16kb" - depends on PACK_STACK + depends on PACK_STACK && !LOCKDEP help If you say Y here and the compiler supports the -mkernel-backchain option the kernel will use a smaller kernel stack size. For 31 bit diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 5deb9f7544a1..6598e5268573 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -35,6 +35,9 @@ cflags-$(CONFIG_MARCH_Z900) += $(call cc-option,-march=z900) cflags-$(CONFIG_MARCH_Z990) += $(call cc-option,-march=z990) cflags-$(CONFIG_MARCH_Z9_109) += $(call cc-option,-march=z9-109) +#KBUILD_IMAGE is necessary for make rpm +KBUILD_IMAGE :=arch/s390/boot/image + # # Prevent tail-call optimizations, to get clearer backtraces: # diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index aa978978d3d1..a81881c9b297 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -4,7 +4,7 @@ EXTRA_AFLAGS := -traditional -obj-y := bitmap.o traps.o time.o process.o \ +obj-y := bitmap.o traps.o time.o process.o reset.o \ setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ semaphore.o s390_ext.o debug.o profile.o irq.o ipl.o diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c index 1eae74e72f95..a5972f1541fe 100644 --- a/arch/s390/kernel/cpcmd.c +++ b/arch/s390/kernel/cpcmd.c @@ -21,14 +21,15 @@ static DEFINE_SPINLOCK(cpcmd_lock); static char cpcmd_buf[241]; /* - * the caller of __cpcmd has to ensure that the response buffer is below 2 GB + * __cpcmd has some restrictions over cpcmd + * - the response buffer must reside below 2GB (if any) + * - __cpcmd is unlocked and therefore not SMP-safe */ int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) { - unsigned long flags, cmdlen; + unsigned cmdlen; int return_code, return_len; - spin_lock_irqsave(&cpcmd_lock, flags); cmdlen = strlen(cmd); BUG_ON(cmdlen > 240); memcpy(cpcmd_buf, cmd, cmdlen); @@ -74,7 +75,6 @@ int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) : "+d" (reg3) : "d" (reg2) : "cc"); return_code = (int) reg3; } - spin_unlock_irqrestore(&cpcmd_lock, flags); if (response_code != NULL) *response_code = return_code; return return_len; @@ -82,15 +82,18 @@ int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) EXPORT_SYMBOL(__cpcmd); -#ifdef CONFIG_64BIT int cpcmd(const char *cmd, char *response, int rlen, int *response_code) { char *lowbuf; int len; + unsigned long flags; if ((rlen == 0) || (response == NULL) - || !((unsigned long)response >> 31)) + || !((unsigned long)response >> 31)) { + spin_lock_irqsave(&cpcmd_lock, flags); len = __cpcmd(cmd, response, rlen, response_code); + spin_unlock_irqrestore(&cpcmd_lock, flags); + } else { lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA); if (!lowbuf) { @@ -98,7 +101,9 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code) "cpcmd: could not allocate response buffer\n"); return -ENOMEM; } + spin_lock_irqsave(&cpcmd_lock, flags); len = __cpcmd(cmd, lowbuf, rlen, response_code); + spin_unlock_irqrestore(&cpcmd_lock, flags); memcpy(response, lowbuf, rlen); kfree(lowbuf); } @@ -106,4 +111,3 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code) } EXPORT_SYMBOL(cpcmd); -#endif /* CONFIG_64BIT */ diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index 0cf59bb7a857..8f8c802f1bcf 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S @@ -418,24 +418,6 @@ start: .gotr: l %r10,.tbl # EBCDIC to ASCII table tr 0(240,%r8),0(%r10) - stidp __LC_CPUID # Are we running on VM maybe - cli __LC_CPUID,0xff - bnz .test - .long 0x83300060 # diag 3,0,x'0060' - storage size - b .done -.test: - mvc 0x68(8),.pgmnw # set up pgm check handler - l %r2,.fourmeg - lr %r3,%r2 - bctr %r3,%r0 # 4M-1 -.loop: iske %r0,%r3 - ar %r3,%r2 -.pgmx: - sr %r3,%r2 - la %r3,1(%r3) -.done: - l %r1,.memsize - st %r3,ARCH_OFFSET(%r1) slr %r0,%r0 st %r0,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r11) st %r0,INITRD_START+ARCH_OFFSET-PARMAREA(%r11) @@ -443,9 +425,6 @@ start: .tbl: .long _ebcasc # translate table .cmd: .long COMMAND_LINE # address of command line buffer .parm: .long PARMAREA -.memsize: .long memory_size -.fourmeg: .long 0x00400000 # 4M -.pgmnw: .long 0x00080000,.pgmx .lowcase: .byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 .byte 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S index 0a2c929486ab..4388b3309e0c 100644 --- a/arch/s390/kernel/head31.S +++ b/arch/s390/kernel/head31.S @@ -131,10 +131,11 @@ startup_continue: .long init_thread_union .Lpmask: .byte 0 -.align 8 + .align 8 .Lpcext:.long 0x00080000,0x80000000 .Lcr: .long 0x00 # place holder for cr0 + .align 8 .Lwaitsclp: .long 0x010a0000,0x80000000 + .Lsclph .Lrcp: @@ -156,7 +157,7 @@ startup_continue: slr %r4,%r4 # set start of chunk to zero slr %r5,%r5 # set end of chunk to zero slr %r6,%r6 # set access code to zero - la %r10, MEMORY_CHUNKS # number of chunks + la %r10,MEMORY_CHUNKS # number of chunks .Lloop: tprot 0(%r5),0 # test protection of first byte ipm %r7 @@ -176,8 +177,6 @@ startup_continue: st %r0,4(%r3) # store size of chunk st %r6,8(%r3) # store type of chunk la %r3,12(%r3) - l %r4,.Lmemsize-.LPG1(%r13) # address of variable memory_size - st %r5,0(%r4) # store last end to memory size ahi %r10,-1 # update chunk number .Lchkloop: lr %r6,%r7 # set access code to last cc @@ -292,7 +291,6 @@ startup_continue: .Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg .Lpcidte:.long 0x00080000,0x80000000 + .Lchkidte .Lpcdiag9c:.long 0x00080000,0x80000000 + .Lchkdiag9c -.Lmemsize:.long memory_size .Lmchunk:.long memory_chunk .Lmflags:.long machine_flags .Lbss_bgn: .long __bss_start diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index 42f54d482441..c526279e1123 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -70,7 +70,20 @@ startup_continue: sgr %r5,%r5 # set src,length and pad to zero mvcle %r2,%r4,0 # clear mem jo .-4 # branch back, if not finish + # set program check new psw mask + mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) + larl %r1,.Lslowmemdetect # set program check address + stg %r1,__LC_PGM_NEW_PSW+8 + lghi %r1,0xc + diag %r0,%r1,0x260 # get memory size of virtual machine + cgr %r0,%r1 # different? -> old detection routine + jne .Lslowmemdetect + aghi %r1,1 # size is one more than end + larl %r2,memory_chunk + stg %r1,8(%r2) # store size of chunk + j .Ldonemem +.Lslowmemdetect: l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word .Lservicecall: stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts @@ -139,8 +152,6 @@ startup_continue: .int 0x100000 .Lfchunk: - # set program check new psw mask - mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) # # find memory chunks. @@ -175,8 +186,6 @@ startup_continue: stg %r0,8(%r3) # store size of chunk st %r6,20(%r3) # store type of chunk la %r3,24(%r3) - larl %r8,memory_size - stg %r5,0(%r8) # store memory size ahi %r10,-1 # update chunk number .Lchkloop: lr %r6,%r7 # set access code to last cc diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 1f5e782b3d05..a36bea1188d9 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -13,12 +13,21 @@ #include <linux/device.h> #include <linux/delay.h> #include <linux/reboot.h> +#include <linux/ctype.h> #include <asm/smp.h> #include <asm/setup.h> #include <asm/cpcmd.h> #include <asm/cio.h> +#include <asm/ebcdic.h> +#include <asm/reset.h> #define IPL_PARM_BLOCK_VERSION 0 +#define LOADPARM_LEN 8 + +extern char s390_readinfo_sccb[]; +#define SCCB_VALID (*((__u16*)&s390_readinfo_sccb[6]) == 0x0010) +#define SCCB_LOADPARM (&s390_readinfo_sccb[24]) +#define SCCB_FLAG (s390_readinfo_sccb[91]) enum ipl_type { IPL_TYPE_NONE = 1, @@ -289,9 +298,25 @@ static struct attribute_group ipl_fcp_attr_group = { /* CCW ipl device attributes */ +static ssize_t ipl_ccw_loadparm_show(struct subsystem *subsys, char *page) +{ + char loadparm[LOADPARM_LEN + 1] = {}; + + if (!SCCB_VALID) + return sprintf(page, "#unknown#\n"); + memcpy(loadparm, SCCB_LOADPARM, LOADPARM_LEN); + EBCASC(loadparm, LOADPARM_LEN); + strstrip(loadparm); + return sprintf(page, "%s\n", loadparm); +} + +static struct subsys_attribute sys_ipl_ccw_loadparm_attr = + __ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL); + static struct attribute *ipl_ccw_attrs[] = { &sys_ipl_type_attr.attr, &sys_ipl_device_attr.attr, + &sys_ipl_ccw_loadparm_attr.attr, NULL, }; @@ -348,8 +373,57 @@ static struct attribute_group reipl_fcp_attr_group = { DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n", reipl_block_ccw->ipl_info.ccw.devno); +static void reipl_get_ascii_loadparm(char *loadparm) +{ + memcpy(loadparm, &reipl_block_ccw->ipl_info.ccw.load_param, + LOADPARM_LEN); + EBCASC(loadparm, LOADPARM_LEN); + loadparm[LOADPARM_LEN] = 0; + strstrip(loadparm); +} + +static ssize_t reipl_ccw_loadparm_show(struct subsystem *subsys, char *page) +{ + char buf[LOADPARM_LEN + 1]; + + reipl_get_ascii_loadparm(buf); + return sprintf(page, "%s\n", buf); +} + +static ssize_t reipl_ccw_loadparm_store(struct subsystem *subsys, + const char *buf, size_t len) +{ + int i, lp_len; + + /* ignore trailing newline */ + lp_len = len; + if ((len > 0) && (buf[len - 1] == '\n')) + lp_len--; + /* loadparm can have max 8 characters and must not start with a blank */ + if ((lp_len > LOADPARM_LEN) || ((lp_len > 0) && (buf[0] == ' '))) + return -EINVAL; + /* loadparm can only contain "a-z,A-Z,0-9,SP,." */ + for (i = 0; i < lp_len; i++) { + if (isalpha(buf[i]) || isdigit(buf[i]) || (buf[i] == ' ') || + (buf[i] == '.')) + continue; + return -EINVAL; + } + /* initialize loadparm with blanks */ + memset(&reipl_block_ccw->ipl_info.ccw.load_param, ' ', LOADPARM_LEN); + /* copy and convert to ebcdic */ + memcpy(&reipl_block_ccw->ipl_info.ccw.load_param, buf, lp_len); + ASCEBC(reipl_block_ccw->ipl_info.ccw.load_param, LOADPARM_LEN); + return len; +} + +static struct subsys_attribute sys_reipl_ccw_loadparm_attr = + __ATTR(loadparm, 0644, reipl_ccw_loadparm_show, + reipl_ccw_loadparm_store); + static struct attribute *reipl_ccw_attrs[] = { &sys_reipl_ccw_device_attr.attr, + &sys_reipl_ccw_loadparm_attr.attr, NULL, }; @@ -502,23 +576,6 @@ static struct subsys_attribute dump_type_attr = static decl_subsys(dump, NULL, NULL); -#ifdef CONFIG_SMP -static void dump_smp_stop_all(void) -{ - int cpu; - preempt_disable(); - for_each_online_cpu(cpu) { - if (cpu == smp_processor_id()) - continue; - while (signal_processor(cpu, sigp_stop) == sigp_busy) - udelay(10); - } - preempt_enable(); -} -#else -#define dump_smp_stop_all() do { } while (0) -#endif - /* * Shutdown actions section */ @@ -571,11 +628,14 @@ void do_reipl(void) { struct ccw_dev_id devid; static char buf[100]; + char loadparm[LOADPARM_LEN + 1]; switch (reipl_type) { case IPL_TYPE_CCW: + reipl_get_ascii_loadparm(loadparm); printk(KERN_EMERG "reboot on ccw device: 0.0.%04x\n", reipl_block_ccw->ipl_info.ccw.devno); + printk(KERN_EMERG "loadparm = '%s'\n", loadparm); break; case IPL_TYPE_FCP: printk(KERN_EMERG "reboot on fcp device:\n"); @@ -588,12 +648,19 @@ void do_reipl(void) switch (reipl_method) { case IPL_METHOD_CCW_CIO: devid.devno = reipl_block_ccw->ipl_info.ccw.devno; + if (ipl_get_type() == IPL_TYPE_CCW && devid.devno == ipl_devno) + diag308(DIAG308_IPL, NULL); devid.ssid = 0; reipl_ccw_dev(&devid); break; case IPL_METHOD_CCW_VM: - sprintf(buf, "IPL %X", reipl_block_ccw->ipl_info.ccw.devno); - cpcmd(buf, NULL, 0, NULL); + if (strlen(loadparm) == 0) + sprintf(buf, "IPL %X", + reipl_block_ccw->ipl_info.ccw.devno); + else + sprintf(buf, "IPL %X LOADPARM '%s'", + reipl_block_ccw->ipl_info.ccw.devno, loadparm); + __cpcmd(buf, NULL, 0, NULL); break; case IPL_METHOD_CCW_DIAG: diag308(DIAG308_SET, reipl_block_ccw); @@ -607,16 +674,17 @@ void do_reipl(void) diag308(DIAG308_IPL, NULL); break; case IPL_METHOD_FCP_RO_VM: - cpcmd("IPL", NULL, 0, NULL); + __cpcmd("IPL", NULL, 0, NULL); break; case IPL_METHOD_NONE: default: if (MACHINE_IS_VM) - cpcmd("IPL", NULL, 0, NULL); + __cpcmd("IPL", NULL, 0, NULL); diag308(DIAG308_IPL, NULL); break; } - panic("reipl failed!\n"); + printk(KERN_EMERG "reboot failed!\n"); + signal_processor(smp_processor_id(), sigp_stop_and_store_status); } static void do_dump(void) @@ -639,17 +707,17 @@ static void do_dump(void) switch (dump_method) { case IPL_METHOD_CCW_CIO: - dump_smp_stop_all(); + smp_send_stop(); devid.devno = dump_block_ccw->ipl_info.ccw.devno; devid.ssid = 0; reipl_ccw_dev(&devid); break; case IPL_METHOD_CCW_VM: - dump_smp_stop_all(); + smp_send_stop(); sprintf(buf, "STORE STATUS"); - cpcmd(buf, NULL, 0, NULL); + __cpcmd(buf, NULL, 0, NULL); sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno); - cpcmd(buf, NULL, 0, NULL); + __cpcmd(buf, NULL, 0, NULL); break; case IPL_METHOD_CCW_DIAG: diag308(DIAG308_SET, dump_block_ccw); @@ -746,6 +814,17 @@ static int __init reipl_ccw_init(void) reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION; reipl_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw); reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW; + /* check if read scp info worked and set loadparm */ + if (SCCB_VALID) + memcpy(reipl_block_ccw->ipl_info.ccw.load_param, + SCCB_LOADPARM, LOADPARM_LEN); + else + /* read scp info failed: set empty loadparm (EBCDIC blanks) */ + memset(reipl_block_ccw->ipl_info.ccw.load_param, 0x40, + LOADPARM_LEN); + /* FIXME: check for diag308_set_works when enabling diag ccw reipl */ + if (!MACHINE_IS_VM) + sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO; if (ipl_get_type() == IPL_TYPE_CCW) reipl_block_ccw->ipl_info.ccw.devno = ipl_devno; reipl_capabilities |= IPL_TYPE_CCW; @@ -827,13 +906,11 @@ static int __init dump_ccw_init(void) return 0; } -extern char s390_readinfo_sccb[]; - static int __init dump_fcp_init(void) { int rc; - if(!(s390_readinfo_sccb[91] & 0x2)) + if(!(SCCB_FLAG & 0x2) || !SCCB_VALID) return 0; /* LDIPL DUMP is not installed */ if (!diag308_set_works) return 0; @@ -931,3 +1008,53 @@ static int __init s390_ipl_init(void) } __initcall(s390_ipl_init); + +static LIST_HEAD(rcall); +static DEFINE_MUTEX(rcall_mutex); + +void register_reset_call(struct reset_call *reset) +{ + mutex_lock(&rcall_mutex); + list_add(&reset->list, &rcall); + mutex_unlock(&rcall_mutex); +} +EXPORT_SYMBOL_GPL(register_reset_call); + +void unregister_reset_call(struct reset_call *reset) +{ + mutex_lock(&rcall_mutex); + list_del(&reset->list); + mutex_unlock(&rcall_mutex); +} +EXPORT_SYMBOL_GPL(unregister_reset_call); + +static void do_reset_calls(void) +{ + struct reset_call *reset; + + list_for_each_entry(reset, &rcall, list) + reset->fn(); +} + +extern void reset_mcck_handler(void); + +void s390_reset_system(void) +{ + struct _lowcore *lc; + + /* Stack for interrupt/machine check handler */ + lc = (struct _lowcore *)(unsigned long) store_prefix(); + lc->panic_stack = S390_lowcore.panic_stack; + + /* Disable prefixing */ + set_prefix(0); + + /* Disable lowcore protection */ + __ctl_clear_bit(0,28); + + /* Set new machine check handler */ + S390_lowcore.mcck_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK; + S390_lowcore.mcck_new_psw.addr = + PSW_ADDR_AMODE | (unsigned long) &reset_mcck_handler; + do_reset_calls(); +} diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c index 60b1ea9f946b..f6d9bcc0f75b 100644 --- a/arch/s390/kernel/machine_kexec.c +++ b/arch/s390/kernel/machine_kexec.c @@ -1,15 +1,10 @@ /* * arch/s390/kernel/machine_kexec.c * - * (C) Copyright IBM Corp. 2005 + * Copyright IBM Corp. 2005,2006 * - * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com> - * - */ - -/* - * s390_machine_kexec.c - handle the transition of Linux booting another kernel - * on the S390 architecture. + * Author(s): Rolf Adelsberger, + * Heiko Carstens <heiko.carstens@de.ibm.com> */ #include <linux/device.h> @@ -22,86 +17,49 @@ #include <asm/pgalloc.h> #include <asm/system.h> #include <asm/smp.h> +#include <asm/reset.h> -static void kexec_halt_all_cpus(void *); - -typedef void (*relocate_kernel_t) (kimage_entry_t *, unsigned long); +typedef void (*relocate_kernel_t)(kimage_entry_t *, unsigned long); extern const unsigned char relocate_kernel[]; extern const unsigned long long relocate_kernel_len; -int -machine_kexec_prepare(struct kimage *image) +int machine_kexec_prepare(struct kimage *image) { - unsigned long reboot_code_buffer; + void *reboot_code_buffer; /* We don't support anything but the default image type for now. */ if (image->type != KEXEC_TYPE_DEFAULT) return -EINVAL; /* Get the destination where the assembler code should be copied to.*/ - reboot_code_buffer = page_to_pfn(image->control_code_page)<<PAGE_SHIFT; + reboot_code_buffer = (void *) page_to_phys(image->control_code_page); /* Then copy it */ - memcpy((void *) reboot_code_buffer, relocate_kernel, - relocate_kernel_len); + memcpy(reboot_code_buffer, relocate_kernel, relocate_kernel_len); return 0; } -void -machine_kexec_cleanup(struct kimage *image) +void machine_kexec_cleanup(struct kimage *image) { } -void -machine_shutdown(void) +void machine_shutdown(void) { printk(KERN_INFO "kexec: machine_shutdown called\n"); } -NORET_TYPE void -machine_kexec(struct kimage *image) +void machine_kexec(struct kimage *image) { - clear_all_subchannels(); - cio_reset_channel_paths(); - - /* Disable lowcore protection */ - ctl_clear_bit(0,28); - - on_each_cpu(kexec_halt_all_cpus, image, 0, 0); - for (;;); -} - -extern void pfault_fini(void); - -static void -kexec_halt_all_cpus(void *kernel_image) -{ - static atomic_t cpuid = ATOMIC_INIT(-1); - int cpu; - struct kimage *image; relocate_kernel_t data_mover; -#ifdef CONFIG_PFAULT - if (MACHINE_IS_VM) - pfault_fini(); -#endif + smp_send_stop(); + pfault_fini(); + s390_reset_system(); - if (atomic_cmpxchg(&cpuid, -1, smp_processor_id()) != -1) - signal_processor(smp_processor_id(), sigp_stop); - - /* Wait for all other cpus to enter stopped state */ - for_each_online_cpu(cpu) { - if (cpu == smp_processor_id()) - continue; - while (!smp_cpu_not_running(cpu)) - cpu_relax(); - } - - image = (struct kimage *) kernel_image; - data_mover = (relocate_kernel_t) - (page_to_pfn(image->control_code_page) << PAGE_SHIFT); + data_mover = (relocate_kernel_t) page_to_phys(image->control_code_page); /* Call the moving routine */ - (*data_mover) (&image->head, image->start); + (*data_mover)(&image->head, image->start); + for (;;); } diff --git a/arch/s390/kernel/reipl.S b/arch/s390/kernel/reipl.S index 0340477f3b08..f9434d42ce9f 100644 --- a/arch/s390/kernel/reipl.S +++ b/arch/s390/kernel/reipl.S @@ -11,19 +11,10 @@ .globl do_reipl_asm do_reipl_asm: basr %r13,0 .Lpg0: lpsw .Lnewpsw-.Lpg0(%r13) - - # switch off lowcore protection - -.Lpg1: stctl %c0,%c0,.Lctlsave1-.Lpg0(%r13) - stctl %c0,%c0,.Lctlsave2-.Lpg0(%r13) - ni .Lctlsave1-.Lpg0(%r13),0xef - lctl %c0,%c0,.Lctlsave1-.Lpg0(%r13) - - # do store status of all registers +.Lpg1: # do store status of all registers stm %r0,%r15,__LC_GPREGS_SAVE_AREA stctl %c0,%c15,__LC_CREGS_SAVE_AREA - mvc __LC_CREGS_SAVE_AREA(4),.Lctlsave2-.Lpg0(%r13) stam %a0,%a15,__LC_AREGS_SAVE_AREA stpx __LC_PREFIX_SAVE_AREA stckc .Lclkcmp-.Lpg0(%r13) @@ -56,8 +47,7 @@ do_reipl_asm: basr %r13,0 .L002: tm .Liplirb+8-.Lpg0(%r13),0xf3 jz .L003 bas %r14,.Ldisab-.Lpg0(%r13) -.L003: spx .Lnull-.Lpg0(%r13) - st %r1,__LC_SUBCHANNEL_ID +.L003: st %r1,__LC_SUBCHANNEL_ID lpsw 0 sigp 0,0,0(6) .Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13) @@ -65,9 +55,6 @@ do_reipl_asm: basr %r13,0 .align 8 .Lclkcmp: .quad 0x0000000000000000 .Lall: .long 0xff000000 -.Lnull: .long 0x00000000 -.Lctlsave1: .long 0x00000000 -.Lctlsave2: .long 0x00000000 .align 8 .Lnewpsw: .long 0x00080000,0x80000000+.Lpg1 .Lpcnew: .long 0x00080000,0x80000000+.Lecs diff --git a/arch/s390/kernel/reipl64.S b/arch/s390/kernel/reipl64.S index de7435054f7c..f18ef260ca23 100644 --- a/arch/s390/kernel/reipl64.S +++ b/arch/s390/kernel/reipl64.S @@ -10,10 +10,10 @@ #include <asm/lowcore.h> .globl do_reipl_asm do_reipl_asm: basr %r13,0 +.Lpg0: lpswe .Lnewpsw-.Lpg0(%r13) +.Lpg1: # do store status of all registers - # do store status of all registers - -.Lpg0: stg %r1,.Lregsave-.Lpg0(%r13) + stg %r1,.Lregsave-.Lpg0(%r13) lghi %r1,0x1000 stmg %r0,%r15,__LC_GPREGS_SAVE_AREA-0x1000(%r1) lg %r0,.Lregsave-.Lpg0(%r13) @@ -27,11 +27,7 @@ do_reipl_asm: basr %r13,0 stpt __LC_CPU_TIMER_SAVE_AREA-0x1000(%r1) stg %r13, __LC_PSW_SAVE_AREA-0x1000+8(%r1) - lpswe .Lnewpsw-.Lpg0(%r13) -.Lpg1: lctlg %c6,%c6,.Lall-.Lpg0(%r13) - stctg %c0,%c0,.Lregsave-.Lpg0(%r13) - ni .Lregsave+4-.Lpg0(%r13),0xef - lctlg %c0,%c0,.Lregsave-.Lpg0(%r13) + lctlg %c6,%c6,.Lall-.Lpg0(%r13) lgr %r1,%r2 mvc __LC_PGM_NEW_PSW(16),.Lpcnew-.Lpg0(%r13) stsch .Lschib-.Lpg0(%r13) @@ -56,8 +52,7 @@ do_reipl_asm: basr %r13,0 .L002: tm .Liplirb+8-.Lpg0(%r13),0xf3 jz .L003 bas %r14,.Ldisab-.Lpg0(%r13) -.L003: spx .Lnull-.Lpg0(%r13) - st %r1,__LC_SUBCHANNEL_ID +.L003: st %r1,__LC_SUBCHANNEL_ID lhi %r1,0 # mode 0 = esa slr %r0,%r0 # set cpuid to zero sigp %r1,%r0,0x12 # switch to esa mode @@ -70,7 +65,6 @@ do_reipl_asm: basr %r13,0 .Lclkcmp: .quad 0x0000000000000000 .Lall: .quad 0x00000000ff000000 .Lregsave: .quad 0x0000000000000000 -.Lnull: .long 0x0000000000000000 .align 16 /* * These addresses have to be 31 bit otherwise diff --git a/arch/s390/kernel/relocate_kernel.S b/arch/s390/kernel/relocate_kernel.S index f9899ff2e5b0..3b456b80bcee 100644 --- a/arch/s390/kernel/relocate_kernel.S +++ b/arch/s390/kernel/relocate_kernel.S @@ -26,8 +26,7 @@ relocate_kernel: basr %r13,0 # base address .base: - stnsm sys_msk-.base(%r13),0xf8 # disable DAT and IRQ (external) - spx zero64-.base(%r13) # absolute addressing mode + stnsm sys_msk-.base(%r13),0xfb # disable DAT stctl %c0,%c15,ctlregs-.base(%r13) stm %r0,%r15,gprregs-.base(%r13) la %r1,load_psw-.base(%r13) @@ -97,8 +96,6 @@ lpsw 0 # hopefully start new kernel... .align 8 - zero64: - .quad 0 load_psw: .long 0x00080000,0x80000000 sys_msk: diff --git a/arch/s390/kernel/relocate_kernel64.S b/arch/s390/kernel/relocate_kernel64.S index 4fb443042d9c..1f9ea2067b59 100644 --- a/arch/s390/kernel/relocate_kernel64.S +++ b/arch/s390/kernel/relocate_kernel64.S @@ -27,8 +27,7 @@ relocate_kernel: basr %r13,0 # base address .base: - stnsm sys_msk-.base(%r13),0xf8 # disable DAT and IRQs - spx zero64-.base(%r13) # absolute addressing mode + stnsm sys_msk-.base(%r13),0xfb # disable DAT stctg %c0,%c15,ctlregs-.base(%r13) stmg %r0,%r15,gprregs-.base(%r13) lghi %r0,3 @@ -100,8 +99,6 @@ lpsw 0 # hopefully start new kernel... .align 8 - zero64: - .quad 0 load_psw: .long 0x00080000,0x80000000 sys_msk: diff --git a/arch/s390/kernel/reset.S b/arch/s390/kernel/reset.S new file mode 100644 index 000000000000..be8688c0665c --- /dev/null +++ b/arch/s390/kernel/reset.S @@ -0,0 +1,48 @@ +/* + * arch/s390/kernel/reset.S + * + * Copyright (C) IBM Corp. 2006 + * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> + */ + +#include <asm/ptrace.h> +#include <asm/lowcore.h> + +#ifdef CONFIG_64BIT + + .globl reset_mcck_handler +reset_mcck_handler: + basr %r13,0 +0: lg %r15,__LC_PANIC_STACK # load panic stack + aghi %r15,-STACK_FRAME_OVERHEAD + lg %r1,s390_reset_mcck_handler-0b(%r13) + ltgr %r1,%r1 + jz 1f + basr %r14,%r1 +1: la %r1,4095 + lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1) + lpswe __LC_MCK_OLD_PSW + + .globl s390_reset_mcck_handler +s390_reset_mcck_handler: + .quad 0 + +#else /* CONFIG_64BIT */ + + .globl reset_mcck_handler +reset_mcck_handler: + basr %r13,0 +0: l %r15,__LC_PANIC_STACK # load panic stack + ahi %r15,-STACK_FRAME_OVERHEAD + l %r1,s390_reset_mcck_handler-0b(%r13) + ltr %r1,%r1 + jz 1f + basr %r14,%r1 +1: lm %r0,%r15,__LC_GPREGS_SAVE_AREA + lpsw __LC_MCK_OLD_PSW + + .globl s390_reset_mcck_handler +s390_reset_mcck_handler: + .long 0 + +#endif /* CONFIG_64BIT */ diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 2aa13e8e000a..b928fecdc743 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -62,13 +62,9 @@ EXPORT_SYMBOL_GPL(uaccess); unsigned int console_mode = 0; unsigned int console_devno = -1; unsigned int console_irq = -1; -unsigned long memory_size = 0; unsigned long machine_flags = 0; -struct { - unsigned long addr, size, type; -} memory_chunk[MEMORY_CHUNKS] = { { 0 } }; -#define CHUNK_READ_WRITE 0 -#define CHUNK_READ_ONLY 1 + +struct mem_chunk memory_chunk[MEMORY_CHUNKS]; volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ unsigned long __initdata zholes_size[MAX_NR_ZONES]; static unsigned long __initdata memory_end; @@ -229,11 +225,11 @@ static void __init conmode_default(void) char *ptr; if (MACHINE_IS_VM) { - __cpcmd("QUERY CONSOLE", query_buffer, 1024, NULL); + cpcmd("QUERY CONSOLE", query_buffer, 1024, NULL); console_devno = simple_strtoul(query_buffer + 5, NULL, 16); ptr = strstr(query_buffer, "SUBCHANNEL ="); console_irq = simple_strtoul(ptr + 13, NULL, 16); - __cpcmd("QUERY TERM", query_buffer, 1024, NULL); + cpcmd("QUERY TERM", query_buffer, 1024, NULL); ptr = strstr(query_buffer, "CONMODE"); /* * Set the conmode to 3215 so that the device recognition @@ -242,7 +238,7 @@ static void __init conmode_default(void) * 3215 and the 3270 driver will try to access the console * device (3215 as console and 3270 as normal tty). */ - __cpcmd("TERM CONMODE 3215", NULL, 0, NULL); + cpcmd("TERM CONMODE 3215", NULL, 0, NULL); if (ptr == NULL) { #if defined(CONFIG_SCLP_CONSOLE) SET_CONSOLE_SCLP; @@ -299,14 +295,14 @@ static void do_machine_restart_nonsmp(char * __unused) static void do_machine_halt_nonsmp(void) { if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) - cpcmd(vmhalt_cmd, NULL, 0, NULL); + __cpcmd(vmhalt_cmd, NULL, 0, NULL); signal_processor(smp_processor_id(), sigp_stop_and_store_status); } static void do_machine_power_off_nonsmp(void) { if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0) - cpcmd(vmpoff_cmd, NULL, 0, NULL); + __cpcmd(vmpoff_cmd, NULL, 0, NULL); signal_processor(smp_processor_id(), sigp_stop_and_store_status); } @@ -489,6 +485,37 @@ setup_resources(void) } } +static void __init setup_memory_end(void) +{ + unsigned long real_size, memory_size; + unsigned long max_mem, max_phys; + int i; + + memory_size = real_size = 0; + max_phys = VMALLOC_END - VMALLOC_MIN_SIZE; + memory_end &= PAGE_MASK; + + max_mem = memory_end ? min(max_phys, memory_end) : max_phys; + + for (i = 0; i < MEMORY_CHUNKS; i++) { + struct mem_chunk *chunk = &memory_chunk[i]; + + real_size = max(real_size, chunk->addr + chunk->size); + if (chunk->addr >= max_mem) { + memset(chunk, 0, sizeof(*chunk)); + continue; + } + if (chunk->addr + chunk->size > max_mem) + chunk->size = max_mem - chunk->addr; + memory_size = max(memory_size, chunk->addr + chunk->size); + } + if (!memory_end) + memory_end = memory_size; + if (real_size > memory_end) + printk("More memory detected than supported. Unused: %luk\n", + (real_size - memory_end) >> 10); +} + static void __init setup_memory(void) { @@ -645,8 +672,6 @@ setup_arch(char **cmdline_p) init_mm.end_data = (unsigned long) &_edata; init_mm.brk = (unsigned long) &_end; - memory_end = memory_size; - if (MACHINE_HAS_MVCOS) memcpy(&uaccess, &uaccess_mvcos, sizeof(uaccess)); else @@ -654,20 +679,7 @@ setup_arch(char **cmdline_p) parse_early_param(); -#ifndef CONFIG_64BIT - memory_end &= ~0x400000UL; - - /* - * We need some free virtual space to be able to do vmalloc. - * On a machine with 2GB memory we make sure that we have at - * least 128 MB free space for vmalloc. - */ - if (memory_end > 1920*1024*1024) - memory_end = 1920*1024*1024; -#else /* CONFIG_64BIT */ - memory_end &= ~0x200000UL; -#endif /* CONFIG_64BIT */ - + setup_memory_end(); setup_memory(); setup_resources(); setup_lowcore(); diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 62822245f9be..19090f7d4f51 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -230,18 +230,37 @@ static inline void do_store_status(void) } } +static inline void do_wait_for_stop(void) +{ + int cpu; + + /* Wait for all other cpus to enter stopped state */ + for_each_online_cpu(cpu) { + if (cpu == smp_processor_id()) + continue; + while(!smp_cpu_not_running(cpu)) + cpu_relax(); + } +} + /* * this function sends a 'stop' sigp to all other CPUs in the system. * it goes straight through. */ void smp_send_stop(void) { + /* Disable all interrupts/machine checks */ + __load_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK); + /* write magic number to zero page (absolute 0) */ lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC; /* stop other processors. */ do_send_stop(); + /* wait until other processors are stopped */ + do_wait_for_stop(); + /* store status of other processors. */ do_store_status(); } @@ -250,88 +269,28 @@ void smp_send_stop(void) * Reboot, halt and power_off routines for SMP. */ -static void do_machine_restart(void * __unused) -{ - int cpu; - static atomic_t cpuid = ATOMIC_INIT(-1); - - if (atomic_cmpxchg(&cpuid, -1, smp_processor_id()) != -1) - signal_processor(smp_processor_id(), sigp_stop); - - /* Wait for all other cpus to enter stopped state */ - for_each_online_cpu(cpu) { - if (cpu == smp_processor_id()) - continue; - while(!smp_cpu_not_running(cpu)) - cpu_relax(); - } - - /* Store status of other cpus. */ - do_store_status(); - - /* - * Finally call reipl. Because we waited for all other - * cpus to enter this function we know that they do - * not hold any s390irq-locks (the cpus have been - * interrupted by an external interrupt and s390irq - * locks are always held disabled). - */ - do_reipl(); -} - void machine_restart_smp(char * __unused) { - on_each_cpu(do_machine_restart, NULL, 0, 0); -} - -static void do_wait_for_stop(void) -{ - unsigned long cr[16]; - - __ctl_store(cr, 0, 15); - cr[0] &= ~0xffff; - cr[6] = 0; - __ctl_load(cr, 0, 15); - for (;;) - enabled_wait(); -} - -static void do_machine_halt(void * __unused) -{ - static atomic_t cpuid = ATOMIC_INIT(-1); - - if (atomic_cmpxchg(&cpuid, -1, smp_processor_id()) == -1) { - smp_send_stop(); - if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) - cpcmd(vmhalt_cmd, NULL, 0, NULL); - signal_processor(smp_processor_id(), - sigp_stop_and_store_status); - } - do_wait_for_stop(); + smp_send_stop(); + do_reipl(); } void machine_halt_smp(void) { - on_each_cpu(do_machine_halt, NULL, 0, 0); -} - -static void do_machine_power_off(void * __unused) -{ - static atomic_t cpuid = ATOMIC_INIT(-1); - - if (atomic_cmpxchg(&cpuid, -1, smp_processor_id()) == -1) { - smp_send_stop(); - if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0) - cpcmd(vmpoff_cmd, NULL, 0, NULL); - signal_processor(smp_processor_id(), - sigp_stop_and_store_status); - } - do_wait_for_stop(); + smp_send_stop(); + if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) + __cpcmd(vmhalt_cmd, NULL, 0, NULL); + signal_processor(smp_processor_id(), sigp_stop_and_store_status); + for (;;); } void machine_power_off_smp(void) { - on_each_cpu(do_machine_power_off, NULL, 0, 0); + smp_send_stop(); + if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0) + __cpcmd(vmpoff_cmd, NULL, 0, NULL); + signal_processor(smp_processor_id(), sigp_stop_and_store_status); + for (;;); } /* @@ -501,8 +460,6 @@ __init smp_count_cpus(void) */ extern void init_cpu_timer(void); extern void init_cpu_vtimer(void); -extern int pfault_init(void); -extern void pfault_fini(void); int __devinit start_secondary(void *cpuvoid) { @@ -514,11 +471,9 @@ int __devinit start_secondary(void *cpuvoid) #ifdef CONFIG_VIRT_TIMER init_cpu_vtimer(); #endif -#ifdef CONFIG_PFAULT /* Enable pfault pseudo page faults on this cpu. */ - if (MACHINE_IS_VM) - pfault_init(); -#endif + pfault_init(); + /* Mark this cpu as online */ cpu_set(smp_processor_id(), cpu_online_map); /* Switch on interrupts */ @@ -708,11 +663,8 @@ __cpu_disable(void) } cpu_clear(cpu, cpu_online_map); -#ifdef CONFIG_PFAULT /* Disable pfault pseudo page faults on this cpu. */ - if (MACHINE_IS_VM) - pfault_fini(); -#endif + pfault_fini(); memset(&cr_parms.orvals, 0, sizeof(cr_parms.orvals)); memset(&cr_parms.andvals, 0xff, sizeof(cr_parms.andvals)); @@ -860,4 +812,3 @@ EXPORT_SYMBOL(smp_ctl_clear_bit); EXPORT_SYMBOL(smp_call_function); EXPORT_SYMBOL(smp_get_cpu); EXPORT_SYMBOL(smp_put_cpu); - diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 92ecffbc8d82..3cbb0dcf1f1d 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -58,12 +58,6 @@ int sysctl_userprocess_debug = 0; extern pgm_check_handler_t do_protection_exception; extern pgm_check_handler_t do_dat_exception; -#ifdef CONFIG_PFAULT -extern int pfault_init(void); -extern void pfault_fini(void); -extern void pfault_interrupt(__u16 error_code); -static ext_int_info_t ext_int_pfault; -#endif extern pgm_check_handler_t do_monitor_call; #define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; }) @@ -135,7 +129,7 @@ __show_trace(unsigned long sp, unsigned long low, unsigned long high) } } -void show_trace(struct task_struct *task, unsigned long * stack) +void show_trace(struct task_struct *task, unsigned long *stack) { register unsigned long __r15 asm ("15"); unsigned long sp; @@ -157,6 +151,9 @@ void show_trace(struct task_struct *task, unsigned long * stack) __show_trace(sp, S390_lowcore.thread_info, S390_lowcore.thread_info + THREAD_SIZE); printk("\n"); + if (!task) + task = current; + debug_show_held_locks(task); } void show_stack(struct task_struct *task, unsigned long *sp) @@ -739,22 +736,5 @@ void __init trap_init(void) pgm_check_table[0x1C] = &space_switch_exception; pgm_check_table[0x1D] = &hfp_sqrt_exception; pgm_check_table[0x40] = &do_monitor_call; - - if (MACHINE_IS_VM) { -#ifdef CONFIG_PFAULT - /* - * Try to get pfault pseudo page faults going. - */ - if (register_early_external_interrupt(0x2603, pfault_interrupt, - &ext_int_pfault) != 0) - panic("Couldn't request external interrupt 0x2603"); - - if (pfault_init() == 0) - return; - - /* Tough luck, no pfault. */ - unregister_early_external_interrupt(0x2603, pfault_interrupt, - &ext_int_pfault); -#endif - } + pfault_irq_init(); } diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile index b0cfa6c4883d..b5f94cf3bde8 100644 --- a/arch/s390/lib/Makefile +++ b/arch/s390/lib/Makefile @@ -4,7 +4,7 @@ EXTRA_AFLAGS := -traditional -lib-y += delay.o string.o uaccess_std.o +lib-y += delay.o string.o uaccess_std.o uaccess_pt.o lib-$(CONFIG_32BIT) += div64.o lib-$(CONFIG_64BIT) += uaccess_mvcos.o lib-$(CONFIG_SMP) += spinlock.o diff --git a/arch/s390/lib/uaccess_mvcos.c b/arch/s390/lib/uaccess_mvcos.c index 121b2935a422..f9a23d57eb79 100644 --- a/arch/s390/lib/uaccess_mvcos.c +++ b/arch/s390/lib/uaccess_mvcos.c @@ -27,6 +27,9 @@ #define SLR "slgr" #endif +extern size_t copy_from_user_std(size_t, const void __user *, void *); +extern size_t copy_to_user_std(size_t, void __user *, const void *); + size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x) { register unsigned long reg0 asm("0") = 0x81UL; @@ -66,6 +69,13 @@ size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x) return size; } +size_t copy_from_user_mvcos_check(size_t size, const void __user *ptr, void *x) +{ + if (size <= 256) + return copy_from_user_std(size, ptr, x); + return copy_from_user_mvcos(size, ptr, x); +} + size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x) { register unsigned long reg0 asm("0") = 0x810000UL; @@ -95,6 +105,13 @@ size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x) return size; } +size_t copy_to_user_mvcos_check(size_t size, void __user *ptr, const void *x) +{ + if (size <= 256) + return copy_to_user_std(size, ptr, x); + return copy_to_user_mvcos(size, ptr, x); +} + size_t copy_in_user_mvcos(size_t size, void __user *to, const void __user *from) { register unsigned long reg0 asm("0") = 0x810081UL; @@ -145,18 +162,16 @@ size_t clear_user_mvcos(size_t size, void __user *to) return size; } -extern size_t copy_from_user_std_small(size_t, const void __user *, void *); -extern size_t copy_to_user_std_small(size_t, void __user *, const void *); extern size_t strnlen_user_std(size_t, const char __user *); extern size_t strncpy_from_user_std(size_t, const char __user *, char *); extern int futex_atomic_op(int, int __user *, int, int *); extern int futex_atomic_cmpxchg(int __user *, int, int); struct uaccess_ops uaccess_mvcos = { - .copy_from_user = copy_from_user_mvcos, - .copy_from_user_small = copy_from_user_std_small, - .copy_to_user = copy_to_user_mvcos, - .copy_to_user_small = copy_to_user_std_small, + .copy_from_user = copy_from_user_mvcos_check, + .copy_from_user_small = copy_from_user_std, + .copy_to_user = copy_to_user_mvcos_check, + .copy_to_user_small = copy_to_user_std, .copy_in_user = copy_in_user_mvcos, .clear_user = clear_user_mvcos, .strnlen_user = strnlen_user_std, diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c new file mode 100644 index 000000000000..8741bdc09299 --- /dev/null +++ b/arch/s390/lib/uaccess_pt.c @@ -0,0 +1,153 @@ +/* + * arch/s390/lib/uaccess_pt.c + * + * User access functions based on page table walks. + * + * Copyright IBM Corp. 2006 + * Author(s): Gerald Schaefer (gerald.schaefer@de.ibm.com) + */ + +#include <linux/errno.h> +#include <asm/uaccess.h> +#include <linux/mm.h> +#include <asm/futex.h> + +static inline int __handle_fault(struct mm_struct *mm, unsigned long address, + int write_access) +{ + struct vm_area_struct *vma; + int ret = -EFAULT; + + down_read(&mm->mmap_sem); + vma = find_vma(mm, address); + if (unlikely(!vma)) + goto out; + if (unlikely(vma->vm_start > address)) { + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto out; + if (expand_stack(vma, address)) + goto out; + } + + if (!write_access) { + /* page not present, check vm flags */ + if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) + goto out; + } else { + if (!(vma->vm_flags & VM_WRITE)) + goto out; + } + +survive: + switch (handle_mm_fault(mm, vma, address, write_access)) { + case VM_FAULT_MINOR: + current->min_flt++; + break; + case VM_FAULT_MAJOR: + current->maj_flt++; + break; + case VM_FAULT_SIGBUS: + goto out_sigbus; + case VM_FAULT_OOM: + goto out_of_memory; + default: + BUG(); + } + ret = 0; +out: + up_read(&mm->mmap_sem); + return ret; + +out_of_memory: + up_read(&mm->mmap_sem); + if (current->pid == 1) { + yield(); + goto survive; + } + printk("VM: killing process %s\n", current->comm); + return ret; + +out_sigbus: + up_read(&mm->mmap_sem); + current->thread.prot_addr = address; + current->thread.trap_no = 0x11; + force_sig(SIGBUS, current); + return ret; +} + +static inline size_t __user_copy_pt(unsigned long uaddr, void *kptr, + size_t n, int write_user) +{ + struct mm_struct *mm = current->mm; + unsigned long offset, pfn, done, size; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + void *from, *to; + + done = 0; +retry: + spin_lock(&mm->page_table_lock); + do { + pgd = pgd_offset(mm, uaddr); + if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) + goto fault; + + pmd = pmd_offset(pgd, uaddr); + if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) + goto fault; + + pte = pte_offset_map(pmd, uaddr); + if (!pte || !pte_present(*pte) || + (write_user && !pte_write(*pte))) + goto fault; + + pfn = pte_pfn(*pte); + if (!pfn_valid(pfn)) + goto out; + + offset = uaddr & (PAGE_SIZE - 1); + size = min(n - done, PAGE_SIZE - offset); + if (write_user) { + to = (void *)((pfn << PAGE_SHIFT) + offset); + from = kptr + done; + } else { + from = (void *)((pfn << PAGE_SHIFT) + offset); + to = kptr + done; + } + memcpy(to, from, size); + done += size; + uaddr += size; + } while (done < n); +out: + spin_unlock(&mm->page_table_lock); + return n - done; +fault: + spin_unlock(&mm->page_table_lock); + if (__handle_fault(mm, uaddr, write_user)) + return n - done; + goto retry; +} + +size_t copy_from_user_pt(size_t n, const void __user *from, void *to) +{ + size_t rc; + + if (segment_eq(get_fs(), KERNEL_DS)) { + memcpy(to, (void __kernel __force *) from, n); + return 0; + } + rc = __user_copy_pt((unsigned long) from, to, n, 0); + if (unlikely(rc)) + memset(to + n - rc, 0, rc); + return rc; +} + +size_t copy_to_user_pt(size_t n, void __user *to, const void *from) +{ + if (segment_eq(get_fs(), KERNEL_DS)) { + memcpy((void __kernel __force *) to, from, n); + return 0; + } + return __user_copy_pt((unsigned long) to, (void *) from, n, 1); +} diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c index f44f0078b354..2d549ed2e113 100644 --- a/arch/s390/lib/uaccess_std.c +++ b/arch/s390/lib/uaccess_std.c @@ -28,6 +28,9 @@ #define SLR "slgr" #endif +extern size_t copy_from_user_pt(size_t n, const void __user *from, void *to); +extern size_t copy_to_user_pt(size_t n, void __user *to, const void *from); + size_t copy_from_user_std(size_t size, const void __user *ptr, void *x) { unsigned long tmp1, tmp2; @@ -69,34 +72,11 @@ size_t copy_from_user_std(size_t size, const void __user *ptr, void *x) return size; } -size_t copy_from_user_std_small(size_t size, const void __user *ptr, void *x) +size_t copy_from_user_std_check(size_t size, const void __user *ptr, void *x) { - unsigned long tmp1, tmp2; - - tmp1 = 0UL; - asm volatile( - "0: mvcp 0(%0,%2),0(%1),%3\n" - " "SLR" %0,%0\n" - " j 5f\n" - "1: la %4,255(%1)\n" /* %4 = ptr + 255 */ - " "LHI" %3,-4096\n" - " nr %4,%3\n" /* %4 = (ptr + 255) & -4096 */ - " "SLR" %4,%1\n" - " "CLR" %0,%4\n" /* copy crosses next page boundary? */ - " jnh 5f\n" - "2: mvcp 0(%4,%2),0(%1),%3\n" - " "SLR" %0,%4\n" - " "ALR" %2,%4\n" - "3:"LHI" %4,-1\n" - " "ALR" %4,%0\n" /* copy remaining size, subtract 1 */ - " bras %3,4f\n" - " xc 0(1,%2),0(%2)\n" - "4: ex %4,0(%3)\n" - "5:\n" - EX_TABLE(0b,1b) EX_TABLE(2b,3b) - : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2) - : : "cc", "memory"); - return size; + if (size <= 1024) + return copy_from_user_std(size, ptr, x); + return copy_from_user_pt(size, ptr, x); } size_t copy_to_user_std(size_t size, void __user *ptr, const void *x) @@ -130,28 +110,11 @@ size_t copy_to_user_std(size_t size, void __user *ptr, const void *x) return size; } -size_t copy_to_user_std_small(size_t size, void __user *ptr, const void *x) +size_t copy_to_user_std_check(size_t size, void __user *ptr, const void *x) { - unsigned long tmp1, tmp2; - - tmp1 = 0UL; - asm volatile( - "0: mvcs 0(%0,%1),0(%2),%3\n" - " "SLR" %0,%0\n" - " j 3f\n" - "1: la %4,255(%1)\n" /* ptr + 255 */ - " "LHI" %3,-4096\n" - " nr %4,%3\n" /* (ptr + 255) & -4096UL */ - " "SLR" %4,%1\n" - " "CLR" %0,%4\n" /* copy crosses next page boundary? */ - " jnh 3f\n" - "2: mvcs 0(%4,%1),0(%2),%3\n" - " "SLR" %0,%4\n" - "3:\n" - EX_TABLE(0b,1b) EX_TABLE(2b,3b) - : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2) - : : "cc", "memory"); - return size; + if (size <= 1024) + return copy_to_user_std(size, ptr, x); + return copy_to_user_pt(size, ptr, x); } size_t copy_in_user_std(size_t size, void __user *to, const void __user *from) @@ -343,10 +306,10 @@ int futex_atomic_cmpxchg(int __user *uaddr, int oldval, int newval) } struct uaccess_ops uaccess_std = { - .copy_from_user = copy_from_user_std, - .copy_from_user_small = copy_from_user_std_small, - .copy_to_user = copy_to_user_std, - .copy_to_user_small = copy_to_user_std_small, + .copy_from_user = copy_from_user_std_check, + .copy_from_user_small = copy_from_user_std, + .copy_to_user = copy_to_user_std_check, + .copy_to_user_small = copy_to_user_std, .copy_in_user = copy_in_user_std, .clear_user = clear_user_std, .strnlen_user = strnlen_user_std, diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index 226275d5c4f6..9e9bc48463a5 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c @@ -14,12 +14,13 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/bootmem.h> +#include <linux/ctype.h> #include <asm/page.h> #include <asm/ebcdic.h> #include <asm/errno.h> #include <asm/extmem.h> #include <asm/cpcmd.h> -#include <linux/ctype.h> +#include <asm/setup.h> #define DCSS_DEBUG /* Debug messages on/off */ @@ -77,15 +78,11 @@ struct dcss_segment { int segcnt; }; -static DEFINE_SPINLOCK(dcss_lock); +static DEFINE_MUTEX(dcss_lock); static struct list_head dcss_list = LIST_HEAD_INIT(dcss_list); static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC", "EW/EN-MIXED" }; -extern struct { - unsigned long addr, size, type; -} memory_chunk[MEMORY_CHUNKS]; - /* * Create the 8 bytes, ebcdic VM segment name from * an ascii name. @@ -117,7 +114,7 @@ segment_by_name (char *name) struct list_head *l; struct dcss_segment *tmp, *retval = NULL; - assert_spin_locked(&dcss_lock); + BUG_ON(!mutex_is_locked(&dcss_lock)); dcss_mkname (name, dcss_name); list_for_each (l, &dcss_list) { tmp = list_entry (l, struct dcss_segment, list); @@ -249,8 +246,8 @@ segment_overlaps_storage(struct dcss_segment *seg) { int i; - for (i=0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) { - if (memory_chunk[i].type != 0) + for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) { + if (memory_chunk[i].type != CHUNK_READ_WRITE) continue; if ((memory_chunk[i].addr >> 20) > (seg->end >> 20)) continue; @@ -272,7 +269,7 @@ segment_overlaps_others (struct dcss_segment *seg) struct list_head *l; struct dcss_segment *tmp; - assert_spin_locked(&dcss_lock); + BUG_ON(!mutex_is_locked(&dcss_lock)); list_for_each(l, &dcss_list) { tmp = list_entry(l, struct dcss_segment, list); if ((tmp->start_addr >> 20) > (seg->end >> 20)) @@ -429,7 +426,7 @@ segment_load (char *name, int do_nonshared, unsigned long *addr, if (!MACHINE_IS_VM) return -ENOSYS; - spin_lock (&dcss_lock); + mutex_lock(&dcss_lock); seg = segment_by_name (name); if (seg == NULL) rc = __segment_load (name, do_nonshared, addr, end); @@ -444,7 +441,7 @@ segment_load (char *name, int do_nonshared, unsigned long *addr, rc = -EPERM; } } - spin_unlock (&dcss_lock); + mutex_unlock(&dcss_lock); return rc; } @@ -467,7 +464,7 @@ segment_modify_shared (char *name, int do_nonshared) unsigned long dummy; int dcss_command, rc, diag_cc; - spin_lock (&dcss_lock); + mutex_lock(&dcss_lock); seg = segment_by_name (name); if (seg == NULL) { rc = -EINVAL; @@ -508,7 +505,7 @@ segment_modify_shared (char *name, int do_nonshared) &dummy, &dummy); kfree(seg); out_unlock: - spin_unlock(&dcss_lock); + mutex_unlock(&dcss_lock); return rc; } @@ -526,7 +523,7 @@ segment_unload(char *name) if (!MACHINE_IS_VM) return; - spin_lock(&dcss_lock); + mutex_lock(&dcss_lock); seg = segment_by_name (name); if (seg == NULL) { PRINT_ERR ("could not find segment %s in segment_unload, " @@ -540,7 +537,7 @@ segment_unload(char *name) kfree(seg); } out_unlock: - spin_unlock(&dcss_lock); + mutex_unlock(&dcss_lock); } /* @@ -559,12 +556,13 @@ segment_save(char *name) if (!MACHINE_IS_VM) return; - spin_lock(&dcss_lock); + mutex_lock(&dcss_lock); seg = segment_by_name (name); if (seg == NULL) { - PRINT_ERR ("could not find segment %s in segment_save, please report to linux390@de.ibm.com\n",name); - return; + PRINT_ERR("could not find segment %s in segment_save, please " + "report to linux390@de.ibm.com\n", name); + goto out; } startpfn = seg->start_addr >> PAGE_SHIFT; @@ -591,7 +589,7 @@ segment_save(char *name) goto out; } out: - spin_unlock(&dcss_lock); + mutex_unlock(&dcss_lock); } EXPORT_SYMBOL(segment_load); diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 1c323bbfda91..cd85e34d8703 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -31,6 +31,7 @@ #include <asm/uaccess.h> #include <asm/pgtable.h> #include <asm/kdebug.h> +#include <asm/s390_ext.h> #ifndef CONFIG_64BIT #define __FAIL_ADDR_MASK 0x7ffff000 @@ -394,6 +395,7 @@ void do_dat_exception(struct pt_regs *regs, unsigned long error_code) /* * 'pfault' pseudo page faults routines. */ +static ext_int_info_t ext_int_pfault; static int pfault_disable = 0; static int __init nopfault(char *str) @@ -422,7 +424,7 @@ int pfault_init(void) __PF_RES_FIELD }; int rc; - if (pfault_disable) + if (!MACHINE_IS_VM || pfault_disable) return -1; asm volatile( " diag %1,%0,0x258\n" @@ -440,7 +442,7 @@ void pfault_fini(void) pfault_refbk_t refbk = { 0x258, 1, 5, 2, 0ULL, 0ULL, 0ULL, 0ULL }; - if (pfault_disable) + if (!MACHINE_IS_VM || pfault_disable) return; __ctl_clear_bit(0,9); asm volatile( @@ -500,5 +502,25 @@ pfault_interrupt(__u16 error_code) set_tsk_need_resched(tsk); } } -#endif +void __init pfault_irq_init(void) +{ + if (!MACHINE_IS_VM) + return; + + /* + * Try to get pfault pseudo page faults going. + */ + if (register_early_external_interrupt(0x2603, pfault_interrupt, + &ext_int_pfault) != 0) + panic("Couldn't request external interrupt 0x2603"); + + if (pfault_init() == 0) + return; + + /* Tough luck, no pfault. */ + pfault_disable = 1; + unregister_early_external_interrupt(0x2603, pfault_interrupt, + &ext_int_pfault); +} +#endif diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 578b99b71d9c..bf5b79ed3613 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -27,6 +27,7 @@ #include <linux/init.h> #include <linux/types.h> #include <linux/notifier.h> +#include <linux/jiffies.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 03f6338acc8f..984ab284382a 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -328,6 +328,15 @@ config PATA_TRIFLEX If unsure, say N. +config PATA_MARVELL + tristate "Marvell PATA support via legacy mode" + depends on PCI + help + This option enables limited support for the Marvell 88SE6145 ATA + controller. + + If unsure, say N. + config PATA_MPIIX tristate "Intel PATA MPIIX support" depends on PCI @@ -483,6 +492,32 @@ config PATA_WINBOND If unsure, say N. +config PATA_WINBOND_VLB + tristate "Winbond W83759A VLB PATA support (Experimental)" + depends on ISA && EXPERIMENTAL + help + Support for the Winbond W83759A controller on Vesa Local Bus + systems. + +config PATA_PLATFORM + tristate "Generic platform device PATA support" + depends on EMBEDDED + help + This option enables support for generic directly connected ATA + devices commonly found on embedded systems. + + If unsure, say N. + +config PATA_IXP4XX_CF + tristate "IXP4XX Compact Flash support" + depends on ARCH_IXP4XX + help + This option enables support for a Compact Flash connected on + the ixp4xx expansion bus. This driver had been written for + Loft/Avila boards in mind but can work with others. + + If unsure, say N. + endif endmenu diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 72243a677f9b..bc3d81ae757e 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o obj-$(CONFIG_PATA_OPTI) += pata_opti.o obj-$(CONFIG_PATA_OPTIDMA) += pata_optidma.o +obj-$(CONFIG_PATA_MARVELL) += pata_marvell.o obj-$(CONFIG_PATA_MPIIX) += pata_mpiix.o obj-$(CONFIG_PATA_OLDPIIX) += pata_oldpiix.o obj-$(CONFIG_PATA_PCMCIA) += pata_pcmcia.o @@ -51,8 +52,11 @@ obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o obj-$(CONFIG_PATA_SIL680) += pata_sil680.o obj-$(CONFIG_PATA_VIA) += pata_via.o obj-$(CONFIG_PATA_WINBOND) += pata_sl82c105.o +obj-$(CONFIG_PATA_WINBOND_VLB) += pata_winbond.o obj-$(CONFIG_PATA_SIS) += pata_sis.o obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o +obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o +obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o # Should be last but one libata driver obj-$(CONFIG_ATA_GENERIC) += ata_generic.o # Should be last libata driver diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index bddb14e91d3c..f36da488a2c1 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -53,6 +53,7 @@ enum { AHCI_PCI_BAR = 5, + AHCI_MAX_PORTS = 32, AHCI_MAX_SG = 168, /* hardware max is 64K */ AHCI_DMA_BOUNDARY = 0xffffffff, AHCI_USE_CLUSTERING = 0, @@ -77,8 +78,9 @@ enum { RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */ board_ahci = 0, - board_ahci_vt8251 = 1, - board_ahci_ign_iferr = 2, + board_ahci_pi = 1, + board_ahci_vt8251 = 2, + board_ahci_ign_iferr = 3, /* global controller registers */ HOST_CAP = 0x00, /* host capabilities */ @@ -167,9 +169,9 @@ enum { AHCI_FLAG_MSI = (1 << 0), /* ap->flags bits */ - AHCI_FLAG_RESET_NEEDS_CLO = (1 << 24), - AHCI_FLAG_NO_NCQ = (1 << 25), - AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 26), /* ignore IRQ_IF_ERR */ + AHCI_FLAG_NO_NCQ = (1 << 24), + AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 25), /* ignore IRQ_IF_ERR */ + AHCI_FLAG_HONOR_PI = (1 << 26), /* honor PORTS_IMPL */ }; struct ahci_cmd_hdr { @@ -216,6 +218,7 @@ static u8 ahci_check_status(struct ata_port *ap); static void ahci_freeze(struct ata_port *ap); static void ahci_thaw(struct ata_port *ap); static void ahci_error_handler(struct ata_port *ap); +static void ahci_vt8251_error_handler(struct ata_port *ap); static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg); static int ahci_port_resume(struct ata_port *ap); @@ -275,6 +278,37 @@ static const struct ata_port_operations ahci_ops = { .port_stop = ahci_port_stop, }; +static const struct ata_port_operations ahci_vt8251_ops = { + .port_disable = ata_port_disable, + + .check_status = ahci_check_status, + .check_altstatus = ahci_check_status, + .dev_select = ata_noop_dev_select, + + .tf_read = ahci_tf_read, + + .qc_prep = ahci_qc_prep, + .qc_issue = ahci_qc_issue, + + .irq_handler = ahci_interrupt, + .irq_clear = ahci_irq_clear, + + .scr_read = ahci_scr_read, + .scr_write = ahci_scr_write, + + .freeze = ahci_freeze, + .thaw = ahci_thaw, + + .error_handler = ahci_vt8251_error_handler, + .post_internal_cmd = ahci_post_internal_cmd, + + .port_suspend = ahci_port_suspend, + .port_resume = ahci_port_resume, + + .port_start = ahci_port_start, + .port_stop = ahci_port_stop, +}; + static const struct ata_port_info ahci_port_info[] = { /* board_ahci */ { @@ -286,16 +320,26 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &ahci_ops, }, + /* board_ahci_pi */ + { + .sht = &ahci_sht, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | + ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI, + .pio_mask = 0x1f, /* pio0-4 */ + .udma_mask = 0x7f, /* udma0-6 ; FIXME */ + .port_ops = &ahci_ops, + }, /* board_ahci_vt8251 */ { .sht = &ahci_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | ATA_FLAG_SKIP_D2H_BSY | - AHCI_FLAG_RESET_NEEDS_CLO | AHCI_FLAG_NO_NCQ, + ATA_FLAG_HRST_TO_RESUME | AHCI_FLAG_NO_NCQ, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ - .port_ops = &ahci_ops, + .port_ops = &ahci_vt8251_ops, }, /* board_ahci_ign_iferr */ { @@ -322,22 +366,22 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */ { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */ { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */ - { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */ - { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */ - { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */ - { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */ - { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */ - { PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */ - { PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */ - { PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */ - { PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */ - { PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x2821), board_ahci_pi }, /* ICH8 */ + { PCI_VDEVICE(INTEL, 0x2822), board_ahci_pi }, /* ICH8 */ + { PCI_VDEVICE(INTEL, 0x2824), board_ahci_pi }, /* ICH8 */ + { PCI_VDEVICE(INTEL, 0x2829), board_ahci_pi }, /* ICH8M */ + { PCI_VDEVICE(INTEL, 0x282a), board_ahci_pi }, /* ICH8M */ + { PCI_VDEVICE(INTEL, 0x2922), board_ahci_pi }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2923), board_ahci_pi }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2924), board_ahci_pi }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2925), board_ahci_pi }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2927), board_ahci_pi }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2929), board_ahci_pi }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x292a), board_ahci_pi }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x292b), board_ahci_pi }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x292f), board_ahci_pi }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x294d), board_ahci_pi }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x294e), board_ahci_pi }, /* ICH9M */ /* JMicron */ { PCI_VDEVICE(JMICRON, 0x2360), board_ahci_ign_iferr }, /* JMB360 */ @@ -372,6 +416,10 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */ { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */ + /* Generic, PCI class code for AHCI */ + { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + 0x010601, 0xffffff, board_ahci }, + { } /* terminate list */ }; @@ -386,6 +434,11 @@ static struct pci_driver ahci_pci_driver = { }; +static inline int ahci_nr_ports(u32 cap) +{ + return (cap & 0x1f) + 1; +} + static inline unsigned long ahci_port_base_ul (unsigned long base, unsigned int port) { return base + 0x100 + (port * 0x80); @@ -559,9 +612,6 @@ static void ahci_power_down(void __iomem *port_mmio, u32 cap) static void ahci_init_port(void __iomem *port_mmio, u32 cap, dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma) { - /* power up */ - ahci_power_up(port_mmio, cap); - /* enable FIS reception */ ahci_start_fis_rx(port_mmio, cap, cmd_slot_dma, rx_fis_dma); @@ -587,19 +637,17 @@ static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg) return rc; } - /* put device into slumber mode */ - ahci_power_down(port_mmio, cap); - return 0; } static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev) { - u32 cap_save, tmp; + u32 cap_save, impl_save, tmp; cap_save = readl(mmio + HOST_CAP); cap_save &= ( (1<<28) | (1<<17) ); cap_save |= (1 << 27); + impl_save = readl(mmio + HOST_PORTS_IMPL); /* global controller reset */ tmp = readl(mmio + HOST_CTL); @@ -620,10 +668,21 @@ static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev) return -EIO; } + /* turn on AHCI mode */ writel(HOST_AHCI_EN, mmio + HOST_CTL); (void) readl(mmio + HOST_CTL); /* flush */ + + /* These write-once registers are normally cleared on reset. + * Restore BIOS values... which we HOPE were present before + * reset. + */ + if (!impl_save) { + impl_save = (1 << ahci_nr_ports(cap_save)) - 1; + dev_printk(KERN_WARNING, &pdev->dev, + "PORTS_IMPL is zero, forcing 0x%x\n", impl_save); + } writel(cap_save, mmio + HOST_CAP); - writel(0xf, mmio + HOST_PORTS_IMPL); + writel(impl_save, mmio + HOST_PORTS_IMPL); (void) readl(mmio + HOST_PORTS_IMPL); /* flush */ if (pdev->vendor == PCI_VENDOR_ID_INTEL) { @@ -639,7 +698,8 @@ static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev) } static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev, - int n_ports, u32 cap) + int n_ports, unsigned int port_flags, + struct ahci_host_priv *hpriv) { int i, rc; u32 tmp; @@ -648,13 +708,12 @@ static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev, void __iomem *port_mmio = ahci_port_base(mmio, i); const char *emsg = NULL; -#if 0 /* BIOSen initialize this incorrectly */ - if (!(hpriv->port_map & (1 << i))) + if ((port_flags & AHCI_FLAG_HONOR_PI) && + !(hpriv->port_map & (1 << i))) continue; -#endif /* make sure port is not active */ - rc = ahci_deinit_port(port_mmio, cap, &emsg); + rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg); if (rc) dev_printk(KERN_WARNING, &pdev->dev, "%s (%d)\n", emsg, rc); @@ -729,17 +788,6 @@ static int ahci_clo(struct ata_port *ap) return 0; } -static int ahci_prereset(struct ata_port *ap) -{ - if ((ap->flags & AHCI_FLAG_RESET_NEEDS_CLO) && - (ata_busy_wait(ap, ATA_BUSY, 1000) & ATA_BUSY)) { - /* ATA_BUSY hasn't cleared, so send a CLO */ - ahci_clo(ap); - } - - return ata_std_prereset(ap); -} - static int ahci_softreset(struct ata_port *ap, unsigned int *class) { struct ahci_port_priv *pp = ap->private_data; @@ -877,6 +925,31 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class) return rc; } +static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class) +{ + void __iomem *mmio = ap->host->mmio_base; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); + int rc; + + DPRINTK("ENTER\n"); + + ahci_stop_engine(port_mmio); + + rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context)); + + /* vt8251 needs SError cleared for the port to operate */ + ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR)); + + ahci_start_engine(port_mmio); + + DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); + + /* vt8251 doesn't clear BSY on signature FIS reception, + * request follow-up softreset. + */ + return rc ?: -EAGAIN; +} + static void ahci_postreset(struct ata_port *ap, unsigned int *class) { void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; @@ -1196,7 +1269,23 @@ static void ahci_error_handler(struct ata_port *ap) } /* perform recovery */ - ata_do_eh(ap, ahci_prereset, ahci_softreset, ahci_hardreset, + ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset, + ahci_postreset); +} + +static void ahci_vt8251_error_handler(struct ata_port *ap) +{ + void __iomem *mmio = ap->host->mmio_base; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); + + if (!(ap->pflags & ATA_PFLAG_FROZEN)) { + /* restart engine */ + ahci_stop_engine(port_mmio); + ahci_start_engine(port_mmio); + } + + /* perform recovery */ + ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_vt8251_hardreset, ahci_postreset); } @@ -1226,7 +1315,9 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) int rc; rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg); - if (rc) { + if (rc == 0) + ahci_power_down(port_mmio, hpriv->cap); + else { ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc); ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma); @@ -1242,6 +1333,7 @@ static int ahci_port_resume(struct ata_port *ap) void __iomem *mmio = ap->host->mmio_base; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); + ahci_power_up(port_mmio, hpriv->cap); ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma); return 0; @@ -1281,7 +1373,8 @@ static int ahci_pci_device_resume(struct pci_dev *pdev) if (rc) return rc; - ahci_init_controller(mmio, pdev, host->n_ports, hpriv->cap); + ahci_init_controller(mmio, pdev, host->n_ports, + host->ports[0]->flags, hpriv); } ata_host_resume(host); @@ -1347,6 +1440,9 @@ static int ahci_port_start(struct ata_port *ap) ap->private_data = pp; + /* power up port */ + ahci_power_up(port_mmio, hpriv->cap); + /* initialize port */ ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma); @@ -1393,7 +1489,7 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) struct ahci_host_priv *hpriv = probe_ent->private_data; struct pci_dev *pdev = to_pci_dev(probe_ent->dev); void __iomem *mmio = probe_ent->mmio_base; - unsigned int i, using_dac; + unsigned int i, cap_n_ports, using_dac; int rc; rc = ahci_reset_controller(mmio, pdev); @@ -1402,10 +1498,34 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) hpriv->cap = readl(mmio + HOST_CAP); hpriv->port_map = readl(mmio + HOST_PORTS_IMPL); - probe_ent->n_ports = (hpriv->cap & 0x1f) + 1; + cap_n_ports = ahci_nr_ports(hpriv->cap); VPRINTK("cap 0x%x port_map 0x%x n_ports %d\n", - hpriv->cap, hpriv->port_map, probe_ent->n_ports); + hpriv->cap, hpriv->port_map, cap_n_ports); + + if (probe_ent->port_flags & AHCI_FLAG_HONOR_PI) { + unsigned int n_ports = cap_n_ports; + u32 port_map = hpriv->port_map; + int max_port = 0; + + for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) { + if (port_map & (1 << i)) { + n_ports--; + port_map &= ~(1 << i); + max_port = i; + } else + probe_ent->dummy_port_mask |= 1 << i; + } + + if (n_ports || port_map) + dev_printk(KERN_WARNING, &pdev->dev, + "nr_ports (%u) and implemented port map " + "(0x%x) don't match\n", + cap_n_ports, hpriv->port_map); + + probe_ent->n_ports = max_port + 1; + } else + probe_ent->n_ports = cap_n_ports; using_dac = hpriv->cap & HOST_CAP_64; if (using_dac && @@ -1437,7 +1557,8 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) for (i = 0; i < probe_ent->n_ports; i++) ahci_setup_port(&probe_ent->port[i], (unsigned long) mmio, i); - ahci_init_controller(mmio, pdev, probe_ent->n_ports, hpriv->cap); + ahci_init_controller(mmio, pdev, probe_ent->n_ports, + probe_ent->port_flags, hpriv); pci_set_master(pdev); diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index 4a80ff9312b8..908751d27e76 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -26,7 +26,7 @@ #include <linux/libata.h> #define DRV_NAME "ata_generic" -#define DRV_VERSION "0.2.6" +#define DRV_VERSION "0.2.10" /* * A generic parallel ATA driver using libata @@ -109,7 +109,6 @@ static struct scsi_host_template generic_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -118,6 +117,8 @@ static struct scsi_host_template generic_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations generic_port_ops = { @@ -226,12 +227,14 @@ static struct pci_driver ata_generic_pci_driver = { .name = DRV_NAME, .id_table = ata_generic, .probe = ata_generic_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init ata_generic_init(void) { - return pci_module_init(&ata_generic_pci_driver); + return pci_register_driver(&ata_generic_pci_driver); } diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 720174d628fa..c7de0bb1591f 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -40,7 +40,7 @@ * Documentation * Publically available from Intel web site. Errata documentation * is also publically available. As an aide to anyone hacking on this - * driver the list of errata that are relevant is below.going back to + * driver the list of errata that are relevant is below, going back to * PIIX4. Older device documentation is now a bit tricky to find. * * The chipsets all follow very much the same design. The orginal Triton @@ -93,7 +93,7 @@ #include <linux/libata.h> #define DRV_NAME "ata_piix" -#define DRV_VERSION "2.00ac6" +#define DRV_VERSION "2.00ac7" enum { PIIX_IOCFG = 0x54, /* IDE I/O configuration register */ @@ -101,11 +101,13 @@ enum { ICH5_PCS = 0x92, /* port control and status */ PIIX_SCC = 0x0A, /* sub-class code register */ - PIIX_FLAG_IGNORE_PCS = (1 << 25), /* ignore PCS present bits */ PIIX_FLAG_SCR = (1 << 26), /* SCR available */ PIIX_FLAG_AHCI = (1 << 27), /* AHCI possible */ PIIX_FLAG_CHECKINTR = (1 << 28), /* make sure PCI INTx enabled */ + PIIX_PATA_FLAGS = ATA_FLAG_SLAVE_POSS, + PIIX_SATA_FLAGS = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR, + /* combined mode. if set, PATA is channel 0. * if clear, PATA is channel 1. */ @@ -122,11 +124,10 @@ enum { ich_pata_100 = 3, /* ICH up to UDMA 100 */ ich_pata_133 = 4, /* ICH up to UDMA 133 */ ich5_sata = 5, - esb_sata = 6, - ich6_sata = 7, - ich6_sata_ahci = 8, - ich6m_sata_ahci = 9, - ich8_sata_ahci = 10, + ich6_sata = 6, + ich6_sata_ahci = 7, + ich6m_sata_ahci = 8, + ich8_sata_ahci = 9, /* constants for mapping table */ P0 = 0, /* port 0 */ @@ -143,13 +144,11 @@ enum { struct piix_map_db { const u32 mask; const u16 port_enable; - const int present_shift; const int map[][4]; }; struct piix_host_priv { const int *map; - const struct piix_map_db *map_db; }; static int piix_init_one (struct pci_dev *pdev, @@ -214,9 +213,9 @@ static const struct pci_device_id piix_pci_tbl[] = { /* 82801EB (ICH5) */ { 0x8086, 0x24df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, /* 6300ESB (ICH5 variant with broken PCS present bits) */ - { 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb_sata }, + { 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, /* 6300ESB pretending RAID */ - { 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb_sata }, + { 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, /* 82801FB/FW (ICH6/ICH6W) */ { 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata }, /* 82801FR/FRW (ICH6R/ICH6RW) */ @@ -367,7 +366,6 @@ static const struct ata_port_operations piix_sata_ops = { static const struct piix_map_db ich5_map_db = { .mask = 0x7, .port_enable = 0x3, - .present_shift = 4, .map = { /* PM PS SM SS MAP */ { P0, NA, P1, NA }, /* 000b */ @@ -384,7 +382,6 @@ static const struct piix_map_db ich5_map_db = { static const struct piix_map_db ich6_map_db = { .mask = 0x3, .port_enable = 0xf, - .present_shift = 4, .map = { /* PM PS SM SS MAP */ { P0, P2, P1, P3 }, /* 00b */ @@ -397,7 +394,6 @@ static const struct piix_map_db ich6_map_db = { static const struct piix_map_db ich6m_map_db = { .mask = 0x3, .port_enable = 0x5, - .present_shift = 4, /* Map 01b isn't specified in the doc but some notebooks use * it anyway. MAP 01b have been spotted on both ICH6M and @@ -415,7 +411,6 @@ static const struct piix_map_db ich6m_map_db = { static const struct piix_map_db ich8_map_db = { .mask = 0x3, .port_enable = 0x3, - .present_shift = 8, .map = { /* PM PS SM SS MAP */ { P0, P2, P1, P3 }, /* 00b (hardwired when in AHCI) */ @@ -427,7 +422,6 @@ static const struct piix_map_db ich8_map_db = { static const struct piix_map_db *piix_map_db_table[] = { [ich5_sata] = &ich5_map_db, - [esb_sata] = &ich5_map_db, [ich6_sata] = &ich6_map_db, [ich6_sata_ahci] = &ich6_map_db, [ich6m_sata_ahci] = &ich6m_map_db, @@ -438,7 +432,7 @@ static struct ata_port_info piix_port_info[] = { /* piix_pata_33: 0: PIIX3 or 4 at 33MHz */ { .sht = &piix_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = PIIX_PATA_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */ .udma_mask = ATA_UDMA_MASK_40C, @@ -448,7 +442,7 @@ static struct ata_port_info piix_port_info[] = { /* ich_pata_33: 1 ICH0 - ICH at 33Mhz*/ { .sht = &piix_sht, - .flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS, + .flags = PIIX_PATA_FLAGS, .pio_mask = 0x1f, /* pio 0-4 */ .mwdma_mask = 0x06, /* Check: maybe 0x07 */ .udma_mask = ATA_UDMA2, /* UDMA33 */ @@ -457,7 +451,7 @@ static struct ata_port_info piix_port_info[] = { /* ich_pata_66: 2 ICH controllers up to 66MHz */ { .sht = &piix_sht, - .flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS, + .flags = PIIX_PATA_FLAGS, .pio_mask = 0x1f, /* pio 0-4 */ .mwdma_mask = 0x06, /* MWDMA0 is broken on chip */ .udma_mask = ATA_UDMA4, @@ -467,7 +461,7 @@ static struct ata_port_info piix_port_info[] = { /* ich_pata_100: 3 */ { .sht = &piix_sht, - .flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS | PIIX_FLAG_CHECKINTR, + .flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x06, /* mwdma1-2 */ .udma_mask = ATA_UDMA5, /* udma0-5 */ @@ -477,7 +471,7 @@ static struct ata_port_info piix_port_info[] = { /* ich_pata_133: 4 ICH with full UDMA6 */ { .sht = &piix_sht, - .flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS | PIIX_FLAG_CHECKINTR, + .flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR, .pio_mask = 0x1f, /* pio 0-4 */ .mwdma_mask = 0x06, /* Check: maybe 0x07 */ .udma_mask = ATA_UDMA6, /* UDMA133 */ @@ -487,41 +481,27 @@ static struct ata_port_info piix_port_info[] = { /* ich5_sata: 5 */ { .sht = &piix_sht, - .flags = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR | - PIIX_FLAG_IGNORE_PCS, - .pio_mask = 0x1f, /* pio0-4 */ - .mwdma_mask = 0x07, /* mwdma0-2 */ - .udma_mask = 0x7f, /* udma0-6 */ - .port_ops = &piix_sata_ops, - }, - - /* i6300esb_sata: 6 */ - { - .sht = &piix_sht, - .flags = ATA_FLAG_SATA | - PIIX_FLAG_CHECKINTR | PIIX_FLAG_IGNORE_PCS, + .flags = PIIX_SATA_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &piix_sata_ops, }, - /* ich6_sata: 7 */ + /* ich6_sata: 6 */ { .sht = &piix_sht, - .flags = ATA_FLAG_SATA | - PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR, + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &piix_sata_ops, }, - /* ich6_sata_ahci: 8 */ + /* ich6_sata_ahci: 7 */ { .sht = &piix_sht, - .flags = ATA_FLAG_SATA | - PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR | + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | PIIX_FLAG_AHCI, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ @@ -529,11 +509,10 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_sata_ops, }, - /* ich6m_sata_ahci: 9 */ + /* ich6m_sata_ahci: 8 */ { .sht = &piix_sht, - .flags = ATA_FLAG_SATA | - PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR | + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | PIIX_FLAG_AHCI, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ @@ -541,11 +520,10 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_sata_ops, }, - /* ich8_sata_ahci: 10 */ + /* ich8_sata_ahci: 9 */ { .sht = &piix_sht, - .flags = ATA_FLAG_SATA | - PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR | + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | PIIX_FLAG_AHCI, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ @@ -566,10 +544,22 @@ MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, piix_pci_tbl); MODULE_VERSION(DRV_VERSION); -static int force_pcs = 0; -module_param(force_pcs, int, 0444); -MODULE_PARM_DESC(force_pcs, "force honoring or ignoring PCS to work around " - "device mis-detection (0=default, 1=ignore PCS, 2=honor PCS)"); +struct ich_laptop { + u16 device; + u16 subvendor; + u16 subdevice; +}; + +/* + * List of laptops that use short cables rather than 80 wire + */ + +static const struct ich_laptop ich_laptop[] = { + /* devid, subvendor, subdev */ + { 0x27DF, 0x0005, 0x0280 }, /* ICH7 on Acer 5602WLMi */ + /* end marker */ + { 0, } +}; /** * piix_pata_cbl_detect - Probe host controller cable detect info @@ -585,12 +575,24 @@ MODULE_PARM_DESC(force_pcs, "force honoring or ignoring PCS to work around " static void ich_pata_cbl_detect(struct ata_port *ap) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); + const struct ich_laptop *lap = &ich_laptop[0]; u8 tmp, mask; /* no 80c support in host controller? */ if ((ap->udma_mask & ~ATA_UDMA_MASK_40C) == 0) goto cbl40; + /* Check for specials - Acer Aspire 5602WLMi */ + while (lap->device) { + if (lap->device == pdev->device && + lap->subvendor == pdev->subsystem_vendor && + lap->subdevice == pdev->subsystem_device) { + ap->cbl = ATA_CBL_PATA40_SHORT; + return; + } + lap++; + } + /* check BIOS cable detect results */ mask = ap->port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC; pci_read_config_byte(pdev, PIIX_IOCFG, &tmp); @@ -659,84 +661,9 @@ static void ich_pata_error_handler(struct ata_port *ap) ata_std_postreset); } -/** - * piix_sata_present_mask - determine present mask for SATA host controller - * @ap: Target port - * - * Reads SATA PCI device's PCI config register Port Configuration - * and Status (PCS) to determine port and device availability. - * - * LOCKING: - * None (inherited from caller). - * - * RETURNS: - * determined present_mask - */ -static unsigned int piix_sata_present_mask(struct ata_port *ap) -{ - struct pci_dev *pdev = to_pci_dev(ap->host->dev); - struct piix_host_priv *hpriv = ap->host->private_data; - const unsigned int *map = hpriv->map; - int base = 2 * ap->port_no; - unsigned int present_mask = 0; - int port, i; - u16 pcs; - - pci_read_config_word(pdev, ICH5_PCS, &pcs); - DPRINTK("ata%u: ENTER, pcs=0x%x base=%d\n", ap->id, pcs, base); - - for (i = 0; i < 2; i++) { - port = map[base + i]; - if (port < 0) - continue; - if ((ap->flags & PIIX_FLAG_IGNORE_PCS) || - (pcs & 1 << (hpriv->map_db->present_shift + port))) - present_mask |= 1 << i; - } - - DPRINTK("ata%u: LEAVE, pcs=0x%x present_mask=0x%x\n", - ap->id, pcs, present_mask); - - return present_mask; -} - -/** - * piix_sata_softreset - reset SATA host port via ATA SRST - * @ap: port to reset - * @classes: resulting classes of attached devices - * - * Reset SATA host port via ATA SRST. On controllers with - * reliable PCS present bits, the bits are used to determine - * device presence. - * - * LOCKING: - * Kernel thread context (may sleep) - * - * RETURNS: - * 0 on success, -errno otherwise. - */ -static int piix_sata_softreset(struct ata_port *ap, unsigned int *classes) -{ - unsigned int present_mask; - int i, rc; - - present_mask = piix_sata_present_mask(ap); - - rc = ata_std_softreset(ap, classes); - if (rc) - return rc; - - for (i = 0; i < ATA_MAX_DEVICES; i++) { - if (!(present_mask & (1 << i))) - classes[i] = ATA_DEV_NONE; - } - - return 0; -} - static void piix_sata_error_handler(struct ata_port *ap) { - ata_bmdma_drive_eh(ap, ata_std_prereset, piix_sata_softreset, NULL, + ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, NULL, ata_std_postreset); } @@ -1051,18 +978,6 @@ static void __devinit piix_init_pcs(struct pci_dev *pdev, pci_write_config_word(pdev, ICH5_PCS, new_pcs); msleep(150); } - - if (force_pcs == 1) { - dev_printk(KERN_INFO, &pdev->dev, - "force ignoring PCS (0x%x)\n", new_pcs); - pinfo[0].flags |= PIIX_FLAG_IGNORE_PCS; - pinfo[1].flags |= PIIX_FLAG_IGNORE_PCS; - } else if (force_pcs == 2) { - dev_printk(KERN_INFO, &pdev->dev, - "force honoring PCS (0x%x)\n", new_pcs); - pinfo[0].flags &= ~PIIX_FLAG_IGNORE_PCS; - pinfo[1].flags &= ~PIIX_FLAG_IGNORE_PCS; - } } static void __devinit piix_init_sata_map(struct pci_dev *pdev, @@ -1112,7 +1027,6 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev, "invalid MAP value %u\n", map_value); hpriv->map = map; - hpriv->map_db = map_db; } /** diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 915a55a6cc14..f8ec3896b793 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -199,7 +199,8 @@ static const u8 ata_rw_cmds[] = { /** * ata_rwcmd_protocol - set taskfile r/w commands and protocol - * @qc: command to examine and configure + * @tf: command to examine and configure + * @dev: device tf belongs to * * Examine the device configuration and tf->flags to calculate * the proper read/write commands and protocol to use. @@ -207,10 +208,8 @@ static const u8 ata_rw_cmds[] = { * LOCKING: * caller. */ -int ata_rwcmd_protocol(struct ata_queued_cmd *qc) +static int ata_rwcmd_protocol(struct ata_taskfile *tf, struct ata_device *dev) { - struct ata_taskfile *tf = &qc->tf; - struct ata_device *dev = qc->dev; u8 cmd; int index, fua, lba48, write; @@ -222,7 +221,7 @@ int ata_rwcmd_protocol(struct ata_queued_cmd *qc) if (dev->flags & ATA_DFLAG_PIO) { tf->protocol = ATA_PROT_PIO; index = dev->multi_count ? 0 : 8; - } else if (lba48 && (qc->ap->flags & ATA_FLAG_PIO_LBA48)) { + } else if (lba48 && (dev->ap->flags & ATA_FLAG_PIO_LBA48)) { /* Unable to use DMA due to host limitation */ tf->protocol = ATA_PROT_PIO; index = dev->multi_count ? 0 : 8; @@ -240,6 +239,174 @@ int ata_rwcmd_protocol(struct ata_queued_cmd *qc) } /** + * ata_tf_read_block - Read block address from ATA taskfile + * @tf: ATA taskfile of interest + * @dev: ATA device @tf belongs to + * + * LOCKING: + * None. + * + * Read block address from @tf. This function can handle all + * three address formats - LBA, LBA48 and CHS. tf->protocol and + * flags select the address format to use. + * + * RETURNS: + * Block address read from @tf. + */ +u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev) +{ + u64 block = 0; + + if (tf->flags & ATA_TFLAG_LBA) { + if (tf->flags & ATA_TFLAG_LBA48) { + block |= (u64)tf->hob_lbah << 40; + block |= (u64)tf->hob_lbam << 32; + block |= tf->hob_lbal << 24; + } else + block |= (tf->device & 0xf) << 24; + + block |= tf->lbah << 16; + block |= tf->lbam << 8; + block |= tf->lbal; + } else { + u32 cyl, head, sect; + + cyl = tf->lbam | (tf->lbah << 8); + head = tf->device & 0xf; + sect = tf->lbal; + + block = (cyl * dev->heads + head) * dev->sectors + sect; + } + + return block; +} + +/** + * ata_build_rw_tf - Build ATA taskfile for given read/write request + * @tf: Target ATA taskfile + * @dev: ATA device @tf belongs to + * @block: Block address + * @n_block: Number of blocks + * @tf_flags: RW/FUA etc... + * @tag: tag + * + * LOCKING: + * None. + * + * Build ATA taskfile @tf for read/write request described by + * @block, @n_block, @tf_flags and @tag on @dev. + * + * RETURNS: + * + * 0 on success, -ERANGE if the request is too large for @dev, + * -EINVAL if the request is invalid. + */ +int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev, + u64 block, u32 n_block, unsigned int tf_flags, + unsigned int tag) +{ + tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf->flags |= tf_flags; + + if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ_OFF | + ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ && + likely(tag != ATA_TAG_INTERNAL)) { + /* yay, NCQ */ + if (!lba_48_ok(block, n_block)) + return -ERANGE; + + tf->protocol = ATA_PROT_NCQ; + tf->flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48; + + if (tf->flags & ATA_TFLAG_WRITE) + tf->command = ATA_CMD_FPDMA_WRITE; + else + tf->command = ATA_CMD_FPDMA_READ; + + tf->nsect = tag << 3; + tf->hob_feature = (n_block >> 8) & 0xff; + tf->feature = n_block & 0xff; + + tf->hob_lbah = (block >> 40) & 0xff; + tf->hob_lbam = (block >> 32) & 0xff; + tf->hob_lbal = (block >> 24) & 0xff; + tf->lbah = (block >> 16) & 0xff; + tf->lbam = (block >> 8) & 0xff; + tf->lbal = block & 0xff; + + tf->device = 1 << 6; + if (tf->flags & ATA_TFLAG_FUA) + tf->device |= 1 << 7; + } else if (dev->flags & ATA_DFLAG_LBA) { + tf->flags |= ATA_TFLAG_LBA; + + if (lba_28_ok(block, n_block)) { + /* use LBA28 */ + tf->device |= (block >> 24) & 0xf; + } else if (lba_48_ok(block, n_block)) { + if (!(dev->flags & ATA_DFLAG_LBA48)) + return -ERANGE; + + /* use LBA48 */ + tf->flags |= ATA_TFLAG_LBA48; + + tf->hob_nsect = (n_block >> 8) & 0xff; + + tf->hob_lbah = (block >> 40) & 0xff; + tf->hob_lbam = (block >> 32) & 0xff; + tf->hob_lbal = (block >> 24) & 0xff; + } else + /* request too large even for LBA48 */ + return -ERANGE; + + if (unlikely(ata_rwcmd_protocol(tf, dev) < 0)) + return -EINVAL; + + tf->nsect = n_block & 0xff; + + tf->lbah = (block >> 16) & 0xff; + tf->lbam = (block >> 8) & 0xff; + tf->lbal = block & 0xff; + + tf->device |= ATA_LBA; + } else { + /* CHS */ + u32 sect, head, cyl, track; + + /* The request -may- be too large for CHS addressing. */ + if (!lba_28_ok(block, n_block)) + return -ERANGE; + + if (unlikely(ata_rwcmd_protocol(tf, dev) < 0)) + return -EINVAL; + + /* Convert LBA to CHS */ + track = (u32)block / dev->sectors; + cyl = track / dev->heads; + head = track % dev->heads; + sect = (u32)block % dev->sectors + 1; + + DPRINTK("block %u track %u cyl %u head %u sect %u\n", + (u32)block, track, cyl, head, sect); + + /* Check whether the converted CHS can fit. + Cylinder: 0-65535 + Head: 0-15 + Sector: 1-255*/ + if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) + return -ERANGE; + + tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */ + tf->lbal = sect; + tf->lbam = cyl; + tf->lbah = cyl >> 8; + tf->device |= head; + } + + return 0; +} + +/** * ata_pack_xfermask - Pack pio, mwdma and udma masks into xfer_mask * @pio_mask: pio_mask * @mwdma_mask: mwdma_mask @@ -999,13 +1166,13 @@ void ata_qc_complete_internal(struct ata_queued_cmd *qc) } /** - * ata_exec_internal - execute libata internal command + * ata_exec_internal_sg - execute libata internal command * @dev: Device to which the command is sent * @tf: Taskfile registers for the command and the result * @cdb: CDB for packet command * @dma_dir: Data tranfer direction of the command - * @buf: Data buffer of the command - * @buflen: Length of data buffer + * @sg: sg list for the data buffer of the command + * @n_elem: Number of sg entries * * Executes libata internal command with timeout. @tf contains * command on entry and result on return. Timeout and error @@ -1019,9 +1186,10 @@ void ata_qc_complete_internal(struct ata_queued_cmd *qc) * RETURNS: * Zero on success, AC_ERR_* mask on failure */ -unsigned ata_exec_internal(struct ata_device *dev, - struct ata_taskfile *tf, const u8 *cdb, - int dma_dir, void *buf, unsigned int buflen) +unsigned ata_exec_internal_sg(struct ata_device *dev, + struct ata_taskfile *tf, const u8 *cdb, + int dma_dir, struct scatterlist *sg, + unsigned int n_elem) { struct ata_port *ap = dev->ap; u8 command = tf->command; @@ -1077,7 +1245,12 @@ unsigned ata_exec_internal(struct ata_device *dev, qc->flags |= ATA_QCFLAG_RESULT_TF; qc->dma_dir = dma_dir; if (dma_dir != DMA_NONE) { - ata_sg_init_one(qc, buf, buflen); + unsigned int i, buflen = 0; + + for (i = 0; i < n_elem; i++) + buflen += sg[i].length; + + ata_sg_init(qc, sg, n_elem); qc->nsect = buflen / ATA_SECT_SIZE; } @@ -1161,6 +1334,35 @@ unsigned ata_exec_internal(struct ata_device *dev, } /** + * ata_exec_internal_sg - execute libata internal command + * @dev: Device to which the command is sent + * @tf: Taskfile registers for the command and the result + * @cdb: CDB for packet command + * @dma_dir: Data tranfer direction of the command + * @buf: Data buffer of the command + * @buflen: Length of data buffer + * + * Wrapper around ata_exec_internal_sg() which takes simple + * buffer instead of sg list. + * + * LOCKING: + * None. Should be called with kernel context, might sleep. + * + * RETURNS: + * Zero on success, AC_ERR_* mask on failure + */ +unsigned ata_exec_internal(struct ata_device *dev, + struct ata_taskfile *tf, const u8 *cdb, + int dma_dir, void *buf, unsigned int buflen) +{ + struct scatterlist sg; + + sg_init_one(&sg, buf, buflen); + + return ata_exec_internal_sg(dev, tf, cdb, dma_dir, &sg, 1); +} + +/** * ata_do_simple_cmd - execute simple internal command * @dev: Device to which the command is sent * @cmd: Opcode to execute @@ -1224,7 +1426,7 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev) * ata_dev_read_id - Read ID data from the specified device * @dev: target device * @p_class: pointer to class of the target device (may be changed) - * @post_reset: is this read ID post-reset? + * @flags: ATA_READID_* flags * @id: buffer to read IDENTIFY data into * * Read ID data from the specified device. ATA_CMD_ID_ATA is @@ -1239,7 +1441,7 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev) * 0 on success, -errno otherwise. */ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, - int post_reset, u16 *id) + unsigned int flags, u16 *id) { struct ata_port *ap = dev->ap; unsigned int class = *p_class; @@ -1271,10 +1473,17 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, } tf.protocol = ATA_PROT_PIO; + tf.flags |= ATA_TFLAG_POLLING; /* for polling presence detection */ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, id, sizeof(id[0]) * ATA_ID_WORDS); if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + DPRINTK("ata%u.%d: NODEV after polling detection\n", + ap->id, dev->devno); + return -ENOENT; + } + rc = -EIO; reason = "I/O error"; goto err_out; @@ -1294,7 +1503,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, goto err_out; } - if (post_reset && class == ATA_DEV_ATA) { + if ((flags & ATA_READID_POSTRESET) && class == ATA_DEV_ATA) { /* * The exact sequence expected by certain pre-ATA4 drives is: * SRST RESET @@ -1314,7 +1523,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, /* current CHS translation info (id[53-58]) might be * changed. reread the identify device info. */ - post_reset = 0; + flags &= ~ATA_READID_POSTRESET; goto retry; } } @@ -1345,7 +1554,10 @@ static void ata_dev_config_ncq(struct ata_device *dev, desc[0] = '\0'; return; } - + if (ata_device_blacklisted(dev) & ATA_HORKAGE_NONCQ) { + snprintf(desc, desc_sz, "NCQ (not used)"); + return; + } if (ap->flags & ATA_FLAG_NCQ) { hdepth = min(ap->scsi_host->can_queue, ATA_MAX_QUEUE - 1); dev->flags |= ATA_DFLAG_NCQ; @@ -1374,7 +1586,6 @@ static void ata_set_port_max_cmd_len(struct ata_port *ap) /** * ata_dev_configure - Configure the specified ATA/ATAPI device * @dev: Target device to configure - * @print_info: Enable device info printout * * Configure @dev according to @dev->id. Generic and low-level * driver specific fixups are also applied. @@ -1385,9 +1596,10 @@ static void ata_set_port_max_cmd_len(struct ata_port *ap) * RETURNS: * 0 on success, -errno otherwise */ -int ata_dev_configure(struct ata_device *dev, int print_info) +int ata_dev_configure(struct ata_device *dev) { struct ata_port *ap = dev->ap; + int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO; const u16 *id = dev->id; unsigned int xfer_mask; char revbuf[7]; /* XYZ-99\0 */ @@ -1454,6 +1666,10 @@ int ata_dev_configure(struct ata_device *dev, int print_info) if (ata_id_has_lba48(id)) { dev->flags |= ATA_DFLAG_LBA48; lba_desc = "LBA48"; + + if (dev->n_sectors >= (1UL << 28) && + ata_id_has_flush_ext(id)) + dev->flags |= ATA_DFLAG_FLUSH_EXT; } /* config NCQ */ @@ -1530,6 +1746,11 @@ int ata_dev_configure(struct ata_device *dev, int print_info) cdb_intr_string); } + /* determine max_sectors */ + dev->max_sectors = ATA_MAX_SECTORS; + if (dev->flags & ATA_DFLAG_LBA48) + dev->max_sectors = ATA_MAX_SECTORS_LBA48; + if (dev->horkage & ATA_HORKAGE_DIAGNOSTIC) { /* Let the user know. We don't want to disallow opens for rescue purposes, or in case the vendor is just a blithering @@ -1631,11 +1852,14 @@ int ata_bus_probe(struct ata_port *ap) if (!ata_dev_enabled(dev)) continue; - rc = ata_dev_read_id(dev, &dev->class, 1, dev->id); + rc = ata_dev_read_id(dev, &dev->class, ATA_READID_POSTRESET, + dev->id); if (rc) goto fail; - rc = ata_dev_configure(dev, 1); + ap->eh_context.i.flags |= ATA_EHI_PRINTINFO; + rc = ata_dev_configure(dev); + ap->eh_context.i.flags &= ~ATA_EHI_PRINTINFO; if (rc) goto fail; } @@ -2153,6 +2377,7 @@ int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0) static int ata_dev_set_mode(struct ata_device *dev) { + struct ata_eh_context *ehc = &dev->ap->eh_context; unsigned int err_mask; int rc; @@ -2167,7 +2392,9 @@ static int ata_dev_set_mode(struct ata_device *dev) return -EIO; } + ehc->i.flags |= ATA_EHI_POST_SETMODE; rc = ata_dev_revalidate(dev, 0); + ehc->i.flags &= ~ATA_EHI_POST_SETMODE; if (rc) return rc; @@ -2325,11 +2552,14 @@ static inline void ata_tf_to_host(struct ata_port *ap, * Sleep until ATA Status register bit BSY clears, * or a timeout occurs. * - * LOCKING: None. + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno otherwise. */ - -unsigned int ata_busy_sleep (struct ata_port *ap, - unsigned long tmout_pat, unsigned long tmout) +int ata_busy_sleep(struct ata_port *ap, + unsigned long tmout_pat, unsigned long tmout) { unsigned long timer_start, timeout; u8 status; @@ -2337,27 +2567,32 @@ unsigned int ata_busy_sleep (struct ata_port *ap, status = ata_busy_wait(ap, ATA_BUSY, 300); timer_start = jiffies; timeout = timer_start + tmout_pat; - while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) { + while (status != 0xff && (status & ATA_BUSY) && + time_before(jiffies, timeout)) { msleep(50); status = ata_busy_wait(ap, ATA_BUSY, 3); } - if (status & ATA_BUSY) + if (status != 0xff && (status & ATA_BUSY)) ata_port_printk(ap, KERN_WARNING, "port is slow to respond, please be patient " "(Status 0x%x)\n", status); timeout = timer_start + tmout; - while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) { + while (status != 0xff && (status & ATA_BUSY) && + time_before(jiffies, timeout)) { msleep(50); status = ata_chk_status(ap); } + if (status == 0xff) + return -ENODEV; + if (status & ATA_BUSY) { ata_port_printk(ap, KERN_ERR, "port failed to respond " "(%lu secs, Status 0x%x)\n", tmout / HZ, status); - return 1; + return -EBUSY; } return 0; @@ -2448,10 +2683,8 @@ static unsigned int ata_bus_softreset(struct ata_port *ap, * the bus shows 0xFF because the odd clown forgets the D7 * pulldown resistor. */ - if (ata_check_status(ap) == 0xFF) { - ata_port_printk(ap, KERN_ERR, "SRST failed (status 0xFF)\n"); - return AC_ERR_OTHER; - } + if (ata_check_status(ap) == 0xFF) + return 0; ata_bus_post_reset(ap, devmask); @@ -2777,9 +3010,9 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes) } /** - * sata_std_hardreset - reset host port via SATA phy reset + * sata_port_hardreset - reset port via SATA phy reset * @ap: port to reset - * @class: resulting class of attached device + * @timing: timing parameters { interval, duratinon, timeout } in msec * * SATA phy-reset host port using DET bits of SControl register. * @@ -2789,10 +3022,8 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes) * RETURNS: * 0 on success, -errno otherwise. */ -int sata_std_hardreset(struct ata_port *ap, unsigned int *class) +int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing) { - struct ata_eh_context *ehc = &ap->eh_context; - const unsigned long *timing = sata_ehc_deb_timing(ehc); u32 scontrol; int rc; @@ -2805,24 +3036,24 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class) * and Sil3124. */ if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) - return rc; + goto out; scontrol = (scontrol & 0x0f0) | 0x304; if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol))) - return rc; + goto out; sata_set_spd(ap); } /* issue phy wake/reset */ if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) - return rc; + goto out; scontrol = (scontrol & 0x0f0) | 0x301; if ((rc = sata_scr_write_flush(ap, SCR_CONTROL, scontrol))) - return rc; + goto out; /* Couldn't find anything in SATA I/II specs, but AHCI-1.1 * 10.4.2 says at least 1 ms. @@ -2830,7 +3061,40 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class) msleep(1); /* bring phy back */ - sata_phy_resume(ap, timing); + rc = sata_phy_resume(ap, timing); + out: + DPRINTK("EXIT, rc=%d\n", rc); + return rc; +} + +/** + * sata_std_hardreset - reset host port via SATA phy reset + * @ap: port to reset + * @class: resulting class of attached device + * + * SATA phy-reset host port using DET bits of SControl register, + * wait for !BSY and classify the attached device. + * + * LOCKING: + * Kernel thread context (may sleep) + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +int sata_std_hardreset(struct ata_port *ap, unsigned int *class) +{ + const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context); + int rc; + + DPRINTK("ENTER\n"); + + /* do hardreset */ + rc = sata_port_hardreset(ap, timing); + if (rc) { + ata_port_printk(ap, KERN_ERR, + "COMRESET failed (errno=%d)\n", rc); + return rc; + } /* TODO: phy layer with polling, timeouts, etc. */ if (ata_port_offline(ap)) { @@ -2969,7 +3233,7 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class, /** * ata_dev_revalidate - Revalidate ATA device * @dev: device to revalidate - * @post_reset: is this revalidation after reset? + * @readid_flags: read ID flags * * Re-read IDENTIFY page and make sure @dev is still attached to * the port. @@ -2980,7 +3244,7 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class, * RETURNS: * 0 on success, negative errno otherwise */ -int ata_dev_revalidate(struct ata_device *dev, int post_reset) +int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags) { unsigned int class = dev->class; u16 *id = (void *)dev->ap->sector_buf; @@ -2992,7 +3256,7 @@ int ata_dev_revalidate(struct ata_device *dev, int post_reset) } /* read ID data */ - rc = ata_dev_read_id(dev, &class, post_reset, id); + rc = ata_dev_read_id(dev, &class, readid_flags, id); if (rc) goto fail; @@ -3005,7 +3269,7 @@ int ata_dev_revalidate(struct ata_device *dev, int post_reset) memcpy(dev->id, id, sizeof(id[0]) * ATA_ID_WORDS); /* configure device according to the new ID */ - rc = ata_dev_configure(dev, 0); + rc = ata_dev_configure(dev); if (rc == 0) return 0; @@ -3014,37 +3278,55 @@ int ata_dev_revalidate(struct ata_device *dev, int post_reset) return rc; } -static const char * const ata_dma_blacklist [] = { - "WDC AC11000H", NULL, - "WDC AC22100H", NULL, - "WDC AC32500H", NULL, - "WDC AC33100H", NULL, - "WDC AC31600H", NULL, - "WDC AC32100H", "24.09P07", - "WDC AC23200L", "21.10N21", - "Compaq CRD-8241B", NULL, - "CRD-8400B", NULL, - "CRD-8480B", NULL, - "CRD-8482B", NULL, - "CRD-84", NULL, - "SanDisk SDP3B", NULL, - "SanDisk SDP3B-64", NULL, - "SANYO CD-ROM CRD", NULL, - "HITACHI CDR-8", NULL, - "HITACHI CDR-8335", NULL, - "HITACHI CDR-8435", NULL, - "Toshiba CD-ROM XM-6202B", NULL, - "TOSHIBA CD-ROM XM-1702BC", NULL, - "CD-532E-A", NULL, - "E-IDE CD-ROM CR-840", NULL, - "CD-ROM Drive/F5A", NULL, - "WPI CDD-820", NULL, - "SAMSUNG CD-ROM SC-148C", NULL, - "SAMSUNG CD-ROM SC", NULL, - "SanDisk SDP3B-64", NULL, - "ATAPI CD-ROM DRIVE 40X MAXIMUM",NULL, - "_NEC DV5800A", NULL, - "SAMSUNG CD-ROM SN-124", "N001" +struct ata_blacklist_entry { + const char *model_num; + const char *model_rev; + unsigned long horkage; +}; + +static const struct ata_blacklist_entry ata_device_blacklist [] = { + /* Devices with DMA related problems under Linux */ + { "WDC AC11000H", NULL, ATA_HORKAGE_NODMA }, + { "WDC AC22100H", NULL, ATA_HORKAGE_NODMA }, + { "WDC AC32500H", NULL, ATA_HORKAGE_NODMA }, + { "WDC AC33100H", NULL, ATA_HORKAGE_NODMA }, + { "WDC AC31600H", NULL, ATA_HORKAGE_NODMA }, + { "WDC AC32100H", "24.09P07", ATA_HORKAGE_NODMA }, + { "WDC AC23200L", "21.10N21", ATA_HORKAGE_NODMA }, + { "Compaq CRD-8241B", NULL, ATA_HORKAGE_NODMA }, + { "CRD-8400B", NULL, ATA_HORKAGE_NODMA }, + { "CRD-8480B", NULL, ATA_HORKAGE_NODMA }, + { "CRD-8482B", NULL, ATA_HORKAGE_NODMA }, + { "CRD-84", NULL, ATA_HORKAGE_NODMA }, + { "SanDisk SDP3B", NULL, ATA_HORKAGE_NODMA }, + { "SanDisk SDP3B-64", NULL, ATA_HORKAGE_NODMA }, + { "SANYO CD-ROM CRD", NULL, ATA_HORKAGE_NODMA }, + { "HITACHI CDR-8", NULL, ATA_HORKAGE_NODMA }, + { "HITACHI CDR-8335", NULL, ATA_HORKAGE_NODMA }, + { "HITACHI CDR-8435", NULL, ATA_HORKAGE_NODMA }, + { "Toshiba CD-ROM XM-6202B", NULL, ATA_HORKAGE_NODMA }, + { "TOSHIBA CD-ROM XM-1702BC", NULL, ATA_HORKAGE_NODMA }, + { "CD-532E-A", NULL, ATA_HORKAGE_NODMA }, + { "E-IDE CD-ROM CR-840",NULL, ATA_HORKAGE_NODMA }, + { "CD-ROM Drive/F5A", NULL, ATA_HORKAGE_NODMA }, + { "WPI CDD-820", NULL, ATA_HORKAGE_NODMA }, + { "SAMSUNG CD-ROM SC-148C", NULL, ATA_HORKAGE_NODMA }, + { "SAMSUNG CD-ROM SC", NULL, ATA_HORKAGE_NODMA }, + { "SanDisk SDP3B-64", NULL, ATA_HORKAGE_NODMA }, + { "ATAPI CD-ROM DRIVE 40X MAXIMUM",NULL,ATA_HORKAGE_NODMA }, + { "_NEC DV5800A", NULL, ATA_HORKAGE_NODMA }, + { "SAMSUNG CD-ROM SN-124","N001", ATA_HORKAGE_NODMA }, + + /* Devices we expect to fail diagnostics */ + + /* Devices where NCQ should be avoided */ + /* NCQ is slow */ + { "WDC WD740ADFD-00", NULL, ATA_HORKAGE_NONCQ }, + + /* Devices with NCQ limits */ + + /* End Marker */ + { } }; static int ata_strim(char *s, size_t len) @@ -3059,20 +3341,12 @@ static int ata_strim(char *s, size_t len) return len; } -static int ata_dma_blacklisted(const struct ata_device *dev) +unsigned long ata_device_blacklisted(const struct ata_device *dev) { unsigned char model_num[40]; unsigned char model_rev[16]; unsigned int nlen, rlen; - int i; - - /* We don't support polling DMA. - * DMA blacklist those ATAPI devices with CDB-intr (and use PIO) - * if the LLDD handles only interrupts in the HSM_ST_LAST state. - */ - if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) && - (dev->flags & ATA_DFLAG_CDB_INTR)) - return 1; + const struct ata_blacklist_entry *ad = ata_device_blacklist; ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num)); @@ -3081,17 +3355,30 @@ static int ata_dma_blacklisted(const struct ata_device *dev) nlen = ata_strim(model_num, sizeof(model_num)); rlen = ata_strim(model_rev, sizeof(model_rev)); - for (i = 0; i < ARRAY_SIZE(ata_dma_blacklist); i += 2) { - if (!strncmp(ata_dma_blacklist[i], model_num, nlen)) { - if (ata_dma_blacklist[i+1] == NULL) - return 1; - if (!strncmp(ata_dma_blacklist[i], model_rev, rlen)) - return 1; + while (ad->model_num) { + if (!strncmp(ad->model_num, model_num, nlen)) { + if (ad->model_rev == NULL) + return ad->horkage; + if (!strncmp(ad->model_rev, model_rev, rlen)) + return ad->horkage; } + ad++; } return 0; } +static int ata_dma_blacklisted(const struct ata_device *dev) +{ + /* We don't support polling DMA. + * DMA blacklist those ATAPI devices with CDB-intr (and use PIO) + * if the LLDD handles only interrupts in the HSM_ST_LAST state. + */ + if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) && + (dev->flags & ATA_DFLAG_CDB_INTR)) + return 1; + return (ata_device_blacklisted(dev) & ATA_HORKAGE_NODMA) ? 1 : 0; +} + /** * ata_dev_xfermask - Compute supported xfermask of the given device * @dev: Device to compute xfermask for @@ -3119,6 +3406,13 @@ static void ata_dev_xfermask(struct ata_device *dev) */ if (ap->cbl == ATA_CBL_PATA40) xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA); + /* Apply drive side cable rule. Unknown or 80 pin cables reported + * host side are checked drive side as well. Cases where we know a + * 40wire cable is used safely for 80 are not checked here. + */ + if (ata_drive_40wire(dev->id) && (ap->cbl == ATA_CBL_PATA_UNK || ap->cbl == ATA_CBL_PATA80)) + xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA); + xfer_mask &= ata_pack_xfermask(dev->pio_mask, dev->mwdma_mask, dev->udma_mask); @@ -3236,8 +3530,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev, * LOCKING: * spin_lock_irqsave(host lock) */ - -static void ata_sg_clean(struct ata_queued_cmd *qc) +void ata_sg_clean(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct scatterlist *sg = qc->__sg; @@ -3395,19 +3688,15 @@ void ata_noop_qc_prep(struct ata_queued_cmd *qc) { } void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen) { - struct scatterlist *sg; - qc->flags |= ATA_QCFLAG_SINGLE; - memset(&qc->sgent, 0, sizeof(qc->sgent)); qc->__sg = &qc->sgent; qc->n_elem = 1; qc->orig_n_elem = 1; qc->buf_virt = buf; qc->nbytes = buflen; - sg = qc->__sg; - sg_init_one(sg, buf, buflen); + sg_init_one(&qc->sgent, buf, buflen); } /** @@ -4200,8 +4489,12 @@ fsm_start: /* device stops HSM for abort/error */ qc->err_mask |= AC_ERR_DEV; else - /* HSM violation. Let EH handle this */ - qc->err_mask |= AC_ERR_HSM; + /* HSM violation. Let EH handle this. + * Phantom devices also trigger this + * condition. Mark hint. + */ + qc->err_mask |= AC_ERR_HSM | + AC_ERR_NODEV_HINT; ap->hsm_task_state = HSM_ST_ERR; goto fsm_start; @@ -4440,6 +4733,14 @@ void __ata_qc_complete(struct ata_queued_cmd *qc) qc->complete_fn(qc); } +static void fill_result_tf(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + ap->ops->tf_read(ap, &qc->result_tf); + qc->result_tf.flags = qc->tf.flags; +} + /** * ata_qc_complete - Complete an active ATA command * @qc: Command to complete @@ -4477,7 +4778,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc) if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) { if (!ata_tag_internal(qc->tag)) { /* always fill result TF for failed qc */ - ap->ops->tf_read(ap, &qc->result_tf); + fill_result_tf(qc); ata_qc_schedule_eh(qc); return; } @@ -4485,7 +4786,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc) /* read result TF if requested */ if (qc->flags & ATA_QCFLAG_RESULT_TF) - ap->ops->tf_read(ap, &qc->result_tf); + fill_result_tf(qc); __ata_qc_complete(qc); } else { @@ -4494,7 +4795,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc) /* read result TF if failed or requested */ if (qc->err_mask || qc->flags & ATA_QCFLAG_RESULT_TF) - ap->ops->tf_read(ap, &qc->result_tf); + fill_result_tf(qc); __ata_qc_complete(qc); } @@ -4674,6 +4975,14 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) } } + /* Some controllers show flaky interrupt behavior after + * setting xfer mode. Use polling instead. + */ + if (unlikely(qc->tf.command == ATA_CMD_SET_FEATURES && + qc->tf.feature == SETFEATURES_XFER) && + (ap->flags & ATA_FLAG_SETXFER_POLLING)) + qc->tf.flags |= ATA_TFLAG_POLLING; + /* select the device */ ata_dev_select(ap, qc->dev->devno, 1, 0); @@ -4782,6 +5091,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) inline unsigned int ata_host_intr (struct ata_port *ap, struct ata_queued_cmd *qc) { + struct ata_eh_info *ehi = &ap->eh_info; u8 status, host_stat = 0; VPRINTK("ata%u: protocol %d task_state %d\n", @@ -4842,6 +5152,11 @@ inline unsigned int ata_host_intr (struct ata_port *ap, ap->ops->irq_clear(ap); ata_hsm_move(ap, qc, status, 0); + + if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA || + qc->tf.protocol == ATA_PROT_ATAPI_DMA)) + ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat); + return 1; /* irq handled */ idle_irq: @@ -5048,7 +5363,7 @@ int ata_flush_cache(struct ata_device *dev) if (!ata_try_flush_cache(dev)) return 0; - if (ata_id_has_flush_ext(dev->id)) + if (dev->flags & ATA_DFLAG_FLUSH_EXT) cmd = ATA_CMD_FLUSH_EXT; else cmd = ATA_CMD_FLUSH; @@ -5520,9 +5835,8 @@ int ata_device_add(const struct ata_probe_ent *ent) ap->ioaddr.bmdma_addr, irq_line); - ata_chk_status(ap); - host->ops->irq_clear(ap); - ata_eh_freeze_port(ap); /* freeze port before requesting IRQ */ + /* freeze port before requesting IRQ */ + ata_eh_freeze_port(ap); } /* obtain irq, that may be shared between channels */ @@ -6120,6 +6434,7 @@ EXPORT_SYMBOL_GPL(__sata_phy_reset); EXPORT_SYMBOL_GPL(ata_bus_reset); EXPORT_SYMBOL_GPL(ata_std_prereset); EXPORT_SYMBOL_GPL(ata_std_softreset); +EXPORT_SYMBOL_GPL(sata_port_hardreset); EXPORT_SYMBOL_GPL(sata_std_hardreset); EXPORT_SYMBOL_GPL(ata_std_postreset); EXPORT_SYMBOL_GPL(ata_dev_classify); @@ -6146,6 +6461,7 @@ EXPORT_SYMBOL_GPL(ata_host_suspend); EXPORT_SYMBOL_GPL(ata_host_resume); EXPORT_SYMBOL_GPL(ata_id_string); EXPORT_SYMBOL_GPL(ata_id_c_string); +EXPORT_SYMBOL_GPL(ata_device_blacklisted); EXPORT_SYMBOL_GPL(ata_scsi_simulate); EXPORT_SYMBOL_GPL(ata_pio_need_iordy); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 02b2b2787d9b..76a85dfb7307 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1136,19 +1136,21 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, break; case ATA_DEV_ATAPI: - tmp = atapi_eh_request_sense(qc->dev, - qc->scsicmd->sense_buffer); - if (!tmp) { - /* ATA_QCFLAG_SENSE_VALID is used to tell - * atapi_qc_complete() that sense data is - * already valid. - * - * TODO: interpret sense data and set - * appropriate err_mask. - */ - qc->flags |= ATA_QCFLAG_SENSE_VALID; - } else - qc->err_mask |= tmp; + if (!(qc->ap->pflags & ATA_PFLAG_FROZEN)) { + tmp = atapi_eh_request_sense(qc->dev, + qc->scsicmd->sense_buffer); + if (!tmp) { + /* ATA_QCFLAG_SENSE_VALID is used to + * tell atapi_qc_complete() that sense + * data is already valid. + * + * TODO: interpret sense data and set + * appropriate err_mask. + */ + qc->flags |= ATA_QCFLAG_SENSE_VALID; + } else + qc->err_mask |= tmp; + } } if (qc->err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT | AC_ERR_ATA_BUS)) @@ -1433,16 +1435,39 @@ static void ata_eh_report(struct ata_port *ap) } for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { + static const char *dma_str[] = { + [DMA_BIDIRECTIONAL] = "bidi", + [DMA_TO_DEVICE] = "out", + [DMA_FROM_DEVICE] = "in", + [DMA_NONE] = "", + }; struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); + struct ata_taskfile *cmd = &qc->tf, *res = &qc->result_tf; + unsigned int nbytes; if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask) continue; - ata_dev_printk(qc->dev, KERN_ERR, "tag %d cmd 0x%x " - "Emask 0x%x stat 0x%x err 0x%x (%s)\n", - qc->tag, qc->tf.command, qc->err_mask, - qc->result_tf.command, qc->result_tf.feature, - ata_err_string(qc->err_mask)); + nbytes = qc->nbytes; + if (!nbytes) + nbytes = qc->nsect << 9; + + ata_dev_printk(qc->dev, KERN_ERR, + "cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x " + "tag %d cdb 0x%x data %u %s\n " + "res %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x " + "Emask 0x%x (%s)\n", + cmd->command, cmd->feature, cmd->nsect, + cmd->lbal, cmd->lbam, cmd->lbah, + cmd->hob_feature, cmd->hob_nsect, + cmd->hob_lbal, cmd->hob_lbam, cmd->hob_lbah, + cmd->device, qc->tag, qc->cdb[0], nbytes, + dma_str[qc->dma_dir], + res->command, res->feature, res->nsect, + res->lbal, res->lbam, res->lbah, + res->hob_feature, res->hob_nsect, + res->hob_lbal, res->hob_lbam, res->hob_lbah, + res->device, qc->err_mask, ata_err_string(qc->err_mask)); } } @@ -1634,11 +1659,14 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, DPRINTK("ENTER\n"); for (i = 0; i < ATA_MAX_DEVICES; i++) { - unsigned int action; + unsigned int action, readid_flags = 0; dev = &ap->device[i]; action = ata_eh_dev_action(dev); + if (ehc->i.flags & ATA_EHI_DID_RESET) + readid_flags |= ATA_READID_POSTRESET; + if (action & ATA_EH_REVALIDATE && ata_dev_ready(dev)) { if (ata_port_offline(ap)) { rc = -EIO; @@ -1646,13 +1674,17 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, } ata_eh_about_to_do(ap, dev, ATA_EH_REVALIDATE); - rc = ata_dev_revalidate(dev, - ehc->i.flags & ATA_EHI_DID_RESET); + rc = ata_dev_revalidate(dev, readid_flags); if (rc) break; ata_eh_done(ap, dev, ATA_EH_REVALIDATE); + /* Configuration may have changed, reconfigure + * transfer mode. + */ + ehc->i.flags |= ATA_EHI_SETMODE; + /* schedule the scsi_rescan_device() here */ queue_work(ata_aux_wq, &(ap->scsi_rescan_task)); } else if (dev->class == ATA_DEV_UNKNOWN && @@ -1660,18 +1692,35 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, ata_class_enabled(ehc->classes[dev->devno])) { dev->class = ehc->classes[dev->devno]; - rc = ata_dev_read_id(dev, &dev->class, 1, dev->id); - if (rc == 0) - rc = ata_dev_configure(dev, 1); + rc = ata_dev_read_id(dev, &dev->class, readid_flags, + dev->id); + if (rc == 0) { + ehc->i.flags |= ATA_EHI_PRINTINFO; + rc = ata_dev_configure(dev); + ehc->i.flags &= ~ATA_EHI_PRINTINFO; + } else if (rc == -ENOENT) { + /* IDENTIFY was issued to non-existent + * device. No need to reset. Just + * thaw and kill the device. + */ + ata_eh_thaw_port(ap); + dev->class = ATA_DEV_UNKNOWN; + rc = 0; + } if (rc) { dev->class = ATA_DEV_UNKNOWN; break; } - spin_lock_irqsave(ap->lock, flags); - ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG; - spin_unlock_irqrestore(ap->lock, flags); + if (ata_dev_enabled(dev)) { + spin_lock_irqsave(ap->lock, flags); + ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG; + spin_unlock_irqrestore(ap->lock, flags); + + /* new device discovered, configure xfermode */ + ehc->i.flags |= ATA_EHI_SETMODE; + } } } @@ -1987,13 +2036,14 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, if (rc) goto dev_fail; - /* configure transfer mode if the port has been reset */ - if (ehc->i.flags & ATA_EHI_DID_RESET) { + /* configure transfer mode if necessary */ + if (ehc->i.flags & ATA_EHI_SETMODE) { rc = ata_set_mode(ap, &dev); if (rc) { down_xfermask = 1; goto dev_fail; } + ehc->i.flags &= ~ATA_EHI_SETMODE; } /* suspend devices */ diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 47ea111d5ace..8eaace94d963 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -671,7 +671,7 @@ void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc, } /* - * ata_gen_ata_desc_sense - Generate check condition sense block. + * ata_gen_passthru_sense - Generate check condition sense block. * @qc: Command that completed. * * This function is specific to the ATA descriptor format sense @@ -681,9 +681,9 @@ void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc, * block. Clear sense key, ASC & ASCQ if there is no error. * * LOCKING: - * spin_lock_irqsave(host lock) + * None. */ -void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc) +static void ata_gen_passthru_sense(struct ata_queued_cmd *qc) { struct scsi_cmnd *cmd = qc->scsicmd; struct ata_taskfile *tf = &qc->result_tf; @@ -713,12 +713,9 @@ void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc) desc[0] = 0x09; - /* - * Set length of additional sense data. - * Since we only populate descriptor 0, the total - * length is the same (fixed) length as descriptor 0. - */ - desc[1] = sb[7] = 14; + /* set length of additional sense data */ + sb[7] = 14; + desc[1] = 12; /* * Copy registers into sense buffer. @@ -746,56 +743,56 @@ void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc) } /** - * ata_gen_fixed_sense - generate a SCSI fixed sense block + * ata_gen_ata_sense - generate a SCSI fixed sense block * @qc: Command that we are erroring out * - * Leverage ata_to_sense_error() to give us the codes. Fit our - * LBA in here if there's room. + * Generate sense block for a failed ATA command @qc. Descriptor + * format is used to accomodate LBA48 block address. * * LOCKING: - * inherited from caller + * None. */ -void ata_gen_fixed_sense(struct ata_queued_cmd *qc) +static void ata_gen_ata_sense(struct ata_queued_cmd *qc) { + struct ata_device *dev = qc->dev; struct scsi_cmnd *cmd = qc->scsicmd; struct ata_taskfile *tf = &qc->result_tf; unsigned char *sb = cmd->sense_buffer; + unsigned char *desc = sb + 8; int verbose = qc->ap->ops->error_handler == NULL; + u64 block; memset(sb, 0, SCSI_SENSE_BUFFERSIZE); cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; - /* - * Use ata_to_sense_error() to map status register bits + /* sense data is current and format is descriptor */ + sb[0] = 0x72; + + /* Use ata_to_sense_error() to map status register bits * onto sense key, asc & ascq. */ if (qc->err_mask || tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) { ata_to_sense_error(qc->ap->id, tf->command, tf->feature, - &sb[2], &sb[12], &sb[13], verbose); - sb[2] &= 0x0f; + &sb[1], &sb[2], &sb[3], verbose); + sb[1] &= 0x0f; } - sb[0] = 0x70; - sb[7] = 0x0a; - - if (tf->flags & ATA_TFLAG_LBA48) { - /* TODO: find solution for LBA48 descriptors */ - } + block = ata_tf_read_block(&qc->result_tf, dev); - else if (tf->flags & ATA_TFLAG_LBA) { - /* A small (28b) LBA will fit in the 32b info field */ - sb[0] |= 0x80; /* set valid bit */ - sb[3] = tf->device & 0x0f; - sb[4] = tf->lbah; - sb[5] = tf->lbam; - sb[6] = tf->lbal; - } + /* information sense data descriptor */ + sb[7] = 12; + desc[0] = 0x00; + desc[1] = 10; - else { - /* TODO: C/H/S */ - } + desc[2] |= 0x80; /* valid */ + desc[6] = block >> 40; + desc[7] = block >> 32; + desc[8] = block >> 24; + desc[9] = block >> 16; + desc[10] = block >> 8; + desc[11] = block; } static void ata_scsi_sdev_config(struct scsi_device *sdev) @@ -807,23 +804,10 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev) static void ata_scsi_dev_config(struct scsi_device *sdev, struct ata_device *dev) { - unsigned int max_sectors; - - /* TODO: 2048 is an arbitrary number, not the - * hardware maximum. This should be increased to - * 65534 when Jens Axboe's patch for dynamically - * determining max_sectors is merged. - */ - max_sectors = ATA_MAX_SECTORS; - if (dev->flags & ATA_DFLAG_LBA48) - max_sectors = ATA_MAX_SECTORS_LBA48; - if (dev->max_sectors) - max_sectors = dev->max_sectors; + /* configure max sectors */ + blk_queue_max_sectors(sdev->request_queue, dev->max_sectors); - blk_queue_max_sectors(sdev->request_queue, max_sectors); - - /* - * SATA DMA transfers must be multiples of 4 byte, so + /* SATA DMA transfers must be multiples of 4 byte, so * we need to pad ATAPI transfers using an extra sg. * Decrement max hw segments accordingly. */ @@ -1040,8 +1024,7 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, const u8 *scs tf->flags |= ATA_TFLAG_DEVICE; tf->protocol = ATA_PROT_NODATA; - if ((qc->dev->flags & ATA_DFLAG_LBA48) && - (ata_id_has_flush_ext(qc->dev->id))) + if (qc->dev->flags & ATA_DFLAG_FLUSH_EXT) tf->command = ATA_CMD_FLUSH_EXT; else tf->command = ATA_CMD_FLUSH; @@ -1282,17 +1265,14 @@ nothing_to_do: static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) { - struct ata_taskfile *tf = &qc->tf; - struct ata_device *dev = qc->dev; + unsigned int tf_flags = 0; u64 block; u32 n_block; - - qc->flags |= ATA_QCFLAG_IO; - tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + int rc; if (scsicmd[0] == WRITE_10 || scsicmd[0] == WRITE_6 || scsicmd[0] == WRITE_16) - tf->flags |= ATA_TFLAG_WRITE; + tf_flags |= ATA_TFLAG_WRITE; /* Calculate the SCSI LBA, transfer length and FUA. */ switch (scsicmd[0]) { @@ -1300,7 +1280,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm case WRITE_10: scsi_10_lba_len(scsicmd, &block, &n_block); if (unlikely(scsicmd[1] & (1 << 3))) - tf->flags |= ATA_TFLAG_FUA; + tf_flags |= ATA_TFLAG_FUA; break; case READ_6: case WRITE_6: @@ -1316,7 +1296,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm case WRITE_16: scsi_16_lba_len(scsicmd, &block, &n_block); if (unlikely(scsicmd[1] & (1 << 3))) - tf->flags |= ATA_TFLAG_FUA; + tf_flags |= ATA_TFLAG_FUA; break; default: DPRINTK("no-byte command\n"); @@ -1334,106 +1314,17 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm */ goto nothing_to_do; - if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ_OFF | - ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) { - /* yay, NCQ */ - if (!lba_48_ok(block, n_block)) - goto out_of_range; - - tf->protocol = ATA_PROT_NCQ; - tf->flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48; - - if (tf->flags & ATA_TFLAG_WRITE) - tf->command = ATA_CMD_FPDMA_WRITE; - else - tf->command = ATA_CMD_FPDMA_READ; - - qc->nsect = n_block; - - tf->nsect = qc->tag << 3; - tf->hob_feature = (n_block >> 8) & 0xff; - tf->feature = n_block & 0xff; - - tf->hob_lbah = (block >> 40) & 0xff; - tf->hob_lbam = (block >> 32) & 0xff; - tf->hob_lbal = (block >> 24) & 0xff; - tf->lbah = (block >> 16) & 0xff; - tf->lbam = (block >> 8) & 0xff; - tf->lbal = block & 0xff; - - tf->device = 1 << 6; - if (tf->flags & ATA_TFLAG_FUA) - tf->device |= 1 << 7; - } else if (dev->flags & ATA_DFLAG_LBA) { - tf->flags |= ATA_TFLAG_LBA; - - if (lba_28_ok(block, n_block)) { - /* use LBA28 */ - tf->device |= (block >> 24) & 0xf; - } else if (lba_48_ok(block, n_block)) { - if (!(dev->flags & ATA_DFLAG_LBA48)) - goto out_of_range; - - /* use LBA48 */ - tf->flags |= ATA_TFLAG_LBA48; - - tf->hob_nsect = (n_block >> 8) & 0xff; - - tf->hob_lbah = (block >> 40) & 0xff; - tf->hob_lbam = (block >> 32) & 0xff; - tf->hob_lbal = (block >> 24) & 0xff; - } else - /* request too large even for LBA48 */ - goto out_of_range; - - if (unlikely(ata_rwcmd_protocol(qc) < 0)) - goto invalid_fld; - - qc->nsect = n_block; - tf->nsect = n_block & 0xff; - - tf->lbah = (block >> 16) & 0xff; - tf->lbam = (block >> 8) & 0xff; - tf->lbal = block & 0xff; - - tf->device |= ATA_LBA; - } else { - /* CHS */ - u32 sect, head, cyl, track; - - /* The request -may- be too large for CHS addressing. */ - if (!lba_28_ok(block, n_block)) - goto out_of_range; - - if (unlikely(ata_rwcmd_protocol(qc) < 0)) - goto invalid_fld; - - /* Convert LBA to CHS */ - track = (u32)block / dev->sectors; - cyl = track / dev->heads; - head = track % dev->heads; - sect = (u32)block % dev->sectors + 1; - - DPRINTK("block %u track %u cyl %u head %u sect %u\n", - (u32)block, track, cyl, head, sect); - - /* Check whether the converted CHS can fit. - Cylinder: 0-65535 - Head: 0-15 - Sector: 1-255*/ - if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) - goto out_of_range; - - qc->nsect = n_block; - tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */ - tf->lbal = sect; - tf->lbam = cyl; - tf->lbah = cyl >> 8; - tf->device |= head; - } + qc->flags |= ATA_QCFLAG_IO; + qc->nsect = n_block; - return 0; + rc = ata_build_rw_tf(&qc->tf, qc->dev, block, n_block, tf_flags, + qc->tag); + if (likely(rc == 0)) + return 0; + if (rc == -ERANGE) + goto out_of_range; + /* treat all other errors as -EINVAL, fall through */ invalid_fld: ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0); /* "Invalid field in cbd" */ @@ -1477,7 +1368,7 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) */ if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) && ((cdb[2] & 0x20) || need_sense)) { - ata_gen_ata_desc_sense(qc); + ata_gen_passthru_sense(qc); } else { if (!need_sense) { cmd->result = SAM_STAT_GOOD; @@ -1488,7 +1379,7 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) * good for smaller LBA (and maybe CHS?) * devices. */ - ata_gen_fixed_sense(qc); + ata_gen_ata_sense(qc); } } @@ -1715,6 +1606,22 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args, } /** + * ATA_SCSI_RBUF_SET - helper to set values in SCSI response buffer + * @idx: byte index into SCSI response buffer + * @val: value to set + * + * To be used by SCSI command simulator functions. This macros + * expects two local variables, u8 *rbuf and unsigned int buflen, + * are in scope. + * + * LOCKING: + * None. + */ +#define ATA_SCSI_RBUF_SET(idx, val) do { \ + if ((idx) < buflen) rbuf[(idx)] = (u8)(val); \ + } while (0) + +/** * ata_scsiop_inq_std - Simulate INQUIRY command * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. @@ -2173,67 +2080,42 @@ saving_not_supp: * Simulate READ CAPACITY commands. * * LOCKING: - * spin_lock_irqsave(host lock) + * None. */ - unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen) { - u64 n_sectors; - u32 tmp; + u64 last_lba = args->dev->n_sectors - 1; /* LBA of the last block */ VPRINTK("ENTER\n"); - if (ata_id_has_lba(args->id)) { - if (ata_id_has_lba48(args->id)) - n_sectors = ata_id_u64(args->id, 100); - else - n_sectors = ata_id_u32(args->id, 60); - } else { - /* CHS default translation */ - n_sectors = args->id[1] * args->id[3] * args->id[6]; - - if (ata_id_current_chs_valid(args->id)) - /* CHS current translation */ - n_sectors = ata_id_u32(args->id, 57); - } - - n_sectors--; /* ATA TotalUserSectors - 1 */ - if (args->cmd->cmnd[0] == READ_CAPACITY) { - if( n_sectors >= 0xffffffffULL ) - tmp = 0xffffffff ; /* Return max count on overflow */ - else - tmp = n_sectors ; + if (last_lba >= 0xffffffffULL) + last_lba = 0xffffffff; /* sector count, 32-bit */ - rbuf[0] = tmp >> (8 * 3); - rbuf[1] = tmp >> (8 * 2); - rbuf[2] = tmp >> (8 * 1); - rbuf[3] = tmp; + ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 3)); + ATA_SCSI_RBUF_SET(1, last_lba >> (8 * 2)); + ATA_SCSI_RBUF_SET(2, last_lba >> (8 * 1)); + ATA_SCSI_RBUF_SET(3, last_lba); /* sector size */ - tmp = ATA_SECT_SIZE; - rbuf[6] = tmp >> 8; - rbuf[7] = tmp; - + ATA_SCSI_RBUF_SET(6, ATA_SECT_SIZE >> 8); + ATA_SCSI_RBUF_SET(7, ATA_SECT_SIZE); } else { /* sector count, 64-bit */ - tmp = n_sectors >> (8 * 4); - rbuf[2] = tmp >> (8 * 3); - rbuf[3] = tmp >> (8 * 2); - rbuf[4] = tmp >> (8 * 1); - rbuf[5] = tmp; - tmp = n_sectors; - rbuf[6] = tmp >> (8 * 3); - rbuf[7] = tmp >> (8 * 2); - rbuf[8] = tmp >> (8 * 1); - rbuf[9] = tmp; + ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 7)); + ATA_SCSI_RBUF_SET(1, last_lba >> (8 * 6)); + ATA_SCSI_RBUF_SET(2, last_lba >> (8 * 5)); + ATA_SCSI_RBUF_SET(3, last_lba >> (8 * 4)); + ATA_SCSI_RBUF_SET(4, last_lba >> (8 * 3)); + ATA_SCSI_RBUF_SET(5, last_lba >> (8 * 2)); + ATA_SCSI_RBUF_SET(6, last_lba >> (8 * 1)); + ATA_SCSI_RBUF_SET(7, last_lba); /* sector size */ - tmp = ATA_SECT_SIZE; - rbuf[12] = tmp >> 8; - rbuf[13] = tmp; + ATA_SCSI_RBUF_SET(10, ATA_SECT_SIZE >> 8); + ATA_SCSI_RBUF_SET(11, ATA_SECT_SIZE); } return 0; @@ -2319,7 +2201,7 @@ static void atapi_sense_complete(struct ata_queued_cmd *qc) * a sense descriptors, since that's only * correct for ATA, not ATAPI */ - ata_gen_ata_desc_sense(qc); + ata_gen_passthru_sense(qc); } qc->scsidone(qc->scsicmd); @@ -2394,7 +2276,7 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc) * sense descriptors, since that's only * correct for ATA, not ATAPI */ - ata_gen_ata_desc_sense(qc); + ata_gen_passthru_sense(qc); } /* SCSI EH automatically locks door if sdev->locked is @@ -2427,7 +2309,7 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc) * a sense descriptors, since that's only * correct for ATA, not ATAPI */ - ata_gen_ata_desc_sense(qc); + ata_gen_passthru_sense(qc); } else { u8 *scsicmd = cmd->cmnd; @@ -3182,10 +3064,12 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, rc = -EINVAL; } - if (rc == 0) + if (rc == 0) { ata_port_schedule_eh(ap); - - spin_unlock_irqrestore(ap->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); + ata_port_wait_eh(ap); + } else + spin_unlock_irqrestore(ap->lock, flags); return rc; } @@ -3205,15 +3089,27 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, void ata_scsi_dev_rescan(void *data) { struct ata_port *ap = data; - struct ata_device *dev; + unsigned long flags; unsigned int i; + spin_lock_irqsave(ap->lock, flags); + for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; + struct ata_device *dev = &ap->device[i]; + struct scsi_device *sdev = dev->sdev; - if (ata_dev_enabled(dev) && dev->sdev) - scsi_rescan_device(&(dev->sdev->sdev_gendev)); + if (!ata_dev_enabled(dev) || !sdev) + continue; + if (scsi_device_get(sdev)) + continue; + + spin_unlock_irqrestore(ap->lock, flags); + scsi_rescan_device(&(sdev->sdev_gendev)); + scsi_device_put(sdev); + spin_lock_irqsave(ap->lock, flags); } + + spin_unlock_irqrestore(ap->lock, flags); } /** diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 7645f2b30ccf..10ee22ae5c15 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -39,6 +39,35 @@ #include "libata.h" /** + * ata_irq_on - Enable interrupts on a port. + * @ap: Port on which interrupts are enabled. + * + * Enable interrupts on a legacy IDE device using MMIO or PIO, + * wait for idle, clear any pending interrupts. + * + * LOCKING: + * Inherited from caller. + */ +u8 ata_irq_on(struct ata_port *ap) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + u8 tmp; + + ap->ctl &= ~ATA_NIEN; + ap->last_ctl = ap->ctl; + + if (ap->flags & ATA_FLAG_MMIO) + writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); + else + outb(ap->ctl, ioaddr->ctl_addr); + tmp = ata_wait_idle(ap); + + ap->ops->irq_clear(ap); + + return tmp; +} + +/** * ata_tf_load_pio - send taskfile registers to host controller * @ap: Port to which output is sent * @tf: ATA taskfile register set @@ -671,6 +700,14 @@ void ata_bmdma_freeze(struct ata_port *ap) writeb(ap->ctl, (void __iomem *)ioaddr->ctl_addr); else outb(ap->ctl, ioaddr->ctl_addr); + + /* Under certain circumstances, some controllers raise IRQ on + * ATA_NIEN manipulation. Also, many controllers fail to mask + * previously pending IRQ on ATA_NIEN assertion. Clear it. + */ + ata_chk_status(ap); + + ap->ops->irq_clear(ap); } /** @@ -714,7 +751,6 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { - struct ata_eh_context *ehc = &ap->eh_context; struct ata_queued_cmd *qc; unsigned long flags; int thaw = 0; @@ -732,9 +768,7 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset, qc->tf.protocol == ATA_PROT_ATAPI_DMA)) { u8 host_stat; - host_stat = ata_bmdma_status(ap); - - ata_ehi_push_desc(&ehc->i, "BMDMA stat 0x%x", host_stat); + host_stat = ap->ops->bmdma_status(ap); /* BMDMA controllers indicate host bus error by * setting DMA_ERR bit and timing out. As it wasn't @@ -877,6 +911,7 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, return NULL; probe_ent->n_ports = 2; + probe_ent->irq_flags = IRQF_SHARED; if (port_mask & ATA_PORT_PRIMARY) { probe_ent->irq = ATA_PRIMARY_IRQ; diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 0ed263be652a..107b2b565229 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -39,26 +39,39 @@ struct ata_scsi_args { }; /* libata-core.c */ +enum { + /* flags for ata_dev_read_id() */ + ATA_READID_POSTRESET = (1 << 0), /* reading ID after reset */ +}; + extern struct workqueue_struct *ata_aux_wq; extern int atapi_enabled; extern int atapi_dmadir; extern int libata_fua; extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev); -extern int ata_rwcmd_protocol(struct ata_queued_cmd *qc); +extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev, + u64 block, u32 n_block, unsigned int tf_flags, + unsigned int tag); +extern u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev); extern void ata_dev_disable(struct ata_device *dev); extern void ata_port_flush_task(struct ata_port *ap); extern unsigned ata_exec_internal(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, int dma_dir, void *buf, unsigned int buflen); +extern unsigned ata_exec_internal_sg(struct ata_device *dev, + struct ata_taskfile *tf, const u8 *cdb, + int dma_dir, struct scatterlist *sg, + unsigned int n_elem); extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd); extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, - int post_reset, u16 *id); -extern int ata_dev_revalidate(struct ata_device *dev, int post_reset); -extern int ata_dev_configure(struct ata_device *dev, int print_info); + unsigned int flags, u16 *id); +extern int ata_dev_revalidate(struct ata_device *dev, unsigned int flags); +extern int ata_dev_configure(struct ata_device *dev); extern int sata_down_spd_limit(struct ata_port *ap); extern int sata_set_spd_needed(struct ata_port *ap); extern int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0); extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev); +extern void ata_sg_clean(struct ata_queued_cmd *qc); extern void ata_qc_free(struct ata_queued_cmd *qc); extern void ata_qc_issue(struct ata_queued_cmd *qc); extern void __ata_qc_complete(struct ata_queued_cmd *qc); @@ -120,4 +133,7 @@ extern void ata_scsi_error(struct Scsi_Host *host); extern void ata_port_wait_eh(struct ata_port *ap); extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc); +/* libata-sff.c */ +extern u8 ata_irq_on(struct ata_port *ap); + #endif /* __LIBATA_H__ */ diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 64eed99f6814..c5d61d1911a5 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -34,7 +34,7 @@ #include <linux/dmi.h> #define DRV_NAME "pata_ali" -#define DRV_VERSION "0.6.6" +#define DRV_VERSION "0.7.2" /* * Cable special cases @@ -78,7 +78,7 @@ static int ali_c2_cable_detect(struct ata_port *ap) implement the detect logic */ if (ali_cable_override(pdev)) - return ATA_CBL_PATA80; + return ATA_CBL_PATA40_SHORT; /* Host view cable detect 0x4A bit 0 primary bit 1 secondary Bit set for 40 pin */ @@ -337,9 +337,6 @@ static struct scsi_host_template ali_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - /* Keep LBA28 counts so large I/O's don't turn LBA48 and PIO - with older controllers. Not locked so will grow on C5 or later */ - .max_sectors = 255, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -348,6 +345,8 @@ static struct scsi_host_template ali_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; /* @@ -497,6 +496,69 @@ static struct ata_port_operations ali_c5_port_ops = { .host_stop = ata_host_stop }; + +/** + * ali_init_chipset - chip setup function + * @pdev: PCI device of ATA controller + * + * Perform the setup on the device that must be done both at boot + * and at resume time. + */ + +static void ali_init_chipset(struct pci_dev *pdev) +{ + u8 rev, tmp; + struct pci_dev *north, *isa_bridge; + + pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); + + /* + * The chipset revision selects the driver operations and + * mode data. + */ + + if (rev >= 0x20 && rev < 0xC2) { + /* 1543-E/F, 1543C-C, 1543C-D, 1543C-E */ + pci_read_config_byte(pdev, 0x4B, &tmp); + /* Clear CD-ROM DMA write bit */ + tmp &= 0x7F; + pci_write_config_byte(pdev, 0x4B, tmp); + } else if (rev >= 0xC2) { + /* Enable cable detection logic */ + pci_read_config_byte(pdev, 0x4B, &tmp); + pci_write_config_byte(pdev, 0x4B, tmp | 0x08); + } + north = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); + isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); + + if (north && north->vendor == PCI_VENDOR_ID_AL && isa_bridge) { + /* Configure the ALi bridge logic. For non ALi rely on BIOS. + Set the south bridge enable bit */ + pci_read_config_byte(isa_bridge, 0x79, &tmp); + if (rev == 0xC2) + pci_write_config_byte(isa_bridge, 0x79, tmp | 0x04); + else if (rev > 0xC2 && rev < 0xC5) + pci_write_config_byte(isa_bridge, 0x79, tmp | 0x02); + } + if (rev >= 0x20) { + /* + * CD_ROM DMA on (0x53 bit 0). Enable this even if we want + * to use PIO. 0x53 bit 1 (rev 20 only) - enable FIFO control + * via 0x54/55. + */ + pci_read_config_byte(pdev, 0x53, &tmp); + if (rev <= 0x20) + tmp &= ~0x02; + if (rev >= 0xc7) + tmp |= 0x03; + else + tmp |= 0x01; /* CD_ROM enable for DMA */ + pci_write_config_byte(pdev, 0x53, tmp); + } + pci_dev_put(isa_bridge); + pci_dev_put(north); + ata_pci_clear_simplex(pdev); +} /** * ali_init_one - discovery callback * @pdev: PCI device ID @@ -570,7 +632,7 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) static struct ata_port_info *port_info[2]; u8 rev, tmp; - struct pci_dev *north, *isa_bridge; + struct pci_dev *isa_bridge; pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); @@ -582,11 +644,6 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) if (rev < 0x20) { port_info[0] = port_info[1] = &info_early; } else if (rev < 0xC2) { - /* 1543-E/F, 1543C-C, 1543C-D, 1543C-E */ - pci_read_config_byte(pdev, 0x4B, &tmp); - /* Clear CD-ROM DMA write bit */ - tmp &= 0x7F; - pci_write_config_byte(pdev, 0x4B, tmp); port_info[0] = port_info[1] = &info_20; } else if (rev == 0xC2) { port_info[0] = port_info[1] = &info_c2; @@ -597,54 +654,25 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) } else port_info[0] = port_info[1] = &info_c5; - if (rev >= 0xC2) { - /* Enable cable detection logic */ - pci_read_config_byte(pdev, 0x4B, &tmp); - pci_write_config_byte(pdev, 0x4B, tmp | 0x08); - } - - north = pci_get_slot(pdev->bus, PCI_DEVFN(0,0)); + ali_init_chipset(pdev); + isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); - - if (north && north->vendor == PCI_VENDOR_ID_AL) { - /* Configure the ALi bridge logic. For non ALi rely on BIOS. - Set the south bridge enable bit */ - pci_read_config_byte(isa_bridge, 0x79, &tmp); - if (rev == 0xC2) - pci_write_config_byte(isa_bridge, 0x79, tmp | 0x04); - else if (rev > 0xC2) - pci_write_config_byte(isa_bridge, 0x79, tmp | 0x02); - } - - if (rev >= 0x20) { - if (rev < 0xC2) { - /* Are we paired with a UDMA capable chip */ - pci_read_config_byte(isa_bridge, 0x5E, &tmp); - if ((tmp & 0x1E) == 0x12) - port_info[0] = port_info[1] = &info_20_udma; - } - /* - * CD_ROM DMA on (0x53 bit 0). Enable this even if we want - * to use PIO. 0x53 bit 1 (rev 20 only) - enable FIFO control - * via 0x54/55. - */ - pci_read_config_byte(pdev, 0x53, &tmp); - if (rev <= 0x20) - tmp &= ~0x02; - if (rev >= 0xc7) - tmp |= 0x03; - else - tmp |= 0x01; /* CD_ROM enable for DMA */ - pci_write_config_byte(pdev, 0x53, tmp); + if (isa_bridge && rev >= 0x20 && rev < 0xC2) { + /* Are we paired with a UDMA capable chip */ + pci_read_config_byte(isa_bridge, 0x5E, &tmp); + if ((tmp & 0x1E) == 0x12) + port_info[0] = port_info[1] = &info_20_udma; + pci_dev_put(isa_bridge); } - - pci_dev_put(isa_bridge); - pci_dev_put(north); - - ata_pci_clear_simplex(pdev); return ata_pci_init_one(pdev, port_info, 2); } +static int ali_reinit_one(struct pci_dev *pdev) +{ + ali_init_chipset(pdev); + return ata_pci_device_resume(pdev); +} + static const struct pci_device_id ali[] = { { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), }, { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5229), }, @@ -656,7 +684,9 @@ static struct pci_driver ali_pci_driver = { .name = DRV_NAME, .id_table = ali, .probe = ali_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ali_reinit_one, }; static int __init ali_init(void) diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 8be46a63af74..a6b330089f22 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -25,7 +25,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_amd" -#define DRV_VERSION "0.2.4" +#define DRV_VERSION "0.2.7" /** * timing_setup - shared timing computation and load @@ -326,7 +326,6 @@ static struct scsi_host_template amd_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -335,6 +334,8 @@ static struct scsi_host_template amd_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations amd33_port_ops = { @@ -662,6 +663,23 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return ata_pci_init_one(pdev, port_info, 2); } +static int amd_reinit_one(struct pci_dev *pdev) +{ + if (pdev->vendor == PCI_VENDOR_ID_AMD) { + u8 fifo; + pci_read_config_byte(pdev, 0x41, &fifo); + if (pdev->device == PCI_DEVICE_ID_AMD_VIPER_7411) + /* FIFO is broken */ + pci_write_config_byte(pdev, 0x41, fifo & 0x0F); + else + pci_write_config_byte(pdev, 0x41, fifo | 0xF0); + if (pdev->device == PCI_DEVICE_ID_AMD_VIPER_7409 || + pdev->device == PCI_DEVICE_ID_AMD_COBRA_7401) + ata_pci_clear_simplex(pdev); + } + return ata_pci_device_resume(pdev); +} + static const struct pci_device_id amd[] = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_COBRA_7401), 0 }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_VIPER_7409), 1 }, @@ -689,7 +707,9 @@ static struct pci_driver amd_pci_driver = { .name = DRV_NAME, .id_table = amd, .probe = amd_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = amd_reinit_one, }; static int __init amd_init(void) diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index 2cd30761ca1f..37bc1323bda7 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c @@ -307,7 +307,6 @@ static struct scsi_host_template artop_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 4e1d3b59adbb..6f6672c55131 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -22,7 +22,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_atiixp" -#define DRV_VERSION "0.4.3" +#define DRV_VERSION "0.4.4" enum { ATIIXP_IDE_PIO_TIMING = 0x40, @@ -209,7 +209,6 @@ static struct scsi_host_template atiixp_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -218,6 +217,8 @@ static struct scsi_host_template atiixp_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations atiixp_port_ops = { @@ -281,7 +282,9 @@ static struct pci_driver atiixp_pci_driver = { .name = DRV_NAME, .id_table = atiixp, .probe = atiixp_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .resume = ata_pci_device_resume, + .suspend = ata_pci_device_suspend, }; static int __init atiixp_init(void) diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index 29a60df465da..15841a563694 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -31,7 +31,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_cmd64x" -#define DRV_VERSION "0.2.1" +#define DRV_VERSION "0.2.2" /* * CMD64x specific registers definition. @@ -268,7 +268,6 @@ static struct scsi_host_template cmd64x_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -277,6 +276,8 @@ static struct scsi_host_template cmd64x_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations cmd64x_port_ops = { @@ -469,6 +470,20 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return ata_pci_init_one(pdev, port_info, 2); } +static int cmd64x_reinit_one(struct pci_dev *pdev) +{ + u8 mrdmode; + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); + pci_read_config_byte(pdev, MRDMODE, &mrdmode); + mrdmode &= ~ 0x30; /* IRQ set up */ + mrdmode |= 0x02; /* Memory read line enable */ + pci_write_config_byte(pdev, MRDMODE, mrdmode); +#ifdef CONFIG_PPC + pci_write_config_byte(pdev, UDIDETCR0, 0xF0); +#endif + return ata_pci_device_resume(pdev); +} + static const struct pci_device_id cmd64x[] = { { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_643), 0 }, { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_646), 1 }, @@ -482,7 +497,9 @@ static struct pci_driver cmd64x_pci_driver = { .name = DRV_NAME, .id_table = cmd64x, .probe = cmd64x_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = cmd64x_reinit_one, }; static int __init cmd64x_init(void) diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index 33d2b88f9c79..9f165a8e032d 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -41,7 +41,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_cs5520" -#define DRV_VERSION "0.6.2" +#define DRV_VERSION "0.6.3" struct pio_clocks { @@ -159,7 +159,6 @@ static struct scsi_host_template cs5520_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -168,6 +167,8 @@ static struct scsi_host_template cs5520_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations cs5520_port_ops = { @@ -297,6 +298,22 @@ static void __devexit cs5520_remove_one(struct pci_dev *pdev) dev_set_drvdata(dev, NULL); } +/** + * cs5520_reinit_one - device resume + * @pdev: PCI device + * + * Do any reconfiguration work needed by a resume from RAM. We need + * to restore DMA mode support on BIOSen which disabled it + */ + +static int cs5520_reinit_one(struct pci_dev *pdev) +{ + u8 pcicfg; + pci_read_config_byte(pdev, 0x60, &pcicfg); + if ((pcicfg & 0x40) == 0) + pci_write_config_byte(pdev, 0x60, pcicfg | 0x40); + return ata_pci_device_resume(pdev); +} /* For now keep DMA off. We can set it for all but A rev CS5510 once the core ATA code can handle it */ @@ -311,7 +328,9 @@ static struct pci_driver cs5520_pci_driver = { .name = DRV_NAME, .id_table = pata_cs5520, .probe = cs5520_init_one, - .remove = cs5520_remove_one + .remove = cs5520_remove_one, + .suspend = ata_pci_device_suspend, + .resume = cs5520_reinit_one, }; static int __init cs5520_init(void) diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index 981f49223469..1c628014dae6 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -35,7 +35,7 @@ #include <linux/dmi.h> #define DRV_NAME "pata_cs5530" -#define DRV_VERSION "0.6" +#define DRV_VERSION "0.7.1" /** * cs5530_set_piomode - PIO setup @@ -173,7 +173,6 @@ static struct scsi_host_template cs5530_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -182,6 +181,8 @@ static struct scsi_host_template cs5530_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations cs5530_port_ops = { @@ -239,38 +240,18 @@ static int cs5530_is_palmax(void) return 0; } + /** - * cs5530_init_one - Initialise a CS5530 - * @dev: PCI device - * @id: Entry in match table + * cs5530_init_chip - Chipset init * - * Install a driver for the newly found CS5530 companion chip. Most of - * this is just housekeeping. We have to set the chip up correctly and - * turn off various bits of emulation magic. + * Perform the chip initialisation work that is shared between both + * setup and resume paths */ - -static int cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id) + +static int cs5530_init_chip(void) { - int compiler_warning_pointless_fix; - struct pci_dev *master_0 = NULL, *cs5530_0 = NULL; - static struct ata_port_info info = { - .sht = &cs5530_sht, - .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST, - .pio_mask = 0x1f, - .mwdma_mask = 0x07, - .udma_mask = 0x07, - .port_ops = &cs5530_port_ops - }; - /* The docking connector doesn't do UDMA, and it seems not MWDMA */ - static struct ata_port_info info_palmax_secondary = { - .sht = &cs5530_sht, - .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST, - .pio_mask = 0x1f, - .port_ops = &cs5530_port_ops - }; - static struct ata_port_info *port_info[2] = { &info, &info }; + struct pci_dev *master_0 = NULL, *cs5530_0 = NULL, *dev = NULL; - dev = NULL; while ((dev = pci_get_device(PCI_VENDOR_ID_CYRIX, PCI_ANY_ID, dev)) != NULL) { switch (dev->device) { case PCI_DEVICE_ID_CYRIX_PCI_MASTER: @@ -291,7 +272,7 @@ static int cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id) } pci_set_master(cs5530_0); - compiler_warning_pointless_fix = pci_set_mwi(cs5530_0); + pci_set_mwi(cs5530_0); /* * Set PCI CacheLineSize to 16-bytes: @@ -339,13 +320,7 @@ static int cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id) pci_dev_put(master_0); pci_dev_put(cs5530_0); - - if (cs5530_is_palmax()) - port_info[1] = &info_palmax_secondary; - - /* Now kick off ATA set up */ - return ata_pci_init_one(dev, port_info, 2); - + return 0; fail_put: if (master_0) pci_dev_put(master_0); @@ -354,6 +329,53 @@ fail_put: return -ENODEV; } +/** + * cs5530_init_one - Initialise a CS5530 + * @dev: PCI device + * @id: Entry in match table + * + * Install a driver for the newly found CS5530 companion chip. Most of + * this is just housekeeping. We have to set the chip up correctly and + * turn off various bits of emulation magic. + */ + +static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id) +{ + static struct ata_port_info info = { + .sht = &cs5530_sht, + .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST, + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x07, + .port_ops = &cs5530_port_ops + }; + /* The docking connector doesn't do UDMA, and it seems not MWDMA */ + static struct ata_port_info info_palmax_secondary = { + .sht = &cs5530_sht, + .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST, + .pio_mask = 0x1f, + .port_ops = &cs5530_port_ops + }; + static struct ata_port_info *port_info[2] = { &info, &info }; + + /* Chip initialisation */ + if (cs5530_init_chip()) + return -ENODEV; + + if (cs5530_is_palmax()) + port_info[1] = &info_palmax_secondary; + + /* Now kick off ATA set up */ + return ata_pci_init_one(pdev, port_info, 2); +} + +static int cs5530_reinit_one(struct pci_dev *pdev) +{ + /* If we fail on resume we are doomed */ + BUG_ON(cs5530_init_chip()); + return ata_pci_device_resume(pdev); +} + static const struct pci_device_id cs5530[] = { { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), }, @@ -364,7 +386,9 @@ static struct pci_driver cs5530_pci_driver = { .name = DRV_NAME, .id_table = cs5530, .probe = cs5530_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = cs5530_reinit_one, }; static int __init cs5530_init(void) diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index 8dafa4a49fdc..e3efec4ffc79 100644 --- a/drivers/ata/pata_cs5535.c +++ b/drivers/ata/pata_cs5535.c @@ -39,7 +39,7 @@ #include <asm/msr.h> #define DRV_NAME "cs5535" -#define DRV_VERSION "0.2.10" +#define DRV_VERSION "0.2.11" /* * The Geode (Aka Athlon GX now) uses an internal MSR based @@ -177,7 +177,6 @@ static struct scsi_host_template cs5535_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -186,6 +185,8 @@ static struct scsi_host_template cs5535_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations cs5535_port_ops = { @@ -268,7 +269,9 @@ static struct pci_driver cs5535_pci_driver = { .name = DRV_NAME, .id_table = cs5535, .probe = cs5535_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init cs5535_init(void) diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c index 5a0b811907ee..e2a95699bae7 100644 --- a/drivers/ata/pata_cypress.c +++ b/drivers/ata/pata_cypress.c @@ -18,7 +18,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_cypress" -#define DRV_VERSION "0.1.2" +#define DRV_VERSION "0.1.4" /* here are the offset definitions for the registers */ @@ -128,7 +128,6 @@ static struct scsi_host_template cy82c693_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -137,6 +136,8 @@ static struct scsi_host_template cy82c693_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations cy82c693_port_ops = { @@ -204,7 +205,9 @@ static struct pci_driver cy82c693_pci_driver = { .name = DRV_NAME, .id_table = cy82c693, .probe = cy82c693_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init cy82c693_init(void) diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index 755f79279de3..edf8a63f50af 100644 --- a/drivers/ata/pata_efar.c +++ b/drivers/ata/pata_efar.c @@ -22,7 +22,7 @@ #include <linux/ata.h> #define DRV_NAME "pata_efar" -#define DRV_VERSION "0.4.2" +#define DRV_VERSION "0.4.3" /** * efar_pre_reset - check for 40/80 pin @@ -226,7 +226,6 @@ static struct scsi_host_template efar_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -235,6 +234,8 @@ static struct scsi_host_template efar_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static const struct ata_port_operations efar_ops = { @@ -316,6 +317,8 @@ static struct pci_driver efar_pci_driver = { .id_table = efar_pci_tbl, .probe = efar_init_one, .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init efar_init(void) diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index c0e150a9586b..2663599a7c02 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -27,7 +27,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_hpt366" -#define DRV_VERSION "0.5" +#define DRV_VERSION "0.5.3" struct hpt_clock { u8 xfer_speed; @@ -222,9 +222,17 @@ static u32 hpt36x_find_mode(struct ata_port *ap, int speed) static int hpt36x_pre_reset(struct ata_port *ap) { + static const struct pci_bits hpt36x_enable_bits[] = { + { 0x50, 1, 0x04, 0x04 }, + { 0x54, 1, 0x04, 0x04 } + }; + u8 ata66; struct pci_dev *pdev = to_pci_dev(ap->host->dev); + if (!pci_test_config_bits(pdev, &hpt36x_enable_bits[ap->port_no])) + return -ENOENT; + pci_read_config_byte(pdev, 0x5A, &ata66); if (ata66 & (1 << ap->port_no)) ap->cbl = ATA_CBL_PATA40; @@ -322,7 +330,6 @@ static struct scsi_host_template hpt36x_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -331,6 +338,8 @@ static struct scsi_host_template hpt36x_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; /* @@ -373,6 +382,27 @@ static struct ata_port_operations hpt366_port_ops = { }; /** + * hpt36x_init_chipset - common chip setup + * @dev: PCI device + * + * Perform the chip setup work that must be done at both init and + * resume time + */ + +static void hpt36x_init_chipset(struct pci_dev *dev) +{ + u8 drive_fast; + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4)); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78); + pci_write_config_byte(dev, PCI_MIN_GNT, 0x08); + pci_write_config_byte(dev, PCI_MAX_LAT, 0x08); + + pci_read_config_byte(dev, 0x51, &drive_fast); + if (drive_fast & 0x80) + pci_write_config_byte(dev, 0x51, drive_fast & ~0x80); +} + +/** * hpt36x_init_one - Initialise an HPT366/368 * @dev: PCI device * @id: Entry in match table @@ -407,7 +437,6 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id) u32 class_rev; u32 reg1; - u8 drive_fast; pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xFF; @@ -417,14 +446,7 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id) if (class_rev > 2) return -ENODEV; - pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4)); - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78); - pci_write_config_byte(dev, PCI_MIN_GNT, 0x08); - pci_write_config_byte(dev, PCI_MAX_LAT, 0x08); - - pci_read_config_byte(dev, 0x51, &drive_fast); - if (drive_fast & 0x80) - pci_write_config_byte(dev, 0x51, drive_fast & ~0x80); + hpt36x_init_chipset(dev); pci_read_config_dword(dev, 0x40, ®1); @@ -445,9 +467,15 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id) return ata_pci_init_one(dev, port_info, 2); } +static int hpt36x_reinit_one(struct pci_dev *dev) +{ + hpt36x_init_chipset(dev); + return ata_pci_device_resume(dev); +} + + static const struct pci_device_id hpt36x[] = { { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), }, - { }, }; @@ -455,7 +483,9 @@ static struct pci_driver hpt36x_pci_driver = { .name = DRV_NAME, .id_table = hpt36x, .probe = hpt36x_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = hpt36x_reinit_one, }; static int __init hpt36x_init(void) @@ -463,13 +493,11 @@ static int __init hpt36x_init(void) return pci_register_driver(&hpt36x_pci_driver); } - static void __exit hpt36x_exit(void) { pci_unregister_driver(&hpt36x_pci_driver); } - MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for the Highpoint HPT366/368"); MODULE_LICENSE("GPL"); diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index 1eeb16f0fb02..47082df7199e 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -768,7 +768,6 @@ static struct scsi_host_template hpt37x_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index 47d7664e9eee..f6817b4093a4 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -334,7 +334,6 @@ static struct scsi_host_template hpt3x2n_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c index d216cc564b56..5f1d385eb592 100644 --- a/drivers/ata/pata_hpt3x3.c +++ b/drivers/ata/pata_hpt3x3.c @@ -23,7 +23,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_hpt3x3" -#define DRV_VERSION "0.4.1" +#define DRV_VERSION "0.4.2" static int hpt3x3_probe_init(struct ata_port *ap) { @@ -111,7 +111,6 @@ static struct scsi_host_template hpt3x3_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -120,6 +119,8 @@ static struct scsi_host_template hpt3x3_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations hpt3x3_port_ops = { @@ -158,6 +159,27 @@ static struct ata_port_operations hpt3x3_port_ops = { }; /** + * hpt3x3_init_chipset - chip setup + * @dev: PCI device + * + * Perform the setup required at boot and on resume. + */ + +static void hpt3x3_init_chipset(struct pci_dev *dev) +{ + u16 cmd; + /* Initialize the board */ + pci_write_config_word(dev, 0x80, 0x00); + /* Check if it is a 343 or a 363. 363 has COMMAND_MEMORY set */ + pci_read_config_word(dev, PCI_COMMAND, &cmd); + if (cmd & PCI_COMMAND_MEMORY) + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0); + else + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); +} + + +/** * hpt3x3_init_one - Initialise an HPT343/363 * @dev: PCI device * @id: Entry in match table @@ -178,21 +200,18 @@ static int hpt3x3_init_one(struct pci_dev *dev, const struct pci_device_id *id) .port_ops = &hpt3x3_port_ops }; static struct ata_port_info *port_info[2] = { &info, &info }; - u16 cmd; - - /* Initialize the board */ - pci_write_config_word(dev, 0x80, 0x00); - /* Check if it is a 343 or a 363. 363 has COMMAND_MEMORY set */ - pci_read_config_word(dev, PCI_COMMAND, &cmd); - if (cmd & PCI_COMMAND_MEMORY) - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0); - else - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); + hpt3x3_init_chipset(dev); /* Now kick off ATA set up */ return ata_pci_init_one(dev, port_info, 2); } +static int hpt3x3_reinit_one(struct pci_dev *dev) +{ + hpt3x3_init_chipset(dev); + return ata_pci_device_resume(dev); +} + static const struct pci_device_id hpt3x3[] = { { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT343), }, @@ -203,7 +222,9 @@ static struct pci_driver hpt3x3_pci_driver = { .name = DRV_NAME, .id_table = hpt3x3, .probe = hpt3x3_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = hpt3x3_reinit_one, }; static int __init hpt3x3_init(void) diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c index 40ca2b82b7fc..a97d55ae95c9 100644 --- a/drivers/ata/pata_isapnp.c +++ b/drivers/ata/pata_isapnp.c @@ -27,7 +27,6 @@ static struct scsi_host_template isapnp_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 7f68f14be6fd..0b56ff3d1cfe 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -80,7 +80,7 @@ #define DRV_NAME "pata_it821x" -#define DRV_VERSION "0.3.2" +#define DRV_VERSION "0.3.3" struct it821x_dev { @@ -666,9 +666,6 @@ static struct scsi_host_template it821x_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - /* 255 sectors to begin with. This is locked in smart mode but not - in pass through */ - .max_sectors = 255, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -677,6 +674,8 @@ static struct scsi_host_template it821x_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations it821x_smart_port_ops = { @@ -809,6 +808,14 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return ata_pci_init_one(pdev, port_info, 2); } +static int it821x_reinit_one(struct pci_dev *pdev) +{ + /* Resume - turn raid back off if need be */ + if (it8212_noraid) + it821x_disable_raid(pdev); + return ata_pci_device_resume(pdev); +} + static const struct pci_device_id it821x[] = { { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), }, { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212), }, @@ -820,7 +827,9 @@ static struct pci_driver it821x_pci_driver = { .name = DRV_NAME, .id_table = it821x, .probe = it821x_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = it821x_reinit_one, }; static int __init it821x_init(void) diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c new file mode 100644 index 000000000000..cb8924109f59 --- /dev/null +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -0,0 +1,271 @@ +/* + * ixp4xx PATA/Compact Flash driver + * Copyright (c) 2006 Tower Technologies + * Author: Alessandro Zummo <a.zummo@towertech.it> + * + * An ATA driver to handle a Compact Flash connected + * to the ixp4xx expansion bus in TrueIDE mode. The CF + * must have it chip selects connected to two CS lines + * on the ixp4xx. The interrupt line is optional, if not + * specified the driver will run in polling mode. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/libata.h> +#include <linux/irq.h> +#include <linux/platform_device.h> +#include <scsi/scsi_host.h> + +#define DRV_NAME "pata_ixp4xx_cf" +#define DRV_VERSION "0.1.1" + +static void ixp4xx_set_mode(struct ata_port *ap) +{ + int i; + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + struct ata_device *dev = &ap->device[i]; + if (ata_dev_enabled(dev)) { + dev->pio_mode = XFER_PIO_0; + dev->xfer_mode = XFER_PIO_0; + dev->xfer_shift = ATA_SHIFT_PIO; + dev->flags |= ATA_DFLAG_PIO; + } + } +} + +static void ixp4xx_phy_reset(struct ata_port *ap) +{ + ap->cbl = ATA_CBL_PATA40; + ata_port_probe(ap); + ata_bus_reset(ap); +} + +static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, + unsigned int buflen, int write_data) +{ + unsigned int i; + unsigned int words = buflen >> 1; + u16 *buf16 = (u16 *) buf; + struct ata_port *ap = adev->ap; + void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr; + struct ixp4xx_pata_data *data = ap->host->dev->platform_data; + + /* set the expansion bus in 16bit mode and restore + * 8 bit mode after the transaction. + */ + *data->cs0_cfg &= ~(0x01); + udelay(100); + + /* Transfer multiple of 2 bytes */ + if (write_data) { + for (i = 0; i < words; i++) + writew(buf16[i], mmio); + } else { + for (i = 0; i < words; i++) + buf16[i] = readw(mmio); + } + + /* Transfer trailing 1 byte, if any. */ + if (unlikely(buflen & 0x01)) { + u16 align_buf[1] = { 0 }; + unsigned char *trailing_buf = buf + buflen - 1; + + if (write_data) { + memcpy(align_buf, trailing_buf, 1); + writew(align_buf[0], mmio); + } else { + align_buf[0] = readw(mmio); + memcpy(trailing_buf, align_buf, 1); + } + } + + udelay(100); + *data->cs0_cfg |= 0x01; +} + +static void ixp4xx_irq_clear(struct ata_port *ap) +{ +} + +static void ixp4xx_host_stop (struct ata_host *host) +{ + struct ixp4xx_pata_data *data = host->dev->platform_data; + + iounmap(data->cs0); + iounmap(data->cs1); +} + +static struct scsi_host_template ixp4xx_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + .bios_param = ata_std_bios_param, +}; + +static struct ata_port_operations ixp4xx_port_ops = { + .set_mode = ixp4xx_set_mode, + .mode_filter = ata_pci_default_filter, + + .port_disable = ata_port_disable, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .eng_timeout = ata_eng_timeout, + .data_xfer = ixp4xx_mmio_data_xfer, + + .irq_handler = ata_interrupt, + .irq_clear = ixp4xx_irq_clear, + + .port_start = ata_port_start, + .port_stop = ata_port_stop, + .host_stop = ixp4xx_host_stop, + + .phy_reset = ixp4xx_phy_reset, +}; + +static void ixp4xx_setup_port(struct ata_ioports *ioaddr, + struct ixp4xx_pata_data *data) +{ + ioaddr->cmd_addr = (unsigned long) data->cs0; + ioaddr->altstatus_addr = (unsigned long) data->cs1 + 0x06; + ioaddr->ctl_addr = (unsigned long) data->cs1 + 0x06; + + ata_std_ports(ioaddr); + +#ifndef __ARMEB__ + + /* adjust the addresses to handle the address swizzling of the + * ixp4xx in little endian mode. + */ + + ioaddr->data_addr ^= 0x02; + ioaddr->cmd_addr ^= 0x03; + ioaddr->altstatus_addr ^= 0x03; + ioaddr->ctl_addr ^= 0x03; + ioaddr->error_addr ^= 0x03; + ioaddr->feature_addr ^= 0x03; + ioaddr->nsect_addr ^= 0x03; + ioaddr->lbal_addr ^= 0x03; + ioaddr->lbam_addr ^= 0x03; + ioaddr->lbah_addr ^= 0x03; + ioaddr->device_addr ^= 0x03; + ioaddr->status_addr ^= 0x03; + ioaddr->command_addr ^= 0x03; +#endif +} + +static __devinit int ixp4xx_pata_probe(struct platform_device *pdev) +{ + int ret; + unsigned int irq; + struct resource *cs0, *cs1; + struct ata_probe_ent ae; + + struct ixp4xx_pata_data *data = pdev->dev.platform_data; + + cs0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); + cs1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); + + if (!cs0 || !cs1) + return -EINVAL; + + pdev->dev.coherent_dma_mask = DMA_32BIT_MASK; + + data->cs0 = ioremap(cs0->start, 0x1000); + data->cs1 = ioremap(cs1->start, 0x1000); + + irq = platform_get_irq(pdev, 0); + if (irq) + set_irq_type(irq, IRQT_HIGH); + + /* Setup expansion bus chip selects */ + *data->cs0_cfg = data->cs0_bits; + *data->cs1_cfg = data->cs1_bits; + + memset(&ae, 0, sizeof(struct ata_probe_ent)); + INIT_LIST_HEAD(&ae.node); + + ae.dev = &pdev->dev; + ae.port_ops = &ixp4xx_port_ops; + ae.sht = &ixp4xx_sht; + ae.n_ports = 1; + ae.pio_mask = 0x1f; /* PIO4 */ + ae.irq = irq; + ae.irq_flags = 0; + ae.port_flags = ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY + | ATA_FLAG_NO_ATAPI | ATA_FLAG_SRST; + + /* run in polling mode if no irq has been assigned */ + if (!irq) + ae.port_flags |= ATA_FLAG_PIO_POLLING; + + ixp4xx_setup_port(&ae.port[0], data); + + dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); + + ret = ata_device_add(&ae); + if (ret == 0) + return -ENODEV; + + return 0; +} + +static __devexit int ixp4xx_pata_remove(struct platform_device *dev) +{ + struct ata_host *host = platform_get_drvdata(dev); + + ata_host_remove(host); + platform_set_drvdata(dev, NULL); + + return 0; +} + +static struct platform_driver ixp4xx_pata_platform_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = ixp4xx_pata_probe, + .remove = __devexit_p(ixp4xx_pata_remove), +}; + +static int __init ixp4xx_pata_init(void) +{ + return platform_driver_register(&ixp4xx_pata_platform_driver); +} + +static void __exit ixp4xx_pata_exit(void) +{ + platform_driver_unregister(&ixp4xx_pata_platform_driver); +} + +MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); +MODULE_DESCRIPTION("low-level driver for ixp4xx Compact Flash PATA"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +module_init(ixp4xx_pata_init); +module_exit(ixp4xx_pata_exit); diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 0210b10d49cd..2d661cb4df3c 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -19,7 +19,7 @@ #include <linux/ata.h> #define DRV_NAME "pata_jmicron" -#define DRV_VERSION "0.1.2" +#define DRV_VERSION "0.1.4" typedef enum { PORT_PATA0 = 0, @@ -128,8 +128,6 @@ static struct scsi_host_template jmicron_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - /* Special handling needed if you have sector or LBA48 limits */ - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -213,12 +211,11 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i /* FIXME: We may want a way to override this in future */ pci_write_config_byte(pdev, 0x41, 0xa1); - } - - /* PATA controller is fn 1, AHCI is fn 0 */ - if (PCI_FUNC(pdev->devfn) != 1) - return -ENODEV; + /* PATA controller is fn 1, AHCI is fn 0 */ + if (PCI_FUNC(pdev->devfn) != 1) + return -ENODEV; + } if ( id->driver_data == 365 || id->driver_data == 366) { /* The 365/66 have two PATA channels, redirect the second */ pci_read_config_dword(pdev, 0x80, ®); @@ -229,6 +226,27 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i return ata_pci_init_one(pdev, port_info, 2); } +static int jmicron_reinit_one(struct pci_dev *pdev) +{ + u32 reg; + + switch(pdev->device) { + case PCI_DEVICE_ID_JMICRON_JMB368: + break; + case PCI_DEVICE_ID_JMICRON_JMB365: + case PCI_DEVICE_ID_JMICRON_JMB366: + /* Restore mapping or disks swap and boy does it get ugly */ + pci_read_config_dword(pdev, 0x80, ®); + reg |= (1 << 24); /* IDE1 to PATA IDE secondary */ + pci_write_config_dword(pdev, 0x80, reg); + /* Fall through */ + default: + /* Make sure AHCI is turned back on */ + pci_write_config_byte(pdev, 0x41, 0xa1); + } + return ata_pci_device_resume(pdev); +} + static const struct pci_device_id jmicron_pci_tbl[] = { { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB361), 361}, { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB363), 363}, @@ -244,6 +262,8 @@ static struct pci_driver jmicron_pci_driver = { .id_table = jmicron_pci_tbl, .probe = jmicron_init_one, .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = jmicron_reinit_one, }; static int __init jmicron_init(void) diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index b39078b2a47b..c7d1738e4e69 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -128,7 +128,6 @@ static struct scsi_host_template legacy_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c new file mode 100644 index 000000000000..1c810ea00253 --- /dev/null +++ b/drivers/ata/pata_marvell.c @@ -0,0 +1,224 @@ +/* + * Marvell PATA driver. + * + * For the moment we drive the PATA port in legacy mode. That + * isn't making full use of the device functionality but it is + * easy to get working. + * + * (c) 2006 Red Hat <alan@redhat.com> + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/blkdev.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <scsi/scsi_host.h> +#include <linux/libata.h> +#include <linux/ata.h> + +#define DRV_NAME "pata_marvell" +#define DRV_VERSION "0.1.1" + +/** + * marvell_pre_reset - check for 40/80 pin + * @ap: Port + * + * Perform the PATA port setup we need. + */ + +static int marvell_pre_reset(struct ata_port *ap) +{ + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + u32 devices; + void __iomem *barp; + int i; + + /* Check if our port is enabled */ + + barp = pci_iomap(pdev, 5, 0x10); + if (barp == NULL) + return -ENOMEM; + printk("BAR5:"); + for(i = 0; i <= 0x0F; i++) + printk("%02X:%02X ", i, readb(barp + i)); + printk("\n"); + + devices = readl(barp + 0x0C); + pci_iounmap(pdev, barp); + + if ((pdev->device == 0x6145) && (ap->port_no == 0) && + (!(devices & 0x10))) /* PATA enable ? */ + return -ENOENT; + + /* Cable type */ + switch(ap->port_no) + { + case 0: + if (inb(ap->ioaddr.bmdma_addr + 1) & 1) + ap->cbl = ATA_CBL_PATA40; + else + ap->cbl = ATA_CBL_PATA80; + break; + + case 1: /* Legacy SATA port */ + ap->cbl = ATA_CBL_SATA; + break; + } + return ata_std_prereset(ap); +} + +/** + * marvell_error_handler - Setup and error handler + * @ap: Port to handle + * + * LOCKING: + * None (inherited from caller). + */ + +static void marvell_error_handler(struct ata_port *ap) +{ + return ata_bmdma_drive_eh(ap, marvell_pre_reset, ata_std_softreset, + NULL, ata_std_postreset); +} + +/* No PIO or DMA methods needed for this device */ + +static struct scsi_host_template marvell_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + /* Use standard CHS mapping rules */ + .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, +}; + +static const struct ata_port_operations marvell_ops = { + .port_disable = ata_port_disable, + + /* Task file is PCI ATA format, use helpers */ + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = marvell_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + + /* BMDMA handling is PCI ATA format, use helpers */ + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_pio_data_xfer, + + /* Timeout handling */ + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + + /* Generic PATA PCI ATA helpers */ + .port_start = ata_port_start, + .port_stop = ata_port_stop, + .host_stop = ata_host_stop, +}; + + +/** + * marvell_init_one - Register Marvell ATA PCI device with kernel services + * @pdev: PCI device to register + * @ent: Entry in marvell_pci_tbl matching with @pdev + * + * Called from kernel PCI layer. + * + * LOCKING: + * Inherited from PCI layer (may sleep). + * + * RETURNS: + * Zero on success, or -ERRNO value. + */ + +static int marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *id) +{ + static struct ata_port_info info = { + .sht = &marvell_sht, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x3f, + + .port_ops = &marvell_ops, + }; + static struct ata_port_info info_sata = { + .sht = &marvell_sht, + /* Slave possible as its magically mapped not real */ + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x7f, + + .port_ops = &marvell_ops, + }; + struct ata_port_info *port_info[2] = { &info, &info_sata }; + int n_port = 2; + + if (pdev->device == 0x6101) + n_port = 1; + + return ata_pci_init_one(pdev, port_info, n_port); +} + +static const struct pci_device_id marvell_pci_tbl[] = { + { PCI_DEVICE(0x11AB, 0x6101), }, + { PCI_DEVICE(0x11AB, 0x6145), }, + { } /* terminate list */ +}; + +static struct pci_driver marvell_pci_driver = { + .name = DRV_NAME, + .id_table = marvell_pci_tbl, + .probe = marvell_init_one, + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, +}; + +static int __init marvell_init(void) +{ + return pci_register_driver(&marvell_pci_driver); +} + +static void __exit marvell_exit(void) +{ + pci_unregister_driver(&marvell_pci_driver); +} + +module_init(marvell_init); +module_exit(marvell_exit); + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("SCSI low-level driver for Marvell ATA in legacy mode"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, marvell_pci_tbl); +MODULE_VERSION(DRV_VERSION); + diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index e00d406bfdf5..4ccca938675e 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -35,7 +35,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_mpiix" -#define DRV_VERSION "0.7.2" +#define DRV_VERSION "0.7.3" enum { IDETIM = 0x6C, /* IDE control register */ @@ -159,7 +159,6 @@ static struct scsi_host_template mpiix_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -168,6 +167,8 @@ static struct scsi_host_template mpiix_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations mpiix_port_ops = { @@ -285,7 +286,9 @@ static struct pci_driver mpiix_pci_driver = { .name = DRV_NAME, .id_table = mpiix, .probe = mpiix_init_one, - .remove = mpiix_remove_one + .remove = mpiix_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init mpiix_init(void) diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c index 1963a4d35873..cf7fe037471c 100644 --- a/drivers/ata/pata_netcell.c +++ b/drivers/ata/pata_netcell.c @@ -16,7 +16,7 @@ #include <linux/ata.h> #define DRV_NAME "pata_netcell" -#define DRV_VERSION "0.1.5" +#define DRV_VERSION "0.1.6" /** * netcell_probe_init - check for 40/80 pin @@ -54,8 +54,6 @@ static struct scsi_host_template netcell_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - /* Special handling needed if you have sector or LBA48 limits */ - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -65,6 +63,8 @@ static struct scsi_host_template netcell_sht = { .slave_destroy = ata_scsi_slave_destroy, /* Use standard CHS mapping rules */ .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static const struct ata_port_operations netcell_ops = { @@ -153,6 +153,8 @@ static struct pci_driver netcell_pci_driver = { .id_table = netcell_pci_tbl, .probe = netcell_init_one, .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init netcell_init(void) diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index 7ec800f00ec8..c3032eb9010d 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -28,7 +28,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_ns87410" -#define DRV_VERSION "0.4.2" +#define DRV_VERSION "0.4.3" /** * ns87410_pre_reset - probe begin @@ -149,7 +149,6 @@ static struct scsi_host_template ns87410_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -158,6 +157,8 @@ static struct scsi_host_template ns87410_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations ns87410_port_ops = { @@ -210,7 +211,9 @@ static struct pci_driver ns87410_pci_driver = { .name = DRV_NAME, .id_table = ns87410, .probe = ns87410_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init ns87410_init(void) diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index 8837256632e9..10ac3cc10181 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c @@ -224,7 +224,6 @@ static struct scsi_host_template oldpiix_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -233,6 +232,8 @@ static struct scsi_host_template oldpiix_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static const struct ata_port_operations oldpiix_pata_ops = { @@ -314,6 +315,8 @@ static struct pci_driver oldpiix_pci_driver = { .id_table = oldpiix_pci_tbl, .probe = oldpiix_init_one, .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init oldpiix_init(void) diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index c6319cf50de4..c2988b0aa8ea 100644 --- a/drivers/ata/pata_opti.c +++ b/drivers/ata/pata_opti.c @@ -34,7 +34,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_opti" -#define DRV_VERSION "0.2.5" +#define DRV_VERSION "0.2.7" enum { READ_REG = 0, /* index of Read cycle timing register */ @@ -109,30 +109,6 @@ static void opti_write_reg(struct ata_port *ap, u8 val, int reg) outb(0x83, regio + 2); } -#if 0 -/** - * opti_read_reg - control register read - * @ap: ATA port - * @reg: control register number - * - * The Opti uses magic 'trapdoor' register accesses to do configuration - * rather than using PCI space as other controllers do. The double inw - * on the error register activates configuration mode. We can then read - * the control register - */ - -static u8 opti_read_reg(struct ata_port *ap, int reg) -{ - unsigned long regio = ap->ioaddr.cmd_addr; - u8 ret; - inw(regio + 1); - inw(regio + 1); - outb(3, regio + 2); - ret = inb(regio + reg); - outb(0x83, regio + 2); -} -#endif - /** * opti_set_piomode - set initial PIO mode data * @ap: ATA interface @@ -195,7 +171,6 @@ static struct scsi_host_template opti_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -204,12 +179,13 @@ static struct scsi_host_template opti_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations opti_port_ops = { .port_disable = ata_port_disable, .set_piomode = opti_set_piomode, -/* .set_dmamode = opti_set_dmamode, */ .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -267,7 +243,9 @@ static struct pci_driver opti_pci_driver = { .name = DRV_NAME, .id_table = opti, .probe = opti_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init opti_init(void) diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index 2f4770cce04e..80d111c569dc 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -33,7 +33,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_optidma" -#define DRV_VERSION "0.2.2" +#define DRV_VERSION "0.2.3" enum { READ_REG = 0, /* index of Read cycle timing register */ @@ -352,7 +352,6 @@ static struct scsi_host_template optidma_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -361,6 +360,8 @@ static struct scsi_host_template optidma_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations optidma_port_ops = { @@ -522,7 +523,9 @@ static struct pci_driver optidma_pci_driver = { .name = DRV_NAME, .id_table = optidma, .probe = optidma_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init optidma_init(void) diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 999922de476e..4ca6fa5dcb42 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -62,7 +62,6 @@ static struct scsi_host_template pcmcia_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index beb6d10a234b..76dd1c935dbd 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -134,7 +134,6 @@ static struct scsi_host_template pdc2027x_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -854,7 +853,7 @@ static void __devexit pdc2027x_remove_one(struct pci_dev *pdev) */ static int __init pdc2027x_init(void) { - return pci_module_init(&pdc2027x_pci_driver); + return pci_register_driver(&pdc2027x_pci_driver); } /** diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index 6baf51b2fda1..ad691b9e7743 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -21,7 +21,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_pdc202xx_old" -#define DRV_VERSION "0.2.1" +#define DRV_VERSION "0.2.3" /** * pdc2024x_pre_reset - probe begin @@ -63,7 +63,7 @@ static void pdc2026x_error_handler(struct ata_port *ap) } /** - * pdc_configure_piomode - set chip PIO timing + * pdc202xx_configure_piomode - set chip PIO timing * @ap: ATA interface * @adev: ATA device * @pio: PIO mode @@ -73,7 +73,7 @@ static void pdc2026x_error_handler(struct ata_port *ap) * versa */ -static void pdc_configure_piomode(struct ata_port *ap, struct ata_device *adev, int pio) +static void pdc202xx_configure_piomode(struct ata_port *ap, struct ata_device *adev, int pio) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); int port = 0x60 + 4 * ap->port_no + 2 * adev->devno; @@ -98,7 +98,7 @@ static void pdc_configure_piomode(struct ata_port *ap, struct ata_device *adev, } /** - * pdc_set_piomode - set initial PIO mode data + * pdc202xx_set_piomode - set initial PIO mode data * @ap: ATA interface * @adev: ATA device * @@ -106,13 +106,13 @@ static void pdc_configure_piomode(struct ata_port *ap, struct ata_device *adev, * but we want to set the PIO timing by default. */ -static void pdc_set_piomode(struct ata_port *ap, struct ata_device *adev) +static void pdc202xx_set_piomode(struct ata_port *ap, struct ata_device *adev) { - pdc_configure_piomode(ap, adev, adev->pio_mode - XFER_PIO_0); + pdc202xx_configure_piomode(ap, adev, adev->pio_mode - XFER_PIO_0); } /** - * pdc_configure_dmamode - set DMA mode in chip + * pdc202xx_configure_dmamode - set DMA mode in chip * @ap: ATA interface * @adev: ATA device * @@ -120,7 +120,7 @@ static void pdc_set_piomode(struct ata_port *ap, struct ata_device *adev) * to occur. */ -static void pdc_set_dmamode(struct ata_port *ap, struct ata_device *adev) +static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); int port = 0x60 + 4 * ap->port_no + 2 * adev->devno; @@ -184,7 +184,7 @@ static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc) /* The DMA clocks may have been trashed by a reset. FIXME: make conditional and move to qc_issue ? */ - pdc_set_dmamode(ap, qc->dev); + pdc202xx_set_dmamode(ap, qc->dev); /* Cases the state machine will not complete correctly without help */ if ((tf->flags & ATA_TFLAG_LBA48) || tf->protocol == ATA_PROT_ATAPI_DMA) @@ -254,7 +254,7 @@ static void pdc2026x_dev_config(struct ata_port *ap, struct ata_device *adev) adev->max_sectors = 256; } -static struct scsi_host_template pdc_sht = { +static struct scsi_host_template pdc202xx_sht = { .module = THIS_MODULE, .name = DRV_NAME, .ioctl = ata_scsi_ioctl, @@ -262,7 +262,6 @@ static struct scsi_host_template pdc_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -271,12 +270,14 @@ static struct scsi_host_template pdc_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations pdc2024x_port_ops = { .port_disable = ata_port_disable, - .set_piomode = pdc_set_piomode, - .set_dmamode = pdc_set_dmamode, + .set_piomode = pdc202xx_set_piomode, + .set_dmamode = pdc202xx_set_dmamode, .mode_filter = ata_pci_default_filter, .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -308,8 +309,8 @@ static struct ata_port_operations pdc2024x_port_ops = { static struct ata_port_operations pdc2026x_port_ops = { .port_disable = ata_port_disable, - .set_piomode = pdc_set_piomode, - .set_dmamode = pdc_set_dmamode, + .set_piomode = pdc202xx_set_piomode, + .set_dmamode = pdc202xx_set_dmamode, .mode_filter = ata_pci_default_filter, .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -340,11 +341,11 @@ static struct ata_port_operations pdc2026x_port_ops = { .host_stop = ata_host_stop }; -static int pdc_init_one(struct pci_dev *dev, const struct pci_device_id *id) +static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id) { static struct ata_port_info info[3] = { { - .sht = &pdc_sht, + .sht = &pdc202xx_sht, .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -352,7 +353,7 @@ static int pdc_init_one(struct pci_dev *dev, const struct pci_device_id *id) .port_ops = &pdc2024x_port_ops }, { - .sht = &pdc_sht, + .sht = &pdc202xx_sht, .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -360,7 +361,7 @@ static int pdc_init_one(struct pci_dev *dev, const struct pci_device_id *id) .port_ops = &pdc2026x_port_ops }, { - .sht = &pdc_sht, + .sht = &pdc202xx_sht, .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -386,7 +387,7 @@ static int pdc_init_one(struct pci_dev *dev, const struct pci_device_id *id) return ata_pci_init_one(dev, port_info, 2); } -static const struct pci_device_id pdc[] = { +static const struct pci_device_id pdc202xx[] = { { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0 }, { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1 }, { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20263), 1 }, @@ -396,28 +397,30 @@ static const struct pci_device_id pdc[] = { { }, }; -static struct pci_driver pdc_pci_driver = { +static struct pci_driver pdc202xx_pci_driver = { .name = DRV_NAME, - .id_table = pdc, - .probe = pdc_init_one, - .remove = ata_pci_remove_one + .id_table = pdc202xx, + .probe = pdc202xx_init_one, + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; -static int __init pdc_init(void) +static int __init pdc202xx_init(void) { - return pci_register_driver(&pdc_pci_driver); + return pci_register_driver(&pdc202xx_pci_driver); } -static void __exit pdc_exit(void) +static void __exit pdc202xx_exit(void) { - pci_unregister_driver(&pdc_pci_driver); + pci_unregister_driver(&pdc202xx_pci_driver); } MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for Promise 2024x and 20262-20267"); MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(pci, pdc); +MODULE_DEVICE_TABLE(pci, pdc202xx); MODULE_VERSION(DRV_VERSION); -module_init(pdc_init); -module_exit(pdc_exit); +module_init(pdc202xx_init); +module_exit(pdc202xx_exit); diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c new file mode 100644 index 000000000000..443b1d85c6c4 --- /dev/null +++ b/drivers/ata/pata_platform.c @@ -0,0 +1,295 @@ +/* + * Generic platform device PATA driver + * + * Copyright (C) 2006 Paul Mundt + * + * Based on pata_pcmcia: + * + * Copyright 2005-2006 Red Hat Inc <alan@redhat.com>, all rights reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/blkdev.h> +#include <scsi/scsi_host.h> +#include <linux/ata.h> +#include <linux/libata.h> +#include <linux/platform_device.h> +#include <linux/pata_platform.h> + +#define DRV_NAME "pata_platform" +#define DRV_VERSION "0.1.2" + +static int pio_mask = 1; + +/* + * Provide our own set_mode() as we don't want to change anything that has + * already been configured.. + */ +static void pata_platform_set_mode(struct ata_port *ap) +{ + int i; + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + struct ata_device *dev = &ap->device[i]; + + if (ata_dev_enabled(dev)) { + /* We don't really care */ + dev->pio_mode = dev->xfer_mode = XFER_PIO_0; + dev->xfer_shift = ATA_SHIFT_PIO; + dev->flags |= ATA_DFLAG_PIO; + } + } +} + +static void pata_platform_host_stop(struct ata_host *host) +{ + int i; + + /* + * Unmap the bases for MMIO + */ + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + + if (ap->flags & ATA_FLAG_MMIO) { + iounmap((void __iomem *)ap->ioaddr.ctl_addr); + iounmap((void __iomem *)ap->ioaddr.cmd_addr); + } + } +} + +static struct scsi_host_template pata_platform_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + .bios_param = ata_std_bios_param, +}; + +static struct ata_port_operations pata_platform_port_ops = { + .set_mode = pata_platform_set_mode, + + .port_disable = ata_port_disable, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .data_xfer = ata_pio_data_xfer_noirq, + + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + + .port_start = ata_port_start, + .port_stop = ata_port_stop, + .host_stop = pata_platform_host_stop +}; + +static void pata_platform_setup_port(struct ata_ioports *ioaddr, + struct pata_platform_info *info) +{ + unsigned int shift = 0; + + /* Fixup the port shift for platforms that need it */ + if (info && info->ioport_shift) + shift = info->ioport_shift; + + ioaddr->data_addr = ioaddr->cmd_addr + (ATA_REG_DATA << shift); + ioaddr->error_addr = ioaddr->cmd_addr + (ATA_REG_ERR << shift); + ioaddr->feature_addr = ioaddr->cmd_addr + (ATA_REG_FEATURE << shift); + ioaddr->nsect_addr = ioaddr->cmd_addr + (ATA_REG_NSECT << shift); + ioaddr->lbal_addr = ioaddr->cmd_addr + (ATA_REG_LBAL << shift); + ioaddr->lbam_addr = ioaddr->cmd_addr + (ATA_REG_LBAM << shift); + ioaddr->lbah_addr = ioaddr->cmd_addr + (ATA_REG_LBAH << shift); + ioaddr->device_addr = ioaddr->cmd_addr + (ATA_REG_DEVICE << shift); + ioaddr->status_addr = ioaddr->cmd_addr + (ATA_REG_STATUS << shift); + ioaddr->command_addr = ioaddr->cmd_addr + (ATA_REG_CMD << shift); +} + +/** + * pata_platform_probe - attach a platform interface + * @pdev: platform device + * + * Register a platform bus IDE interface. Such interfaces are PIO and we + * assume do not support IRQ sharing. + * + * Platform devices are expected to contain 3 resources per port: + * + * - I/O Base (IORESOURCE_IO or IORESOURCE_MEM) + * - CTL Base (IORESOURCE_IO or IORESOURCE_MEM) + * - IRQ (IORESOURCE_IRQ) + * + * If the base resources are both mem types, the ioremap() is handled + * here. For IORESOURCE_IO, it's assumed that there's no remapping + * necessary. + */ +static int __devinit pata_platform_probe(struct platform_device *pdev) +{ + struct resource *io_res, *ctl_res; + struct ata_probe_ent ae; + unsigned int mmio; + int ret; + + /* + * Simple resource validation .. + */ + if (unlikely(pdev->num_resources != 3)) { + dev_err(&pdev->dev, "invalid number of resources\n"); + return -EINVAL; + } + + /* + * Get the I/O base first + */ + io_res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (io_res == NULL) { + io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (unlikely(io_res == NULL)) + return -EINVAL; + } + + /* + * Then the CTL base + */ + ctl_res = platform_get_resource(pdev, IORESOURCE_IO, 1); + if (ctl_res == NULL) { + ctl_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (unlikely(ctl_res == NULL)) + return -EINVAL; + } + + /* + * Check for MMIO + */ + mmio = (( io_res->flags == IORESOURCE_MEM) && + (ctl_res->flags == IORESOURCE_MEM)); + + /* + * Now that that's out of the way, wire up the port.. + */ + memset(&ae, 0, sizeof(struct ata_probe_ent)); + INIT_LIST_HEAD(&ae.node); + ae.dev = &pdev->dev; + ae.port_ops = &pata_platform_port_ops; + ae.sht = &pata_platform_sht; + ae.n_ports = 1; + ae.pio_mask = pio_mask; + ae.irq = platform_get_irq(pdev, 0); + ae.irq_flags = 0; + ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; + + /* + * Handle the MMIO case + */ + if (mmio) { + ae.port_flags |= ATA_FLAG_MMIO; + + ae.port[0].cmd_addr = (unsigned long)ioremap(io_res->start, + io_res->end - io_res->start + 1); + if (unlikely(!ae.port[0].cmd_addr)) { + dev_err(&pdev->dev, "failed to remap IO base\n"); + return -ENXIO; + } + + ae.port[0].ctl_addr = (unsigned long)ioremap(ctl_res->start, + ctl_res->end - ctl_res->start + 1); + if (unlikely(!ae.port[0].ctl_addr)) { + dev_err(&pdev->dev, "failed to remap CTL base\n"); + ret = -ENXIO; + goto bad_remap; + } + } else { + ae.port[0].cmd_addr = io_res->start; + ae.port[0].ctl_addr = ctl_res->start; + } + + ae.port[0].altstatus_addr = ae.port[0].ctl_addr; + + pata_platform_setup_port(&ae.port[0], pdev->dev.platform_data); + + if (unlikely(ata_device_add(&ae) == 0)) { + ret = -ENODEV; + goto add_failed; + } + + return 0; + +add_failed: + if (ae.port[0].ctl_addr && mmio) + iounmap((void __iomem *)ae.port[0].ctl_addr); +bad_remap: + if (ae.port[0].cmd_addr && mmio) + iounmap((void __iomem *)ae.port[0].cmd_addr); + + return ret; +} + +/** + * pata_platform_remove - unplug a platform interface + * @pdev: platform device + * + * A platform bus ATA device has been unplugged. Perform the needed + * cleanup. Also called on module unload for any active devices. + */ +static int __devexit pata_platform_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ata_host *host = dev_get_drvdata(dev); + + ata_host_remove(host); + dev_set_drvdata(dev, NULL); + + return 0; +} + +static struct platform_driver pata_platform_driver = { + .probe = pata_platform_probe, + .remove = __devexit_p(pata_platform_remove), + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init pata_platform_init(void) +{ + return platform_driver_register(&pata_platform_driver); +} + +static void __exit pata_platform_exit(void) +{ + platform_driver_unregister(&pata_platform_driver); +} +module_init(pata_platform_init); +module_exit(pata_platform_exit); + +module_param(pio_mask, int, 0); + +MODULE_AUTHOR("Paul Mundt"); +MODULE_DESCRIPTION("low-level driver for platform device ATA"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index 314938dea1fc..36f621abc390 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -157,7 +157,6 @@ static struct scsi_host_template qdi_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c index 048c2bb21ef1..065541d034ad 100644 --- a/drivers/ata/pata_radisys.c +++ b/drivers/ata/pata_radisys.c @@ -220,7 +220,6 @@ static struct scsi_host_template radisys_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -229,6 +228,8 @@ static struct scsi_host_template radisys_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static const struct ata_port_operations radisys_pata_ops = { @@ -311,6 +312,8 @@ static struct pci_driver radisys_pci_driver = { .id_table = radisys_pci_tbl, .probe = radisys_init_one, .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init radisys_init(void) diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index e4e5ea423fef..3677c642c9f9 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -21,7 +21,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_rz1000" -#define DRV_VERSION "0.2.2" +#define DRV_VERSION "0.2.3" /** @@ -83,7 +83,6 @@ static struct scsi_host_template rz1000_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -92,6 +91,8 @@ static struct scsi_host_template rz1000_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations rz1000_port_ops = { @@ -129,6 +130,19 @@ static struct ata_port_operations rz1000_port_ops = { .host_stop = ata_host_stop }; +static int rz1000_fifo_disable(struct pci_dev *pdev) +{ + u16 reg; + /* Be exceptionally paranoid as we must be sure to apply the fix */ + if (pci_read_config_word(pdev, 0x40, ®) != 0) + return -1; + reg &= 0xDFFF; + if (pci_write_config_word(pdev, 0x40, reg) != 0) + return -1; + printk(KERN_INFO DRV_NAME ": disabled chipset readahead.\n"); + return 0; +} + /** * rz1000_init_one - Register RZ1000 ATA PCI device with kernel services * @pdev: PCI device to register @@ -143,7 +157,6 @@ static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *en { static int printed_version; struct ata_port_info *port_info[2]; - u16 reg; static struct ata_port_info info = { .sht = &rz1000_sht, .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, @@ -154,23 +167,25 @@ static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *en if (!printed_version++) printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); - /* Be exceptionally paranoid as we must be sure to apply the fix */ - if (pci_read_config_word(pdev, 0x40, ®) != 0) - goto fail; - reg &= 0xDFFF; - if (pci_write_config_word(pdev, 0x40, reg) != 0) - goto fail; - printk(KERN_INFO DRV_NAME ": disabled chipset readahead.\n"); - - port_info[0] = &info; - port_info[1] = &info; - return ata_pci_init_one(pdev, port_info, 2); -fail: + if (rz1000_fifo_disable(pdev) == 0) { + port_info[0] = &info; + port_info[1] = &info; + return ata_pci_init_one(pdev, port_info, 2); + } printk(KERN_ERR DRV_NAME ": failed to disable read-ahead on chipset..\n"); /* Not safe to use so skip */ return -ENODEV; } +static int rz1000_reinit_one(struct pci_dev *pdev) +{ + /* If this fails on resume (which is a "cant happen" case), we + must stop as any progress risks data loss */ + if (rz1000_fifo_disable(pdev)) + panic("rz1000 fifo"); + return ata_pci_device_resume(pdev); +} + static const struct pci_device_id pata_rz1000[] = { { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000), }, { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001), }, @@ -182,7 +197,9 @@ static struct pci_driver rz1000_pci_driver = { .name = DRV_NAME, .id_table = pata_rz1000, .probe = rz1000_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = rz1000_reinit_one, }; static int __init rz1000_init(void) diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c index 0c75dae74764..a3b35bc50394 100644 --- a/drivers/ata/pata_sc1200.c +++ b/drivers/ata/pata_sc1200.c @@ -40,7 +40,7 @@ #include <linux/libata.h> #define DRV_NAME "sc1200" -#define DRV_VERSION "0.2.3" +#define DRV_VERSION "0.2.4" #define SC1200_REV_A 0x00 #define SC1200_REV_B1 0x01 @@ -186,7 +186,6 @@ static struct scsi_host_template sc1200_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -195,6 +194,8 @@ static struct scsi_host_template sc1200_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations sc1200_port_ops = { @@ -264,7 +265,9 @@ static struct pci_driver sc1200_pci_driver = { .name = DRV_NAME, .id_table = sc1200, .probe = sc1200_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init sc1200_init(void) diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index be7f60efcb61..f02b6a3b0f10 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -41,7 +41,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_serverworks" -#define DRV_VERSION "0.3.7" +#define DRV_VERSION "0.3.9" #define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */ #define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */ @@ -318,7 +318,6 @@ static struct scsi_host_template serverworks_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -327,6 +326,8 @@ static struct scsi_host_template serverworks_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations serverworks_osb4_port_ops = { @@ -554,6 +555,30 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id return ata_pci_init_one(pdev, port_info, ports); } +static int serverworks_reinit_one(struct pci_dev *pdev) +{ + /* Force master latency timer to 64 PCI clocks */ + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40); + + switch (pdev->device) + { + case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE: + serverworks_fixup_osb4(pdev); + break; + case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE: + ata_pci_clear_simplex(pdev); + /* fall through */ + case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE: + case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2: + serverworks_fixup_csb(pdev); + break; + case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE: + serverworks_fixup_ht1000(pdev); + break; + } + return ata_pci_device_resume(pdev); +} + static const struct pci_device_id serverworks[] = { { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0}, { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE), 2}, @@ -568,7 +593,9 @@ static struct pci_driver serverworks_pci_driver = { .name = DRV_NAME, .id_table = serverworks, .probe = serverworks_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = serverworks_reinit_one, }; static int __init serverworks_init(void) diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index 11942fd03b55..32cf0bfa8921 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -33,7 +33,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_sil680" -#define DRV_VERSION "0.3.2" +#define DRV_VERSION "0.4.1" /** * sil680_selreg - return register base @@ -218,7 +218,6 @@ static struct scsi_host_template sil680_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -263,32 +262,20 @@ static struct ata_port_operations sil680_port_ops = { .host_stop = ata_host_stop }; -static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id) +/** + * sil680_init_chip - chip setup + * @pdev: PCI device + * + * Perform all the chip setup which must be done both when the device + * is powered up on boot and when we resume in case we resumed from RAM. + * Returns the final clock settings. + */ + +static u8 sil680_init_chip(struct pci_dev *pdev) { - static struct ata_port_info info = { - .sht = &sil680_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, - .pio_mask = 0x1f, - .mwdma_mask = 0x07, - .udma_mask = 0x7f, - .port_ops = &sil680_port_ops - }; - static struct ata_port_info info_slow = { - .sht = &sil680_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, - .pio_mask = 0x1f, - .mwdma_mask = 0x07, - .udma_mask = 0x3f, - .port_ops = &sil680_port_ops - }; - static struct ata_port_info *port_info[2] = {&info, &info}; - static int printed_version; u32 class_rev = 0; u8 tmpbyte = 0; - if (!printed_version++) - dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; /* FIXME: double check */ @@ -323,8 +310,6 @@ static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id) pci_read_config_byte(pdev, 0x8A, &tmpbyte); printk(KERN_INFO "sil680: BA5_EN = %d clock = %02X\n", tmpbyte & 1, tmpbyte & 0x30); - if ((tmpbyte & 0x30) == 0) - port_info[0] = port_info[1] = &info_slow; pci_write_config_byte(pdev, 0xA1, 0x72); pci_write_config_word(pdev, 0xA2, 0x328A); @@ -343,11 +328,51 @@ static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id) case 0x20: printk(KERN_INFO "sil680: Using PCI clock.\n");break; /* This last case is _NOT_ ok */ case 0x30: printk(KERN_ERR "sil680: Clock disabled ?\n"); - return -EIO; + } + return tmpbyte & 0x30; +} + +static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id) +{ + static struct ata_port_info info = { + .sht = &sil680_sht, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x7f, + .port_ops = &sil680_port_ops + }; + static struct ata_port_info info_slow = { + .sht = &sil680_sht, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x3f, + .port_ops = &sil680_port_ops + }; + static struct ata_port_info *port_info[2] = {&info, &info}; + static int printed_version; + + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); + + switch(sil680_init_chip(pdev)) + { + case 0: + port_info[0] = port_info[1] = &info_slow; + break; + case 0x30: + return -ENODEV; } return ata_pci_init_one(pdev, port_info, 2); } +static int sil680_reinit_one(struct pci_dev *pdev) +{ + sil680_init_chip(pdev); + return ata_pci_device_resume(pdev); +} + static const struct pci_device_id sil680[] = { { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_680), }, @@ -358,7 +383,9 @@ static struct pci_driver sil680_pci_driver = { .name = DRV_NAME, .id_table = sil680, .probe = sil680_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = sil680_reinit_one, }; static int __init sil680_init(void) diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index 91e85f90941d..916cedb3d755 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -34,7 +34,7 @@ #include <linux/ata.h> #define DRV_NAME "pata_sis" -#define DRV_VERSION "0.4.4" +#define DRV_VERSION "0.4.5" struct sis_chipset { u16 device; /* PCI host ID */ @@ -538,7 +538,6 @@ static struct scsi_host_template sis_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -547,6 +546,8 @@ static struct scsi_host_template sis_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static const struct ata_port_operations sis_133_ops = { @@ -1000,6 +1001,8 @@ static struct pci_driver sis_pci_driver = { .id_table = sis_pci_tbl, .probe = sis_init_one, .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init sis_init(void) diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index dc1cfc6d805b..e94f515ef54b 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -230,7 +230,6 @@ static struct scsi_host_template sl82c105_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index bfda1f7e760a..a142971f1307 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -43,7 +43,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_triflex" -#define DRV_VERSION "0.2.5" +#define DRV_VERSION "0.2.7" /** * triflex_prereset - probe begin @@ -185,7 +185,6 @@ static struct scsi_host_template triflex_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -194,6 +193,8 @@ static struct scsi_host_template triflex_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations triflex_port_ops = { @@ -258,7 +259,9 @@ static struct pci_driver triflex_pci_driver = { .name = DRV_NAME, .id_table = triflex, .probe = triflex_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init triflex_init(void) diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index c5f1616d224d..cc09d47fb927 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -23,6 +23,7 @@ * VIA VT8233c - UDMA100 * VIA VT8235 - UDMA133 * VIA VT8237 - UDMA133 + * VIA VT8251 - UDMA133 * * Most registers remain compatible across chips. Others start reserved * and acquire sensible semantics if set to 1 (eg cable detect). A few @@ -60,7 +61,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_via" -#define DRV_VERSION "0.1.14" +#define DRV_VERSION "0.2.0" /* * The following comes directly from Vojtech Pavlik's ide/pci/via82cxxx @@ -94,6 +95,7 @@ static const struct via_isa_bridge { u8 rev_max; u16 flags; } via_isa_bridges[] = { + { "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES}, { "vt8237a", PCI_DEVICE_ID_VIA_8237A, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, @@ -288,7 +290,6 @@ static struct scsi_host_template via_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, @@ -297,6 +298,8 @@ static struct scsi_host_template via_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations via_port_ops = { @@ -370,8 +373,42 @@ static struct ata_port_operations via_port_ops_noirq = { }; /** + * via_config_fifo - set up the FIFO + * @pdev: PCI device + * @flags: configuration flags + * + * Set the FIFO properties for this device if neccessary. Used both on + * set up and on and the resume path + */ + +static void via_config_fifo(struct pci_dev *pdev, unsigned int flags) +{ + u8 enable; + + /* 0x40 low bits indicate enabled channels */ + pci_read_config_byte(pdev, 0x40 , &enable); + enable &= 3; + + if (flags & VIA_SET_FIFO) { + u8 fifo_setting[4] = {0x00, 0x60, 0x00, 0x20}; + u8 fifo; + + pci_read_config_byte(pdev, 0x43, &fifo); + + /* Clear PREQ# until DDACK# for errata */ + if (flags & VIA_BAD_PREQ) + fifo &= 0x7F; + else + fifo &= 0x9f; + /* Turn on FIFO for enabled channels */ + fifo |= fifo_setting[enable]; + pci_write_config_byte(pdev, 0x43, fifo); + } +} + +/** * via_init_one - discovery callback - * @pdev: PCI device ID + * @pdev: PCI device * @id: PCI table info * * A VIA IDE interface has been discovered. Figure out what revision @@ -383,7 +420,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) /* Early VIA without UDMA support */ static struct ata_port_info via_mwdma_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SETXFER_POLLING, .pio_mask = 0x1f, .mwdma_mask = 0x07, .port_ops = &via_port_ops @@ -391,7 +428,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) /* Ditto with IRQ masking required */ static struct ata_port_info via_mwdma_info_borked = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SETXFER_POLLING, .pio_mask = 0x1f, .mwdma_mask = 0x07, .port_ops = &via_port_ops_noirq, @@ -399,7 +436,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) /* VIA UDMA 33 devices (and borked 66) */ static struct ata_port_info via_udma33_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SETXFER_POLLING, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = 0x7, @@ -408,7 +445,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) /* VIA UDMA 66 devices */ static struct ata_port_info via_udma66_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SETXFER_POLLING, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = 0x1f, @@ -417,7 +454,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) /* VIA UDMA 100 devices */ static struct ata_port_info via_udma100_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SETXFER_POLLING, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = 0x3f, @@ -426,7 +463,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) /* UDMA133 with bad AST (All current 133) */ static struct ata_port_info via_udma133_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SETXFER_POLLING, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = 0x7f, /* FIXME: should check north bridge */ @@ -471,21 +508,8 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) } /* Initialise the FIFO for the enabled channels. */ - if (config->flags & VIA_SET_FIFO) { - u8 fifo_setting[4] = {0x00, 0x60, 0x00, 0x20}; - u8 fifo; - - pci_read_config_byte(pdev, 0x43, &fifo); - - /* Clear PREQ# until DDACK# for errata */ - if (config->flags & VIA_BAD_PREQ) - fifo &= 0x7F; - else - fifo &= 0x9f; - /* Turn on FIFO for enabled channels */ - fifo |= fifo_setting[enable]; - pci_write_config_byte(pdev, 0x43, fifo); - } + via_config_fifo(pdev, config->flags); + /* Clock set up */ switch(config->flags & VIA_UDMA) { case VIA_UDMA_NONE: @@ -529,6 +553,39 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return ata_pci_init_one(pdev, port_info, 2); } +/** + * via_reinit_one - reinit after resume + * @pdev; PCI device + * + * Called when the VIA PATA device is resumed. We must then + * reconfigure the fifo and other setup we may have altered. In + * addition the kernel needs to have the resume methods on PCI + * quirk supported. + */ + +static int via_reinit_one(struct pci_dev *pdev) +{ + u32 timing; + struct ata_host *host = dev_get_drvdata(&pdev->dev); + const struct via_isa_bridge *config = host->private_data; + + via_config_fifo(pdev, config->flags); + + if ((config->flags & VIA_UDMA) == VIA_UDMA_66) { + /* The 66 MHz devices require we enable the clock */ + pci_read_config_dword(pdev, 0x50, &timing); + timing |= 0x80008; + pci_write_config_dword(pdev, 0x50, timing); + } + if (config->flags & VIA_BAD_CLK66) { + /* Disable the 66MHz clock on problem devices */ + pci_read_config_dword(pdev, 0x50, &timing); + timing &= ~0x80008; + pci_write_config_dword(pdev, 0x50, timing); + } + return ata_pci_device_resume(pdev); +} + static const struct pci_device_id via[] = { { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C576_1), }, { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C586_1), }, @@ -542,7 +599,9 @@ static struct pci_driver via_pci_driver = { .name = DRV_NAME, .id_table = via, .probe = via_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = via_reinit_one, }; static int __init via_init(void) diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c new file mode 100644 index 000000000000..3ea345cde52e --- /dev/null +++ b/drivers/ata/pata_winbond.c @@ -0,0 +1,306 @@ +/* + * pata_winbond.c - Winbond VLB ATA controllers + * (C) 2006 Red Hat <alan@redhat.com> + * + * Support for the Winbond 83759A when operating in advanced mode. + * Multichip mode is not currently supported. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/blkdev.h> +#include <linux/delay.h> +#include <scsi/scsi_host.h> +#include <linux/libata.h> +#include <linux/platform_device.h> + +#define DRV_NAME "pata_winbond" +#define DRV_VERSION "0.0.1" + +#define NR_HOST 4 /* Two winbond controllers, two channels each */ + +struct winbond_data { + unsigned long config; + struct platform_device *platform_dev; +}; + +static struct ata_host *winbond_host[NR_HOST]; +static struct winbond_data winbond_data[NR_HOST]; +static int nr_winbond_host; + +#ifdef MODULE +static int probe_winbond = 1; +#else +static int probe_winbond; +#endif + +static spinlock_t winbond_lock = SPIN_LOCK_UNLOCKED; + +static void winbond_writecfg(unsigned long port, u8 reg, u8 val) +{ + unsigned long flags; + spin_lock_irqsave(&winbond_lock, flags); + outb(reg, port + 0x01); + outb(val, port + 0x02); + spin_unlock_irqrestore(&winbond_lock, flags); +} + +static u8 winbond_readcfg(unsigned long port, u8 reg) +{ + u8 val; + + unsigned long flags; + spin_lock_irqsave(&winbond_lock, flags); + outb(reg, port + 0x01); + val = inb(port + 0x02); + spin_unlock_irqrestore(&winbond_lock, flags); + + return val; +} + +static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + struct ata_timing t; + struct winbond_data *winbond = ap->host->private_data; + int active, recovery; + u8 reg; + int timing = 0x88 + (ap->port_no * 4) + (adev->devno * 2); + + reg = winbond_readcfg(winbond->config, 0x81); + + /* Get the timing data in cycles */ + if (reg & 0x40) /* Fast VLB bus, assume 50MHz */ + ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000); + else + ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); + + active = (FIT(t.active, 3, 17) - 1) & 0x0F; + recovery = (FIT(t.recover, 1, 15) + 1) & 0x0F; + timing = (active << 4) | recovery; + winbond_writecfg(winbond->config, timing, reg); + + /* Load the setup timing */ + + reg = 0x35; + if (adev->class != ATA_DEV_ATA) + reg |= 0x08; /* FIFO off */ + if (!ata_pio_need_iordy(adev)) + reg |= 0x02; /* IORDY off */ + reg |= (FIT(t.setup, 0, 3) << 6); + winbond_writecfg(winbond->config, timing + 1, reg); +} + + +static void winbond_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) +{ + struct ata_port *ap = adev->ap; + int slop = buflen & 3; + + if (ata_id_has_dword_io(adev->id)) { + if (write_data) + outsl(ap->ioaddr.data_addr, buf, buflen >> 2); + else + insl(ap->ioaddr.data_addr, buf, buflen >> 2); + + if (unlikely(slop)) { + u32 pad; + if (write_data) { + memcpy(&pad, buf + buflen - slop, slop); + outl(le32_to_cpu(pad), ap->ioaddr.data_addr); + } else { + pad = cpu_to_le16(inl(ap->ioaddr.data_addr)); + memcpy(buf + buflen - slop, &pad, slop); + } + } + } else + ata_pio_data_xfer(adev, buf, buflen, write_data); +} + +static struct scsi_host_template winbond_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + .bios_param = ata_std_bios_param, +}; + +static struct ata_port_operations winbond_port_ops = { + .port_disable = ata_port_disable, + .set_piomode = winbond_set_piomode, + + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .data_xfer = winbond_data_xfer, + + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + + .port_start = ata_port_start, + .port_stop = ata_port_stop, + .host_stop = ata_host_stop +}; + +/** + * winbond_init_one - attach a winbond interface + * @type: Type to display + * @io: I/O port start + * @irq: interrupt line + * @fast: True if on a > 33Mhz VLB + * + * Register a VLB bus IDE interface. Such interfaces are PIO and we + * assume do not support IRQ sharing. + */ + +static __init int winbond_init_one(unsigned long port) +{ + struct ata_probe_ent ae; + struct platform_device *pdev; + int ret; + u8 reg; + int i; + + reg = winbond_readcfg(port, 0x81); + reg |= 0x80; /* jumpered mode off */ + winbond_writecfg(port, 0x81, reg); + reg = winbond_readcfg(port, 0x83); + reg |= 0xF0; /* local control */ + winbond_writecfg(port, 0x83, reg); + reg = winbond_readcfg(port, 0x85); + reg |= 0xF0; /* programmable timing */ + winbond_writecfg(port, 0x85, reg); + + reg = winbond_readcfg(port, 0x81); + + if (!(reg & 0x03)) /* Disabled */ + return 0; + + for (i = 0; i < 2 ; i ++) { + + if (reg & (1 << i)) { + /* + * Fill in a probe structure first of all + */ + + pdev = platform_device_register_simple(DRV_NAME, nr_winbond_host, NULL, 0); + if (pdev == NULL) + return -ENOMEM; + + memset(&ae, 0, sizeof(struct ata_probe_ent)); + INIT_LIST_HEAD(&ae.node); + ae.dev = &pdev->dev; + + ae.port_ops = &winbond_port_ops; + ae.pio_mask = 0x1F; + + ae.sht = &winbond_sht; + + ae.n_ports = 1; + ae.irq = 14 + i; + ae.irq_flags = 0; + ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; + ae.port[0].cmd_addr = 0x1F0 - (0x80 * i); + ae.port[0].altstatus_addr = ae.port[0].cmd_addr + 0x0206; + ae.port[0].ctl_addr = ae.port[0].altstatus_addr; + ata_std_ports(&ae.port[0]); + /* + * Hook in a private data structure per channel + */ + ae.private_data = &winbond_data[nr_winbond_host]; + winbond_data[nr_winbond_host].config = port; + winbond_data[nr_winbond_host].platform_dev = pdev; + + ret = ata_device_add(&ae); + if (ret == 0) { + platform_device_unregister(pdev); + return -ENODEV; + } + winbond_host[nr_winbond_host++] = dev_get_drvdata(&pdev->dev); + } + } + + return 0; +} + +/** + * winbond_init - attach winbond interfaces + * + * Attach winbond IDE interfaces by scanning the ports it may occupy. + */ + +static __init int winbond_init(void) +{ + static const unsigned long config[2] = { 0x130, 0x1B0 }; + + int ct = 0; + int i; + + if (probe_winbond == 0) + return -ENODEV; + + /* + * Check both base addresses + */ + + for (i = 0; i < 2; i++) { + if (probe_winbond & (1<<i)) { + int ret = 0; + unsigned long port = config[i]; + + if (request_region(port, 2, "pata_winbond")) { + ret = winbond_init_one(port); + if(ret <= 0) + release_region(port, 2); + else ct+= ret; + } + } + } + if (ct != 0) + return 0; + return -ENODEV; +} + +static __exit void winbond_exit(void) +{ + int i; + + for (i = 0; i < nr_winbond_host; i++) { + ata_host_remove(winbond_host[i]); + release_region(winbond_data[i].config, 2); + platform_device_unregister(winbond_data[i].platform_dev); + } +} + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("low-level driver for Winbond VL ATA"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +module_init(winbond_init); +module_exit(winbond_exit); + +module_param(probe_winbond, int, 0); + diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index d65ebfd7c7b2..0d316eb3c214 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -29,6 +29,11 @@ * NV-specific details such as register offsets, SATA phy location, * hotplug info, etc. * + * CK804/MCP04 controllers support an alternate programming interface + * similar to the ADMA specification (with some modifications). + * This allows the use of NCQ. Non-DMA-mapped ATA commands are still + * sent through the legacy interface. + * */ #include <linux/kernel.h> @@ -40,10 +45,13 @@ #include <linux/interrupt.h> #include <linux/device.h> #include <scsi/scsi_host.h> +#include <scsi/scsi_device.h> #include <linux/libata.h> #define DRV_NAME "sata_nv" -#define DRV_VERSION "2.0" +#define DRV_VERSION "3.2" + +#define NV_ADMA_DMA_BOUNDARY 0xffffffffUL enum { NV_PORTS = 2, @@ -78,8 +86,138 @@ enum { // For PCI config register 20 NV_MCP_SATA_CFG_20 = 0x50, NV_MCP_SATA_CFG_20_SATA_SPACE_EN = 0x04, + NV_MCP_SATA_CFG_20_PORT0_EN = (1 << 17), + NV_MCP_SATA_CFG_20_PORT1_EN = (1 << 16), + NV_MCP_SATA_CFG_20_PORT0_PWB_EN = (1 << 14), + NV_MCP_SATA_CFG_20_PORT1_PWB_EN = (1 << 12), + + NV_ADMA_MAX_CPBS = 32, + NV_ADMA_CPB_SZ = 128, + NV_ADMA_APRD_SZ = 16, + NV_ADMA_SGTBL_LEN = (1024 - NV_ADMA_CPB_SZ) / + NV_ADMA_APRD_SZ, + NV_ADMA_SGTBL_TOTAL_LEN = NV_ADMA_SGTBL_LEN + 5, + NV_ADMA_SGTBL_SZ = NV_ADMA_SGTBL_LEN * NV_ADMA_APRD_SZ, + NV_ADMA_PORT_PRIV_DMA_SZ = NV_ADMA_MAX_CPBS * + (NV_ADMA_CPB_SZ + NV_ADMA_SGTBL_SZ), + + /* BAR5 offset to ADMA general registers */ + NV_ADMA_GEN = 0x400, + NV_ADMA_GEN_CTL = 0x00, + NV_ADMA_NOTIFIER_CLEAR = 0x30, + + /* BAR5 offset to ADMA ports */ + NV_ADMA_PORT = 0x480, + + /* size of ADMA port register space */ + NV_ADMA_PORT_SIZE = 0x100, + + /* ADMA port registers */ + NV_ADMA_CTL = 0x40, + NV_ADMA_CPB_COUNT = 0x42, + NV_ADMA_NEXT_CPB_IDX = 0x43, + NV_ADMA_STAT = 0x44, + NV_ADMA_CPB_BASE_LOW = 0x48, + NV_ADMA_CPB_BASE_HIGH = 0x4C, + NV_ADMA_APPEND = 0x50, + NV_ADMA_NOTIFIER = 0x68, + NV_ADMA_NOTIFIER_ERROR = 0x6C, + + /* NV_ADMA_CTL register bits */ + NV_ADMA_CTL_HOTPLUG_IEN = (1 << 0), + NV_ADMA_CTL_CHANNEL_RESET = (1 << 5), + NV_ADMA_CTL_GO = (1 << 7), + NV_ADMA_CTL_AIEN = (1 << 8), + NV_ADMA_CTL_READ_NON_COHERENT = (1 << 11), + NV_ADMA_CTL_WRITE_NON_COHERENT = (1 << 12), + + /* CPB response flag bits */ + NV_CPB_RESP_DONE = (1 << 0), + NV_CPB_RESP_ATA_ERR = (1 << 3), + NV_CPB_RESP_CMD_ERR = (1 << 4), + NV_CPB_RESP_CPB_ERR = (1 << 7), + + /* CPB control flag bits */ + NV_CPB_CTL_CPB_VALID = (1 << 0), + NV_CPB_CTL_QUEUE = (1 << 1), + NV_CPB_CTL_APRD_VALID = (1 << 2), + NV_CPB_CTL_IEN = (1 << 3), + NV_CPB_CTL_FPDMA = (1 << 4), + + /* APRD flags */ + NV_APRD_WRITE = (1 << 1), + NV_APRD_END = (1 << 2), + NV_APRD_CONT = (1 << 3), + + /* NV_ADMA_STAT flags */ + NV_ADMA_STAT_TIMEOUT = (1 << 0), + NV_ADMA_STAT_HOTUNPLUG = (1 << 1), + NV_ADMA_STAT_HOTPLUG = (1 << 2), + NV_ADMA_STAT_CPBERR = (1 << 4), + NV_ADMA_STAT_SERROR = (1 << 5), + NV_ADMA_STAT_CMD_COMPLETE = (1 << 6), + NV_ADMA_STAT_IDLE = (1 << 8), + NV_ADMA_STAT_LEGACY = (1 << 9), + NV_ADMA_STAT_STOPPED = (1 << 10), + NV_ADMA_STAT_DONE = (1 << 12), + NV_ADMA_STAT_ERR = NV_ADMA_STAT_CPBERR | + NV_ADMA_STAT_TIMEOUT, + + /* port flags */ + NV_ADMA_PORT_REGISTER_MODE = (1 << 0), + NV_ADMA_ATAPI_SETUP_COMPLETE = (1 << 1), + +}; + +/* ADMA Physical Region Descriptor - one SG segment */ +struct nv_adma_prd { + __le64 addr; + __le32 len; + u8 flags; + u8 packet_len; + __le16 reserved; +}; + +enum nv_adma_regbits { + CMDEND = (1 << 15), /* end of command list */ + WNB = (1 << 14), /* wait-not-BSY */ + IGN = (1 << 13), /* ignore this entry */ + CS1n = (1 << (4 + 8)), /* std. PATA signals follow... */ + DA2 = (1 << (2 + 8)), + DA1 = (1 << (1 + 8)), + DA0 = (1 << (0 + 8)), +}; + +/* ADMA Command Parameter Block + The first 5 SG segments are stored inside the Command Parameter Block itself. + If there are more than 5 segments the remainder are stored in a separate + memory area indicated by next_aprd. */ +struct nv_adma_cpb { + u8 resp_flags; /* 0 */ + u8 reserved1; /* 1 */ + u8 ctl_flags; /* 2 */ + /* len is length of taskfile in 64 bit words */ + u8 len; /* 3 */ + u8 tag; /* 4 */ + u8 next_cpb_idx; /* 5 */ + __le16 reserved2; /* 6-7 */ + __le16 tf[12]; /* 8-31 */ + struct nv_adma_prd aprd[5]; /* 32-111 */ + __le64 next_aprd; /* 112-119 */ + __le64 reserved3; /* 120-127 */ +}; + + +struct nv_adma_port_priv { + struct nv_adma_cpb *cpb; + dma_addr_t cpb_dma; + struct nv_adma_prd *aprd; + dma_addr_t aprd_dma; + u8 flags; }; +#define NV_ADMA_CHECK_INTR(GCTL, PORT) ((GCTL) & ( 1 << (19 + (12 * (PORT))))) + static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static void nv_ck804_host_stop(struct ata_host *host); static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance); @@ -93,13 +231,28 @@ static void nv_nf2_thaw(struct ata_port *ap); static void nv_ck804_freeze(struct ata_port *ap); static void nv_ck804_thaw(struct ata_port *ap); static void nv_error_handler(struct ata_port *ap); +static int nv_adma_slave_config(struct scsi_device *sdev); +static int nv_adma_check_atapi_dma(struct ata_queued_cmd *qc); +static void nv_adma_qc_prep(struct ata_queued_cmd *qc); +static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc); +static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance); +static void nv_adma_irq_clear(struct ata_port *ap); +static int nv_adma_port_start(struct ata_port *ap); +static void nv_adma_port_stop(struct ata_port *ap); +static void nv_adma_error_handler(struct ata_port *ap); +static void nv_adma_host_stop(struct ata_host *host); +static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc); +static void nv_adma_bmdma_start(struct ata_queued_cmd *qc); +static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc); +static u8 nv_adma_bmdma_status(struct ata_port *ap); enum nv_host_type { GENERIC, NFORCE2, NFORCE3 = NFORCE2, /* NF2 == NF3 as far as sata_nv is concerned */ - CK804 + CK804, + ADMA }; static const struct pci_device_id nv_pci_tbl[] = { @@ -160,6 +313,24 @@ static struct scsi_host_template nv_sht = { .bios_param = ata_std_bios_param, }; +static struct scsi_host_template nv_adma_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = NV_ADMA_MAX_CPBS, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = NV_ADMA_SGTBL_TOTAL_LEN, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = NV_ADMA_DMA_BOUNDARY, + .slave_configure = nv_adma_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + .bios_param = ata_std_bios_param, +}; + static const struct ata_port_operations nv_generic_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, @@ -241,11 +412,40 @@ static const struct ata_port_operations nv_ck804_ops = { .host_stop = nv_ck804_host_stop, }; +static const struct ata_port_operations nv_adma_ops = { + .port_disable = ata_port_disable, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_atapi_dma = nv_adma_check_atapi_dma, + .exec_command = ata_exec_command, + .check_status = ata_check_status, + .dev_select = ata_std_dev_select, + .bmdma_setup = nv_adma_bmdma_setup, + .bmdma_start = nv_adma_bmdma_start, + .bmdma_stop = nv_adma_bmdma_stop, + .bmdma_status = nv_adma_bmdma_status, + .qc_prep = nv_adma_qc_prep, + .qc_issue = nv_adma_qc_issue, + .freeze = nv_ck804_freeze, + .thaw = nv_ck804_thaw, + .error_handler = nv_adma_error_handler, + .post_internal_cmd = nv_adma_bmdma_stop, + .data_xfer = ata_mmio_data_xfer, + .irq_handler = nv_adma_interrupt, + .irq_clear = nv_adma_irq_clear, + .scr_read = nv_scr_read, + .scr_write = nv_scr_write, + .port_start = nv_adma_port_start, + .port_stop = nv_adma_port_stop, + .host_stop = nv_adma_host_stop, +}; + static struct ata_port_info nv_port_info[] = { /* generic */ { .sht = &nv_sht, - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, @@ -254,7 +454,8 @@ static struct ata_port_info nv_port_info[] = { /* nforce2/3 */ { .sht = &nv_sht, - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, @@ -263,12 +464,23 @@ static struct ata_port_info nv_port_info[] = { /* ck804 */ { .sht = &nv_sht, - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, .port_ops = &nv_ck804_ops, }, + /* ADMA */ + { + .sht = &nv_adma_sht, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO | ATA_FLAG_NCQ, + .pio_mask = NV_PIO_MASK, + .mwdma_mask = NV_MWDMA_MASK, + .udma_mask = NV_UDMA_MASK, + .port_ops = &nv_adma_ops, + }, }; MODULE_AUTHOR("NVIDIA"); @@ -277,37 +489,220 @@ MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, nv_pci_tbl); MODULE_VERSION(DRV_VERSION); -static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance) +static int adma_enabled = 1; + +static inline void __iomem *__nv_adma_ctl_block(void __iomem *mmio, + unsigned int port_no) { - struct ata_host *host = dev_instance; - unsigned int i; - unsigned int handled = 0; - unsigned long flags; + mmio += NV_ADMA_PORT + port_no * NV_ADMA_PORT_SIZE; + return mmio; +} - spin_lock_irqsave(&host->lock, flags); +static inline void __iomem *nv_adma_ctl_block(struct ata_port *ap) +{ + return __nv_adma_ctl_block(ap->host->mmio_base, ap->port_no); +} - for (i = 0; i < host->n_ports; i++) { - struct ata_port *ap; +static inline void __iomem *nv_adma_gen_block(struct ata_port *ap) +{ + return (ap->host->mmio_base + NV_ADMA_GEN); +} - ap = host->ports[i]; - if (ap && - !(ap->flags & ATA_FLAG_DISABLED)) { - struct ata_queued_cmd *qc; +static inline void __iomem *nv_adma_notifier_clear_block(struct ata_port *ap) +{ + return (nv_adma_gen_block(ap) + NV_ADMA_NOTIFIER_CLEAR + (4 * ap->port_no)); +} - qc = ata_qc_from_tag(ap, ap->active_tag); - if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) - handled += ata_host_intr(ap, qc); - else - // No request pending? Clear interrupt status - // anyway, in case there's one pending. - ap->ops->check_status(ap); - } +static void nv_adma_register_mode(struct ata_port *ap) +{ + void __iomem *mmio = nv_adma_ctl_block(ap); + struct nv_adma_port_priv *pp = ap->private_data; + u16 tmp; + + if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) + return; + + tmp = readw(mmio + NV_ADMA_CTL); + writew(tmp & ~NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL); + + pp->flags |= NV_ADMA_PORT_REGISTER_MODE; +} + +static void nv_adma_mode(struct ata_port *ap) +{ + void __iomem *mmio = nv_adma_ctl_block(ap); + struct nv_adma_port_priv *pp = ap->private_data; + u16 tmp; + if (!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) + return; + + WARN_ON(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE); + + tmp = readw(mmio + NV_ADMA_CTL); + writew(tmp | NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL); + + pp->flags &= ~NV_ADMA_PORT_REGISTER_MODE; +} + +static int nv_adma_slave_config(struct scsi_device *sdev) +{ + struct ata_port *ap = ata_shost_to_port(sdev->host); + struct nv_adma_port_priv *pp = ap->private_data; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + u64 bounce_limit; + unsigned long segment_boundary; + unsigned short sg_tablesize; + int rc; + int adma_enable; + u32 current_reg, new_reg, config_mask; + + rc = ata_scsi_slave_config(sdev); + + if (sdev->id >= ATA_MAX_DEVICES || sdev->channel || sdev->lun) + /* Not a proper libata device, ignore */ + return rc; + + if (ap->device[sdev->id].class == ATA_DEV_ATAPI) { + /* + * NVIDIA reports that ADMA mode does not support ATAPI commands. + * Therefore ATAPI commands are sent through the legacy interface. + * However, the legacy interface only supports 32-bit DMA. + * Restrict DMA parameters as required by the legacy interface + * when an ATAPI device is connected. + */ + bounce_limit = ATA_DMA_MASK; + segment_boundary = ATA_DMA_BOUNDARY; + /* Subtract 1 since an extra entry may be needed for padding, see + libata-scsi.c */ + sg_tablesize = LIBATA_MAX_PRD - 1; + + /* Since the legacy DMA engine is in use, we need to disable ADMA + on the port. */ + adma_enable = 0; + nv_adma_register_mode(ap); + } + else { + bounce_limit = *ap->dev->dma_mask; + segment_boundary = NV_ADMA_DMA_BOUNDARY; + sg_tablesize = NV_ADMA_SGTBL_TOTAL_LEN; + adma_enable = 1; + } + + pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, ¤t_reg); + + if(ap->port_no == 1) + config_mask = NV_MCP_SATA_CFG_20_PORT1_EN | + NV_MCP_SATA_CFG_20_PORT1_PWB_EN; + else + config_mask = NV_MCP_SATA_CFG_20_PORT0_EN | + NV_MCP_SATA_CFG_20_PORT0_PWB_EN; + + if(adma_enable) { + new_reg = current_reg | config_mask; + pp->flags &= ~NV_ADMA_ATAPI_SETUP_COMPLETE; + } + else { + new_reg = current_reg & ~config_mask; + pp->flags |= NV_ADMA_ATAPI_SETUP_COMPLETE; } + + if(current_reg != new_reg) + pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, new_reg); + + blk_queue_bounce_limit(sdev->request_queue, bounce_limit); + blk_queue_segment_boundary(sdev->request_queue, segment_boundary); + blk_queue_max_hw_segments(sdev->request_queue, sg_tablesize); + ata_port_printk(ap, KERN_INFO, + "bounce limit 0x%llX, segment boundary 0x%lX, hw segs %hu\n", + (unsigned long long)bounce_limit, segment_boundary, sg_tablesize); + return rc; +} - spin_unlock_irqrestore(&host->lock, flags); +static int nv_adma_check_atapi_dma(struct ata_queued_cmd *qc) +{ + struct nv_adma_port_priv *pp = qc->ap->private_data; + return !(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE); +} - return IRQ_RETVAL(handled); +static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, __le16 *cpb) +{ + unsigned int idx = 0; + + cpb[idx++] = cpu_to_le16((ATA_REG_DEVICE << 8) | tf->device | WNB); + + if ((tf->flags & ATA_TFLAG_LBA48) == 0) { + cpb[idx++] = cpu_to_le16(IGN); + cpb[idx++] = cpu_to_le16(IGN); + cpb[idx++] = cpu_to_le16(IGN); + cpb[idx++] = cpu_to_le16(IGN); + cpb[idx++] = cpu_to_le16(IGN); + } + else { + cpb[idx++] = cpu_to_le16((ATA_REG_ERR << 8) | tf->hob_feature); + cpb[idx++] = cpu_to_le16((ATA_REG_NSECT << 8) | tf->hob_nsect); + cpb[idx++] = cpu_to_le16((ATA_REG_LBAL << 8) | tf->hob_lbal); + cpb[idx++] = cpu_to_le16((ATA_REG_LBAM << 8) | tf->hob_lbam); + cpb[idx++] = cpu_to_le16((ATA_REG_LBAH << 8) | tf->hob_lbah); + } + cpb[idx++] = cpu_to_le16((ATA_REG_ERR << 8) | tf->feature); + cpb[idx++] = cpu_to_le16((ATA_REG_NSECT << 8) | tf->nsect); + cpb[idx++] = cpu_to_le16((ATA_REG_LBAL << 8) | tf->lbal); + cpb[idx++] = cpu_to_le16((ATA_REG_LBAM << 8) | tf->lbam); + cpb[idx++] = cpu_to_le16((ATA_REG_LBAH << 8) | tf->lbah); + + cpb[idx++] = cpu_to_le16((ATA_REG_CMD << 8) | tf->command | CMDEND); + + return idx; +} + +static void nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) +{ + struct nv_adma_port_priv *pp = ap->private_data; + int complete = 0, have_err = 0; + u8 flags = pp->cpb[cpb_num].resp_flags; + + VPRINTK("CPB %d, flags=0x%x\n", cpb_num, flags); + + if (flags & NV_CPB_RESP_DONE) { + VPRINTK("CPB flags done, flags=0x%x\n", flags); + complete = 1; + } + if (flags & NV_CPB_RESP_ATA_ERR) { + ata_port_printk(ap, KERN_ERR, "CPB flags ATA err, flags=0x%x\n", flags); + have_err = 1; + complete = 1; + } + if (flags & NV_CPB_RESP_CMD_ERR) { + ata_port_printk(ap, KERN_ERR, "CPB flags CMD err, flags=0x%x\n", flags); + have_err = 1; + complete = 1; + } + if (flags & NV_CPB_RESP_CPB_ERR) { + ata_port_printk(ap, KERN_ERR, "CPB flags CPB err, flags=0x%x\n", flags); + have_err = 1; + complete = 1; + } + if(complete || force_err) + { + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, cpb_num); + if(likely(qc)) { + u8 ata_status = 0; + /* Only use the ATA port status for non-NCQ commands. + For NCQ commands the current status may have nothing to do with + the command just completed. */ + if(qc->tf.protocol != ATA_PROT_NCQ) + ata_status = readb(nv_adma_ctl_block(ap) + (ATA_REG_STATUS * 4)); + + if(have_err || force_err) + ata_status |= ATA_ERR; + + qc->err_mask |= ac_err_mask(ata_status); + DPRINTK("Completing qc from tag %d with err_mask %u\n",cpb_num, + qc->err_mask); + ata_qc_complete(qc); + } + } } static int nv_host_intr(struct ata_port *ap, u8 irq_stat) @@ -341,6 +736,486 @@ static int nv_host_intr(struct ata_port *ap, u8 irq_stat) return 1; } +static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) +{ + struct ata_host *host = dev_instance; + int i, handled = 0; + u32 notifier_clears[2]; + + spin_lock(&host->lock); + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + notifier_clears[i] = 0; + + if (ap && !(ap->flags & ATA_FLAG_DISABLED)) { + struct nv_adma_port_priv *pp = ap->private_data; + void __iomem *mmio = nv_adma_ctl_block(ap); + u16 status; + u32 gen_ctl; + int have_global_err = 0; + u32 notifier, notifier_error; + + /* if in ATA register mode, use standard ata interrupt handler */ + if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) { + u8 irq_stat = readb(host->mmio_base + NV_INT_STATUS_CK804) + >> (NV_INT_PORT_SHIFT * i); + handled += nv_host_intr(ap, irq_stat); + continue; + } + + notifier = readl(mmio + NV_ADMA_NOTIFIER); + notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR); + notifier_clears[i] = notifier | notifier_error; + + gen_ctl = readl(nv_adma_gen_block(ap) + NV_ADMA_GEN_CTL); + + if( !NV_ADMA_CHECK_INTR(gen_ctl, ap->port_no) && !notifier && + !notifier_error) + /* Nothing to do */ + continue; + + status = readw(mmio + NV_ADMA_STAT); + + /* Clear status. Ensure the controller sees the clearing before we start + looking at any of the CPB statuses, so that any CPB completions after + this point in the handler will raise another interrupt. */ + writew(status, mmio + NV_ADMA_STAT); + readw(mmio + NV_ADMA_STAT); /* flush posted write */ + rmb(); + + /* freeze if hotplugged */ + if (unlikely(status & (NV_ADMA_STAT_HOTPLUG | NV_ADMA_STAT_HOTUNPLUG))) { + ata_port_printk(ap, KERN_NOTICE, "Hotplug event, freezing\n"); + ata_port_freeze(ap); + handled++; + continue; + } + + if (status & NV_ADMA_STAT_TIMEOUT) { + ata_port_printk(ap, KERN_ERR, "timeout, stat=0x%x\n", status); + have_global_err = 1; + } + if (status & NV_ADMA_STAT_CPBERR) { + ata_port_printk(ap, KERN_ERR, "CPB error, stat=0x%x\n", status); + have_global_err = 1; + } + if ((status & NV_ADMA_STAT_DONE) || have_global_err) { + /** Check CPBs for completed commands */ + + if(ata_tag_valid(ap->active_tag)) + /* Non-NCQ command */ + nv_adma_check_cpb(ap, ap->active_tag, have_global_err || + (notifier_error & (1 << ap->active_tag))); + else { + int pos; + u32 active = ap->sactive; + while( (pos = ffs(active)) ) { + pos--; + nv_adma_check_cpb(ap, pos, have_global_err || + (notifier_error & (1 << pos)) ); + active &= ~(1 << pos ); + } + } + } + + handled++; /* irq handled if we got here */ + } + } + + if(notifier_clears[0] || notifier_clears[1]) { + /* Note: Both notifier clear registers must be written + if either is set, even if one is zero, according to NVIDIA. */ + writel(notifier_clears[0], + nv_adma_notifier_clear_block(host->ports[0])); + writel(notifier_clears[1], + nv_adma_notifier_clear_block(host->ports[1])); + } + + spin_unlock(&host->lock); + + return IRQ_RETVAL(handled); +} + +static void nv_adma_irq_clear(struct ata_port *ap) +{ + void __iomem *mmio = nv_adma_ctl_block(ap); + u16 status = readw(mmio + NV_ADMA_STAT); + u32 notifier = readl(mmio + NV_ADMA_NOTIFIER); + u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR); + unsigned long dma_stat_addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS; + + /* clear ADMA status */ + writew(status, mmio + NV_ADMA_STAT); + writel(notifier | notifier_error, + nv_adma_notifier_clear_block(ap)); + + /** clear legacy status */ + outb(inb(dma_stat_addr), dma_stat_addr); +} + +static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); + struct nv_adma_port_priv *pp = ap->private_data; + u8 dmactl; + + if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) { + WARN_ON(1); + return; + } + + /* load PRD table addr. */ + outl(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS); + + /* specify data direction, triple-check start bit is clear */ + dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + dmactl &= ~(ATA_DMA_WR | ATA_DMA_START); + if (!rw) + dmactl |= ATA_DMA_WR; + + outb(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + + /* issue r/w command */ + ata_exec_command(ap, &qc->tf); +} + +static void nv_adma_bmdma_start(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct nv_adma_port_priv *pp = ap->private_data; + u8 dmactl; + + if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) { + WARN_ON(1); + return; + } + + /* start host DMA transaction */ + dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + outb(dmactl | ATA_DMA_START, + ap->ioaddr.bmdma_addr + ATA_DMA_CMD); +} + +static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct nv_adma_port_priv *pp = ap->private_data; + + if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) + return; + + /* clear start/stop bit */ + outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START, + ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + + /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ + ata_altstatus(ap); /* dummy read */ +} + +static u8 nv_adma_bmdma_status(struct ata_port *ap) +{ + struct nv_adma_port_priv *pp = ap->private_data; + + WARN_ON(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)); + + return inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); +} + +static int nv_adma_port_start(struct ata_port *ap) +{ + struct device *dev = ap->host->dev; + struct nv_adma_port_priv *pp; + int rc; + void *mem; + dma_addr_t mem_dma; + void __iomem *mmio = nv_adma_ctl_block(ap); + u16 tmp; + + VPRINTK("ENTER\n"); + + rc = ata_port_start(ap); + if (rc) + return rc; + + pp = kzalloc(sizeof(*pp), GFP_KERNEL); + if (!pp) { + rc = -ENOMEM; + goto err_out; + } + + mem = dma_alloc_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ, + &mem_dma, GFP_KERNEL); + + if (!mem) { + rc = -ENOMEM; + goto err_out_kfree; + } + memset(mem, 0, NV_ADMA_PORT_PRIV_DMA_SZ); + + /* + * First item in chunk of DMA memory: + * 128-byte command parameter block (CPB) + * one for each command tag + */ + pp->cpb = mem; + pp->cpb_dma = mem_dma; + + writel(mem_dma & 0xFFFFFFFF, mmio + NV_ADMA_CPB_BASE_LOW); + writel((mem_dma >> 16 ) >> 16, mmio + NV_ADMA_CPB_BASE_HIGH); + + mem += NV_ADMA_MAX_CPBS * NV_ADMA_CPB_SZ; + mem_dma += NV_ADMA_MAX_CPBS * NV_ADMA_CPB_SZ; + + /* + * Second item: block of ADMA_SGTBL_LEN s/g entries + */ + pp->aprd = mem; + pp->aprd_dma = mem_dma; + + ap->private_data = pp; + + /* clear any outstanding interrupt conditions */ + writew(0xffff, mmio + NV_ADMA_STAT); + + /* initialize port variables */ + pp->flags = NV_ADMA_PORT_REGISTER_MODE; + + /* clear CPB fetch count */ + writew(0, mmio + NV_ADMA_CPB_COUNT); + + /* clear GO for register mode */ + tmp = readw(mmio + NV_ADMA_CTL); + writew(tmp & ~NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL); + + tmp = readw(mmio + NV_ADMA_CTL); + writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL); + readl( mmio + NV_ADMA_CTL ); /* flush posted write */ + udelay(1); + writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL); + readl( mmio + NV_ADMA_CTL ); /* flush posted write */ + + return 0; + +err_out_kfree: + kfree(pp); +err_out: + ata_port_stop(ap); + return rc; +} + +static void nv_adma_port_stop(struct ata_port *ap) +{ + struct device *dev = ap->host->dev; + struct nv_adma_port_priv *pp = ap->private_data; + void __iomem *mmio = nv_adma_ctl_block(ap); + + VPRINTK("ENTER\n"); + + writew(0, mmio + NV_ADMA_CTL); + + ap->private_data = NULL; + dma_free_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ, pp->cpb, pp->cpb_dma); + kfree(pp); + ata_port_stop(ap); +} + + +static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int port) +{ + void __iomem *mmio = probe_ent->mmio_base; + struct ata_ioports *ioport = &probe_ent->port[port]; + + VPRINTK("ENTER\n"); + + mmio += NV_ADMA_PORT + port * NV_ADMA_PORT_SIZE; + + ioport->cmd_addr = (unsigned long) mmio; + ioport->data_addr = (unsigned long) mmio + (ATA_REG_DATA * 4); + ioport->error_addr = + ioport->feature_addr = (unsigned long) mmio + (ATA_REG_ERR * 4); + ioport->nsect_addr = (unsigned long) mmio + (ATA_REG_NSECT * 4); + ioport->lbal_addr = (unsigned long) mmio + (ATA_REG_LBAL * 4); + ioport->lbam_addr = (unsigned long) mmio + (ATA_REG_LBAM * 4); + ioport->lbah_addr = (unsigned long) mmio + (ATA_REG_LBAH * 4); + ioport->device_addr = (unsigned long) mmio + (ATA_REG_DEVICE * 4); + ioport->status_addr = + ioport->command_addr = (unsigned long) mmio + (ATA_REG_STATUS * 4); + ioport->altstatus_addr = + ioport->ctl_addr = (unsigned long) mmio + 0x20; +} + +static int nv_adma_host_init(struct ata_probe_ent *probe_ent) +{ + struct pci_dev *pdev = to_pci_dev(probe_ent->dev); + unsigned int i; + u32 tmp32; + + VPRINTK("ENTER\n"); + + /* enable ADMA on the ports */ + pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &tmp32); + tmp32 |= NV_MCP_SATA_CFG_20_PORT0_EN | + NV_MCP_SATA_CFG_20_PORT0_PWB_EN | + NV_MCP_SATA_CFG_20_PORT1_EN | + NV_MCP_SATA_CFG_20_PORT1_PWB_EN; + + pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, tmp32); + + for (i = 0; i < probe_ent->n_ports; i++) + nv_adma_setup_port(probe_ent, i); + + for (i = 0; i < probe_ent->n_ports; i++) { + void __iomem *mmio = __nv_adma_ctl_block(probe_ent->mmio_base, i); + u16 tmp; + + /* enable interrupt, clear reset if not already clear */ + tmp = readw(mmio + NV_ADMA_CTL); + writew(tmp | NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL); + } + + return 0; +} + +static void nv_adma_fill_aprd(struct ata_queued_cmd *qc, + struct scatterlist *sg, + int idx, + struct nv_adma_prd *aprd) +{ + u8 flags; + + memset(aprd, 0, sizeof(struct nv_adma_prd)); + + flags = 0; + if (qc->tf.flags & ATA_TFLAG_WRITE) + flags |= NV_APRD_WRITE; + if (idx == qc->n_elem - 1) + flags |= NV_APRD_END; + else if (idx != 4) + flags |= NV_APRD_CONT; + + aprd->addr = cpu_to_le64(((u64)sg_dma_address(sg))); + aprd->len = cpu_to_le32(((u32)sg_dma_len(sg))); /* len in bytes */ + aprd->flags = flags; +} + +static void nv_adma_fill_sg(struct ata_queued_cmd *qc, struct nv_adma_cpb *cpb) +{ + struct nv_adma_port_priv *pp = qc->ap->private_data; + unsigned int idx; + struct nv_adma_prd *aprd; + struct scatterlist *sg; + + VPRINTK("ENTER\n"); + + idx = 0; + + ata_for_each_sg(sg, qc) { + aprd = (idx < 5) ? &cpb->aprd[idx] : &pp->aprd[NV_ADMA_SGTBL_LEN * qc->tag + (idx-5)]; + nv_adma_fill_aprd(qc, sg, idx, aprd); + idx++; + } + if (idx > 5) + cpb->next_aprd = cpu_to_le64(((u64)(pp->aprd_dma + NV_ADMA_SGTBL_SZ * qc->tag))); +} + +static void nv_adma_qc_prep(struct ata_queued_cmd *qc) +{ + struct nv_adma_port_priv *pp = qc->ap->private_data; + struct nv_adma_cpb *cpb = &pp->cpb[qc->tag]; + u8 ctl_flags = NV_CPB_CTL_CPB_VALID | + NV_CPB_CTL_APRD_VALID | + NV_CPB_CTL_IEN; + + VPRINTK("qc->flags = 0x%lx\n", qc->flags); + + if (!(qc->flags & ATA_QCFLAG_DMAMAP) || + (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)) { + nv_adma_register_mode(qc->ap); + ata_qc_prep(qc); + return; + } + + memset(cpb, 0, sizeof(struct nv_adma_cpb)); + + cpb->len = 3; + cpb->tag = qc->tag; + cpb->next_cpb_idx = 0; + + /* turn on NCQ flags for NCQ commands */ + if (qc->tf.protocol == ATA_PROT_NCQ) + ctl_flags |= NV_CPB_CTL_QUEUE | NV_CPB_CTL_FPDMA; + + nv_adma_tf_to_cpb(&qc->tf, cpb->tf); + + nv_adma_fill_sg(qc, cpb); + + /* Be paranoid and don't let the device see NV_CPB_CTL_CPB_VALID until we are + finished filling in all of the contents */ + wmb(); + cpb->ctl_flags = ctl_flags; +} + +static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc) +{ + struct nv_adma_port_priv *pp = qc->ap->private_data; + void __iomem *mmio = nv_adma_ctl_block(qc->ap); + + VPRINTK("ENTER\n"); + + if (!(qc->flags & ATA_QCFLAG_DMAMAP) || + (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)) { + /* use ATA register mode */ + VPRINTK("no dmamap or ATAPI, using ATA register mode: 0x%lx\n", qc->flags); + nv_adma_register_mode(qc->ap); + return ata_qc_issue_prot(qc); + } else + nv_adma_mode(qc->ap); + + /* write append register, command tag in lower 8 bits + and (number of cpbs to append -1) in top 8 bits */ + wmb(); + writew(qc->tag, mmio + NV_ADMA_APPEND); + + DPRINTK("Issued tag %u\n",qc->tag); + + return 0; +} + +static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance) +{ + struct ata_host *host = dev_instance; + unsigned int i; + unsigned int handled = 0; + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap; + + ap = host->ports[i]; + if (ap && + !(ap->flags & ATA_FLAG_DISABLED)) { + struct ata_queued_cmd *qc; + + qc = ata_qc_from_tag(ap, ap->active_tag); + if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) + handled += ata_host_intr(ap, qc); + else + // No request pending? Clear interrupt status + // anyway, in case there's one pending. + ap->ops->check_status(ap); + } + + } + + spin_unlock_irqrestore(&host->lock, flags); + + return IRQ_RETVAL(handled); +} + static irqreturn_t nv_do_interrupt(struct ata_host *host, u8 irq_stat) { int i, handled = 0; @@ -466,6 +1341,56 @@ static void nv_error_handler(struct ata_port *ap) nv_hardreset, ata_std_postreset); } +static void nv_adma_error_handler(struct ata_port *ap) +{ + struct nv_adma_port_priv *pp = ap->private_data; + if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) { + void __iomem *mmio = nv_adma_ctl_block(ap); + int i; + u16 tmp; + + u32 notifier = readl(mmio + NV_ADMA_NOTIFIER); + u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR); + u32 gen_ctl = readl(nv_adma_gen_block(ap) + NV_ADMA_GEN_CTL); + u32 status = readw(mmio + NV_ADMA_STAT); + + ata_port_printk(ap, KERN_ERR, "EH in ADMA mode, notifier 0x%X " + "notifier_error 0x%X gen_ctl 0x%X status 0x%X\n", + notifier, notifier_error, gen_ctl, status); + + for( i=0;i<NV_ADMA_MAX_CPBS;i++) { + struct nv_adma_cpb *cpb = &pp->cpb[i]; + if( cpb->ctl_flags || cpb->resp_flags ) + ata_port_printk(ap, KERN_ERR, + "CPB %d: ctl_flags 0x%x, resp_flags 0x%x\n", + i, cpb->ctl_flags, cpb->resp_flags); + } + + /* Push us back into port register mode for error handling. */ + nv_adma_register_mode(ap); + + ata_port_printk(ap, KERN_ERR, "Resetting port\n"); + + /* Mark all of the CPBs as invalid to prevent them from being executed */ + for( i=0;i<NV_ADMA_MAX_CPBS;i++) + pp->cpb[i].ctl_flags &= ~NV_CPB_CTL_CPB_VALID; + + /* clear CPB fetch count */ + writew(0, mmio + NV_ADMA_CPB_COUNT); + + /* Reset channel */ + tmp = readw(mmio + NV_ADMA_CTL); + writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL); + readl( mmio + NV_ADMA_CTL ); /* flush posted write */ + udelay(1); + writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL); + readl( mmio + NV_ADMA_CTL ); /* flush posted write */ + } + + ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, + nv_hardreset, ata_std_postreset); +} + static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version = 0; @@ -475,6 +1400,8 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) int rc; u32 bar; unsigned long base; + unsigned long type = ent->driver_data; + int mask_set = 0; // Make sure this is a SATA controller by counting the number of bars // (NVIDIA SATA controllers will always have six bars). Otherwise, @@ -483,7 +1410,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (pci_resource_start(pdev, bar) == 0) return -ENODEV; - if (!printed_version++) + if ( !printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); rc = pci_enable_device(pdev); @@ -496,16 +1423,26 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_disable; } - rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); - if (rc) - goto err_out_regions; - rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); - if (rc) - goto err_out_regions; + if(type >= CK804 && adma_enabled) { + dev_printk(KERN_NOTICE, &pdev->dev, "Using ADMA mode\n"); + type = ADMA; + if(!pci_set_dma_mask(pdev, DMA_64BIT_MASK) && + !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) + mask_set = 1; + } + + if(!mask_set) { + rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; + } rc = -ENOMEM; - ppi[0] = ppi[1] = &nv_port_info[ent->driver_data]; + ppi[0] = ppi[1] = &nv_port_info[type]; probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) goto err_out_regions; @@ -522,7 +1459,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET; /* enable SATA space for CK804 */ - if (ent->driver_data == CK804) { + if (type >= CK804) { u8 regval; pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, ®val); @@ -532,6 +1469,12 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); + if (type == ADMA) { + rc = nv_adma_host_init(probe_ent); + if (rc) + goto err_out_iounmap; + } + rc = ata_device_add(probe_ent); if (rc != NV_PORTS) goto err_out_iounmap; @@ -566,6 +1509,33 @@ static void nv_ck804_host_stop(struct ata_host *host) ata_pci_host_stop(host); } +static void nv_adma_host_stop(struct ata_host *host) +{ + struct pci_dev *pdev = to_pci_dev(host->dev); + int i; + u32 tmp32; + + for (i = 0; i < host->n_ports; i++) { + void __iomem *mmio = __nv_adma_ctl_block(host->mmio_base, i); + u16 tmp; + + /* disable interrupt */ + tmp = readw(mmio + NV_ADMA_CTL); + writew(tmp & ~NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL); + } + + /* disable ADMA on the ports */ + pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &tmp32); + tmp32 &= ~(NV_MCP_SATA_CFG_20_PORT0_EN | + NV_MCP_SATA_CFG_20_PORT0_PWB_EN | + NV_MCP_SATA_CFG_20_PORT1_EN | + NV_MCP_SATA_CFG_20_PORT1_PWB_EN); + + pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, tmp32); + + nv_ck804_host_stop(host); +} + static int __init nv_init(void) { return pci_register_driver(&nv_pci_driver); @@ -578,3 +1548,5 @@ static void __exit nv_exit(void) module_init(nv_init); module_exit(nv_exit); +module_param_named(adma, adma_enabled, bool, 0444); +MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: true)"); diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 72eda5160fad..a2778cf016bc 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -46,20 +46,19 @@ #include "sata_promise.h" #define DRV_NAME "sata_promise" -#define DRV_VERSION "1.04" +#define DRV_VERSION "1.05" enum { PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */ PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */ - PDC_TBG_MODE = 0x41, /* TBG mode */ PDC_FLASH_CTL = 0x44, /* Flash control register */ - PDC_PCI_CTL = 0x48, /* PCI control and status register */ PDC_GLOBAL_CTL = 0x48, /* Global control/status (per port) */ PDC_CTLSTAT = 0x60, /* IDE control and status (per port) */ PDC_SATA_PLUG_CSR = 0x6C, /* SATA Plug control/status reg */ PDC2_SATA_PLUG_CSR = 0x60, /* SATAII Plug control/status reg */ - PDC_SLEW_CTL = 0x470, /* slew rate control reg */ + PDC_TBG_MODE = 0x41C, /* TBG mode (not SATAII) */ + PDC_SLEW_CTL = 0x470, /* slew rate control reg (not SATAII) */ PDC_ERR_MASK = (1<<19) | (1<<20) | (1<<21) | (1<<22) | (1<<8) | (1<<9) | (1<<10), @@ -78,6 +77,9 @@ enum { PDC_COMMON_FLAGS = ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING, + + /* hp->flags bits */ + PDC_FLAG_GEN_II = (1 << 0), }; @@ -87,6 +89,7 @@ struct pdc_port_priv { }; struct pdc_host_priv { + unsigned long flags; int hotplug_offset; }; @@ -235,20 +238,20 @@ static const struct ata_port_info pdc_port_info[] = { static const struct pci_device_id pdc_ata_pci_tbl[] = { { PCI_VDEVICE(PROMISE, 0x3371), board_2037x }, - { PCI_VDEVICE(PROMISE, 0x3570), board_2037x }, - { PCI_VDEVICE(PROMISE, 0x3571), board_2037x }, { PCI_VDEVICE(PROMISE, 0x3373), board_2037x }, { PCI_VDEVICE(PROMISE, 0x3375), board_2037x }, { PCI_VDEVICE(PROMISE, 0x3376), board_2037x }, + { PCI_VDEVICE(PROMISE, 0x3570), board_2057x }, + { PCI_VDEVICE(PROMISE, 0x3571), board_2057x }, { PCI_VDEVICE(PROMISE, 0x3574), board_2057x }, + { PCI_VDEVICE(PROMISE, 0x3d73), board_2057x }, { PCI_VDEVICE(PROMISE, 0x3d75), board_2057x }, - { PCI_VDEVICE(PROMISE, 0x3d73), board_2037x }, { PCI_VDEVICE(PROMISE, 0x3318), board_20319 }, { PCI_VDEVICE(PROMISE, 0x3319), board_20319 }, { PCI_VDEVICE(PROMISE, 0x3515), board_20319 }, { PCI_VDEVICE(PROMISE, 0x3519), board_20319 }, - { PCI_VDEVICE(PROMISE, 0x3d17), board_20319 }, + { PCI_VDEVICE(PROMISE, 0x3d17), board_40518 }, { PCI_VDEVICE(PROMISE, 0x3d18), board_40518 }, { PCI_VDEVICE(PROMISE, 0x6629), board_20619 }, @@ -277,6 +280,7 @@ static struct pci_driver pdc_ata_pci_driver = { static int pdc_port_start(struct ata_port *ap) { struct device *dev = ap->host->dev; + struct pdc_host_priv *hp = ap->host->private_data; struct pdc_port_priv *pp; int rc; @@ -298,6 +302,16 @@ static int pdc_port_start(struct ata_port *ap) ap->private_data = pp; + /* fix up PHYMODE4 align timing */ + if ((hp->flags & PDC_FLAG_GEN_II) && sata_scr_valid(ap)) { + void __iomem *mmio = (void __iomem *) ap->ioaddr.scr_addr; + unsigned int tmp; + + tmp = readl(mmio + 0x014); + tmp = (tmp & ~3) | 1; /* set bits 1:0 = 0:1 */ + writel(tmp, mmio + 0x014); + } + return 0; err_out_kfree: @@ -640,9 +654,11 @@ static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe) * "TODO: figure out why we do this" */ - /* change FIFO_SHD to 8 dwords, enable BMR_BURST */ + /* enable BMR_BURST, maybe change FIFO_SHD to 8 dwords */ tmp = readl(mmio + PDC_FLASH_CTL); - tmp |= 0x12000; /* bit 16 (fifo 8 dw) and 13 (bmr burst?) */ + tmp |= 0x02000; /* bit 13 (enable bmr burst) */ + if (!(hp->flags & PDC_FLAG_GEN_II)) + tmp |= 0x10000; /* bit 16 (fifo threshold at 8 dw) */ writel(tmp, mmio + PDC_FLASH_CTL); /* clear plug/unplug flags for all ports */ @@ -653,6 +669,10 @@ static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe) tmp = readl(mmio + hotplug_offset); writel(tmp | 0xff0000, mmio + hotplug_offset); + /* don't initialise TBG or SLEW on 2nd generation chips */ + if (hp->flags & PDC_FLAG_GEN_II) + return; + /* reduce TBG clock to 133 Mhz. */ tmp = readl(mmio + PDC_TBG_MODE); tmp &= ~0x30000; /* clear bit 17, 16*/ @@ -746,6 +766,7 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e /* notice 4-port boards */ switch (board_idx) { case board_40518: + hp->flags |= PDC_FLAG_GEN_II; /* Override hotplug offset for SATAII150 */ hp->hotplug_offset = PDC2_SATA_PLUG_CSR; /* Fall through */ @@ -759,15 +780,14 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e probe_ent->port[3].scr_addr = base + 0x700; break; case board_2057x: + case board_20771: + hp->flags |= PDC_FLAG_GEN_II; /* Override hotplug offset for SATAII150 */ hp->hotplug_offset = PDC2_SATA_PLUG_CSR; /* Fall through */ case board_2037x: probe_ent->n_ports = 2; break; - case board_20771: - probe_ent->n_ports = 2; - break; case board_20619: probe_ent->n_ports = 4; diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index ca8d99312472..7808d0369d91 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -356,6 +356,7 @@ static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) static void sil_host_intr(struct ata_port *ap, u32 bmdma2) { + struct ata_eh_info *ehi = &ap->eh_info; struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); u8 status; @@ -428,6 +429,10 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2) /* kick HSM in the ass */ ata_hsm_move(ap, qc, status, 0); + if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA || + qc->tf.protocol == ATA_PROT_ATAPI_DMA)) + ata_ehi_push_desc(ehi, "BMDMA2 stat 0x%x", bmdma2); + return; err_hsm: @@ -534,6 +539,7 @@ static void sil_thaw(struct ata_port *ap) */ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev) { + int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO; unsigned int n, quirks = 0; unsigned char model_num[41]; @@ -549,16 +555,18 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev) if (slow_down || ((ap->flags & SIL_FLAG_MOD15WRITE) && (quirks & SIL_QUIRK_MOD15WRITE))) { - ata_dev_printk(dev, KERN_INFO, "applying Seagate errata fix " - "(mod15write workaround)\n"); + if (print_info) + ata_dev_printk(dev, KERN_INFO, "applying Seagate " + "errata fix (mod15write workaround)\n"); dev->max_sectors = 15; return; } /* limit to udma5 */ if (quirks & SIL_QUIRK_UDMA5MAX) { - ata_dev_printk(dev, KERN_INFO, - "applying Maxtor errata fix %s\n", model_num); + if (print_info) + ata_dev_printk(dev, KERN_INFO, "applying Maxtor " + "errata fix %s\n", model_num); dev->udma_mask &= ATA_UDMA5; return; } diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 169e200a6a71..5aa288d2fb86 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -100,10 +100,14 @@ enum { */ PORT_REGS_SIZE = 0x2000, - PORT_LRAM = 0x0000, /* 31 LRAM slots and PM regs */ + PORT_LRAM = 0x0000, /* 31 LRAM slots and PMP regs */ PORT_LRAM_SLOT_SZ = 0x0080, /* 32 bytes PRB + 2 SGE, ACT... */ - PORT_PM = 0x0f80, /* 8 bytes PM * 16 (128 bytes) */ + PORT_PMP = 0x0f80, /* 8 bytes PMP * 16 (128 bytes) */ + PORT_PMP_STATUS = 0x0000, /* port device status offset */ + PORT_PMP_QACTIVE = 0x0004, /* port device QActive offset */ + PORT_PMP_SIZE = 0x0008, /* 8 bytes per PMP */ + /* 32 bit regs */ PORT_CTRL_STAT = 0x1000, /* write: ctrl-set, read: stat */ PORT_CTRL_CLR = 0x1004, /* write: ctrl-clear */ @@ -126,6 +130,7 @@ enum { PORT_PHY_CFG = 0x1050, PORT_SLOT_STAT = 0x1800, PORT_CMD_ACTIVATE = 0x1c00, /* 64 bit cmd activate * 31 (248 bytes) */ + PORT_CONTEXT = 0x1e04, PORT_EXEC_DIAG = 0x1e00, /* 32bit exec diag * 16 (64 bytes, 0-10 used on 3124) */ PORT_PSD_DIAG = 0x1e40, /* 32bit psd diag * 16 (64 bytes, 0-8 used on 3124) */ PORT_SCONTROL = 0x1f00, @@ -139,9 +144,9 @@ enum { PORT_CS_INIT = (1 << 2), /* port initialize */ PORT_CS_IRQ_WOC = (1 << 3), /* interrupt write one to clear */ PORT_CS_CDB16 = (1 << 5), /* 0=12b cdb, 1=16b cdb */ - PORT_CS_RESUME = (1 << 6), /* port resume */ + PORT_CS_PMP_RESUME = (1 << 6), /* PMP resume */ PORT_CS_32BIT_ACTV = (1 << 10), /* 32-bit activation */ - PORT_CS_PM_EN = (1 << 13), /* port multiplier enable */ + PORT_CS_PMP_EN = (1 << 13), /* port multiplier enable */ PORT_CS_RDY = (1 << 31), /* port ready to accept commands */ /* PORT_IRQ_STAT/ENABLE_SET/CLR */ @@ -562,7 +567,7 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class) /* do SRST */ prb->ctrl = cpu_to_le16(PRB_CTRL_SRST); - prb->fis[1] = 0; /* no PM yet */ + prb->fis[1] = 0; /* no PMP yet */ writel((u32)paddr, port + PORT_CMD_ACTIVATE); writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4); @@ -1050,7 +1055,8 @@ static void sil24_init_controller(struct pci_dev *pdev, int n_ports, writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR); /* Clear port multiplier enable and resume bits */ - writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR); + writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, + port + PORT_CTRL_CLR); } /* Turn on interrupts */ diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index 9d1235ba06b1..9c25a1e91730 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c @@ -173,7 +173,7 @@ static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg) if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED)) pci_read_config_dword(pdev, cfg_addr+0x10, &val2); - return val|val2; + return (val|val2) & 0xfffffffb; /* avoid problems with powerdowned ports */ } static void sis_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val) @@ -212,7 +212,7 @@ static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg) if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED)) val2 = inl(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10); - return val | val2; + return (val | val2) & 0xfffffffb; } static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) @@ -239,7 +239,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) static int printed_version; struct ata_probe_ent *probe_ent = NULL; int rc; - u32 genctl; + u32 genctl, val; struct ata_port_info pi = sis_port_info, *ppi[2] = { &pi, &pi }; int pci_dev_busy = 0; u8 pmr; @@ -285,17 +285,24 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (ent->device != 0x182) { if ((pmr & SIS_PMR_COMBINED) == 0) { dev_printk(KERN_INFO, &pdev->dev, - "Detected SiS 180/181 chipset in SATA mode\n"); + "Detected SiS 180/181/964 chipset in SATA mode\n"); port2_start = 64; } else { dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 180/181 chipset in combined mode\n"); port2_start=0; + pi.flags |= ATA_FLAG_SLAVE_POSS; } } else { - dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 182 chipset\n"); + pci_read_config_dword ( pdev, 0x6C, &val); + if (val & (1L << 31)) { + dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 182/965 chipset\n"); + pi.flags |= ATA_FLAG_SLAVE_POSS; + } + else + dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 182/965L chipset\n"); port2_start = 0x20; } diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 4bef76a2f3f2..1f745f12f94e 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -5,6 +5,7 @@ #include <linux/sysdev.h> #include <linux/module.h> #include <linux/init.h> +#include <linux/sched.h> #include <linux/cpu.h> #include <linux/topology.h> #include <linux/device.h> diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index ad8b537ad47b..24f922f12783 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -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" diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 777cad045094..b1fcdab90947 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -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 diff --git a/drivers/char/ftape/Kconfig b/drivers/char/ftape/Kconfig deleted file mode 100644 index 0d65189a7ae8..000000000000 --- a/drivers/char/ftape/Kconfig +++ /dev/null @@ -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. - diff --git a/drivers/char/ftape/Makefile b/drivers/char/ftape/Makefile deleted file mode 100644 index 0e67d2f8b7ec..000000000000 --- a/drivers/char/ftape/Makefile +++ /dev/null @@ -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/ diff --git a/drivers/char/ftape/README.PCI b/drivers/char/ftape/README.PCI deleted file mode 100644 index 18de159d36e0..000000000000 --- a/drivers/char/ftape/README.PCI +++ /dev/null @@ -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 diff --git a/drivers/char/ftape/RELEASE-NOTES b/drivers/char/ftape/RELEASE-NOTES deleted file mode 100644 index 03799dbc05a4..000000000000 --- a/drivers/char/ftape/RELEASE-NOTES +++ /dev/null @@ -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 diff --git a/drivers/char/ftape/compressor/Makefile b/drivers/char/ftape/compressor/Makefile deleted file mode 100644 index 1fbd6c4019db..000000000000 --- a/drivers/char/ftape/compressor/Makefile +++ /dev/null @@ -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 diff --git a/drivers/char/ftape/compressor/lzrw3.c b/drivers/char/ftape/compressor/lzrw3.c deleted file mode 100644 index a032a0ee2a99..000000000000 --- a/drivers/char/ftape/compressor/lzrw3.c +++ /dev/null @@ -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 */ -/******************************************************************************/ diff --git a/drivers/char/ftape/compressor/lzrw3.h b/drivers/char/ftape/compressor/lzrw3.h deleted file mode 100644 index 533feba47526..000000000000 --- a/drivers/char/ftape/compressor/lzrw3.h +++ /dev/null @@ -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 diff --git a/drivers/char/ftape/compressor/zftape-compress.c b/drivers/char/ftape/compressor/zftape-compress.c deleted file mode 100644 index 65ffc0be3df9..000000000000 --- a/drivers/char/ftape/compressor/zftape-compress.c +++ /dev/null @@ -1,1203 +0,0 @@ -/* - * 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. - - * - * This file implements a "generic" interface between the * - * zftape-driver and a compression-algorithm. The * - * compression-algorithm currently used is a LZ77. I use the * - * implementation lzrw3 by Ross N. Williams (Renaissance * - * Software). The compression program itself is in the file - * lzrw3.c * and lzrw3.h. To adopt another compression algorithm - * the functions * zft_compress() and zft_uncompress() must be - * changed * appropriately. See below. - */ - -#include <linux/errno.h> -#include <linux/mm.h> -#include <linux/module.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 "../compressor/zftape-compress.h" -#include "../zftape/zftape-vtbl.h" -#include "../compressor/lzrw3.h" - -/* - * global variables - */ - -/* I handle the allocation of this buffer as a special case, because - * it's size varies depending on the tape length inserted. - */ - -/* local variables - */ -static void *zftc_wrk_mem = NULL; -static __u8 *zftc_buf = NULL; -static void *zftc_scratch_buf = NULL; - -/* compression statistics - */ -static unsigned int zftc_wr_uncompressed = 0; -static unsigned int zftc_wr_compressed = 0; -static unsigned int zftc_rd_uncompressed = 0; -static unsigned int zftc_rd_compressed = 0; - -/* forward */ -static int zftc_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); -static int zftc_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); -static int zftc_seek(unsigned int new_block_pos, - zft_position *pos, const zft_volinfo *volume, - __u8 *buffer); -static void zftc_lock (void); -static void zftc_reset (void); -static void zftc_cleanup(void); -static void zftc_stats (void); - -/* compressed segment. This conforms to QIC-80-MC, Revision K. - * - * Rev. K applies to tapes with `fixed length format' which is - * indicated by format code 2,3 and 5. See below for format code 4 and 6 - * - * 2 bytes: offset of compression segment structure - * 29k > offset >= 29k-18: data from previous segment ens in this - * segment and no compressed block starts - * in this segment - * offset == 0: data from previous segment occupies entire - * segment and continues in next segment - * n bytes: remainder from previous segment - * - * Rev. K: - * 4 bytes: 4 bytes: files set byte offset - * Post Rev. K and QIC-3020/3020: - * 8 bytes: 8 bytes: files set byte offset - * 2 bytes: byte count N (amount of data following) - * bit 15 is set if data is compressed, bit 15 is not - * set if data is uncompressed - * N bytes: data (as much as specified in the byte count) - * 2 bytes: byte count N_1 of next cluster - * N_1 bytes: data of next cluset - * 2 bytes: byte count N_2 of next cluster - * N_2 bytes: ... - * - * Note that the `N' byte count accounts only for the bytes that in the - * current segment if the cluster spans to the next segment. - */ - -typedef struct -{ - int cmpr_pos; /* actual position in compression buffer */ - int cmpr_sz; /* what is left in the compression buffer - * when copying the compressed data to the - * deblock buffer - */ - unsigned int first_block; /* location of header information in - * this segment - */ - unsigned int count; /* amount of data of current block - * contained in current segment - */ - unsigned int offset; /* offset in current segment */ - unsigned int spans:1; /* might continue in next segment */ - unsigned int uncmpr; /* 0x8000 if this block contains - * uncompressed data - */ - __s64 foffs; /* file set byte offset, same as in - * compression map segment - */ -} cmpr_info; - -static cmpr_info cseg; /* static data. Must be kept uptodate and shared by - * read, write and seek functions - */ - -#define DUMP_CMPR_INFO(level, msg, info) \ - TRACE(level, msg "\n" \ - KERN_INFO "cmpr_pos : %d\n" \ - KERN_INFO "cmpr_sz : %d\n" \ - KERN_INFO "first_block: %d\n" \ - KERN_INFO "count : %d\n" \ - KERN_INFO "offset : %d\n" \ - KERN_INFO "spans : %d\n" \ - KERN_INFO "uncmpr : 0x%04x\n" \ - KERN_INFO "foffs : " LL_X, \ - (info)->cmpr_pos, (info)->cmpr_sz, (info)->first_block, \ - (info)->count, (info)->offset, (info)->spans == 1, \ - (info)->uncmpr, LL((info)->foffs)) - -/* dispatch compression segment info, return error code - * - * afterwards, cseg->offset points to start of data of the NEXT - * compressed block, and cseg->count contains the amount of data - * left in the actual compressed block. cseg->spans is set to 1 if - * the block is continued in the following segment. Otherwise it is - * set to 0. - */ -static int get_cseg (cmpr_info *cinfo, const __u8 *buff, - const unsigned int seg_sz, - const zft_volinfo *volume) -{ - TRACE_FUN(ft_t_flow); - - cinfo->first_block = GET2(buff, 0); - if (cinfo->first_block == 0) { /* data spans to next segment */ - cinfo->count = seg_sz - sizeof(__u16); - cinfo->offset = seg_sz; - cinfo->spans = 1; - } else { /* cluster definetely ends in this segment */ - if (cinfo->first_block > seg_sz) { - /* data corrupted */ - TRACE_ABORT(-EIO, ft_t_err, "corrupted data:\n" - KERN_INFO "segment size: %d\n" - KERN_INFO "first block : %d", - seg_sz, cinfo->first_block); - } - cinfo->count = cinfo->first_block - sizeof(__u16); - cinfo->offset = cinfo->first_block; - cinfo->spans = 0; - } - /* now get the offset the first block should have in the - * uncompressed data stream. - * - * For this magic `18' refer to CRF-3 standard or QIC-80MC, - * Rev. K. - */ - if ((seg_sz - cinfo->offset) > 18) { - if (volume->qic113) { /* > revision K */ - TRACE(ft_t_data_flow, "New QIC-113 compliance"); - cinfo->foffs = GET8(buff, cinfo->offset); - cinfo->offset += sizeof(__s64); - } else { - TRACE(/* ft_t_data_flow */ ft_t_noise, "pre QIC-113 version"); - cinfo->foffs = (__s64)GET4(buff, cinfo->offset); - cinfo->offset += sizeof(__u32); - } - } - if (cinfo->foffs > volume->size) { - TRACE_ABORT(-EIO, ft_t_err, "Inconsistency:\n" - KERN_INFO "offset in current volume: %d\n" - KERN_INFO "size of current volume : %d", - (int)(cinfo->foffs>>10), (int)(volume->size>>10)); - } - if (cinfo->cmpr_pos + cinfo->count > volume->blk_sz) { - TRACE_ABORT(-EIO, ft_t_err, "Inconsistency:\n" - KERN_INFO "block size : %d\n" - KERN_INFO "data record: %d", - volume->blk_sz, cinfo->cmpr_pos + cinfo->count); - } - DUMP_CMPR_INFO(ft_t_noise /* ft_t_any */, "", cinfo); - TRACE_EXIT 0; -} - -/* This one is called, when a new cluster starts in same segment. - * - * Note: if this is the first cluster in the current segment, we must - * not check whether there are more than 18 bytes available because - * this have already been done in get_cseg() and there may be less - * than 18 bytes available due to header information. - * - */ -static void get_next_cluster(cmpr_info *cluster, const __u8 *buff, - const int seg_sz, const int finish) -{ - TRACE_FUN(ft_t_flow); - - if (seg_sz - cluster->offset > 18 || cluster->foffs != 0) { - cluster->count = GET2(buff, cluster->offset); - cluster->uncmpr = cluster->count & 0x8000; - cluster->count -= cluster->uncmpr; - cluster->offset += sizeof(__u16); - cluster->foffs = 0; - if ((cluster->offset + cluster->count) < seg_sz) { - cluster->spans = 0; - } else if (cluster->offset + cluster->count == seg_sz) { - cluster->spans = !finish; - } else { - /* either an error or a volume written by an - * old version. If this is a data error, then we'll - * catch it later. - */ - TRACE(ft_t_data_flow, "Either error or old volume"); - cluster->spans = 1; - cluster->count = seg_sz - cluster->offset; - } - } else { - cluster->count = 0; - cluster->spans = 0; - cluster->foffs = 0; - } - DUMP_CMPR_INFO(ft_t_noise /* ft_t_any */ , "", cluster); - TRACE_EXIT; -} - -static void zftc_lock(void) -{ -} - -/* this function is needed for zftape_reset_position in zftape-io.c - */ -static void zftc_reset(void) -{ - TRACE_FUN(ft_t_flow); - - memset((void *)&cseg, '\0', sizeof(cseg)); - zftc_stats(); - TRACE_EXIT; -} - -static int cmpr_mem_initialized = 0; -static unsigned int alloc_blksz = 0; - -static int zft_allocate_cmpr_mem(unsigned int blksz) -{ - TRACE_FUN(ft_t_flow); - - if (cmpr_mem_initialized && blksz == alloc_blksz) { - TRACE_EXIT 0; - } - TRACE_CATCH(zft_vmalloc_once(&zftc_wrk_mem, CMPR_WRK_MEM_SIZE), - zftc_cleanup()); - TRACE_CATCH(zft_vmalloc_always(&zftc_buf, blksz + CMPR_OVERRUN), - zftc_cleanup()); - alloc_blksz = blksz; - TRACE_CATCH(zft_vmalloc_always(&zftc_scratch_buf, blksz+CMPR_OVERRUN), - zftc_cleanup()); - cmpr_mem_initialized = 1; - TRACE_EXIT 0; -} - -static void zftc_cleanup(void) -{ - TRACE_FUN(ft_t_flow); - - zft_vfree(&zftc_wrk_mem, CMPR_WRK_MEM_SIZE); - zft_vfree(&zftc_buf, alloc_blksz + CMPR_OVERRUN); - zft_vfree(&zftc_scratch_buf, alloc_blksz + CMPR_OVERRUN); - cmpr_mem_initialized = alloc_blksz = 0; - TRACE_EXIT; -} - -/***************************************************************************** - * * - * The following two functions "ftape_compress()" and * - * "ftape_uncompress()" are the interface to the actual compression * - * algorithm (i.e. they are calling the "compress()" function from * - * the lzrw3 package for now). These routines could quite easily be * - * changed to adopt another compression algorithm instead of lzrw3, * - * which currently is used. * - * * - *****************************************************************************/ - -/* called by zft_compress_write() to perform the compression. Must - * return the size of the compressed data. - * - * NOTE: The size of the compressed data should not exceed the size of - * the uncompressed data. Most compression algorithms have means - * to store data unchanged if the "compressed" data amount would - * exceed the original one. Mostly this is done by storing some - * flag-bytes in front of the compressed data to indicate if it - * is compressed or not. Thus the worst compression result - * length is the original length plus those flag-bytes. - * - * We don't want that, as the QIC-80 standard provides a means - * of marking uncompressed blocks by simply setting bit 15 of - * the compressed block's length. Thus a compessed block can - * have at most a length of 2^15-1 bytes. The QIC-80 standard - * restricts the block-length even further, allowing only 29k - - * 6 bytes. - * - * Currently, the maximum blocksize used by zftape is 28k. - * - * In short: don't exceed the length of the input-package, set - * bit 15 of the compressed size to 1 if you have copied data - * instead of compressing it. - */ -static int zft_compress(__u8 *in_buffer, unsigned int in_sz, __u8 *out_buffer) -{ - __s32 compressed_sz; - TRACE_FUN(ft_t_flow); - - - lzrw3_compress(COMPRESS_ACTION_COMPRESS, zftc_wrk_mem, - in_buffer, in_sz, out_buffer, &compressed_sz); - if (TRACE_LEVEL >= ft_t_info) { - /* the compiler will optimize this away when - * compiled with NO_TRACE_AT_ALL option - */ - TRACE(ft_t_data_flow, "\n" - KERN_INFO "before compression: %d bytes\n" - KERN_INFO "after compresison : %d bytes", - in_sz, - (int)(compressed_sz < 0 - ? -compressed_sz : compressed_sz)); - /* for statistical purposes - */ - zftc_wr_compressed += (compressed_sz < 0 - ? -compressed_sz : compressed_sz); - zftc_wr_uncompressed += in_sz; - } - TRACE_EXIT (int)compressed_sz; -} - -/* called by zft_compress_read() to decompress the data. Must - * return the size of the decompressed data for sanity checks - * (compared with zft_blk_sz) - * - * NOTE: Read the note for zft_compress() above! If bit 15 of the - * parameter in_sz is set, then the data in in_buffer isn't - * compressed, which must be handled by the un-compression - * algorithm. (I changed lzrw3 to handle this.) - * - * The parameter max_out_sz is needed to prevent buffer overruns when - * uncompressing corrupt data. - */ -static unsigned int zft_uncompress(__u8 *in_buffer, - int in_sz, - __u8 *out_buffer, - unsigned int max_out_sz) -{ - TRACE_FUN(ft_t_flow); - - lzrw3_compress(COMPRESS_ACTION_DECOMPRESS, zftc_wrk_mem, - in_buffer, (__s32)in_sz, - out_buffer, (__u32 *)&max_out_sz); - - if (TRACE_LEVEL >= ft_t_info) { - TRACE(ft_t_data_flow, "\n" - KERN_INFO "before decompression: %d bytes\n" - KERN_INFO "after decompression : %d bytes", - in_sz < 0 ? -in_sz : in_sz,(int)max_out_sz); - /* for statistical purposes - */ - zftc_rd_compressed += in_sz < 0 ? -in_sz : in_sz; - zftc_rd_uncompressed += max_out_sz; - } - TRACE_EXIT (unsigned int)max_out_sz; -} - -/* print some statistics about the efficiency of the compression to - * the kernel log - */ -static void zftc_stats(void) -{ - TRACE_FUN(ft_t_flow); - - if (TRACE_LEVEL < ft_t_info) { - TRACE_EXIT; - } - if (zftc_wr_uncompressed != 0) { - if (zftc_wr_compressed > (1<<14)) { - TRACE(ft_t_info, "compression statistics (writing):\n" - KERN_INFO " compr./uncmpr. : %3d %%", - (((zftc_wr_compressed>>10) * 100) - / (zftc_wr_uncompressed>>10))); - } else { - TRACE(ft_t_info, "compression statistics (writing):\n" - KERN_INFO " compr./uncmpr. : %3d %%", - ((zftc_wr_compressed * 100) - / zftc_wr_uncompressed)); - } - } - if (zftc_rd_uncompressed != 0) { - if (zftc_rd_compressed > (1<<14)) { - TRACE(ft_t_info, "compression statistics (reading):\n" - KERN_INFO " compr./uncmpr. : %3d %%", - (((zftc_rd_compressed>>10) * 100) - / (zftc_rd_uncompressed>>10))); - } else { - TRACE(ft_t_info, "compression statistics (reading):\n" - KERN_INFO " compr./uncmpr. : %3d %%", - ((zftc_rd_compressed * 100) - / zftc_rd_uncompressed)); - } - } - /* only print it once: */ - zftc_wr_uncompressed = - zftc_wr_compressed = - zftc_rd_uncompressed = - zftc_rd_compressed = 0; - TRACE_EXIT; -} - -/* start new compressed block - */ -static int start_new_cseg(cmpr_info *cluster, - char *dst_buf, - const zft_position *pos, - const unsigned int blk_sz, - const char *src_buf, - const int this_segs_sz, - const int qic113) -{ - int size_left; - int cp_cnt; - int buf_pos; - TRACE_FUN(ft_t_flow); - - size_left = this_segs_sz - sizeof(__u16) - cluster->cmpr_sz; - TRACE(ft_t_data_flow,"\n" - KERN_INFO "segment size : %d\n" - KERN_INFO "compressed_sz: %d\n" - KERN_INFO "size_left : %d", - this_segs_sz, cluster->cmpr_sz, size_left); - if (size_left > 18) { /* start a new cluseter */ - cp_cnt = cluster->cmpr_sz; - cluster->cmpr_sz = 0; - buf_pos = cp_cnt + sizeof(__u16); - PUT2(dst_buf, 0, buf_pos); - - if (qic113) { - __s64 foffs = pos->volume_pos; - if (cp_cnt) foffs += (__s64)blk_sz; - - TRACE(ft_t_data_flow, "new style QIC-113 header"); - PUT8(dst_buf, buf_pos, foffs); - buf_pos += sizeof(__s64); - } else { - __u32 foffs = (__u32)pos->volume_pos; - if (cp_cnt) foffs += (__u32)blk_sz; - - TRACE(ft_t_data_flow, "old style QIC-80MC header"); - PUT4(dst_buf, buf_pos, foffs); - buf_pos += sizeof(__u32); - } - } else if (size_left >= 0) { - cp_cnt = cluster->cmpr_sz; - cluster->cmpr_sz = 0; - buf_pos = cp_cnt + sizeof(__u16); - PUT2(dst_buf, 0, buf_pos); - /* zero unused part of segment. */ - memset(dst_buf + buf_pos, '\0', size_left); - buf_pos = this_segs_sz; - } else { /* need entire segment and more space */ - PUT2(dst_buf, 0, 0); - cp_cnt = this_segs_sz - sizeof(__u16); - cluster->cmpr_sz -= cp_cnt; - buf_pos = this_segs_sz; - } - memcpy(dst_buf + sizeof(__u16), src_buf + cluster->cmpr_pos, cp_cnt); - cluster->cmpr_pos += cp_cnt; - TRACE_EXIT buf_pos; -} - -/* return-value: the number of bytes removed from the user-buffer - * `src_buf' or error code - * - * int *write_cnt : how much actually has been moved to the - * dst_buf. Need not be initialized when - * function returns with an error code - * (negativ return value) - * __u8 *dst_buf : kernel space buffer where the has to be - * copied to. The contents of this buffers - * goes to a specific segment. - * const int seg_sz : the size of the segment dst_buf will be - * copied to. - * const zft_position *pos : struct containing the coordinates in - * the current volume (byte position, - * segment id of current segment etc) - * const zft_volinfo *volume: information about the current volume, - * size etc. - * const __u8 *src_buf : user space buffer that contains the - * data the user wants to be written to - * tape. - * const int req_len : the amount of data the user wants to be - * written to tape. - */ -static int zftc_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 req_len_left = req_len; - int result; - int len_left; - int buf_pos_write = pos->seg_byte_pos; - TRACE_FUN(ft_t_flow); - - /* Note: we do not unlock the module because - * there are some values cached in that `cseg' variable. We - * don't don't want to use this information when being - * unloaded by kerneld even when the tape is full or when we - * cannot allocate enough memory. - */ - if (pos->tape_pos > (volume->size-volume->blk_sz-ZFT_CMPR_OVERHEAD)) { - TRACE_EXIT -ENOSPC; - } - if (zft_allocate_cmpr_mem(volume->blk_sz) < 0) { - /* should we unlock the module? But it shouldn't - * be locked anyway ... - */ - TRACE_EXIT -ENOMEM; - } - if (buf_pos_write == 0) { /* fill a new segment */ - *write_cnt = buf_pos_write = start_new_cseg(&cseg, - dst_buf, - pos, - volume->blk_sz, - zftc_buf, - seg_sz, - volume->qic113); - if (cseg.cmpr_sz == 0 && cseg.cmpr_pos != 0) { - req_len_left -= result = volume->blk_sz; - cseg.cmpr_pos = 0; - } else { - result = 0; - } - } else { - *write_cnt = result = 0; - } - - len_left = seg_sz - buf_pos_write; - while ((req_len_left > 0) && (len_left > 18)) { - /* now we have some size left for a new compressed - * block. We know, that the compression buffer is - * empty (else there wouldn't be any space left). - */ - if (copy_from_user(zftc_scratch_buf, src_buf + result, - volume->blk_sz) != 0) { - TRACE_EXIT -EFAULT; - } - req_len_left -= volume->blk_sz; - cseg.cmpr_sz = zft_compress(zftc_scratch_buf, volume->blk_sz, - zftc_buf); - if (cseg.cmpr_sz < 0) { - cseg.uncmpr = 0x8000; - cseg.cmpr_sz = -cseg.cmpr_sz; - } else { - cseg.uncmpr = 0; - } - /* increment "result" iff we copied the entire - * compressed block to the zft_deblock_buf - */ - len_left -= sizeof(__u16); - if (len_left >= cseg.cmpr_sz) { - len_left -= cseg.count = cseg.cmpr_sz; - cseg.cmpr_pos = cseg.cmpr_sz = 0; - result += volume->blk_sz; - } else { - cseg.cmpr_sz -= - cseg.cmpr_pos = - cseg.count = len_left; - len_left = 0; - } - PUT2(dst_buf, buf_pos_write, cseg.uncmpr | cseg.count); - buf_pos_write += sizeof(__u16); - memcpy(dst_buf + buf_pos_write, zftc_buf, cseg.count); - buf_pos_write += cseg.count; - *write_cnt += cseg.count + sizeof(__u16); - FT_SIGNAL_EXIT(_DONT_BLOCK); - } - /* erase the remainder of the segment if less than 18 bytes - * left (18 bytes is due to the QIC-80 standard) - */ - if (len_left <= 18) { - memset(dst_buf + buf_pos_write, '\0', len_left); - (*write_cnt) += len_left; - } - TRACE(ft_t_data_flow, "returning %d", result); - TRACE_EXIT result; -} - -/* 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. - * - * 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 from _ftape_read() - * int buf_len_read : copy of buf_len_rd from _ftape_read() - * char *zft_deblock_buf: zft_deblock_buf - * unsigned short blk_sz: the block size valid for this volume, may differ - * from zft_blk_sz. - * int finish: if != 0 means that this is the last segment belonging - * to this volume - * returns the amount of data actually copied to the user-buffer - * - * to_do MUST NOT SHRINK except to indicate an EOF. In this case *to_do has to - * be set to 0 - */ -static int zftc_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) -{ - int uncompressed_sz; - int result = 0; - int remaining = to_do; - TRACE_FUN(ft_t_flow); - - TRACE_CATCH(zft_allocate_cmpr_mem(volume->blk_sz),); - if (pos->seg_byte_pos == 0) { - /* new segment just read - */ - TRACE_CATCH(get_cseg(&cseg, src_buf, seg_sz, volume), - *read_cnt = 0); - memcpy(zftc_buf + cseg.cmpr_pos, src_buf + sizeof(__u16), - cseg.count); - cseg.cmpr_pos += cseg.count; - *read_cnt = cseg.offset; - DUMP_CMPR_INFO(ft_t_noise /* ft_t_any */, "", &cseg); - } else { - *read_cnt = 0; - } - /* loop and uncompress until user buffer full or - * deblock-buffer empty - */ - TRACE(ft_t_data_flow, "compressed_sz: %d, compos : %d, *read_cnt: %d", - cseg.cmpr_sz, cseg.cmpr_pos, *read_cnt); - while ((cseg.spans == 0) && (remaining > 0)) { - if (cseg.cmpr_pos != 0) { /* cmpr buf is not empty */ - uncompressed_sz = - zft_uncompress(zftc_buf, - cseg.uncmpr == 0x8000 ? - -cseg.cmpr_pos : cseg.cmpr_pos, - zftc_scratch_buf, - volume->blk_sz); - if (uncompressed_sz != volume->blk_sz) { - *read_cnt = 0; - TRACE_ABORT(-EIO, ft_t_warn, - "Uncompressed blk (%d) != blk size (%d)", - uncompressed_sz, volume->blk_sz); - } - if (copy_to_user(dst_buf + result, - zftc_scratch_buf, - uncompressed_sz) != 0 ) { - TRACE_EXIT -EFAULT; - } - remaining -= uncompressed_sz; - result += uncompressed_sz; - cseg.cmpr_pos = 0; - } - if (remaining > 0) { - get_next_cluster(&cseg, src_buf, seg_sz, - volume->end_seg == pos->seg_pos); - if (cseg.count != 0) { - memcpy(zftc_buf, src_buf + cseg.offset, - cseg.count); - cseg.cmpr_pos = cseg.count; - cseg.offset += cseg.count; - *read_cnt += cseg.count + sizeof(__u16); - } else { - remaining = 0; - } - } - TRACE(ft_t_data_flow, "\n" - KERN_INFO "compressed_sz: %d\n" - KERN_INFO "compos : %d\n" - KERN_INFO "*read_cnt : %d", - cseg.cmpr_sz, cseg.cmpr_pos, *read_cnt); - } - if (seg_sz - cseg.offset <= 18) { - *read_cnt += seg_sz - cseg.offset; - TRACE(ft_t_data_flow, "expanding read cnt to: %d", *read_cnt); - } - TRACE(ft_t_data_flow, "\n" - KERN_INFO "segment size : %d\n" - KERN_INFO "read count : %d\n" - KERN_INFO "buf_pos_read : %d\n" - KERN_INFO "remaining : %d", - seg_sz, *read_cnt, pos->seg_byte_pos, - seg_sz - *read_cnt - pos->seg_byte_pos); - TRACE(ft_t_data_flow, "returning: %d", result); - TRACE_EXIT result; -} - -/* seeks to the new data-position. Reads sometimes a segment. - * - * start_seg and end_seg give the boundaries of the current volume - * blk_sz is the blk_sz of the current volume as stored in the - * volume label - * - * We don't allow blocksizes less than 1024 bytes, therefore we don't need - * a 64 bit argument for new_block_pos. - */ - -static int seek_in_segment(const unsigned int to_do, cmpr_info *c_info, - const char *src_buf, const int seg_sz, - const int seg_pos, const zft_volinfo *volume); -static int slow_seek_forward_until_error(const unsigned int distance, - cmpr_info *c_info, zft_position *pos, - const zft_volinfo *volume, __u8 *buf); -static int search_valid_segment(unsigned int segment, - const unsigned int end_seg, - const unsigned int max_foffs, - zft_position *pos, cmpr_info *c_info, - const zft_volinfo *volume, __u8 *buf); -static int slow_seek_forward(unsigned int dest, cmpr_info *c_info, - zft_position *pos, const zft_volinfo *volume, - __u8 *buf); -static int compute_seg_pos(unsigned int dest, zft_position *pos, - const zft_volinfo *volume); - -#define ZFT_SLOW_SEEK_THRESHOLD 10 /* segments */ -#define ZFT_FAST_SEEK_MAX_TRIALS 10 /* times */ -#define ZFT_FAST_SEEK_BACKUP 10 /* segments */ - -static int zftc_seek(unsigned int new_block_pos, - zft_position *pos, const zft_volinfo *volume, __u8 *buf) -{ - unsigned int dest; - int limit; - int distance; - int result = 0; - int seg_dist; - int new_seg; - int old_seg = 0; - int fast_seek_trials = 0; - TRACE_FUN(ft_t_flow); - - if (new_block_pos == 0) { - pos->seg_pos = volume->start_seg; - pos->seg_byte_pos = 0; - pos->volume_pos = 0; - zftc_reset(); - TRACE_EXIT 0; - } - dest = new_block_pos * (volume->blk_sz >> 10); - distance = dest - (pos->volume_pos >> 10); - while (distance != 0) { - seg_dist = compute_seg_pos(dest, pos, volume); - TRACE(ft_t_noise, "\n" - KERN_INFO "seg_dist: %d\n" - KERN_INFO "distance: %d\n" - KERN_INFO "dest : %d\n" - KERN_INFO "vpos : %d\n" - KERN_INFO "seg_pos : %d\n" - KERN_INFO "trials : %d", - seg_dist, distance, dest, - (unsigned int)(pos->volume_pos>>10), pos->seg_pos, - fast_seek_trials); - if (distance > 0) { - if (seg_dist < 0) { - TRACE(ft_t_bug, "BUG: distance %d > 0, " - "segment difference %d < 0", - distance, seg_dist); - result = -EIO; - break; - } - new_seg = pos->seg_pos + seg_dist; - if (new_seg > volume->end_seg) { - new_seg = volume->end_seg; - } - if (old_seg == new_seg || /* loop */ - seg_dist <= ZFT_SLOW_SEEK_THRESHOLD || - fast_seek_trials >= ZFT_FAST_SEEK_MAX_TRIALS) { - TRACE(ft_t_noise, "starting slow seek:\n" - KERN_INFO "fast seek failed too often: %s\n" - KERN_INFO "near target position : %s\n" - KERN_INFO "looping between two segs : %s", - (fast_seek_trials >= - ZFT_FAST_SEEK_MAX_TRIALS) - ? "yes" : "no", - (seg_dist <= ZFT_SLOW_SEEK_THRESHOLD) - ? "yes" : "no", - (old_seg == new_seg) - ? "yes" : "no"); - result = slow_seek_forward(dest, &cseg, - pos, volume, buf); - break; - } - old_seg = new_seg; - limit = volume->end_seg; - fast_seek_trials ++; - for (;;) { - result = search_valid_segment(new_seg, limit, - volume->size, - pos, &cseg, - volume, buf); - if (result == 0 || result == -EINTR) { - break; - } - if (new_seg == volume->start_seg) { - result = -EIO; /* set errror - * condition - */ - break; - } - limit = new_seg; - new_seg -= ZFT_FAST_SEEK_BACKUP; - if (new_seg < volume->start_seg) { - new_seg = volume->start_seg; - } - } - if (result < 0) { - TRACE(ft_t_warn, - "Couldn't find a readable segment"); - break; - } - } else /* if (distance < 0) */ { - if (seg_dist > 0) { - TRACE(ft_t_bug, "BUG: distance %d < 0, " - "segment difference %d >0", - distance, seg_dist); - result = -EIO; - break; - } - new_seg = pos->seg_pos + seg_dist; - if (fast_seek_trials > 0 && seg_dist == 0) { - /* this avoids sticking to the same - * segment all the time. On the other hand: - * if we got here for the first time, and the - * deblock_buffer still contains a valid - * segment, then there is no need to skip to - * the previous segment if the desired position - * is inside this segment. - */ - new_seg --; - } - if (new_seg < volume->start_seg) { - new_seg = volume->start_seg; - } - limit = pos->seg_pos; - fast_seek_trials ++; - for (;;) { - result = search_valid_segment(new_seg, limit, - pos->volume_pos, - pos, &cseg, - volume, buf); - if (result == 0 || result == -EINTR) { - break; - } - if (new_seg == volume->start_seg) { - result = -EIO; /* set errror - * condition - */ - break; - } - limit = new_seg; - new_seg -= ZFT_FAST_SEEK_BACKUP; - if (new_seg < volume->start_seg) { - new_seg = volume->start_seg; - } - } - if (result < 0) { - TRACE(ft_t_warn, - "Couldn't find a readable segment"); - break; - } - } - distance = dest - (pos->volume_pos >> 10); - } - TRACE_EXIT result; -} - - -/* advance inside the given segment at most to_do bytes. - * of kilobytes moved - */ - -static int seek_in_segment(const unsigned int to_do, - cmpr_info *c_info, - const char *src_buf, - const int seg_sz, - const int seg_pos, - const zft_volinfo *volume) -{ - int result = 0; - int blk_sz = volume->blk_sz >> 10; - int remaining = to_do; - TRACE_FUN(ft_t_flow); - - if (c_info->offset == 0) { - /* new segment just read - */ - TRACE_CATCH(get_cseg(c_info, src_buf, seg_sz, volume),); - c_info->cmpr_pos += c_info->count; - DUMP_CMPR_INFO(ft_t_noise, "", c_info); - } - /* loop and uncompress until user buffer full or - * deblock-buffer empty - */ - TRACE(ft_t_noise, "compressed_sz: %d, compos : %d", - c_info->cmpr_sz, c_info->cmpr_pos); - while (c_info->spans == 0 && remaining > 0) { - if (c_info->cmpr_pos != 0) { /* cmpr buf is not empty */ - result += blk_sz; - remaining -= blk_sz; - c_info->cmpr_pos = 0; - } - if (remaining > 0) { - get_next_cluster(c_info, src_buf, seg_sz, - volume->end_seg == seg_pos); - if (c_info->count != 0) { - c_info->cmpr_pos = c_info->count; - c_info->offset += c_info->count; - } else { - break; - } - } - /* Allow escape from this loop on signal! - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - DUMP_CMPR_INFO(ft_t_noise, "", c_info); - TRACE(ft_t_noise, "to_do: %d", remaining); - } - if (seg_sz - c_info->offset <= 18) { - c_info->offset = seg_sz; - } - TRACE(ft_t_noise, "\n" - KERN_INFO "segment size : %d\n" - KERN_INFO "buf_pos_read : %d\n" - KERN_INFO "remaining : %d", - seg_sz, c_info->offset, - seg_sz - c_info->offset); - TRACE_EXIT result; -} - -static int slow_seek_forward_until_error(const unsigned int distance, - cmpr_info *c_info, - zft_position *pos, - const zft_volinfo *volume, - __u8 *buf) -{ - unsigned int remaining = distance; - int seg_sz; - int seg_pos; - int result; - TRACE_FUN(ft_t_flow); - - seg_pos = pos->seg_pos; - do { - TRACE_CATCH(seg_sz = zft_fetch_segment(seg_pos, buf, - FT_RD_AHEAD),); - /* now we have the contents of the actual segment in - * the deblock buffer - */ - TRACE_CATCH(result = seek_in_segment(remaining, c_info, buf, - seg_sz, seg_pos,volume),); - remaining -= result; - pos->volume_pos += result<<10; - pos->seg_pos = seg_pos; - pos->seg_byte_pos = c_info->offset; - seg_pos ++; - if (seg_pos <= volume->end_seg && c_info->offset == seg_sz) { - pos->seg_pos ++; - pos->seg_byte_pos = 0; - c_info->offset = 0; - } - /* Allow escape from this loop on signal! - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - TRACE(ft_t_noise, "\n" - KERN_INFO "remaining: %d\n" - KERN_INFO "seg_pos: %d\n" - KERN_INFO "end_seg: %d\n" - KERN_INFO "result: %d", - remaining, seg_pos, volume->end_seg, result); - } while (remaining > 0 && seg_pos <= volume->end_seg); - TRACE_EXIT 0; -} - -/* return segment id of next segment containing valid data, -EIO otherwise - */ -static int search_valid_segment(unsigned int segment, - const unsigned int end_seg, - const unsigned int max_foffs, - zft_position *pos, - cmpr_info *c_info, - const zft_volinfo *volume, - __u8 *buf) -{ - cmpr_info tmp_info; - int seg_sz; - TRACE_FUN(ft_t_flow); - - memset(&tmp_info, 0, sizeof(cmpr_info)); - while (segment <= end_seg) { - FT_SIGNAL_EXIT(_DONT_BLOCK); - TRACE(ft_t_noise, - "Searching readable segment between %d and %d", - segment, end_seg); - seg_sz = zft_fetch_segment(segment, buf, FT_RD_AHEAD); - if ((seg_sz > 0) && - (get_cseg (&tmp_info, buf, seg_sz, volume) >= 0) && - (tmp_info.foffs != 0 || segment == volume->start_seg)) { - if ((tmp_info.foffs>>10) > max_foffs) { - TRACE_ABORT(-EIO, ft_t_noise, "\n" - KERN_INFO "cseg.foff: %d\n" - KERN_INFO "dest : %d", - (int)(tmp_info.foffs >> 10), - max_foffs); - } - DUMP_CMPR_INFO(ft_t_noise, "", &tmp_info); - *c_info = tmp_info; - pos->seg_pos = segment; - pos->volume_pos = c_info->foffs; - pos->seg_byte_pos = c_info->offset; - TRACE(ft_t_noise, "found segment at %d", segment); - TRACE_EXIT 0; - } - segment++; - } - TRACE_EXIT -EIO; -} - -static int slow_seek_forward(unsigned int dest, - cmpr_info *c_info, - zft_position *pos, - const zft_volinfo *volume, - __u8 *buf) -{ - unsigned int distance; - int result = 0; - TRACE_FUN(ft_t_flow); - - distance = dest - (pos->volume_pos >> 10); - while ((distance > 0) && - (result = slow_seek_forward_until_error(distance, - c_info, - pos, - volume, - buf)) < 0) { - if (result == -EINTR) { - break; - } - TRACE(ft_t_noise, "seg_pos: %d", pos->seg_pos); - /* the failing segment is either pos->seg_pos or - * pos->seg_pos + 1. There is no need to further try - * that segment, because ftape_read_segment() already - * has tried very much to read it. So we start with - * following segment, which is pos->seg_pos + 1 - */ - if(search_valid_segment(pos->seg_pos+1, volume->end_seg, dest, - pos, c_info, - volume, buf) < 0) { - TRACE(ft_t_noise, "search_valid_segment() failed"); - result = -EIO; - break; - } - distance = dest - (pos->volume_pos >> 10); - result = 0; - TRACE(ft_t_noise, "segment: %d", pos->seg_pos); - /* found valid segment, retry the seek */ - } - TRACE_EXIT result; -} - -static int compute_seg_pos(const unsigned int dest, - zft_position *pos, - const zft_volinfo *volume) -{ - int segment; - int distance = dest - (pos->volume_pos >> 10); - unsigned int raw_size; - unsigned int virt_size; - unsigned int factor; - TRACE_FUN(ft_t_flow); - - if (distance >= 0) { - raw_size = volume->end_seg - pos->seg_pos + 1; - virt_size = ((unsigned int)(volume->size>>10) - - (unsigned int)(pos->volume_pos>>10) - + FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS - 1); - virt_size /= FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS; - if (virt_size == 0 || raw_size == 0) { - TRACE_EXIT 0; - } - if (raw_size >= (1<<25)) { - factor = raw_size/(virt_size>>7); - } else { - factor = (raw_size<<7)/virt_size; - } - segment = distance/(FT_SECTORS_PER_SEGMENT-FT_ECC_SECTORS); - segment = (segment * factor)>>7; - } else { - raw_size = pos->seg_pos - volume->start_seg + 1; - virt_size = ((unsigned int)(pos->volume_pos>>10) - + FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS - 1); - virt_size /= FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS; - if (virt_size == 0 || raw_size == 0) { - TRACE_EXIT 0; - } - if (raw_size >= (1<<25)) { - factor = raw_size/(virt_size>>7); - } else { - factor = (raw_size<<7)/virt_size; - } - segment = distance/(FT_SECTORS_PER_SEGMENT-FT_ECC_SECTORS); - } - TRACE(ft_t_noise, "factor: %d/%d", factor, 1<<7); - TRACE_EXIT segment; -} - -static struct zft_cmpr_ops cmpr_ops = { - zftc_write, - zftc_read, - zftc_seek, - zftc_lock, - zftc_reset, - zftc_cleanup -}; - -int zft_compressor_init(void) -{ - TRACE_FUN(ft_t_flow); - -#ifdef MODULE - printk(KERN_INFO "zftape compressor v1.00a 970514 for " FTAPE_VERSION "\n"); - if (TRACE_LEVEL >= ft_t_info) { - printk( -KERN_INFO "(c) 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)\n" -KERN_INFO "Compressor for zftape (lzrw3 algorithm)\n"); - } -#else /* !MODULE */ - /* print a short no-nonsense boot message */ - printk(KERN_INFO "zftape compressor v1.00a 970514\n"); - printk(KERN_INFO "For use with " FTAPE_VERSION "\n"); -#endif /* MODULE */ - TRACE(ft_t_info, "zft_compressor_init @ 0x%p", zft_compressor_init); - TRACE(ft_t_info, "installing compressor for zftape ..."); - TRACE_CATCH(zft_cmpr_register(&cmpr_ops),); - TRACE_EXIT 0; -} - -#ifdef MODULE - -MODULE_AUTHOR( - "(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de"); -MODULE_DESCRIPTION( -"Compression routines for zftape. Uses the lzrw3 algorithm by Ross Williams"); -MODULE_LICENSE("GPL"); - -/* Called by modules package when installing the driver - */ -int init_module(void) -{ - return zft_compressor_init(); -} - -#endif /* MODULE */ diff --git a/drivers/char/ftape/compressor/zftape-compress.h b/drivers/char/ftape/compressor/zftape-compress.h deleted file mode 100644 index f200741e33bf..000000000000 --- a/drivers/char/ftape/compressor/zftape-compress.h +++ /dev/null @@ -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 */ diff --git a/drivers/char/ftape/lowlevel/Makefile b/drivers/char/ftape/lowlevel/Makefile deleted file mode 100644 index febab07ba427..000000000000 --- a/drivers/char/ftape/lowlevel/Makefile +++ /dev/null @@ -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 diff --git a/drivers/char/ftape/lowlevel/fc-10.c b/drivers/char/ftape/lowlevel/fc-10.c deleted file mode 100644 index 9bc1cddade76..000000000000 --- a/drivers/char/ftape/lowlevel/fc-10.c +++ /dev/null @@ -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; -} diff --git a/drivers/char/ftape/lowlevel/fc-10.h b/drivers/char/ftape/lowlevel/fc-10.h deleted file mode 100644 index da7b88bca889..000000000000 --- a/drivers/char/ftape/lowlevel/fc-10.h +++ /dev/null @@ -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 diff --git a/drivers/char/ftape/lowlevel/fdc-io.c b/drivers/char/ftape/lowlevel/fdc-io.c deleted file mode 100644 index bbcf918f056f..000000000000 --- a/drivers/char/ftape/lowlevel/fdc-io.c +++ /dev/null @@ -1,1349 +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/fdc-io.c,v $ - * $Revision: 1.7.4.2 $ - * $Date: 1997/11/16 14:48:17 $ - * - * This file contains the low-level floppy disk interface code - * for the QIC-40/80/3010/3020 floppy-tape driver "ftape" for - * Linux. - */ - -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/ioport.h> -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <asm/system.h> -#include <asm/io.h> -#include <asm/dma.h> -#include <asm/irq.h> - -#include <linux/ftape.h> -#include <linux/qic117.h> -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/fdc-io.h" -#include "../lowlevel/fdc-isr.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-calibr.h" -#include "../lowlevel/fc-10.h" - -/* Global vars. - */ -static int ftape_motor; -volatile int ftape_current_cylinder = -1; -volatile fdc_mode_enum fdc_mode = fdc_idle; -fdc_config_info fdc; -DECLARE_WAIT_QUEUE_HEAD(ftape_wait_intr); - -unsigned int ft_fdc_base = CONFIG_FT_FDC_BASE; -unsigned int ft_fdc_irq = CONFIG_FT_FDC_IRQ; -unsigned int ft_fdc_dma = CONFIG_FT_FDC_DMA; -unsigned int ft_fdc_threshold = CONFIG_FT_FDC_THR; /* bytes */ -unsigned int ft_fdc_rate_limit = CONFIG_FT_FDC_MAX_RATE; /* bits/sec */ -int ft_probe_fc10 = CONFIG_FT_PROBE_FC10; -int ft_mach2 = CONFIG_FT_MACH2; - -/* Local vars. - */ -static spinlock_t fdc_io_lock; -static unsigned int fdc_calibr_count; -static unsigned int fdc_calibr_time; -static int fdc_status; -volatile __u8 fdc_head; /* FDC head from sector id */ -volatile __u8 fdc_cyl; /* FDC track from sector id */ -volatile __u8 fdc_sect; /* FDC sector from sector id */ -static int fdc_data_rate = 500; /* data rate (Kbps) */ -static int fdc_rate_code; /* data rate code (0 == 500 Kbps) */ -static int fdc_seek_rate = 2; /* step rate (msec) */ -static void (*do_ftape) (void); -static int fdc_fifo_state; /* original fifo setting - fifo enabled */ -static int fdc_fifo_thr; /* original fifo setting - threshold */ -static int fdc_lock_state; /* original lock setting - locked */ -static int fdc_fifo_locked; /* has fifo && lock set ? */ -static __u8 fdc_precomp; /* default precomp. value (nsec) */ -static __u8 fdc_prec_code; /* fdc precomp. select code */ - -static char ftape_id[] = "ftape"; /* used by request irq and free irq */ - -static int fdc_set_seek_rate(int seek_rate); - -void fdc_catch_stray_interrupts(int count) -{ - unsigned long flags; - - spin_lock_irqsave(&fdc_io_lock, flags); - if (count == 0) { - ft_expected_stray_interrupts = 0; - } else { - ft_expected_stray_interrupts += count; - } - spin_unlock_irqrestore(&fdc_io_lock, flags); -} - -/* Wait during a timeout period for a given FDC status. - * If usecs == 0 then just test status, else wait at least for usecs. - * Returns -ETIME on timeout. Function must be calibrated first ! - */ -static int fdc_wait(unsigned int usecs, __u8 mask, __u8 state) -{ - int count_1 = (fdc_calibr_count * usecs + - fdc_calibr_count - 1) / fdc_calibr_time; - - do { - fdc_status = inb_p(fdc.msr); - if ((fdc_status & mask) == state) { - return 0; - } - } while (count_1-- >= 0); - return -ETIME; -} - -int fdc_ready_wait(unsigned int usecs) -{ - return fdc_wait(usecs, FDC_DATA_READY | FDC_BUSY, FDC_DATA_READY); -} - -/* Why can't we just use udelay()? - */ -static void fdc_usec_wait(unsigned int usecs) -{ - fdc_wait(usecs, 0, 1); /* will always timeout ! */ -} - -static int fdc_ready_out_wait(unsigned int usecs) -{ - fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ - return fdc_wait(usecs, FDC_DATA_OUT_READY, FDC_DATA_OUT_READY); -} - -void fdc_wait_calibrate(void) -{ - ftape_calibrate("fdc_wait", - fdc_usec_wait, &fdc_calibr_count, &fdc_calibr_time); -} - -/* Wait for a (short) while for the FDC to become ready - * and transfer the next command byte. - * Return -ETIME on timeout on getting ready (depends on hardware!). - */ -static int fdc_write(const __u8 data) -{ - fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ - if (fdc_wait(150, FDC_DATA_READY_MASK, FDC_DATA_IN_READY) < 0) { - return -ETIME; - } else { - outb(data, fdc.fifo); - return 0; - } -} - -/* Wait for a (short) while for the FDC to become ready - * and transfer the next result byte. - * Return -ETIME if timeout on getting ready (depends on hardware!). - */ -static int fdc_read(__u8 * data) -{ - fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ - if (fdc_wait(150, FDC_DATA_READY_MASK, FDC_DATA_OUT_READY) < 0) { - return -ETIME; - } else { - *data = inb(fdc.fifo); - return 0; - } -} - -/* Output a cmd_len long command string to the FDC. - * The FDC should be ready to receive a new command or - * an error (EBUSY or ETIME) will occur. - */ -int fdc_command(const __u8 * cmd_data, int cmd_len) -{ - int result = 0; - unsigned long flags; - int count = cmd_len; - int retry = 0; -#ifdef TESTING - static unsigned int last_time; - unsigned int time; -#endif - TRACE_FUN(ft_t_any); - - fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ - spin_lock_irqsave(&fdc_io_lock, flags); - if (!in_interrupt()) - /* Yes, I know, too much comments inside this function - * ... - * - * Yet another bug in the original driver. All that - * havoc is caused by the fact that the isr() sends - * itself a command to the floppy tape driver (pause, - * micro step pause). Now, the problem is that - * commands are transmitted via the fdc_seek - * command. But: the fdc performs seeks in the - * background i.e. it doesn't signal busy while - * sending the step pulses to the drive. Therefore the - * non-interrupt level driver has no chance to tell - * whether the isr() just has issued a seek. Therefore - * we HAVE TO have a look at the ft_hide_interrupt - * flag: it signals the non-interrupt level part of - * the driver that it has to wait for the fdc until it - * has completet seeking. - * - * THIS WAS PRESUMABLY THE REASON FOR ALL THAT - * "fdc_read timeout" errors, I HOPE :-) - */ - if (ft_hide_interrupt) { - restore_flags(flags); - TRACE(ft_t_info, - "Waiting for the isr() completing fdc_seek()"); - if (fdc_interrupt_wait(2 * FT_SECOND) < 0) { - TRACE(ft_t_warn, - "Warning: timeout waiting for isr() seek to complete"); - } - if (ft_hide_interrupt || !ft_seek_completed) { - /* There cannot be another - * interrupt. The isr() only stops - * the tape and the next interrupt - * won't come until we have send our - * command to the drive. - */ - TRACE_ABORT(-EIO, ft_t_bug, - "BUG? isr() is still seeking?\n" - KERN_INFO "hide: %d\n" - KERN_INFO "seek: %d", - ft_hide_interrupt, - ft_seek_completed); - - } - fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ - spin_lock_irqsave(&fdc_io_lock, flags); - } - fdc_status = inb(fdc.msr); - if ((fdc_status & FDC_DATA_READY_MASK) != FDC_DATA_IN_READY) { - spin_unlock_irqrestore(&fdc_io_lock, flags); - TRACE_ABORT(-EBUSY, ft_t_err, "fdc not ready"); - } - fdc_mode = *cmd_data; /* used by isr */ -#ifdef TESTING - if (fdc_mode == FDC_SEEK) { - time = ftape_timediff(last_time, ftape_timestamp()); - if (time < 6000) { - TRACE(ft_t_bug,"Warning: short timeout between seek commands: %d", - time); - } - } -#endif - if (!in_interrupt()) { - /* shouldn't be cleared if called from isr - */ - ft_interrupt_seen = 0; - } - while (count) { - result = fdc_write(*cmd_data); - if (result < 0) { - TRACE(ft_t_fdc_dma, - "fdc_mode = %02x, status = %02x at index %d", - (int) fdc_mode, (int) fdc_status, - cmd_len - count); - if (++retry <= 3) { - TRACE(ft_t_warn, "fdc_write timeout, retry"); - } else { - TRACE(ft_t_err, "fdc_write timeout, fatal"); - /* recover ??? */ - break; - } - } else { - --count; - ++cmd_data; - } - } -#ifdef TESTING - if (fdc_mode == FDC_SEEK) { - last_time = ftape_timestamp(); - } -#endif - spin_unlock_irqrestore(&fdc_io_lock, flags); - TRACE_EXIT result; -} - -/* Input a res_len long result string from the FDC. - * The FDC should be ready to send the result or an error - * (EBUSY or ETIME) will occur. - */ -int fdc_result(__u8 * res_data, int res_len) -{ - int result = 0; - unsigned long flags; - int count = res_len; - int retry = 0; - TRACE_FUN(ft_t_any); - - spin_lock_irqsave(&fdc_io_lock, flags); - fdc_status = inb(fdc.msr); - if ((fdc_status & FDC_DATA_READY_MASK) != FDC_DATA_OUT_READY) { - TRACE(ft_t_err, "fdc not ready"); - result = -EBUSY; - } else while (count) { - if (!(fdc_status & FDC_BUSY)) { - spin_unlock_irqrestore(&fdc_io_lock, flags); - TRACE_ABORT(-EIO, ft_t_err, "premature end of result phase"); - } - result = fdc_read(res_data); - if (result < 0) { - TRACE(ft_t_fdc_dma, - "fdc_mode = %02x, status = %02x at index %d", - (int) fdc_mode, - (int) fdc_status, - res_len - count); - if (++retry <= 3) { - TRACE(ft_t_warn, "fdc_read timeout, retry"); - } else { - TRACE(ft_t_err, "fdc_read timeout, fatal"); - /* recover ??? */ - break; - ++retry; - } - } else { - --count; - ++res_data; - } - } - spin_unlock_irqrestore(&fdc_io_lock, flags); - fdc_usec_wait(FT_RQM_DELAY); /* allow FDC to negate BSY */ - TRACE_EXIT result; -} - -/* Handle command and result phases for - * commands without data phase. - */ -static int fdc_issue_command(const __u8 * out_data, int out_count, - __u8 * in_data, int in_count) -{ - TRACE_FUN(ft_t_any); - - if (out_count > 0) { - TRACE_CATCH(fdc_command(out_data, out_count),); - } - /* will take 24 - 30 usec for fdc_sense_drive_status and - * fdc_sense_interrupt_status commands. - * 35 fails sometimes (5/9/93 SJL) - * On a loaded system it incidentally takes longer than - * this for the fdc to get ready ! ?????? WHY ?????? - * So until we know what's going on use a very long timeout. - */ - TRACE_CATCH(fdc_ready_out_wait(500 /* usec */),); - if (in_count > 0) { - TRACE_CATCH(fdc_result(in_data, in_count), - TRACE(ft_t_err, "result phase aborted")); - } - TRACE_EXIT 0; -} - -/* Wait for FDC interrupt with timeout (in milliseconds). - * Signals are blocked so the wait will not be aborted. - * Note: interrupts must be enabled ! (23/05/93 SJL) - */ -int fdc_interrupt_wait(unsigned int time) -{ - DECLARE_WAITQUEUE(wait,current); - sigset_t old_sigmask; - static int resetting; - long timeout; - - TRACE_FUN(ft_t_fdc_dma); - - if (waitqueue_active(&ftape_wait_intr)) { - TRACE_ABORT(-EIO, ft_t_err, "error: nested call"); - } - /* timeout time will be up to USPT microseconds too long ! */ - timeout = (1000 * time + FT_USPT - 1) / FT_USPT; - - spin_lock_irq(¤t->sighand->siglock); - old_sigmask = current->blocked; - sigfillset(¤t->blocked); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&ftape_wait_intr, &wait); - while (!ft_interrupt_seen && timeout) - timeout = schedule_timeout_interruptible(timeout); - - spin_lock_irq(¤t->sighand->siglock); - current->blocked = old_sigmask; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - remove_wait_queue(&ftape_wait_intr, &wait); - /* the following IS necessary. True: as well - * wake_up_interruptible() as the schedule() set TASK_RUNNING - * when they wakeup a task, BUT: it may very well be that - * ft_interrupt_seen is already set to 1 when we enter here - * in which case schedule() gets never called, and - * TASK_RUNNING never set. This has the funny effect that we - * execute all the code until we leave kernel space, but then - * the task is stopped (a task CANNOT be preempted while in - * kernel mode. Sending a pair of SIGSTOP/SIGCONT to the - * tasks wakes it up again. Funny! :-) - */ - current->state = TASK_RUNNING; - if (ft_interrupt_seen) { /* woken up by interrupt */ - ft_interrupt_seen = 0; - TRACE_EXIT 0; - } - /* Original comment: - * In first instance, next statement seems unnecessary since - * it will be cleared in fdc_command. However, a small part of - * the software seems to rely on this being cleared here - * (ftape_close might fail) so stick to it until things get fixed ! - */ - /* My deeply sought of knowledge: - * Behold NO! It is obvious. fdc_reset() doesn't call fdc_command() - * but nevertheless uses fdc_interrupt_wait(). OF COURSE this needs to - * be reset here. - */ - ft_interrupt_seen = 0; /* clear for next call */ - if (!resetting) { - resetting = 1; /* break infinite recursion if reset fails */ - TRACE(ft_t_any, "cleanup reset"); - fdc_reset(); - resetting = 0; - } - TRACE_EXIT (signal_pending(current)) ? -EINTR : -ETIME; -} - -/* Start/stop drive motor. Enable DMA mode. - */ -void fdc_motor(int motor) -{ - int unit = ft_drive_sel; - int data = unit | FDC_RESET_NOT | FDC_DMA_MODE; - TRACE_FUN(ft_t_any); - - ftape_motor = motor; - if (ftape_motor) { - data |= FDC_MOTOR_0 << unit; - TRACE(ft_t_noise, "turning motor %d on", unit); - } else { - TRACE(ft_t_noise, "turning motor %d off", unit); - } - if (ft_mach2) { - outb_p(data, fdc.dor2); - } else { - outb_p(data, fdc.dor); - } - ftape_sleep(10 * FT_MILLISECOND); - TRACE_EXIT; -} - -static void fdc_update_dsr(void) -{ - TRACE_FUN(ft_t_any); - - TRACE(ft_t_flow, "rate = %d Kbps, precomp = %d ns", - fdc_data_rate, fdc_precomp); - if (fdc.type >= i82077) { - outb_p((fdc_rate_code & 0x03) | fdc_prec_code, fdc.dsr); - } else { - outb_p(fdc_rate_code & 0x03, fdc.ccr); - } - TRACE_EXIT; -} - -void fdc_set_write_precomp(int precomp) -{ - TRACE_FUN(ft_t_any); - - TRACE(ft_t_noise, "New precomp: %d nsec", precomp); - fdc_precomp = precomp; - /* write precompensation can be set in multiples of 41.67 nsec. - * round the parameter to the nearest multiple and convert it - * into a fdc setting. Note that 0 means default to the fdc, - * 7 is used instead of that. - */ - fdc_prec_code = ((fdc_precomp + 21) / 42) << 2; - if (fdc_prec_code == 0 || fdc_prec_code > (6 << 2)) { - fdc_prec_code = 7 << 2; - } - fdc_update_dsr(); - TRACE_EXIT; -} - -/* Reprogram the 82078 registers to use Data Rate Table 1 on all drives. - */ -static void fdc_set_drive_specs(void) -{ - __u8 cmd[] = { FDC_DRIVE_SPEC, 0x00, 0x00, 0x00, 0x00, 0xc0}; - int result; - TRACE_FUN(ft_t_any); - - TRACE(ft_t_flow, "Setting of drive specs called"); - if (fdc.type >= i82078_1) { - cmd[1] = (0 << 5) | (2 << 2); - cmd[2] = (1 << 5) | (2 << 2); - cmd[3] = (2 << 5) | (2 << 2); - cmd[4] = (3 << 5) | (2 << 2); - result = fdc_command(cmd, NR_ITEMS(cmd)); - if (result < 0) { - TRACE(ft_t_err, "Setting of drive specs failed"); - } - } - TRACE_EXIT; -} - -/* Select clock for fdc, must correspond with tape drive setting ! - * This also influences the fdc timing so we must adjust some values. - */ -int fdc_set_data_rate(int rate) -{ - int bad_rate = 0; - TRACE_FUN(ft_t_any); - - /* Select clock for fdc, must correspond with tape drive setting ! - * This also influences the fdc timing so we must adjust some values. - */ - TRACE(ft_t_fdc_dma, "new rate = %d", rate); - switch (rate) { - case 250: - fdc_rate_code = fdc_data_rate_250; - break; - case 500: - fdc_rate_code = fdc_data_rate_500; - break; - case 1000: - if (fdc.type < i82077) { - bad_rate = 1; - } else { - fdc_rate_code = fdc_data_rate_1000; - } - break; - case 2000: - if (fdc.type < i82078_1) { - bad_rate = 1; - } else { - fdc_rate_code = fdc_data_rate_2000; - } - break; - default: - bad_rate = 1; - } - if (bad_rate) { - TRACE_ABORT(-EIO, - ft_t_fdc_dma, "%d is not a valid data rate", rate); - } - fdc_data_rate = rate; - fdc_update_dsr(); - fdc_set_seek_rate(fdc_seek_rate); /* clock changed! */ - ftape_udelay(1000); - TRACE_EXIT 0; -} - -/* keep the unit select if keep_select is != 0, - */ -static void fdc_dor_reset(int keep_select) -{ - __u8 fdc_ctl = ft_drive_sel; - - if (keep_select != 0) { - fdc_ctl |= FDC_DMA_MODE; - if (ftape_motor) { - fdc_ctl |= FDC_MOTOR_0 << ft_drive_sel; - } - } - ftape_udelay(10); /* ??? but seems to be necessary */ - if (ft_mach2) { - outb_p(fdc_ctl & 0x0f, fdc.dor); - outb_p(fdc_ctl, fdc.dor2); - } else { - outb_p(fdc_ctl, fdc.dor); - } - fdc_usec_wait(10); /* delay >= 14 fdc clocks */ - if (keep_select == 0) { - fdc_ctl = 0; - } - fdc_ctl |= FDC_RESET_NOT; - if (ft_mach2) { - outb_p(fdc_ctl & 0x0f, fdc.dor); - outb_p(fdc_ctl, fdc.dor2); - } else { - outb_p(fdc_ctl, fdc.dor); - } -} - -/* Reset the floppy disk controller. Leave the ftape_unit selected. - */ -void fdc_reset(void) -{ - int st0; - int i; - int dummy; - unsigned long flags; - TRACE_FUN(ft_t_any); - - spin_lock_irqsave(&fdc_io_lock, flags); - - fdc_dor_reset(1); /* keep unit selected */ - - fdc_mode = fdc_idle; - - /* maybe the spin_lock_irq* pair is not necessary, BUT: - * the following line MUST be here. Otherwise fdc_interrupt_wait() - * won't wait. Note that fdc_reset() is called from - * ftape_dumb_stop() when the fdc is busy transferring data. In this - * case fdc_isr() MOST PROBABLY sets ft_interrupt_seen, and tries - * to get the result bytes from the fdc etc. CLASH. - */ - ft_interrupt_seen = 0; - - /* Program data rate - */ - fdc_update_dsr(); /* restore data rate and precomp */ - - spin_unlock_irqrestore(&fdc_io_lock, flags); - - /* - * Wait for first polling cycle to complete - */ - if (fdc_interrupt_wait(1 * FT_SECOND) < 0) { - TRACE(ft_t_err, "no drive polling interrupt!"); - } else { /* clear all disk-changed statuses */ - for (i = 0; i < 4; ++i) { - if(fdc_sense_interrupt_status(&st0, &dummy) != 0) { - TRACE(ft_t_err, "sense failed for %d", i); - } - if (i == ft_drive_sel) { - ftape_current_cylinder = dummy; - } - } - TRACE(ft_t_noise, "drive polling completed"); - } - /* - * SPECIFY COMMAND - */ - fdc_set_seek_rate(fdc_seek_rate); - /* - * DRIVE SPECIFICATION COMMAND (if fdc type known) - */ - if (fdc.type >= i82078_1) { - fdc_set_drive_specs(); - } - TRACE_EXIT; -} - -#if !defined(CLK_48MHZ) -# define CLK_48MHZ 1 -#endif - -/* When we're done, put the fdc into reset mode so that the regular - * floppy disk driver will figure out that something is wrong and - * initialize the controller the way it wants. - */ -void fdc_disable(void) -{ - __u8 cmd1[] = {FDC_CONFIGURE, 0x00, 0x00, 0x00}; - __u8 cmd2[] = {FDC_LOCK}; - __u8 cmd3[] = {FDC_UNLOCK}; - __u8 stat[1]; - TRACE_FUN(ft_t_flow); - - if (!fdc_fifo_locked) { - fdc_reset(); - TRACE_EXIT; - } - if (fdc_issue_command(cmd3, 1, stat, 1) < 0 || stat[0] != 0x00) { - fdc_dor_reset(0); - TRACE_ABORT(/**/, ft_t_bug, - "couldn't unlock fifo, configuration remains changed"); - } - fdc_fifo_locked = 0; - if (CLK_48MHZ && fdc.type >= i82078) { - cmd1[0] |= FDC_CLK48_BIT; - } - cmd1[2] = ((fdc_fifo_state) ? 0 : 0x20) + (fdc_fifo_thr - 1); - if (fdc_command(cmd1, NR_ITEMS(cmd1)) < 0) { - fdc_dor_reset(0); - TRACE_ABORT(/**/, ft_t_bug, - "couldn't reconfigure fifo to old state"); - } - if (fdc_lock_state && - fdc_issue_command(cmd2, 1, stat, 1) < 0) { - fdc_dor_reset(0); - TRACE_ABORT(/**/, ft_t_bug, "couldn't lock old state again"); - } - TRACE(ft_t_noise, "fifo restored: %sabled, thr. %d, %slocked", - fdc_fifo_state ? "en" : "dis", - fdc_fifo_thr, (fdc_lock_state) ? "" : "not "); - fdc_dor_reset(0); - TRACE_EXIT; -} - -/* Specify FDC seek-rate (milliseconds) - */ -static int fdc_set_seek_rate(int seek_rate) -{ - /* set step rate, dma mode, and minimal head load and unload times - */ - __u8 in[3] = { FDC_SPECIFY, 1, (1 << 1)}; - - fdc_seek_rate = seek_rate; - in[1] |= (16 - (fdc_data_rate * fdc_seek_rate) / 500) << 4; - - return fdc_command(in, 3); -} - -/* Sense drive status: get unit's drive status (ST3) - */ -int fdc_sense_drive_status(int *st3) -{ - __u8 out[2]; - __u8 in[1]; - TRACE_FUN(ft_t_any); - - out[0] = FDC_SENSED; - out[1] = ft_drive_sel; - TRACE_CATCH(fdc_issue_command(out, 2, in, 1),); - *st3 = in[0]; - TRACE_EXIT 0; -} - -/* Sense Interrupt Status command: - * should be issued at the end of each seek. - * get ST0 and current cylinder. - */ -int fdc_sense_interrupt_status(int *st0, int *current_cylinder) -{ - __u8 out[1]; - __u8 in[2]; - TRACE_FUN(ft_t_any); - - out[0] = FDC_SENSEI; - TRACE_CATCH(fdc_issue_command(out, 1, in, 2),); - *st0 = in[0]; - *current_cylinder = in[1]; - TRACE_EXIT 0; -} - -/* step to track - */ -int fdc_seek(int track) -{ - __u8 out[3]; - int st0, pcn; -#ifdef TESTING - unsigned int time; -#endif - TRACE_FUN(ft_t_any); - - out[0] = FDC_SEEK; - out[1] = ft_drive_sel; - out[2] = track; -#ifdef TESTING - time = ftape_timestamp(); -#endif - /* We really need this command to work ! - */ - ft_seek_completed = 0; - TRACE_CATCH(fdc_command(out, 3), - fdc_reset(); - TRACE(ft_t_noise, "destination was: %d, resetting FDC...", - track)); - /* Handle interrupts until ft_seek_completed or timeout. - */ - for (;;) { - TRACE_CATCH(fdc_interrupt_wait(2 * FT_SECOND),); - if (ft_seek_completed) { - TRACE_CATCH(fdc_sense_interrupt_status(&st0, &pcn),); - if ((st0 & ST0_SEEK_END) == 0) { - TRACE_ABORT(-EIO, ft_t_err, - "no seek-end after seek completion !??"); - } - break; - } - } -#ifdef TESTING - time = ftape_timediff(time, ftape_timestamp()) / abs(track - ftape_current_cylinder); - if ((time < 900 || time > 3100) && abs(track - ftape_current_cylinder) > 5) { - TRACE(ft_t_warn, "Wrong FDC STEP interval: %d usecs (%d)", - time, track - ftape_current_cylinder); - } -#endif - /* Verify whether we issued the right tape command. - */ - /* Verify that we seek to the proper track. */ - if (pcn != track) { - TRACE_ABORT(-EIO, ft_t_err, "bad seek.."); - } - ftape_current_cylinder = track; - TRACE_EXIT 0; -} - -static int perpend_mode; /* set if fdc is in perpendicular mode */ - -static int perpend_off(void) -{ - __u8 perpend[] = {FDC_PERPEND, 0x00}; - TRACE_FUN(ft_t_any); - - if (perpend_mode) { - /* Turn off perpendicular mode */ - perpend[1] = 0x80; - TRACE_CATCH(fdc_command(perpend, 2), - TRACE(ft_t_err,"Perpendicular mode exit failed!")); - perpend_mode = 0; - } - TRACE_EXIT 0; -} - -static int handle_perpend(int segment_id) -{ - __u8 perpend[] = {FDC_PERPEND, 0x00}; - TRACE_FUN(ft_t_any); - - /* When writing QIC-3020 tapes, turn on perpendicular mode - * if tape is moving in forward direction (even tracks). - */ - if (ft_qic_std == QIC_TAPE_QIC3020 && - ((segment_id / ft_segments_per_track) & 1) == 0) { -/* FIXME: some i82077 seem to support perpendicular mode as - * well. - */ -#if 0 - if (fdc.type < i82077AA) {} -#else - if (fdc.type < i82077 && ft_data_rate < 1000) { -#endif - /* fdc does not support perpendicular mode: complain - */ - TRACE_ABORT(-EIO, ft_t_err, - "Your FDC does not support QIC-3020."); - } - perpend[1] = 0x03 /* 0x83 + (0x4 << ft_drive_sel) */ ; - TRACE_CATCH(fdc_command(perpend, 2), - TRACE(ft_t_err,"Perpendicular mode entry failed!")); - TRACE(ft_t_flow, "Perpendicular mode set"); - perpend_mode = 1; - TRACE_EXIT 0; - } - TRACE_EXIT perpend_off(); -} - -static inline void fdc_setup_dma(char mode, - volatile void *addr, unsigned int count) -{ - /* Program the DMA controller. - */ - disable_dma(fdc.dma); - clear_dma_ff(fdc.dma); - set_dma_mode(fdc.dma, mode); - set_dma_addr(fdc.dma, virt_to_bus((void*)addr)); - set_dma_count(fdc.dma, count); - enable_dma(fdc.dma); -} - -/* Setup fdc and dma for formatting the next segment - */ -int fdc_setup_formatting(buffer_struct * buff) -{ - unsigned long flags; - __u8 out[6] = { - FDC_FORMAT, 0x00, 3, 4 * FT_SECTORS_PER_SEGMENT, 0x00, 0x6b - }; - TRACE_FUN(ft_t_any); - - TRACE_CATCH(handle_perpend(buff->segment_id),); - /* Program the DMA controller. - */ - TRACE(ft_t_fdc_dma, - "phys. addr. = %lx", virt_to_bus((void*) buff->ptr)); - spin_lock_irqsave(&fdc_io_lock, flags); - fdc_setup_dma(DMA_MODE_WRITE, buff->ptr, FT_SECTORS_PER_SEGMENT * 4); - /* Issue FDC command to start reading/writing. - */ - out[1] = ft_drive_sel; - out[4] = buff->gap3; - TRACE_CATCH(fdc_setup_error = fdc_command(out, sizeof(out)), - restore_flags(flags); fdc_mode = fdc_idle); - spin_unlock_irqrestore(&fdc_io_lock, flags); - TRACE_EXIT 0; -} - - -/* Setup Floppy Disk Controller and DMA to read or write the next cluster - * of good sectors from or to the current segment. - */ -int fdc_setup_read_write(buffer_struct * buff, __u8 operation) -{ - unsigned long flags; - __u8 out[9]; - int dma_mode; - TRACE_FUN(ft_t_any); - - switch(operation) { - case FDC_VERIFY: - if (fdc.type < i82077) { - operation = FDC_READ; - } - case FDC_READ: - case FDC_READ_DELETED: - dma_mode = DMA_MODE_READ; - TRACE(ft_t_fdc_dma, "xfer %d sectors to 0x%p", - buff->sector_count, buff->ptr); - TRACE_CATCH(perpend_off(),); - break; - case FDC_WRITE_DELETED: - TRACE(ft_t_noise, "deleting segment %d", buff->segment_id); - case FDC_WRITE: - dma_mode = DMA_MODE_WRITE; - /* When writing QIC-3020 tapes, turn on perpendicular mode - * if tape is moving in forward direction (even tracks). - */ - TRACE_CATCH(handle_perpend(buff->segment_id),); - TRACE(ft_t_fdc_dma, "xfer %d sectors from 0x%p", - buff->sector_count, buff->ptr); - break; - default: - TRACE_ABORT(-EIO, - ft_t_bug, "bug: invalid operation parameter"); - } - TRACE(ft_t_fdc_dma, "phys. addr. = %lx",virt_to_bus((void*)buff->ptr)); - spin_lock_irqsave(&fdc_io_lock, flags); - if (operation != FDC_VERIFY) { - fdc_setup_dma(dma_mode, buff->ptr, - FT_SECTOR_SIZE * buff->sector_count); - } - /* Issue FDC command to start reading/writing. - */ - out[0] = operation; - out[1] = ft_drive_sel; - out[2] = buff->cyl; - out[3] = buff->head; - out[4] = buff->sect + buff->sector_offset; - out[5] = 3; /* Sector size of 1K. */ - out[6] = out[4] + buff->sector_count - 1; /* last sector */ - out[7] = 109; /* Gap length. */ - out[8] = 0xff; /* No limit to transfer size. */ - TRACE(ft_t_fdc_dma, "C: 0x%02x, H: 0x%02x, R: 0x%02x, cnt: 0x%02x", - out[2], out[3], out[4], out[6] - out[4] + 1); - spin_unlock_irqrestore(&fdc_io_lock, flags); - TRACE_CATCH(fdc_setup_error = fdc_command(out, 9),fdc_mode = fdc_idle); - TRACE_EXIT 0; -} - -int fdc_fifo_threshold(__u8 threshold, - int *fifo_state, int *lock_state, int *fifo_thr) -{ - const __u8 cmd0[] = {FDC_DUMPREGS}; - __u8 cmd1[] = {FDC_CONFIGURE, 0, (0x0f & (threshold - 1)), 0}; - const __u8 cmd2[] = {FDC_LOCK}; - const __u8 cmd3[] = {FDC_UNLOCK}; - __u8 reg[10]; - __u8 stat; - int i; - int result; - TRACE_FUN(ft_t_any); - - if (CLK_48MHZ && fdc.type >= i82078) { - cmd1[0] |= FDC_CLK48_BIT; - } - /* Dump fdc internal registers for examination - */ - TRACE_CATCH(fdc_command(cmd0, NR_ITEMS(cmd0)), - TRACE(ft_t_warn, "dumpreg cmd failed, fifo unchanged")); - /* Now read fdc internal registers from fifo - */ - for (i = 0; i < (int)NR_ITEMS(reg); ++i) { - fdc_read(®[i]); - TRACE(ft_t_fdc_dma, "Register %d = 0x%02x", i, reg[i]); - } - if (fifo_state && lock_state && fifo_thr) { - *fifo_state = (reg[8] & 0x20) == 0; - *lock_state = reg[7] & 0x80; - *fifo_thr = 1 + (reg[8] & 0x0f); - } - TRACE(ft_t_noise, - "original fifo state: %sabled, threshold %d, %slocked", - ((reg[8] & 0x20) == 0) ? "en" : "dis", - 1 + (reg[8] & 0x0f), (reg[7] & 0x80) ? "" : "not "); - /* If fdc is already locked, unlock it first ! */ - if (reg[7] & 0x80) { - fdc_ready_wait(100); - TRACE_CATCH(fdc_issue_command(cmd3, NR_ITEMS(cmd3), &stat, 1), - TRACE(ft_t_bug, "FDC unlock command failed, " - "configuration unchanged")); - } - fdc_fifo_locked = 0; - /* Enable fifo and set threshold at xx bytes to allow a - * reasonably large latency and reduce number of dma bursts. - */ - fdc_ready_wait(100); - if ((result = fdc_command(cmd1, NR_ITEMS(cmd1))) < 0) { - TRACE(ft_t_bug, "configure cmd failed, fifo unchanged"); - } - /* Now lock configuration so reset will not change it - */ - if(fdc_issue_command(cmd2, NR_ITEMS(cmd2), &stat, 1) < 0 || - stat != 0x10) { - TRACE_ABORT(-EIO, ft_t_bug, - "FDC lock command failed, stat = 0x%02x", stat); - } - fdc_fifo_locked = 1; - TRACE_EXIT result; -} - -static int fdc_fifo_enable(void) -{ - TRACE_FUN(ft_t_any); - - if (fdc_fifo_locked) { - TRACE_ABORT(0, ft_t_warn, "Fifo not enabled because locked"); - } - TRACE_CATCH(fdc_fifo_threshold(ft_fdc_threshold /* bytes */, - &fdc_fifo_state, - &fdc_lock_state, - &fdc_fifo_thr),); - TRACE_CATCH(fdc_fifo_threshold(ft_fdc_threshold /* bytes */, - NULL, NULL, NULL),); - TRACE_EXIT 0; -} - -/* Determine fd controller type - */ -static __u8 fdc_save_state[2]; - -static int fdc_probe(void) -{ - __u8 cmd[1]; - __u8 stat[16]; /* must be able to hold dumpregs & save results */ - int i; - TRACE_FUN(ft_t_any); - - /* Try to find out what kind of fd controller we have to deal with - * Scheme borrowed from floppy driver: - * first try if FDC_DUMPREGS command works - * (this indicates that we have a 82072 or better) - * then try the FDC_VERSION command (82072 doesn't support this) - * then try the FDC_UNLOCK command (some older 82077's don't support this) - * then try the FDC_PARTID command (82078's support this) - */ - cmd[0] = FDC_DUMPREGS; - if (fdc_issue_command(cmd, 1, stat, 1) != 0) { - TRACE_ABORT(no_fdc, ft_t_bug, "No FDC found"); - } - if (stat[0] == 0x80) { - /* invalid command: must be pre 82072 */ - TRACE_ABORT(i8272, - ft_t_warn, "Type 8272A/765A compatible FDC found"); - } - fdc_result(&stat[1], 9); - fdc_save_state[0] = stat[7]; - fdc_save_state[1] = stat[8]; - cmd[0] = FDC_VERSION; - if (fdc_issue_command(cmd, 1, stat, 1) < 0 || stat[0] == 0x80) { - TRACE_ABORT(i8272, ft_t_warn, "Type 82072 FDC found"); - } - if (*stat != 0x90) { - TRACE_ABORT(i8272, ft_t_warn, "Unknown FDC found"); - } - cmd[0] = FDC_UNLOCK; - if(fdc_issue_command(cmd, 1, stat, 1) < 0 || stat[0] != 0x00) { - TRACE_ABORT(i8272, ft_t_warn, - "Type pre-1991 82077 FDC found, " - "treating it like a 82072"); - } - if (fdc_save_state[0] & 0x80) { /* was locked */ - cmd[0] = FDC_LOCK; /* restore lock */ - (void)fdc_issue_command(cmd, 1, stat, 1); - TRACE(ft_t_warn, "FDC is already locked"); - } - /* Test for a i82078 FDC */ - cmd[0] = FDC_PARTID; - if (fdc_issue_command(cmd, 1, stat, 1) < 0 || stat[0] == 0x80) { - /* invalid command: not a i82078xx type FDC */ - for (i = 0; i < 4; ++i) { - outb_p(i, fdc.tdr); - if ((inb_p(fdc.tdr) & 0x03) != i) { - TRACE_ABORT(i82077, - ft_t_warn, "Type 82077 FDC found"); - } - } - TRACE_ABORT(i82077AA, ft_t_warn, "Type 82077AA FDC found"); - } - /* FDC_PARTID cmd succeeded */ - switch (stat[0] >> 5) { - case 0x0: - /* i82078SL or i82078-1. The SL part cannot run at - * 2Mbps (the SL and -1 dies are identical; they are - * speed graded after production, according to Intel). - * Some SL's can be detected by doing a SAVE cmd and - * look at bit 7 of the first byte (the SEL3V# bit). - * If it is 0, the part runs off 3Volts, and hence it - * is a SL. - */ - cmd[0] = FDC_SAVE; - if(fdc_issue_command(cmd, 1, stat, 16) < 0) { - TRACE(ft_t_err, "FDC_SAVE failed. Dunno why"); - /* guess we better claim the fdc to be a i82078 */ - TRACE_ABORT(i82078, - ft_t_warn, - "Type i82078 FDC (i suppose) found"); - } - if ((stat[0] & FDC_SEL3V_BIT)) { - /* fdc running off 5Volts; Pray that it's a i82078-1 - */ - TRACE_ABORT(i82078_1, ft_t_warn, - "Type i82078-1 or 5Volt i82078SL FDC found"); - } - TRACE_ABORT(i82078, ft_t_warn, - "Type 3Volt i82078SL FDC (1Mbps) found"); - case 0x1: - case 0x2: /* S82078B */ - /* The '78B isn't '78 compatible. Detect it as a '77AA */ - TRACE_ABORT(i82077AA, ft_t_warn, "Type i82077AA FDC found"); - case 0x3: /* NSC PC8744 core; used in several super-IO chips */ - TRACE_ABORT(i82077AA, - ft_t_warn, "Type 82077AA compatible FDC found"); - default: - TRACE(ft_t_warn, "A previously undetected FDC found"); - TRACE_ABORT(i82077AA, ft_t_warn, - "Treating it as a 82077AA. Please report partid= %d", - stat[0]); - } /* switch(stat[ 0] >> 5) */ - TRACE_EXIT no_fdc; -} - -static int fdc_request_regions(void) -{ - TRACE_FUN(ft_t_flow); - - if (ft_mach2 || ft_probe_fc10) { - if (!request_region(fdc.sra, 8, "fdc (ft)")) { -#ifndef BROKEN_FLOPPY_DRIVER - TRACE_EXIT -EBUSY; -#else - TRACE(ft_t_warn, -"address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra); -#endif - } - } else { - if (!request_region(fdc.sra, 6, "fdc (ft)")) { -#ifndef BROKEN_FLOPPY_DRIVER - TRACE_EXIT -EBUSY; -#else - TRACE(ft_t_warn, -"address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra); -#endif - } - if (!request_region(fdc.sra + 7, 1, "fdc (ft)")) { -#ifndef BROKEN_FLOPPY_DRIVER - release_region(fdc.sra, 6); - TRACE_EXIT -EBUSY; -#else - TRACE(ft_t_warn, -"address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra + 7); -#endif - } - } - TRACE_EXIT 0; -} - -void fdc_release_regions(void) -{ - TRACE_FUN(ft_t_flow); - - if (fdc.sra != 0) { - if (fdc.dor2 != 0) { - release_region(fdc.sra, 8); - } else { - release_region(fdc.sra, 6); - release_region(fdc.dir, 1); - } - } - TRACE_EXIT; -} - -static int fdc_config_regs(unsigned int fdc_base, - unsigned int fdc_irq, - unsigned int fdc_dma) -{ - TRACE_FUN(ft_t_flow); - - fdc.irq = fdc_irq; - fdc.dma = fdc_dma; - fdc.sra = fdc_base; - fdc.srb = fdc_base + 1; - fdc.dor = fdc_base + 2; - fdc.tdr = fdc_base + 3; - fdc.msr = fdc.dsr = fdc_base + 4; - fdc.fifo = fdc_base + 5; - fdc.dir = fdc.ccr = fdc_base + 7; - fdc.dor2 = (ft_mach2 || ft_probe_fc10) ? fdc_base + 6 : 0; - TRACE_CATCH(fdc_request_regions(), fdc.sra = 0); - TRACE_EXIT 0; -} - -static int fdc_config(void) -{ - static int already_done; - TRACE_FUN(ft_t_any); - - if (already_done) { - TRACE_CATCH(fdc_request_regions(),); - *(fdc.hook) = fdc_isr; /* hook our handler in */ - TRACE_EXIT 0; - } - if (ft_probe_fc10) { - int fc_type; - - TRACE_CATCH(fdc_config_regs(ft_fdc_base, - ft_fdc_irq, ft_fdc_dma),); - fc_type = fc10_enable(); - if (fc_type != 0) { - TRACE(ft_t_warn, "FC-%c0 controller found", '0' + fc_type); - fdc.type = fc10; - fdc.hook = &do_ftape; - *(fdc.hook) = fdc_isr; /* hook our handler in */ - already_done = 1; - TRACE_EXIT 0; - } else { - TRACE(ft_t_warn, "FC-10/20 controller not found"); - fdc_release_regions(); - fdc.type = no_fdc; - ft_probe_fc10 = 0; - ft_fdc_base = 0x3f0; - ft_fdc_irq = 6; - ft_fdc_dma = 2; - } - } - TRACE(ft_t_warn, "fdc base: 0x%x, irq: %d, dma: %d", - ft_fdc_base, ft_fdc_irq, ft_fdc_dma); - TRACE_CATCH(fdc_config_regs(ft_fdc_base, ft_fdc_irq, ft_fdc_dma),); - fdc.hook = &do_ftape; - *(fdc.hook) = fdc_isr; /* hook our handler in */ - already_done = 1; - TRACE_EXIT 0; -} - -static irqreturn_t ftape_interrupt(int irq, void *dev_id) -{ - void (*handler) (void) = *fdc.hook; - int handled = 0; - TRACE_FUN(ft_t_any); - - *fdc.hook = NULL; - if (handler) { - handled = 1; - handler(); - } else { - TRACE(ft_t_bug, "Unexpected ftape interrupt"); - } - TRACE_EXIT IRQ_RETVAL(handled); -} - -static int fdc_grab_irq_and_dma(void) -{ - TRACE_FUN(ft_t_any); - - if (fdc.hook == &do_ftape) { - /* Get fast interrupt handler. - */ - if (request_irq(fdc.irq, ftape_interrupt, - IRQF_DISABLED, "ft", ftape_id)) { - TRACE_ABORT(-EIO, ft_t_bug, - "Unable to grab IRQ%d for ftape driver", - fdc.irq); - } - if (request_dma(fdc.dma, ftape_id)) { - free_irq(fdc.irq, ftape_id); - TRACE_ABORT(-EIO, ft_t_bug, - "Unable to grab DMA%d for ftape driver", - fdc.dma); - } - } - if (ft_fdc_base != 0x3f0 && (ft_fdc_dma == 2 || ft_fdc_irq == 6)) { - /* Using same dma channel or irq as standard fdc, need - * to disable the dma-gate on the std fdc. This - * couldn't be done in the floppy driver as some - * laptops are using the dma-gate to enter a low power - * or even suspended state :-( - */ - outb_p(FDC_RESET_NOT, 0x3f2); - TRACE(ft_t_noise, "DMA-gate on standard fdc disabled"); - } - TRACE_EXIT 0; -} - -int fdc_release_irq_and_dma(void) -{ - TRACE_FUN(ft_t_any); - - if (fdc.hook == &do_ftape) { - disable_dma(fdc.dma); /* just in case... */ - free_dma(fdc.dma); - free_irq(fdc.irq, ftape_id); - } - if (ft_fdc_base != 0x3f0 && (ft_fdc_dma == 2 || ft_fdc_irq == 6)) { - /* Using same dma channel as standard fdc, need to - * disable the dma-gate on the std fdc. This couldn't - * be done in the floppy driver as some laptops are - * using the dma-gate to enter a low power or even - * suspended state :-( - */ - outb_p(FDC_RESET_NOT | FDC_DMA_MODE, 0x3f2); - TRACE(ft_t_noise, "DMA-gate on standard fdc enabled again"); - } - TRACE_EXIT 0; -} - -int fdc_init(void) -{ - TRACE_FUN(ft_t_any); - - /* find a FDC to use */ - TRACE_CATCH(fdc_config(),); - TRACE_CATCH(fdc_grab_irq_and_dma(), fdc_release_regions()); - ftape_motor = 0; - fdc_catch_stray_interrupts(0); /* clear number of awainted - * stray interrupte - */ - fdc_catch_stray_interrupts(1); /* one always comes (?) */ - TRACE(ft_t_flow, "resetting fdc"); - fdc_set_seek_rate(2); /* use nominal QIC step rate */ - fdc_reset(); /* init fdc & clear track counters */ - if (fdc.type == no_fdc) { /* no FC-10 or FC-20 found */ - fdc.type = fdc_probe(); - fdc_reset(); /* update with new knowledge */ - } - if (fdc.type == no_fdc) { - fdc_release_irq_and_dma(); - fdc_release_regions(); - TRACE_EXIT -ENXIO; - } - if (fdc.type >= i82077) { - if (fdc_fifo_enable() < 0) { - TRACE(ft_t_warn, "couldn't enable fdc fifo !"); - } else { - TRACE(ft_t_flow, "fdc fifo enabled and locked"); - } - } - TRACE_EXIT 0; -} diff --git a/drivers/char/ftape/lowlevel/fdc-io.h b/drivers/char/ftape/lowlevel/fdc-io.h deleted file mode 100644 index 7ec3c72178bb..000000000000 --- a/drivers/char/ftape/lowlevel/fdc-io.h +++ /dev/null @@ -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 diff --git a/drivers/char/ftape/lowlevel/fdc-isr.c b/drivers/char/ftape/lowlevel/fdc-isr.c deleted file mode 100644 index ad2bc733ae1b..000000000000 --- a/drivers/char/ftape/lowlevel/fdc-isr.c +++ /dev/null @@ -1,1170 +0,0 @@ -/* - * 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/fdc-isr.c,v $ - * $Revision: 1.9 $ - * $Date: 1997/10/17 23:01:53 $ - * - * This file contains the interrupt service routine and - * associated code for the QIC-40/80/3010/3020 floppy-tape driver - * "ftape" for Linux. - */ - -#include <asm/io.h> -#include <asm/dma.h> - -#define volatile /* */ - -#include <linux/ftape.h> -#include <linux/qic117.h> -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/fdc-isr.h" -#include "../lowlevel/fdc-io.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-calibr.h" -#include "../lowlevel/ftape-bsm.h" - -/* Global vars. - */ -volatile int ft_expected_stray_interrupts; -volatile int ft_interrupt_seen; -volatile int ft_seek_completed; -volatile int ft_hide_interrupt; -/* Local vars. - */ -typedef enum { - no_error = 0, id_am_error = 0x01, id_crc_error = 0x02, - data_am_error = 0x04, data_crc_error = 0x08, - no_data_error = 0x10, overrun_error = 0x20, -} error_cause; -static int stop_read_ahead; - - -static void print_error_cause(int cause) -{ - TRACE_FUN(ft_t_any); - - switch (cause) { - case no_data_error: - TRACE(ft_t_noise, "no data error"); - break; - case id_am_error: - TRACE(ft_t_noise, "id am error"); - break; - case id_crc_error: - TRACE(ft_t_noise, "id crc error"); - break; - case data_am_error: - TRACE(ft_t_noise, "data am error"); - break; - case data_crc_error: - TRACE(ft_t_noise, "data crc error"); - break; - case overrun_error: - TRACE(ft_t_noise, "overrun error"); - break; - default:; - } - TRACE_EXIT; -} - -static char *fdc_mode_txt(fdc_mode_enum mode) -{ - switch (mode) { - case fdc_idle: - return "fdc_idle"; - case fdc_reading_data: - return "fdc_reading_data"; - case fdc_seeking: - return "fdc_seeking"; - case fdc_writing_data: - return "fdc_writing_data"; - case fdc_reading_id: - return "fdc_reading_id"; - case fdc_recalibrating: - return "fdc_recalibrating"; - case fdc_formatting: - return "fdc_formatting"; - case fdc_verifying: - return "fdc_verifying"; - default: - return "unknown"; - } -} - -static inline error_cause decode_irq_cause(fdc_mode_enum mode, __u8 st[]) -{ - error_cause cause = no_error; - TRACE_FUN(ft_t_any); - - /* Valid st[], decode cause of interrupt. - */ - switch (st[0] & ST0_INT_MASK) { - case FDC_INT_NORMAL: - TRACE(ft_t_fdc_dma,"normal completion: %s",fdc_mode_txt(mode)); - break; - case FDC_INT_ABNORMAL: - TRACE(ft_t_flow, "abnormal completion %s", fdc_mode_txt(mode)); - TRACE(ft_t_fdc_dma, "ST0: 0x%02x, ST1: 0x%02x, ST2: 0x%02x", - st[0], st[1], st[2]); - TRACE(ft_t_fdc_dma, - "C: 0x%02x, H: 0x%02x, R: 0x%02x, N: 0x%02x", - st[3], st[4], st[5], st[6]); - if (st[1] & 0x01) { - if (st[2] & 0x01) { - cause = data_am_error; - } else { - cause = id_am_error; - } - } else if (st[1] & 0x20) { - if (st[2] & 0x20) { - cause = data_crc_error; - } else { - cause = id_crc_error; - } - } else if (st[1] & 0x04) { - cause = no_data_error; - } else if (st[1] & 0x10) { - cause = overrun_error; - } - print_error_cause(cause); - break; - case FDC_INT_INVALID: - TRACE(ft_t_flow, "invalid completion %s", fdc_mode_txt(mode)); - break; - case FDC_INT_READYCH: - if (st[0] & ST0_SEEK_END) { - TRACE(ft_t_flow, "drive poll completed"); - } else { - TRACE(ft_t_flow, "ready change %s",fdc_mode_txt(mode)); - } - break; - default: - break; - } - TRACE_EXIT cause; -} - -static void update_history(error_cause cause) -{ - switch (cause) { - case id_am_error: - ft_history.id_am_errors++; - break; - case id_crc_error: - ft_history.id_crc_errors++; - break; - case data_am_error: - ft_history.data_am_errors++; - break; - case data_crc_error: - ft_history.data_crc_errors++; - break; - case overrun_error: - ft_history.overrun_errors++; - break; - case no_data_error: - ft_history.no_data_errors++; - break; - default:; - } -} - -static void skip_bad_sector(buffer_struct * buff) -{ - TRACE_FUN(ft_t_any); - - /* Mark sector as soft error and skip it - */ - if (buff->remaining > 0) { - ++buff->sector_offset; - ++buff->data_offset; - --buff->remaining; - buff->ptr += FT_SECTOR_SIZE; - buff->bad_sector_map >>= 1; - } else { - /* Hey, what is this????????????? C code: if we shift - * more than 31 bits, we get no shift. That's bad!!!!!! - */ - ++buff->sector_offset; /* hack for error maps */ - TRACE(ft_t_warn, "skipping last sector in segment"); - } - TRACE_EXIT; -} - -static void update_error_maps(buffer_struct * buff, unsigned int error_offset) -{ - int hard = 0; - TRACE_FUN(ft_t_any); - - if (buff->retry < FT_SOFT_RETRIES) { - buff->soft_error_map |= (1 << error_offset); - } else { - buff->hard_error_map |= (1 << error_offset); - buff->soft_error_map &= ~buff->hard_error_map; - buff->retry = -1; /* will be set to 0 in setup_segment */ - hard = 1; - } - TRACE(ft_t_noise, "sector %d : %s error\n" - KERN_INFO "hard map: 0x%08lx\n" - KERN_INFO "soft map: 0x%08lx", - FT_SECTOR(error_offset), hard ? "hard" : "soft", - (long) buff->hard_error_map, (long) buff->soft_error_map); - TRACE_EXIT; -} - -static void print_progress(buffer_struct *buff, error_cause cause) -{ - TRACE_FUN(ft_t_any); - - switch (cause) { - case no_error: - TRACE(ft_t_flow,"%d Sector(s) transferred", buff->sector_count); - break; - case no_data_error: - TRACE(ft_t_flow, "Sector %d not found", - FT_SECTOR(buff->sector_offset)); - break; - case overrun_error: - /* got an overrun error on the first byte, must be a - * hardware problem - */ - TRACE(ft_t_bug, - "Unexpected error: failing DMA or FDC controller ?"); - break; - case data_crc_error: - TRACE(ft_t_flow, "Error in sector %d", - FT_SECTOR(buff->sector_offset - 1)); - break; - case id_crc_error: - case id_am_error: - case data_am_error: - TRACE(ft_t_flow, "Error in sector %d", - FT_SECTOR(buff->sector_offset)); - break; - default: - TRACE(ft_t_flow, "Unexpected error at sector %d", - FT_SECTOR(buff->sector_offset)); - break; - } - TRACE_EXIT; -} - -/* - * Error cause: Amount xferred: Action: - * - * id_am_error 0 mark bad and skip - * id_crc_error 0 mark bad and skip - * data_am_error 0 mark bad and skip - * data_crc_error % 1024 mark bad and skip - * no_data_error 0 retry on write - * mark bad and skip on read - * overrun_error [ 0..all-1 ] mark bad and skip - * no_error all continue - */ - -/* the arg `sector' is returned by the fdc and tells us at which sector we - * are positioned at (relative to starting sector of segment) - */ -static void determine_verify_progress(buffer_struct *buff, - error_cause cause, - __u8 sector) -{ - TRACE_FUN(ft_t_any); - - if (cause == no_error && sector == 1) { - buff->sector_offset = FT_SECTORS_PER_SEGMENT; - buff->remaining = 0; - if (TRACE_LEVEL >= ft_t_flow) { - print_progress(buff, cause); - } - } else { - buff->sector_offset = sector - buff->sect; - buff->remaining = FT_SECTORS_PER_SEGMENT - buff->sector_offset; - TRACE(ft_t_noise, "%ssector offset: 0x%04x", - (cause == no_error) ? "unexpected " : "", - buff->sector_offset); - switch (cause) { - case overrun_error: - break; -#if 0 - case no_data_error: - buff->retry = FT_SOFT_RETRIES; - if (buff->hard_error_map && - buff->sector_offset > 1 && - (buff->hard_error_map & - (1 << (buff->sector_offset-2)))) { - buff->retry --; - } - break; -#endif - default: - buff->retry = FT_SOFT_RETRIES; - break; - } - if (TRACE_LEVEL >= ft_t_flow) { - print_progress(buff, cause); - } - /* Sector_offset points to the problem area Now adjust - * sector_offset so it always points one past he failing - * sector. I.e. skip the bad sector. - */ - ++buff->sector_offset; - --buff->remaining; - update_error_maps(buff, buff->sector_offset - 1); - } - TRACE_EXIT; -} - -static void determine_progress(buffer_struct *buff, - error_cause cause, - __u8 sector) -{ - unsigned int dma_residue; - TRACE_FUN(ft_t_any); - - /* Using less preferred order of disable_dma and - * get_dma_residue because this seems to fail on at least one - * system if reversed! - */ - dma_residue = get_dma_residue(fdc.dma); - disable_dma(fdc.dma); - if (cause != no_error || dma_residue != 0) { - TRACE(ft_t_noise, "%sDMA residue: 0x%04x", - (cause == no_error) ? "unexpected " : "", - dma_residue); - /* adjust to actual value: */ - if (dma_residue == 0) { - /* this happens sometimes with overrun errors. - * I don't know whether we could ignore the - * overrun error. Play save. - */ - buff->sector_count --; - } else { - buff->sector_count -= ((dma_residue + - (FT_SECTOR_SIZE - 1)) / - FT_SECTOR_SIZE); - } - } - /* Update var's influenced by the DMA operation. - */ - if (buff->sector_count > 0) { - buff->sector_offset += buff->sector_count; - buff->data_offset += buff->sector_count; - buff->ptr += (buff->sector_count * - FT_SECTOR_SIZE); - buff->remaining -= buff->sector_count; - buff->bad_sector_map >>= buff->sector_count; - } - if (TRACE_LEVEL >= ft_t_flow) { - print_progress(buff, cause); - } - if (cause != no_error) { - if (buff->remaining == 0) { - TRACE(ft_t_warn, "foo?\n" - KERN_INFO "count : %d\n" - KERN_INFO "offset: %d\n" - KERN_INFO "soft : %08x\n" - KERN_INFO "hard : %08x", - buff->sector_count, - buff->sector_offset, - buff->soft_error_map, - buff->hard_error_map); - } - /* Sector_offset points to the problem area, except if we got - * a data_crc_error. In that case it points one past the - * failing sector. - * - * Now adjust sector_offset so it always points one past he - * failing sector. I.e. skip the bad sector. - */ - if (cause != data_crc_error) { - skip_bad_sector(buff); - } - update_error_maps(buff, buff->sector_offset - 1); - } - TRACE_EXIT; -} - -static int calc_steps(int cmd) -{ - if (ftape_current_cylinder > cmd) { - return ftape_current_cylinder - cmd; - } else { - return ftape_current_cylinder + cmd; - } -} - -static void pause_tape(int retry, int mode) -{ - int result; - __u8 out[3] = {FDC_SEEK, ft_drive_sel, 0}; - TRACE_FUN(ft_t_any); - - /* We'll use a raw seek command to get the tape to rewind and - * stop for a retry. - */ - ++ft_history.rewinds; - if (qic117_cmds[ftape_current_command].non_intr) { - TRACE(ft_t_warn, "motion command may be issued too soon"); - } - if (retry && (mode == fdc_reading_data || - mode == fdc_reading_id || - mode == fdc_verifying)) { - ftape_current_command = QIC_MICRO_STEP_PAUSE; - ftape_might_be_off_track = 1; - } else { - ftape_current_command = QIC_PAUSE; - } - out[2] = calc_steps(ftape_current_command); - result = fdc_command(out, 3); /* issue QIC_117 command */ - ftape_current_cylinder = out[ 2]; - if (result < 0) { - TRACE(ft_t_noise, "qic-pause failed, status = %d", result); - } else { - ft_location.known = 0; - ft_runner_status = idle; - ft_hide_interrupt = 1; - ftape_tape_running = 0; - } - TRACE_EXIT; -} - -static void continue_xfer(buffer_struct *buff, - fdc_mode_enum mode, - unsigned int skip) -{ - int write = 0; - TRACE_FUN(ft_t_any); - - if (mode == fdc_writing_data || mode == fdc_deleting) { - write = 1; - } - /* This part can be removed if it never happens - */ - if (skip > 0 && - (ft_runner_status != running || - (write && (buff->status != writing)) || - (!write && (buff->status != reading && - buff->status != verifying)))) { - TRACE(ft_t_err, "unexpected runner/buffer state %d/%d", - ft_runner_status, buff->status); - buff->status = error; - /* finish this buffer: */ - (void)ftape_next_buffer(ft_queue_head); - ft_runner_status = aborting; - fdc_mode = fdc_idle; - } else if (buff->remaining > 0 && ftape_calc_next_cluster(buff) > 0) { - /* still sectors left in current segment, continue - * with this segment - */ - if (fdc_setup_read_write(buff, mode) < 0) { - /* failed, abort operation - */ - buff->bytes = buff->ptr - buff->address; - buff->status = error; - /* finish this buffer: */ - (void)ftape_next_buffer(ft_queue_head); - ft_runner_status = aborting; - fdc_mode = fdc_idle; - } - } else { - /* current segment completed - */ - unsigned int last_segment = buff->segment_id; - int eot = ((last_segment + 1) % ft_segments_per_track) == 0; - unsigned int next = buff->next_segment; /* 0 means stop ! */ - - buff->bytes = buff->ptr - buff->address; - buff->status = done; - buff = ftape_next_buffer(ft_queue_head); - if (eot) { - /* finished last segment on current track, - * can't continue - */ - ft_runner_status = logical_eot; - fdc_mode = fdc_idle; - TRACE_EXIT; - } - if (next <= 0) { - /* don't continue with next segment - */ - TRACE(ft_t_noise, "no %s allowed, stopping tape", - (write) ? "write next" : "read ahead"); - pause_tape(0, mode); - ft_runner_status = idle; /* not quite true until - * next irq - */ - TRACE_EXIT; - } - /* continue with next segment - */ - if (buff->status != waiting) { - TRACE(ft_t_noise, "all input buffers %s, pausing tape", - (write) ? "empty" : "full"); - pause_tape(0, mode); - ft_runner_status = idle; /* not quite true until - * next irq - */ - TRACE_EXIT; - } - if (write && next != buff->segment_id) { - TRACE(ft_t_noise, - "segments out of order, aborting write"); - ft_runner_status = do_abort; - fdc_mode = fdc_idle; - TRACE_EXIT; - } - ftape_setup_new_segment(buff, next, 0); - if (stop_read_ahead) { - buff->next_segment = 0; - stop_read_ahead = 0; - } - if (ftape_calc_next_cluster(buff) == 0 || - fdc_setup_read_write(buff, mode) != 0) { - TRACE(ft_t_err, "couldn't start %s-ahead", - write ? "write" : "read"); - ft_runner_status = do_abort; - fdc_mode = fdc_idle; - } else { - /* keep on going */ - switch (ft_driver_state) { - case reading: buff->status = reading; break; - case verifying: buff->status = verifying; break; - case writing: buff->status = writing; break; - case deleting: buff->status = deleting; break; - default: - TRACE(ft_t_err, - "BUG: ft_driver_state %d should be one out of " - "{reading, writing, verifying, deleting}", - ft_driver_state); - buff->status = write ? writing : reading; - break; - } - } - } - TRACE_EXIT; -} - -static void retry_sector(buffer_struct *buff, - int mode, - unsigned int skip) -{ - TRACE_FUN(ft_t_any); - - TRACE(ft_t_noise, "%s error, will retry", - (mode == fdc_writing_data || mode == fdc_deleting) ? "write" : "read"); - pause_tape(1, mode); - ft_runner_status = aborting; - buff->status = error; - buff->skip = skip; - TRACE_EXIT; -} - -static unsigned int find_resume_point(buffer_struct *buff) -{ - int i = 0; - SectorMap mask; - SectorMap map; - TRACE_FUN(ft_t_any); - - /* This function is to be called after all variables have been - * updated to point past the failing sector. - * If there are any soft errors before the failing sector, - * find the first soft error and return the sector offset. - * Otherwise find the last hard error. - * Note: there should always be at least one hard or soft error ! - */ - if (buff->sector_offset < 1 || buff->sector_offset > 32) { - TRACE(ft_t_bug, "BUG: sector_offset = %d", - buff->sector_offset); - TRACE_EXIT 0; - } - if (buff->sector_offset >= 32) { /* C-limitation on shift ! */ - mask = 0xffffffff; - } else { - mask = (1 << buff->sector_offset) - 1; - } - map = buff->soft_error_map & mask; - if (map) { - while ((map & (1 << i)) == 0) { - ++i; - } - TRACE(ft_t_noise, "at sector %d", FT_SECTOR(i)); - } else { - map = buff->hard_error_map & mask; - i = buff->sector_offset - 1; - if (map) { - while ((map & (1 << i)) == 0) { - --i; - } - TRACE(ft_t_noise, "after sector %d", FT_SECTOR(i)); - ++i; /* first sector after last hard error */ - } else { - TRACE(ft_t_bug, "BUG: no soft or hard errors"); - } - } - TRACE_EXIT i; -} - -/* check possible dma residue when formatting, update position record in - * buffer struct. This is, of course, modelled after determine_progress(), but - * we don't need to set up for retries because the format process cannot be - * interrupted (except at the end of the tape track). - */ -static int determine_fmt_progress(buffer_struct *buff, error_cause cause) -{ - unsigned int dma_residue; - TRACE_FUN(ft_t_any); - - /* Using less preferred order of disable_dma and - * get_dma_residue because this seems to fail on at least one - * system if reversed! - */ - dma_residue = get_dma_residue(fdc.dma); - disable_dma(fdc.dma); - if (cause != no_error || dma_residue != 0) { - TRACE(ft_t_info, "DMA residue = 0x%04x", dma_residue); - fdc_mode = fdc_idle; - switch(cause) { - case no_error: - ft_runner_status = aborting; - buff->status = idle; - break; - case overrun_error: - /* got an overrun error on the first byte, must be a - * hardware problem - */ - TRACE(ft_t_bug, - "Unexpected error: failing DMA controller ?"); - ft_runner_status = do_abort; - buff->status = error; - break; - default: - TRACE(ft_t_noise, "Unexpected error at segment %d", - buff->segment_id); - ft_runner_status = do_abort; - buff->status = error; - break; - } - TRACE_EXIT -EIO; /* can only retry entire track in format mode - */ - } - /* Update var's influenced by the DMA operation. - */ - buff->ptr += FT_SECTORS_PER_SEGMENT * 4; - buff->bytes -= FT_SECTORS_PER_SEGMENT * 4; - buff->remaining -= FT_SECTORS_PER_SEGMENT; - buff->segment_id ++; /* done with segment */ - TRACE_EXIT 0; -} - -/* - * Continue formatting, switch buffers if there is no data left in - * current buffer. This is, of course, modelled after - * continue_xfer(), but we don't need to set up for retries because - * the format process cannot be interrupted (except at the end of the - * tape track). - */ -static void continue_formatting(buffer_struct *buff) -{ - TRACE_FUN(ft_t_any); - - if (buff->remaining <= 0) { /* no space left in dma buffer */ - unsigned int next = buff->next_segment; - - if (next == 0) { /* end of tape track */ - buff->status = done; - ft_runner_status = logical_eot; - fdc_mode = fdc_idle; - TRACE(ft_t_noise, "Done formatting track %d", - ft_location.track); - TRACE_EXIT; - } - /* - * switch to next buffer! - */ - buff->status = done; - buff = ftape_next_buffer(ft_queue_head); - - if (buff->status != waiting || next != buff->segment_id) { - goto format_setup_error; - } - } - if (fdc_setup_formatting(buff) < 0) { - goto format_setup_error; - } - buff->status = formatting; - TRACE(ft_t_fdc_dma, "Formatting segment %d on track %d", - buff->segment_id, ft_location.track); - TRACE_EXIT; - format_setup_error: - ft_runner_status = do_abort; - fdc_mode = fdc_idle; - buff->status = error; - TRACE(ft_t_err, "Error setting up for segment %d on track %d", - buff->segment_id, ft_location.track); - TRACE_EXIT; - -} - -/* this handles writing, read id, reading and formatting - */ -static void handle_fdc_busy(buffer_struct *buff) -{ - static int no_data_error_count; - int retry = 0; - error_cause cause; - __u8 in[7]; - int skip; - fdc_mode_enum fmode = fdc_mode; - TRACE_FUN(ft_t_any); - - if (fdc_result(in, 7) < 0) { /* better get it fast ! */ - TRACE(ft_t_err, - "Probably fatal error during FDC Result Phase\n" - KERN_INFO - "drive may hang until (power on) reset :-("); - /* what to do next ???? - */ - TRACE_EXIT; - } - cause = decode_irq_cause(fdc_mode, in); -#ifdef TESTING - { int i; - for (i = 0; i < (int)ft_nr_buffers; ++i) - TRACE(ft_t_any, "buffer[%d] status: %d, segment_id: %d", - i, ft_buffer[i]->status, ft_buffer[i]->segment_id); - } -#endif - if (fmode == fdc_reading_data && ft_driver_state == verifying) { - fmode = fdc_verifying; - } - switch (fmode) { - case fdc_verifying: - if (ft_runner_status == aborting || - ft_runner_status == do_abort) { - TRACE(ft_t_noise,"aborting %s",fdc_mode_txt(fdc_mode)); - break; - } - if (buff->retry > 0) { - TRACE(ft_t_flow, "this is retry nr %d", buff->retry); - } - switch (cause) { - case no_error: - no_data_error_count = 0; - determine_verify_progress(buff, cause, in[5]); - if (in[2] & 0x40) { - /* This should not happen when verifying - */ - TRACE(ft_t_warn, - "deleted data in segment %d/%d", - buff->segment_id, - FT_SECTOR(buff->sector_offset - 1)); - buff->remaining = 0; /* abort transfer */ - buff->hard_error_map = EMPTY_SEGMENT; - skip = 1; - } else { - skip = 0; - } - continue_xfer(buff, fdc_mode, skip); - break; - case no_data_error: - no_data_error_count ++; - case overrun_error: - retry ++; - case id_am_error: - case id_crc_error: - case data_am_error: - case data_crc_error: - determine_verify_progress(buff, cause, in[5]); - if (cause == no_data_error) { - if (no_data_error_count >= 2) { - TRACE(ft_t_warn, - "retrying because of successive " - "no data errors"); - no_data_error_count = 0; - } else { - retry --; - } - } else { - no_data_error_count = 0; - } - if (retry) { - skip = find_resume_point(buff); - } else { - skip = buff->sector_offset; - } - if (retry && skip < 32) { - retry_sector(buff, fdc_mode, skip); - } else { - continue_xfer(buff, fdc_mode, skip); - } - update_history(cause); - break; - default: - /* Don't know why this could happen - * but find out. - */ - determine_verify_progress(buff, cause, in[5]); - retry_sector(buff, fdc_mode, 0); - TRACE(ft_t_err, "Error: unexpected error"); - break; - } - break; - case fdc_reading_data: -#ifdef TESTING - /* I'm sorry, but: NOBODY ever used this trace - * messages for ages. I guess that Bas was the last person - * that ever really used this (thank you, between the lines) - */ - if (cause == no_error) { - TRACE(ft_t_flow,"reading segment %d",buff->segment_id); - } else { - TRACE(ft_t_noise, "error reading segment %d", - buff->segment_id); - TRACE(ft_t_noise, "\n" - KERN_INFO - "IRQ:C: 0x%02x, H: 0x%02x, R: 0x%02x, N: 0x%02x\n" - KERN_INFO - "BUF:C: 0x%02x, H: 0x%02x, R: 0x%02x", - in[3], in[4], in[5], in[6], - buff->cyl, buff->head, buff->sect); - } -#endif - if (ft_runner_status == aborting || - ft_runner_status == do_abort) { - TRACE(ft_t_noise,"aborting %s",fdc_mode_txt(fdc_mode)); - break; - } - if (buff->bad_sector_map == FAKE_SEGMENT) { - /* This condition occurs when reading a `fake' - * sector that's not accessible. Doesn't - * really matter as we would have ignored it - * anyway ! - * - * Chance is that we're past the next segment - * now, so the next operation may fail and - * result in a retry. - */ - buff->remaining = 0; /* skip failing sector */ - /* buff->ptr = buff->address; */ - /* fake success: */ - continue_xfer(buff, fdc_mode, 1); - /* trace calls are expensive: place them AFTER - * the real stuff has been done. - * - */ - TRACE(ft_t_noise, "skipping empty segment %d (read), size? %d", - buff->segment_id, buff->ptr - buff->address); - TRACE_EXIT; - } - if (buff->retry > 0) { - TRACE(ft_t_flow, "this is retry nr %d", buff->retry); - } - switch (cause) { - case no_error: - determine_progress(buff, cause, in[5]); - if (in[2] & 0x40) { - /* Handle deleted data in header segments. - * Skip segment and force read-ahead. - */ - TRACE(ft_t_warn, - "deleted data in segment %d/%d", - buff->segment_id, - FT_SECTOR(buff->sector_offset - 1)); - buff->deleted = 1; - buff->remaining = 0;/*abort transfer */ - buff->soft_error_map |= - (-1L << buff->sector_offset); - if (buff->segment_id == 0) { - /* stop on next segment */ - stop_read_ahead = 1; - } - /* force read-ahead: */ - buff->next_segment = - buff->segment_id + 1; - skip = (FT_SECTORS_PER_SEGMENT - - buff->sector_offset); - } else { - skip = 0; - } - continue_xfer(buff, fdc_mode, skip); - break; - case no_data_error: - /* Tape started too far ahead of or behind the - * right sector. This may also happen in the - * middle of a segment ! - * - * Handle no-data as soft error. If next - * sector fails too, a retry (with needed - * reposition) will follow. - */ - retry ++; - case id_am_error: - case id_crc_error: - case data_am_error: - case data_crc_error: - case overrun_error: - retry += (buff->soft_error_map != 0 || - buff->hard_error_map != 0); - determine_progress(buff, cause, in[5]); -#if 1 || defined(TESTING) - if (cause == overrun_error) retry ++; -#endif - if (retry) { - skip = find_resume_point(buff); - } else { - skip = buff->sector_offset; - } - /* Try to resume with next sector on single - * errors (let ecc correct it), but retry on - * no_data (we'll be past the target when we - * get here so we cannot retry) or on - * multiple errors (reduce chance on ecc - * failure). - */ - /* cH: 23/02/97: if the last sector in the - * segment was a hard error, then there is - * no sense in a retry. This occasion seldom - * occurs but ... @:³²¸`@%&§$ - */ - if (retry && skip < 32) { - retry_sector(buff, fdc_mode, skip); - } else { - continue_xfer(buff, fdc_mode, skip); - } - update_history(cause); - break; - default: - /* Don't know why this could happen - * but find out. - */ - determine_progress(buff, cause, in[5]); - retry_sector(buff, fdc_mode, 0); - TRACE(ft_t_err, "Error: unexpected error"); - break; - } - break; - case fdc_reading_id: - if (cause == no_error) { - fdc_cyl = in[3]; - fdc_head = in[4]; - fdc_sect = in[5]; - TRACE(ft_t_fdc_dma, - "id read: C: 0x%02x, H: 0x%02x, R: 0x%02x", - fdc_cyl, fdc_head, fdc_sect); - } else { /* no valid information, use invalid sector */ - fdc_cyl = fdc_head = fdc_sect = 0; - TRACE(ft_t_flow, "Didn't find valid sector Id"); - } - fdc_mode = fdc_idle; - break; - case fdc_deleting: - case fdc_writing_data: -#ifdef TESTING - if (cause == no_error) { - TRACE(ft_t_flow, "writing segment %d", buff->segment_id); - } else { - TRACE(ft_t_noise, "error writing segment %d", - buff->segment_id); - } -#endif - if (ft_runner_status == aborting || - ft_runner_status == do_abort) { - TRACE(ft_t_flow, "aborting %s",fdc_mode_txt(fdc_mode)); - break; - } - if (buff->retry > 0) { - TRACE(ft_t_flow, "this is retry nr %d", buff->retry); - } - if (buff->bad_sector_map == FAKE_SEGMENT) { - /* This condition occurs when trying to write to a - * `fake' sector that's not accessible. Doesn't really - * matter as it isn't used anyway ! Might be located - * at wrong segment, then we'll fail on the next - * segment. - */ - TRACE(ft_t_noise, "skipping empty segment (write)"); - buff->remaining = 0; /* skip failing sector */ - /* fake success: */ - continue_xfer(buff, fdc_mode, 1); - break; - } - switch (cause) { - case no_error: - determine_progress(buff, cause, in[5]); - continue_xfer(buff, fdc_mode, 0); - break; - case no_data_error: - case id_am_error: - case id_crc_error: - case data_am_error: - case overrun_error: - update_history(cause); - determine_progress(buff, cause, in[5]); - skip = find_resume_point(buff); - retry_sector(buff, fdc_mode, skip); - break; - default: - if (in[1] & 0x02) { - TRACE(ft_t_err, "media not writable"); - } else { - TRACE(ft_t_bug, "unforeseen write error"); - } - fdc_mode = fdc_idle; - break; - } - break; /* fdc_deleting || fdc_writing_data */ - case fdc_formatting: - /* The interrupt comes after formatting a segment. We then - * have to set up QUICKLY for the next segment. But - * afterwards, there is plenty of time. - */ - switch (cause) { - case no_error: - /* would like to keep most of the formatting stuff - * outside the isr code, but timing is too critical - */ - if (determine_fmt_progress(buff, cause) >= 0) { - continue_formatting(buff); - } - break; - case no_data_error: - case id_am_error: - case id_crc_error: - case data_am_error: - case overrun_error: - default: - determine_fmt_progress(buff, cause); - update_history(cause); - if (in[1] & 0x02) { - TRACE(ft_t_err, "media not writable"); - } else { - TRACE(ft_t_bug, "unforeseen write error"); - } - break; - } /* cause */ - break; - default: - TRACE(ft_t_warn, "Warning: unexpected irq during: %s", - fdc_mode_txt(fdc_mode)); - fdc_mode = fdc_idle; - break; - } - TRACE_EXIT; -} - -/* FDC interrupt service routine. - */ -void fdc_isr(void) -{ - static int isr_active; -#ifdef TESTING - unsigned int t0 = ftape_timestamp(); -#endif - TRACE_FUN(ft_t_any); - - if (isr_active++) { - --isr_active; - TRACE(ft_t_bug, "BUG: nested interrupt, not good !"); - *fdc.hook = fdc_isr; /* hook our handler into the fdc - * code again - */ - TRACE_EXIT; - } - sti(); - if (inb_p(fdc.msr) & FDC_BUSY) { /* Entering Result Phase */ - ft_hide_interrupt = 0; - handle_fdc_busy(ftape_get_buffer(ft_queue_head)); - if (ft_runner_status == do_abort) { - /* cease operation, remember tape position - */ - TRACE(ft_t_flow, "runner aborting"); - ft_runner_status = aborting; - ++ft_expected_stray_interrupts; - } - } else { /* !FDC_BUSY */ - /* clear interrupt, cause should be gotten by issuing - * a Sense Interrupt Status command. - */ - if (fdc_mode == fdc_recalibrating || fdc_mode == fdc_seeking) { - if (ft_hide_interrupt) { - int st0; - int pcn; - - if (fdc_sense_interrupt_status(&st0, &pcn) < 0) - TRACE(ft_t_err, - "sense interrupt status failed"); - ftape_current_cylinder = pcn; - TRACE(ft_t_flow, "handled hidden interrupt"); - } - ft_seek_completed = 1; - fdc_mode = fdc_idle; - } else if (!waitqueue_active(&ftape_wait_intr)) { - if (ft_expected_stray_interrupts == 0) { - TRACE(ft_t_warn, "unexpected stray interrupt"); - } else { - TRACE(ft_t_flow, "expected stray interrupt"); - --ft_expected_stray_interrupts; - } - } else { - if (fdc_mode == fdc_reading_data || - fdc_mode == fdc_verifying || - fdc_mode == fdc_writing_data || - fdc_mode == fdc_deleting || - fdc_mode == fdc_formatting || - fdc_mode == fdc_reading_id) { - if (inb_p(fdc.msr) & FDC_BUSY) { - TRACE(ft_t_bug, - "***** FDC failure, busy too late"); - } else { - TRACE(ft_t_bug, - "***** FDC failure, no busy"); - } - } else { - TRACE(ft_t_fdc_dma, "awaited stray interrupt"); - } - } - ft_hide_interrupt = 0; - } - /* Handle sleep code. - */ - if (!ft_hide_interrupt) { - ft_interrupt_seen ++; - if (waitqueue_active(&ftape_wait_intr)) { - wake_up_interruptible(&ftape_wait_intr); - } - } else { - TRACE(ft_t_flow, "hiding interrupt while %s", - waitqueue_active(&ftape_wait_intr) ? "waiting":"active"); - } -#ifdef TESTING - t0 = ftape_timediff(t0, ftape_timestamp()); - if (t0 >= 1000) { - /* only tell us about long calls */ - TRACE(ft_t_noise, "isr() duration: %5d usec", t0); - } -#endif - *fdc.hook = fdc_isr; /* hook our handler into the fdc code again */ - --isr_active; - TRACE_EXIT; -} diff --git a/drivers/char/ftape/lowlevel/fdc-isr.h b/drivers/char/ftape/lowlevel/fdc-isr.h deleted file mode 100644 index 065aa978942d..000000000000 --- a/drivers/char/ftape/lowlevel/fdc-isr.h +++ /dev/null @@ -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 diff --git a/drivers/char/ftape/lowlevel/ftape-bsm.c b/drivers/char/ftape/lowlevel/ftape-bsm.c deleted file mode 100644 index d1a301cc344f..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-bsm.c +++ /dev/null @@ -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; -} diff --git a/drivers/char/ftape/lowlevel/ftape-bsm.h b/drivers/char/ftape/lowlevel/ftape-bsm.h deleted file mode 100644 index ed45465af4d4..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-bsm.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef _FTAPE_BSM_H -#define _FTAPE_BSM_H - -/* - * Copyright (C) 1994-1996 Bas Laarhoven, - * (C) 1996-1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-bsm.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:07 $ - * - * This file contains definitions for the bad sector map handling - * routines for the QIC-117 floppy-tape driver for Linux. - */ - -#include <linux/ftape.h> -#include <linux/ftape-header-segment.h> - -#define EMPTY_SEGMENT (0xffffffff) -#define FAKE_SEGMENT (0xfffffffe) - -/* maximum (format code 4) bad sector map size (bytes). - */ -#define BAD_SECTOR_MAP_SIZE (29 * SECTOR_SIZE - 256) - -/* format code 4 bad sector entry, ftape uses this - * internally for all format codes - */ -typedef __u32 SectorMap; -/* variable and 1100 ft bad sector map entry. These three bytes represent - * a single sector address measured from BOT. - */ -typedef struct NewSectorMap { - __u8 bytes[3]; -} SectorCount; - - -/* - * ftape-bsm.c defined global vars. - */ - -/* - * ftape-bsm.c defined global functions. - */ -extern void update_bad_sector_map(__u8 * buffer); -extern void ftape_extract_bad_sector_map(__u8 * buffer); -extern SectorMap ftape_get_bad_sector_entry(int segment_id); -extern __u8 *ftape_find_end_of_bsm_list(__u8 * address); -extern void ftape_init_bsm(void); - -#endif diff --git a/drivers/char/ftape/lowlevel/ftape-buffer.c b/drivers/char/ftape/lowlevel/ftape-buffer.c deleted file mode 100644 index c706ff162771..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-buffer.c +++ /dev/null @@ -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; -} diff --git a/drivers/char/ftape/lowlevel/ftape-buffer.h b/drivers/char/ftape/lowlevel/ftape-buffer.h deleted file mode 100644 index eec99cee8f82..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-buffer.h +++ /dev/null @@ -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 diff --git a/drivers/char/ftape/lowlevel/ftape-calibr.c b/drivers/char/ftape/lowlevel/ftape-calibr.c deleted file mode 100644 index 8e50bfd35a52..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-calibr.c +++ /dev/null @@ -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; -} diff --git a/drivers/char/ftape/lowlevel/ftape-calibr.h b/drivers/char/ftape/lowlevel/ftape-calibr.h deleted file mode 100644 index 0c7e75246c7d..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-calibr.h +++ /dev/null @@ -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 */ diff --git a/drivers/char/ftape/lowlevel/ftape-ctl.c b/drivers/char/ftape/lowlevel/ftape-ctl.c deleted file mode 100644 index 5d7c1ce92d59..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-ctl.c +++ /dev/null @@ -1,896 +0,0 @@ -/* - * Copyright (C) 1993-1996 Bas Laarhoven, - * 1996-1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-ctl.c,v $ - * $Revision: 1.4 $ - * $Date: 1997/11/11 14:37:44 $ - * - * This file contains the non-read/write ftape functions for the - * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. - */ - -#include <linux/errno.h> -#include <linux/mm.h> -#include <linux/mman.h> - -#include <linux/ftape.h> -#include <linux/qic117.h> -#include <asm/uaccess.h> -#include <asm/io.h> - -/* ease porting between pre-2.4.x and later kernels */ -#define vma_get_pgoff(v) ((v)->vm_pgoff) - -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-write.h" -#include "../lowlevel/ftape-read.h" -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/ftape-bsm.h" - -/* Global vars. - */ -ftape_info ftape_status = { -/* vendor information */ - { 0, }, /* drive type */ -/* data rates */ - 500, /* used data rate */ - 500, /* drive max rate */ - 500, /* fdc max rate */ -/* drive selection, either FTAPE_SEL_A/B/C/D */ - -1, /* drive selection */ -/* flags set after decode the drive and tape status */ - 0, /* formatted */ - 1, /* no tape */ - 1, /* write protected */ - 1, /* new tape */ -/* values of last queried drive/tape status and error */ - {{0,}}, /* last error code */ - {{0,}}, /* drive status, configuration, tape status */ -/* cartridge geometry */ - 20, /* tracks_per_tape */ - 102, /* segments_per_track */ -/* location of header segments, etc. */ - -1, /* used_header_segment */ - -1, /* header_segment_1 */ - -1, /* header_segment_2 */ - -1, /* first_data_segment */ - -1, /* last_data_segment */ -/* the format code as stored in the header segment */ - fmt_normal, /* format code */ -/* the default for the qic std: unknown */ - -1, -/* is tape running? */ - idle, /* runner_state */ -/* is tape reading/writing/verifying/formatting/deleting */ - idle, /* driver state */ -/* flags fatal hardware error */ - 1, /* failure */ -/* history record */ - { 0, } /* history record */ -}; - -int ftape_segments_per_head = 1020; -int ftape_segments_per_cylinder = 4; -int ftape_init_drive_needed = 1; /* need to be global for ftape_reset_drive() - * in ftape-io.c - */ - -/* Local vars. - */ -static const vendor_struct vendors[] = QIC117_VENDORS; -static const wakeup_method methods[] = WAKEUP_METHODS; - -const ftape_info *ftape_get_status(void) -{ -#if defined(STATUS_PARANOYA) - static ftape_info get_status; - - get_status = ftape_status; - return &get_status; -#else - return &ftape_status; /* maybe return only a copy of it to assure - * read only access - */ -#endif -} - -static int ftape_not_operational(int status) -{ - /* return true if status indicates tape can not be used. - */ - return ((status ^ QIC_STATUS_CARTRIDGE_PRESENT) & - (QIC_STATUS_ERROR | - QIC_STATUS_CARTRIDGE_PRESENT | - QIC_STATUS_NEW_CARTRIDGE)); -} - -int ftape_seek_to_eot(void) -{ - int status; - TRACE_FUN(ft_t_any); - - TRACE_CATCH(ftape_ready_wait(ftape_timeout.pause, &status),); - while ((status & QIC_STATUS_AT_EOT) == 0) { - if (ftape_not_operational(status)) { - TRACE_EXIT -EIO; - } - TRACE_CATCH(ftape_command_wait(QIC_PHYSICAL_FORWARD, - ftape_timeout.rewind,&status),); - } - TRACE_EXIT 0; -} - -int ftape_seek_to_bot(void) -{ - int status; - TRACE_FUN(ft_t_any); - - TRACE_CATCH(ftape_ready_wait(ftape_timeout.pause, &status),); - while ((status & QIC_STATUS_AT_BOT) == 0) { - if (ftape_not_operational(status)) { - TRACE_EXIT -EIO; - } - TRACE_CATCH(ftape_command_wait(QIC_PHYSICAL_REVERSE, - ftape_timeout.rewind,&status),); - } - TRACE_EXIT 0; -} - -static int ftape_new_cartridge(void) -{ - ft_location.track = -1; /* force seek on first access */ - ftape_zap_read_buffers(); - ftape_zap_write_buffers(); - return 0; -} - -int ftape_abort_operation(void) -{ - int result = 0; - int status; - TRACE_FUN(ft_t_flow); - - if (ft_runner_status == running) { - TRACE(ft_t_noise, "aborting runner, waiting"); - - ft_runner_status = do_abort; - /* set timeout so that the tape will run to logical EOT - * if we missed the last sector and there are no queue pulses. - */ - result = ftape_dumb_stop(); - } - if (ft_runner_status != idle) { - if (ft_runner_status == do_abort) { - TRACE(ft_t_noise, "forcing runner abort"); - } - TRACE(ft_t_noise, "stopping tape"); - result = ftape_stop_tape(&status); - ft_location.known = 0; - ft_runner_status = idle; - } - ftape_reset_buffer(); - ftape_zap_read_buffers(); - ftape_set_state(idle); - TRACE_EXIT result; -} - -static int lookup_vendor_id(unsigned int vendor_id) -{ - int i = 0; - - while (vendors[i].vendor_id != vendor_id) { - if (++i >= NR_ITEMS(vendors)) { - return -1; - } - } - return i; -} - -static void ftape_detach_drive(void) -{ - TRACE_FUN(ft_t_any); - - TRACE(ft_t_flow, "disabling tape drive and fdc"); - ftape_put_drive_to_sleep(ft_drive_type.wake_up); - fdc_catch_stray_interrupts(1); /* one always comes */ - fdc_disable(); - fdc_release_irq_and_dma(); - fdc_release_regions(); - TRACE_EXIT; -} - -static void clear_history(void) -{ - ft_history.used = 0; - ft_history.id_am_errors = - ft_history.id_crc_errors = - ft_history.data_am_errors = - ft_history.data_crc_errors = - ft_history.overrun_errors = - ft_history.no_data_errors = - ft_history.retries = - ft_history.crc_errors = - ft_history.crc_failures = - ft_history.ecc_failures = - ft_history.corrected = - ft_history.defects = - ft_history.rewinds = 0; -} - -static int ftape_activate_drive(vendor_struct * drive_type) -{ - int result = 0; - TRACE_FUN(ft_t_flow); - - /* If we already know the drive type, wake it up. - * Else try to find out what kind of drive is attached. - */ - if (drive_type->wake_up != unknown_wake_up) { - TRACE(ft_t_flow, "enabling tape drive and fdc"); - result = ftape_wakeup_drive(drive_type->wake_up); - if (result < 0) { - TRACE(ft_t_err, "known wakeup method failed"); - } - } else { - wake_up_types method; - const ft_trace_t old_tracing = TRACE_LEVEL; - if (TRACE_LEVEL < ft_t_flow) { - SET_TRACE_LEVEL(ft_t_bug); - } - - /* Try to awaken the drive using all known methods. - * Lower tracing for a while. - */ - for (method=no_wake_up; method < NR_ITEMS(methods); ++method) { - drive_type->wake_up = method; -#ifdef CONFIG_FT_TWO_DRIVES - /* Test setup for dual drive configuration. - * /dev/rft2 uses mountain wakeup - * /dev/rft3 uses colorado wakeup - * Other systems will use the normal scheme. - */ - if ((ft_drive_sel < 2) || - (ft_drive_sel == 2 && method == FT_WAKE_UP_1) || - (ft_drive_sel == 3 && method == FT_WAKE_UP_2)) { - result=ftape_wakeup_drive(drive_type->wake_up); - } else { - result = -EIO; - } -#else - result = ftape_wakeup_drive(drive_type->wake_up); -#endif - if (result >= 0) { - TRACE(ft_t_warn, "drive wakeup method: %s", - methods[drive_type->wake_up].name); - break; - } - } - SET_TRACE_LEVEL(old_tracing); - - if (method >= NR_ITEMS(methods)) { - /* no response at all, cannot open this drive */ - drive_type->wake_up = unknown_wake_up; - TRACE(ft_t_err, "no tape drive found !"); - result = -ENODEV; - } - } - TRACE_EXIT result; -} - -static int ftape_get_drive_status(void) -{ - int result; - int status; - TRACE_FUN(ft_t_flow); - - ft_no_tape = ft_write_protected = 0; - /* Tape drive is activated now. - * First clear error status if present. - */ - do { - result = ftape_ready_wait(ftape_timeout.reset, &status); - if (result < 0) { - if (result == -ETIME) { - TRACE(ft_t_err, "ftape_ready_wait timeout"); - } else if (result == -EINTR) { - TRACE(ft_t_err, "ftape_ready_wait aborted"); - } else { - TRACE(ft_t_err, "ftape_ready_wait failed"); - } - TRACE_EXIT -EIO; - } - /* Clear error condition (drive is ready !) - */ - if (status & QIC_STATUS_ERROR) { - unsigned int error; - qic117_cmd_t command; - - TRACE(ft_t_err, "error status set"); - result = ftape_report_error(&error, &command, 1); - if (result < 0) { - TRACE(ft_t_err, - "report_error_code failed: %d", result); - /* hope it's working next time */ - ftape_reset_drive(); - TRACE_EXIT -EIO; - } else if (error != 0) { - TRACE(ft_t_noise, "error code : %d", error); - TRACE(ft_t_noise, "error command: %d", command); - } - } - if (status & QIC_STATUS_NEW_CARTRIDGE) { - unsigned int error; - qic117_cmd_t command; - const ft_trace_t old_tracing = TRACE_LEVEL; - SET_TRACE_LEVEL(ft_t_bug); - - /* Undocumented feature: Must clear (not present!) - * error here or we'll fail later. - */ - ftape_report_error(&error, &command, 1); - - SET_TRACE_LEVEL(old_tracing); - TRACE(ft_t_info, "status: new cartridge"); - ft_new_tape = 1; - } else { - ft_new_tape = 0; - } - FT_SIGNAL_EXIT(_DONT_BLOCK); - } while (status & QIC_STATUS_ERROR); - - ft_no_tape = !(status & QIC_STATUS_CARTRIDGE_PRESENT); - ft_write_protected = (status & QIC_STATUS_WRITE_PROTECT) != 0; - if (ft_no_tape) { - TRACE(ft_t_warn, "no cartridge present"); - } else { - if (ft_write_protected) { - TRACE(ft_t_noise, "Write protected cartridge"); - } - } - TRACE_EXIT 0; -} - -static void ftape_log_vendor_id(void) -{ - int vendor_index; - TRACE_FUN(ft_t_flow); - - ftape_report_vendor_id(&ft_drive_type.vendor_id); - vendor_index = lookup_vendor_id(ft_drive_type.vendor_id); - if (ft_drive_type.vendor_id == UNKNOWN_VENDOR && - ft_drive_type.wake_up == wake_up_colorado) { - vendor_index = 0; - /* hack to get rid of all this mail */ - ft_drive_type.vendor_id = 0; - } - if (vendor_index < 0) { - /* Unknown vendor id, first time opening device. The - * drive_type remains set to type found at wakeup - * time, this will probably keep the driver operating - * for this new vendor. - */ - TRACE(ft_t_warn, "\n" - KERN_INFO "============ unknown vendor id ===========\n" - KERN_INFO "A new, yet unsupported tape drive is found\n" - KERN_INFO "Please report the following values:\n" - KERN_INFO " Vendor id : 0x%04x\n" - KERN_INFO " Wakeup method : %s\n" - KERN_INFO "And a description of your tape drive\n" - KERN_INFO "to "THE_FTAPE_MAINTAINER"\n" - KERN_INFO "==========================================", - ft_drive_type.vendor_id, - methods[ft_drive_type.wake_up].name); - ft_drive_type.speed = 0; /* unknown */ - } else { - ft_drive_type.name = vendors[vendor_index].name; - ft_drive_type.speed = vendors[vendor_index].speed; - TRACE(ft_t_info, "tape drive type: %s", ft_drive_type.name); - /* scan all methods for this vendor_id in table */ - while(ft_drive_type.wake_up != vendors[vendor_index].wake_up) { - if (vendor_index < NR_ITEMS(vendors) - 1 && - vendors[vendor_index + 1].vendor_id - == - ft_drive_type.vendor_id) { - ++vendor_index; - } else { - break; - } - } - if (ft_drive_type.wake_up != vendors[vendor_index].wake_up) { - TRACE(ft_t_warn, "\n" - KERN_INFO "==========================================\n" - KERN_INFO "wakeup type mismatch:\n" - KERN_INFO "found: %s, expected: %s\n" - KERN_INFO "please report this to "THE_FTAPE_MAINTAINER"\n" - KERN_INFO "==========================================", - methods[ft_drive_type.wake_up].name, - methods[vendors[vendor_index].wake_up].name); - } - } - TRACE_EXIT; -} - -void ftape_calc_timeouts(unsigned int qic_std, - unsigned int data_rate, - unsigned int tape_len) -{ - int speed; /* deci-ips ! */ - int ff_speed; - int length; - TRACE_FUN(ft_t_any); - - /* tape transport speed - * data rate: QIC-40 QIC-80 QIC-3010 QIC-3020 - * - * 250 Kbps 25 ips n/a n/a n/a - * 500 Kbps 50 ips 34 ips 22.6 ips n/a - * 1 Mbps n/a 68 ips 45.2 ips 22.6 ips - * 2 Mbps n/a n/a n/a 45.2 ips - * - * fast tape transport speed is at least 68 ips. - */ - switch (qic_std) { - case QIC_TAPE_QIC40: - speed = (data_rate == 250) ? 250 : 500; - break; - case QIC_TAPE_QIC80: - speed = (data_rate == 500) ? 340 : 680; - break; - case QIC_TAPE_QIC3010: - speed = (data_rate == 500) ? 226 : 452; - break; - case QIC_TAPE_QIC3020: - speed = (data_rate == 1000) ? 226 : 452; - break; - default: - TRACE(ft_t_bug, "Unknown qic_std (bug) ?"); - speed = 500; - break; - } - if (ft_drive_type.speed == 0) { - unsigned long t0; - static int dt = 0; /* keep gcc from complaining */ - static int first_time = 1; - - /* Measure the time it takes to wind to EOT and back to BOT. - * If the tape length is known, calculate the rewind speed. - * Else keep the time value for calculation of the rewind - * speed later on, when the length _is_ known. - * Ask for a report only when length and speed are both known. - */ - if (first_time) { - ftape_seek_to_bot(); - t0 = jiffies; - ftape_seek_to_eot(); - ftape_seek_to_bot(); - dt = (int) (((jiffies - t0) * FT_USPT) / 1000); - if (dt < 1) { - dt = 1; /* prevent div by zero on failures */ - } - first_time = 0; - TRACE(ft_t_info, - "trying to determine seek timeout, got %d msec", - dt); - } - if (tape_len != 0) { - ft_drive_type.speed = - (2 * 12 * tape_len * 1000) / dt; - TRACE(ft_t_warn, "\n" - KERN_INFO "==========================================\n" - KERN_INFO "drive type: %s\n" - KERN_INFO "delta time = %d ms, length = %d ft\n" - KERN_INFO "has a maximum tape speed of %d ips\n" - KERN_INFO "please report this to "THE_FTAPE_MAINTAINER"\n" - KERN_INFO "==========================================", - ft_drive_type.name, dt, tape_len, - ft_drive_type.speed); - } - } - /* Handle unknown length tapes as very long ones. We'll - * determine the actual length from a header segment later. - * This is normal for all modern (Wide,TR1/2/3) formats. - */ - if (tape_len <= 0) { - TRACE(ft_t_noise, - "Unknown tape length, using maximal timeouts"); - length = QIC_TOP_TAPE_LEN; /* use worst case values */ - } else { - length = tape_len; /* use actual values */ - } - if (ft_drive_type.speed == 0) { - ff_speed = speed; - } else { - ff_speed = ft_drive_type.speed; - } - /* time to go from bot to eot at normal speed (data rate): - * time = (1+delta) * length (ft) * 12 (inch/ft) / speed (ips) - * delta = 10 % for seek speed, 20 % for rewind speed. - */ - ftape_timeout.seek = (length * 132 * FT_SECOND) / speed; - ftape_timeout.rewind = (length * 144 * FT_SECOND) / (10 * ff_speed); - ftape_timeout.reset = 20 * FT_SECOND + ftape_timeout.rewind; - TRACE(ft_t_noise, "timeouts for speed = %d, length = %d\n" - KERN_INFO "seek timeout : %d sec\n" - KERN_INFO "rewind timeout: %d sec\n" - KERN_INFO "reset timeout : %d sec", - speed, length, - (ftape_timeout.seek + 500) / 1000, - (ftape_timeout.rewind + 500) / 1000, - (ftape_timeout.reset + 500) / 1000); - TRACE_EXIT; -} - -/* This function calibrates the datarate (i.e. determines the maximal - * usable data rate) and sets the global variable ft_qic_std to qic_std - * - */ -int ftape_calibrate_data_rate(unsigned int qic_std) -{ - int rate = ft_fdc_rate_limit; - int result; - TRACE_FUN(ft_t_flow); - - ft_qic_std = qic_std; - - if (ft_qic_std == -1) { - TRACE_ABORT(-EIO, ft_t_err, - "Unable to determine data rate if QIC standard is unknown"); - } - - /* Select highest rate supported by both fdc and drive. - * Start with highest rate supported by the fdc. - */ - while (fdc_set_data_rate(rate) < 0 && rate > 250) { - rate /= 2; - } - TRACE(ft_t_info, - "Highest FDC supported data rate: %d Kbps", rate); - ft_fdc_max_rate = rate; - do { - result = ftape_set_data_rate(rate, ft_qic_std); - } while (result == -EINVAL && (rate /= 2) > 250); - if (result < 0) { - TRACE_ABORT(-EIO, ft_t_err, "set datarate failed"); - } - ft_data_rate = rate; - TRACE_EXIT 0; -} - -static int ftape_init_drive(void) -{ - int status; - qic_model model; - unsigned int qic_std; - unsigned int data_rate; - TRACE_FUN(ft_t_flow); - - ftape_init_drive_needed = 0; /* don't retry if this fails ? */ - TRACE_CATCH(ftape_report_raw_drive_status(&status),); - if (status & QIC_STATUS_CARTRIDGE_PRESENT) { - if (!(status & QIC_STATUS_AT_BOT)) { - /* Antique drives will get here after a soft reset, - * modern ones only if the driver is loaded when the - * tape wasn't rewound properly. - */ - /* Tape should be at bot if new cartridge ! */ - ftape_seek_to_bot(); - } - if (!(status & QIC_STATUS_REFERENCED)) { - TRACE(ft_t_flow, "starting seek_load_point"); - TRACE_CATCH(ftape_command_wait(QIC_SEEK_LOAD_POINT, - ftape_timeout.reset, - &status),); - } - } - ft_formatted = (status & QIC_STATUS_REFERENCED) != 0; - if (!ft_formatted) { - TRACE(ft_t_warn, "Warning: tape is not formatted !"); - } - - /* report configuration aborts when ftape_tape_len == -1 - * unknown qic_std is okay if not formatted. - */ - TRACE_CATCH(ftape_report_configuration(&model, - &data_rate, - &qic_std, - &ftape_tape_len),); - - /* Maybe add the following to the /proc entry - */ - TRACE(ft_t_info, "%s drive @ %d Kbps", - (model == prehistoric) ? "prehistoric" : - ((model == pre_qic117c) ? "pre QIC-117C" : - ((model == post_qic117b) ? "post QIC-117B" : - "post QIC-117D")), data_rate); - - if (ft_formatted) { - /* initialize ft_used_data_rate to maximum value - * and set ft_qic_std - */ - TRACE_CATCH(ftape_calibrate_data_rate(qic_std),); - if (ftape_tape_len == 0) { - TRACE(ft_t_info, "unknown length QIC-%s tape", - (ft_qic_std == QIC_TAPE_QIC40) ? "40" : - ((ft_qic_std == QIC_TAPE_QIC80) ? "80" : - ((ft_qic_std == QIC_TAPE_QIC3010) - ? "3010" : "3020"))); - } else { - TRACE(ft_t_info, "%d ft. QIC-%s tape", ftape_tape_len, - (ft_qic_std == QIC_TAPE_QIC40) ? "40" : - ((ft_qic_std == QIC_TAPE_QIC80) ? "80" : - ((ft_qic_std == QIC_TAPE_QIC3010) - ? "3010" : "3020"))); - } - ftape_calc_timeouts(ft_qic_std, ft_data_rate, ftape_tape_len); - /* soft write-protect QIC-40/QIC-80 cartridges used with a - * Colorado T3000 drive. Buggy hardware! - */ - if ((ft_drive_type.vendor_id == 0x011c6) && - ((ft_qic_std == QIC_TAPE_QIC40 || - ft_qic_std == QIC_TAPE_QIC80) && - !ft_write_protected)) { - TRACE(ft_t_warn, "\n" - KERN_INFO "The famous Colorado T3000 bug:\n" - KERN_INFO "%s drives can't write QIC40 and QIC80\n" - KERN_INFO "cartridges but don't set the write-protect flag!", - ft_drive_type.name); - ft_write_protected = 1; - } - } else { - /* Doesn't make too much sense to set the data rate - * because we don't know what to use for the write - * precompensation. - * Need to do this again when formatting the cartridge. - */ - ft_data_rate = data_rate; - ftape_calc_timeouts(QIC_TAPE_QIC40, - data_rate, - ftape_tape_len); - } - ftape_new_cartridge(); - TRACE_EXIT 0; -} - -static void ftape_munmap(void) -{ - int i; - TRACE_FUN(ft_t_flow); - - for (i = 0; i < ft_nr_buffers; i++) { - ft_buffer[i]->mmapped = 0; - } - TRACE_EXIT; -} - -/* Map the dma buffers into the virtual address range given by vma. - * We only check the caller doesn't map non-existent buffers. We - * don't check for multiple mappings. - */ -int ftape_mmap(struct vm_area_struct *vma) -{ - int num_buffers; - int i; - TRACE_FUN(ft_t_flow); - - if (ft_failure) { - TRACE_EXIT -ENODEV; - } - if (!(vma->vm_flags & (VM_READ|VM_WRITE))) { - TRACE_ABORT(-EINVAL, ft_t_err, "Undefined mmap() access"); - } - if (vma_get_pgoff(vma) != 0) { - TRACE_ABORT(-EINVAL, ft_t_err, "page offset must be 0"); - } - if ((vma->vm_end - vma->vm_start) % FT_BUFF_SIZE != 0) { - TRACE_ABORT(-EINVAL, ft_t_err, - "size = %ld, should be a multiple of %d", - vma->vm_end - vma->vm_start, - FT_BUFF_SIZE); - } - num_buffers = (vma->vm_end - vma->vm_start) / FT_BUFF_SIZE; - if (num_buffers > ft_nr_buffers) { - TRACE_ABORT(-EINVAL, - ft_t_err, "size = %ld, should be less than %d", - vma->vm_end - vma->vm_start, - ft_nr_buffers * FT_BUFF_SIZE); - } - if (ft_driver_state != idle) { - /* this also clears the buffer states - */ - ftape_abort_operation(); - } else { - ftape_reset_buffer(); - } - for (i = 0; i < num_buffers; i++) { - unsigned long pfn; - - pfn = virt_to_phys(ft_buffer[i]->address) >> PAGE_SHIFT; - TRACE_CATCH(remap_pfn_range(vma, vma->vm_start + - i * FT_BUFF_SIZE, - pfn, - FT_BUFF_SIZE, - vma->vm_page_prot), - _res = -EAGAIN); - TRACE(ft_t_noise, "remapped dma buffer @ %p to location @ %p", - ft_buffer[i]->address, - (void *)(vma->vm_start + i * FT_BUFF_SIZE)); - } - for (i = 0; i < num_buffers; i++) { - memset(ft_buffer[i]->address, 0xAA, FT_BUFF_SIZE); - ft_buffer[i]->mmapped++; - } - TRACE_EXIT 0; -} - -static void ftape_init_driver(void); /* forward declaration */ - -/* OPEN routine called by kernel-interface code - */ -int ftape_enable(int drive_selection) -{ - TRACE_FUN(ft_t_any); - - if (ft_drive_sel == -1 || ft_drive_sel != drive_selection) { - /* Other selection than last time - */ - ftape_init_driver(); - } - ft_drive_sel = FTAPE_SEL(drive_selection); - ft_failure = 0; - TRACE_CATCH(fdc_init(),); /* init & detect fdc */ - TRACE_CATCH(ftape_activate_drive(&ft_drive_type), - fdc_disable(); - fdc_release_irq_and_dma(); - fdc_release_regions()); - TRACE_CATCH(ftape_get_drive_status(), ftape_detach_drive()); - if (ft_drive_type.vendor_id == UNKNOWN_VENDOR) { - ftape_log_vendor_id(); - } - if (ft_new_tape) { - ftape_init_drive_needed = 1; - } - if (!ft_no_tape && ftape_init_drive_needed) { - TRACE_CATCH(ftape_init_drive(), ftape_detach_drive()); - } - ftape_munmap(); /* clear the mmap flag */ - clear_history(); - TRACE_EXIT 0; -} - -/* release routine called by the high level interface modules - * zftape or sftape. - */ -void ftape_disable(void) -{ - int i; - TRACE_FUN(ft_t_any); - - for (i = 0; i < ft_nr_buffers; i++) { - if (ft_buffer[i]->mmapped) { - TRACE(ft_t_noise, "first byte of buffer %d: 0x%02x", - i, *ft_buffer[i]->address); - } - } - if (sigtestsetmask(¤t->pending.signal, _DONT_BLOCK) && - !(sigtestsetmask(¤t->pending.signal, _NEVER_BLOCK)) && - ftape_tape_running) { - TRACE(ft_t_warn, - "Interrupted by fatal signal and tape still running"); - ftape_dumb_stop(); - ftape_abort_operation(); /* it's annoying */ - } else { - ftape_set_state(idle); - } - ftape_detach_drive(); - if (ft_history.used) { - TRACE(ft_t_info, "== Non-fatal errors this run: =="); - TRACE(ft_t_info, "fdc isr statistics:\n" - KERN_INFO " id_am_errors : %3d\n" - KERN_INFO " id_crc_errors : %3d\n" - KERN_INFO " data_am_errors : %3d\n" - KERN_INFO " data_crc_errors : %3d\n" - KERN_INFO " overrun_errors : %3d\n" - KERN_INFO " no_data_errors : %3d\n" - KERN_INFO " retries : %3d", - ft_history.id_am_errors, ft_history.id_crc_errors, - ft_history.data_am_errors, ft_history.data_crc_errors, - ft_history.overrun_errors, ft_history.no_data_errors, - ft_history.retries); - if (ft_history.used & 1) { - TRACE(ft_t_info, "ecc statistics:\n" - KERN_INFO " crc_errors : %3d\n" - KERN_INFO " crc_failures : %3d\n" - KERN_INFO " ecc_failures : %3d\n" - KERN_INFO " sectors corrected: %3d", - ft_history.crc_errors, ft_history.crc_failures, - ft_history.ecc_failures, ft_history.corrected); - } - if (ft_history.defects > 0) { - TRACE(ft_t_warn, "Warning: %d media defects!", - ft_history.defects); - } - if (ft_history.rewinds > 0) { - TRACE(ft_t_info, "tape motion statistics:\n" - KERN_INFO "repositions : %3d", - ft_history.rewinds); - } - } - ft_failure = 1; - TRACE_EXIT; -} - -static void ftape_init_driver(void) -{ - TRACE_FUN(ft_t_flow); - - ft_drive_type.vendor_id = UNKNOWN_VENDOR; - ft_drive_type.speed = 0; - ft_drive_type.wake_up = unknown_wake_up; - ft_drive_type.name = "Unknown"; - - ftape_timeout.seek = 650 * FT_SECOND; - ftape_timeout.reset = 670 * FT_SECOND; - ftape_timeout.rewind = 650 * FT_SECOND; - ftape_timeout.head_seek = 15 * FT_SECOND; - ftape_timeout.stop = 5 * FT_SECOND; - ftape_timeout.pause = 16 * FT_SECOND; - - ft_qic_std = -1; - ftape_tape_len = 0; /* unknown */ - ftape_current_command = 0; - ftape_current_cylinder = -1; - - ft_segments_per_track = 102; - ftape_segments_per_head = 1020; - ftape_segments_per_cylinder = 4; - ft_tracks_per_tape = 20; - - ft_failure = 1; - - ft_formatted = 0; - ft_no_tape = 1; - ft_write_protected = 1; - ft_new_tape = 1; - - ft_driver_state = idle; - - ft_data_rate = - ft_fdc_max_rate = 500; - ft_drive_max_rate = 0; /* triggers set_rate_test() */ - - ftape_init_drive_needed = 1; - - ft_header_segment_1 = -1; - ft_header_segment_2 = -1; - ft_used_header_segment = -1; - ft_first_data_segment = -1; - ft_last_data_segment = -1; - - ft_location.track = -1; - ft_location.known = 0; - - ftape_tape_running = 0; - ftape_might_be_off_track = 1; - - ftape_new_cartridge(); /* init some tape related variables */ - ftape_init_bsm(); - TRACE_EXIT; -} diff --git a/drivers/char/ftape/lowlevel/ftape-ctl.h b/drivers/char/ftape/lowlevel/ftape-ctl.h deleted file mode 100644 index 5f5e30bc3615..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-ctl.h +++ /dev/null @@ -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 diff --git a/drivers/char/ftape/lowlevel/ftape-ecc.c b/drivers/char/ftape/lowlevel/ftape-ecc.c deleted file mode 100644 index e5632f674bc8..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-ecc.c +++ /dev/null @@ -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; -} diff --git a/drivers/char/ftape/lowlevel/ftape-ecc.h b/drivers/char/ftape/lowlevel/ftape-ecc.h deleted file mode 100644 index 4829146fe9a0..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-ecc.h +++ /dev/null @@ -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_ */ diff --git a/drivers/char/ftape/lowlevel/ftape-format.c b/drivers/char/ftape/lowlevel/ftape-format.c deleted file mode 100644 index 5dd4c59a3f34..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-format.c +++ /dev/null @@ -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; -} diff --git a/drivers/char/ftape/lowlevel/ftape-format.h b/drivers/char/ftape/lowlevel/ftape-format.h deleted file mode 100644 index f15161566643..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-format.h +++ /dev/null @@ -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 diff --git a/drivers/char/ftape/lowlevel/ftape-init.c b/drivers/char/ftape/lowlevel/ftape-init.c deleted file mode 100644 index 4998132a81d1..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-init.c +++ /dev/null @@ -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); diff --git a/drivers/char/ftape/lowlevel/ftape-init.h b/drivers/char/ftape/lowlevel/ftape-init.h deleted file mode 100644 index 99a7b8ab086f..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-init.h +++ /dev/null @@ -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 diff --git a/drivers/char/ftape/lowlevel/ftape-io.c b/drivers/char/ftape/lowlevel/ftape-io.c deleted file mode 100644 index 259015aeff55..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-io.c +++ /dev/null @@ -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; -} diff --git a/drivers/char/ftape/lowlevel/ftape-io.h b/drivers/char/ftape/lowlevel/ftape-io.h deleted file mode 100644 index 26a7baad8717..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-io.h +++ /dev/null @@ -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 diff --git a/drivers/char/ftape/lowlevel/ftape-proc.c b/drivers/char/ftape/lowlevel/ftape-proc.c deleted file mode 100644 index e805b15e0a12..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-proc.c +++ /dev/null @@ -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) */ diff --git a/drivers/char/ftape/lowlevel/ftape-proc.h b/drivers/char/ftape/lowlevel/ftape-proc.h deleted file mode 100644 index 264dfcc1d22d..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-proc.h +++ /dev/null @@ -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 diff --git a/drivers/char/ftape/lowlevel/ftape-read.c b/drivers/char/ftape/lowlevel/ftape-read.c deleted file mode 100644 index d967d8cd86dc..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-read.c +++ /dev/null @@ -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; -} diff --git a/drivers/char/ftape/lowlevel/ftape-read.h b/drivers/char/ftape/lowlevel/ftape-read.h deleted file mode 100644 index 069f99f2a984..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-read.h +++ /dev/null @@ -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 */ diff --git a/drivers/char/ftape/lowlevel/ftape-rw.c b/drivers/char/ftape/lowlevel/ftape-rw.c deleted file mode 100644 index c0d6dc2cbfd3..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-rw.c +++ /dev/null @@ -1,1092 +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-rw.c,v $ - * $Revision: 1.7 $ - * $Date: 1997/10/28 14:26:49 $ - * - * This file contains some common code for the segment read and - * segment write routines for the QIC-117 floppy-tape driver 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-rw.h" -#include "../lowlevel/fdc-io.h" -#include "../lowlevel/ftape-init.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-read.h" -#include "../lowlevel/ftape-ecc.h" -#include "../lowlevel/ftape-bsm.h" - -/* Global vars. - */ -int ft_nr_buffers; -buffer_struct *ft_buffer[FT_MAX_NR_BUFFERS]; -static volatile int ft_head; -static volatile int ft_tail; /* not volatile but need same type as head */ -int fdc_setup_error; -location_record ft_location = {-1, 0}; -volatile int ftape_tape_running; - -/* Local vars. - */ -static int overrun_count_offset; -static int inhibit_correction; - -/* maxmimal allowed overshoot when fast seeking - */ -#define OVERSHOOT_LIMIT 10 - -/* Increment cyclic buffer nr. - */ -buffer_struct *ftape_next_buffer(ft_buffer_queue_t pos) -{ - switch (pos) { - case ft_queue_head: - if (++ft_head >= ft_nr_buffers) { - ft_head = 0; - } - return ft_buffer[ft_head]; - case ft_queue_tail: - if (++ft_tail >= ft_nr_buffers) { - ft_tail = 0; - } - return ft_buffer[ft_tail]; - default: - return NULL; - } -} -int ftape_buffer_id(ft_buffer_queue_t pos) -{ - switch(pos) { - case ft_queue_head: return ft_head; - case ft_queue_tail: return ft_tail; - default: return -1; - } -} -buffer_struct *ftape_get_buffer(ft_buffer_queue_t pos) -{ - switch(pos) { - case ft_queue_head: return ft_buffer[ft_head]; - case ft_queue_tail: return ft_buffer[ft_tail]; - default: return NULL; - } -} -void ftape_reset_buffer(void) -{ - ft_head = ft_tail = 0; -} - -buffer_state_enum ftape_set_state(buffer_state_enum new_state) -{ - buffer_state_enum old_state = ft_driver_state; - - ft_driver_state = new_state; - return old_state; -} -/* Calculate Floppy Disk Controller and DMA parameters for a segment. - * head: selects buffer struct in array. - * offset: number of physical sectors to skip (including bad ones). - * count: number of physical sectors to handle (including bad ones). - */ -static int setup_segment(buffer_struct * buff, - int segment_id, - unsigned int sector_offset, - unsigned int sector_count, - int retry) -{ - SectorMap offset_mask; - SectorMap mask; - TRACE_FUN(ft_t_any); - - buff->segment_id = segment_id; - buff->sector_offset = sector_offset; - buff->remaining = sector_count; - buff->head = segment_id / ftape_segments_per_head; - buff->cyl = (segment_id % ftape_segments_per_head) / ftape_segments_per_cylinder; - buff->sect = (segment_id % ftape_segments_per_cylinder) * FT_SECTORS_PER_SEGMENT + 1; - buff->deleted = 0; - offset_mask = (1 << buff->sector_offset) - 1; - mask = ftape_get_bad_sector_entry(segment_id) & offset_mask; - while (mask) { - if (mask & 1) { - offset_mask >>= 1; /* don't count bad sector */ - } - mask >>= 1; - } - buff->data_offset = count_ones(offset_mask); /* good sectors to skip */ - buff->ptr = buff->address + buff->data_offset * FT_SECTOR_SIZE; - TRACE(ft_t_flow, "data offset = %d sectors", buff->data_offset); - if (retry) { - buff->soft_error_map &= offset_mask; /* keep skipped part */ - } else { - buff->hard_error_map = buff->soft_error_map = 0; - } - buff->bad_sector_map = ftape_get_bad_sector_entry(buff->segment_id); - if (buff->bad_sector_map != 0) { - TRACE(ft_t_noise, "segment: %d, bad sector map: %08lx", - buff->segment_id, (long)buff->bad_sector_map); - } else { - TRACE(ft_t_flow, "segment: %d", buff->segment_id); - } - if (buff->sector_offset > 0) { - buff->bad_sector_map >>= buff->sector_offset; - } - if (buff->sector_offset != 0 || buff->remaining != FT_SECTORS_PER_SEGMENT) { - TRACE(ft_t_flow, "sector offset = %d, count = %d", - buff->sector_offset, buff->remaining); - } - /* Segments with 3 or less sectors are not written with valid - * data because there is no space left for the ecc. The - * data written is whatever happens to be in the buffer. - * Reading such a segment will return a zero byte-count. - * To allow us to read/write segments with all bad sectors - * we fake one readable sector in the segment. This - * prevents having to handle these segments in a very - * special way. It is not important if the reading of this - * bad sector fails or not (the data is ignored). It is - * only read to keep the driver running. - * - * The QIC-40/80 spec. has no information on how to handle - * this case, so this is my interpretation. - */ - if (buff->bad_sector_map == EMPTY_SEGMENT) { - TRACE(ft_t_flow, "empty segment %d, fake first sector good", - buff->segment_id); - if (buff->ptr != buff->address) { - TRACE(ft_t_bug, "This is a bug: %p/%p", - buff->ptr, buff->address); - } - buff->bad_sector_map = FAKE_SEGMENT; - } - fdc_setup_error = 0; - buff->next_segment = segment_id + 1; - TRACE_EXIT 0; -} - -/* Calculate Floppy Disk Controller and DMA parameters for a new segment. - */ -int ftape_setup_new_segment(buffer_struct * buff, int segment_id, int skip) -{ - int result = 0; - static int old_segment_id = -1; - static buffer_state_enum old_ft_driver_state = idle; - int retry = 0; - unsigned offset = 0; - int count = FT_SECTORS_PER_SEGMENT; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_flow, "%s segment %d (old = %d)", - (ft_driver_state == reading || ft_driver_state == verifying) - ? "reading" : "writing", - segment_id, old_segment_id); - if (ft_driver_state != old_ft_driver_state) { /* when verifying */ - old_segment_id = -1; - old_ft_driver_state = ft_driver_state; - } - if (segment_id == old_segment_id) { - ++buff->retry; - ++ft_history.retries; - TRACE(ft_t_flow, "setting up for retry nr %d", buff->retry); - retry = 1; - if (skip && buff->skip > 0) { /* allow skip on retry */ - offset = buff->skip; - count -= offset; - TRACE(ft_t_flow, "skipping %d sectors", offset); - } - } else { - buff->retry = 0; - buff->skip = 0; - old_segment_id = segment_id; - } - result = setup_segment(buff, segment_id, offset, count, retry); - TRACE_EXIT result; -} - -/* Determine size of next cluster of good sectors. - */ -int ftape_calc_next_cluster(buffer_struct * buff) -{ - /* Skip bad sectors. - */ - while (buff->remaining > 0 && (buff->bad_sector_map & 1) != 0) { - buff->bad_sector_map >>= 1; - ++buff->sector_offset; - --buff->remaining; - } - /* Find next cluster of good sectors - */ - if (buff->bad_sector_map == 0) { /* speed up */ - buff->sector_count = buff->remaining; - } else { - SectorMap map = buff->bad_sector_map; - - buff->sector_count = 0; - while (buff->sector_count < buff->remaining && (map & 1) == 0) { - ++buff->sector_count; - map >>= 1; - } - } - return buff->sector_count; -} - -/* if just passed the last segment on a track, wait for BOT - * or EOT mark. - */ -int ftape_handle_logical_eot(void) -{ - TRACE_FUN(ft_t_flow); - - if (ft_runner_status == logical_eot) { - int status; - - TRACE(ft_t_noise, "tape at logical EOT"); - TRACE_CATCH(ftape_ready_wait(ftape_timeout.seek, &status),); - if ((status & (QIC_STATUS_AT_BOT | QIC_STATUS_AT_EOT)) == 0) { - TRACE_ABORT(-EIO, ft_t_err, "eot/bot not reached"); - } - ft_runner_status = end_of_tape; - } - if (ft_runner_status == end_of_tape) { - TRACE(ft_t_noise, "runner stopped because of logical EOT"); - ft_runner_status = idle; - } - TRACE_EXIT 0; -} - -static int check_bot_eot(int status) -{ - TRACE_FUN(ft_t_flow); - - if (status & (QIC_STATUS_AT_BOT | QIC_STATUS_AT_EOT)) { - ft_location.bot = ((ft_location.track & 1) == 0 ? - (status & QIC_STATUS_AT_BOT) != 0: - (status & QIC_STATUS_AT_EOT) != 0); - ft_location.eot = !ft_location.bot; - ft_location.segment = (ft_location.track + - (ft_location.bot ? 0 : 1)) * ft_segments_per_track - 1; - ft_location.sector = -1; - ft_location.known = 1; - TRACE(ft_t_flow, "tape at logical %s", - ft_location.bot ? "bot" : "eot"); - TRACE(ft_t_flow, "segment = %d", ft_location.segment); - } else { - ft_location.known = 0; - } - TRACE_EXIT ft_location.known; -} - -/* Read Id of first sector passing tape head. - */ -static int ftape_read_id(void) -{ - int status; - __u8 out[2]; - TRACE_FUN(ft_t_any); - - /* Assume tape is running on entry, be able to handle - * situation where it stopped or is stopping. - */ - ft_location.known = 0; /* default is location not known */ - out[0] = FDC_READID; - out[1] = ft_drive_sel; - TRACE_CATCH(fdc_command(out, 2),); - switch (fdc_interrupt_wait(20 * FT_SECOND)) { - case 0: - if (fdc_sect == 0) { - if (ftape_report_drive_status(&status) >= 0 && - (status & QIC_STATUS_READY)) { - ftape_tape_running = 0; - TRACE(ft_t_flow, "tape has stopped"); - check_bot_eot(status); - } - } else { - ft_location.known = 1; - ft_location.segment = (ftape_segments_per_head - * fdc_head - + ftape_segments_per_cylinder - * fdc_cyl - + (fdc_sect - 1) - / FT_SECTORS_PER_SEGMENT); - ft_location.sector = ((fdc_sect - 1) - % FT_SECTORS_PER_SEGMENT); - ft_location.eot = ft_location.bot = 0; - } - break; - case -ETIME: - /* Didn't find id on tape, must be near end: Wait - * until stopped. - */ - if (ftape_ready_wait(FT_FOREVER, &status) >= 0) { - ftape_tape_running = 0; - TRACE(ft_t_flow, "tape has stopped"); - check_bot_eot(status); - } - break; - default: - /* Interrupted or otherwise failing - * fdc_interrupt_wait() - */ - TRACE(ft_t_err, "fdc_interrupt_wait failed"); - break; - } - if (!ft_location.known) { - TRACE_ABORT(-EIO, ft_t_flow, "no id found"); - } - if (ft_location.sector == 0) { - TRACE(ft_t_flow, "passing segment %d/%d", - ft_location.segment, ft_location.sector); - } else { - TRACE(ft_t_fdc_dma, "passing segment %d/%d", - ft_location.segment, ft_location.sector); - } - TRACE_EXIT 0; -} - -static int logical_forward(void) -{ - ftape_tape_running = 1; - return ftape_command(QIC_LOGICAL_FORWARD); -} - -int ftape_stop_tape(int *pstatus) -{ - int retry = 0; - int result; - TRACE_FUN(ft_t_flow); - - do { - result = ftape_command_wait(QIC_STOP_TAPE, - ftape_timeout.stop, pstatus); - if (result == 0) { - if ((*pstatus & QIC_STATUS_READY) == 0) { - result = -EIO; - } else { - ftape_tape_running = 0; - } - } - } while (result < 0 && ++retry <= 3); - if (result < 0) { - TRACE(ft_t_err, "failed ! (fatal)"); - } - TRACE_EXIT result; -} - -int ftape_dumb_stop(void) -{ - int result; - int status; - TRACE_FUN(ft_t_flow); - - /* Abort current fdc operation if it's busy (probably read - * or write operation pending) with a reset. - */ - if (fdc_ready_wait(100 /* usec */) < 0) { - TRACE(ft_t_noise, "aborting fdc operation"); - fdc_reset(); - } - /* Reading id's after the last segment on a track may fail - * but eventually the drive will become ready (logical eot). - */ - result = ftape_report_drive_status(&status); - ft_location.known = 0; - do { - if (result == 0 && status & QIC_STATUS_READY) { - /* Tape is not running any more. - */ - TRACE(ft_t_noise, "tape already halted"); - check_bot_eot(status); - ftape_tape_running = 0; - } else if (ftape_tape_running) { - /* Tape is (was) still moving. - */ -#ifdef TESTING - ftape_read_id(); -#endif - result = ftape_stop_tape(&status); - } else { - /* Tape not yet ready but stopped. - */ - result = ftape_ready_wait(ftape_timeout.pause,&status); - } - } while (ftape_tape_running - && !(sigtestsetmask(¤t->pending.signal, _NEVER_BLOCK))); -#ifndef TESTING - ft_location.known = 0; -#endif - if (ft_runner_status == aborting || ft_runner_status == do_abort) { - ft_runner_status = idle; - } - TRACE_EXIT result; -} - -/* Wait until runner has finished tail buffer. - * - */ -int ftape_wait_segment(buffer_state_enum state) -{ - int status; - int result = 0; - TRACE_FUN(ft_t_flow); - - while (ft_buffer[ft_tail]->status == state) { - TRACE(ft_t_flow, "state: %d", ft_buffer[ft_tail]->status); - /* First buffer still being worked on, wait up to timeout. - * - * Note: we check two times for being killed. 50 - * seconds are quite long. Note that - * fdc_interrupt_wait() is not killable by any - * means. ftape_read_segment() wants us to return - * -EINTR in case of a signal. - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - result = fdc_interrupt_wait(50 * FT_SECOND); - FT_SIGNAL_EXIT(_DONT_BLOCK); - if (result < 0) { - TRACE_ABORT(result, - ft_t_err, "fdc_interrupt_wait failed"); - } - if (fdc_setup_error) { - /* recover... FIXME */ - TRACE_ABORT(-EIO, ft_t_err, "setup error"); - } - } - if (ft_buffer[ft_tail]->status != error) { - TRACE_EXIT 0; - } - TRACE_CATCH(ftape_report_drive_status(&status),); - TRACE(ft_t_noise, "ftape_report_drive_status: 0x%02x", status); - if ((status & QIC_STATUS_READY) && - (status & QIC_STATUS_ERROR)) { - unsigned int error; - qic117_cmd_t command; - - /* Report and clear error state. - * In case the drive can't operate at the selected - * rate, select the next lower data rate. - */ - ftape_report_error(&error, &command, 1); - if (error == 31 && command == QIC_LOGICAL_FORWARD) { - /* drive does not accept this data rate */ - if (ft_data_rate > 250) { - TRACE(ft_t_info, - "Probable data rate conflict"); - TRACE(ft_t_info, - "Lowering data rate to %d Kbps", - ft_data_rate / 2); - ftape_half_data_rate(); - if (ft_buffer[ft_tail]->retry > 0) { - /* give it a chance */ - --ft_buffer[ft_tail]->retry; - } - } else { - /* no rate is accepted... */ - TRACE(ft_t_err, "We're dead :("); - } - } else { - TRACE(ft_t_err, "Unknown error"); - } - TRACE_EXIT -EIO; /* g.p. error */ - } - TRACE_EXIT 0; -} - -/* forward */ static int seek_forward(int segment_id, int fast); - -static int fast_seek(int count, int reverse) -{ - int result = 0; - int status; - TRACE_FUN(ft_t_flow); - - if (count > 0) { - /* If positioned at begin or end of tape, fast seeking needs - * special treatment. - * Starting from logical bot needs a (slow) seek to the first - * segment before the high speed seek. Most drives do this - * automatically but some older don't, so we treat them - * all the same. - * Starting from logical eot is even more difficult because - * we cannot (slow) reverse seek to the last segment. - * TO BE IMPLEMENTED. - */ - inhibit_correction = 0; - if (ft_location.known && - ((ft_location.bot && !reverse) || - (ft_location.eot && reverse))) { - if (!reverse) { - /* (slow) skip to first segment on a track - */ - seek_forward(ft_location.track * ft_segments_per_track, 0); - --count; - } else { - /* When seeking backwards from - * end-of-tape the number of erased - * gaps found seems to be higher than - * expected. Therefor the drive must - * skip some more segments than - * calculated, but we don't know how - * many. Thus we will prevent the - * re-calculation of offset and - * overshoot when seeking backwards. - */ - inhibit_correction = 1; - count += 3; /* best guess */ - } - } - } else { - TRACE(ft_t_flow, "warning: zero or negative count: %d", count); - } - if (count > 0) { - int i; - int nibbles = count > 255 ? 3 : 2; - - if (count > 4095) { - TRACE(ft_t_noise, "skipping clipped at 4095 segment"); - count = 4095; - } - /* Issue this tape command first. */ - if (!reverse) { - TRACE(ft_t_noise, "skipping %d segment(s)", count); - result = ftape_command(nibbles == 3 ? - QIC_SKIP_EXTENDED_FORWARD : QIC_SKIP_FORWARD); - } else { - TRACE(ft_t_noise, "backing up %d segment(s)", count); - result = ftape_command(nibbles == 3 ? - QIC_SKIP_EXTENDED_REVERSE : QIC_SKIP_REVERSE); - } - if (result < 0) { - TRACE(ft_t_noise, "Skip command failed"); - } else { - --count; /* 0 means one gap etc. */ - for (i = 0; i < nibbles; ++i) { - if (result >= 0) { - result = ftape_parameter(count & 15); - count /= 16; - } - } - result = ftape_ready_wait(ftape_timeout.rewind, &status); - if (result >= 0) { - ftape_tape_running = 0; - } - } - } - TRACE_EXIT result; -} - -static int validate(int id) -{ - /* Check to see if position found is off-track as reported - * once. Because all tracks in one direction lie next to - * each other, if off-track the error will be approximately - * 2 * ft_segments_per_track. - */ - if (ft_location.track == -1) { - return 1; /* unforseen situation, don't generate error */ - } else { - /* Use margin of ft_segments_per_track on both sides - * because ftape needs some margin and the error we're - * looking for is much larger ! - */ - int lo = (ft_location.track - 1) * ft_segments_per_track; - int hi = (ft_location.track + 2) * ft_segments_per_track; - - return (id >= lo && id < hi); - } -} - -static int seek_forward(int segment_id, int fast) -{ - int failures = 0; - int count; - static int margin = 1; /* fixed: stop this before target */ - static int overshoot = 1; - static int min_count = 8; - int expected = -1; - int target = segment_id - margin; - int fast_seeking; - int prev_segment = ft_location.segment; - TRACE_FUN(ft_t_flow); - - if (!ft_location.known) { - TRACE_ABORT(-EIO, ft_t_err, - "fatal: cannot seek from unknown location"); - } - if (!validate(segment_id)) { - ftape_sleep(1 * FT_SECOND); - ft_failure = 1; - TRACE_ABORT(-EIO, ft_t_err, - "fatal: head off track (bad hardware?)"); - } - TRACE(ft_t_noise, "from %d/%d to %d/0 - %d", - ft_location.segment, ft_location.sector,segment_id,margin); - count = target - ft_location.segment - overshoot; - fast_seeking = (fast && - count > (min_count + (ft_location.bot ? 1 : 0))); - if (fast_seeking) { - TRACE(ft_t_noise, "fast skipping %d segments", count); - expected = segment_id - margin; - fast_seek(count, 0); - } - if (!ftape_tape_running) { - logical_forward(); - } - while (ft_location.segment < segment_id) { - /* This requires at least one sector in a (bad) segment to - * have a valid and readable sector id ! - * It looks like this is not guaranteed, so we must try - * to find a way to skip an EMPTY_SEGMENT. !!! FIXME !!! - */ - if (ftape_read_id() < 0 || !ft_location.known || - sigtestsetmask(¤t->pending.signal, _DONT_BLOCK)) { - ft_location.known = 0; - if (!ftape_tape_running || - ++failures > FT_SECTORS_PER_SEGMENT) { - TRACE_ABORT(-EIO, ft_t_err, - "read_id failed completely"); - } - FT_SIGNAL_EXIT(_DONT_BLOCK); - TRACE(ft_t_flow, "read_id failed, retry (%d)", - failures); - continue; - } - if (fast_seeking) { - TRACE(ft_t_noise, "ended at %d/%d (%d,%d)", - ft_location.segment, ft_location.sector, - overshoot, inhibit_correction); - if (!inhibit_correction && - (ft_location.segment < expected || - ft_location.segment > expected + margin)) { - int error = ft_location.segment - expected; - TRACE(ft_t_noise, - "adjusting overshoot from %d to %d", - overshoot, overshoot + error); - overshoot += error; - /* All overshoots have the same - * direction, so it should never - * become negative, but who knows. - */ - if (overshoot < -5 || - overshoot > OVERSHOOT_LIMIT) { - if (overshoot < 0) { - /* keep sane value */ - overshoot = -5; - } else { - /* keep sane value */ - overshoot = OVERSHOOT_LIMIT; - } - TRACE(ft_t_noise, - "clipped overshoot to %d", - overshoot); - } - } - fast_seeking = 0; - } - if (ft_location.known) { - if (ft_location.segment > prev_segment + 1) { - TRACE(ft_t_noise, - "missed segment %d while skipping", - prev_segment + 1); - } - prev_segment = ft_location.segment; - } - } - if (ft_location.segment > segment_id) { - TRACE_ABORT(-EIO, - ft_t_noise, "failed: skip ended at segment %d/%d", - ft_location.segment, ft_location.sector); - } - TRACE_EXIT 0; -} - -static int skip_reverse(int segment_id, int *pstatus) -{ - int failures = 0; - static int overshoot = 1; - static int min_rewind = 2; /* 1 + overshoot */ - static const int margin = 1; /* stop this before target */ - int expected = 0; - int count = 1; - int short_seek; - int target = segment_id - margin; - TRACE_FUN(ft_t_flow); - - if (ft_location.known && !validate(segment_id)) { - ftape_sleep(1 * FT_SECOND); - ft_failure = 1; - TRACE_ABORT(-EIO, ft_t_err, - "fatal: head off track (bad hardware?)"); - } - do { - if (!ft_location.known) { - TRACE(ft_t_warn, "warning: location not known"); - } - TRACE(ft_t_noise, "from %d/%d to %d/0 - %d", - ft_location.segment, ft_location.sector, - segment_id, margin); - /* min_rewind == 1 + overshoot_when_doing_minimum_rewind - * overshoot == overshoot_when_doing_larger_rewind - * Initially min_rewind == 1 + overshoot, optimization - * of both values will be done separately. - * overshoot and min_rewind can be negative as both are - * sums of three components: - * any_overshoot == rewind_overshoot - - * stop_overshoot - - * start_overshoot - */ - if (ft_location.segment - target - (min_rewind - 1) < 1) { - short_seek = 1; - } else { - count = ft_location.segment - target - overshoot; - short_seek = (count < 1); - } - if (short_seek) { - count = 1; /* do shortest rewind */ - expected = ft_location.segment - min_rewind; - if (expected/ft_segments_per_track != ft_location.track) { - expected = (ft_location.track * - ft_segments_per_track); - } - } else { - expected = target; - } - fast_seek(count, 1); - logical_forward(); - if (ftape_read_id() < 0 || !ft_location.known || - (sigtestsetmask(¤t->pending.signal, _DONT_BLOCK))) { - if ((!ftape_tape_running && !ft_location.known) || - ++failures > FT_SECTORS_PER_SEGMENT) { - TRACE_ABORT(-EIO, ft_t_err, - "read_id failed completely"); - } - FT_SIGNAL_EXIT(_DONT_BLOCK); - TRACE_CATCH(ftape_report_drive_status(pstatus),); - TRACE(ft_t_noise, "ftape_read_id failed, retry (%d)", - failures); - continue; - } - TRACE(ft_t_noise, "ended at %d/%d (%d,%d,%d)", - ft_location.segment, ft_location.sector, - min_rewind, overshoot, inhibit_correction); - if (!inhibit_correction && - (ft_location.segment < expected || - ft_location.segment > expected + margin)) { - int error = expected - ft_location.segment; - if (short_seek) { - TRACE(ft_t_noise, - "adjusting min_rewind from %d to %d", - min_rewind, min_rewind + error); - min_rewind += error; - if (min_rewind < -5) { - /* is this right ? FIXME ! */ - /* keep sane value */ - min_rewind = -5; - TRACE(ft_t_noise, - "clipped min_rewind to %d", - min_rewind); - } - } else { - TRACE(ft_t_noise, - "adjusting overshoot from %d to %d", - overshoot, overshoot + error); - overshoot += error; - if (overshoot < -5 || - overshoot > OVERSHOOT_LIMIT) { - if (overshoot < 0) { - /* keep sane value */ - overshoot = -5; - } else { - /* keep sane value */ - overshoot = OVERSHOOT_LIMIT; - } - TRACE(ft_t_noise, - "clipped overshoot to %d", - overshoot); - } - } - } - } while (ft_location.segment > segment_id); - if (ft_location.known) { - TRACE(ft_t_noise, "current location: %d/%d", - ft_location.segment, ft_location.sector); - } - TRACE_EXIT 0; -} - -static int determine_position(void) -{ - int retry = 0; - int status; - int result; - TRACE_FUN(ft_t_flow); - - if (!ftape_tape_running) { - /* This should only happen if tape is stopped by isr. - */ - TRACE(ft_t_flow, "waiting for tape stop"); - if (ftape_ready_wait(ftape_timeout.pause, &status) < 0) { - TRACE(ft_t_flow, "drive still running (fatal)"); - ftape_tape_running = 1; /* ? */ - } - } else { - ftape_report_drive_status(&status); - } - if (status & QIC_STATUS_READY) { - /* Drive must be ready to check error state ! - */ - TRACE(ft_t_flow, "drive is ready"); - if (status & QIC_STATUS_ERROR) { - unsigned int error; - qic117_cmd_t command; - - /* Report and clear error state, try to continue. - */ - TRACE(ft_t_flow, "error status set"); - ftape_report_error(&error, &command, 1); - ftape_ready_wait(ftape_timeout.reset, &status); - ftape_tape_running = 0; /* ? */ - } - if (check_bot_eot(status)) { - if (ft_location.bot) { - if ((status & QIC_STATUS_READY) == 0) { - /* tape moving away from - * bot/eot, let's see if we - * can catch up with the first - * segment on this track. - */ - } else { - TRACE(ft_t_flow, - "start tape from logical bot"); - logical_forward(); /* start moving */ - } - } else { - if ((status & QIC_STATUS_READY) == 0) { - TRACE(ft_t_noise, "waiting for logical end of track"); - result = ftape_ready_wait(ftape_timeout.reset, &status); - /* error handling needed ? */ - } else { - TRACE(ft_t_noise, - "tape at logical end of track"); - } - } - } else { - TRACE(ft_t_flow, "start tape"); - logical_forward(); /* start moving */ - ft_location.known = 0; /* not cleared by logical forward ! */ - } - } - /* tape should be moving now, start reading id's - */ - while (!ft_location.known && - retry++ < FT_SECTORS_PER_SEGMENT && - (result = ftape_read_id()) < 0) { - - TRACE(ft_t_flow, "location unknown"); - - /* exit on signal - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - - /* read-id somehow failed, tape may - * have reached end or some other - * error happened. - */ - TRACE(ft_t_flow, "read-id failed"); - TRACE_CATCH(ftape_report_drive_status(&status),); - TRACE(ft_t_err, "ftape_report_drive_status: 0x%02x", status); - if (status & QIC_STATUS_READY) { - ftape_tape_running = 0; - TRACE(ft_t_noise, "tape stopped for unknown reason! " - "status = 0x%02x", status); - if (status & QIC_STATUS_ERROR || - !check_bot_eot(status)) { - /* oops, tape stopped but not at end! - */ - TRACE_EXIT -EIO; - } - } - } - TRACE(ft_t_flow, - "tape is positioned at segment %d", ft_location.segment); - TRACE_EXIT ft_location.known ? 0 : -EIO; -} - -/* Get the tape running and position it just before the - * requested segment. - * Seek tape-track and reposition as needed. - */ -int ftape_start_tape(int segment_id, int sector_offset) -{ - int track = segment_id / ft_segments_per_track; - int result = -EIO; - int status; - static int last_segment = -1; - static int bad_bus_timing = 0; - /* number of segments passing the head between starting the tape - * and being able to access the first sector. - */ - static int start_offset = 1; - int retry; - TRACE_FUN(ft_t_flow); - - /* If sector_offset > 0, seek into wanted segment instead of - * into previous. - * This allows error recovery if a part of the segment is bad - * (erased) causing the tape drive to generate an index pulse - * thus causing a no-data error before the requested sector - * is reached. - */ - ftape_tape_running = 0; - TRACE(ft_t_noise, "target segment: %d/%d%s", segment_id, sector_offset, - ft_buffer[ft_head]->retry > 0 ? " retry" : ""); - if (ft_buffer[ft_head]->retry > 0) { /* this is a retry */ - int dist = segment_id - last_segment; - - if ((int)ft_history.overrun_errors < overrun_count_offset) { - overrun_count_offset = ft_history.overrun_errors; - } else if (dist < 0 || dist > 50) { - overrun_count_offset = ft_history.overrun_errors; - } else if ((ft_history.overrun_errors - - overrun_count_offset) >= 8) { - if (ftape_increase_threshold() >= 0) { - --ft_buffer[ft_head]->retry; - overrun_count_offset = - ft_history.overrun_errors; - TRACE(ft_t_warn, "increased threshold because " - "of excessive overrun errors"); - } else if (!bad_bus_timing && ft_data_rate >= 1000) { - ftape_half_data_rate(); - --ft_buffer[ft_head]->retry; - bad_bus_timing = 1; - overrun_count_offset = - ft_history.overrun_errors; - TRACE(ft_t_warn, "reduced datarate because " - "of excessive overrun errors"); - } - } - } - last_segment = segment_id; - if (ft_location.track != track || - (ftape_might_be_off_track && ft_buffer[ft_head]->retry== 0)) { - /* current track unknown or not equal to destination - */ - ftape_ready_wait(ftape_timeout.seek, &status); - ftape_seek_head_to_track(track); - /* overrun_count_offset = ft_history.overrun_errors; */ - } - result = -EIO; - retry = 0; - while (result < 0 && - retry++ <= 5 && - !ft_failure && - !(sigtestsetmask(¤t->pending.signal, _DONT_BLOCK))) { - - if (retry && start_offset < 5) { - start_offset ++; - } - /* Check if we are able to catch the requested - * segment in time. - */ - if ((ft_location.known || (determine_position() == 0)) && - ft_location.segment >= - (segment_id - - ((ftape_tape_running || ft_location.bot) - ? 0 : start_offset))) { - /* Too far ahead (in or past target segment). - */ - if (ftape_tape_running) { - if ((result = ftape_stop_tape(&status)) < 0) { - TRACE(ft_t_err, - "stop tape failed with code %d", - result); - break; - } - TRACE(ft_t_noise, "tape stopped"); - ftape_tape_running = 0; - } - TRACE(ft_t_noise, "repositioning"); - ++ft_history.rewinds; - if (segment_id % ft_segments_per_track < start_offset){ - TRACE(ft_t_noise, "end of track condition\n" - KERN_INFO "segment_id : %d\n" - KERN_INFO "ft_segments_per_track: %d\n" - KERN_INFO "start_offset : %d", - segment_id, ft_segments_per_track, - start_offset); - - /* If seeking to first segments on - * track better do a complete rewind - * to logical begin of track to get a - * more steady tape motion. - */ - result = ftape_command_wait( - (ft_location.track & 1) - ? QIC_PHYSICAL_FORWARD - : QIC_PHYSICAL_REVERSE, - ftape_timeout.rewind, &status); - check_bot_eot(status); /* update location */ - } else { - result= skip_reverse(segment_id - start_offset, - &status); - } - } - if (!ft_location.known) { - TRACE(ft_t_bug, "panic: location not known"); - result = -EIO; - continue; /* while() will check for failure */ - } - TRACE(ft_t_noise, "current segment: %d/%d", - ft_location.segment, ft_location.sector); - /* We're on the right track somewhere before the - * wanted segment. Start tape movement if needed and - * skip to just before or inside the requested - * segment. Keep tape running. - */ - result = 0; - if (ft_location.segment < - (segment_id - ((ftape_tape_running || ft_location.bot) - ? 0 : start_offset))) { - if (sector_offset > 0) { - result = seek_forward(segment_id, - retry <= 3); - } else { - result = seek_forward(segment_id - 1, - retry <= 3); - } - } - if (result == 0 && - ft_location.segment != - (segment_id - (sector_offset > 0 ? 0 : 1))) { - result = -EIO; - } - } - if (result < 0) { - TRACE(ft_t_err, "failed to reposition"); - } else { - ft_runner_status = running; - } - TRACE_EXIT result; -} diff --git a/drivers/char/ftape/lowlevel/ftape-rw.h b/drivers/char/ftape/lowlevel/ftape-rw.h deleted file mode 100644 index 32f4feeb887c..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-rw.h +++ /dev/null @@ -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 */ diff --git a/drivers/char/ftape/lowlevel/ftape-setup.c b/drivers/char/ftape/lowlevel/ftape-setup.c deleted file mode 100644 index 678340acd0b7..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-setup.c +++ /dev/null @@ -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); diff --git a/drivers/char/ftape/lowlevel/ftape-tracing.c b/drivers/char/ftape/lowlevel/ftape-tracing.c deleted file mode 100644 index 7fdc6567440b..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-tracing.c +++ /dev/null @@ -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); -} diff --git a/drivers/char/ftape/lowlevel/ftape-tracing.h b/drivers/char/ftape/lowlevel/ftape-tracing.h deleted file mode 100644 index 2950810c7085..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-tracing.h +++ /dev/null @@ -1,179 +0,0 @@ -#ifndef _FTAPE_TRACING_H -#define _FTAPE_TRACING_H - -/* - * Copyright (C) 1994-1996 Bas Laarhoven, - * (C) 1996-1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-tracing.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:28 $ - * - * This file contains definitions that eases the debugging of the - * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. - */ - -#include <linux/kernel.h> - -/* - * Be very careful with TRACE_EXIT and TRACE_ABORT. - * - * if (something) TRACE_EXIT error; - * - * will NOT work. Use - * - * if (something) { - * TRACE_EXIT error; - * } - * - * instead. Maybe a bit dangerous, but save lots of lines of code. - */ - -#define LL_X "%d/%d KB" -#define LL(x) (unsigned int)((__u64)(x)>>10), (unsigned int)((x)&1023) - -typedef enum { - ft_t_nil = -1, - ft_t_bug, - ft_t_err, - ft_t_warn, - ft_t_info, - ft_t_noise, - ft_t_flow, - ft_t_fdc_dma, - ft_t_data_flow, - ft_t_any -} ft_trace_t; - -#ifdef CONFIG_FT_NO_TRACE_AT_ALL -/* the compiler will optimize away most TRACE() macros - */ -#define FT_TRACE_TOP_LEVEL ft_t_bug -#define TRACE_FUN(level) do {} while(0) -#define TRACE_EXIT return -#define TRACE(l, m, i...) \ -{ \ - if ((ft_trace_t)(l) == FT_TRACE_TOP_LEVEL) { \ - printk(KERN_INFO"ftape%s(%s):\n" \ - KERN_INFO m".\n" ,__FILE__, __FUNCTION__ , ##i); \ - } \ -} -#define SET_TRACE_LEVEL(l) if ((l) == (l)) do {} while(0) -#define TRACE_LEVEL FT_TRACE_TOP_LEVEL - -#else - -#ifdef CONFIG_FT_NO_TRACE -/* the compiler will optimize away many TRACE() macros - * the ftape_simple_trace_call() function simply increments - * the function nest level. - */ -#define FT_TRACE_TOP_LEVEL ft_t_warn -#define TRACE_FUN(level) ftape_function_nest_level++ -#define TRACE_EXIT ftape_function_nest_level--; return - -#else -#ifdef CONFIG_FT_FULL_DEBUG -#define FT_TRACE_TOP_LEVEL ft_t_any -#else -#define FT_TRACE_TOP_LEVEL ft_t_flow -#endif -#define TRACE_FUN(level) \ - const ft_trace_t _tracing = level; \ - if (ftape_tracing >= (ft_trace_t)(level) && \ - (ft_trace_t)(level) <= FT_TRACE_TOP_LEVEL) \ - ftape_trace_call(__FILE__, __FUNCTION__); \ - ftape_function_nest_level ++; - -#define TRACE_EXIT \ - --ftape_function_nest_level; \ - if (ftape_tracing >= (ft_trace_t)(_tracing) && \ - (ft_trace_t)(_tracing) <= FT_TRACE_TOP_LEVEL) \ - ftape_trace_exit(__FILE__, __FUNCTION__); \ - return - -#endif - -#define TRACE(l, m, i...) \ -{ \ - if (ftape_tracing >= (ft_trace_t)(l) && \ - (ft_trace_t)(l) <= FT_TRACE_TOP_LEVEL) { \ - ftape_trace_log(__FILE__, __FUNCTION__); \ - printk(m".\n" ,##i); \ - } \ -} - -#define SET_TRACE_LEVEL(l) \ -{ \ - if ((ft_trace_t)(l) <= FT_TRACE_TOP_LEVEL) { \ - ftape_tracing = (ft_trace_t)(l); \ - } else { \ - ftape_tracing = FT_TRACE_TOP_LEVEL; \ - } \ -} -#define TRACE_LEVEL \ -((ftape_tracing <= FT_TRACE_TOP_LEVEL) ? ftape_tracing : FT_TRACE_TOP_LEVEL) - - -/* Global variables declared in tracing.c - */ -extern ft_trace_t ftape_tracing; /* sets default level */ -extern int ftape_function_nest_level; - -/* Global functions declared in tracing.c - */ -extern void ftape_trace_call(const char *file, const char *name); -extern void ftape_trace_exit(const char *file, const char *name); -extern void ftape_trace_log (const char *file, const char *name); - -#endif /* !defined(CONFIG_FT_NO_TRACE_AT_ALL) */ - -/* - * Abort with a message. - */ -#define TRACE_ABORT(res, i...) \ -{ \ - TRACE(i); \ - TRACE_EXIT res; \ -} - -/* The following transforms the common "if(result < 0) ... " into a - * one-liner. - */ -#define _TRACE_CATCH(level, fun, action) \ -{ \ - int _res = (fun); \ - if (_res < 0) { \ - do { action /* */ ; } while(0); \ - TRACE_ABORT(_res, level, "%s failed: %d", #fun, _res); \ - } \ -} - -#define TRACE_CATCH(fun, fail) _TRACE_CATCH(ft_t_err, fun, fail) - -/* Abort the current function when signalled. This doesn't belong here, - * but rather into ftape-rw.h (maybe) - */ -#define FT_SIGNAL_EXIT(sig_mask) \ - if (sigtestsetmask(¤t->pending.signal, sig_mask)) { \ - TRACE_ABORT(-EINTR, \ - ft_t_warn, \ - "interrupted by non-blockable signal"); \ - } - -#endif /* _FTAPE_TRACING_H */ diff --git a/drivers/char/ftape/lowlevel/ftape-write.c b/drivers/char/ftape/lowlevel/ftape-write.c deleted file mode 100644 index 45601ec801ee..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-write.c +++ /dev/null @@ -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); - } -} diff --git a/drivers/char/ftape/lowlevel/ftape-write.h b/drivers/char/ftape/lowlevel/ftape-write.h deleted file mode 100644 index 0e7f898b7af9..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-write.h +++ /dev/null @@ -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 */ - diff --git a/drivers/char/ftape/lowlevel/ftape_syms.c b/drivers/char/ftape/lowlevel/ftape_syms.c deleted file mode 100644 index 8e0dc4a07ca6..000000000000 --- a/drivers/char/ftape/lowlevel/ftape_syms.c +++ /dev/null @@ -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 - diff --git a/drivers/char/ftape/zftape/Makefile b/drivers/char/ftape/zftape/Makefile deleted file mode 100644 index 6d91c1f77c05..000000000000 --- a/drivers/char/ftape/zftape/Makefile +++ /dev/null @@ -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 diff --git a/drivers/char/ftape/zftape/zftape-buffers.c b/drivers/char/ftape/zftape/zftape-buffers.c deleted file mode 100644 index 7ebce2ec7897..000000000000 --- a/drivers/char/ftape/zftape/zftape-buffers.c +++ /dev/null @@ -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; -} diff --git a/drivers/char/ftape/zftape/zftape-buffers.h b/drivers/char/ftape/zftape/zftape-buffers.h deleted file mode 100644 index 798e3128c682..000000000000 --- a/drivers/char/ftape/zftape/zftape-buffers.h +++ /dev/null @@ -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 - - - - - - - diff --git a/drivers/char/ftape/zftape/zftape-ctl.c b/drivers/char/ftape/zftape/zftape-ctl.c deleted file mode 100644 index 22ba0f5d00cf..000000000000 --- a/drivers/char/ftape/zftape/zftape-ctl.c +++ /dev/null @@ -1,1417 +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-ctl.c,v $ - * $Revision: 1.2.6.2 $ - * $Date: 1997/11/14 18:07:33 $ - * - * This file contains the non-read/write zftape functions - * for the QIC-40/80/3010/3020 floppy-tape driver for Linux. - */ - -#include <linux/errno.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/fcntl.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_write_protected; /* this is when cartridge rdonly or O_RDONLY */ -int zft_header_read; -int zft_offline; -unsigned int zft_unit; -int zft_resid; -int zft_mt_compression; - -/* Local vars. - */ -static int going_offline; - -typedef int (mt_fun)(int *argptr); -typedef int (*mt_funp)(int *argptr); -typedef struct -{ - mt_funp function; - unsigned offline : 1; /* op permitted if offline or no_tape */ - unsigned write_protected : 1; /* op permitted if write-protected */ - unsigned not_formatted : 1; /* op permitted if tape not formatted */ - unsigned raw_mode : 1; /* op permitted if zft_mode == 0 */ - unsigned need_idle_state : 1; /* need to call def_idle_state */ - char *name; -} fun_entry; - -static mt_fun mt_dummy, mt_reset, mt_fsr, mt_bsr, mt_rew, mt_offl, mt_nop, - mt_weof, mt_erase, mt_ras2, mt_setblk, mt_setdensity, - mt_seek, mt_tell, mt_reten, mt_eom, mt_fsf, mt_bsf, - mt_fsfm, mt_bsfm, mt_setdrvbuffer, mt_compression; - -static fun_entry mt_funs[]= -{ - {mt_reset , 1, 1, 1, 1, 0, "MT_RESET" }, /* 0 */ - {mt_fsf , 0, 1, 0, 0, 1, "MT_FSF" }, - {mt_bsf , 0, 1, 0, 0, 1, "MT_BSF" }, - {mt_fsr , 0, 1, 0, 1, 1, "MT_FSR" }, - {mt_bsr , 0, 1, 0, 1, 1, "MT_BSR" }, - {mt_weof , 0, 0, 0, 0, 0, "MT_WEOF" }, /* 5 */ - {mt_rew , 0, 1, 1, 1, 0, "MT_REW" }, - {mt_offl , 0, 1, 1, 1, 0, "MT_OFFL" }, - {mt_nop , 1, 1, 1, 1, 0, "MT_NOP" }, - {mt_reten , 0, 1, 1, 1, 0, "MT_RETEN" }, - {mt_bsfm , 0, 1, 0, 0, 1, "MT_BSFM" }, /* 10 */ - {mt_fsfm , 0, 1, 0, 0, 1, "MT_FSFM" }, - {mt_eom , 0, 1, 0, 0, 1, "MT_EOM" }, - {mt_erase , 0, 0, 0, 1, 0, "MT_ERASE" }, - {mt_dummy , 1, 1, 1, 1, 0, "MT_RAS1" }, - {mt_ras2 , 0, 0, 0, 1, 0, "MT_RAS2" }, - {mt_dummy , 1, 1, 1, 1, 0, "MT_RAS3" }, - {mt_dummy , 1, 1, 1, 1, 0, "UNKNOWN" }, - {mt_dummy , 1, 1, 1, 1, 0, "UNKNOWN" }, - {mt_dummy , 1, 1, 1, 1, 0, "UNKNOWN" }, - {mt_setblk , 1, 1, 1, 1, 1, "MT_SETBLK"}, /* 20 */ - {mt_setdensity , 1, 1, 1, 1, 0, "MT_SETDENSITY"}, - {mt_seek , 0, 1, 0, 1, 1, "MT_SEEK" }, - {mt_dummy , 0, 1, 0, 1, 1, "MT_TELL" }, /* wr-only ?! */ - {mt_setdrvbuffer, 1, 1, 1, 1, 0, "MT_SETDRVBUFFER" }, - {mt_dummy , 1, 1, 1, 1, 0, "MT_FSS" }, /* 25 */ - {mt_dummy , 1, 1, 1, 1, 0, "MT_BSS" }, - {mt_dummy , 1, 1, 1, 1, 0, "MT_WSM" }, - {mt_dummy , 1, 1, 1, 1, 0, "MT_LOCK" }, - {mt_dummy , 1, 1, 1, 1, 0, "MT_UNLOCK"}, - {mt_dummy , 1, 1, 1, 1, 0, "MT_LOAD" }, /* 30 */ - {mt_dummy , 1, 1, 1, 1, 0, "MT_UNLOAD"}, - {mt_compression , 1, 1, 1, 0, 1, "MT_COMPRESSION"}, - {mt_dummy , 1, 1, 1, 1, 0, "MT_SETPART"}, - {mt_dummy , 1, 1, 1, 1, 0, "MT_MKPART"} -}; - -#define NR_MT_CMDS NR_ITEMS(mt_funs) - -void zft_reset_position(zft_position *pos) -{ - TRACE_FUN(ft_t_flow); - - pos->seg_byte_pos = - pos->volume_pos = 0; - if (zft_header_read) { - /* need to keep track of the volume table and - * compression map. We therefor simply - * position at the beginning of the first - * volume. This covers old ftape archives as - * well has various flavours of the - * compression map segments. The worst case is - * that the compression map shows up as a - * additional volume in front of all others. - */ - pos->seg_pos = zft_find_volume(0)->start_seg; - pos->tape_pos = zft_calc_tape_pos(pos->seg_pos); - } else { - pos->tape_pos = 0; - pos->seg_pos = -1; - } - zft_just_before_eof = 0; - zft_deblock_segment = -1; - zft_io_state = zft_idle; - zft_zap_read_buffers(); - zft_prevent_flush(); - /* unlock the compresison module if it is loaded. - * The zero arg means not to try to load the module. - */ - if (zft_cmpr_lock(0) == 0) { - (*zft_cmpr_ops->reset)(); /* unlock */ - } - TRACE_EXIT; -} - -static void zft_init_driver(void) -{ - TRACE_FUN(ft_t_flow); - - zft_resid = - zft_header_read = - zft_old_ftape = - zft_offline = - zft_write_protected = - going_offline = - zft_mt_compression = - zft_header_changed = - zft_volume_table_changed = - zft_written_segments = 0; - zft_blk_sz = CONFIG_ZFT_DFLT_BLK_SZ; - zft_reset_position(&zft_pos); /* does most of the stuff */ - ftape_zap_read_buffers(); - ftape_set_state(idle); - TRACE_EXIT; -} - -int zft_def_idle_state(void) -{ - int result = 0; - TRACE_FUN(ft_t_flow); - - if (!zft_header_read) { - result = zft_read_header_segments(); - } else if ((result = zft_flush_buffers()) >= 0 && zft_qic_mode) { - /* don't move past eof - */ - (void)zft_close_volume(&zft_pos); - } - if (ftape_abort_operation() < 0) { - TRACE(ft_t_warn, "ftape_abort_operation() failed"); - result = -EIO; - } - /* clear remaining read buffers */ - zft_zap_read_buffers(); - zft_io_state = zft_idle; - TRACE_EXIT result; -} - -/***************************************************************************** - * * - * functions for the MTIOCTOP commands * - * * - *****************************************************************************/ - -static int mt_dummy(int *dummy) -{ - TRACE_FUN(ft_t_flow); - - TRACE_EXIT -ENOSYS; -} - -static int mt_reset(int *dummy) -{ - TRACE_FUN(ft_t_flow); - - (void)ftape_seek_to_bot(); - TRACE_CATCH(ftape_reset_drive(), - zft_init_driver(); zft_uninit_mem(); zft_offline = 1); - /* fake a re-open of the device. This will set all flage and - * allocate buffers as appropriate. The new tape condition will - * force the open routine to do anything we need. - */ - TRACE_CATCH(_zft_open(-1 /* fake reopen */, 0 /* dummy */),); - TRACE_EXIT 0; -} - -static int mt_fsf(int *arg) -{ - int result; - TRACE_FUN(ft_t_flow); - - result = zft_skip_volumes(*arg, &zft_pos); - zft_just_before_eof = 0; - TRACE_EXIT result; -} - -static int mt_bsf(int *arg) -{ - int result = 0; - TRACE_FUN(ft_t_flow); - - if (*arg != 0) { - result = zft_skip_volumes(-*arg + 1, &zft_pos); - } - TRACE_EXIT result; -} - -static int seek_block(__s64 data_offset, - __s64 block_increment, - zft_position *pos) -{ - int result = 0; - __s64 new_block_pos; - __s64 vol_block_count; - const zft_volinfo *volume; - int exceed; - TRACE_FUN(ft_t_flow); - - volume = zft_find_volume(pos->seg_pos); - if (volume->start_seg == 0 || volume->end_seg == 0) { - TRACE_EXIT -EIO; - } - new_block_pos = (zft_div_blksz(data_offset, volume->blk_sz) - + block_increment); - vol_block_count = zft_div_blksz(volume->size, volume->blk_sz); - if (new_block_pos < 0) { - TRACE(ft_t_noise, - "new_block_pos " LL_X " < 0", LL(new_block_pos)); - zft_resid = (int)new_block_pos; - new_block_pos = 0; - exceed = 1; - } else if (new_block_pos > vol_block_count) { - TRACE(ft_t_noise, - "new_block_pos " LL_X " exceeds size of volume " LL_X, - LL(new_block_pos), LL(vol_block_count)); - zft_resid = (int)(vol_block_count - new_block_pos); - new_block_pos = vol_block_count; - exceed = 1; - } else { - exceed = 0; - } - if (zft_use_compression && volume->use_compression) { - TRACE_CATCH(zft_cmpr_lock(1 /* try to load */),); - result = (*zft_cmpr_ops->seek)(new_block_pos, pos, volume, - zft_deblock_buf); - pos->tape_pos = zft_calc_tape_pos(pos->seg_pos); - pos->tape_pos += pos->seg_byte_pos; - } else { - pos->volume_pos = zft_mul_blksz(new_block_pos, volume->blk_sz); - pos->tape_pos = zft_calc_tape_pos(volume->start_seg); - pos->tape_pos += pos->volume_pos; - pos->seg_pos = zft_calc_seg_byte_coord(&pos->seg_byte_pos, - pos->tape_pos); - } - zft_just_before_eof = volume->size == pos->volume_pos; - if (zft_just_before_eof) { - /* why this? because zft_file_no checks agains start - * and end segment of a volume. We do not want to - * advance to the next volume with this function. - */ - TRACE(ft_t_noise, "set zft_just_before_eof"); - zft_position_before_eof(pos, volume); - } - TRACE(ft_t_noise, "\n" - KERN_INFO "new_seg_pos : %d\n" - KERN_INFO "new_tape_pos: " LL_X "\n" - KERN_INFO "vol_size : " LL_X "\n" - KERN_INFO "seg_byte_pos: %d\n" - KERN_INFO "blk_sz : %d", - pos->seg_pos, LL(pos->tape_pos), - LL(volume->size), pos->seg_byte_pos, - volume->blk_sz); - if (!exceed) { - zft_resid = new_block_pos - zft_div_blksz(pos->volume_pos, - volume->blk_sz); - } - if (zft_resid < 0) { - zft_resid = -zft_resid; - } - TRACE_EXIT ((exceed || zft_resid != 0) && result >= 0) ? -EINVAL : result; -} - -static int mt_fsr(int *arg) -{ - int result; - TRACE_FUN(ft_t_flow); - - result = seek_block(zft_pos.volume_pos, *arg, &zft_pos); - TRACE_EXIT result; -} - -static int mt_bsr(int *arg) -{ - int result; - TRACE_FUN(ft_t_flow); - - result = seek_block(zft_pos.volume_pos, -*arg, &zft_pos); - TRACE_EXIT result; -} - -static int mt_weof(int *arg) -{ - int result; - TRACE_FUN(ft_t_flow); - - TRACE_CATCH(zft_flush_buffers(),); - result = zft_weof(*arg, &zft_pos); - TRACE_EXIT result; -} - -static int mt_rew(int *dummy) -{ - int result; - TRACE_FUN(ft_t_flow); - - if(zft_header_read) { - (void)zft_def_idle_state(); - } - result = ftape_seek_to_bot(); - zft_reset_position(&zft_pos); - TRACE_EXIT result; -} - -static int mt_offl(int *dummy) -{ - int result; - TRACE_FUN(ft_t_flow); - - going_offline= 1; - result = mt_rew(NULL); - TRACE_EXIT result; -} - -static int mt_nop(int *dummy) -{ - TRACE_FUN(ft_t_flow); - /* should we set tape status? - */ - if (!zft_offline) { /* offline includes no_tape */ - (void)zft_def_idle_state(); - } - TRACE_EXIT 0; -} - -static int mt_reten(int *dummy) -{ - int result; - TRACE_FUN(ft_t_flow); - - if(zft_header_read) { - (void)zft_def_idle_state(); - } - result = ftape_seek_to_eot(); - if (result >= 0) { - result = ftape_seek_to_bot(); - } - TRACE_EXIT(result); -} - -static int fsfbsfm(int arg, zft_position *pos) -{ - const zft_volinfo *vtbl; - __s64 block_pos; - TRACE_FUN(ft_t_flow); - - /* What to do? This should seek to the next file-mark and - * position BEFORE. That is, a next write would just extend - * the current file. Well. Let's just seek to the end of the - * current file, if count == 1. If count > 1, then do a - * "mt_fsf(count - 1)", and then seek to the end of that file. - * If count == 0, do nothing - */ - if (arg == 0) { - TRACE_EXIT 0; - } - zft_just_before_eof = 0; - TRACE_CATCH(zft_skip_volumes(arg < 0 ? arg : arg-1, pos), - if (arg > 0) { - zft_resid ++; - }); - vtbl = zft_find_volume(pos->seg_pos); - block_pos = zft_div_blksz(vtbl->size, vtbl->blk_sz); - (void)seek_block(0, block_pos, pos); - if (pos->volume_pos != vtbl->size) { - zft_just_before_eof = 0; - zft_resid = 1; - /* we didn't managed to go there */ - TRACE_ABORT(-EIO, ft_t_err, - "wanted file position " LL_X ", arrived at " LL_X, - LL(vtbl->size), LL(pos->volume_pos)); - } - zft_just_before_eof = 1; - TRACE_EXIT 0; -} - -static int mt_bsfm(int *arg) -{ - int result; - TRACE_FUN(ft_t_flow); - - result = fsfbsfm(-*arg, &zft_pos); - TRACE_EXIT result; -} - -static int mt_fsfm(int *arg) -{ - int result; - TRACE_FUN(ft_t_flow); - - result = fsfbsfm(*arg, &zft_pos); - TRACE_EXIT result; -} - -static int mt_eom(int *dummy) -{ - TRACE_FUN(ft_t_flow); - - zft_skip_to_eom(&zft_pos); - TRACE_EXIT 0; -} - -static int mt_erase(int *dummy) -{ - int result; - TRACE_FUN(ft_t_flow); - - result = zft_erase(); - TRACE_EXIT result; -} - -static int mt_ras2(int *dummy) -{ - int result; - TRACE_FUN(ft_t_flow); - - result = -ENOSYS; - TRACE_EXIT result; -} - -/* Sets the new blocksize in BYTES - * - */ -static int mt_setblk(int *new_size) -{ - TRACE_FUN(ft_t_flow); - - if((unsigned int)(*new_size) > ZFT_MAX_BLK_SZ) { - TRACE_ABORT(-EINVAL, ft_t_info, - "desired blk_sz (%d) should be <= %d bytes", - *new_size, ZFT_MAX_BLK_SZ); - } - if ((*new_size & (FT_SECTOR_SIZE-1)) != 0) { - TRACE_ABORT(-EINVAL, ft_t_info, - "desired blk_sz (%d) must be a multiple of %d bytes", - *new_size, FT_SECTOR_SIZE); - } - if (*new_size == 0) { - if (zft_use_compression) { - TRACE_ABORT(-EINVAL, ft_t_info, - "Variable block size not yet " - "supported with compression"); - } - *new_size = 1; - } - zft_blk_sz = *new_size; - TRACE_EXIT 0; -} - -static int mt_setdensity(int *arg) -{ - TRACE_FUN(ft_t_flow); - - SET_TRACE_LEVEL(*arg); - TRACE(TRACE_LEVEL, "tracing set to %d", TRACE_LEVEL); - if ((int)TRACE_LEVEL != *arg) { - TRACE_EXIT -EINVAL; - } - TRACE_EXIT 0; -} - -static int mt_seek(int *new_block_pos) -{ - int result= 0; - TRACE_FUN(ft_t_any); - - result = seek_block(0, (__s64)*new_block_pos, &zft_pos); - TRACE_EXIT result; -} - -/* OK, this is totally different from SCSI, but the worst thing that can - * happen is that there is not enough defragmentated memory that can be - * allocated. Also, there is a hardwired limit of 16 dma buffers in the - * stock ftape module. This shouldn't bring the system down. - * - * NOTE: the argument specifies the total number of dma buffers to use. - * The driver needs at least 3 buffers to function at all. - * - */ -static int mt_setdrvbuffer(int *cnt) -{ - TRACE_FUN(ft_t_flow); - - if (*cnt < 3) { - TRACE_EXIT -EINVAL; - } - TRACE_CATCH(ftape_set_nr_buffers(*cnt),); - TRACE_EXIT 0; -} -/* return the block position from start of volume - */ -static int mt_tell(int *arg) -{ - TRACE_FUN(ft_t_flow); - - *arg = zft_div_blksz(zft_pos.volume_pos, - zft_find_volume(zft_pos.seg_pos)->blk_sz); - TRACE_EXIT 0; -} - -static int mt_compression(int *arg) -{ - TRACE_FUN(ft_t_flow); - - /* Ok. We could also check whether compression is available at - * all by trying to load the compression module. We could - * also check for a block size of 1 byte which is illegal - * with compression. Instead of doing it here we rely on - * zftape_write() to do the proper checks. - */ - if ((unsigned int)*arg > 1) { - TRACE_EXIT -EINVAL; - } - if (*arg != 0 && zft_blk_sz == 1) { /* variable block size */ - TRACE_ABORT(-EINVAL, ft_t_info, - "Compression not yet supported " - "with variable block size"); - } - zft_mt_compression = *arg; - if ((zft_unit & ZFT_ZIP_MODE) == 0) { - zft_use_compression = zft_mt_compression; - } - TRACE_EXIT 0; -} - -/* check whether write access is allowed. Write access is denied when - * + zft_write_protected == 1 -- this accounts for either hard write - * protection of the cartridge or for - * O_RDONLY access mode of the tape device - * + zft_offline == 1 -- this meany that there is either no tape - * or that the MTOFFLINE ioctl has been - * previously issued (`soft eject') - * + ft_formatted == 0 -- this means that the cartridge is not - * formatted - * Then we distinuguish two cases. When zft_qic_mode is TRUE, then we try - * to emulate a `traditional' (aka SCSI like) UN*X tape device. Therefore we - * deny writes when - * + zft_qic_mode ==1 && - * (!zft_tape_at_lbot() && -- tape no at logical BOT - * !(zft_tape_at_eom() || -- tape not at logical EOM (or EOD) - * (zft_tape_at_eom() && - * zft_old_ftape()))) -- we can't add new volume to tapes - * written by old ftape because ftape - * don't use the volume table - * - * when the drive is in true raw mode (aka /dev/rawft0) then we don't - * care about LBOT and EOM conditions. This device is intended for a - * user level program that wants to truly implement the QIC-80 compliance - * at the logical data layout level of the cartridge, i.e. implement all - * that volume table and volume directory stuff etc.< - */ -int zft_check_write_access(zft_position *pos) -{ - TRACE_FUN(ft_t_flow); - - if (zft_offline) { /* offline includes no_tape */ - TRACE_ABORT(-ENXIO, - ft_t_info, "tape is offline or no cartridge"); - } - if (!ft_formatted) { - TRACE_ABORT(-EACCES, ft_t_info, "tape is not formatted"); - } - if (zft_write_protected) { - TRACE_ABORT(-EACCES, ft_t_info, "cartridge write protected"); - } - if (zft_qic_mode) { - /* check BOT condition */ - if (!zft_tape_at_lbot(pos)) { - /* protect cartridges written by old ftape if - * not at BOT because they use the vtbl - * segment for storing data - */ - if (zft_old_ftape) { - TRACE_ABORT(-EACCES, ft_t_warn, - "Cannot write to cartridges written by old ftape when not at BOT"); - } - /* not at BOT, but allow writes at EOD, of course - */ - if (!zft_tape_at_eod(pos)) { - TRACE_ABORT(-EACCES, ft_t_info, - "tape not at BOT and not at EOD"); - } - } - /* fine. Now the tape is either at BOT or at EOD. */ - } - /* or in raw mode in which case we don't care about BOT and EOD */ - TRACE_EXIT 0; -} - -/* OPEN routine called by kernel-interface code - * - * NOTE: this is also called by mt_reset() with dev_minor == -1 - * to fake a reopen after a reset. - */ -int _zft_open(unsigned int dev_minor, unsigned int access_mode) -{ - static unsigned int tape_unit; - static unsigned int file_access_mode; - int result; - TRACE_FUN(ft_t_flow); - - if ((int)dev_minor == -1) { - /* fake reopen */ - zft_unit = tape_unit; - access_mode = file_access_mode; - zft_init_driver(); /* reset all static data to defaults */ - } else { - tape_unit = dev_minor; - file_access_mode = access_mode; - if ((result = ftape_enable(FTAPE_SEL(dev_minor))) < 0) { - TRACE_ABORT(-ENXIO, ft_t_err, - "ftape_enable failed: %d", result); - } - if (ft_new_tape || ft_no_tape || !ft_formatted || - (FTAPE_SEL(zft_unit) != FTAPE_SEL(dev_minor)) || - (zft_unit & ZFT_RAW_MODE) != (dev_minor & ZFT_RAW_MODE)) { - /* reset all static data to defaults, - */ - zft_init_driver(); - } - zft_unit = dev_minor; - } - zft_set_flags(zft_unit); /* decode the minor bits */ - if (zft_blk_sz == 1 && zft_use_compression) { - ftape_disable(); /* resets ft_no_tape */ - TRACE_ABORT(-ENODEV, ft_t_warn, "Variable block size not yet " - "supported with compression"); - } - /* no need for most of the buffers when no tape or not - * formatted. for the read/write operations, it is the - * regardless whether there is no tape, a not-formatted tape - * or the whether the driver is soft offline. - * Nevertheless we allow some ioctls with non-formatted tapes, - * like rewind and reset. - */ - if (ft_no_tape || !ft_formatted) { - zft_uninit_mem(); - } - if (ft_no_tape) { - zft_offline = 1; /* so we need not test two variables */ - } - if ((access_mode == O_WRONLY || access_mode == O_RDWR) && - (ft_write_protected || ft_no_tape)) { - ftape_disable(); /* resets ft_no_tape */ - TRACE_ABORT(ft_no_tape ? -ENXIO : -EROFS, - ft_t_warn, "wrong access mode %s cartridge", - ft_no_tape ? "without a" : "with write protected"); - } - zft_write_protected = (access_mode == O_RDONLY || - ft_write_protected != 0); - if (zft_write_protected) { - TRACE(ft_t_noise, - "read only access mode: %d, " - "drive write protected: %d", - access_mode == O_RDONLY, - ft_write_protected != 0); - } - if (!zft_offline) { - TRACE_CATCH(zft_vmalloc_once(&zft_deblock_buf,FT_SEGMENT_SIZE), - ftape_disable()); - } - /* zft_seg_pos should be greater than the vtbl segpos but not - * if in compatibility mode and only after we read in the - * header segments - * - * might also be a problem if the user makes a backup with a - * *qft* device and rewinds it with a raw device. - */ - if (zft_qic_mode && - !zft_old_ftape && - zft_pos.seg_pos >= 0 && - zft_header_read && - zft_pos.seg_pos <= ft_first_data_segment) { - TRACE(ft_t_noise, "you probably mixed up the zftape devices!"); - zft_reset_position(&zft_pos); - } - TRACE_EXIT 0; -} - -/* RELEASE routine called by kernel-interface code - */ -int _zft_close(void) -{ - int result = 0; - TRACE_FUN(ft_t_flow); - - if (zft_offline) { - /* call the hardware release routine. Puts the drive offline */ - ftape_disable(); - TRACE_EXIT 0; - } - if (!(ft_write_protected || zft_old_ftape)) { - result = zft_flush_buffers(); - TRACE(ft_t_noise, "writing file mark at current position"); - if (zft_qic_mode && zft_close_volume(&zft_pos) == 0) { - zft_move_past_eof(&zft_pos); - } - if ((zft_tape_at_lbot(&zft_pos) || - !(zft_unit & FTAPE_NO_REWIND))) { - if (result >= 0) { - result = zft_update_header_segments(); - } else { - TRACE(ft_t_err, - "Error: unable to update header segments"); - } - } - } - ftape_abort_operation(); - if (!(zft_unit & FTAPE_NO_REWIND)) { - TRACE(ft_t_noise, "rewinding tape"); - if (ftape_seek_to_bot() < 0 && result >= 0) { - result = -EIO; /* keep old value */ - } - zft_reset_position(&zft_pos); - } - zft_zap_read_buffers(); - /* now free up memory as much as possible. We don't destroy - * the deblock buffer if it containes a valid segment. - */ - if (zft_deblock_segment == -1) { - zft_vfree(&zft_deblock_buf, FT_SEGMENT_SIZE); - } - /* high level driver status, forces creation of a new volume - * when calling ftape_write again and not zft_just_before_eof - */ - zft_io_state = zft_idle; - if (going_offline) { - zft_init_driver(); - zft_uninit_mem(); - going_offline = 0; - zft_offline = 1; - } else if (zft_cmpr_lock(0 /* don't load */) == 0) { - (*zft_cmpr_ops->reset)(); /* unlock it again */ - } - zft_memory_stats(); - /* call the hardware release routine. Puts the drive offline */ - ftape_disable(); - TRACE_EXIT result; -} - -/* - * the wrapper function around the wrapper MTIOCTOP ioctl - */ -static int mtioctop(struct mtop *mtop, int arg_size) -{ - int result = 0; - fun_entry *mt_fun_entry; - TRACE_FUN(ft_t_flow); - - if (arg_size != sizeof(struct mtop) || mtop->mt_op >= NR_MT_CMDS) { - TRACE_EXIT -EINVAL; - } - TRACE(ft_t_noise, "calling MTIOCTOP command: %s", - mt_funs[mtop->mt_op].name); - mt_fun_entry= &mt_funs[mtop->mt_op]; - zft_resid = mtop->mt_count; - if (!mt_fun_entry->offline && zft_offline) { - if (ft_no_tape) { - TRACE_ABORT(-ENXIO, ft_t_info, "no tape present"); - } else { - TRACE_ABORT(-ENXIO, ft_t_info, "drive is offline"); - } - } - if (!mt_fun_entry->not_formatted && !ft_formatted) { - TRACE_ABORT(-EACCES, ft_t_info, "tape is not formatted"); - } - if (!mt_fun_entry->write_protected) { - TRACE_CATCH(zft_check_write_access(&zft_pos),); - } - if (mt_fun_entry->need_idle_state && !(zft_offline || !ft_formatted)) { - TRACE_CATCH(zft_def_idle_state(),); - } - if (!zft_qic_mode && !mt_fun_entry->raw_mode) { - TRACE_ABORT(-EACCES, ft_t_info, -"Drive needs to be in QIC-80 compatibility mode for this command"); - } - result = (mt_fun_entry->function)(&mtop->mt_count); - if (zft_tape_at_lbot(&zft_pos)) { - TRACE_CATCH(zft_update_header_segments(),); - } - if (result >= 0) { - zft_resid = 0; - } - TRACE_EXIT result; -} - -/* - * standard MTIOCGET ioctl - */ -static int mtiocget(struct mtget *mtget, int arg_size) -{ - const zft_volinfo *volume; - __s64 max_tape_pos; - TRACE_FUN(ft_t_flow); - - if (arg_size != sizeof(struct mtget)) { - TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", - arg_size); - } - mtget->mt_type = ft_drive_type.vendor_id + 0x800000; - mtget->mt_dsreg = ft_last_status.space; - mtget->mt_erreg = ft_last_error.space; /* error register */ - mtget->mt_resid = zft_resid; /* residuum of writes, reads and - * MTIOCTOP commands - */ - if (!zft_offline) { /* neither no_tape nor soft offline */ - mtget->mt_gstat = GMT_ONLINE(~0UL); - /* should rather return the status of the cartridge - * than the access mode of the file, therefor use - * ft_write_protected, not zft_write_protected - */ - if (ft_write_protected) { - mtget->mt_gstat |= GMT_WR_PROT(~0UL); - } - if(zft_header_read) { /* this catches non-formatted */ - volume = zft_find_volume(zft_pos.seg_pos); - mtget->mt_fileno = volume->count; - max_tape_pos = zft_capacity - zft_blk_sz; - if (zft_use_compression) { - max_tape_pos -= ZFT_CMPR_OVERHEAD; - } - if (zft_tape_at_eod(&zft_pos)) { - mtget->mt_gstat |= GMT_EOD(~0UL); - } - if (zft_pos.tape_pos > max_tape_pos) { - mtget->mt_gstat |= GMT_EOT(~0UL); - } - mtget->mt_blkno = zft_div_blksz(zft_pos.volume_pos, - volume->blk_sz); - if (zft_just_before_eof) { - mtget->mt_gstat |= GMT_EOF(~0UL); - } - if (zft_tape_at_lbot(&zft_pos)) { - mtget->mt_gstat |= GMT_BOT(~0UL); - } - } else { - mtget->mt_fileno = mtget->mt_blkno = -1; - if (mtget->mt_dsreg & QIC_STATUS_AT_BOT) { - mtget->mt_gstat |= GMT_BOT(~0UL); - } - } - } else { - if (ft_no_tape) { - mtget->mt_gstat = GMT_DR_OPEN(~0UL); - } else { - mtget->mt_gstat = 0UL; - } - mtget->mt_fileno = mtget->mt_blkno = -1; - } - TRACE_EXIT 0; -} - -#ifdef MTIOCRDFTSEG -/* - * Read a floppy tape segment. This is useful for manipulating the - * volume table, and read the old header segment before re-formatting - * the cartridge. - */ -static int mtiocrdftseg(struct mtftseg * mtftseg, int arg_size) -{ - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCRDFTSEG"); - if (zft_qic_mode) { - TRACE_ABORT(-EACCES, ft_t_info, - "driver needs to be in raw mode for this ioctl"); - } - if (arg_size != sizeof(struct mtftseg)) { - TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", - arg_size); - } - if (zft_offline) { - TRACE_EXIT -ENXIO; - } - if (mtftseg->mt_mode != FT_RD_SINGLE && - mtftseg->mt_mode != FT_RD_AHEAD) { - TRACE_ABORT(-EINVAL, ft_t_info, "invalid read mode"); - } - if (!ft_formatted) { - TRACE_EXIT -EACCES; /* -ENXIO ? */ - - } - if (!zft_header_read) { - TRACE_CATCH(zft_def_idle_state(),); - } - if (mtftseg->mt_segno > ft_last_data_segment) { - TRACE_ABORT(-EINVAL, ft_t_info, "segment number is too large"); - } - mtftseg->mt_result = ftape_read_segment(mtftseg->mt_segno, - zft_deblock_buf, - mtftseg->mt_mode); - if (mtftseg->mt_result < 0) { - /* a negativ result is not an ioctl error. if - * the user wants to read damaged tapes, - * it's up to her/him - */ - TRACE_EXIT 0; - } - if (copy_to_user(mtftseg->mt_data, - zft_deblock_buf, - mtftseg->mt_result) != 0) { - TRACE_EXIT -EFAULT; - } - TRACE_EXIT 0; -} -#endif - -#ifdef MTIOCWRFTSEG -/* - * write a floppy tape segment. This version features writing of - * deleted address marks, and gracefully ignores the (software) - * ft_formatted flag to support writing of header segments after - * formatting. - */ -static int mtiocwrftseg(struct mtftseg * mtftseg, int arg_size) -{ - int result; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCWRFTSEG"); - if (zft_write_protected || zft_qic_mode) { - TRACE_EXIT -EACCES; - } - if (arg_size != sizeof(struct mtftseg)) { - TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", - arg_size); - } - if (zft_offline) { - TRACE_EXIT -ENXIO; - } - if (mtftseg->mt_mode != FT_WR_ASYNC && - mtftseg->mt_mode != FT_WR_MULTI && - mtftseg->mt_mode != FT_WR_SINGLE && - mtftseg->mt_mode != FT_WR_DELETE) { - TRACE_ABORT(-EINVAL, ft_t_info, "invalid write mode"); - } - /* - * We don't check for ft_formatted, because this gives - * only the software status of the driver. - * - * We assume that the user knows what it is - * doing. And rely on the low level stuff to fail - * when the tape isn't formatted. We only make sure - * that The header segment buffer is allocated, - * because it holds the bad sector map. - */ - if (zft_hseg_buf == NULL) { - TRACE_EXIT -ENXIO; - } - if (mtftseg->mt_mode != FT_WR_DELETE) { - if (copy_from_user(zft_deblock_buf, - mtftseg->mt_data, - FT_SEGMENT_SIZE) != 0) { - TRACE_EXIT -EFAULT; - } - } - mtftseg->mt_result = ftape_write_segment(mtftseg->mt_segno, - zft_deblock_buf, - mtftseg->mt_mode); - if (mtftseg->mt_result >= 0 && mtftseg->mt_mode == FT_WR_SINGLE) { - /* - * a negativ result is not an ioctl error. if - * the user wants to write damaged tapes, - * it's up to her/him - */ - if ((result = ftape_loop_until_writes_done()) < 0) { - mtftseg->mt_result = result; - } - } - TRACE_EXIT 0; -} -#endif - -#ifdef MTIOCVOLINFO -/* - * get information about volume positioned at. - */ -static int mtiocvolinfo(struct mtvolinfo *volinfo, int arg_size) -{ - const zft_volinfo *volume; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCVOLINFO"); - if (arg_size != sizeof(struct mtvolinfo)) { - TRACE_ABORT(-EINVAL, - ft_t_info, "bad argument size: %d", arg_size); - } - if (zft_offline) { - TRACE_EXIT -ENXIO; - } - if (!ft_formatted) { - TRACE_EXIT -EACCES; - } - TRACE_CATCH(zft_def_idle_state(),); - volume = zft_find_volume(zft_pos.seg_pos); - volinfo->mt_volno = volume->count; - volinfo->mt_blksz = volume->blk_sz == 1 ? 0 : volume->blk_sz; - volinfo->mt_size = volume->size >> 10; - volinfo->mt_rawsize = ((zft_calc_tape_pos(volume->end_seg + 1) >> 10) - - (zft_calc_tape_pos(volume->start_seg) >> 10)); - volinfo->mt_cmpr = volume->use_compression; - TRACE_EXIT 0; -} -#endif - -#ifdef ZFT_OBSOLETE -static int mtioc_zftape_getblksz(struct mtblksz *blksz, int arg_size) -{ - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "\n" - KERN_INFO "Mag tape ioctl command: MTIOC_ZTAPE_GETBLKSZ\n" - KERN_INFO "This ioctl is here merely for compatibility.\n" - KERN_INFO "Please use MTIOCVOLINFO instead"); - if (arg_size != sizeof(struct mtblksz)) { - TRACE_ABORT(-EINVAL, - ft_t_info, "bad argument size: %d", arg_size); - } - if (zft_offline) { - TRACE_EXIT -ENXIO; - } - if (!ft_formatted) { - TRACE_EXIT -EACCES; - } - TRACE_CATCH(zft_def_idle_state(),); - blksz->mt_blksz = zft_find_volume(zft_pos.seg_pos)->blk_sz; - TRACE_EXIT 0; -} -#endif - -#ifdef MTIOCGETSIZE -/* - * get the capacity of the tape cartridge. - */ -static int mtiocgetsize(struct mttapesize *size, int arg_size) -{ - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Mag tape ioctl command: MTIOC_ZFTAPE_GETSIZE"); - if (arg_size != sizeof(struct mttapesize)) { - TRACE_ABORT(-EINVAL, - ft_t_info, "bad argument size: %d", arg_size); - } - if (zft_offline) { - TRACE_EXIT -ENXIO; - } - if (!ft_formatted) { - TRACE_EXIT -EACCES; - } - TRACE_CATCH(zft_def_idle_state(),); - size->mt_capacity = (unsigned int)(zft_capacity>>10); - size->mt_used = (unsigned int)(zft_get_eom_pos()>>10); - TRACE_EXIT 0; -} -#endif - -static int mtiocpos(struct mtpos *mtpos, int arg_size) -{ - int result; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCPOS"); - if (arg_size != sizeof(struct mtpos)) { - TRACE_ABORT(-EINVAL, - ft_t_info, "bad argument size: %d", arg_size); - } - result = mt_tell((int *)&mtpos->mt_blkno); - TRACE_EXIT result; -} - -#ifdef MTIOCFTFORMAT -/* - * formatting of floppy tape cartridges. This is intended to be used - * together with the MTIOCFTCMD ioctl and the new mmap feature - */ - -/* - * This function uses ftape_decode_header_segment() to inform the low - * level ftape module about the new parameters. - * - * It erases the hseg_buf. The calling process must specify all - * parameters to assure proper operation. - * - * return values: -EINVAL - wrong argument size - * -EINVAL - if ftape_decode_header_segment() failed. - */ -static int set_format_parms(struct ftfmtparms *p, __u8 *hseg_buf) -{ - ft_trace_t old_level = TRACE_LEVEL; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "MTIOCFTFORMAT operation FTFMT_SETPARMS"); - memset(hseg_buf, 0, FT_SEGMENT_SIZE); - PUT4(hseg_buf, FT_SIGNATURE, FT_HSEG_MAGIC); - - /* fill in user specified parameters - */ - hseg_buf[FT_FMT_CODE] = (__u8)p->ft_fmtcode; - PUT2(hseg_buf, FT_SPT, p->ft_spt); - hseg_buf[FT_TPC] = (__u8)p->ft_tpc; - hseg_buf[FT_FHM] = (__u8)p->ft_fhm; - hseg_buf[FT_FTM] = (__u8)p->ft_ftm; - - /* fill in sane defaults to make ftape happy. - */ - hseg_buf[FT_FSM] = (__u8)128; /* 128 is hard wired all over ftape */ - if (p->ft_fmtcode == fmt_big) { - PUT4(hseg_buf, FT_6_HSEG_1, 0); - PUT4(hseg_buf, FT_6_HSEG_2, 1); - PUT4(hseg_buf, FT_6_FRST_SEG, 2); - PUT4(hseg_buf, FT_6_LAST_SEG, p->ft_spt * p->ft_tpc - 1); - } else { - PUT2(hseg_buf, FT_HSEG_1, 0); - PUT2(hseg_buf, FT_HSEG_2, 1); - PUT2(hseg_buf, FT_FRST_SEG, 2); - PUT2(hseg_buf, FT_LAST_SEG, p->ft_spt * p->ft_tpc - 1); - } - - /* Synchronize with the low level module. This is particularly - * needed for unformatted cartridges as the QIC std was previously - * unknown BUT is needed to set data rate and to calculate timeouts. - */ - TRACE_CATCH(ftape_calibrate_data_rate(p->ft_qicstd&QIC_TAPE_STD_MASK), - _res = -EINVAL); - - /* The following will also recalcualte the timeouts for the tape - * length and QIC std we want to format to. - * abort with -EINVAL rather than -EIO - */ - SET_TRACE_LEVEL(ft_t_warn); - TRACE_CATCH(ftape_decode_header_segment(hseg_buf), - SET_TRACE_LEVEL(old_level); _res = -EINVAL); - SET_TRACE_LEVEL(old_level); - TRACE_EXIT 0; -} - -/* - * Return the internal SOFTWARE status of the kernel driver. This does - * NOT query the tape drive about its status. - */ -static int get_format_parms(struct ftfmtparms *p, __u8 *hseg_buffer) -{ - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "MTIOCFTFORMAT operation FTFMT_GETPARMS"); - p->ft_qicstd = ft_qic_std; - p->ft_fmtcode = ft_format_code; - p->ft_fhm = hseg_buffer[FT_FHM]; - p->ft_ftm = hseg_buffer[FT_FTM]; - p->ft_spt = ft_segments_per_track; - p->ft_tpc = ft_tracks_per_tape; - TRACE_EXIT 0; -} - -static int mtiocftformat(struct mtftformat *mtftformat, int arg_size) -{ - int result; - union fmt_arg *arg = &mtftformat->fmt_arg; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCFTFORMAT"); - if (zft_offline) { - if (ft_no_tape) { - TRACE_ABORT(-ENXIO, ft_t_info, "no tape present"); - } else { - TRACE_ABORT(-ENXIO, ft_t_info, "drive is offline"); - } - } - if (zft_qic_mode) { - TRACE_ABORT(-EACCES, ft_t_info, - "driver needs to be in raw mode for this ioctl"); - } - if (zft_hseg_buf == NULL) { - TRACE_CATCH(zft_vcalloc_once(&zft_hseg_buf, FT_SEGMENT_SIZE),); - } - zft_header_read = 0; - switch(mtftformat->fmt_op) { - case FTFMT_SET_PARMS: - TRACE_CATCH(set_format_parms(&arg->fmt_parms, zft_hseg_buf),); - TRACE_EXIT 0; - case FTFMT_GET_PARMS: - TRACE_CATCH(get_format_parms(&arg->fmt_parms, zft_hseg_buf),); - TRACE_EXIT 0; - case FTFMT_FORMAT_TRACK: - if ((ft_formatted && zft_check_write_access(&zft_pos) < 0) || - (!ft_formatted && zft_write_protected)) { - TRACE_ABORT(-EACCES, ft_t_info, "Write access denied"); - } - TRACE_CATCH(ftape_format_track(arg->fmt_track.ft_track, - arg->fmt_track.ft_gap3),); - TRACE_EXIT 0; - case FTFMT_STATUS: - TRACE_CATCH(ftape_format_status(&arg->fmt_status.ft_segment),); - TRACE_EXIT 0; - case FTFMT_VERIFY: - TRACE_CATCH(ftape_verify_segment(arg->fmt_verify.ft_segment, - (SectorMap *)&arg->fmt_verify.ft_bsm),); - TRACE_EXIT 0; - default: - TRACE_ABORT(-EINVAL, ft_t_err, "Invalid format operation"); - } - TRACE_EXIT result; -} -#endif - -#ifdef MTIOCFTCMD -/* - * send a QIC-117 command to the drive, with optional timeouts, - * parameter and result bits. This is intended to be used together - * with the formatting ioctl. - */ -static int mtiocftcmd(struct mtftcmd *ftcmd, int arg_size) -{ - int i; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCFTCMD"); - if (!capable(CAP_SYS_ADMIN)) { - TRACE_ABORT(-EPERM, ft_t_info, - "need CAP_SYS_ADMIN capability to send raw qic-117 commands"); - } - if (zft_qic_mode) { - TRACE_ABORT(-EACCES, ft_t_info, - "driver needs to be in raw mode for this ioctl"); - } - if (arg_size != sizeof(struct mtftcmd)) { - TRACE_ABORT(-EINVAL, - ft_t_info, "bad argument size: %d", arg_size); - } - if (ftcmd->ft_wait_before) { - TRACE_CATCH(ftape_ready_wait(ftcmd->ft_wait_before, - &ftcmd->ft_status),); - } - if (ftcmd->ft_status & QIC_STATUS_ERROR) - goto ftmtcmd_error; - if (ftcmd->ft_result_bits != 0) { - TRACE_CATCH(ftape_report_operation(&ftcmd->ft_result, - ftcmd->ft_cmd, - ftcmd->ft_result_bits),); - } else { - TRACE_CATCH(ftape_command(ftcmd->ft_cmd),); - if (ftcmd->ft_status & QIC_STATUS_ERROR) - goto ftmtcmd_error; - for (i = 0; i < ftcmd->ft_parm_cnt; i++) { - TRACE_CATCH(ftape_parameter(ftcmd->ft_parms[i]&0x0f),); - if (ftcmd->ft_status & QIC_STATUS_ERROR) - goto ftmtcmd_error; - } - } - if (ftcmd->ft_wait_after != 0) { - TRACE_CATCH(ftape_ready_wait(ftcmd->ft_wait_after, - &ftcmd->ft_status),); - } -ftmtcmd_error: - if (ftcmd->ft_status & QIC_STATUS_ERROR) { - TRACE(ft_t_noise, "error status set"); - TRACE_CATCH(ftape_report_error(&ftcmd->ft_error, - &ftcmd->ft_cmd, 1),); - } - TRACE_EXIT 0; /* this is not an i/o error */ -} -#endif - -/* IOCTL routine called by kernel-interface code - */ -int _zft_ioctl(unsigned int command, void __user * arg) -{ - int result; - union { struct mtop mtop; - struct mtget mtget; - struct mtpos mtpos; -#ifdef MTIOCRDFTSEG - struct mtftseg mtftseg; -#endif -#ifdef MTIOCVOLINFO - struct mtvolinfo mtvolinfo; -#endif -#ifdef MTIOCGETSIZE - struct mttapesize mttapesize; -#endif -#ifdef MTIOCFTFORMAT - struct mtftformat mtftformat; -#endif -#ifdef ZFT_OBSOLETE - struct mtblksz mtblksz; -#endif -#ifdef MTIOCFTCMD - struct mtftcmd mtftcmd; -#endif - } krnl_arg; - int arg_size = _IOC_SIZE(command); - int dir = _IOC_DIR(command); - TRACE_FUN(ft_t_flow); - - /* This check will only catch arguments that are too large ! - */ - if (dir & (_IOC_READ | _IOC_WRITE) && arg_size > sizeof(krnl_arg)) { - TRACE_ABORT(-EINVAL, - ft_t_info, "bad argument size: %d", arg_size); - } - if (dir & _IOC_WRITE) { - if (copy_from_user(&krnl_arg, arg, arg_size) != 0) { - TRACE_EXIT -EFAULT; - } - } - TRACE(ft_t_flow, "called with ioctl command: 0x%08x", command); - switch (command) { - case MTIOCTOP: - result = mtioctop(&krnl_arg.mtop, arg_size); - break; - case MTIOCGET: - result = mtiocget(&krnl_arg.mtget, arg_size); - break; - case MTIOCPOS: - result = mtiocpos(&krnl_arg.mtpos, arg_size); - break; -#ifdef MTIOCVOLINFO - case MTIOCVOLINFO: - result = mtiocvolinfo(&krnl_arg.mtvolinfo, arg_size); - break; -#endif -#ifdef ZFT_OBSOLETE - case MTIOC_ZFTAPE_GETBLKSZ: - result = mtioc_zftape_getblksz(&krnl_arg.mtblksz, arg_size); - break; -#endif -#ifdef MTIOCRDFTSEG - case MTIOCRDFTSEG: /* read a segment via ioctl */ - result = mtiocrdftseg(&krnl_arg.mtftseg, arg_size); - break; -#endif -#ifdef MTIOCWRFTSEG - case MTIOCWRFTSEG: /* write a segment via ioctl */ - result = mtiocwrftseg(&krnl_arg.mtftseg, arg_size); - break; -#endif -#ifdef MTIOCGETSIZE - case MTIOCGETSIZE: - result = mtiocgetsize(&krnl_arg.mttapesize, arg_size); - break; -#endif -#ifdef MTIOCFTFORMAT - case MTIOCFTFORMAT: - result = mtiocftformat(&krnl_arg.mtftformat, arg_size); - break; -#endif -#ifdef MTIOCFTCMD - case MTIOCFTCMD: - result = mtiocftcmd(&krnl_arg.mtftcmd, arg_size); - break; -#endif - default: - result = -EINVAL; - break; - } - if ((result >= 0) && (dir & _IOC_READ)) { - if (copy_to_user(arg, &krnl_arg, arg_size) != 0) { - TRACE_EXIT -EFAULT; - } - } - TRACE_EXIT result; -} diff --git a/drivers/char/ftape/zftape/zftape-ctl.h b/drivers/char/ftape/zftape/zftape-ctl.h deleted file mode 100644 index 8e6f2d7ac74e..000000000000 --- a/drivers/char/ftape/zftape/zftape-ctl.h +++ /dev/null @@ -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 - - - diff --git a/drivers/char/ftape/zftape/zftape-eof.c b/drivers/char/ftape/zftape/zftape-eof.c deleted file mode 100644 index dcadcaee9ac1..000000000000 --- a/drivers/char/ftape/zftape/zftape-eof.c +++ /dev/null @@ -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; -} diff --git a/drivers/char/ftape/zftape/zftape-eof.h b/drivers/char/ftape/zftape/zftape-eof.h deleted file mode 100644 index 26568c26c518..000000000000 --- a/drivers/char/ftape/zftape/zftape-eof.h +++ /dev/null @@ -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 diff --git a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c deleted file mode 100644 index 164a1aa77a2f..000000000000 --- a/drivers/char/ftape/zftape/zftape-init.c +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Copyright (C) 1996, 1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * This file contains the code that registers the zftape frontend - * to the ftape floppy tape driver for Linux - */ - -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/fs.h> -#include <linux/kernel.h> -#include <linux/signal.h> -#include <linux/major.h> -#include <linux/slab.h> -#ifdef CONFIG_KMOD -#include <linux/kmod.h> -#endif -#include <linux/fcntl.h> -#include <linux/smp_lock.h> - -#include <linux/zftape.h> -#include <linux/init.h> -#include <linux/device.h> - -#include "../zftape/zftape-init.h" -#include "../zftape/zftape-read.h" -#include "../zftape/zftape-write.h" -#include "../zftape/zftape-ctl.h" -#include "../zftape/zftape-buffers.h" - -MODULE_AUTHOR("(c) 1996, 1997 Claus-Justus Heine " - "(claus@momo.math.rwth-aachen.de)"); -MODULE_DESCRIPTION(ZFTAPE_VERSION " - " - "VFS interface for the Linux floppy tape driver. " - "Support for QIC-113 compatible volume table " - "and builtin compression (lzrw3 algorithm)"); -MODULE_SUPPORTED_DEVICE("char-major-27"); -MODULE_LICENSE("GPL"); - -/* Global vars. - */ -struct zft_cmpr_ops *zft_cmpr_ops = NULL; -const ftape_info *zft_status; - -/* Local vars. - */ -static unsigned long busy_flag; - -static sigset_t orig_sigmask; - -/* the interface to the kernel vfs layer - */ - -/* Note about llseek(): - * - * st.c and tpqic.c update fp->f_pos but don't implment llseek() and - * initialize the llseek component of the file_ops struct with NULL. - * This means that the user will get the default seek, but the tape - * device will not respect the new position, but happily read from the - * old position. Think a zftape specific llseek() function would be - * better, returning -ESPIPE. TODO. - */ - -static int zft_open (struct inode *ino, struct file *filep); -static int zft_close(struct inode *ino, struct file *filep); -static int zft_ioctl(struct inode *ino, struct file *filep, - unsigned int command, unsigned long arg); -static int zft_mmap(struct file *filep, struct vm_area_struct *vma); -static ssize_t zft_read (struct file *fp, char __user *buff, - size_t req_len, loff_t *ppos); -static ssize_t zft_write(struct file *fp, const char __user *buff, - size_t req_len, loff_t *ppos); - -static const struct file_operations zft_cdev = -{ - .owner = THIS_MODULE, - .read = zft_read, - .write = zft_write, - .ioctl = zft_ioctl, - .mmap = zft_mmap, - .open = zft_open, - .release = zft_close, -}; - -static struct class *zft_class; - -/* Open floppy tape device - */ -static int zft_open(struct inode *ino, struct file *filep) -{ - int result; - TRACE_FUN(ft_t_flow); - - nonseekable_open(ino, filep); - TRACE(ft_t_flow, "called for minor %d", iminor(ino)); - if ( test_and_set_bit(0,&busy_flag) ) { - TRACE_ABORT(-EBUSY, ft_t_warn, "failed: already busy"); - } - if ((iminor(ino) & ~(ZFT_MINOR_OP_MASK | FTAPE_NO_REWIND)) - > - FTAPE_SEL_D) { - clear_bit(0,&busy_flag); - TRACE_ABORT(-ENXIO, ft_t_err, "failed: invalid unit nr"); - } - orig_sigmask = current->blocked; - sigfillset(¤t->blocked); - result = _zft_open(iminor(ino), filep->f_flags & O_ACCMODE); - if (result < 0) { - current->blocked = orig_sigmask; /* restore mask */ - clear_bit(0,&busy_flag); - TRACE_ABORT(result, ft_t_err, "_ftape_open failed"); - } else { - /* Mask signals that will disturb proper operation of the - * program that is calling. - */ - current->blocked = orig_sigmask; - sigaddsetmask (¤t->blocked, _DO_BLOCK); - TRACE_EXIT 0; - } -} - -/* Close floppy tape device - */ -static int zft_close(struct inode *ino, struct file *filep) -{ - int result; - TRACE_FUN(ft_t_flow); - - if ( !test_bit(0,&busy_flag) || iminor(ino) != zft_unit) { - TRACE(ft_t_err, "failed: not busy or wrong unit"); - TRACE_EXIT 0; - } - sigfillset(¤t->blocked); - result = _zft_close(); - if (result < 0) { - TRACE(ft_t_err, "_zft_close failed"); - } - current->blocked = orig_sigmask; /* restore before open state */ - clear_bit(0,&busy_flag); - TRACE_EXIT 0; -} - -/* Ioctl for floppy tape device - */ -static int zft_ioctl(struct inode *ino, struct file *filep, - unsigned int command, unsigned long arg) -{ - int result = -EIO; - sigset_t old_sigmask; - TRACE_FUN(ft_t_flow); - - if ( !test_bit(0,&busy_flag) || iminor(ino) != zft_unit || ft_failure) { - TRACE_ABORT(-EIO, ft_t_err, - "failed: not busy, failure or wrong unit"); - } - old_sigmask = current->blocked; /* save mask */ - sigfillset(¤t->blocked); - /* This will work as long as sizeof(void *) == sizeof(long) */ - result = _zft_ioctl(command, (void __user *) arg); - current->blocked = old_sigmask; /* restore mask */ - TRACE_EXIT result; -} - -/* Ioctl for floppy tape device - */ -static int zft_mmap(struct file *filep, struct vm_area_struct *vma) -{ - int result = -EIO; - sigset_t old_sigmask; - TRACE_FUN(ft_t_flow); - - if ( !test_bit(0,&busy_flag) || - iminor(filep->f_dentry->d_inode) != zft_unit || - ft_failure) - { - TRACE_ABORT(-EIO, ft_t_err, - "failed: not busy, failure or wrong unit"); - } - old_sigmask = current->blocked; /* save mask */ - sigfillset(¤t->blocked); - if ((result = ftape_mmap(vma)) >= 0) { -#ifndef MSYNC_BUG_WAS_FIXED - static struct vm_operations_struct dummy = { NULL, }; - vma->vm_ops = &dummy; -#endif - } - current->blocked = old_sigmask; /* restore mask */ - TRACE_EXIT result; -} - -/* Read from floppy tape device - */ -static ssize_t zft_read(struct file *fp, char __user *buff, - size_t req_len, loff_t *ppos) -{ - int result = -EIO; - sigset_t old_sigmask; - struct inode *ino = fp->f_dentry->d_inode; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_data_flow, "called with count: %ld", (unsigned long)req_len); - if (!test_bit(0,&busy_flag) || iminor(ino) != zft_unit || ft_failure) { - TRACE_ABORT(-EIO, ft_t_err, - "failed: not busy, failure or wrong unit"); - } - old_sigmask = current->blocked; /* save mask */ - sigfillset(¤t->blocked); - result = _zft_read(buff, req_len); - current->blocked = old_sigmask; /* restore mask */ - TRACE(ft_t_data_flow, "return with count: %d", result); - TRACE_EXIT result; -} - -/* Write to tape device - */ -static ssize_t zft_write(struct file *fp, const char __user *buff, - size_t req_len, loff_t *ppos) -{ - int result = -EIO; - sigset_t old_sigmask; - struct inode *ino = fp->f_dentry->d_inode; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_flow, "called with count: %ld", (unsigned long)req_len); - if (!test_bit(0,&busy_flag) || iminor(ino) != zft_unit || ft_failure) { - TRACE_ABORT(-EIO, ft_t_err, - "failed: not busy, failure or wrong unit"); - } - old_sigmask = current->blocked; /* save mask */ - sigfillset(¤t->blocked); - result = _zft_write(buff, req_len); - current->blocked = old_sigmask; /* restore mask */ - TRACE(ft_t_data_flow, "return with count: %d", result); - TRACE_EXIT result; -} - -/* END OF VFS INTERFACE - * - *****************************************************************************/ - -/* driver/module initialization - */ - -/* the compression module has to call this function to hook into the zftape - * code - */ -int zft_cmpr_register(struct zft_cmpr_ops *new_ops) -{ - TRACE_FUN(ft_t_flow); - - if (zft_cmpr_ops != NULL) { - TRACE_EXIT -EBUSY; - } else { - zft_cmpr_ops = new_ops; - TRACE_EXIT 0; - } -} - -/* lock the zft-compressor() module. - */ -int zft_cmpr_lock(int try_to_load) -{ - if (zft_cmpr_ops == NULL) { -#ifdef CONFIG_KMOD - if (try_to_load) { - request_module("zft-compressor"); - if (zft_cmpr_ops == NULL) { - return -ENOSYS; - } - } else { - return -ENOSYS; - } -#else - return -ENOSYS; -#endif - } - (*zft_cmpr_ops->lock)(); - return 0; -} - -#ifdef CONFIG_ZFT_COMPRESSOR -extern int zft_compressor_init(void); -#endif - -/* Called by modules package when installing the driver or by kernel - * during the initialization phase - */ -int __init zft_init(void) -{ - int i; - TRACE_FUN(ft_t_flow); - -#ifdef MODULE - printk(KERN_INFO ZFTAPE_VERSION "\n"); - if (TRACE_LEVEL >= ft_t_info) { - printk( -KERN_INFO -"(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)\n" -KERN_INFO -"vfs interface for ftape floppy tape driver.\n" -KERN_INFO -"Support for QIC-113 compatible volume table, dynamic memory allocation\n" -KERN_INFO -"and builtin compression (lzrw3 algorithm).\n"); - } -#else /* !MODULE */ - /* print a short no-nonsense boot message */ - printk(KERN_INFO ZFTAPE_VERSION "\n"); -#endif /* MODULE */ - TRACE(ft_t_info, "zft_init @ 0x%p", zft_init); - TRACE(ft_t_info, - "installing zftape VFS interface for ftape driver ..."); - TRACE_CATCH(register_chrdev(QIC117_TAPE_MAJOR, "zft", &zft_cdev),); - - zft_class = class_create(THIS_MODULE, "zft"); - for (i = 0; i < 4; i++) { - class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i), NULL, "qft%i", i); - class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 4), NULL, "nqft%i", i); - class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 16), NULL, "zqft%i", i); - class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 20), NULL, "nzqft%i", i); - class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 32), NULL, "rawqft%i", i); - class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 36), NULL, "nrawrawqft%i", i); - } - -#ifdef CONFIG_ZFT_COMPRESSOR - (void)zft_compressor_init(); -#endif - zft_status = ftape_get_status(); /* fetch global data of ftape - * hardware driver - */ - TRACE_EXIT 0; -} - - -/* Called by modules package when removing the driver - */ -static void zft_exit(void) -{ - int i; - TRACE_FUN(ft_t_flow); - - if (unregister_chrdev(QIC117_TAPE_MAJOR, "zft") != 0) { - TRACE(ft_t_warn, "failed"); - } else { - TRACE(ft_t_info, "successful"); - } - for (i = 0; i < 4; i++) { - class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i)); - class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 4)); - class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 16)); - class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 20)); - class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 32)); - class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 36)); - } - class_destroy(zft_class); - zft_uninit_mem(); /* release remaining memory, if any */ - printk(KERN_INFO "zftape successfully unloaded.\n"); - TRACE_EXIT; -} - -module_init(zft_init); -module_exit(zft_exit); diff --git a/drivers/char/ftape/zftape/zftape-init.h b/drivers/char/ftape/zftape/zftape-init.h deleted file mode 100644 index 937e5d48c20e..000000000000 --- a/drivers/char/ftape/zftape/zftape-init.h +++ /dev/null @@ -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 - - diff --git a/drivers/char/ftape/zftape/zftape-read.c b/drivers/char/ftape/zftape/zftape-read.c deleted file mode 100644 index 214bf03dce68..000000000000 --- a/drivers/char/ftape/zftape/zftape-read.c +++ /dev/null @@ -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; -} diff --git a/drivers/char/ftape/zftape/zftape-read.h b/drivers/char/ftape/zftape/zftape-read.h deleted file mode 100644 index 42941de0c23a..000000000000 --- a/drivers/char/ftape/zftape/zftape-read.h +++ /dev/null @@ -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 */ diff --git a/drivers/char/ftape/zftape/zftape-rw.c b/drivers/char/ftape/zftape/zftape-rw.c deleted file mode 100644 index dab634686885..000000000000 --- a/drivers/char/ftape/zftape/zftape-rw.c +++ /dev/null @@ -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; -} diff --git a/drivers/char/ftape/zftape/zftape-rw.h b/drivers/char/ftape/zftape/zftape-rw.h deleted file mode 100644 index 1ceec22b60bd..000000000000 --- a/drivers/char/ftape/zftape/zftape-rw.h +++ /dev/null @@ -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 */ - diff --git a/drivers/char/ftape/zftape/zftape-vtbl.c b/drivers/char/ftape/zftape/zftape-vtbl.c deleted file mode 100644 index ad7f8be6340b..000000000000 --- a/drivers/char/ftape/zftape/zftape-vtbl.c +++ /dev/null @@ -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; -} diff --git a/drivers/char/ftape/zftape/zftape-vtbl.h b/drivers/char/ftape/zftape/zftape-vtbl.h deleted file mode 100644 index f31d196d1759..000000000000 --- a/drivers/char/ftape/zftape/zftape-vtbl.h +++ /dev/null @@ -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 */ diff --git a/drivers/char/ftape/zftape/zftape-write.c b/drivers/char/ftape/zftape/zftape-write.c deleted file mode 100644 index 94327b8c97b9..000000000000 --- a/drivers/char/ftape/zftape/zftape-write.c +++ /dev/null @@ -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 */ -} diff --git a/drivers/char/ftape/zftape/zftape-write.h b/drivers/char/ftape/zftape/zftape-write.h deleted file mode 100644 index ea887015b493..000000000000 --- a/drivers/char/ftape/zftape/zftape-write.h +++ /dev/null @@ -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 */ diff --git a/drivers/char/ftape/zftape/zftape_syms.c b/drivers/char/ftape/zftape/zftape_syms.c deleted file mode 100644 index 2db1401682df..000000000000 --- a/drivers/char/ftape/zftape/zftape_syms.c +++ /dev/null @@ -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); diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 091a11cd878c..20dc3be5ecfc 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -21,6 +21,7 @@ #include <linux/fcntl.h> #include <linux/init.h> #include <linux/poll.h> +#include <linux/mm.h> #include <linux/proc_fs.h> #include <linux/spinlock.h> #include <linux/sysctl.h> diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index ebace201bec6..26a860adcb38 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -36,6 +36,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> +#include <linux/sched.h> #include <linux/init.h> #include <linux/miscdevice.h> #include <linux/delay.h> diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 050ced247f68..bb9a43c6cf3d 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -22,6 +22,7 @@ #include <linux/pci.h> #include <linux/delay.h> #include <linux/fs.h> +#include <linux/sched.h> #include <linux/miscdevice.h> #include <linux/platform_device.h> #include <linux/io.h> diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index e5cb0fdab9b1..b1dc63e4ac7b 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c @@ -21,6 +21,7 @@ etc voltage & frequency control is not supported! */ #include <linux/module.h> +#include <linux/sched.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/jiffies.h> diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c index 26be4ea8a38a..e8ef62b83d6b 100644 --- a/drivers/hwmon/hdaps.c +++ b/drivers/hwmon/hdaps.c @@ -33,6 +33,7 @@ #include <linux/module.h> #include <linux/timer.h> #include <linux/dmi.h> +#include <linux/jiffies.h> #include <asm/io.h> #define HDAPS_LOW_PORT 0x1600 /* first port used by hdaps */ diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 0606744c3f84..5e122501fd80 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -35,6 +35,7 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/mm.h> +#include <linux/highmem.h> #include <asm/io.h> #include <asm/scatterlist.h> #include <linux/scatterlist.h> diff --git a/drivers/isdn/divert/isdn_divert.c b/drivers/isdn/divert/isdn_divert.c index 1f5ebe9ee72c..03319ea5aa0c 100644 --- a/drivers/isdn/divert/isdn_divert.c +++ b/drivers/isdn/divert/isdn_divert.c @@ -10,6 +10,8 @@ */ #include <linux/proc_fs.h> +#include <linux/timer.h> +#include <linux/jiffies.h> #include "isdn_divert.h" diff --git a/drivers/leds/ledtrig-ide-disk.c b/drivers/leds/ledtrig-ide-disk.c index fa651886ab4f..54b155c7026f 100644 --- a/drivers/leds/ledtrig-ide-disk.c +++ b/drivers/leds/ledtrig-ide-disk.c @@ -12,6 +12,7 @@ */ #include <linux/module.h> +#include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/timer.h> diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c index 29a8818a32ec..d756bdb01c59 100644 --- a/drivers/leds/ledtrig-timer.c +++ b/drivers/leds/ledtrig-timer.c @@ -12,6 +12,7 @@ */ #include <linux/module.h> +#include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/list.h> diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index 55bc891768c2..8a7dd507cf6e 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -30,6 +30,7 @@ #include <linux/input.h> #include <linux/dvb/frontend.h> #include <linux/mutex.h> +#include <linux/mm.h> #include "dmxdev.h" #include "dvb_demux.h" diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c index 72ef7bde3346..f143e13b229d 100644 --- a/drivers/net/ehea/ehea_qmr.c +++ b/drivers/net/ehea/ehea_qmr.c @@ -26,6 +26,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include <linux/mm.h> #include "ehea.h" #include "ehea_phyp.h" #include "ehea_qmr.h" diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 6efbd499d752..4256c13c73c2 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -57,6 +57,7 @@ static const char version[] = "lance.c:v1.16 2006/11/09 dplatt@3do.com, becker@c #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> +#include <linux/mm.h> #include <linux/bitops.h> #include <asm/io.h> diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c index d66328975425..1a6fed76d4cc 100644 --- a/drivers/net/ne3210.c +++ b/drivers/net/ne3210.c @@ -36,6 +36,7 @@ #include <linux/interrupt.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> +#include <linux/mm.h> #include <asm/io.h> #include <asm/system.h> diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index 12cbfd190dd7..92d11b961db8 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -114,6 +114,7 @@ #include <linux/dma-mapping.h> #include <linux/ip.h> #include <linux/mii.h> +#include <linux/mm.h> #include "h/skdrv1st.h" #include "h/skdrv2nd.h" diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 7a0aee6c869d..bf873ea25797 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -41,6 +41,7 @@ #include <linux/ethtool.h> #include <linux/mii.h> #include <linux/if_vlan.h> +#include <linux/mm.h> #include <asm/processor.h> /* Processor type for cache alignment. */ #include <asm/uaccess.h> #include <asm/io.h> diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index b865db363ba0..47a1c09d19ac 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -38,6 +38,7 @@ static char *version = "sun3lance.c: v1.2 1/12/2001 Sam Creasey (sammy@sammy.ne #include <linux/skbuff.h> #include <linux/bitops.h> +#include <asm/cacheflush.h> #include <asm/setup.h> #include <asm/irq.h> #include <asm/io.h> diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 334c6cfd6595..cf44e72399b9 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -56,6 +56,7 @@ #include <linux/if_vlan.h> #include <linux/bitops.h> #include <linux/mutex.h> +#include <linux/mm.h> #include <asm/system.h> #include <asm/io.h> diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index ec432ea879fb..ef671739cfea 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -32,6 +32,7 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> +#include <linux/mm.h> #include <linux/bitops.h> #include <asm/system.h> @@ -3012,6 +3013,11 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, #endif err = -ENODEV; + + if (pci_enable_device(pdev)) + goto err_out; + pci_set_master(pdev); + if (!strcmp(prom_name, "SUNW,qfe") || !strcmp(prom_name, "qfe")) { qp = quattro_pci_find(pdev); if (qp == NULL) diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 8ddea1da7c05..9781b16bb8b6 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -117,6 +117,7 @@ static const int multicast_filter_limit = 32; #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> +#include <linux/mm.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/ethtool.h> diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 73a58c73d526..fc405f0165d9 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -1,5 +1,6 @@ #include <linux/pci.h> #include <linux/module.h> +#include <linux/sched.h> #include <linux/ioport.h> #include <linux/wait.h> diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 79ffef6bfaf8..a2cef57d7bcb 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1264,15 +1264,21 @@ __dasd_check_expire(struct dasd_device * device) if (list_empty(&device->ccw_queue)) return; cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list); - if (cqr->status == DASD_CQR_IN_IO && cqr->expires != 0) { - if (time_after_eq(jiffies, cqr->expires + cqr->starttime)) { + if ((cqr->status == DASD_CQR_IN_IO && cqr->expires != 0) && + (time_after_eq(jiffies, cqr->expires + cqr->starttime))) { + if (device->discipline->term_IO(cqr) != 0) { + /* Hmpf, try again in 5 sec */ + dasd_set_timer(device, 5*HZ); + DEV_MESSAGE(KERN_ERR, device, + "internal error - timeout (%is) expired " + "for cqr %p, termination failed, " + "retrying in 5s", + (cqr->expires/HZ), cqr); + } else { DEV_MESSAGE(KERN_ERR, device, "internal error - timeout (%is) expired " "for cqr %p (%i retries left)", (cqr->expires/HZ), cqr, cqr->retries); - if (device->discipline->term_IO(cqr) != 0) - /* Hmpf, try again in 1/10 sec */ - dasd_set_timer(device, 10); } } } diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 91cf971f0652..17fdd8c9f740 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -684,21 +684,26 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct dasd_devmap *devmap; - int ro_flag; + int val; + char *endp; devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); if (IS_ERR(devmap)) return PTR_ERR(devmap); - ro_flag = buf[0] == '1'; + + val = simple_strtoul(buf, &endp, 0); + if (((endp + 1) < (buf + count)) || (val > 1)) + return -EINVAL; + spin_lock(&dasd_devmap_lock); - if (ro_flag) + if (val) devmap->features |= DASD_FEATURE_READONLY; else devmap->features &= ~DASD_FEATURE_READONLY; if (devmap->device) devmap->device->features = devmap->features; if (devmap->device && devmap->device->gdp) - set_disk_ro(devmap->device->gdp, ro_flag); + set_disk_ro(devmap->device->gdp, val); spin_unlock(&dasd_devmap_lock); return count; } @@ -729,17 +734,22 @@ dasd_use_diag_store(struct device *dev, struct device_attribute *attr, { struct dasd_devmap *devmap; ssize_t rc; - int use_diag; + int val; + char *endp; devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); if (IS_ERR(devmap)) return PTR_ERR(devmap); - use_diag = buf[0] == '1'; + + val = simple_strtoul(buf, &endp, 0); + if (((endp + 1) < (buf + count)) || (val > 1)) + return -EINVAL; + spin_lock(&dasd_devmap_lock); /* Changing diag discipline flag is only allowed in offline state. */ rc = count; if (!devmap->device) { - if (use_diag) + if (val) devmap->features |= DASD_FEATURE_USEDIAG; else devmap->features &= ~DASD_FEATURE_USEDIAG; @@ -854,14 +864,20 @@ dasd_eer_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct dasd_devmap *devmap; - int rc; + int val, rc; + char *endp; devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); if (IS_ERR(devmap)) return PTR_ERR(devmap); if (!devmap->device) - return count; - if (buf[0] == '1') { + return -ENODEV; + + val = simple_strtoul(buf, &endp, 0); + if (((endp + 1) < (buf + count)) || (val > 1)) + return -EINVAL; + + if (val) { rc = dasd_eer_enable(devmap->device); if (rc) return rc; diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index d7de175d53f0..c9321b920e90 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -299,14 +299,14 @@ raw3215_timeout(unsigned long __data) struct raw3215_info *raw = (struct raw3215_info *) __data; unsigned long flags; - spin_lock_irqsave(raw->lock, flags); + spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); if (raw->flags & RAW3215_TIMER_RUNS) { del_timer(&raw->timer); raw->flags &= ~RAW3215_TIMER_RUNS; raw3215_mk_write_req(raw); raw3215_start_io(raw); } - spin_unlock_irqrestore(raw->lock, flags); + spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); } /* @@ -355,10 +355,10 @@ raw3215_tasklet(void *data) unsigned long flags; raw = (struct raw3215_info *) data; - spin_lock_irqsave(raw->lock, flags); + spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); raw3215_mk_write_req(raw); raw3215_try_io(raw); - spin_unlock_irqrestore(raw->lock, flags); + spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); /* Check for pending message from raw3215_irq */ if (raw->message != NULL) { printk(raw->message, raw->msg_dstat, raw->msg_cstat); @@ -512,9 +512,9 @@ raw3215_make_room(struct raw3215_info *raw, unsigned int length) if (RAW3215_BUFFER_SIZE - raw->count >= length) break; /* there might be another cpu waiting for the lock */ - spin_unlock(raw->lock); + spin_unlock(get_ccwdev_lock(raw->cdev)); udelay(100); - spin_lock(raw->lock); + spin_lock(get_ccwdev_lock(raw->cdev)); } } @@ -528,7 +528,7 @@ raw3215_write(struct raw3215_info *raw, const char *str, unsigned int length) int c, count; while (length > 0) { - spin_lock_irqsave(raw->lock, flags); + spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); count = (length > RAW3215_BUFFER_SIZE) ? RAW3215_BUFFER_SIZE : length; length -= count; @@ -555,7 +555,7 @@ raw3215_write(struct raw3215_info *raw, const char *str, unsigned int length) /* start or queue request */ raw3215_try_io(raw); } - spin_unlock_irqrestore(raw->lock, flags); + spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); } } @@ -568,7 +568,7 @@ raw3215_putchar(struct raw3215_info *raw, unsigned char ch) unsigned long flags; unsigned int length, i; - spin_lock_irqsave(raw->lock, flags); + spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); if (ch == '\t') { length = TAB_STOP_SIZE - (raw->line_pos%TAB_STOP_SIZE); raw->line_pos += length; @@ -592,7 +592,7 @@ raw3215_putchar(struct raw3215_info *raw, unsigned char ch) /* start or queue request */ raw3215_try_io(raw); } - spin_unlock_irqrestore(raw->lock, flags); + spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); } /* @@ -604,13 +604,13 @@ raw3215_flush_buffer(struct raw3215_info *raw) { unsigned long flags; - spin_lock_irqsave(raw->lock, flags); + spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); if (raw->count > 0) { raw->flags |= RAW3215_FLUSHING; raw3215_try_io(raw); raw->flags &= ~RAW3215_FLUSHING; } - spin_unlock_irqrestore(raw->lock, flags); + spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); } /* @@ -625,9 +625,9 @@ raw3215_startup(struct raw3215_info *raw) return 0; raw->line_pos = 0; raw->flags |= RAW3215_ACTIVE; - spin_lock_irqsave(raw->lock, flags); + spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); raw3215_try_io(raw); - spin_unlock_irqrestore(raw->lock, flags); + spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); return 0; } @@ -644,21 +644,21 @@ raw3215_shutdown(struct raw3215_info *raw) if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FIXED)) return; /* Wait for outstanding requests, then free irq */ - spin_lock_irqsave(raw->lock, flags); + spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); if ((raw->flags & RAW3215_WORKING) || raw->queued_write != NULL || raw->queued_read != NULL) { raw->flags |= RAW3215_CLOSING; add_wait_queue(&raw->empty_wait, &wait); set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(raw->lock, flags); + spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); schedule(); - spin_lock_irqsave(raw->lock, flags); + spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); remove_wait_queue(&raw->empty_wait, &wait); set_current_state(TASK_RUNNING); raw->flags &= ~(RAW3215_ACTIVE | RAW3215_CLOSING); } - spin_unlock_irqrestore(raw->lock, flags); + spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); } static int @@ -686,7 +686,6 @@ raw3215_probe (struct ccw_device *cdev) } raw->cdev = cdev; - raw->lock = get_ccwdev_lock(cdev); raw->inbuf = (char *) raw + sizeof(struct raw3215_info); memset(raw, 0, sizeof(struct raw3215_info)); raw->buffer = (char *) kmalloc(RAW3215_BUFFER_SIZE, @@ -809,9 +808,9 @@ con3215_unblank(void) unsigned long flags; raw = raw3215[0]; /* console 3215 is the first one */ - spin_lock_irqsave(raw->lock, flags); + spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); raw3215_make_room(raw, RAW3215_BUFFER_SIZE); - spin_unlock_irqrestore(raw->lock, flags); + spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); } static int __init @@ -873,7 +872,6 @@ con3215_init(void) raw->buffer = (char *) alloc_bootmem_low(RAW3215_BUFFER_SIZE); raw->inbuf = (char *) alloc_bootmem_low(RAW3215_INBUF_SIZE); raw->cdev = cdev; - raw->lock = get_ccwdev_lock(cdev); cdev->dev.driver_data = raw; cdev->handler = raw3215_irq; @@ -1066,10 +1064,10 @@ tty3215_unthrottle(struct tty_struct * tty) raw = (struct raw3215_info *) tty->driver_data; if (raw->flags & RAW3215_THROTTLED) { - spin_lock_irqsave(raw->lock, flags); + spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); raw->flags &= ~RAW3215_THROTTLED; raw3215_try_io(raw); - spin_unlock_irqrestore(raw->lock, flags); + spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); } } @@ -1096,10 +1094,10 @@ tty3215_start(struct tty_struct *tty) raw = (struct raw3215_info *) tty->driver_data; if (raw->flags & RAW3215_STOPPED) { - spin_lock_irqsave(raw->lock, flags); + spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); raw->flags &= ~RAW3215_STOPPED; raw3215_try_io(raw); - spin_unlock_irqrestore(raw->lock, flags); + spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); } } diff --git a/drivers/s390/char/sclp_quiesce.c b/drivers/s390/char/sclp_quiesce.c index 32004aae95c1..ffa9282ce97a 100644 --- a/drivers/s390/char/sclp_quiesce.c +++ b/drivers/s390/char/sclp_quiesce.c @@ -19,52 +19,17 @@ #include "sclp.h" - -#ifdef CONFIG_SMP -/* Signal completion of shutdown process. All CPUs except the first to enter - * this function: go to stopped state. First CPU: wait until all other - * CPUs are in stopped or check stop state. Afterwards, load special PSW - * to indicate completion. */ -static void -do_load_quiesce_psw(void * __unused) -{ - static atomic_t cpuid = ATOMIC_INIT(-1); - psw_t quiesce_psw; - int cpu; - - if (atomic_cmpxchg(&cpuid, -1, smp_processor_id()) != -1) - signal_processor(smp_processor_id(), sigp_stop); - /* Wait for all other cpus to enter stopped state */ - for_each_online_cpu(cpu) { - if (cpu == smp_processor_id()) - continue; - while(!smp_cpu_not_running(cpu)) - cpu_relax(); - } - /* Quiesce the last cpu with the special psw */ - quiesce_psw.mask = PSW_BASE_BITS | PSW_MASK_WAIT; - quiesce_psw.addr = 0xfff; - __load_psw(quiesce_psw); -} - -/* Shutdown handler. Perform shutdown function on all CPUs. */ -static void -do_machine_quiesce(void) -{ - on_each_cpu(do_load_quiesce_psw, NULL, 0, 0); -} -#else /* Shutdown handler. Signal completion of shutdown by loading special PSW. */ static void do_machine_quiesce(void) { psw_t quiesce_psw; + smp_send_stop(); quiesce_psw.mask = PSW_BASE_BITS | PSW_MASK_WAIT; quiesce_psw.addr = 0xfff; __load_psw(quiesce_psw); } -#endif /* Handler for quiesce event. Start shutdown procedure. */ static void diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 2d78f0f4a40f..dbfb77b03928 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -251,6 +251,8 @@ s390_subchannel_remove_chpid(struct device *dev, void *data) cc = cio_clear(sch); if (cc == -ENODEV) goto out_unreg; + /* Request retry of internal operation. */ + device_set_intretry(sch); /* Call handler. */ if (sch->driver && sch->driver->termination) sch->driver->termination(&sch->dev); @@ -711,9 +713,6 @@ static inline int check_for_io_on_path(struct subchannel *sch, int index) { int cc; - if (!device_is_online(sch)) - /* cio could be doing I/O. */ - return 0; cc = stsch(sch->schid, &sch->schib); if (cc) return 0; @@ -722,6 +721,26 @@ static inline int check_for_io_on_path(struct subchannel *sch, int index) return 0; } +static void terminate_internal_io(struct subchannel *sch) +{ + if (cio_clear(sch)) { + /* Recheck device in case clear failed. */ + sch->lpm = 0; + if (device_trigger_verify(sch) != 0) { + if(css_enqueue_subchannel_slow(sch->schid)) { + css_clear_subchannel_slow_list(); + need_rescan = 1; + } + } + return; + } + /* Request retry of internal operation. */ + device_set_intretry(sch); + /* Call handler. */ + if (sch->driver && sch->driver->termination) + sch->driver->termination(&sch->dev); +} + static inline void __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on) { @@ -744,20 +763,26 @@ __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on) device_trigger_reprobe(sch); else if (sch->driver && sch->driver->verify) sch->driver->verify(&sch->dev); - } else { - sch->opm &= ~(0x80 >> chp); - sch->lpm &= ~(0x80 >> chp); - if (check_for_io_on_path(sch, chp)) + break; + } + sch->opm &= ~(0x80 >> chp); + sch->lpm &= ~(0x80 >> chp); + if (check_for_io_on_path(sch, chp)) { + if (device_is_online(sch)) /* Path verification is done after killing. */ device_kill_io(sch); - else if (!sch->lpm) { + else + /* Kill and retry internal I/O. */ + terminate_internal_io(sch); + } else if (!sch->lpm) { + if (device_trigger_verify(sch) != 0) { if (css_enqueue_subchannel_slow(sch->schid)) { css_clear_subchannel_slow_list(); need_rescan = 1; } - } else if (sch->driver && sch->driver->verify) - sch->driver->verify(&sch->dev); - } + } + } else if (sch->driver && sch->driver->verify) + sch->driver->verify(&sch->dev); break; } spin_unlock_irqrestore(&sch->lock, flags); @@ -1465,41 +1490,6 @@ chsc_get_chp_desc(struct subchannel *sch, int chp_no) return desc; } -static int reset_channel_path(struct channel_path *chp) -{ - int cc; - - cc = rchp(chp->id); - switch (cc) { - case 0: - return 0; - case 2: - return -EBUSY; - default: - return -ENODEV; - } -} - -static void reset_channel_paths_css(struct channel_subsystem *css) -{ - int i; - - for (i = 0; i <= __MAX_CHPID; i++) { - if (css->chps[i]) - reset_channel_path(css->chps[i]); - } -} - -void cio_reset_channel_paths(void) -{ - int i; - - for (i = 0; i <= __MAX_CSSID; i++) { - if (css[i] && css[i]->valid) - reset_channel_paths_css(css[i]); - } -} - static int __init chsc_alloc_sei_area(void) { diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 8936e460a807..20aee2783847 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -21,6 +21,7 @@ #include <asm/irq.h> #include <asm/irq_regs.h> #include <asm/setup.h> +#include <asm/reset.h> #include "airq.h" #include "cio.h" #include "css.h" @@ -28,6 +29,7 @@ #include "ioasm.h" #include "blacklist.h" #include "cio_debug.h" +#include "../s390mach.h" debug_info_t *cio_debug_msg_id; debug_info_t *cio_debug_trace_id; @@ -841,26 +843,12 @@ __clear_subchannel_easy(struct subchannel_id schid) return -EBUSY; } -struct sch_match_id { - struct subchannel_id schid; - struct ccw_dev_id devid; - int rc; -}; - -static int __shutdown_subchannel_easy_and_match(struct subchannel_id schid, - void *data) +static int __shutdown_subchannel_easy(struct subchannel_id schid, void *data) { struct schib schib; - struct sch_match_id *match_id = data; if (stsch_err(schid, &schib)) return -ENXIO; - if (match_id && schib.pmcw.dnv && - (schib.pmcw.dev == match_id->devid.devno) && - (schid.ssid == match_id->devid.ssid)) { - match_id->schid = schid; - match_id->rc = 0; - } if (!schib.pmcw.ena) return 0; switch(__disable_subchannel_easy(schid, &schib)) { @@ -876,27 +864,111 @@ static int __shutdown_subchannel_easy_and_match(struct subchannel_id schid, return 0; } -static int clear_all_subchannels_and_match(struct ccw_dev_id *devid, - struct subchannel_id *schid) +static atomic_t chpid_reset_count; + +static void s390_reset_chpids_mcck_handler(void) +{ + struct crw crw; + struct mci *mci; + + /* Check for pending channel report word. */ + mci = (struct mci *)&S390_lowcore.mcck_interruption_code; + if (!mci->cp) + return; + /* Process channel report words. */ + while (stcrw(&crw) == 0) { + /* Check for responses to RCHP. */ + if (crw.slct && crw.rsc == CRW_RSC_CPATH) + atomic_dec(&chpid_reset_count); + } +} + +#define RCHP_TIMEOUT (30 * USEC_PER_SEC) +static void css_reset(void) +{ + int i, ret; + unsigned long long timeout; + + /* Reset subchannels. */ + for_each_subchannel(__shutdown_subchannel_easy, NULL); + /* Reset channel paths. */ + s390_reset_mcck_handler = s390_reset_chpids_mcck_handler; + /* Enable channel report machine checks. */ + __ctl_set_bit(14, 28); + /* Temporarily reenable machine checks. */ + local_mcck_enable(); + for (i = 0; i <= __MAX_CHPID; i++) { + ret = rchp(i); + if ((ret == 0) || (ret == 2)) + /* + * rchp either succeeded, or another rchp is already + * in progress. In either case, we'll get a crw. + */ + atomic_inc(&chpid_reset_count); + } + /* Wait for machine check for all channel paths. */ + timeout = get_clock() + (RCHP_TIMEOUT << 12); + while (atomic_read(&chpid_reset_count) != 0) { + if (get_clock() > timeout) + break; + cpu_relax(); + } + /* Disable machine checks again. */ + local_mcck_disable(); + /* Disable channel report machine checks. */ + __ctl_clear_bit(14, 28); + s390_reset_mcck_handler = NULL; +} + +static struct reset_call css_reset_call = { + .fn = css_reset, +}; + +static int __init init_css_reset_call(void) +{ + atomic_set(&chpid_reset_count, 0); + register_reset_call(&css_reset_call); + return 0; +} + +arch_initcall(init_css_reset_call); + +struct sch_match_id { + struct subchannel_id schid; + struct ccw_dev_id devid; + int rc; +}; + +static int __reipl_subchannel_match(struct subchannel_id schid, void *data) +{ + struct schib schib; + struct sch_match_id *match_id = data; + + if (stsch_err(schid, &schib)) + return -ENXIO; + if (schib.pmcw.dnv && + (schib.pmcw.dev == match_id->devid.devno) && + (schid.ssid == match_id->devid.ssid)) { + match_id->schid = schid; + match_id->rc = 0; + return 1; + } + return 0; +} + +static int reipl_find_schid(struct ccw_dev_id *devid, + struct subchannel_id *schid) { struct sch_match_id match_id; match_id.devid = *devid; match_id.rc = -ENODEV; - local_irq_disable(); - for_each_subchannel(__shutdown_subchannel_easy_and_match, &match_id); + for_each_subchannel(__reipl_subchannel_match, &match_id); if (match_id.rc == 0) *schid = match_id.schid; return match_id.rc; } - -void clear_all_subchannels(void) -{ - local_irq_disable(); - for_each_subchannel(__shutdown_subchannel_easy_and_match, NULL); -} - extern void do_reipl_asm(__u32 schid); /* Make sure all subchannels are quiet before we re-ipl an lpar. */ @@ -904,9 +976,9 @@ void reipl_ccw_dev(struct ccw_dev_id *devid) { struct subchannel_id schid; - if (clear_all_subchannels_and_match(devid, &schid)) + s390_reset_system(); + if (reipl_find_schid(devid, &schid) != 0) panic("IPL Device not found\n"); - cio_reset_channel_paths(); do_reipl_asm(*((__u32*)&schid)); } diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 4c2ff8336288..9ff064e71767 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -94,6 +94,7 @@ struct ccw_device_private { unsigned int donotify:1; /* call notify function */ unsigned int recog_done:1; /* dev. recog. complete */ unsigned int fake_irb:1; /* deliver faked irb */ + unsigned int intretry:1; /* retry internal operation */ } __attribute__((packed)) flags; unsigned long intparm; /* user interruption parameter */ struct qdio_irq *qdio_data; @@ -171,6 +172,8 @@ void device_trigger_reprobe(struct subchannel *); /* Helper functions for vary on/off. */ int device_is_online(struct subchannel *); void device_kill_io(struct subchannel *); +void device_set_intretry(struct subchannel *sch); +int device_trigger_verify(struct subchannel *sch); /* Machine check helper function. */ void device_kill_pending_timer(struct subchannel *); diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 39c98f940507..d3d3716ff84b 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -687,8 +687,20 @@ io_subchannel_register(void *data) cdev = data; sch = to_subchannel(cdev->dev.parent); + /* + * io_subchannel_register() will also be called after device + * recognition has been done for a boxed device (which will already + * be registered). We need to reprobe since we may now have sense id + * information. + */ if (klist_node_attached(&cdev->dev.knode_parent)) { - bus_rescan_devices(&ccw_bus_type); + if (!cdev->drv) { + ret = device_reprobe(&cdev->dev); + if (ret) + /* We can't do much here. */ + dev_info(&cdev->dev, "device_reprobe() returned" + " %d\n", ret); + } goto out; } /* make it known to the system */ @@ -948,6 +960,9 @@ io_subchannel_ioterm(struct device *dev) cdev = dev->driver_data; if (!cdev) return; + /* Internal I/O will be retried by the interrupt handler. */ + if (cdev->private->flags.intretry) + return; cdev->private->state = DEV_STATE_CLEAR_VERIFY; if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index de3d0857db9f..09c7672eb3f3 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -59,6 +59,27 @@ device_set_disconnected(struct subchannel *sch) cdev->private->state = DEV_STATE_DISCONNECTED; } +void device_set_intretry(struct subchannel *sch) +{ + struct ccw_device *cdev; + + cdev = sch->dev.driver_data; + if (!cdev) + return; + cdev->private->flags.intretry = 1; +} + +int device_trigger_verify(struct subchannel *sch) +{ + struct ccw_device *cdev; + + cdev = sch->dev.driver_data; + if (!cdev || !cdev->online) + return -EINVAL; + dev_fsm_event(cdev, DEV_EVENT_VERIFY); + return 0; +} + /* * Timeout function. It just triggers a DEV_EVENT_TIMEOUT. */ @@ -893,6 +914,12 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event) * had killed the original request. */ if (irb->scsw.fctl & (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) { + /* Retry Basic Sense if requested. */ + if (cdev->private->flags.intretry) { + cdev->private->flags.intretry = 0; + ccw_device_do_sense(cdev, irb); + return; + } cdev->private->flags.dosense = 0; memset(&cdev->private->irb, 0, sizeof(struct irb)); ccw_device_accumulate_irb(cdev, irb); diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c index a74785b9e4eb..f17275917fe5 100644 --- a/drivers/s390/cio/device_id.c +++ b/drivers/s390/cio/device_id.c @@ -191,6 +191,8 @@ __ccw_device_sense_id_start(struct ccw_device *cdev) if ((sch->opm & cdev->private->imask) != 0 && cdev->private->iretry > 0) { cdev->private->iretry--; + /* Reset internal retry indication. */ + cdev->private->flags.intretry = 0; ret = cio_start (sch, cdev->private->iccws, cdev->private->imask); /* ret is 0, -EBUSY, -EACCES or -ENODEV */ @@ -237,8 +239,14 @@ ccw_device_check_sense_id(struct ccw_device *cdev) return 0; /* Success */ } /* Check the error cases. */ - if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) + if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { + /* Retry Sense ID if requested. */ + if (cdev->private->flags.intretry) { + cdev->private->flags.intretry = 0; + return -EAGAIN; + } return -ETIME; + } if (irb->esw.esw0.erw.cons && (irb->ecw[0] & SNS0_CMD_REJECT)) { /* * if the device doesn't support the SenseID diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index 2975ce888c19..cb1879a96818 100644 --- a/drivers/s390/cio/device_pgid.c +++ b/drivers/s390/cio/device_pgid.c @@ -71,6 +71,8 @@ __ccw_device_sense_pgid_start(struct ccw_device *cdev) ccw->cda = (__u32) __pa (&cdev->private->pgid[i]); if (cdev->private->iretry > 0) { cdev->private->iretry--; + /* Reset internal retry indication. */ + cdev->private->flags.intretry = 0; ret = cio_start (sch, cdev->private->iccws, cdev->private->imask); /* ret is 0, -EBUSY, -EACCES or -ENODEV */ @@ -122,8 +124,14 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev) sch = to_subchannel(cdev->dev.parent); irb = &cdev->private->irb; - if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) + if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { + /* Retry Sense PGID if requested. */ + if (cdev->private->flags.intretry) { + cdev->private->flags.intretry = 0; + return -EAGAIN; + } return -ETIME; + } if (irb->esw.esw0.erw.cons && (irb->ecw[0]&(SNS0_CMD_REJECT|SNS0_INTERVENTION_REQ))) { /* @@ -253,6 +261,8 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func) ret = -EACCES; if (cdev->private->iretry > 0) { cdev->private->iretry--; + /* Reset internal retry indication. */ + cdev->private->flags.intretry = 0; ret = cio_start (sch, cdev->private->iccws, cdev->private->imask); /* We expect an interrupt in case of success or busy @@ -293,6 +303,8 @@ static int __ccw_device_do_nop(struct ccw_device *cdev) ret = -EACCES; if (cdev->private->iretry > 0) { cdev->private->iretry--; + /* Reset internal retry indication. */ + cdev->private->flags.intretry = 0; ret = cio_start (sch, cdev->private->iccws, cdev->private->imask); /* We expect an interrupt in case of success or busy @@ -321,8 +333,14 @@ __ccw_device_check_pgid(struct ccw_device *cdev) sch = to_subchannel(cdev->dev.parent); irb = &cdev->private->irb; - if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) + if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { + /* Retry Set PGID if requested. */ + if (cdev->private->flags.intretry) { + cdev->private->flags.intretry = 0; + return -EAGAIN; + } return -ETIME; + } if (irb->esw.esw0.erw.cons) { if (irb->ecw[0] & SNS0_CMD_REJECT) return -EOPNOTSUPP; @@ -360,8 +378,14 @@ static int __ccw_device_check_nop(struct ccw_device *cdev) sch = to_subchannel(cdev->dev.parent); irb = &cdev->private->irb; - if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) + if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { + /* Retry NOP if requested. */ + if (cdev->private->flags.intretry) { + cdev->private->flags.intretry = 0; + return -EAGAIN; + } return -ETIME; + } if (irb->scsw.cc == 3) { CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel 0.%x.%04x," " lpm %02X, became 'not operational'\n", diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c index 3f7cbce4cd87..bdcf930f7beb 100644 --- a/drivers/s390/cio/device_status.c +++ b/drivers/s390/cio/device_status.c @@ -319,6 +319,9 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb) sch->sense_ccw.count = SENSE_MAX_COUNT; sch->sense_ccw.flags = CCW_FLAG_SLI; + /* Reset internal retry indication. */ + cdev->private->flags.intretry = 0; + return cio_start (sch, &sch->sense_ccw, 0xff); } diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 476aa1da5cbc..8d5fa1b4d11f 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -481,7 +481,7 @@ qdio_stop_polling(struct qdio_q *q) unsigned char state = 0; struct qdio_irq *irq = (struct qdio_irq *) q->irq_ptr; - if (!atomic_swap(&q->polling,0)) + if (!atomic_xchg(&q->polling,0)) return 1; QDIO_DBF_TEXT4(0,trace,"stoppoll"); @@ -1964,8 +1964,8 @@ qdio_irq_check_sense(struct subchannel_id schid, struct irb *irb) QDIO_DBF_HEX0(0,sense,irb,QDIO_DBF_SENSE_LEN); QDIO_PRINT_WARN("sense data available on qdio channel.\n"); - HEXDUMP16(WARN,"irb: ",irb); - HEXDUMP16(WARN,"sense data: ",irb->ecw); + QDIO_HEXDUMP16(WARN,"irb: ",irb); + QDIO_HEXDUMP16(WARN,"sense data: ",irb->ecw); } } @@ -3425,7 +3425,7 @@ do_qdio_handle_inbound(struct qdio_q *q, unsigned int callflags, if ((used_elements+count==QDIO_MAX_BUFFERS_PER_Q)&& (callflags&QDIO_FLAG_UNDER_INTERRUPT)) - atomic_swap(&q->polling,0); + atomic_xchg(&q->polling,0); if (used_elements) return; diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 49bb9e371c32..42927c1b7451 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -236,7 +236,7 @@ enum qdio_irq_states { #define QDIO_PRINT_EMERG(x...) do { } while (0) #endif -#define HEXDUMP16(importance,header,ptr) \ +#define QDIO_HEXDUMP16(importance,header,ptr) \ QDIO_PRINT_##importance(header "%02x %02x %02x %02x " \ "%02x %02x %02x %02x %02x %02x %02x %02x " \ "%02x %02x %02x %02x\n",*(((char*)ptr)), \ @@ -429,8 +429,6 @@ struct qdio_perf_stats { }; #endif /* QDIO_PERFORMANCE_STATS */ -#define atomic_swap(a,b) xchg((int*)a.counter,b) - /* unlikely as the later the better */ #define SYNC_MEMORY if (unlikely(q->siga_sync)) qdio_siga_sync_q(q) #define SYNC_MEMORY_ALL if (unlikely(q->siga_sync)) \ diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 79d89c368919..6a54334ffe09 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -431,7 +431,15 @@ static int ap_uevent (struct device *dev, char **envp, int num_envp, ap_dev->device_type); if (buffer_size - length <= 0) return -ENOMEM; - envp[1] = 0; + buffer += length; + buffer_size -= length; + /* Add MODALIAS= */ + envp[1] = buffer; + length = scnprintf(buffer, buffer_size, "MODALIAS=ap:t%02X", + ap_dev->device_type); + if (buffer_size - length <= 0) + return -ENOMEM; + envp[2] = NULL; return 0; } diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 66a8aec6efa6..08d4e47070bd 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -54,6 +54,8 @@ #error Cannot compile lcs.c without some net devices switched on. #endif +#define PRINTK_HEADER " lcs: " + /** * initialization string for output */ @@ -120,7 +122,7 @@ lcs_alloc_channel(struct lcs_channel *channel) kzalloc(LCS_IOBUFFERSIZE, GFP_DMA | GFP_KERNEL); if (channel->iob[cnt].data == NULL) break; - channel->iob[cnt].state = BUF_STATE_EMPTY; + channel->iob[cnt].state = LCS_BUF_STATE_EMPTY; } if (cnt < LCS_NUM_BUFFS) { /* Not all io buffers could be allocated. */ @@ -236,7 +238,7 @@ lcs_setup_read_ccws(struct lcs_card *card) ((struct lcs_header *) card->read.iob[cnt].data)->offset = LCS_ILLEGAL_OFFSET; card->read.iob[cnt].callback = lcs_get_frames_cb; - card->read.iob[cnt].state = BUF_STATE_READY; + card->read.iob[cnt].state = LCS_BUF_STATE_READY; card->read.iob[cnt].count = LCS_IOBUFFERSIZE; } card->read.ccws[0].flags &= ~CCW_FLAG_PCI; @@ -247,7 +249,7 @@ lcs_setup_read_ccws(struct lcs_card *card) card->read.ccws[LCS_NUM_BUFFS].cda = (__u32) __pa(card->read.ccws); /* Setg initial state of the read channel. */ - card->read.state = CH_STATE_INIT; + card->read.state = LCS_CH_STATE_INIT; card->read.io_idx = 0; card->read.buf_idx = 0; @@ -294,7 +296,7 @@ lcs_setup_write_ccws(struct lcs_card *card) card->write.ccws[LCS_NUM_BUFFS].cda = (__u32) __pa(card->write.ccws); /* Set initial state of the write channel. */ - card->read.state = CH_STATE_INIT; + card->read.state = LCS_CH_STATE_INIT; card->write.io_idx = 0; card->write.buf_idx = 0; @@ -496,7 +498,7 @@ lcs_start_channel(struct lcs_channel *channel) channel->ccws + channel->io_idx, 0, 0, DOIO_DENY_PREFETCH | DOIO_ALLOW_SUSPEND); if (rc == 0) - channel->state = CH_STATE_RUNNING; + channel->state = LCS_CH_STATE_RUNNING; spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); if (rc) { LCS_DBF_TEXT_(4,trace,"essh%s", channel->ccwdev->dev.bus_id); @@ -520,8 +522,8 @@ lcs_clear_channel(struct lcs_channel *channel) LCS_DBF_TEXT_(4,trace,"ecsc%s", channel->ccwdev->dev.bus_id); return rc; } - wait_event(channel->wait_q, (channel->state == CH_STATE_CLEARED)); - channel->state = CH_STATE_STOPPED; + wait_event(channel->wait_q, (channel->state == LCS_CH_STATE_CLEARED)); + channel->state = LCS_CH_STATE_STOPPED; return rc; } @@ -535,11 +537,11 @@ lcs_stop_channel(struct lcs_channel *channel) unsigned long flags; int rc; - if (channel->state == CH_STATE_STOPPED) + if (channel->state == LCS_CH_STATE_STOPPED) return 0; LCS_DBF_TEXT(4,trace,"haltsch"); LCS_DBF_TEXT_(4,trace,"%s", channel->ccwdev->dev.bus_id); - channel->state = CH_STATE_INIT; + channel->state = LCS_CH_STATE_INIT; spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); rc = ccw_device_halt(channel->ccwdev, (addr_t) channel); spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); @@ -548,7 +550,7 @@ lcs_stop_channel(struct lcs_channel *channel) return rc; } /* Asynchronous halt initialted. Wait for its completion. */ - wait_event(channel->wait_q, (channel->state == CH_STATE_HALTED)); + wait_event(channel->wait_q, (channel->state == LCS_CH_STATE_HALTED)); lcs_clear_channel(channel); return 0; } @@ -596,8 +598,8 @@ __lcs_get_buffer(struct lcs_channel *channel) LCS_DBF_TEXT(5, trace, "_getbuff"); index = channel->io_idx; do { - if (channel->iob[index].state == BUF_STATE_EMPTY) { - channel->iob[index].state = BUF_STATE_LOCKED; + if (channel->iob[index].state == LCS_BUF_STATE_EMPTY) { + channel->iob[index].state = LCS_BUF_STATE_LOCKED; return channel->iob + index; } index = (index + 1) & (LCS_NUM_BUFFS - 1); @@ -626,7 +628,7 @@ __lcs_resume_channel(struct lcs_channel *channel) { int rc; - if (channel->state != CH_STATE_SUSPENDED) + if (channel->state != LCS_CH_STATE_SUSPENDED) return 0; if (channel->ccws[channel->io_idx].flags & CCW_FLAG_SUSPEND) return 0; @@ -636,7 +638,7 @@ __lcs_resume_channel(struct lcs_channel *channel) LCS_DBF_TEXT_(4, trace, "ersc%s", channel->ccwdev->dev.bus_id); PRINT_ERR("Error in lcs_resume_channel: rc=%d\n",rc); } else - channel->state = CH_STATE_RUNNING; + channel->state = LCS_CH_STATE_RUNNING; return rc; } @@ -670,10 +672,10 @@ lcs_ready_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer) int index, rc; LCS_DBF_TEXT(5, trace, "rdybuff"); - BUG_ON(buffer->state != BUF_STATE_LOCKED && - buffer->state != BUF_STATE_PROCESSED); + BUG_ON(buffer->state != LCS_BUF_STATE_LOCKED && + buffer->state != LCS_BUF_STATE_PROCESSED); spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); - buffer->state = BUF_STATE_READY; + buffer->state = LCS_BUF_STATE_READY; index = buffer - channel->iob; /* Set length. */ channel->ccws[index].count = buffer->count; @@ -695,8 +697,8 @@ __lcs_processed_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer) int index, prev, next; LCS_DBF_TEXT(5, trace, "prcsbuff"); - BUG_ON(buffer->state != BUF_STATE_READY); - buffer->state = BUF_STATE_PROCESSED; + BUG_ON(buffer->state != LCS_BUF_STATE_READY); + buffer->state = LCS_BUF_STATE_PROCESSED; index = buffer - channel->iob; prev = (index - 1) & (LCS_NUM_BUFFS - 1); next = (index + 1) & (LCS_NUM_BUFFS - 1); @@ -704,7 +706,7 @@ __lcs_processed_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer) channel->ccws[index].flags |= CCW_FLAG_SUSPEND; channel->ccws[index].flags &= ~CCW_FLAG_PCI; /* Check the suspend bit of the previous buffer. */ - if (channel->iob[prev].state == BUF_STATE_READY) { + if (channel->iob[prev].state == LCS_BUF_STATE_READY) { /* * Previous buffer is in state ready. It might have * happened in lcs_ready_buffer that the suspend bit @@ -727,10 +729,10 @@ lcs_release_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer) unsigned long flags; LCS_DBF_TEXT(5, trace, "relbuff"); - BUG_ON(buffer->state != BUF_STATE_LOCKED && - buffer->state != BUF_STATE_PROCESSED); + BUG_ON(buffer->state != LCS_BUF_STATE_LOCKED && + buffer->state != LCS_BUF_STATE_PROCESSED); spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); - buffer->state = BUF_STATE_EMPTY; + buffer->state = LCS_BUF_STATE_EMPTY; spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); } @@ -1264,7 +1266,7 @@ lcs_register_mc_addresses(void *data) netif_carrier_off(card->dev); netif_tx_disable(card->dev); wait_event(card->write.wait_q, - (card->write.state != CH_STATE_RUNNING)); + (card->write.state != LCS_CH_STATE_RUNNING)); lcs_fix_multicast_list(card); if (card->state == DEV_STATE_UP) { netif_carrier_on(card->dev); @@ -1404,7 +1406,7 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) } } /* How far in the ccw chain have we processed? */ - if ((channel->state != CH_STATE_INIT) && + if ((channel->state != LCS_CH_STATE_INIT) && (irb->scsw.fctl & SCSW_FCTL_START_FUNC)) { index = (struct ccw1 *) __va((addr_t) irb->scsw.cpa) - channel->ccws; @@ -1424,20 +1426,20 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) (irb->scsw.dstat & DEV_STAT_CHN_END) || (irb->scsw.dstat & DEV_STAT_UNIT_CHECK)) /* Mark channel as stopped. */ - channel->state = CH_STATE_STOPPED; + channel->state = LCS_CH_STATE_STOPPED; else if (irb->scsw.actl & SCSW_ACTL_SUSPENDED) /* CCW execution stopped on a suspend bit. */ - channel->state = CH_STATE_SUSPENDED; + channel->state = LCS_CH_STATE_SUSPENDED; if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC) { if (irb->scsw.cc != 0) { ccw_device_halt(channel->ccwdev, (addr_t) channel); return; } /* The channel has been stopped by halt_IO. */ - channel->state = CH_STATE_HALTED; + channel->state = LCS_CH_STATE_HALTED; } if (irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) { - channel->state = CH_STATE_CLEARED; + channel->state = LCS_CH_STATE_CLEARED; } /* Do the rest in the tasklet. */ tasklet_schedule(&channel->irq_tasklet); @@ -1461,7 +1463,7 @@ lcs_tasklet(unsigned long data) /* Check for processed buffers. */ iob = channel->iob; buf_idx = channel->buf_idx; - while (iob[buf_idx].state == BUF_STATE_PROCESSED) { + while (iob[buf_idx].state == LCS_BUF_STATE_PROCESSED) { /* Do the callback thing. */ if (iob[buf_idx].callback != NULL) iob[buf_idx].callback(channel, iob + buf_idx); @@ -1469,12 +1471,12 @@ lcs_tasklet(unsigned long data) } channel->buf_idx = buf_idx; - if (channel->state == CH_STATE_STOPPED) + if (channel->state == LCS_CH_STATE_STOPPED) // FIXME: what if rc != 0 ?? rc = lcs_start_channel(channel); spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); - if (channel->state == CH_STATE_SUSPENDED && - channel->iob[channel->io_idx].state == BUF_STATE_READY) { + if (channel->state == LCS_CH_STATE_SUSPENDED && + channel->iob[channel->io_idx].state == LCS_BUF_STATE_READY) { // FIXME: what if rc != 0 ?? rc = __lcs_resume_channel(channel); } @@ -1689,8 +1691,8 @@ lcs_detect(struct lcs_card *card) card->state = DEV_STATE_UP; } else { card->state = DEV_STATE_DOWN; - card->write.state = CH_STATE_INIT; - card->read.state = CH_STATE_INIT; + card->write.state = LCS_CH_STATE_INIT; + card->read.state = LCS_CH_STATE_INIT; } return rc; } @@ -1705,8 +1707,8 @@ lcs_stopcard(struct lcs_card *card) LCS_DBF_TEXT(3, setup, "stopcard"); - if (card->read.state != CH_STATE_STOPPED && - card->write.state != CH_STATE_STOPPED && + if (card->read.state != LCS_CH_STATE_STOPPED && + card->write.state != LCS_CH_STATE_STOPPED && card->state == DEV_STATE_UP) { lcs_clear_multicast_list(card); rc = lcs_send_stoplan(card,LCS_INITIATOR_TCPIP); @@ -1871,7 +1873,7 @@ lcs_stop_device(struct net_device *dev) netif_tx_disable(dev); dev->flags &= ~IFF_UP; wait_event(card->write.wait_q, - (card->write.state != CH_STATE_RUNNING)); + (card->write.state != LCS_CH_STATE_RUNNING)); rc = lcs_stopcard(card); if (rc) PRINT_ERR("Try it again!\n "); diff --git a/drivers/s390/net/lcs.h b/drivers/s390/net/lcs.h index b5247dc08b57..0e1e4a0a88f0 100644 --- a/drivers/s390/net/lcs.h +++ b/drivers/s390/net/lcs.h @@ -23,11 +23,6 @@ do { \ } while (0) /** - * some more definitions for debug or output stuff - */ -#define PRINTK_HEADER " lcs: " - -/** * sysfs related stuff */ #define CARD_FROM_DEV(cdev) \ @@ -127,22 +122,22 @@ do { \ * LCS Buffer states */ enum lcs_buffer_states { - BUF_STATE_EMPTY, /* buffer is empty */ - BUF_STATE_LOCKED, /* buffer is locked, don't touch */ - BUF_STATE_READY, /* buffer is ready for read/write */ - BUF_STATE_PROCESSED, + LCS_BUF_STATE_EMPTY, /* buffer is empty */ + LCS_BUF_STATE_LOCKED, /* buffer is locked, don't touch */ + LCS_BUF_STATE_READY, /* buffer is ready for read/write */ + LCS_BUF_STATE_PROCESSED, }; /** * LCS Channel State Machine declarations */ enum lcs_channel_states { - CH_STATE_INIT, - CH_STATE_HALTED, - CH_STATE_STOPPED, - CH_STATE_RUNNING, - CH_STATE_SUSPENDED, - CH_STATE_CLEARED, + LCS_CH_STATE_INIT, + LCS_CH_STATE_HALTED, + LCS_CH_STATE_STOPPED, + LCS_CH_STATE_RUNNING, + LCS_CH_STATE_SUSPENDED, + LCS_CH_STATE_CLEARED, }; /** diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h index 821383d8cbe7..53c358c7d368 100644 --- a/drivers/s390/net/qeth.h +++ b/drivers/s390/net/qeth.h @@ -151,8 +151,6 @@ qeth_hex_dump(unsigned char *buf, size_t len) #define SENSE_RESETTING_EVENT_BYTE 1 #define SENSE_RESETTING_EVENT_FLAG 0x80 -#define atomic_swap(a,b) xchg((int *)a.counter, b) - /* * Common IO related definitions */ diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 8364d5475ac7..7fdc5272c446 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -2982,7 +2982,7 @@ qeth_check_outbound_queue(struct qeth_qdio_out_q *queue) */ if ((atomic_read(&queue->used_buffers) <= QETH_LOW_WATERMARK_PACK) || !atomic_read(&queue->set_pci_flags_count)){ - if (atomic_swap(&queue->state, QETH_OUT_Q_LOCKED_FLUSH) == + if (atomic_xchg(&queue->state, QETH_OUT_Q_LOCKED_FLUSH) == QETH_OUT_Q_UNLOCKED) { /* * If we get in here, there was no action in @@ -3245,7 +3245,7 @@ qeth_free_qdio_buffers(struct qeth_card *card) int i, j; QETH_DBF_TEXT(trace, 2, "freeqdbf"); - if (atomic_swap(&card->qdio.state, QETH_QDIO_UNINITIALIZED) == + if (atomic_xchg(&card->qdio.state, QETH_QDIO_UNINITIALIZED) == QETH_QDIO_UNINITIALIZED) return; kfree(card->qdio.in_q); @@ -4366,7 +4366,7 @@ out: if (flush_count) qeth_flush_buffers(queue, 0, start_index, flush_count); else if (!atomic_read(&queue->set_pci_flags_count)) - atomic_swap(&queue->state, QETH_OUT_Q_LOCKED_FLUSH); + atomic_xchg(&queue->state, QETH_OUT_Q_LOCKED_FLUSH); /* * queue->state will go from LOCKED -> UNLOCKED or from * LOCKED_FLUSH -> LOCKED if output_handler wanted to 'notify' us diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index b5b0c2cba96b..5c0b75bbfa10 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -25,6 +25,7 @@ #include <linux/init.h> #include <linux/module.h> +#include <linux/jiffies.h> #include <linux/err.h> #include <linux/slab.h> #include <linux/string.h> diff --git a/drivers/spi/spi_butterfly.c b/drivers/spi/spi_butterfly.c index 39d9b20f2038..c2f601f8e4f2 100644 --- a/drivers/spi/spi_butterfly.c +++ b/drivers/spi/spi_butterfly.c @@ -23,6 +23,7 @@ #include <linux/platform_device.h> #include <linux/parport.h> +#include <linux/sched.h> #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> #include <linux/spi/flash.h> diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c index 5372cfcbd054..b022fffd8c51 100644 --- a/drivers/w1/slaves/w1_therm.c +++ b/drivers/w1/slaves/w1_therm.c @@ -24,6 +24,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> +#include <linux/sched.h> #include <linux/device.h> #include <linux/types.h> #include <linux/delay.h> diff --git a/fs/9p/conv.c b/fs/9p/conv.c index 56d88c1a09c5..a3ed571eee31 100644 --- a/fs/9p/conv.c +++ b/fs/9p/conv.c @@ -27,6 +27,7 @@ #include <linux/module.h> #include <linux/errno.h> #include <linux/fs.h> +#include <linux/sched.h> #include <linux/idr.h> #include <asm/uaccess.h> #include "debug.h" diff --git a/fs/9p/fcall.c b/fs/9p/fcall.c index 8556097fcda8..dc336a67592f 100644 --- a/fs/9p/fcall.c +++ b/fs/9p/fcall.c @@ -27,6 +27,7 @@ #include <linux/module.h> #include <linux/errno.h> #include <linux/fs.h> +#include <linux/sched.h> #include <linux/idr.h> #include "debug.h" diff --git a/fs/9p/fid.c b/fs/9p/fid.c index 70492ccb4385..27507201f9e7 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c @@ -23,6 +23,7 @@ #include <linux/module.h> #include <linux/errno.h> #include <linux/fs.h> +#include <linux/sched.h> #include <linux/idr.h> #include "debug.h" diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 0f628041e3f7..0b96fae8b479 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -26,6 +26,7 @@ #include <linux/module.h> #include <linux/errno.h> #include <linux/fs.h> +#include <linux/sched.h> #include <linux/parser.h> #include <linux/idr.h> diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index e32d5971039b..905c882f4e2f 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c @@ -30,6 +30,7 @@ #include <linux/stat.h> #include <linux/string.h> #include <linux/smp_lock.h> +#include <linux/sched.h> #include <linux/inet.h> #include <linux/idr.h> diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index c3c47eda7574..79e6f9cd7340 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -26,6 +26,7 @@ #include <linux/module.h> #include <linux/errno.h> #include <linux/fs.h> +#include <linux/sched.h> #include <linux/file.h> #include <linux/stat.h> #include <linux/string.h> diff --git a/fs/compat.c b/fs/compat.c index 8d0a0018a7d2..06dad665b88f 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -45,6 +45,8 @@ #include <linux/personality.h> #include <linux/rwsem.h> #include <linux/tsacct_kern.h> +#include <linux/highmem.h> +#include <linux/poll.h> #include <linux/mm.h> #include <net/sock.h> /* siocdevprivate_ioctl */ diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c index 7365aec9511b..3799f19b282f 100644 --- a/fs/gfs2/locking/dlm/plock.c +++ b/fs/gfs2/locking/dlm/plock.c @@ -8,6 +8,7 @@ #include <linux/miscdevice.h> #include <linux/lock_dlm_plock.h> +#include <linux/poll.h> #include "lock_dlm.h" diff --git a/fs/inotify.c b/fs/inotify.c index 723836a1f718..f5099d86fd91 100644 --- a/fs/inotify.c +++ b/fs/inotify.c @@ -27,6 +27,7 @@ #include <linux/idr.h> #include <linux/slab.h> #include <linux/fs.h> +#include <linux/sched.h> #include <linux/init.h> #include <linux/list.h> #include <linux/writeback.h> diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c index 0ae3cd10702c..73f0d60f73a5 100644 --- a/fs/jffs2/acl.c +++ b/fs/jffs2/acl.c @@ -11,6 +11,7 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/fs.h> +#include <linux/sched.h> #include <linux/time.h> #include <linux/crc32.h> #include <linux/jffs2.h> diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index b9b700730dfe..70707309dfa1 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -19,6 +19,7 @@ #include <linux/crc32.h> #include <linux/mtd/nand.h> #include <linux/jiffies.h> +#include <linux/sched.h> #include "nodelist.h" diff --git a/fs/jfs/ioctl.c b/fs/jfs/ioctl.c index 37db52488262..ed814b1ff4d9 100644 --- a/fs/jfs/ioctl.c +++ b/fs/jfs/ioctl.c @@ -9,6 +9,7 @@ #include <linux/ctype.h> #include <linux/capability.h> #include <linux/time.h> +#include <linux/sched.h> #include <asm/current.h> #include <asm/uaccess.h> diff --git a/fs/partitions/mac.c b/fs/partitions/mac.c index c0871002d00d..d4a0fad3563b 100644 --- a/fs/partitions/mac.c +++ b/fs/partitions/mac.c @@ -74,6 +74,8 @@ int mac_partition(struct parsed_partitions *state, struct block_device *bdev) be32_to_cpu(part->start_block) * (secsize/512), be32_to_cpu(part->block_count) * (secsize/512)); + if (!strnicmp(part->type, "Linux_RAID", 10)) + state->parts[slot].flags = 1; #ifdef CONFIG_PPC_PMAC /* * If this is the first bootable partition, tell the diff --git a/fs/proc/root.c b/fs/proc/root.c index ffe66c38488b..64d242b6dcfa 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -13,6 +13,7 @@ #include <linux/proc_fs.h> #include <linux/stat.h> #include <linux/init.h> +#include <linux/sched.h> #include <linux/module.h> #include <linux/bitops.h> #include <linux/smp_lock.h> diff --git a/fs/super.c b/fs/super.c index 47e554c12e76..84c320f6ad7e 100644 --- a/fs/super.c +++ b/fs/super.c @@ -221,6 +221,24 @@ static int grab_super(struct super_block *s) __releases(sb_lock) } /* + * Superblock locking. We really ought to get rid of these two. + */ +void lock_super(struct super_block * sb) +{ + get_fs_excl(); + mutex_lock(&sb->s_lock); +} + +void unlock_super(struct super_block * sb) +{ + put_fs_excl(); + mutex_unlock(&sb->s_lock); +} + +EXPORT_SYMBOL(lock_super); +EXPORT_SYMBOL(unlock_super); + +/* * Write out and wait upon all dirty data associated with this * superblock. Filesystem data as well as the underlying block * device. Takes the superblock lock. Requires a second blkdev diff --git a/fs/sync.c b/fs/sync.c index 1de747b5ddb9..865f32be386e 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -6,6 +6,7 @@ #include <linux/file.h> #include <linux/fs.h> #include <linux/module.h> +#include <linux/sched.h> #include <linux/writeback.h> #include <linux/syscalls.h> #include <linux/linkage.h> diff --git a/fs/utimes.c b/fs/utimes.c index 1bcd852fc4a9..99cf2cb11fec 100644 --- a/fs/utimes.c +++ b/fs/utimes.c @@ -2,6 +2,7 @@ #include <linux/fs.h> #include <linux/linkage.h> #include <linux/namei.h> +#include <linux/sched.h> #include <linux/utime.h> #include <asm/uaccess.h> #include <asm/unistd.h> diff --git a/include/asm-arm/arch-ixp4xx/platform.h b/include/asm-arm/arch-ixp4xx/platform.h index 8d10a9187693..ab194e5f6653 100644 --- a/include/asm-arm/arch-ixp4xx/platform.h +++ b/include/asm-arm/arch-ixp4xx/platform.h @@ -86,6 +86,19 @@ struct ixp4xx_i2c_pins { unsigned long scl_pin; }; +/* + * This structure provide a means for the board setup code + * to give information to th pata_ixp4xx driver. It is + * passed as platform_data. + */ +struct ixp4xx_pata_data { + volatile u32 *cs0_cfg; + volatile u32 *cs1_cfg; + unsigned long cs0_bits; + unsigned long cs1_bits; + void __iomem *cs0; + void __iomem *cs1; +}; struct sys_timer; diff --git a/include/asm-m68knommu/dma-mapping.h b/include/asm-m68knommu/dma-mapping.h index 5622b855a577..6aeab18e58bd 100644 --- a/include/asm-m68knommu/dma-mapping.h +++ b/include/asm-m68knommu/dma-mapping.h @@ -1,9 +1,10 @@ #ifndef _M68KNOMMU_DMA_MAPPING_H #define _M68KNOMMU_DMA_MAPPING_H - #ifdef CONFIG_PCI #include <asm-generic/dma-mapping.h> +#else +#include <asm-generic/dma-mapping-broken.h> #endif #endif /* _M68KNOMMU_DMA_MAPPING_H */ diff --git a/include/asm-m68knommu/m520xsim.h b/include/asm-m68knommu/m520xsim.h index 1dac22ea95ba..49d016e6391a 100644 --- a/include/asm-m68knommu/m520xsim.h +++ b/include/asm-m68knommu/m520xsim.h @@ -31,6 +31,16 @@ #define MCFINT_QSPI 31 /* Interrupt number for QSPI */ #define MCFINT_PIT1 4 /* Interrupt number for PIT1 (PIT0 in processor) */ +/* + * SDRAM configuration registers. + */ +#define MCFSIM_SDMR 0x000a8000 /* SDRAM Mode/Extended Mode Register */ +#define MCFSIM_SDCR 0x000a8004 /* SDRAM Control Register */ +#define MCFSIM_SDCFG1 0x000a8008 /* SDRAM Configuration Register 1 */ +#define MCFSIM_SDCFG2 0x000a800c /* SDRAM Configuration Register 2 */ +#define MCFSIM_SDCS0 0x000a8110 /* SDRAM Chip Select 0 Configuration */ +#define MCFSIM_SDCS1 0x000a8114 /* SDRAM Chip Select 1 Configuration */ + #define MCF_GPIO_PAR_UART (0xA4036) #define MCF_GPIO_PAR_FECI2C (0xA4033) @@ -47,7 +57,7 @@ #define ICR_INTRCONF 0x05 #define MCFPIT_IMR MCFINTC_IMRL -#define MCFPIT_IMR_IBIT (1 << MCFINT_PIT1) +#define MCFPIT_IMR_IBIT (1 << MCFINT_PIT1) /****************************************************************************/ #endif /* m520xsim_h */ diff --git a/include/asm-m68knommu/scatterlist.h b/include/asm-m68knommu/scatterlist.h index 12309b181d29..2085d6ff8782 100644 --- a/include/asm-m68knommu/scatterlist.h +++ b/include/asm-m68knommu/scatterlist.h @@ -10,7 +10,7 @@ struct scatterlist { unsigned int length; }; -#define sg_address(sg) (page_address((sg)->page) + (sg)->offset +#define sg_address(sg) (page_address((sg)->page) + (sg)->offset) #define sg_dma_address(sg) ((sg)->dma_address) #define sg_dma_len(sg) ((sg)->length) diff --git a/include/asm-s390/cio.h b/include/asm-s390/cio.h index 81287d86329d..d92785030980 100644 --- a/include/asm-s390/cio.h +++ b/include/asm-s390/cio.h @@ -278,17 +278,16 @@ struct ccw_dev_id { static inline int ccw_dev_id_is_equal(struct ccw_dev_id *dev_id1, struct ccw_dev_id *dev_id2) { - return !memcmp(dev_id1, dev_id2, sizeof(struct ccw_dev_id)); + if ((dev_id1->ssid == dev_id2->ssid) && + (dev_id1->devno == dev_id2->devno)) + return 1; + return 0; } extern int diag210(struct diag210 *addr); extern void wait_cons_dev(void); -extern void clear_all_subchannels(void); - -extern void cio_reset_channel_paths(void); - extern void css_schedule_reprobe(void); extern void reipl_ccw_dev(struct ccw_dev_id *id); diff --git a/include/asm-s390/cpcmd.h b/include/asm-s390/cpcmd.h index 1fcf65be7a23..48a9eab16429 100644 --- a/include/asm-s390/cpcmd.h +++ b/include/asm-s390/cpcmd.h @@ -7,8 +7,8 @@ * Christian Borntraeger (cborntra@de.ibm.com), */ -#ifndef __CPCMD__ -#define __CPCMD__ +#ifndef _ASM_S390_CPCMD_H +#define _ASM_S390_CPCMD_H /* * the lowlevel function for cpcmd @@ -16,9 +16,6 @@ */ extern int __cpcmd(const char *cmd, char *response, int rlen, int *response_code); -#ifndef __s390x__ -#define cpcmd __cpcmd -#else /* * cpcmd is the in-kernel interface for issuing CP commands * @@ -33,6 +30,5 @@ extern int __cpcmd(const char *cmd, char *response, int rlen, int *response_code * NOTE: If the response buffer is not below 2 GB, cpcmd can sleep */ extern int cpcmd(const char *cmd, char *response, int rlen, int *response_code); -#endif /*__s390x__*/ -#endif +#endif /* _ASM_S390_CPCMD_H */ diff --git a/include/asm-s390/kexec.h b/include/asm-s390/kexec.h index ce28ddda0f50..9c35c8ad1afd 100644 --- a/include/asm-s390/kexec.h +++ b/include/asm-s390/kexec.h @@ -26,7 +26,7 @@ /* Maximum address we can use for the control pages */ /* Not more than 2GB */ -#define KEXEC_CONTROL_MEMORY_LIMIT (1<<31) +#define KEXEC_CONTROL_MEMORY_LIMIT (1UL<<31) /* Allocate one page for the pdp and the second for the code */ #define KEXEC_CONTROL_CODE_SIZE 4096 diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h index 06583ed0bde7..74f7389bd3ee 100644 --- a/include/asm-s390/lowcore.h +++ b/include/asm-s390/lowcore.h @@ -362,6 +362,14 @@ static inline void set_prefix(__u32 address) asm volatile("spx %0" : : "m" (address) : "memory"); } +static inline __u32 store_prefix(void) +{ + __u32 address; + + asm volatile("stpx %0" : "=m" (address)); + return address; +} + #define __PANIC_MAGIC 0xDEADC0DE #endif diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h index 36bb6dacf008..2d968a69ed1f 100644 --- a/include/asm-s390/pgtable.h +++ b/include/asm-s390/pgtable.h @@ -110,13 +110,22 @@ extern char empty_zero_page[PAGE_SIZE]; #define VMALLOC_OFFSET (8*1024*1024) #define VMALLOC_START (((unsigned long) high_memory + VMALLOC_OFFSET) \ & ~(VMALLOC_OFFSET-1)) + +/* + * We need some free virtual space to be able to do vmalloc. + * VMALLOC_MIN_SIZE defines the minimum size of the vmalloc + * area. On a machine with 2GB memory we make sure that we + * have at least 128MB free space for vmalloc. On a machine + * with 4TB we make sure we have at least 1GB. + */ #ifndef __s390x__ -# define VMALLOC_END (0x7fffffffL) +#define VMALLOC_MIN_SIZE 0x8000000UL +#define VMALLOC_END 0x80000000UL #else /* __s390x__ */ -# define VMALLOC_END (0x40000000000L) +#define VMALLOC_MIN_SIZE 0x40000000UL +#define VMALLOC_END 0x40000000000UL #endif /* __s390x__ */ - /* * A 31 bit pagetable entry of S390 has following format: * | PFRA | | OS | diff --git a/include/asm-s390/reset.h b/include/asm-s390/reset.h new file mode 100644 index 000000000000..9b439cf67800 --- /dev/null +++ b/include/asm-s390/reset.h @@ -0,0 +1,23 @@ +/* + * include/asm-s390/reset.h + * + * Copyright IBM Corp. 2006 + * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> + */ + +#ifndef _ASM_S390_RESET_H +#define _ASM_S390_RESET_H + +#include <linux/list.h> + +struct reset_call { + struct list_head list; + void (*fn)(void); +}; + +extern void register_reset_call(struct reset_call *reset); +extern void unregister_reset_call(struct reset_call *reset); +extern void s390_reset_system(void); +extern void (*s390_reset_mcck_handler)(void); + +#endif /* _ASM_S390_RESET_H */ diff --git a/include/asm-s390/setup.h b/include/asm-s390/setup.h index 5d72eda8a11b..7664bacdd832 100644 --- a/include/asm-s390/setup.h +++ b/include/asm-s390/setup.h @@ -2,7 +2,7 @@ * include/asm-s390/setup.h * * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright IBM Corp. 1999,2006 */ #ifndef _ASM_S390_SETUP_H @@ -30,6 +30,17 @@ #endif /* __s390x__ */ #define COMMAND_LINE ((char *) (0x10480)) +#define CHUNK_READ_WRITE 0 +#define CHUNK_READ_ONLY 1 + +struct mem_chunk { + unsigned long addr; + unsigned long size; + unsigned long type; +}; + +extern struct mem_chunk memory_chunk[]; + /* * Machine features detected in head.S */ @@ -53,7 +64,6 @@ extern unsigned long machine_flags; #define MACHINE_HAS_MVCOS (machine_flags & 512) #endif /* __s390x__ */ - #define MACHINE_HAS_SCLP (!MACHINE_IS_P390) /* @@ -71,7 +81,6 @@ extern unsigned int console_irq; #define SET_CONSOLE_3215 do { console_mode = 2; } while (0) #define SET_CONSOLE_3270 do { console_mode = 3; } while (0) - struct ipl_list_hdr { u32 len; u8 reserved1[3]; diff --git a/include/asm-s390/smp.h b/include/asm-s390/smp.h index c3cf030ada4d..7097c96ed026 100644 --- a/include/asm-s390/smp.h +++ b/include/asm-s390/smp.h @@ -18,6 +18,7 @@ #include <asm/lowcore.h> #include <asm/sigp.h> +#include <asm/ptrace.h> /* s390 specific smp.c headers @@ -101,6 +102,13 @@ smp_call_function_on(void (*func) (void *info), void *info, func(info); return 0; } + +static inline void smp_send_stop(void) +{ + /* Disable all interrupts/machine checks */ + __load_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK); +} + #define smp_cpu_not_running(cpu) 1 #define smp_get_cpu(cpu) ({ 0; }) #define smp_put_cpu(cpu) ({ 0; }) diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h index ccbafe4bf2cb..bd0b05ae87d2 100644 --- a/include/asm-s390/system.h +++ b/include/asm-s390/system.h @@ -115,6 +115,16 @@ extern void account_system_vtime(struct task_struct *); #define account_vtime(x) do { /* empty */ } while (0) #endif +#ifdef CONFIG_PFAULT +extern void pfault_irq_init(void); +extern int pfault_init(void); +extern void pfault_fini(void); +#else /* CONFIG_PFAULT */ +#define pfault_irq_init() do { } while (0) +#define pfault_init() ({-1;}) +#define pfault_fini() do { } while (0) +#endif /* CONFIG_PFAULT */ + #define finish_arch_switch(prev) do { \ set_fs(current->thread.mm_segment); \ account_vtime(prev); \ diff --git a/include/asm-s390/termios.h b/include/asm-s390/termios.h index d1e29cca54c9..62b23caf370e 100644 --- a/include/asm-s390/termios.h +++ b/include/asm-s390/termios.h @@ -75,39 +75,7 @@ struct termio { */ #define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" -/* - * Translate a "termio" structure into a "termios". Ugh. - */ -#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \ - unsigned short __tmp; \ - get_user(__tmp,&(termio)->x); \ - (termios)->x = (0xffff0000 & ((termios)->x)) | __tmp; \ -} - -#define user_termio_to_kernel_termios(termios, termio) \ -({ \ - SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \ - SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \ - SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \ - SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \ - copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \ -}) - -/* - * Translate a "termios" structure into a "termio". Ugh. - */ -#define kernel_termios_to_user_termio(termio, termios) \ -({ \ - put_user((termios)->c_iflag, &(termio)->c_iflag); \ - put_user((termios)->c_oflag, &(termio)->c_oflag); \ - put_user((termios)->c_cflag, &(termio)->c_cflag); \ - put_user((termios)->c_lflag, &(termio)->c_lflag); \ - put_user((termios)->c_line, &(termio)->c_line); \ - copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \ -}) - -#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios)) -#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios)) +#include <asm-generic/termios.h> #endif /* __KERNEL__ */ diff --git a/include/asm-s390/uaccess.h b/include/asm-s390/uaccess.h index 72ae4efddb49..73ac4e82217b 100644 --- a/include/asm-s390/uaccess.h +++ b/include/asm-s390/uaccess.h @@ -201,7 +201,7 @@ extern int __get_user_bad(void) __attribute__((noreturn)); * Returns number of bytes that could not be copied. * On success, this will be zero. */ -static inline unsigned long +static inline unsigned long __must_check __copy_to_user(void __user *to, const void *from, unsigned long n) { if (__builtin_constant_p(n) && (n <= 256)) @@ -226,7 +226,7 @@ __copy_to_user(void __user *to, const void *from, unsigned long n) * Returns number of bytes that could not be copied. * On success, this will be zero. */ -static inline unsigned long +static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n) { might_sleep(); @@ -252,7 +252,7 @@ copy_to_user(void __user *to, const void *from, unsigned long n) * If some data could not be copied, this function will pad the copied * data to the requested size using zero bytes. */ -static inline unsigned long +static inline unsigned long __must_check __copy_from_user(void *to, const void __user *from, unsigned long n) { if (__builtin_constant_p(n) && (n <= 256)) @@ -277,7 +277,7 @@ __copy_from_user(void *to, const void __user *from, unsigned long n) * If some data could not be copied, this function will pad the copied * data to the requested size using zero bytes. */ -static inline unsigned long +static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) { might_sleep(); @@ -288,13 +288,13 @@ copy_from_user(void *to, const void __user *from, unsigned long n) return n; } -static inline unsigned long +static inline unsigned long __must_check __copy_in_user(void __user *to, const void __user *from, unsigned long n) { return uaccess.copy_in_user(n, to, from); } -static inline unsigned long +static inline unsigned long __must_check copy_in_user(void __user *to, const void __user *from, unsigned long n) { might_sleep(); @@ -306,7 +306,7 @@ copy_in_user(void __user *to, const void __user *from, unsigned long n) /* * Copy a null terminated string from userspace. */ -static inline long +static inline long __must_check strncpy_from_user(char *dst, const char __user *src, long count) { long res = -EFAULT; @@ -343,13 +343,13 @@ strnlen_user(const char __user * src, unsigned long n) * Zero Userspace */ -static inline unsigned long +static inline unsigned long __must_check __clear_user(void __user *to, unsigned long n) { return uaccess.clear_user(n, to); } -static inline unsigned long +static inline unsigned long __must_check clear_user(void __user *to, unsigned long n) { might_sleep(); diff --git a/include/asm-s390/zcrypt.h b/include/asm-s390/zcrypt.h index 7244c68464f2..b90e55888a55 100644 --- a/include/asm-s390/zcrypt.h +++ b/include/asm-s390/zcrypt.h @@ -180,40 +180,8 @@ struct ica_xcRB { * for the implementation details for the contents of the * block * - * Z90STAT_TOTALCOUNT - * Return an integer count of all device types together. - * - * Z90STAT_PCICACOUNT - * Return an integer count of all PCICAs. - * - * Z90STAT_PCICCCOUNT - * Return an integer count of all PCICCs. - * - * Z90STAT_PCIXCCMCL2COUNT - * Return an integer count of all MCL2 PCIXCCs. - * - * Z90STAT_PCIXCCMCL3COUNT - * Return an integer count of all MCL3 PCIXCCs. - * - * Z90STAT_CEX2CCOUNT - * Return an integer count of all CEX2Cs. - * - * Z90STAT_CEX2ACOUNT - * Return an integer count of all CEX2As. - * - * Z90STAT_REQUESTQ_COUNT - * Return an integer count of the number of entries waiting to be - * sent to a device. - * - * Z90STAT_PENDINGQ_COUNT - * Return an integer count of the number of entries sent to a - * device awaiting the reply. - * - * Z90STAT_TOTALOPEN_COUNT - * Return an integer count of the number of open file handles. - * - * Z90STAT_DOMAIN_INDEX - * Return the integer value of the Cryptographic Domain. + * ZSECSENDCPRB + * Send an arbitrary CPRB to a crypto card. * * Z90STAT_STATUS_MASK * Return an 64 element array of unsigned chars for the status of @@ -235,28 +203,51 @@ struct ica_xcRB { * of successfully completed requests per device since the device * was detected and made available. * - * ICAZ90STATUS (deprecated) + * Z90STAT_REQUESTQ_COUNT + * Return an integer count of the number of entries waiting to be + * sent to a device. + * + * Z90STAT_PENDINGQ_COUNT + * Return an integer count of the number of entries sent to all + * devices awaiting the reply. + * + * Z90STAT_TOTALOPEN_COUNT + * Return an integer count of the number of open file handles. + * + * Z90STAT_DOMAIN_INDEX + * Return the integer value of the Cryptographic Domain. + * + * The following ioctls are deprecated and should be no longer used: + * + * Z90STAT_TOTALCOUNT + * Return an integer count of all device types together. + * + * Z90STAT_PCICACOUNT + * Return an integer count of all PCICAs. + * + * Z90STAT_PCICCCOUNT + * Return an integer count of all PCICCs. + * + * Z90STAT_PCIXCCMCL2COUNT + * Return an integer count of all MCL2 PCIXCCs. + * + * Z90STAT_PCIXCCMCL3COUNT + * Return an integer count of all MCL3 PCIXCCs. + * + * Z90STAT_CEX2CCOUNT + * Return an integer count of all CEX2Cs. + * + * Z90STAT_CEX2ACOUNT + * Return an integer count of all CEX2As. + * + * ICAZ90STATUS * Return some device driver status in a ica_z90_status struct * This takes an ica_z90_status struct as its arg. * - * NOTE: this ioctl() is deprecated, and has been replaced with - * single ioctl()s for each type of status being requested - * - * Z90STAT_PCIXCCCOUNT (deprecated) + * Z90STAT_PCIXCCCOUNT * Return an integer count of all PCIXCCs (MCL2 + MCL3). * This is DEPRECATED now that MCL3 PCIXCCs are treated differently from * MCL2 PCIXCCs. - * - * Z90QUIESCE (not recommended) - * Quiesce the driver. This is intended to stop all new - * requests from being processed. Its use is NOT recommended, - * except in circumstances where there is no other way to stop - * callers from accessing the driver. Its original use was to - * allow the driver to be "drained" of work in preparation for - * a system shutdown. - * - * NOTE: once issued, this ban on new work cannot be undone - * except by unloading and reloading the driver. */ /** diff --git a/include/asm-x86_64/elf.h b/include/asm-x86_64/elf.h index a406fcb1e924..6d24ea7c4d9d 100644 --- a/include/asm-x86_64/elf.h +++ b/include/asm-x86_64/elf.h @@ -45,7 +45,6 @@ typedef struct user_i387_struct elf_fpregset_t; #ifdef __KERNEL__ #include <asm/processor.h> -#include <asm/compat.h> /* * This is used to ensure we don't load something for the wrong architecture. diff --git a/include/asm-x86_64/uaccess.h b/include/asm-x86_64/uaccess.h index 19f99178fe83..d5dbc87274f8 100644 --- a/include/asm-x86_64/uaccess.h +++ b/include/asm-x86_64/uaccess.h @@ -6,7 +6,6 @@ */ #include <linux/compiler.h> #include <linux/errno.h> -#include <linux/sched.h> #include <linux/prefetch.h> #include <asm/page.h> diff --git a/include/linux/Kbuild b/include/linux/Kbuild index d7e04689304c..ff433126361f 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -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 diff --git a/include/linux/acct.h b/include/linux/acct.h index 0496d1f09952..302eb727ecb8 100644 --- a/include/linux/acct.h +++ b/include/linux/acct.h @@ -119,6 +119,7 @@ struct acct_v3 #ifdef CONFIG_BSD_PROCESS_ACCT struct vfsmount; struct super_block; +struct pacct_struct; extern void acct_auto_close_mnt(struct vfsmount *m); extern void acct_auto_close(struct super_block *sb); extern void acct_init_pacct(struct pacct_struct *pacct); diff --git a/include/linux/ata.h b/include/linux/ata.h index d89441907024..1df941648a57 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -200,8 +200,9 @@ enum { ATA_CBL_NONE = 0, ATA_CBL_PATA40 = 1, ATA_CBL_PATA80 = 2, - ATA_CBL_PATA_UNK = 3, - ATA_CBL_SATA = 4, + ATA_CBL_PATA40_SHORT = 3, /* 40 wire cable to high UDMA spec */ + ATA_CBL_PATA_UNK = 4, + ATA_CBL_SATA = 5, /* SATA Status and Control Registers */ SCR_STATUS = 0, @@ -342,6 +343,15 @@ static inline int ata_id_is_cfa(const u16 *id) return 0; } +static inline int ata_drive_40wire(const u16 *dev_id) +{ + if (ata_id_major_version(dev_id) >= 5 && ata_id_is_sata(dev_id)) + return 0; /* SATA */ + if (dev_id[93] & 0x4000) + return 0; /* 80 wire */ + return 1; +} + static inline int atapi_cdb_len(const u16 *dev_id) { u16 tmp = dev_id[0] & 0x3; diff --git a/include/linux/fs.h b/include/linux/fs.h index 2fe6e3f900ba..cac7b1ef9543 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -276,7 +276,7 @@ extern int dir_notify_enable; #include <linux/radix-tree.h> #include <linux/prio_tree.h> #include <linux/init.h> -#include <linux/sched.h> +#include <linux/pid.h> #include <linux/mutex.h> #include <asm/atomic.h> @@ -977,36 +977,13 @@ enum { #define vfs_check_frozen(sb, level) \ wait_event((sb)->s_wait_unfrozen, ((sb)->s_frozen < (level))) -static inline void get_fs_excl(void) -{ - atomic_inc(¤t->fs_excl); -} - -static inline void put_fs_excl(void) -{ - atomic_dec(¤t->fs_excl); -} - -static inline int has_fs_excl(void) -{ - return atomic_read(¤t->fs_excl); -} +#define get_fs_excl() atomic_inc(¤t->fs_excl) +#define put_fs_excl() atomic_dec(¤t->fs_excl) +#define has_fs_excl() atomic_read(¤t->fs_excl) - -/* - * Superblock locking. - */ -static inline void lock_super(struct super_block * sb) -{ - get_fs_excl(); - mutex_lock(&sb->s_lock); -} - -static inline void unlock_super(struct super_block * sb) -{ - put_fs_excl(); - mutex_unlock(&sb->s_lock); -} +/* not quite ready to be deprecated, but... */ +extern void lock_super(struct super_block *); +extern void unlock_super(struct super_block *); /* * VFS helper functions.. diff --git a/include/linux/ftape-header-segment.h b/include/linux/ftape-header-segment.h deleted file mode 100644 index 4732218f0708..000000000000 --- a/include/linux/ftape-header-segment.h +++ /dev/null @@ -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 */ diff --git a/include/linux/ftape-vendors.h b/include/linux/ftape-vendors.h deleted file mode 100644 index ec1a81f059e5..000000000000 --- a/include/linux/ftape-vendors.h +++ /dev/null @@ -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 */ diff --git a/include/linux/ftape.h b/include/linux/ftape.h deleted file mode 100644 index 7e7038cba86a..000000000000 --- a/include/linux/ftape.h +++ /dev/null @@ -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 diff --git a/include/linux/igmp.h b/include/linux/igmp.h index 6e7ea2f0a57c..9dbb525c5178 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -127,6 +127,7 @@ struct igmpv3_query { #ifdef __KERNEL__ #include <linux/skbuff.h> +#include <linux/timer.h> #include <linux/in.h> extern int sysctl_igmp_max_memberships; diff --git a/include/linux/kernelcapi.h b/include/linux/kernelcapi.h index 891bb2cf0aa8..aea34e74c496 100644 --- a/include/linux/kernelcapi.h +++ b/include/linux/kernelcapi.h @@ -47,6 +47,8 @@ typedef struct kcapi_carddef { #include <linux/list.h> #include <linux/skbuff.h> +#include <linux/workqueue.h> +#include <asm/semaphore.h> #define KCI_CONTRUP 0 /* arg: struct capi_profile */ #define KCI_CONTRDOWN 1 /* arg: NULL */ diff --git a/include/linux/libata.h b/include/linux/libata.h index abd2debebca2..202283b5df96 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -140,6 +140,7 @@ enum { ATA_DFLAG_LBA48 = (1 << 1), /* device supports LBA48 */ ATA_DFLAG_CDB_INTR = (1 << 2), /* device asserts INTRQ when ready for CDB */ ATA_DFLAG_NCQ = (1 << 3), /* device supports NCQ */ + ATA_DFLAG_FLUSH_EXT = (1 << 4), /* do FLUSH_EXT instead of FLUSH */ ATA_DFLAG_CFG_MASK = (1 << 8) - 1, ATA_DFLAG_PIO = (1 << 8), /* device limited to PIO mode */ @@ -175,6 +176,7 @@ enum { ATA_FLAG_SKIP_D2H_BSY = (1 << 12), /* can't wait for the first D2H * Register FIS clearing BSY */ ATA_FLAG_DEBUGMSG = (1 << 13), + ATA_FLAG_SETXFER_POLLING= (1 << 14), /* use polling for SETXFER */ /* The following flag belongs to ap->pflags but is kept in * ap->flags because it's referenced in many LLDs and will be @@ -283,6 +285,9 @@ enum { ATA_EHI_QUIET = (1 << 3), /* be quiet */ ATA_EHI_DID_RESET = (1 << 16), /* already reset this port */ + ATA_EHI_PRINTINFO = (1 << 17), /* print configuration info */ + ATA_EHI_SETMODE = (1 << 18), /* configure transfer mode */ + ATA_EHI_POST_SETMODE = (1 << 19), /* revaildating after setmode */ ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK, @@ -307,10 +312,11 @@ enum { (some horkage may be drive/controller pair dependant */ ATA_HORKAGE_DIAGNOSTIC = (1 << 0), /* Failed boot diag */ + ATA_HORKAGE_NODMA = (1 << 1), /* DMA problems */ + ATA_HORKAGE_NONCQ = (1 << 2), /* Don't use NCQ */ }; enum hsm_task_states { - HSM_ST_UNKNOWN, /* state unknown */ HSM_ST_IDLE, /* no command on going */ HSM_ST, /* (waiting the device to) transfer data */ HSM_ST_LAST, /* (waiting the device to) complete command */ @@ -329,6 +335,7 @@ enum ata_completion_errors { AC_ERR_SYSTEM = (1 << 6), /* system error */ AC_ERR_INVALID = (1 << 7), /* invalid argument */ AC_ERR_OTHER = (1 << 8), /* unknown */ + AC_ERR_NODEV_HINT = (1 << 9), /* polling device detection hint */ }; /* forward declarations */ @@ -700,6 +707,8 @@ extern int sata_phy_debounce(struct ata_port *ap, const unsigned long *param); extern int sata_phy_resume(struct ata_port *ap, const unsigned long *param); extern int ata_std_prereset(struct ata_port *ap); extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes); +extern int sata_port_hardreset(struct ata_port *ap, + const unsigned long *timing); extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class); extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes); extern void ata_port_disable(struct ata_port *); @@ -744,9 +753,8 @@ extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t mesg); extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg); extern void ata_host_resume(struct ata_host *host); extern int ata_ratelimit(void); -extern unsigned int ata_busy_sleep(struct ata_port *ap, - unsigned long timeout_pat, - unsigned long timeout); +extern int ata_busy_sleep(struct ata_port *ap, + unsigned long timeout_pat, unsigned long timeout); extern void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data, unsigned long delay); extern u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val, @@ -787,6 +795,7 @@ extern void ata_id_string(const u16 *id, unsigned char *s, unsigned int ofs, unsigned int len); extern void ata_id_c_string(const u16 *id, unsigned char *s, unsigned int ofs, unsigned int len); +extern unsigned long ata_device_blacklisted(const struct ata_device *dev); extern void ata_bmdma_setup (struct ata_queued_cmd *qc); extern void ata_bmdma_start (struct ata_queued_cmd *qc); extern void ata_bmdma_stop(struct ata_queued_cmd *qc); @@ -1061,7 +1070,7 @@ static inline u8 ata_busy_wait(struct ata_port *ap, unsigned int bits, udelay(10); status = ata_chk_status(ap); max--; - } while ((status & bits) && (max > 0)); + } while (status != 0xff && (status & bits) && (max > 0)); return status; } @@ -1082,7 +1091,7 @@ static inline u8 ata_wait_idle(struct ata_port *ap) { u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - if (status & (ATA_BUSY | ATA_DRQ)) { + if (status != 0xff && (status & (ATA_BUSY | ATA_DRQ))) { unsigned long l = ap->ioaddr.status_addr; if (ata_msg_warn(ap)) printk(KERN_WARNING "ATA: abnormal status 0x%X on port 0x%lX\n", @@ -1148,37 +1157,6 @@ static inline void ata_qc_reinit(struct ata_queued_cmd *qc) } /** - * ata_irq_on - Enable interrupts on a port. - * @ap: Port on which interrupts are enabled. - * - * Enable interrupts on a legacy IDE device using MMIO or PIO, - * wait for idle, clear any pending interrupts. - * - * LOCKING: - * Inherited from caller. - */ - -static inline u8 ata_irq_on(struct ata_port *ap) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - u8 tmp; - - ap->ctl &= ~ATA_NIEN; - ap->last_ctl = ap->ctl; - - if (ap->flags & ATA_FLAG_MMIO) - writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); - else - outb(ap->ctl, ioaddr->ctl_addr); - tmp = ata_wait_idle(ap); - - ap->ops->irq_clear(ap); - - return tmp; -} - - -/** * ata_irq_ack - Acknowledge a device interrupt. * @ap: Port on which interrupts are enabled. * diff --git a/include/linux/module.h b/include/linux/module.h index 9258ffd8a7f0..d33df2408e05 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -6,7 +6,6 @@ * Rewritten by Richard Henderson <rth@tamu.edu> Dec 1996 * Rewritten again by Rusty Russell, 2002 */ -#include <linux/sched.h> #include <linux/spinlock.h> #include <linux/list.h> #include <linux/stat.h> @@ -411,17 +410,7 @@ static inline int try_module_get(struct module *module) return ret; } -static inline void module_put(struct module *module) -{ - if (module) { - unsigned int cpu = get_cpu(); - local_dec(&module->ref[cpu].count); - /* Maybe they're waiting for us to drop reference? */ - if (unlikely(!module_is_live(module))) - wake_up_process(module->waiter); - put_cpu(); - } -} +extern void module_put(struct module *module); #else /*!CONFIG_MODULE_UNLOAD*/ static inline int try_module_get(struct module *module) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 949eada46ce1..c57088f575a3 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -30,6 +30,7 @@ #include <linux/if_packet.h> #ifdef __KERNEL__ +#include <linux/timer.h> #include <asm/atomic.h> #include <asm/cache.h> #include <asm/byteorder.h> diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h index 61da56941dce..33581c13d947 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack.h +++ b/include/linux/netfilter_ipv4/ip_conntrack.h @@ -9,6 +9,7 @@ #include <linux/compiler.h> #include <asm/atomic.h> +#include <linux/timer.h> #include <linux/netfilter_ipv4/ip_conntrack_tcp.h> #include <linux/netfilter_ipv4/ip_conntrack_icmp.h> #include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> diff --git a/include/linux/pata_platform.h b/include/linux/pata_platform.h new file mode 100644 index 000000000000..2d5fd647e0e9 --- /dev/null +++ b/include/linux/pata_platform.h @@ -0,0 +1,13 @@ +#ifndef __LINUX_PATA_PLATFORM_H +#define __LINUX_PATA_PLATFORM_H + +struct pata_platform_info { + /* + * I/O port shift, for platforms with ports that are + * constantly spaced and need larger than the 1-byte + * spacing used by ata_std_ports(). + */ + unsigned int ioport_shift; +}; + +#endif /* __LINUX_PATA_PLATFORM_H */ diff --git a/include/linux/poll.h b/include/linux/poll.h index 51e1b56741fb..27690798623f 100644 --- a/include/linux/poll.h +++ b/include/linux/poll.h @@ -8,7 +8,8 @@ #include <linux/compiler.h> #include <linux/wait.h> #include <linux/string.h> -#include <linux/mm.h> +#include <linux/fs.h> +#include <linux/sched.h> #include <asm/uaccess.h> /* ~832 bytes of stack space used max in sys_select/sys_poll before allocating diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h index 9158a68140c9..cbfa11537421 100644 --- a/include/linux/radix-tree.h +++ b/include/linux/radix-tree.h @@ -19,7 +19,6 @@ #ifndef _LINUX_RADIX_TREE_H #define _LINUX_RADIX_TREE_H -#include <linux/sched.h> #include <linux/preempt.h> #include <linux/types.h> diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 14ec16d2d9ba..a05a5f7c0b73 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -22,12 +22,10 @@ #include <asm/atomic.h> #include <asm/types.h> #include <linux/spinlock.h> -#include <linux/mm.h> -#include <linux/highmem.h> -#include <linux/poll.h> #include <linux/net.h> #include <linux/textsearch.h> #include <net/checksum.h> +#include <linux/rcupdate.h> #include <linux/dmaengine.h> #define HAVE_ALLOC_SKB /* For the drivers to know */ @@ -1295,24 +1293,6 @@ static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len) return __pskb_trim(skb, len); } -static inline void *kmap_skb_frag(const skb_frag_t *frag) -{ -#ifdef CONFIG_HIGHMEM - BUG_ON(in_irq()); - - local_bh_disable(); -#endif - return kmap_atomic(frag->page, KM_SKB_DATA_SOFTIRQ); -} - -static inline void kunmap_skb_frag(void *vaddr) -{ - kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ); -#ifdef CONFIG_HIGHMEM - local_bh_enable(); -#endif -} - #define skb_queue_walk(queue, skb) \ for (skb = (queue)->next; \ prefetch(skb->next), (skb != (struct sk_buff *)(queue)); \ diff --git a/include/linux/zftape.h b/include/linux/zftape.h deleted file mode 100644 index b057c65366c6..000000000000 --- a/include/linux/zftape.h +++ /dev/null @@ -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 diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index cccea051e922..bf16d98d372c 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h @@ -18,6 +18,7 @@ #include <linux/compiler.h> #include <linux/string.h> #include <linux/timer.h> +#include <linux/poll.h> #include <net/inet_sock.h> #include <net/request_sock.h> diff --git a/include/net/irda/timer.h b/include/net/irda/timer.h index 2c5d8864ab77..cb61568547d1 100644 --- a/include/net/irda/timer.h +++ b/include/net/irda/timer.h @@ -28,6 +28,7 @@ #define TIMER_H #include <linux/timer.h> +#include <linux/jiffies.h> #include <asm/param.h> /* for HZ */ diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 032b36a0e378..bd01b4633ee2 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -56,6 +56,7 @@ union nf_conntrack_help { #include <linux/types.h> #include <linux/skbuff.h> +#include <linux/timer.h> #ifdef CONFIG_NETFILTER_DEBUG #define NF_CT_ASSERT(x) \ diff --git a/include/net/netlink.h b/include/net/netlink.h index fd75fd65d59e..bcaf67b7a19d 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -3,6 +3,7 @@ #include <linux/types.h> #include <linux/netlink.h> +#include <linux/jiffies.h> /* ======================================================================== * Netlink Messages and Attributes Interface (As Seen On TV) diff --git a/include/net/sock.h b/include/net/sock.h index 26fc0b16bc0c..fe3a33fad03f 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -47,6 +47,7 @@ #include <linux/lockdep.h> #include <linux/netdevice.h> #include <linux/skbuff.h> /* struct sk_buff */ +#include <linux/mm.h> #include <linux/security.h> #include <linux/filter.h> diff --git a/include/net/udp.h b/include/net/udp.h index 1548d68d45da..1b921fa81474 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -29,6 +29,7 @@ #include <net/ip.h> #include <linux/ipv6.h> #include <linux/seq_file.h> +#include <linux/poll.h> /** * struct udp_skb_cb - UDP(-Lite) private variables diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 61eebec00a7b..ea0816d4904d 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -25,6 +25,8 @@ #include <linux/types.h> #include <linux/mutex.h> +#include <linux/timer.h> +#include <linux/workqueue.h> #include <scsi/iscsi_proto.h> #include <scsi/iscsi_if.h> diff --git a/include/sound/pcm.h b/include/sound/pcm.h index afaf3e88e086..2f645dfd7f70 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -26,6 +26,7 @@ #include <sound/asound.h> #include <sound/memalloc.h> #include <linux/poll.h> +#include <linux/mm.h> #include <linux/bitops.h> #define snd_pcm_substream_chip(substream) ((substream)->private_data) diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 42f2f1179711..ab97e5101232 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -64,6 +64,7 @@ #include <linux/tty.h> #include <linux/selinux.h> #include <linux/binfmts.h> +#include <linux/highmem.h> #include <linux/syscalls.h> #include "audit.h" diff --git a/kernel/latency.c b/kernel/latency.c index 258f2555abbc..e63fcacb61a7 100644 --- a/kernel/latency.c +++ b/kernel/latency.c @@ -36,6 +36,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/notifier.h> +#include <linux/jiffies.h> #include <asm/atomic.h> struct latency_info { diff --git a/kernel/module.c b/kernel/module.c index 45e01cb60101..e2d09d604ca0 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -34,10 +34,10 @@ #include <linux/err.h> #include <linux/vermagic.h> #include <linux/notifier.h> +#include <linux/sched.h> #include <linux/stop_machine.h> #include <linux/device.h> #include <linux/string.h> -#include <linux/sched.h> #include <linux/mutex.h> #include <linux/unwind.h> #include <asm/uaccess.h> @@ -790,6 +790,19 @@ static struct module_attribute refcnt = { .show = show_refcnt, }; +void module_put(struct module *module) +{ + if (module) { + unsigned int cpu = get_cpu(); + local_dec(&module->ref[cpu].count); + /* Maybe they're waiting for us to drop reference? */ + if (unlikely(!module_is_live(module))) + wake_up_process(module->waiter); + put_cpu(); + } +} +EXPORT_SYMBOL(module_put); + #else /* !CONFIG_MODULE_UNLOAD */ static void print_unload_info(struct seq_file *m, struct module *mod) { diff --git a/lib/random32.c b/lib/random32.c index 4a15ce51cea7..ec7f81d3fb18 100644 --- a/lib/random32.c +++ b/lib/random32.c @@ -36,6 +36,7 @@ #include <linux/types.h> #include <linux/percpu.h> #include <linux/module.h> +#include <linux/jiffies.h> #include <linux/random.h> struct rnd_state { diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 485e35c3b28b..3a7052207708 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -61,6 +61,7 @@ #include <net/tcp_states.h> #include <net/route.h> #include <linux/atalk.h> +#include "../core/kmap_skb.h" struct datalink_proto *ddp_dl, *aarp_dl; static const struct proto_ops atalk_dgram_ops; diff --git a/net/core/kmap_skb.h b/net/core/kmap_skb.h new file mode 100644 index 000000000000..283c2b993fb8 --- /dev/null +++ b/net/core/kmap_skb.h @@ -0,0 +1,19 @@ +#include <linux/highmem.h> + +static inline void *kmap_skb_frag(const skb_frag_t *frag) +{ +#ifdef CONFIG_HIGHMEM + BUG_ON(in_irq()); + + local_bh_disable(); +#endif + return kmap_atomic(frag->page, KM_SKB_DATA_SOFTIRQ); +} + +static inline void kunmap_skb_frag(void *vaddr) +{ + kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ); +#ifdef CONFIG_HIGHMEM + local_bh_enable(); +#endif +} diff --git a/net/core/skbuff.c b/net/core/skbuff.c index a90bc439488e..8e1c385e5ba9 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -56,7 +56,6 @@ #include <linux/cache.h> #include <linux/rtnetlink.h> #include <linux/init.h> -#include <linux/highmem.h> #include <net/protocol.h> #include <net/dst.h> @@ -67,6 +66,8 @@ #include <asm/uaccess.h> #include <asm/system.h> +#include "kmap_skb.h" + static kmem_cache_t *skbuff_head_cache __read_mostly; static kmem_cache_t *skbuff_fclone_cache __read_mostly; diff --git a/net/core/sock.c b/net/core/sock.c index ab8fafadb4ba..419c7d3289c7 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -111,6 +111,7 @@ #include <linux/poll.h> #include <linux/tcp.h> #include <linux/init.h> +#include <linux/highmem.h> #include <asm/uaccess.h> #include <asm/system.h> diff --git a/net/dccp/ccids/Kconfig b/net/dccp/ccids/Kconfig index dac89166eb18..80f469887691 100644 --- a/net/dccp/ccids/Kconfig +++ b/net/dccp/ccids/Kconfig @@ -89,4 +89,37 @@ config IP_DCCP_CCID3_DEBUG parameter to 0 or 1. If in doubt, say N. + +config IP_DCCP_CCID3_RTO + int "Use higher bound for nofeedback timer" + default 100 + depends on IP_DCCP_CCID3 && EXPERIMENTAL + ---help--- + Use higher lower bound for nofeedback timer expiration. + + The TFRC nofeedback timer normally expires after the maximum of 4 + RTTs and twice the current send interval (RFC 3448, 4.3). On LANs + with a small RTT this can mean a high processing load and reduced + performance, since then the nofeedback timer is triggered very + frequently. + + This option enables to set a higher lower bound for the nofeedback + value. Values in units of milliseconds can be set here. + + A value of 0 disables this feature by enforcing the value specified + in RFC 3448. The following values have been suggested as bounds for + experimental use: + * 16-20ms to match the typical multimedia inter-frame interval + * 100ms as a reasonable compromise [default] + * 1000ms corresponds to the lower TCP RTO bound (RFC 2988, 2.4) + + The default of 100ms is a compromise between a large value for + efficient DCCP implementations, and a small value to avoid disrupting + the network in times of congestion. + + The purpose of the nofeedback timer is to slow DCCP down when there + is serious network congestion: experimenting with larger values should + therefore not be performed on WANs. + + endmenu diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 70ebe705eb75..cf8c07b2704f 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -121,12 +121,15 @@ static inline void ccid3_update_send_time(struct ccid3_hc_tx_sock *hctx) /* * Update X by * If (p > 0) - * x_calc = calcX(s, R, p); + * X_calc = calcX(s, R, p); * X = max(min(X_calc, 2 * X_recv), s / t_mbi); * Else * If (now - tld >= R) * X = max(min(2 * X, 2 * X_recv), s / R); * tld = now; + * + * If X has changed, we also update the scheduled send time t_now, + * the inter-packet interval t_ipi, and the delta value. */ static void ccid3_hc_tx_update_x(struct sock *sk, struct timeval *now) @@ -134,8 +137,7 @@ static void ccid3_hc_tx_update_x(struct sock *sk, struct timeval *now) struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); const __u32 old_x = hctx->ccid3hctx_x; - /* To avoid large error in calcX */ - if (hctx->ccid3hctx_p >= TFRC_SMALLEST_P) { + if (hctx->ccid3hctx_p > 0) { hctx->ccid3hctx_x_calc = tfrc_calc_x(hctx->ccid3hctx_s, hctx->ccid3hctx_rtt, hctx->ccid3hctx_p); @@ -223,16 +225,14 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data) ccid3_tx_state_name(hctx->ccid3hctx_state)); /* Halve sending rate */ - /* If (X_calc > 2 * X_recv) + /* If (p == 0 || X_calc > 2 * X_recv) * X_recv = max(X_recv / 2, s / (2 * t_mbi)); * Else * X_recv = X_calc / 4; */ - BUG_ON(hctx->ccid3hctx_p >= TFRC_SMALLEST_P && - hctx->ccid3hctx_x_calc == 0); + BUG_ON(hctx->ccid3hctx_p && !hctx->ccid3hctx_x_calc); - /* check also if p is zero -> x_calc is infinity? */ - if (hctx->ccid3hctx_p < TFRC_SMALLEST_P || + if (hctx->ccid3hctx_p == 0 || hctx->ccid3hctx_x_calc > 2 * hctx->ccid3hctx_x_recv) hctx->ccid3hctx_x_recv = max_t(u32, hctx->ccid3hctx_x_recv / 2, hctx->ccid3hctx_s / (2 * TFRC_T_MBI)); @@ -245,9 +245,10 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data) } /* * Schedule no feedback timer to expire in - * max(4 * R, 2 * s/X) = max(4 * R, 2 * t_ipi) + * max(t_RTO, 2 * s/X) = max(t_RTO, 2 * t_ipi) + * See comments in packet_recv() regarding the value of t_RTO. */ - t_nfb = max(4 * hctx->ccid3hctx_rtt, 2 * hctx->ccid3hctx_t_ipi); + t_nfb = max(hctx->ccid3hctx_t_rto, 2 * hctx->ccid3hctx_t_ipi); break; case TFRC_SSTATE_NO_SENT: DCCP_BUG("Illegal %s state NO_SENT, sk=%p", dccp_role(sk), sk); @@ -338,7 +339,7 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) * else * // send the packet in (t_nom - t_now) milliseconds. */ - if (delay >= hctx->ccid3hctx_delta) + if (delay - (long)hctx->ccid3hctx_delta >= 0) return delay / 1000L; break; case TFRC_SSTATE_TERM: @@ -412,10 +413,8 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) struct dccp_tx_hist_entry *packet; struct timeval now; unsigned long t_nfb; - u32 t_elapsed; u32 pinv; - u32 x_recv; - u32 r_sample; + long r_sample, t_elapsed; BUG_ON(hctx == NULL); @@ -426,31 +425,44 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) opt_recv = &hctx->ccid3hctx_options_received; - t_elapsed = dp->dccps_options_received.dccpor_elapsed_time * 10; - x_recv = opt_recv->ccid3or_receive_rate; - pinv = opt_recv->ccid3or_loss_event_rate; - switch (hctx->ccid3hctx_state) { case TFRC_SSTATE_NO_FBACK: case TFRC_SSTATE_FBACK: - /* Calculate new round trip sample by - * R_sample = (now - t_recvdata) - t_delay */ - /* get t_recvdata from history */ + /* get packet from history to look up t_recvdata */ packet = dccp_tx_hist_find_entry(&hctx->ccid3hctx_hist, DCCP_SKB_CB(skb)->dccpd_ack_seq); if (unlikely(packet == NULL)) { - DCCP_WARN("%s, sk=%p, seqno %llu(%s) does't exist " + DCCP_WARN("%s(%p), seqno %llu(%s) doesn't exist " "in history!\n", dccp_role(sk), sk, (unsigned long long)DCCP_SKB_CB(skb)->dccpd_ack_seq, dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type)); return; } - /* Update RTT */ + /* Update receive rate */ + hctx->ccid3hctx_x_recv = opt_recv->ccid3or_receive_rate; + + /* Update loss event rate */ + pinv = opt_recv->ccid3or_loss_event_rate; + if (pinv == ~0U || pinv == 0) + hctx->ccid3hctx_p = 0; + else + hctx->ccid3hctx_p = 1000000 / pinv; + dccp_timestamp(sk, &now); - r_sample = timeval_delta(&now, &packet->dccphtx_tstamp); - if (unlikely(r_sample <= t_elapsed)) - DCCP_WARN("r_sample=%uus,t_elapsed=%uus\n", + + /* + * Calculate new round trip sample as per [RFC 3448, 4.3] by + * R_sample = (now - t_recvdata) - t_elapsed + */ + r_sample = timeval_delta(&now, &packet->dccphtx_tstamp); + t_elapsed = dp->dccps_options_received.dccpor_elapsed_time * 10; + + if (unlikely(r_sample <= 0)) { + DCCP_WARN("WARNING: R_sample (%ld) <= 0!\n", r_sample); + r_sample = 0; + } else if (unlikely(r_sample <= t_elapsed)) + DCCP_WARN("WARNING: r_sample=%ldus <= t_elapsed=%ldus\n", r_sample, t_elapsed); else r_sample -= t_elapsed; @@ -473,31 +485,25 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) hctx->ccid3hctx_t_ld = now; ccid3_update_send_time(hctx); - ccid3_hc_tx_set_state(sk, TFRC_SSTATE_FBACK); - } else { - hctx->ccid3hctx_rtt = (hctx->ccid3hctx_rtt * 9) / 10 + - r_sample / 10; - ccid3_hc_tx_update_x(sk, &now); - } - ccid3_pr_debug("%s, sk=%p, New RTT estimate=%uus, " - "r_sample=%us\n", dccp_role(sk), sk, - hctx->ccid3hctx_rtt, r_sample); + ccid3_pr_debug("%s(%p), s=%u, w_init=%u, " + "R_sample=%ldus, X=%u\n", dccp_role(sk), + sk, hctx->ccid3hctx_s, w_init, r_sample, + hctx->ccid3hctx_x); - /* Update receive rate */ - hctx->ccid3hctx_x_recv = x_recv;/* X_recv in bytes per sec */ + ccid3_hc_tx_set_state(sk, TFRC_SSTATE_FBACK); + } else { + hctx->ccid3hctx_rtt = (9 * hctx->ccid3hctx_rtt + + (u32)r_sample ) / 10; - /* Update loss event rate */ - if (pinv == ~0 || pinv == 0) - hctx->ccid3hctx_p = 0; - else { - hctx->ccid3hctx_p = 1000000 / pinv; + ccid3_hc_tx_update_x(sk, &now); - if (hctx->ccid3hctx_p < TFRC_SMALLEST_P) { - hctx->ccid3hctx_p = TFRC_SMALLEST_P; - ccid3_pr_debug("%s, sk=%p, Smallest p used!\n", - dccp_role(sk), sk); - } + ccid3_pr_debug("%s(%p), RTT=%uus (sample=%ldus), s=%u, " + "p=%u, X_calc=%u, X=%u\n", dccp_role(sk), + sk, hctx->ccid3hctx_rtt, r_sample, + hctx->ccid3hctx_s, hctx->ccid3hctx_p, + hctx->ccid3hctx_x_calc, + hctx->ccid3hctx_x); } /* unschedule no feedback timer */ @@ -512,16 +518,20 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) */ sk->sk_write_space(sk); - /* Update timeout interval. We use the alternative variant of - * [RFC 3448, 3.1] which sets the upper bound of t_rto to one - * second, as it is suggested for TCP (see RFC 2988, 2.4). */ + /* + * Update timeout interval for the nofeedback timer. + * We use a configuration option to increase the lower bound. + * This can help avoid triggering the nofeedback timer too often + * ('spinning') on LANs with small RTTs. + */ hctx->ccid3hctx_t_rto = max_t(u32, 4 * hctx->ccid3hctx_rtt, - USEC_PER_SEC ); + CONFIG_IP_DCCP_CCID3_RTO * + (USEC_PER_SEC/1000) ); /* * Schedule no feedback timer to expire in - * max(4 * R, 2 * s/X) = max(4 * R, 2 * t_ipi) + * max(t_RTO, 2 * s/X) = max(t_RTO, 2 * t_ipi) */ - t_nfb = max(4 * hctx->ccid3hctx_rtt, 2 * hctx->ccid3hctx_t_ipi); + t_nfb = max(hctx->ccid3hctx_t_rto, 2 * hctx->ccid3hctx_t_ipi); ccid3_pr_debug("%s, sk=%p, Scheduled no feedback timer to " "expire in %lu jiffies (%luus)\n", @@ -535,7 +545,8 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) hctx->ccid3hctx_idle = 1; break; case TFRC_SSTATE_NO_SENT: - DCCP_WARN("Illegal ACK received - no packet has been sent\n"); + if (dccp_sk(sk)->dccps_role == DCCP_ROLE_CLIENT) + DCCP_WARN("Illegal ACK received - no packet sent\n"); /* fall through */ case TFRC_SSTATE_TERM: /* ignore feedback when closing */ break; diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h index 27cb20ae1da8..07596d704ef9 100644 --- a/net/dccp/ccids/ccid3.h +++ b/net/dccp/ccids/ccid3.h @@ -51,8 +51,6 @@ /* Parameter t_mbi from [RFC 3448, 4.3]: backoff interval in seconds */ #define TFRC_T_MBI 64 -#define TFRC_SMALLEST_P 40 - enum ccid3_options { TFRC_OPT_LOSS_EVENT_RATE = 192, TFRC_OPT_LOSS_INTERVALS = 193, diff --git a/net/dccp/ccids/lib/tfrc_equation.c b/net/dccp/ccids/lib/tfrc_equation.c index 2601012383fb..ddac2c511e2f 100644 --- a/net/dccp/ccids/lib/tfrc_equation.c +++ b/net/dccp/ccids/lib/tfrc_equation.c @@ -18,10 +18,79 @@ #include "tfrc.h" #define TFRC_CALC_X_ARRSIZE 500 +#define TFRC_CALC_X_SPLIT 50000 /* 0.05 * 1000000, details below */ +#define TFRC_SMALLEST_P (TFRC_CALC_X_SPLIT/TFRC_CALC_X_ARRSIZE) -#define TFRC_CALC_X_SPLIT 50000 -/* equivalent to 0.05 */ - +/* + TFRC TCP Reno Throughput Equation Lookup Table for f(p) + + The following two-column lookup table implements a part of the TCP throughput + equation from [RFC 3448, sec. 3.1]: + + s + X_calc = -------------------------------------------------------------- + R * sqrt(2*b*p/3) + (3 * t_RTO * sqrt(3*b*p/8) * (p + 32*p^3)) + + Where: + X is the transmit rate in bytes/second + s is the packet size in bytes + R is the round trip time in seconds + p is the loss event rate, between 0 and 1.0, of the number of loss + events as a fraction of the number of packets transmitted + t_RTO is the TCP retransmission timeout value in seconds + b is the number of packets acknowledged by a single TCP ACK + + We can assume that b = 1 and t_RTO is 4 * R. The equation now becomes: + + s + X_calc = ------------------------------------------------------- + R * sqrt(p*2/3) + (12 * R * sqrt(p*3/8) * (p + 32*p^3)) + + which we can break down into: + + s + X_calc = --------- + R * f(p) + + where f(p) is given for 0 < p <= 1 by: + + f(p) = sqrt(2*p/3) + 12 * sqrt(3*p/8) * (p + 32*p^3) + + Since this is kernel code, floating-point arithmetic is avoided in favour of + integer arithmetic. This means that nearly all fractional parameters are + scaled by 1000000: + * the parameters p and R + * the return result f(p) + The lookup table therefore actually tabulates the following function g(q): + + g(q) = 1000000 * f(q/1000000) + + Hence, when p <= 1, q must be less than or equal to 1000000. To achieve finer + granularity for the practically more relevant case of small values of p (up to + 5%), the second column is used; the first one ranges up to 100%. This split + corresponds to the value of q = TFRC_CALC_X_SPLIT. At the same time this also + determines the smallest resolution possible with this lookup table: + + TFRC_SMALLEST_P = TFRC_CALC_X_SPLIT / TFRC_CALC_X_ARRSIZE + + The entire table is generated by: + for(i=0; i < TFRC_CALC_X_ARRSIZE; i++) { + lookup[i][0] = g((i+1) * 1000000/TFRC_CALC_X_ARRSIZE); + lookup[i][1] = g((i+1) * TFRC_CALC_X_SPLIT/TFRC_CALC_X_ARRSIZE); + } + + With the given configuration, we have, with M = TFRC_CALC_X_ARRSIZE-1, + lookup[0][0] = g(1000000/(M+1)) = 1000000 * f(0.2%) + lookup[M][0] = g(1000000) = 1000000 * f(100%) + lookup[0][1] = g(TFRC_SMALLEST_P) = 1000000 * f(0.01%) + lookup[M][1] = g(TFRC_CALC_X_SPLIT) = 1000000 * f(5%) + + In summary, the two columns represent f(p) for the following ranges: + * The first column is for 0.002 <= p <= 1.0 + * The second column is for 0.0001 <= p <= 0.05 + Where the columns overlap, the second (finer-grained) is given preference, + i.e. the first column is used only for p >= 0.05. + */ static const u32 tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE][2] = { { 37172, 8172 }, { 53499, 11567 }, @@ -525,85 +594,69 @@ static const u32 tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE][2] = { { 243315981, 271305 } }; -/* Calculate the send rate as per section 3.1 of RFC3448 - -Returns send rate in bytes per second - -Integer maths and lookups are used as not allowed floating point in kernel - -The function for Xcalc as per section 3.1 of RFC3448 is: - -X = s - ------------------------------------------------------------- - R*sqrt(2*b*p/3) + (t_RTO * (3*sqrt(3*b*p/8) * p * (1+32*p^2))) - -where -X is the trasmit rate in bytes/second -s is the packet size in bytes -R is the round trip time in seconds -p is the loss event rate, between 0 and 1.0, of the number of loss events - as a fraction of the number of packets transmitted -t_RTO is the TCP retransmission timeout value in seconds -b is the number of packets acknowledged by a single TCP acknowledgement - -we can assume that b = 1 and t_RTO is 4 * R. With this the equation becomes: - -X = s - ----------------------------------------------------------------------- - R * sqrt(2 * p / 3) + (12 * R * (sqrt(3 * p / 8) * p * (1 + 32 * p^2))) - - -which we can break down into: - -X = s - -------- - R * f(p) - -where f(p) = sqrt(2 * p / 3) + (12 * sqrt(3 * p / 8) * p * (1 + 32 * p * p)) - -Function parameters: -s - bytes -R - RTT in usecs -p - loss rate (decimal fraction multiplied by 1,000,000) - -Returns Xcalc in bytes per second - -DON'T alter this code unless you run test cases against it as the code -has been manipulated to stop underflow/overlow. +/* return largest index i such that fval <= lookup[i][small] */ +static inline u32 tfrc_binsearch(u32 fval, u8 small) +{ + u32 try, low = 0, high = TFRC_CALC_X_ARRSIZE - 1; + + while (low < high) { + try = (low + high) / 2; + if (fval <= tfrc_calc_x_lookup[try][small]) + high = try; + else + low = try + 1; + } + return high; +} -*/ +/** + * tfrc_calc_x - Calculate the send rate as per section 3.1 of RFC3448 + * + * @s: packet size in bytes + * @R: RTT scaled by 1000000 (i.e., microseconds) + * @p: loss ratio estimate scaled by 1000000 + * Returns X_calc in bytes per second (not scaled). + * + * Note: DO NOT alter this code unless you run test cases against it, + * as the code has been optimized to stop underflow/overflow. + */ u32 tfrc_calc_x(u16 s, u32 R, u32 p) { int index; u32 f; u64 tmp1, tmp2; - if (p < TFRC_CALC_X_SPLIT) - index = (p / (TFRC_CALC_X_SPLIT / TFRC_CALC_X_ARRSIZE)) - 1; - else - index = (p / (1000000 / TFRC_CALC_X_ARRSIZE)) - 1; + /* check against invalid parameters and divide-by-zero */ + BUG_ON(p > 1000000); /* p must not exceed 100% */ + BUG_ON(p == 0); /* f(0) = 0, divide by zero */ + if (R == 0) { /* possible divide by zero */ + DCCP_CRIT("WARNING: RTT is 0, returning maximum X_calc."); + return ~0U; + } - if (index < 0) - /* p should be 0 unless there is a bug in my code */ - index = 0; + if (p <= TFRC_CALC_X_SPLIT) { /* 0.0000 < p <= 0.05 */ + if (p < TFRC_SMALLEST_P) { /* 0.0000 < p < 0.0001 */ + DCCP_WARN("Value of p (%d) below resolution. " + "Substituting %d\n", p, TFRC_SMALLEST_P); + index = 0; + } else /* 0.0001 <= p <= 0.05 */ + index = p/TFRC_SMALLEST_P - 1; - if (R == 0) { - DCCP_WARN("RTT==0, setting to 1\n"); - R = 1; /* RTT can't be zero or else divide by zero */ - } + f = tfrc_calc_x_lookup[index][1]; - BUG_ON(index >= TFRC_CALC_X_ARRSIZE); + } else { /* 0.05 < p <= 1.00 */ + index = p/(1000000/TFRC_CALC_X_ARRSIZE) - 1; - if (p >= TFRC_CALC_X_SPLIT) f = tfrc_calc_x_lookup[index][0]; - else - f = tfrc_calc_x_lookup[index][1]; + } + /* The following computes X = s/(R*f(p)) in bytes per second. Since f(p) + * and R are both scaled by 1000000, we need to multiply by 1000000^2. + * ==> DO NOT alter this unless you test against overflow on 32 bit */ tmp1 = ((u64)s * 100000000); tmp2 = ((u64)R * (u64)f); do_div(tmp2, 10000); do_div(tmp1, tmp2); - /* Don't alter above math unless you test due to overflow on 32 bit */ return (u32)tmp1; } @@ -611,33 +664,36 @@ u32 tfrc_calc_x(u16 s, u32 R, u32 p) EXPORT_SYMBOL_GPL(tfrc_calc_x); /* - * args: fvalue - function value to match - * returns: p closest to that value + * tfrc_calc_x_reverse_lookup - try to find p given f(p) * - * both fvalue and p are multiplied by 1,000,000 to use ints + * @fvalue: function value to match, scaled by 1000000 + * Returns closest match for p, also scaled by 1000000 */ u32 tfrc_calc_x_reverse_lookup(u32 fvalue) { - int ctr = 0; - int small; + int index; - if (fvalue < tfrc_calc_x_lookup[0][1]) + if (fvalue == 0) /* f(p) = 0 whenever p = 0 */ return 0; - if (fvalue <= tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE - 1][1]) - small = 1; - else if (fvalue > tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE - 1][0]) + /* Error cases. */ + if (fvalue < tfrc_calc_x_lookup[0][1]) { + DCCP_WARN("fvalue %d smaller than resolution\n", fvalue); + return tfrc_calc_x_lookup[0][1]; + } + if (fvalue > tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE - 1][0]) { + DCCP_WARN("fvalue %d exceeds bounds!\n", fvalue); return 1000000; - else - small = 0; - - while (fvalue > tfrc_calc_x_lookup[ctr][small]) - ctr++; + } - if (small) - return TFRC_CALC_X_SPLIT * ctr / TFRC_CALC_X_ARRSIZE; - else - return 1000000 * ctr / TFRC_CALC_X_ARRSIZE; + if (fvalue <= tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE - 1][1]) { + index = tfrc_binsearch(fvalue, 1); + return (index + 1) * TFRC_CALC_X_SPLIT / TFRC_CALC_X_ARRSIZE; + } + + /* else ... it must be in the coarse-grained column */ + index = tfrc_binsearch(fvalue, 0); + return (index + 1) * 1000000 / TFRC_CALC_X_ARRSIZE; } EXPORT_SYMBOL_GPL(tfrc_calc_x_reverse_lookup); diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index 4200ec509866..fc1f99a59732 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c @@ -16,6 +16,7 @@ #include <linux/random.h> #include <linux/skbuff.h> #include <linux/netdevice.h> +#include <linux/mm.h> #include <linux/if_ether.h> #include <linux/if_arp.h> #include <asm/string.h> diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/ieee80211/ieee80211_crypt_wep.c index 1b2efff11d39..7a95c3d81314 100644 --- a/net/ieee80211/ieee80211_crypt_wep.c +++ b/net/ieee80211/ieee80211_crypt_wep.c @@ -15,6 +15,7 @@ #include <linux/slab.h> #include <linux/random.h> #include <linux/skbuff.h> +#include <linux/mm.h> #include <asm/string.h> #include <net/ieee80211.h> diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 1da3d32f8289..a35209d517ad 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -53,6 +53,7 @@ #include <linux/mm.h> #include <linux/string.h> #include <linux/errno.h> +#include <linux/highmem.h> #include <linux/socket.h> #include <linux/sockios.h> diff --git a/net/ipv4/ipvs/ip_vs_lblc.c b/net/ipv4/ipvs/ip_vs_lblc.c index 524751e031de..a4385a2180ee 100644 --- a/net/ipv4/ipvs/ip_vs_lblc.c +++ b/net/ipv4/ipvs/ip_vs_lblc.c @@ -45,6 +45,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/skbuff.h> +#include <linux/jiffies.h> /* for sysctl */ #include <linux/fs.h> diff --git a/net/ipv4/ipvs/ip_vs_lblcr.c b/net/ipv4/ipvs/ip_vs_lblcr.c index 08990192b6ec..fe1af5d079af 100644 --- a/net/ipv4/ipvs/ip_vs_lblcr.c +++ b/net/ipv4/ipvs/ip_vs_lblcr.c @@ -43,6 +43,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/skbuff.h> +#include <linux/jiffies.h> /* for sysctl */ #include <linux/fs.h> diff --git a/net/irda/discovery.c b/net/irda/discovery.c index 3fefc822c1c0..89fd2a2cbca6 100644 --- a/net/irda/discovery.c +++ b/net/irda/discovery.c @@ -32,6 +32,7 @@ #include <linux/string.h> #include <linux/socket.h> +#include <linux/fs.h> #include <linux/seq_file.h> #include <net/irda/irda.h> diff --git a/net/irda/iriap.c b/net/irda/iriap.c index 8cfd076c4c12..8f1c6d65b247 100644 --- a/net/irda/iriap.c +++ b/net/irda/iriap.c @@ -27,6 +27,7 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/skbuff.h> +#include <linux/fs.h> #include <linux/string.h> #include <linux/init.h> #include <linux/seq_file.h> diff --git a/net/irda/irttp.c b/net/irda/irttp.c index 9c446a72ff1f..252f11012566 100644 --- a/net/irda/irttp.c +++ b/net/irda/irttp.c @@ -26,6 +26,7 @@ #include <linux/skbuff.h> #include <linux/init.h> +#include <linux/fs.h> #include <linux/seq_file.h> #include <asm/byteorder.h> diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 93d97d9f9da8..eaa0f8a1adb6 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -46,6 +46,7 @@ #include <linux/kernel.h> #include <linux/netdevice.h> #include <linux/socket.h> +#include <linux/mm.h> #include <net/netfilter/nf_conntrack.h> #include <net/netfilter/nf_conntrack_l3proto.h> diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 58522fc65d33..8996584b8499 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -21,6 +21,7 @@ #include <linux/string.h> #include <linux/vmalloc.h> #include <linux/mutex.h> +#include <linux/mm.h> #include <linux/netfilter/x_tables.h> #include <linux/netfilter_arp.h> diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index 501c564e247f..a98de0b54d65 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -17,6 +17,7 @@ #include <linux/seq_file.h> #include <linux/list.h> #include <linux/skbuff.h> +#include <linux/mm.h> #include <linux/in.h> #include <linux/ip.h> #include <linux/ipv6.h> diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 271d2eed0699..08e68b67bbf6 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -71,6 +71,7 @@ #include <asm/uaccess.h> #include <asm/ioctls.h> #include <asm/page.h> +#include <asm/cacheflush.h> #include <asm/io.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 6f97665983d2..311205ffa775 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -858,7 +858,6 @@ static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, int i; xp->xfrm_nr = nr; - xp->family = ut->family; for (i = 0; i < nr; i++, ut++) { struct xfrm_tmpl *t = &xp->xfrm_vec[i]; @@ -876,19 +875,53 @@ static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, } } +static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family) +{ + int i; + + if (nr > XFRM_MAX_DEPTH) + return -EINVAL; + + for (i = 0; i < nr; i++) { + /* We never validated the ut->family value, so many + * applications simply leave it at zero. The check was + * never made and ut->family was ignored because all + * templates could be assumed to have the same family as + * the policy itself. Now that we will have ipv4-in-ipv6 + * and ipv6-in-ipv4 tunnels, this is no longer true. + */ + if (!ut[i].family) + ut[i].family = family; + + switch (ut[i].family) { + case AF_INET: + break; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case AF_INET6: + break; +#endif + default: + return -EINVAL; + }; + } + + return 0; +} + static int copy_from_user_tmpl(struct xfrm_policy *pol, struct rtattr **xfrma) { struct rtattr *rt = xfrma[XFRMA_TMPL-1]; - struct xfrm_user_tmpl *utmpl; - int nr; if (!rt) { pol->xfrm_nr = 0; } else { - nr = (rt->rta_len - sizeof(*rt)) / sizeof(*utmpl); + struct xfrm_user_tmpl *utmpl = RTA_DATA(rt); + int nr = (rt->rta_len - sizeof(*rt)) / sizeof(*utmpl); + int err; - if (nr > XFRM_MAX_DEPTH) - return -EINVAL; + err = validate_tmpl(nr, utmpl, pol->family); + if (err) + return err; copy_templates(pol, RTA_DATA(rt), nr); } @@ -1530,7 +1563,8 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xf } /* build an XP */ - xp = xfrm_policy_construct(&ua->policy, (struct rtattr **) xfrma, &err); if (!xp) { + xp = xfrm_policy_construct(&ua->policy, (struct rtattr **) xfrma, &err); + if (!xp) { kfree(x); return err; } @@ -1979,7 +2013,7 @@ static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt, return NULL; nr = ((len - sizeof(*p)) / sizeof(*ut)); - if (nr > XFRM_MAX_DEPTH) + if (validate_tmpl(nr, ut, p->sel.family)) return NULL; if (p->dir > XFRM_POLICY_OUT) diff --git a/sound/oss/cs46xx.c b/sound/oss/cs46xx.c index b1c5d8286e40..147c8a951137 100644 --- a/sound/oss/cs46xx.c +++ b/sound/oss/cs46xx.c @@ -91,6 +91,7 @@ #include <linux/poll.h> #include <linux/ac97_codec.h> #include <linux/mutex.h> +#include <linux/mm.h> #include <asm/io.h> #include <asm/dma.h> diff --git a/sound/oss/dmabuf.c b/sound/oss/dmabuf.c index b256c0401161..eaf69971bf92 100644 --- a/sound/oss/dmabuf.c +++ b/sound/oss/dmabuf.c @@ -25,6 +25,7 @@ #define BE_CONSERVATIVE #define SAMPLE_ROUNDUP 0 +#include <linux/mm.h> #include "sound_config.h" #define DMAP_FREE_ON_CLOSE 0 diff --git a/sound/oss/emu10k1/audio.c b/sound/oss/emu10k1/audio.c index cde4d59d5430..86dd23974e05 100644 --- a/sound/oss/emu10k1/audio.c +++ b/sound/oss/emu10k1/audio.c @@ -36,6 +36,7 @@ #include <linux/bitops.h> #include <asm/io.h> #include <linux/sched.h> +#include <linux/mm.h> #include <linux/smp_lock.h> #include "hwaccess.h" diff --git a/sound/oss/es1371.c b/sound/oss/es1371.c index ddf6b0a0bca5..cc282a0cd539 100644 --- a/sound/oss/es1371.c +++ b/sound/oss/es1371.c @@ -130,6 +130,7 @@ #include <linux/wait.h> #include <linux/dma-mapping.h> #include <linux/mutex.h> +#include <linux/mm.h> #include <asm/io.h> #include <asm/page.h> diff --git a/sound/oss/i810_audio.c b/sound/oss/i810_audio.c index 240cc7939b69..c3c8a720d555 100644 --- a/sound/oss/i810_audio.c +++ b/sound/oss/i810_audio.c @@ -101,6 +101,7 @@ #include <linux/ac97_codec.h> #include <linux/bitops.h> #include <linux/mutex.h> +#include <linux/mm.h> #include <asm/uaccess.h> diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c index 75c5e745705f..8fb8e7f99556 100644 --- a/sound/oss/soundcard.c +++ b/sound/oss/soundcard.c @@ -42,6 +42,7 @@ #include <linux/proc_fs.h> #include <linux/smp_lock.h> #include <linux/module.h> +#include <linux/mm.h> /* * This ought to be moved into include/asm/dma.h diff --git a/sound/oss/sscape.c b/sound/oss/sscape.c index 51f2fa615413..30c36d1f35d7 100644 --- a/sound/oss/sscape.c +++ b/sound/oss/sscape.c @@ -39,6 +39,7 @@ #include <linux/ioport.h> #include <linux/delay.h> #include <linux/proc_fs.h> +#include <linux/mm.h> #include <linux/spinlock.h> #include "coproc.h" diff --git a/sound/oss/trident.c b/sound/oss/trident.c index 7a363a178afd..6b1f8c9cdcf8 100644 --- a/sound/oss/trident.c +++ b/sound/oss/trident.c @@ -216,6 +216,7 @@ #include <linux/gameport.h> #include <linux/kernel.h> #include <linux/mutex.h> +#include <linux/mm.h> #include <asm/uaccess.h> #include <asm/io.h> |