]> git.neil.brown.name Git - history.git/commitdiff
Import 1.3.98 1.3.98
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:56 +0000 (15:10 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:56 +0000 (15:10 -0500)
115 files changed:
Documentation/Configure.help
Documentation/locks.txt [new file with mode: 0644]
Documentation/networking/ncsa-telnet [new file with mode: 0644]
Documentation/oops-tracing.txt [new file with mode: 0644]
Documentation/ramdisk.txt
Documentation/rtc.txt
MAINTAINERS
Makefile
arch/alpha/config.in
arch/alpha/defconfig
arch/alpha/kernel/ptrace.c
arch/i386/config.in
arch/i386/defconfig
arch/i386/kernel/ptrace.c
arch/i386/kernel/time.c
arch/sparc/kernel/ptrace.c
drivers/block/README.fd
drivers/block/README.ide
drivers/block/cmd640.c
drivers/block/dtc2278.c
drivers/block/floppy.c
drivers/block/ide-cd.c
drivers/block/ide-tape.c
drivers/block/ide-tape.h
drivers/block/ide.c
drivers/block/ide.h
drivers/block/qd6580.c
drivers/cdrom/aztcd.c
drivers/char/ChangeLog
drivers/char/Config.in
drivers/char/apm_bios.c
drivers/char/lp.c
drivers/char/random.c
drivers/char/rtc.c
drivers/char/serial.c
drivers/net/Config.in
drivers/net/new_tunnel.c
drivers/sbus/char/sunkbd.c
drivers/sbus/char/sunserial.c
drivers/scsi/53c7,8xx.h
drivers/scsi/AM53C974.h
drivers/scsi/README.st
drivers/scsi/aha152x.c
drivers/scsi/aha152x.h
drivers/scsi/aic7xxx.c
drivers/scsi/eata.h
drivers/scsi/eata_dma.c
drivers/scsi/eata_dma.h
drivers/scsi/eata_generic.h
drivers/scsi/eata_pio.c
drivers/scsi/eata_pio.h
drivers/scsi/fdomain.c
drivers/scsi/in2000.c
drivers/scsi/in2000.readme
drivers/scsi/scsi.c
drivers/scsi/scsi.h
drivers/scsi/scsi_ioctl.c
drivers/scsi/scsi_ioctl.h [deleted file]
drivers/scsi/scsi_syms.c
drivers/scsi/sd.c
drivers/scsi/sd_ioctl.c
drivers/scsi/seagate.c
drivers/scsi/sg.c
drivers/scsi/sg.h [deleted file]
drivers/scsi/sr.c
drivers/scsi/sr_ioctl.c
drivers/scsi/st.c
drivers/scsi/st.h
drivers/scsi/wd33c93.c
fs/Config.in
fs/buffer.c
fs/ext2/ialloc.c
fs/ext2/inode.c
fs/ext2/super.c
fs/fcntl.c
fs/locks.c
fs/nfs/nfsroot.c
fs/pipe.c
fs/proc/array.c
fs/proc/mem.c
fs/proc/root.c
include/asm-alpha/fcntl.h
include/asm-i386/checksum.h
include/asm-i386/fcntl.h
include/asm-m68k/fcntl.h
include/asm-mips/fcntl.h
include/asm-ppc/fcntl.h
include/asm-sparc/fcntl.h
include/linux/apm_bios.h
include/linux/bios32.h
include/linux/ext2_fs.h
include/linux/ext2_fs_i.h
include/linux/ext2_fs_sb.h
include/linux/kernel.h
include/linux/mtio.h
include/linux/proc_fs.h
include/linux/random.h
include/linux/scsi.h [deleted file]
include/linux/scsicam.h [deleted file]
include/linux/timex.h
include/net/route.h
include/scsi/scsi.h [new file with mode: 0644]
include/scsi/scsi_ioctl.h [new file with mode: 0644]
include/scsi/scsicam.h [new file with mode: 0644]
include/scsi/sg.h [new file with mode: 0644]
kernel/sys.c
mm/filemap.c
net/Config.in
net/ax25/ax25_out.c
net/ax25/ax25_route.c
net/core/dev.c
net/ipv4/Config.in
net/ipv4/af_inet.c
net/ipv4/ip_sockglue.c
scripts/Menuconfig

index 9dce6c1811ebb7f387e19486abb7ea6b2a1819fc..a984a50baebb8c4ea1c3f2b23e98f2aa09b7583c 100644 (file)
 # in your own kernel configuration tools. The texts are copyrighted
 # (c) 1995,1996 by Axel Boldt and governed by the GNU Public License.
 
+Prompt for development and/or incomplete code/drivers
+CONFIG_EXPERIMENTAL
+  Some of the various things that Linux supports (such as network 
+  drivers, filesystems, network protocols, etc.) can be in a state 
+  of development where the functionality, stability, or the level of 
+  testing is not yet high enough for general use. This is usually
+  known as the "alpha-test" phase amongst developers. If a feature is
+  currently in alpha-test, then the developers usually discourage 
+  widespread use of this feature by the general public to avoid 
+  "Why doesn't this work?" type mail messages. However, active testing
+  and and detailed bug reports from people familiar with the kernel's
+  internals are usually welcomed by the developers. Unless you intend
+  to help test and develop a feature or driver that falls into this 
+  category, you should probably say N here, which will cause this 
+  configure script to present you with less choices. If you say Y here,
+  you will be offered the choice of using features or drivers that are
+  currently considered to be in the alpha-test phase.
+
 Kernel math emulation
 CONFIG_MATH_EMULATION
   Linux can emulate a math coprocessor (used for floating point
@@ -990,10 +1008,12 @@ CONFIG_ATALK
   say Y. You will need to use the netatalk package so that your Linux
   box can act as a print and file server for macs as well as access
   appletalk printers. Check out
-  http://www.cs.dartmouth.edu/~flowerpt/projects/linux-netatalk/ on
-  the WWW for details (to browse the WWW, you need to have access to a
+  http://artoo.hitchcock.org/~flowerpt/projects/linux-netatalk/ on the
+  WWW for details (to browse the WWW, you need to have access to a
   machine on the Internet that has one of the programs lynx, netscape
-  or Mosaic). This driver is also available as a module ( = code which
+  or Mosaic). The NET-2-HOWTO, available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO contains valuable information
+  as well. This driver is also available as a module ( = code which
   can be inserted in and removed from the running kernel whenever you
   want). If you want to compile it as a module, say M here and read
   Documentation/modules.txt. I hear that the GNU boycott of Apple is
@@ -1052,7 +1072,7 @@ CONFIG_BPQETHER
   useful if some other computer on your local network has a direct
   amateur radio connection.
 
-Bridging (test)
+Bridging (EXPERIMENTAL)
 CONFIG_BRIDGE
   If you enable this, your Linux box will be able to act as an
   ethernet bridge, which means that the different ethernet segments it
@@ -1065,9 +1085,7 @@ CONFIG_BRIDGE
   the Multiple-Ethernet-mini-HOWTO, available via ftp (user:
   anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. The
   Bridging code is still in test. If unsure, say N.
-###
-### How to use?
-###
+  The bridge configuration tools are available via ftp from shadow.cabi.net.
 
 Kernel/User network link driver(ALPHA)
 CONFIG_NETLINK
@@ -1561,6 +1579,12 @@ CONFIG_SLIP_SMART
   RELCOM line fill and keepalive monitoring. Ideal on poor quality
   analogue lines.
 
+Radio network interfaces
+CONFIG_NET_RADIO
+  Radio based interfaces for Linux. Both amateur radio (AX.25) and other
+  systems. In addition shadow.cabi.net carries user mode drivers for the
+  Scarab devices. These need no kernel support.
+
 PPP (point-to-point) support
 CONFIG_PPP
   PPP (Point to Point Protocol) is a newer and better SLIP. It serves
@@ -1641,9 +1665,11 @@ CONFIG_PLIP
   time (you can find the wiring of these cables in
   drivers/net/README?.plip). The cables can be up to 15m long. This
   works also if one of the machines runs DOS and has some PLIP
-  software installed, e.g. NCSA telnet.  If you want to use this, say
-  Y and read the PLIP mini-HOWTO, available via ftp (user: anonymous)
-  in sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini as well as the
+  software installed, e.g. the Crynwr PLIP packet driver
+  (http://sunsite.cnam.fr/packages/Telnet/PC/msdos/misc/pktdrvr.txt)
+  and NCSA's telnet.  If you want to use this, say Y and read the PLIP
+  mini-HOWTO, available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini as well as the
   NET-2-HOWTO in sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that the
   PLIP protocol was changed and this PLIP driver won't work together
   with the PLIP support in Linux versions 1.0.x.  This option enlarges
@@ -1737,20 +1763,6 @@ CONFIG_SUN_INTEL
   This is support for the intel ethernet cards on some Sun workstations
   (all those with a network interface 'ie0' under SunOS).
 
-Do you want to be offered ALPHA test drivers
-CONFIG_NET_ALPHA
-  ALPHA means that they might be unstable and buggy; it has nothing to
-  do with the computer architecture of the same name. If you don't
-  have a network card in your computer, say N; otherwise say Y,
-  because in most circumstances buggy support for your hardware is
-  still better than none at all (in particular, it enables you to test
-  and improve the drivers). Note that the answer to this question
-  doesn't directly affect the kernel: saying N will just cause this
-  configure script to present you with less choices. If you plan to
-  use more than one network card under linux, read the
-  Multiple-Ethernet-mini-HOWTO, available via ftp (user anonymous)
-  from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
-
 Western Digital/SMC cards
 CONFIG_NET_VENDOR_SMC
   If you have a network (ethernet) card belonging to this class, say Y
@@ -2447,8 +2459,8 @@ CONFIG_SBPCD
   addresses and drive types; this can help to find facts in cases you
   are not sure, but can consume some time during the boot process if
   none of the supported drives gets found.
-  Once your drive got found, you should enter the reported parameters into
-  linux/include/linux/sbpcd.h and set "DISTRIBUTION 0" there.
+  Once your drive got found, you should enter the reported parameters 
+  into linux/include/linux/sbpcd.h and set "DISTRIBUTION 0" there.
   This driver can support up to four CDROM interface cards, and each
   card can support up to four CDROM drives; if you say Y here, you
   will be asked how many controllers you have. If compiled as a
@@ -2462,12 +2474,13 @@ CONFIG_SBPCD2
   the parameters for the second, third and fourth interface card into
   linux/include/linux/sbpcd.h before compiling the new kernel.
 
-Aztech/Orchid/Okano/Wearnes/TXC (non IDE) CDROM support
+Aztech/Orchid/Okano/Wearnes/TXC/CyDROM  CDROM support
 CONFIG_AZTCD
-  This is your driver if you have an Aztech CDA268-01A, Orchid CD-3110,
-  Okano or Wearnes CDD110 or a Conrad TXC CDROM drive.
-  This driver - just like all these CDROM drivers - is NOT for CDROM
-  drives with IDE/ATAPI interface, such as Aztech CDA269-031SE.
+  This is your driver if you have an Aztech CDA268-01A, Orchid
+  CD-3110, Okano or Wearnes CDD110, Conrad TXC, or CyCDROM CR520 or
+  CR540 CDROM drive.  This driver - just like all these CDROM drivers
+  - is NOT for CDROM drives with IDE/ATAPI interface, such as Aztech
+  CDA269-031SE.
 
 Sony CDU535 CDROM support
 CONFIG_CDU535
@@ -2510,7 +2523,6 @@ CONFIG_ISP16_CDI
   at boot time, please say Y. Boot time command line options (or
   'append=' options in /etc/lilo.conf) are:
                 isp16=<port>,<irq>,<dma>,<drive_type>
-
   Here 'port','irq' and 'dma' are the base i/o address, irq number and
   dma line assumed to be used by the attached cdrom
   drive. 'drive_type' is the type of cdrom drive or its emulation
@@ -2816,7 +2828,7 @@ CONFIG_BSD_DISKLABEL
   FreeBSD uses its own partition scheme on your PC. It requires only
   one entry in the primary partition table of your disk and manages it
   similarly to DOS extended partitions, putting in its first sector a
-  new partition table in disklabel format. Enabling this option allow
+  new partition table in disklabel format. Enabling this option allows
   you to read these disklabels and further mount FreeBSD partitions on
   your Linux box if you also have configured BSD ufs filesystem
   support. If you don't know what all this is about, say N.
@@ -2824,7 +2836,7 @@ CONFIG_BSD_DISKLABEL
 SMD disklabel (Sun partition tables) support
 CONFIG_SMD_DISKLABEL
   Like most systems, SunOS uses its own partition table format,
-  incompatible with each other. Enabling this option allow you to read
+  incompatible with all others. Enabling this option allows you to read
   these partition tables and further mount SunOS disks on your Linux
   box if you also have configured BSD ufs filesystem support. This is
   mainly used to carry data from a Sparc under SunOS to your Linux box
@@ -2868,9 +2880,9 @@ Amiga FFS filesystem support (read only)
 CONFIG_AFFS_FS
   The Fast File System (FFS) is the common filesystem used on harddisks
   by Amiga (tm) Systems since AmigaOS Version 1.3 (34.20). It's also
-  possible to mount Diskfiles used by the Un*X Amiga Emulator by Bernd
+  possible to mount diskfiles used by the Un*X Amiga Emulator by Bernd
   Schmidt (http://www-users.informatik.rwth-aachen.de/~crux/uae.html)
-  If you want to do this, you will also need the loopback device
+  If you want to do the latter, you will also need the loop device
   support. Because it's in an early development state, the AFFS is 
   read only. Say Y if you want to be able to read files from an Amiga
   FFS partition of your harddrive. Amiga floppies however cannot be
@@ -3147,7 +3159,13 @@ CONFIG_APM_DISPLAY_BLANK
   anything to do with your VESA-compliant power-saving monitor).
   Further, this option doesn't work for all laptops -- it might not turn
   off your backlight at all, or it might print a lot of errors to the
-  console.
+  console, especially if you are using gpm.
+
+Power off on shutdown 
+CONFIG_APM_POWER_OFF
+  This option will power off the computer after the Linux kernel is halted
+  (e.g., with the halt(8) command).  As with the other APM options, this
+  option may not work reliably with some APM BIOS implementations.
 
 Watchdog Timer Support 
 CONFIG_WATCHDOG
@@ -3391,4 +3409,7 @@ CONFIG_AP1000
 # LocalWords:  DIGI Xe Xeve digiboard UMISC touchscreens mtu ethernets HBAs MEX
 # LocalWords:  Shifflett netcom js jshiffle WIC DECchip ELCP EtherPower dst RTC
 # LocalWords:  rtc SMP lp Digi Intl RightSwitch DGRS dgrs AFFS Amiga UFS SDL AP
-# LocalWords:  Solaris RISCom riscom syncPPP PCBIT pcbit sparc anu au
+# LocalWords:  Solaris RISCom riscom syncPPP PCBIT pcbit sparc anu au artoo ufs
+# LocalWords:  hitchcock Crynwr cnam pktdrvr NCSA's CyDROM CyCDROM FreeBSD NeXT
+# LocalWords:  NeXTstep disklabel disklabels SMD FFS tm AmigaOS diskfiles Un
+# LocalWords:  Bernd informatik rwth aachen uae affs
diff --git a/Documentation/locks.txt b/Documentation/locks.txt
new file mode 100644 (file)
index 0000000..ab136d4
--- /dev/null
@@ -0,0 +1,56 @@
+                     File Locking Release Notes
+
+               Andy Walker <andy@lysaker.kvaerner.no>
+
+                          15 April 1996
+
+
+What's New?
+-----------
+
+Flock Emulation Warnings
+------------------------
+Many people will have noticed the ugly messages that the file locking
+code started generating with the release of kernel version 1.3.95. The
+messages look something like this:
+
+    fcntl_setlk() called by process XX with broken flock() emulation
+
+This is a warning for people using older C libraries that those libraries
+are still calling the pre 1.3.x flock() emulation routines, instead of
+the real flock() system call. The old routines are quite badly broken,
+especially with respect to parent-child lock sharing, and can give bad
+results if, for example, sendmail attempts to use them.
+
+Fixed versions of the C libraries have been on public release for many
+months. The latest versions are 5.2.18 or 5.3.12 for ELF, and I believe
+somebody made a 4.7.6 release for people using a.out systems.
+
+In 1.3.96 Linus decided to be lenient on the stragglers and changed the
+warning message so that the kernel will only complain five times and
+then shut up. That should make life more bearable even for people who,
+for some reason, don't want to upgrade.
+
+Sendmail Problems
+-----------------
+Because sendmail was unable to use the old flock() emulation, many sendmail
+installations use fcntl() instead of flock(). This is true of Slackware 3.0
+for example. This gave rise to some other subtle problems if sendmail was
+configured to rebuild the alias file. Sendmail tried to lock the aliases.dir
+file with fcntl() at the same time as the GDBM routines tried to lock this
+file with flock(). With pre 1.3.96 kernels this could result in deadlocks that,
+over time, or under a very heavy mail load, would eventually cause the kernel
+to lock solid with deadlocked processes.
+
+I have chosen the rather cruel solution of returning an error when such a
+deadlock would occur. I can't see any other way to handle this situation
+gracefully. The other options are to maintain two entirely separate lists
+for flock() and fcntl() locks, thus defeating any protection between the
+two, or to free locks placed by one method when the same process later
+tries to lock the same file by the other method. Neither option seems
+satisfactory.
+
+Some programs may break (again, groan). In particular the aforementioned
+sendmail may have problems running in 'newaliases' mode. It will no longer
+deadlock though. Recompile sendmail to use flock() and your troubles will
+be over.
diff --git a/Documentation/networking/ncsa-telnet b/Documentation/networking/ncsa-telnet
new file mode 100644 (file)
index 0000000..d77d28b
--- /dev/null
@@ -0,0 +1,16 @@
+NCSA telnet doesn't work with path MTU discovery enabled. This is due to a
+bug in NCSA that also stops it working with other modern networking code
+such as Solaris.
+
+The following information is courtesy of 
+Marek <marekm@i17linuxb.ists.pwr.wroc.pl>
+
+There is a fixed version somewhere on ftp.upe.ac.za (sorry, I don't
+remember the exact pathname, and this site is very slow from here).
+It may or may not be faster for you to get it from
+ftp://ftp.ists.pwr.wroc.pl/pub/msdos/telnet/ncsa_upe/tel23074.zip
+(source is in v230704s.zip).  I have tested it with 1.3.79 (with
+path mtu discovery enabled - ncsa 2.3.08 didn't work) and it seems
+to work.  I don't know if anyone is working on this code - this
+version is over a year old.  Too bad - it's faster and often more
+stable than these windoze telnets, and runs on almost anything...
diff --git a/Documentation/oops-tracing.txt b/Documentation/oops-tracing.txt
new file mode 100644 (file)
index 0000000..5d8a42f
--- /dev/null
@@ -0,0 +1,72 @@
+From: Linus Torvalds <torvalds@cs.helsinki.fi>
+
+How to track down an Oops.. [originally a mail to linux-kernel]
+
+The main trick is having 5 years of experience with those pesky oops 
+messages ;-)
+
+Actually, there are things you can do that make this easier. I have two 
+separate approached:
+
+       gdb /usr/src/linux/vmlinux
+       gdb> disassemble <offending_function>
+
+That's the easy way to find the problem, at least if the bug-report is 
+well made (like this one was - run through ksymoops to get the 
+information of which function and the offset in the function that it 
+happened in).
+
+Oh, it helps if the report happens on a kernel that is compiled with the 
+same compiler and similar setups.
+
+The other thing to do is disassemble the "Code:" part of the bugreprot: 
+ksymoops will do this too with the correct tools (and new version of 
+ksymoops), but if you don't have the tools you can just do a silly 
+program:
+
+       char str[] = "\xXX\xXX\xXX...";
+       main(){}
+
+and compile it with gcc -g and then do "disassemble str" (where the "XX" 
+stuff are the values reported by the Oops - you can just cut-and-paste 
+and do a replace of spaces to "\x" - that's what I do, as I'm too lazy 
+to write a prigram to automate this all).
+
+Finally, if you want to see where the code comes from, you can do
+
+       cd /usr/src/linux
+       make fs/buffer.s        # or whatever file the bug happened in
+
+and then you get a better idea of what happens than with the gdb 
+disassembly.
+
+Now, the trick is just then to combine all the data you have: the C 
+sources (and general knowledge of what it _should_ do, the assembly 
+listing and the code disassembly (and additionally the register dump you 
+also get from the "oops" message - that can be useful to see _what_ the 
+corrupted pointers were, and when you have the assembler listing you can 
+also match the other registers to whatever C expressions they were used 
+for).
+
+Essentially, you just look at what doesn't match (in this case it was the 
+"Code" disassembly that didn't match with what the compiler generated). 
+Then you need to find out _why_ they don't match. Often it's simple - you 
+see that the code uses a NULL pointer and then you look at the code and 
+wonder how the NULL pointer got there, and if it's a valid thing to do 
+you just check against it..
+
+Now, if somebody gets the idea that this is time-consuming and requires 
+some small amount of concentration, you're right. Which is why I will 
+mostly just ignore any panic reports that don't have the symbol table 
+info etc looked up: it simply gets too hard to look it up (I have some 
+programs to search for specific patterns in the kernel code segment, and 
+sometimes I have been able to look up those kinds of panics too, but 
+that really requires pretty good knowledge of the kernel just to be able 
+to pick out the right sequences etc..)
+
+_Sometimes_ it happens that I just see the disassembled code sequence 
+from the panic, and I know immediately where it's coming from. That's when 
+I get worried that I've been doing this for too long ;-)
+
+               Linus
+
index 05a42ee9fa0aa353c39edc5dce577edbce280b7a..881b671fdf399b7d9fcec959f205dbdef3fdbcb3 100644 (file)
@@ -36,7 +36,7 @@ uses minor #1, so start with ram2 and go from there.
 
 The old "ramdisk=<ram_size>" has been changed to "ramdisk_size=<ram_size>"
 to make it clearer.  The original "ramdisk=<ram_size>" has been kept around
-for compatiblity reasons, but it will probably be removed in 2.1.x.
+for compatibility reasons, but it will probably be removed in 2.1.x.
 
 The new ramdisk also has the ability to load compressed ramdisk images,
 allowing one to squeeze more programs onto an average installation or 
index 9eeb4258d559db409ff71a56416f448c6c6704cb..ba9362faedfb26d13f6f77818623e19acd6dbdae 100644 (file)
@@ -45,7 +45,15 @@ Programming and/or enabling interrupt frequencies greater than 64Hz is
 only allowed by root. This is perhaps a bit conservative, but we don't want
 an evil user generating lots of IRQs on a slow 386sx-16, where it might have
 a negative impact on performance.  Note that the interrupt handler is only
-four lines of code to minimize any possibility of this effect.
+a few lines of code to minimize any possibility of this effect.
+
+Also, if the kernel time is synchronized with an external source, the 
+kernel will write the time back to the CMOS clock every 11 minutes. In 
+the process of doing this, the kernel briefly turns off RTC periodic 
+interrupts, so be aware of this if you are doing serious work. If you
+don't synchronize the kernel time with an external source (via ntp or
+whatever) then the kernel will keep its hands off the RTC, allowing you
+exclusive access to the device for your applications.
 
 The alarm and/or interrupt frequency are programmed into the RTC via
 various ioctl(2) calls as listed in ./include/linux/mc146818rtc.h
index feb4014654df85738e7a20997e146b5d1b59860c..1b18d7655b482d07c55f0faf6462fea986cf61ae 100644 (file)
@@ -65,8 +65,8 @@ S: Status, one of the following:
        Orphan:         No current maintainer [but maybe you could take the 
                        role as you write your new code].
        Obsolete:       Old code. Something tagged obsolete generally means
-                       its been replaced by a better system and you should
-                       be using that.
+                       it has been replaced by a better system and you
+                       should be using that.
 
 3C501 NETWORK DRIVER
 P:     Alan Cox
index 03337a4950d53f7c60050ad7121249b13867c632..614339fb9e2891d3c7c55e63ba61024c2e0428e8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 97
+SUBLEVEL = 98
 
 ARCH = i386
 
index 487ee1a3aa28708ec9cabe44bfe2ad67eff9c32d..7bc03bf6efd7b6921dc6165ce27ff750498f7584 100644 (file)
@@ -9,6 +9,11 @@ unset CONFIG_CROSSCOMPILE CONFIG_NATIVE
 unset CONFIG_PCI CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS
 unset CONFIG_ALPHA_NEED_ROUNDING_EMULATION
 
+mainmenu_option next_comment
+comment 'Code maturity level options'
+bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+endmenu
+
 mainmenu_option next_comment
 comment 'Loadable module support'
 bool 'Enable loadable module support' CONFIG_MODULES
index 26031b05ab87dc40a24a1b327bb3519db8f2d524..a1069c8b724af5c470d9f65a6f4583e3a06fb472 100644 (file)
@@ -2,6 +2,11 @@
 # Automatically generated make config: don't edit
 #
 
+#
+# Code maturity level options
+#
+# CONFIG_EXPERIMENTAL is not set
+
 #
 # Loadable module support
 #
@@ -75,7 +80,6 @@ CONFIG_SKB_LARGE=y
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
 # CONFIG_AX25 is not set
-# CONFIG_BRIDGE is not set
 # CONFIG_NETLINK is not set
 
 #
@@ -133,25 +137,21 @@ CONFIG_SCSI_NCR53C7xx_FAST=y
 #
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=m
-# CONFIG_SLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_STRIP is not set
-# CONFIG_WIC is not set
-# CONFIG_SCC is not set
-# CONFIG_PLIP is not set
 # CONFIG_EQUALIZER is not set
-# CONFIG_DLCI is not set
-# CONFIG_NET_ALPHA is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_LANCE is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_RADIO is not set
+CONFIG_NET_ETHERNET=y
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
 # CONFIG_APRICOT is not set
 CONFIG_DE4X5=y
 # CONFIG_DEC_ELCP is not set
 # CONFIG_DGRS is not set
-# CONFIG_ZNET is not set
 # CONFIG_NET_POCKET is not set
 # CONFIG_TR is not set
 # CONFIG_ARCNET is not set
index d5e36e316291f58eeb0d7e99ab994b18a4ce08c0..d4dbdeb66962117e753f6de487e5e2e8374ab96c 100644 (file)
@@ -510,8 +510,10 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data,
                        return -EPERM;
                if ((!child->dumpable ||
                     (current->uid != child->euid) ||
+                    (current->uid != child->suid) ||
                     (current->uid != child->uid) ||
                     (current->gid != child->egid) ||
+                    (current->gid != child->sgid) ||
                     (current->gid != child->gid)) && !suser())
                        return -EPERM;
                /* the same process cannot be attached many times */
index d1f8672b874196b9de8ff0a407c73320082a4796..8d04799902f27d273b291e8f5664b078fa51c816 100644 (file)
@@ -4,6 +4,11 @@
 #
 mainmenu_name "Linux Kernel Configuration"
 
+mainmenu_option next_comment
+comment 'Code maturity level options'
+bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+endmenu
+
 mainmenu_option next_comment
 comment 'Loadable module support'
 bool 'Enable loadable module support' CONFIG_MODULES
index bc4b04906fd7f4ad3ff6c0a8617906d9988007f7..b92b21ff09c7f66aadad0a662fe2023a6bb29d2f 100644 (file)
@@ -2,6 +2,11 @@
 # Automatically generated make config: don't edit
 #
 
+#
+# Code maturity level options
+#
+# CONFIG_EXPERIMENTAL is not set
+
 #
 # Loadable module support
 #
@@ -74,7 +79,6 @@ CONFIG_SKB_LARGE=y
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
 # CONFIG_AX25 is not set
-# CONFIG_BRIDGE is not set
 # CONFIG_NETLINK is not set
 
 #
@@ -87,22 +91,19 @@ CONFIG_SKB_LARGE=y
 #
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=m
-# CONFIG_SLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_STRIP is not set
-# CONFIG_WIC is not set
-# CONFIG_SCC is not set
-# CONFIG_PLIP is not set
 # CONFIG_EQUALIZER is not set
-# CONFIG_DLCI is not set
-# CONFIG_NET_ALPHA is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_LANCE is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_RADIO is not set
+CONFIG_NET_ETHERNET=y
 CONFIG_NET_VENDOR_3COM=y
 # CONFIG_EL1 is not set
 # CONFIG_EL2 is not set
 CONFIG_EL3=y
 # CONFIG_VORTEX is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_ISA is not set
 # CONFIG_NET_EISA is not set
 # CONFIG_NET_POCKET is not set
index ce4fdf3affadec0bc64aee331c4433edd4b08aa6..3f901264c388ee50864591977a969cc3f8290c5a 100644 (file)
@@ -320,8 +320,10 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                        return -EPERM;
                if ((!child->dumpable ||
                    (current->uid != child->euid) ||
+                   (current->uid != child->suid) ||
                    (current->uid != child->uid) ||
                    (current->gid != child->egid) ||
+                   (current->gid != child->sgid) ||
                    (current->gid != child->gid)) && !suser())
                        return -EPERM;
                /* the same process cannot be attached many times */
index e9e1215ae18d14654dba62685aceccc096a7665f..b80c2c8d029e60973e2a420f8a24d03ba950d93b 100644 (file)
@@ -29,6 +29,7 @@
 
 extern int setup_x86_irq(int, struct irqaction *);
 
+#ifndef        CONFIG_APM      /* cycle counter may be unreliable */
 /* Cycle counter value at the previous timer interrupt.. */
 static unsigned long long last_timer_cc = 0;
 static unsigned long long init_timer_cc = 0;
@@ -82,6 +83,7 @@ static unsigned long do_fast_gettimeoffset(void)
                quotient = 1000000/HZ-1;
        return quotient;
 }
+#endif
 
 /* This function must be called with interrupts disabled 
  * It was inspired by Steve McCanne's microtime-i386 for BSD.  -- jrs
@@ -176,8 +178,8 @@ void do_settimeofday(struct timeval *tv)
 
        xtime = *tv;
        time_state = TIME_BAD;
-       time_maxerror = 0x70000000;
-       time_esterror = 0x70000000;
+       time_maxerror = MAXPHASE;
+       time_esterror = MAXPHASE;
        sti();
 }
 
@@ -271,6 +273,7 @@ static inline void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
            
 }
 
+#ifndef        CONFIG_APM      /* cycle counter may be unreliable */
 /*
  * This is the same as the above, except we _also_ save the current
  * cycle counter value at the time of the timer interrupt, so that
@@ -284,6 +287,7 @@ static void pentium_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                 "=d" (((unsigned long *) &last_timer_cc)[1]));
        timer_interrupt(irq, NULL, regs);
 }
+#endif
 
 /* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
  * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
index ceb464aafa74e203957e919e62aae74f2dea0fc5..e2be0e34ad957dcb45bd43f3be9155a81de175cd 100644 (file)
@@ -340,7 +340,7 @@ static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset,
                break;
 
        case 948:
-               /* Isn't binary compatability _fun_??? */
+               /* Isn't binary compatibility _fun_??? */
                if(cregs->psr & PSR_C)
                        regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I0] << 24;
                else
index 028ed5974715e51f6502c60f9b6447a46604240c..11e1455b6e0cee54e5cfe8ab0583253fe8c1e4cc 100644 (file)
@@ -99,7 +99,7 @@ available: floppy="daring two_fdc" insmod floppy
 floppy=nofifo
        Disables the FIFO entirely. This is needed if you get "Bus
        master arbitration error" messages from your ethernet card (or
-       from other devices) while accessing the foppy.
+       from other devices) while accessing the floppy.
 
 floppy=fifo
        Enables the FIFO (default)
@@ -119,9 +119,9 @@ floppy=fifo
        higher value, until you only get an occasional Over/Underrun.
        It is a good idea to compile the floppy driver as a module
        when doing this tuning. Indeed, it allows to try different
-       fifo values whithout rebooting the machine for each test. Note
+       fifo values without rebooting the machine for each test. Note
        that you need to do 'floppycontrol --messages' every time you
-       re-inseert the module.
+       re-insert the module.
        Usually, tuning the fifo threshold should not be needed, as
        the default (0xa) is reasonable.
 
index 9f4ddbe6278a95e0b3ccee4c75217f8df5675e67..781258153d95e8645bafec9516febaf8ddde13c9 100644 (file)
@@ -210,6 +210,7 @@ Summary of ide driver parameters for kernel "command line":
  "idex=" is recognized for all "x" from "0" to "3", such as "ide1".
 
  "hdx=noprobe"         : drive may be present, but do not probe for it
+ "hdx=none"            : drive is NOT present, ignore cmos and do not probe
  "hdx=nowerr"          : ignore the WRERR_STAT bit on this drive
  "hdx=cdrom"           : drive is present, and is a cdrom drive
  "hdx=cyl,head,sect"   : disk drive is present, with specified geometry
index 050a92d501c8754dc03b0563c3f39c8ca83044ac..5647f0575b7eb3a4cee458400552d2c5b4186de9 100644 (file)
@@ -110,7 +110,7 @@ static ide_tuneproc_t cmd640_tune_drive;
 
 /* Interface to access cmd640x registers */
 static void (*put_cmd640_reg)(int reg_no, int val);
-static byte (*get_cmd640_reg)(int reg_no);
+       byte (*get_cmd640_reg)(int reg_no);
 
 enum { none, vlb, pci1, pci2 };
 static int     bus_type = none;
index 31bed884db343f59511fcae27a94ec24bc7b4f74..489a99c5593544f31db9fdc25ffffbe2486152fb 100644 (file)
@@ -42,6 +42,7 @@
  * DTC2278S has only a single IDE interface.
  * DTC2278D has two IDE interfaces and is otherwise identical to the S version.
  * DTC2278E has onboard BIOS, while the others do not.
+ * DTC2278EB: "works like a charm" -- Kent Bradford <kent@theory.caltech.edu>
  *
  * There may be a fourth controller type. The S and D versions use the
  * Winbond chip, and I think the E version does also.
index 146c1e2728979879a3fdb0c28412ee73a521eefc..0fd8d2a04fdbe1d6f3cf50195ac2b7910cc9559f 100644 (file)
@@ -1733,9 +1733,6 @@ static void reset_interrupt(void)
 {
 #ifdef DEBUGT
        debugt("reset interrupt:");
-#endif
-#ifdef __sparc__
-       fdc_specify();  /* P3: It gives us "sector not found" without this. */
 #endif
        result();               /* get the status ready for set_fdc */
        if (FDCS->reset) {
@@ -4004,6 +4001,10 @@ int floppy_init(void)
                CLEARSTRUCT(FDCS);
                FDCS->dtr = -1;
                FDCS->dor = 0x4;
+#ifdef __sparc__
+               /*sparcs don't have a DOR reset which we can fall back on to*/
+               FDCS->version = FDC_82072A;
+#endif
        }
 
        fdc_state[0].address = FDC1;
@@ -4036,6 +4037,7 @@ int floppy_init(void)
                FDCS->rawcmd = 2;
                if (user_reset_fdc(-1,FD_RESET_ALWAYS,0)){
                        FDCS->address = -1;
+                       FDCS->version = FDC_NONE;
                        continue;
                }
                /* Try to determine the floppy controller type */
@@ -4266,7 +4268,7 @@ void floppy_eject(void)
 {
        int dummy;
        floppy_grab_irq_and_dma();
-       lock_fdc(0,0);
+       lock_fdc(MAXTIMEOUT,0);
        dummy=fd_eject(0);
        process_fd_request();
        floppy_release_irq_and_dma();
index 10ab19815d769ca763c14c9ae0361ce9c424e77e..db6fa33ef1293ad7ce2691ed6b83577934bf361f 100644 (file)
@@ -92,6 +92,8 @@
  *                       Reformat to match kernel tabbing style.
  *                       Add CDROM_GET_UPC ioctl.
  * 3.10  Apr 10, 1996 -- Fix compilation error with STANDARD_ATAPI.
+ * 3.11  Apr 29, 1996 -- Patch from Heiko Eissfeldt <heiko@colossus.escape.de>
+ *                       to remove redundant verify_area calls.
  *
  * NOTE: Direct audio reads will only work on some types of drive.
  * So far, i've received reports of success for Sony and Toshiba drives.
@@ -2079,9 +2081,6 @@ int ide_cdrom_ioctl (ide_drive_t *drive, struct inode *inode,
                struct cdrom_tocentry tocentry;
                struct atapi_toc_entry *toce;
 
-               stat = verify_area (VERIFY_READ, (void *) arg,
-                                   sizeof (tocentry));
-               if (stat) return stat;
                stat = verify_area (VERIFY_WRITE, (void *) arg,
                                    sizeof (tocentry));
                if (stat) return stat;
@@ -2117,9 +2116,6 @@ int ide_cdrom_ioctl (ide_drive_t *drive, struct inode *inode,
                stat = verify_area (VERIFY_WRITE, (void *) arg,
                                    sizeof (subchnl));
                if (stat) return stat;
-               stat = verify_area (VERIFY_READ, (void *) arg,
-                                   sizeof (subchnl));
-               if (stat) return stat;
 
                memcpy_fromfs (&subchnl, (void *) arg, sizeof (subchnl));
 
@@ -2228,9 +2224,6 @@ int ide_cdrom_ioctl (ide_drive_t *drive, struct inode *inode,
                struct atapi_toc *toc;
                int stat;
 
-               stat = verify_area (VERIFY_READ,  (void *)arg,
-                                   sizeof (ms_info));
-               if (stat) return stat;
                stat = verify_area (VERIFY_WRITE, (void *)arg,
                                    sizeof (ms_info));
                if (stat) return stat;
@@ -2327,8 +2320,6 @@ int ide_cdrom_ioctl (ide_drive_t *drive, struct inode *inode,
                        format = 3;
                }
 
-               stat = verify_area (VERIFY_READ, (char *)arg, sizeof (msf));
-               if (stat) return stat;
                stat = verify_area (VERIFY_WRITE, (char *)arg, blocksize);
                if (stat) return stat;
 
index 5f4e64e572b35b6e575dec9c2027d0c45da1ae16..3083a9dbd8e0543cea290d9fa8532797e8b206b3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/block/ide-tape.c      Version 1.5 - ALPHA     Apr  12, 1996
  *
- * Copyright (C) 1995, 1996 Gadi Oxman <tgud@tochnapc2.technion.ac.il>
+ * Copyright (C) 1995, 1996 Gadi Oxman <gadio@netvision.net.il>
  *
  * This driver was constructed as a student project in the software laboratory
  * of the faculty of electrical engineering in the Technion - Israel's
@@ -1525,6 +1525,7 @@ void idetape_issue_packet_command  (ide_drive_t *drive,idetape_packet_command_t
        }               
 #endif /* CONFIG_BLK_DEV_TRITON */
 
+       OUT_BYTE (drive->ctl,IDETAPE_CONTROL_REG);
        OUT_BYTE (dma_ok ? 1:0,IDETAPE_FEATURES_REG);                   /* Use PIO/DMA */
        OUT_BYTE (bcount.b.high,IDETAPE_BCOUNTH_REG);
        OUT_BYTE (bcount.b.low,IDETAPE_BCOUNTL_REG);
index ee71f66a088aff288d918a022dcd551e9c65cd5e..ff9cbf5ed19d9496745e99ae8b36e900031ad0a0 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * linux/drivers/block/ide-tape.h      Version 1.3 - ALPHA     Feb   9, 1996
+ * linux/drivers/block/ide-tape.h      Version 1.5 - ALPHA     Apr  12, 1996
  *
- * Copyright (C) 1995, 1996 Gadi Oxman <tgud@tochnapc2.technion.ac.il>
+ * Copyright (C) 1995, 1996 Gadi Oxman <gadio@netvision.net.il>
  */
 
 /*
index c4a3ea6fee73af5968f2f17f00d11d4805e6ae24..84bed2ee7504cae35ff03309eba3d6ce3cd668ea 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide.c  Version 5.37  Apr 6, 1996
+ *  linux/drivers/block/ide.c  Version 5.39  May 3, 1996
  *
  *  Copyright (C) 1994-1996  Linus Torvalds & authors (see below)
  */
  * Version 5.37                don't use DMA when "noautotune" is specified
  * Version 5.37a (go)  fix shared irq probing (was broken in kernel 1.3.72)
  *                     call unplug_device() from ide_do_drive_cmd()
+ * Version 5.38                add "hdx=none" option, courtesy of Joel Maslak
+ *                     mask drive irq after use, if sharing with another hwif
+ *                     add code to help debug weird cmd640 problems
+ * Version 5.39                fix horrible error in earlier irq sharing "fix"
  *
  *  Some additional driver compile-time options are in ide.h
  *
@@ -749,6 +753,7 @@ static void do_reset1 (ide_drive_t *drive, int  do_not_try_atapi)
        OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG); /* set SRST and nIEN */
        udelay(5);                      /* more than enough time */
        OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* clear SRST, leave nIEN */
+       udelay(5);                      /* more than enough time */
        hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
        ide_set_handler (drive, &reset_pollfunc, HZ/20);
 #endif /* OK_TO_RESET_CONTROLLER */
@@ -1476,6 +1481,8 @@ void ide_do_request (ide_hwgroup_t *hwgroup)
                ide_hwif_t *hwif = hwgroup->hwif;
                struct request *rq;
                if ((rq = hwgroup->rq) == NULL) {
+                       if (hwif->sharing_irq && hwgroup->drive) /* set nIEN */
+                               OUT_BYTE(hwgroup->drive->ctl|2,hwif->ctl_port);
                        /*
                         * hwgroup->next_hwif is different from hwgroup->hwif
                         * only when a request is inserted using "ide_next".
@@ -2405,8 +2412,17 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
                irqs = probe_irq_off(irqs);     /* get irq number */
                if (irqs > 0)
                        HWIF(drive)->irq = irqs;
-               else                            /* Mmmm.. multiple IRQs */
+               else {                          /* Mmmm.. multiple IRQs */
                        printk("%s: IRQ probe failed (%d)\n", drive->name, irqs);
+#ifdef CONFIG_BLK_DEV_CMD640
+                       if (HWIF(drive)->chipset == ide_cmd640) {
+                               extern byte (*get_cmd640_reg)(int);
+                               printk("%s: Hmmm.. probably a driver problem.\n", drive->name);
+                               printk("%s: cmd640 reg 09h == 0x%02x\n", drive->name, get_cmd640_reg(9));
+                               printk("%s: cmd640 reg 51h == 0x%02x\n", drive->name, get_cmd640_reg(0x51));
+                       }
+#endif /* CONFIG_BLK_DEV_CMD640 */
+               }
        }
        return rc;
 }
@@ -2542,7 +2558,7 @@ static void probe_cmos_for_drives (ide_hwif_t *hwif)
        /* Extract drive geometry from CMOS+BIOS if not already setup */
        for (unit = 0; unit < MAX_DRIVES; ++unit) {
                ide_drive_t *drive = &hwif->drives[unit];
-               if ((cmos_disks & (0xf0 >> (unit*4))) && !drive->present) {
+               if ((cmos_disks & (0xf0 >> (unit*4))) && !drive->present && !drive->nobios) {
                        drive->cyl   = drive->bios_cyl  = *(unsigned short *)BIOS;
                        drive->head  = drive->bios_head = *(BIOS+2);
                        drive->sect  = drive->bios_sect = *(BIOS+14);
@@ -2683,6 +2699,7 @@ static int match_parm (char *s, const char *keywords[], int vals[], int max_vals
  * "idex=" is recognized for all "x" from "0" to "3", such as "ide1".
  *
  * "hdx=noprobe"       : drive may be present, but do not probe for it
+ * "hdx=none"          : drive is NOT present, ignore cmos and do not probe
  * "hdx=nowerr"                : ignore the WRERR_STAT bit on this drive
  * "hdx=cdrom"         : drive is present, and is a cdrom drive
  * "hdx=cyl,head,sect" : disk drive is present, with specified geometry
@@ -2737,33 +2754,35 @@ void ide_setup (char *s)
         * Look for drive options:  "hdx="
         */
        if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
-               const char *hd_words[] = {"noprobe", "nowerr", "cdrom", "serialize",
-                                               "autotune", "noautotune", NULL};
+               const char *hd_words[] = {"none", "noprobe", "nowerr", "cdrom",
+                               "serialize", "autotune", "noautotune", NULL};
                unit = s[2] - 'a';
                hw   = unit / MAX_DRIVES;
                unit = unit % MAX_DRIVES;
                hwif = &ide_hwifs[hw];
                drive = &hwif->drives[unit];
                switch (match_parm(&s[3], hd_words, vals, 3)) {
-                       case -1: /* "noprobe" */
+                       case -1: /* "none" */
+                               drive->nobios = 1;  /* drop into "noprobe" */
+                       case -2: /* "noprobe" */
                                drive->noprobe = 1;
                                goto done;
-                       case -2: /* "nowerr" */
+                       case -3: /* "nowerr" */
                                drive->bad_wstat = BAD_R_STAT;
                                hwif->noprobe = 0;
                                goto done;
-                       case -3: /* "cdrom" */
+                       case -4: /* "cdrom" */
                                drive->present = 1;
                                drive->media = ide_cdrom;
                                hwif->noprobe = 0;
                                goto done;
-                       case -4: /* "serialize" */
+                       case -5: /* "serialize" */
                                printk(" -- USE \"ide%d=serialize\" INSTEAD", hw);
                                goto do_serialize;
-                       case -5: /* "autotune" */
+                       case -6: /* "autotune" */
                                drive->autotune = 1;
                                goto done;
-                       case -6: /* "noautotune" */
+                       case -7: /* "noautotune" */
                                drive->autotune = 2;
                                goto done;
                        case 3: /* cyl,head,sect */
@@ -2856,7 +2875,7 @@ void ide_setup (char *s)
                        }
 #endif /* CONFIG_BLK_DEV_HT6560B */
 #if CONFIG_BLK_DEV_QD6580
-                       case -5: /* "qd6580" (no secondary i/f) */
+                       case -5: /* "qd6580" (has secondary i/f) */
                        {
                                extern void init_qd6580 (void);
                                init_qd6580();
@@ -3011,12 +3030,13 @@ static int init_irq (ide_hwif_t *hwif)
         */
        for (index = 0; index < MAX_HWIFS; index++) {
                if (index != hwif->index) {
-                       ide_hwif_t *g = &ide_hwifs[index];
-                       if (g->irq == hwif->irq || g->irq == mate_irq) {
-                               if (hwgroup && !g->hwgroup)
-                                       g->hwgroup = hwgroup;
+                       ide_hwif_t *h = &ide_hwifs[index];
+                       if (h->irq == hwif->irq || h->irq == mate_irq) {
+                               hwif->sharing_irq = h->sharing_irq = 1;
+                               if (hwgroup && !h->hwgroup)
+                                       h->hwgroup = hwgroup;
                                else if (!hwgroup)
-                                       hwgroup = g->hwgroup;
+                                       hwgroup = h->hwgroup;
                        }
                }
        }
index 4a664e7f39f1f8029e3a83b25b80facf909d1bef..5241b7a8e4c35cb00e6be71f203b771a7af45971 100644 (file)
@@ -313,6 +313,7 @@ typedef struct ide_drive_s {
        unsigned using_dma      : 1;    /* disk is using dma for read/write */
        unsigned forced_geom    : 1;    /* 1 if hdx=c,h,s was given at boot */
        unsigned unmask         : 1;    /* flag: okay to unmask other irqs */
+       unsigned nobios         : 1;    /* flag: do not probe bios for drive */
        unsigned autotune       : 2;    /* 1=autotune, 2=noautotune, 0=default */
 #if FAKE_FDISK_FOR_EZDRIVE
        unsigned remap_0_to_1   : 1;    /* flag: partitioned with ezdrive */
@@ -419,6 +420,7 @@ typedef struct hwif_s {
        unsigned        serialized : 1; /* serialized operation with mate hwif */
        unsigned        no_unmask  : 1; /* disallow setting unmask bits */
        unsigned        got_irq    : 1; /* 1 = already alloc'd our irq */
+       unsigned        sharing_irq: 1; /* 1 = sharing irq with another hwif */
 #ifdef CONFIG_BLK_DEV_PROMISE
        unsigned        is_promise2: 1; /* 2nd i/f on promise DC4030 */
 #endif /* CONFIG_BLK_DEV_PROMISE */
index d11e9d96cd9dd4cf2f55b69157ebe2d2df6cb270..4a928d1af468b71a1646ec65e013099b7d8daa84 100644 (file)
@@ -38,6 +38,9 @@
  * and can work out the answers!
  *
  * I/O ports are 0xb0 0xb2 and 0xb3
+ *
+ * More research on qd6580 being done by willmore@cig.mot.com (David)
+ *     -- this is apparently a *dual* IDE interface
  */
 
 static void tune_qd6580 (ide_drive_t *drive, byte pio)
@@ -61,5 +64,6 @@ static void tune_qd6580 (ide_drive_t *drive, byte pio)
 void init_qd6580 (void)
 {
        ide_hwifs[0].chipset = ide_qd6580;
+       ide_hwifs[1].chipset = ide_qd6580;
        ide_hwifs[0].tuneproc = &tune_qd6580;
 }
index b3bdeb08b27dad9a015d1377086538be3fd724b2..9c25513672f88cc63a5a6489b29b03edd68ca9db 100644 (file)
@@ -1,5 +1,5 @@
-#define AZT_VERSION "2.30"
-/*      $Id: aztcd.c,v 2.30 1996/04/26 05:32:15 root Exp root $
+#define AZT_VERSION "2.40"
+/*      $Id: aztcd.c,v 2.40 1996/05/01 11:09:35 root Exp root $
        linux/drivers/block/aztcd.c - Aztech CD268 CDROM driver
 
        Copyright (C) 1994,95,96 Werner Zimmermann(zimmerma@rz.fht-esslingen.de)
         V2.30   Implemented support for CyCDROM CR520, CR940, Code for CR520 
                delivered by H.Berger with preworks by E.Moenkeberg.
                 Werner Zimmermann, April 29, 96
-
+        V2.40   Reorganized the placement of functions in the source code file
+                to reflect the layered approach; did not actually change code
+                Werner Zimmermann, Mai 1, 96
 */
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/blk.h>
 #include <linux/aztcd.h>
 
+/*###########################################################################
+  Defines
+  ###########################################################################
+*/
 #define SET_TIMER(func, jifs)   delay_timer.expires = jiffies + (jifs); \
                                 delay_timer.function = (void *) (func); \
                                 add_timer(&delay_timer); 
                          outb_p(0x10,azt_port+6); 
 #define SWITCH_IDE_MASTER outb_p(0xa0,azt_port+6);
 
-static int aztPresent = 0;
 
 #if 0
 #define AZT_TEST
@@ -209,17 +214,14 @@ static int aztPresent = 0;
 #define AFL_STATUSorDATA (AFL_STATUS | AFL_DATA)
 #define AZT_BUF_SIZ 16
 
-static volatile int azt_transfer_is_active=0;
+#define READ_TIMEOUT 3000
 
-static char azt_buf[CD_FRAMESIZE_RAW*AZT_BUF_SIZ];/*buffer for block size conversion*/
-#if AZT_PRIVATE_IOCTLS
-static char buf[CD_FRAMESIZE_RAW];              /*separate buffer for the ioctls*/
-#endif
+#define azt_port aztcd  /*needed for the modutils*/
 
-static volatile int azt_buf_bn[AZT_BUF_SIZ], azt_next_bn;
-static volatile int azt_buf_in, azt_buf_out = -1;
-static volatile int azt_error=0;
-static int azt_open_count=0;
+/*##########################################################################
+  Type Definitions
+  ##########################################################################
+*/
 enum azt_state_e 
 { AZT_S_IDLE,    /* 0 */
   AZT_S_START,   /* 1 */
@@ -229,24 +231,39 @@ enum azt_state_e
   AZT_S_STOP,    /* 5 */
   AZT_S_STOPPING /* 6 */
 };
-static volatile enum azt_state_e azt_state = AZT_S_IDLE;
-#ifdef AZT_TEST3
-static volatile enum azt_state_e azt_state_old = AZT_S_STOP;  
-static volatile int azt_st_old = 0;
-#endif
 enum azt_read_modes 
 { AZT_MODE_0,     /*read mode for audio disks, not supported by Aztech firmware*/
   AZT_MODE_1,     /*read mode for normal CD-ROMs*/
   AZT_MODE_2      /*read mode for XA CD-ROMs*/
 };
+
+/*##########################################################################
+  Global Variables
+  ##########################################################################
+*/
+static int aztPresent = 0;
+
+static volatile int azt_transfer_is_active=0;
+
+static char azt_buf[CD_FRAMESIZE_RAW*AZT_BUF_SIZ];/*buffer for block size conversion*/
+#if AZT_PRIVATE_IOCTLS
+static char buf[CD_FRAMESIZE_RAW];              /*separate buffer for the ioctls*/
+#endif
+
+static volatile int azt_buf_bn[AZT_BUF_SIZ], azt_next_bn;
+static volatile int azt_buf_in, azt_buf_out = -1;
+static volatile int azt_error=0;
+static int azt_open_count=0;
+static volatile enum azt_state_e azt_state = AZT_S_IDLE;
+#ifdef AZT_TEST3
+static volatile enum azt_state_e azt_state_old = AZT_S_STOP;  
+static volatile int azt_st_old = 0;
+#endif
 static volatile enum azt_read_modes azt_read_mode = AZT_MODE_1;
 
 static int azt_mode = -1;
 static volatile int azt_read_count = 1;
 
-#define READ_TIMEOUT 3000
-
-#define azt_port aztcd  /*needed for the modutils*/
 static int azt_port = AZT_BASE_ADDR;
 
 static char  azt_cont = 0;
@@ -265,35 +282,85 @@ static int  aztAudioStatus = CDROM_AUDIO_NO_STATUS;
 static char aztDiskChanged = 1;
 static char aztTocUpToDate = 0;
 
-static void azt_transfer(void);
-static void azt_poll(void);
-static void azt_invalidate_buffers(void);
-static void do_aztcd_request(void);
-static void azt_hsg2msf(long hsg, struct msf *msf);
-static void azt_bin2bcd(unsigned char *p);
-static long azt_msf2hsg(struct msf *mp);
-static int  azt_bcd2bin(unsigned char bcd);
-static int  aztStatus(void);
-static int  getAztStatus(void);
+static unsigned char aztIndatum;
+static unsigned long aztTimeOutCount;
+static int aztCmd = 0;
+
+/*###########################################################################
+   Function Prototypes
+  ###########################################################################
+*/
+/* CDROM Drive Low Level I/O Functions */
+void        op_ok(void);
+void        pa_ok(void);
+void        sten_low(void);
+void        dten_low(void);
+void        statusAzt(void);
+static void aztStatTimer(void);
+
+/* CDROM Drive Command Functions */
 static int  aztSendCmd(int cmd);
 static int  sendAztCmd(int cmd, struct azt_Play_msf *params);
+static int  aztSeek(struct azt_Play_msf *params);
+static int  aztSetDiskType(int type);
+static int  aztStatus(void);
+static int  getAztStatus(void);
+static int  aztPlay(struct azt_Play_msf *arg);
+static void aztCloseDoor(void);
+static void aztLockDoor(void);
+static void aztUnlockDoor(void);
+static int  aztGetValue(unsigned char *result);
 static int  aztGetQChannelInfo(struct azt_Toc *qp);
 static int  aztUpdateToc(void);
 static int  aztGetDiskInfo(void);
 #if AZT_MULTISESSION 
 static int  aztGetMultiDiskInfo(void);
static int aztGetMultiDiskInfo(void);
 #endif
 static int  aztGetToc(int multi);
-static int  aztGetValue(unsigned char *result);
-static void aztStatTimer(void);
-static void aztCloseDoor(void);
-static void aztLockDoor(void);
-static void aztUnlockDoor(void);
 
-static unsigned char aztIndatum;
-static unsigned long aztTimeOutCount;
-static int aztCmd = 0;
+/* Kernel Interface Functions */
+void        aztcd_setup(char *str, int *ints);
+static int  check_aztcd_media_change(kdev_t full_dev);
+static int  aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
+static void azt_transfer(void);
+static void do_aztcd_request(void);
+static void azt_invalidate_buffers(void);
+int         aztcd_open(struct inode *ip, struct file *fp);
+static void aztcd_release(struct inode * inode, struct file * file);
+int         aztcd_init(void);
+#ifdef MODULE
+ int        init_module(void);
+ void       cleanup_module(void);
+#endif MODULE
+static struct file_operations azt_fops = {
+       NULL,                   /* lseek - default */
+       block_read,             /* read - general block-dev read */
+       block_write,            /* write - general block-dev write */
+       NULL,                   /* readdir - bad */
+       NULL,                   /* select */
+       aztcd_ioctl,            /* ioctl */
+       NULL,                   /* mmap */
+       aztcd_open,             /* open */
+       aztcd_release,          /* release */
+       NULL,                   /* fsync */
+       NULL,                   /* fasync*/
+       check_aztcd_media_change, /*media change*/
+       NULL                    /* revalidate*/
+};
+
+/* Aztcd State Machine: Controls Drive Operating State */
+static void azt_poll(void);
 
+/* Miscellaneous support functions */
+static void azt_hsg2msf(long hsg, struct msf *msf);
+static long azt_msf2hsg(struct msf *mp);
+static void azt_bin2bcd(unsigned char *p);
+static int  azt_bcd2bin(unsigned char bcd);
+
+/*##########################################################################
+  CDROM Drive Low Level I/O Functions
+  ##########################################################################
+*/
 /* Macros for the drive hardware interface handshake, these macros use
    busy waiting */
 /* Wait for OP_OK = drive answers with AFL_OP_OK after receiving a command*/
@@ -375,43 +442,10 @@ static void aztStatTimer(void)
   SET_TIMER(aztStatTimer, HZ/100);
 }
 
-void aztcd_setup(char *str, int *ints)
-{  if (ints[0] > 0)
-      azt_port = ints[1];
-   if (ints[0] > 1)
-      azt_cont = ints[2];
-}
-
-/*
- * Subroutines to automatically close the door (tray) and 
- * lock it closed when the cd is mounted.  Leave the tray
- * locking as an option
- */
-static void aztCloseDoor(void)
-{
-  aztSendCmd(ACMD_CLOSE);
-  STEN_LOW;
-  return;
-}
-
-static void aztLockDoor(void)
-{
-#if AZT_ALLOW_TRAY_LOCK
-  aztSendCmd(ACMD_LOCK);
-  STEN_LOW;
-#endif
-  return;
-}
-
-static void aztUnlockDoor(void)
-{
-#if AZT_ALLOW_TRAY_LOCK
-  aztSendCmd(ACMD_UNLOCK);
-  STEN_LOW;
-#endif
-  return;
-}
-
+/*##########################################################################
+  CDROM Drive Command Functions
+  ##########################################################################
+*/
 /* 
  * Send a single command, return -1 on error, else 0
 */
@@ -557,14 +591,6 @@ static int aztSetDiskType(int type)
 }
 
 
-/* 
- * Checking if the media has been changed not yet implemented
-*/
-static int check_aztcd_media_change(kdev_t full_dev)
-{ return 0;
-}
-
-
 /* used in azt_poll to poll the status, expects another program to issue a 
  * ACMD_GET_STATUS directly before 
  */
@@ -621,838 +647,847 @@ static int aztPlay(struct azt_Play_msf *arg)
        return 0;
 }
 
+/*
+ * Subroutines to automatically close the door (tray) and 
+ * lock it closed when the cd is mounted.  Leave the tray
+ * locking as an option
+ */
+static void aztCloseDoor(void)
+{
+  aztSendCmd(ACMD_CLOSE);
+  STEN_LOW;
+  return;
+}
 
-
-static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg)
-{       int i, st;
-       struct azt_Toc qInfo;
-       struct cdrom_ti ti;
-       struct cdrom_tochdr tocHdr;
-       struct cdrom_msf msf;
-       struct cdrom_tocentry entry;
-       struct azt_Toc *tocPtr;            
-       struct cdrom_subchnl subchnl;
-        struct cdrom_volctrl volctrl;
-
-#ifdef AZT_DEBUG
-       printk("aztcd: starting aztcd_ioctl - Command:%x   Time: %li\n",cmd, jiffies);
-        printk("aztcd Status %x\n", getAztStatus());
+static void aztLockDoor(void)
+{
+#if AZT_ALLOW_TRAY_LOCK
+  aztSendCmd(ACMD_LOCK);
+  STEN_LOW;
 #endif
-       if (!ip) RETURNM("aztcd_ioctl 1",-EINVAL);
-       if (getAztStatus()<0) RETURNM("aztcd_ioctl 2", -EIO);
-       if ((!aztTocUpToDate)||(aztDiskChanged))
-       { if ((i=aztUpdateToc())<0) RETURNM("aztcd_ioctl 3", i); /* error reading TOC */
-       }
+  return;
+}
 
-       switch (cmd)
-       {
-       case CDROMSTART:     /* Spin up the drive. Don't know, what to do,
-                               at least close the tray */
-#if AZT_PRIVATE_IOCTLS 
-               if (aztSendCmd(ACMD_CLOSE)) RETURNM("aztcd_ioctl 4",-1);
-               STEN_LOW_WAIT;
+static void aztUnlockDoor(void)
+{
+#if AZT_ALLOW_TRAY_LOCK
+  aztSendCmd(ACMD_UNLOCK);
+  STEN_LOW;
 #endif
-               break;
-       case CDROMSTOP:      /* Spin down the drive */
-               if (aztSendCmd(ACMD_STOP)) RETURNM("aztcd_ioctl 5",-1);
-               STEN_LOW_WAIT;
-               /* should we do anything if it fails? */
-               aztAudioStatus = CDROM_AUDIO_NO_STATUS;
-               break;
-       case CDROMPAUSE:     /* Pause the drive */
-                if (aztAudioStatus != CDROM_AUDIO_PLAY) return -EINVAL; 
+  return;
+}
 
-               if (aztGetQChannelInfo(&qInfo) < 0)
-               { /* didn't get q channel info */
-                 aztAudioStatus = CDROM_AUDIO_NO_STATUS;
-                 RETURNM("aztcd_ioctl 7",0);
-               }
-               azt_Play.start = qInfo.diskTime;        /* remember restart point */
+/*
+ * Read a value from the drive.  Should return quickly, so a busy wait
+ * is used to avoid excessive rescheduling. The read command itself must
+ * be issued with aztSendCmd() directly before
+ */
+static int aztGetValue(unsigned char *result)
+{       int s;
+
+       STEN_LOW;
+       if (aztTimeOutCount>=AZT_TIMEOUT)
+       {       printk("aztcd: aztGetValue timeout\n");
+               return -1;
+       }
+       s = inb(DATA_PORT) & 0xFF;
+       *result = (unsigned char) s;
+       return 0;
+}
+
+/*
+ * Read the current Q-channel info.  Also used for reading the
+ * table of contents.
+ */
+int aztGetQChannelInfo(struct azt_Toc *qp)
+{       unsigned char notUsed;
+       int st;
 
-               if (aztSendCmd(ACMD_PAUSE)) RETURNM("aztcd_ioctl 8",-1);
-               STEN_LOW_WAIT;
-               aztAudioStatus = CDROM_AUDIO_PAUSED;
-               break;
-       case CDROMRESUME:    /* Play it again, Sam */
-               if (aztAudioStatus != CDROM_AUDIO_PAUSED) return -EINVAL;
-               /* restart the drive at the saved position. */
-               i = aztPlay(&azt_Play);
-               if (i < 0)
-               { aztAudioStatus = CDROM_AUDIO_ERROR;
-                 return -EIO;
-               }
-               aztAudioStatus = CDROM_AUDIO_PLAY;
-               break;
-       case CDROMMULTISESSION: /*multisession support -- experimental*/
-               { struct cdrom_multisession ms;
 #ifdef AZT_DEBUG
-                 printk("aztcd ioctl MULTISESSION\n");
-#endif
-                 st = verify_area(VERIFY_READ, (void*) arg, sizeof(struct cdrom_multisession));
-                 if (st) return st;
-                 memcpy_fromfs(&ms, (void*) arg, sizeof(struct cdrom_multisession));
-                 if (ms.addr_format == CDROM_MSF) 
-                    { ms.addr.msf.minute = azt_bcd2bin(DiskInfo.lastSession.min);
-                      ms.addr.msf.second = azt_bcd2bin(DiskInfo.lastSession.sec);
-                      ms.addr.msf.frame  = azt_bcd2bin(DiskInfo.lastSession.frame);
-                    } 
-                 else if (ms.addr_format == CDROM_LBA)
-                      ms.addr.lba = azt_msf2hsg(&DiskInfo.lastSession);
-                 else
-                      return -EINVAL;
-                 ms.xa_flag = DiskInfo.xa;
-                 st = verify_area(VERIFY_WRITE, (void*) arg, sizeof(struct cdrom_multisession));
-                 if (st) return st;
-                 memcpy_tofs((void*) arg, &ms, sizeof(struct cdrom_multisession));
-#ifdef AZT_DEBUG 
-                 if (ms.addr_format == CDROM_MSF) 
-                      printk("aztcd multisession xa:%d, msf:%02x:%02x.%02x [%02x:%02x.%02x])\n",
-                             ms.xa_flag, ms.addr.msf.minute, ms.addr.msf.second, 
-                             ms.addr.msf.frame, DiskInfo.lastSession.min,
-                             DiskInfo.lastSession.sec, DiskInfo.lastSession.frame);
-                 else
-                     printk("aztcd multisession %d, lba:0x%08x [%02x:%02x.%02x])\n",
-                             ms.xa_flag, ms.addr.lba, DiskInfo.lastSession.min,
-                             DiskInfo.lastSession.sec, DiskInfo.lastSession.frame);
-#endif
-                 return 0;
-               }
-       case CDROMPLAYTRKIND:     /* Play a track.  This currently ignores index. */
-               st = verify_area(VERIFY_READ, (void *) arg, sizeof ti);
-               if (st) return st;
-               memcpy_fromfs(&ti, (void *) arg, sizeof ti);
-               if (ti.cdti_trk0 < DiskInfo.first
-                       || ti.cdti_trk0 > DiskInfo.last
-                       || ti.cdti_trk1 < ti.cdti_trk0)
-               { return -EINVAL;
-               }
-               if (ti.cdti_trk1 > DiskInfo.last)
-                   ti.cdti_trk1 = DiskInfo.last;
-               azt_Play.start = Toc[ti.cdti_trk0].diskTime;
-               azt_Play.end = Toc[ti.cdti_trk1 + 1].diskTime;
-#ifdef AZT_DEBUG
-printk("aztcd play: %02x:%02x.%02x to %02x:%02x.%02x\n",
-       azt_Play.start.min, azt_Play.start.sec, azt_Play.start.frame,
-       azt_Play.end.min, azt_Play.end.sec, azt_Play.end.frame);
+       printk("aztcd: starting aztGetQChannelInfo  Time:%li\n",jiffies);
 #endif
-               i = aztPlay(&azt_Play);
-               if (i < 0)
-               { aztAudioStatus = CDROM_AUDIO_ERROR;
-                 return -EIO;
-               }
-               aztAudioStatus = CDROM_AUDIO_PLAY;
-               break;
-       case CDROMPLAYMSF:   /* Play starting at the given MSF address. */
-/*              if (aztAudioStatus == CDROM_AUDIO_PLAY) 
-               { if (aztSendCmd(ACMD_STOP)) RETURNM("aztcd_ioctl 9",-1);
-                 STEN_LOW;
-                 aztAudioStatus = CDROM_AUDIO_NO_STATUS;
-               }
-*/
-               st = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
-               if (st) return st;
-               memcpy_fromfs(&msf, (void *) arg, sizeof msf);
-               /* convert to bcd */
-               azt_bin2bcd(&msf.cdmsf_min0);
-               azt_bin2bcd(&msf.cdmsf_sec0);
-               azt_bin2bcd(&msf.cdmsf_frame0);
-               azt_bin2bcd(&msf.cdmsf_min1);
-               azt_bin2bcd(&msf.cdmsf_sec1);
-               azt_bin2bcd(&msf.cdmsf_frame1);
-               azt_Play.start.min = msf.cdmsf_min0;
-               azt_Play.start.sec = msf.cdmsf_sec0;
-               azt_Play.start.frame = msf.cdmsf_frame0;
-               azt_Play.end.min = msf.cdmsf_min1;
-               azt_Play.end.sec = msf.cdmsf_sec1;
-               azt_Play.end.frame = msf.cdmsf_frame1;
+       if ((st=getAztStatus())==-1)        RETURNM("aztGetQChannelInfo 1",-1);
+       if (aztSendCmd(ACMD_GET_Q_CHANNEL)) RETURNM("aztGetQChannelInfo 2",-1);
+       /*STEN_LOW_WAIT; ??? Dosemu0.60's cdrom.c does not like STEN_LOW_WAIT here*/
+       if (aztGetValue(&notUsed)) RETURNM("aztGetQChannelInfo 3",-1); /*??? Nullbyte einlesen*/
+       if ((st&AST_MODE_BITS)==AST_INITIAL)
+        { qp->ctrl_addr=0;      /* when audio stop ACMD_GET_Q_CHANNEL returns */
+          qp->track=0;          /* only one byte with Aztech drives */
+          qp->pointIndex=0;
+          qp->trackTime.min=0;
+          qp->trackTime.sec=0;
+          qp->trackTime.frame=0;
+          qp->diskTime.min=0;
+          qp->diskTime.sec=0;
+          qp->diskTime.frame=0;
+          return 0;  
+        }
+       else
+        { if (aztGetValue(&qp -> ctrl_addr) < 0)       RETURNM("aztGetQChannelInfo 4",-1);
+          if (aztGetValue(&qp -> track) < 0)           RETURNM("aztGetQChannelInfo 4",-1);
+          if (aztGetValue(&qp -> pointIndex) < 0)      RETURNM("aztGetQChannelInfo 4",-1);
+          if (aztGetValue(&qp -> trackTime.min) < 0)   RETURNM("aztGetQChannelInfo 4",-1);
+          if (aztGetValue(&qp -> trackTime.sec) < 0)   RETURNM("aztGetQChannelInfo 4",-1);
+          if (aztGetValue(&qp -> trackTime.frame) < 0) RETURNM("aztGetQChannelInfo 4",-1);
+          if (aztGetValue(&notUsed) < 0)               RETURNM("aztGetQChannelInfo 4",-1);
+          if (aztGetValue(&qp -> diskTime.min) < 0)    RETURNM("aztGetQChannelInfo 4",-1);
+          if (aztGetValue(&qp -> diskTime.sec) < 0)    RETURNM("aztGetQChannelInfo 4",-1);
+          if (aztGetValue(&qp -> diskTime.frame) < 0)  RETURNM("aztGetQChannelInfo 4",-1);
+        }
 #ifdef AZT_DEBUG
-printk("aztcd play: %02x:%02x.%02x to %02x:%02x.%02x\n",
-azt_Play.start.min, azt_Play.start.sec, azt_Play.start.frame,
-azt_Play.end.min, azt_Play.end.sec, azt_Play.end.frame);
+       printk("aztcd: exiting aztGetQChannelInfo  Time:%li\n",jiffies);
 #endif
-               i = aztPlay(&azt_Play);
-               if (i < 0)
-               { aztAudioStatus = CDROM_AUDIO_ERROR;
-                 return -EIO;
-               }
-               aztAudioStatus = CDROM_AUDIO_PLAY;
-               break;
+       return 0;
+}
+
+/*
+ * Read the table of contents (TOC) and TOC header if necessary
+ */
+static int aztUpdateToc()
+{       int st;
 
-       case CDROMREADTOCHDR:        /* Read the table of contents header */
-               st = verify_area(VERIFY_WRITE, (void *) arg, sizeof tocHdr);
-               if (st) return st;
-               tocHdr.cdth_trk0 = DiskInfo.first;
-               tocHdr.cdth_trk1 = DiskInfo.last;
-               memcpy_tofs((void *) arg, &tocHdr, sizeof tocHdr);
-               break;
-       case CDROMREADTOCENTRY:      /* Read an entry in the table of contents */
-               st = verify_area(VERIFY_READ, (void *) arg, sizeof entry);
-               if (st) return st;
-               st = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry);
-               if (st) return st;
-               memcpy_fromfs(&entry, (void *) arg, sizeof entry);
-               if ((!aztTocUpToDate)||aztDiskChanged) aztUpdateToc();
-               if (entry.cdte_track == CDROM_LEADOUT)
-                 tocPtr = &Toc[DiskInfo.last + 1];
-               else if (entry.cdte_track > DiskInfo.last
-                               || entry.cdte_track < DiskInfo.first)
-               { return -EINVAL;
-               }
-               else 
-                 tocPtr = &Toc[entry.cdte_track];
-               entry.cdte_adr = tocPtr -> ctrl_addr;
-               entry.cdte_ctrl = tocPtr -> ctrl_addr >> 4;
-               if (entry.cdte_format == CDROM_LBA)
-                 entry.cdte_addr.lba = azt_msf2hsg(&tocPtr -> diskTime);
-               else if (entry.cdte_format == CDROM_MSF)
-               { entry.cdte_addr.msf.minute = azt_bcd2bin(tocPtr -> diskTime.min);
-                 entry.cdte_addr.msf.second = azt_bcd2bin(tocPtr -> diskTime.sec);
-                 entry.cdte_addr.msf.frame  = azt_bcd2bin(tocPtr -> diskTime.frame);
-               }
-               else
-               { return -EINVAL;
-               }
-               memcpy_tofs((void *) arg, &entry, sizeof entry);
-               break;
-       case CDROMSUBCHNL:   /* Get subchannel info */
-               st = verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_subchnl));
-               if (st) { 
 #ifdef AZT_DEBUG
-                         printk("aztcd: exiting aztcd_ioctl - Error 1 - Command:%x\n",cmd);
+       printk("aztcd: starting aztUpdateToc  Time:%li\n",jiffies);
+#endif  
+       if (aztTocUpToDate)
+               return 0;
+
+       if (aztGetDiskInfo() < 0)
+               return -EIO;
+
+       if (aztGetToc(0) < 0)
+               return -EIO;
+
+        /*audio disk detection
+          with my Aztech drive there is no audio status bit, so I use the copy
+          protection bit of the first track. If this track is copy protected 
+          (copy bit = 0), I assume, it's an audio  disk. Strange, but works ??? */
+        if (!(Toc[DiskInfo.first].ctrl_addr & 0x40)) 
+           DiskInfo.audio=1;
+        else 
+           DiskInfo.audio=0;
+
+        /* XA detection */
+       if (! DiskInfo.audio) 
+          { azt_Play.start.min   = 0;  /*XA detection only seems to work*/
+             azt_Play.start.sec   = 2;  /*when we play a track*/
+            azt_Play.start.frame = 0;
+            azt_Play.end.min     = 0;
+            azt_Play.end.sec     = 0;
+            azt_Play.end.frame   = 1;
+            if (sendAztCmd(ACMD_PLAY_READ, &azt_Play)) return -1;
+            DTEN_LOW;
+            for (st=0;st<CD_FRAMESIZE;st++) inb(DATA_PORT);
+           } 
+        DiskInfo.xa = getAztStatus() & AST_MODE;
+        if (DiskInfo.xa) 
+           { printk("aztcd: XA support experimental - mail results to zimmerma@rz.fht-esslingen.de\n");
+           }
+        
+        /*multisession detection
+          support for multisession CDs is done automatically with Aztech drives,
+          we don't have to take care about TOC redirection; if we want the isofs
+          to take care about redirection, we have to set AZT_MULTISESSION to 1*/
+        DiskInfo.multi=0;
+#if AZT_MULTISESSION
+       if (DiskInfo.xa) 
+          { aztGetMultiDiskInfo(); /*here Disk.Info.multi is set*/
+          }
 #endif
-                         return st;
-                       }  
-               st = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_subchnl));
-               if (st) { 
+        if (DiskInfo.multi)
+           { DiskInfo.lastSession.min  = Toc[DiskInfo.next].diskTime.min;
+            DiskInfo.lastSession.sec  = Toc[DiskInfo.next].diskTime.sec;
+             DiskInfo.lastSession.frame= Toc[DiskInfo.next].diskTime.frame;
+             printk("aztcd: Multisession support experimental\n");
+           }
+        else
+           { DiskInfo.lastSession.min  = Toc[DiskInfo.first].diskTime.min;
+            DiskInfo.lastSession.sec  = Toc[DiskInfo.first].diskTime.sec;
+             DiskInfo.lastSession.frame= Toc[DiskInfo.first].diskTime.frame;
+           }
+
+       aztTocUpToDate = 1;
 #ifdef AZT_DEBUG
-                         printk("aztcd: exiting aztcd_ioctl - Error 2 - Command:%x\n",cmd);
+       printk("aztcd: exiting aztUpdateToc  Time:%li\n",jiffies);
 #endif
-                         return st;
-                       }  
-               memcpy_fromfs(&subchnl, (void *) arg, sizeof (struct cdrom_subchnl));
-               if (aztGetQChannelInfo(&qInfo) < 0)
-               if (st) { 
+       return 0;
+}
+
+
+/* Read the table of contents header, i.e. no. of tracks and start of first 
+ * track
+ */
+static int aztGetDiskInfo()
+{ int limit;
+  unsigned char test;
+  struct azt_Toc qInfo;
+
 #ifdef AZT_DEBUG
-                         printk("aztcd: exiting aztcd_ioctl - Error 3 - Command:%x\n",cmd);
+  printk("aztcd: starting aztGetDiskInfo  Time:%li\n",jiffies);
 #endif
-                         return -EIO;
-                       }  
-               subchnl.cdsc_audiostatus = aztAudioStatus;
-               subchnl.cdsc_adr = qInfo.ctrl_addr;
-               subchnl.cdsc_ctrl = qInfo.ctrl_addr >> 4;
-               subchnl.cdsc_trk = azt_bcd2bin(qInfo.track);
-               subchnl.cdsc_ind = azt_bcd2bin(qInfo.pointIndex);
-               if (subchnl.cdsc_format == CDROM_LBA)
-               { subchnl.cdsc_absaddr.lba = azt_msf2hsg(&qInfo.diskTime);
-                 subchnl.cdsc_reladdr.lba = azt_msf2hsg(&qInfo.trackTime);
-               }
-               else  /*default*/
-               { subchnl.cdsc_format = CDROM_MSF;
-                 subchnl.cdsc_absaddr.msf.minute = azt_bcd2bin(qInfo.diskTime.min);
-                 subchnl.cdsc_absaddr.msf.second = azt_bcd2bin(qInfo.diskTime.sec);
-                 subchnl.cdsc_absaddr.msf.frame  = azt_bcd2bin(qInfo.diskTime.frame);
-                 subchnl.cdsc_reladdr.msf.minute = azt_bcd2bin(qInfo.trackTime.min);
-                 subchnl.cdsc_reladdr.msf.second = azt_bcd2bin(qInfo.trackTime.sec);
-                 subchnl.cdsc_reladdr.msf.frame  = azt_bcd2bin(qInfo.trackTime.frame);
-               }
-               memcpy_tofs((void *) arg, &subchnl, sizeof (struct cdrom_subchnl));
-               break;
-       case CDROMVOLCTRL:   /* Volume control 
-        * With my Aztech CD268-01A volume control does not work, I can only
-          turn the channels on (any value !=0) or off (value==0). Maybe it
-           works better with your drive */
-                st=verify_area(VERIFY_READ,(void *) arg, sizeof(volctrl));
-                if (st) return (st);
-                memcpy_fromfs(&volctrl,(char *) arg,sizeof(volctrl));
-               azt_Play.start.min = 0x21;
-               azt_Play.start.sec = 0x84;
-               azt_Play.start.frame = volctrl.channel0;
-               azt_Play.end.min =     volctrl.channel1;
-               azt_Play.end.sec =     volctrl.channel2;
-               azt_Play.end.frame =   volctrl.channel3;
-                sendAztCmd(ACMD_SET_VOLUME, &azt_Play);
-                STEN_LOW_WAIT;
-                break;
-       case CDROMEJECT:
-                aztUnlockDoor(); /* Assume user knows what they're doing */
-              /* all drives can at least stop! */
-               if (aztAudioStatus == CDROM_AUDIO_PLAY) 
-               { if (aztSendCmd(ACMD_STOP)) RETURNM("azt_ioctl 10",-1);
-                 STEN_LOW_WAIT;
-               }
-               if (aztSendCmd(ACMD_EJECT)) RETURNM("azt_ioctl 11",-1);
-               STEN_LOW_WAIT;
-               aztAudioStatus = CDROM_AUDIO_NO_STATUS;
-               break;
-       case CDROMEJECT_SW:
-               azt_auto_eject = (char) arg;
-               break;  
-        case CDROMRESET:
-               outb(ACMD_SOFT_RESET,CMD_PORT);   /*send reset*/
-               STEN_LOW;
-               if (inb(DATA_PORT)!=AFL_OP_OK)    /*OP_OK?*/
-                 { printk("aztcd: AZTECH CD-ROM drive does not respond\n");
-                  }
-                break;
-/*Take care, the following code is not compatible with other CD-ROM drivers,
-  use it at your own risk with cdplay.c. Set AZT_PRIVATE_IOCTLS to 0 in aztcd.h,
-  if you do not want to use it!
-*/                  
-#if AZT_PRIVATE_IOCTLS 
-       case CDROMREADCOOKED: /*read data in mode 1 (2048 Bytes)*/
-       case CDROMREADRAW:    /*read data in mode 2 (2336 Bytes)*/
-               { st = verify_area(VERIFY_READ,  (void *) arg, sizeof msf);
-                 if (st) return st;
-                 st = verify_area(VERIFY_WRITE, (void *) arg, sizeof buf);
-                 if (st) return st;
-                 memcpy_fromfs(&msf, (void *) arg, sizeof msf);
-                 /* convert to bcd */
-                 azt_bin2bcd(&msf.cdmsf_min0);
-                 azt_bin2bcd(&msf.cdmsf_sec0);
-                 azt_bin2bcd(&msf.cdmsf_frame0);
-                 msf.cdmsf_min1=0;
-                 msf.cdmsf_sec1=0;
-                 msf.cdmsf_frame1=1; /*read only one frame*/
-                 azt_Play.start.min = msf.cdmsf_min0;
-                 azt_Play.start.sec = msf.cdmsf_sec0;
-                 azt_Play.start.frame = msf.cdmsf_frame0;
-                 azt_Play.end.min = msf.cdmsf_min1;
-                 azt_Play.end.sec = msf.cdmsf_sec1;
-                 azt_Play.end.frame = msf.cdmsf_frame1;
-                 if (cmd==CDROMREADRAW)
-                 { if (DiskInfo.xa)
-                      { return -1;         /*XA Disks can't be read raw*/
-                      }
-                   else   
-                      { if (sendAztCmd(ACMD_PLAY_READ_RAW, &azt_Play)) return -1;
-                        DTEN_LOW;
-                        insb(DATA_PORT,buf,CD_FRAMESIZE_RAW);
-                        memcpy_tofs((void *) arg, &buf, CD_FRAMESIZE_RAW);
-                      }  
-                 }
-                 else /*CDROMREADCOOKED*/
-                 { if (sendAztCmd(ACMD_PLAY_READ, &azt_Play)) return -1;
-                   DTEN_LOW;
-                   insb(DATA_PORT,buf,CD_FRAMESIZE);
-                   memcpy_tofs((void *) arg, &buf, CD_FRAMESIZE);
-                 }
-                } 
-                break;
-       case CDROMSEEK:    /*seek msf address*/
-               st = verify_area(VERIFY_READ,  (void *) arg, sizeof msf);
-               if (st) return st;
-               memcpy_fromfs(&msf, (void *) arg, sizeof msf);
-               /* convert to bcd */
-               azt_bin2bcd(&msf.cdmsf_min0);
-               azt_bin2bcd(&msf.cdmsf_sec0);
-               azt_bin2bcd(&msf.cdmsf_frame0);
-               azt_Play.start.min = msf.cdmsf_min0;
-               azt_Play.start.sec = msf.cdmsf_sec0;
-               azt_Play.start.frame = msf.cdmsf_frame0;
-               if (aztSeek(&azt_Play)) return -1;
-                break;
-#endif /*end of incompatible code*/       
-       case CDROMREADMODE1: /*set read data in mode 1*/
-                return aztSetDiskType(AZT_MODE_1);
-       case CDROMREADMODE2: /*set read data in mode 2*/
-                return aztSetDiskType(AZT_MODE_2);         
-       default:
-               return -EINVAL;
+  if (aztSendCmd(ACMD_SEEK_TO_LEADIN)) RETURNM("aztGetDiskInfo 1",-1);
+  STEN_LOW_WAIT;
+  test=0;
+  for (limit=300;limit>0;limit--)
+   {  if (aztGetQChannelInfo(&qInfo)<0) RETURNM("aztGetDiskInfo 2",-1);
+      if (qInfo.pointIndex==0xA0)   /*Number of FirstTrack*/
+       { DiskInfo.first = qInfo.diskTime.min;
+         DiskInfo.first = azt_bcd2bin(DiskInfo.first);
+         test=test|0x01;
+       }
+      if (qInfo.pointIndex==0xA1)   /*Number of LastTrack*/
+       { DiskInfo.last  = qInfo.diskTime.min;
+         DiskInfo.last  = azt_bcd2bin(DiskInfo.last);
+         test=test|0x02;
+       }
+      if (qInfo.pointIndex==0xA2)   /*DiskLength*/
+       { DiskInfo.diskLength.min=qInfo.diskTime.min;
+         DiskInfo.diskLength.sec=qInfo.diskTime.sec;
+         DiskInfo.diskLength.frame=qInfo.diskTime.frame;
+         test=test|0x04;
+       }
+      if ((qInfo.pointIndex==DiskInfo.first)&&(test&0x01))   /*StartTime of First Track*/
+       { DiskInfo.firstTrack.min=qInfo.diskTime.min;
+         DiskInfo.firstTrack.sec=qInfo.diskTime.sec;
+         DiskInfo.firstTrack.frame=qInfo.diskTime.frame;
+         test=test|0x08;
        }
+      if (test==0x0F) break;
+   }
 #ifdef AZT_DEBUG
-        printk("aztcd: exiting aztcd_ioctl Command:%x  Time:%li\n",cmd,jiffies);
+  printk ("aztcd: exiting aztGetDiskInfo  Time:%li\n",jiffies);
+  printk("Disk Info: first %d last %d length %02X:%02X.%02X dez  first %02X:%02X.%02X dez\n",
+         DiskInfo.first,
+         DiskInfo.last,
+         DiskInfo.diskLength.min,
+         DiskInfo.diskLength.sec,
+         DiskInfo.diskLength.frame,
+         DiskInfo.firstTrack.min,
+         DiskInfo.firstTrack.sec,
+         DiskInfo.firstTrack.frame);
 #endif
-       return 0;
+  if (test!=0x0F) return -1;
+  return 0;
 }
 
-
+#if AZT_MULTISESSION
 /*
- * Take care of the different block sizes between cdrom and Linux.
- * When Linux gets variable block sizes this will probably go away.
+ * Get Multisession Disk Info
  */
-static void azt_transfer(void)
-{ 
-#ifdef AZT_TEST
-  printk("aztcd: executing azt_transfer Time:%li\n",jiffies);
-#endif
-  if (CURRENT_VALID) {
-    while (CURRENT -> nr_sectors) {
-      int bn = CURRENT -> sector / 4;
-      int i;
-      for (i = 0; i < AZT_BUF_SIZ && azt_buf_bn[i] != bn; ++i)
-       ;
-      if (i < AZT_BUF_SIZ) {
-       int offs = (i * 4 + (CURRENT -> sector & 3)) * 512;
-       int nr_sectors = 4 - (CURRENT -> sector & 3);
-       if (azt_buf_out != i) {
-         azt_buf_out = i;
-         if (azt_buf_bn[i] != bn) {
-           azt_buf_out = -1;
-           continue;
-         }
-       }
-       if (nr_sectors > CURRENT -> nr_sectors)
-         nr_sectors = CURRENT -> nr_sectors;
-       memcpy(CURRENT -> buffer, azt_buf + offs, nr_sectors * 512);
-       CURRENT -> nr_sectors -= nr_sectors;
-       CURRENT -> sector += nr_sectors;
-       CURRENT -> buffer += nr_sectors * 512;
-      } else {
-       azt_buf_out = -1;
-       break;
-      }
-    }
-  }
-}
-
+static int aztGetMultiDiskInfo(void)
+{ int limit, k=5;
+  unsigned char test;
+  struct azt_Toc qInfo;
 
-static void do_aztcd_request(void)
-{
-#ifdef AZT_TEST
-  printk(" do_aztcd_request(%ld+%ld) Time:%li\n", CURRENT -> sector, CURRENT -> nr_sectors,jiffies);
-#endif
-  if (DiskInfo.audio) 
-    { printk("aztcd: Error, tried to mount an Audio CD\n");
-      end_request(0);
-      return;
-    }
-  azt_transfer_is_active = 1;
-  while (CURRENT_VALID) {
-    if (CURRENT->bh) {
-      if (!buffer_locked(CURRENT->bh))
-       panic(DEVICE_NAME ": block not locked");
-    }
-    azt_transfer();
-    if (CURRENT -> nr_sectors == 0) {
-      end_request(1);
-    } else {
-      azt_buf_out = -1;         /* Want to read a block not in buffer */
-      if (azt_state == AZT_S_IDLE) {
-       if ((!aztTocUpToDate)||aztDiskChanged) {
-         if (aztUpdateToc() < 0) {
-           while (CURRENT_VALID)
-             end_request(0);
-           break;
-         }
-       }
-       azt_state = AZT_S_START;
-       AztTries = 5;
-       SET_TIMER(azt_poll, HZ/100);
-      }
-      break;
-    }
-  }
-  azt_transfer_is_active = 0;
-#ifdef AZT_TEST2
-  printk("azt_next_bn:%x  azt_buf_in:%x azt_buf_out:%x  azt_buf_bn:%x\n", \
-         azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]);
-  printk(" do_aztcd_request ends  Time:%li\n",jiffies);
+#ifdef AZT_DEBUG
+  printk("aztcd: starting aztGetMultiDiskInfo\n");
 #endif
-}
 
-static void azt_poll(void)
-{
-    int st = 0;
-    int loop_ctl = 1;
-    int skip = 0;
+  do { azt_Play.start.min   = Toc[DiskInfo.last+1].diskTime.min;
+       azt_Play.start.sec   = Toc[DiskInfo.last+1].diskTime.sec;
+       azt_Play.start.frame = Toc[DiskInfo.last+1].diskTime.frame;
+       test=0;
 
-    if (azt_error) {                            
-       if (aztSendCmd(ACMD_GET_ERROR)) RETURN("azt_poll 1");
-       STEN_LOW;
-       azt_error=inb(DATA_PORT)&0xFF;
-       printk("aztcd: I/O error 0x%02x\n", azt_error);
-       azt_invalidate_buffers();
-#ifdef WARN_IF_READ_FAILURE
-       if (AztTries == 5)
-         printk("aztcd: Read of Block %d Failed - Maybe Audio Disk?\n", azt_next_bn);
+       for (limit=30;limit>0;limit--)   /*Seek for LeadIn of next session*/
+           { if (aztSeek(&azt_Play)) RETURNM("aztGetMultiDiskInfo 1",-1);
+             if (aztGetQChannelInfo(&qInfo)<0) RETURNM("aztGetMultiDiskInfo 2",-1);
+             if ((qInfo.track==0)&&(qInfo.pointIndex)) break;  /*LeadIn found*/
+             if ((azt_Play.start.sec+=10) > 59)
+                { azt_Play.start.sec=0;
+                  azt_Play.start.min++;
+                }
+           }
+       if (!limit) break;  /*Check, if a leadin track was found, if not we're
+                             at the end of the disk*/
+#ifdef AZT_DEBUG_MULTISESSION
+       printk("leadin found track %d  pointIndex %x  limit %d\n",qInfo.track,qInfo.pointIndex,limit);
 #endif
-       if (!AztTries--) {
-         printk("aztcd: Read of Block %d Failed, Maybe Audio Disk? Giving up\n", azt_next_bn);
-         if (azt_transfer_is_active) {
-           AztTries = 0;
-           loop_ctl = 0;
-         }
-         if (CURRENT_VALID)
-           end_request(0);
-         AztTries = 5;
-       }
-    azt_error = 0;
-    azt_state = AZT_S_STOP;
-    }
-
-    while (loop_ctl)
-    {
-      loop_ctl = 0;   /* each case must flip this back to 1 if we want
-                        to come back up here */
-      switch (azt_state) {
-
-       case AZT_S_IDLE:
-#ifdef AZT_TEST3
-         if (azt_state!=azt_state_old) {
-           azt_state_old=azt_state;
-           printk("AZT_S_IDLE\n");
-           }
+       for (limit=300;limit>0;limit--)
+           { if (++azt_Play.start.frame>74)
+                { azt_Play.start.frame=0;
+                  if (azt_Play.start.sec > 59)
+                     { azt_Play.start.sec=0;
+                       azt_Play.start.min++;
+                     }
+                }     
+             if (aztSeek(&azt_Play)) RETURNM("aztGetMultiDiskInfo 3",-1);
+             if (aztGetQChannelInfo(&qInfo)<0) RETURNM("aztGetMultiDiskInfo 4",-1);
+             if (qInfo.pointIndex==0xA0)   /*Number of NextTrack*/
+               { DiskInfo.next = qInfo.diskTime.min;
+                 DiskInfo.next = azt_bcd2bin(DiskInfo.next);
+                 test=test|0x01;
+               }
+             if (qInfo.pointIndex==0xA1)   /*Number of LastTrack*/
+               { DiskInfo.last  = qInfo.diskTime.min;
+                 DiskInfo.last  = azt_bcd2bin(DiskInfo.last);
+                 test=test|0x02;
+               }
+            if (qInfo.pointIndex==0xA2)   /*DiskLength*/
+               { DiskInfo.diskLength.min  =qInfo.diskTime.min;
+                 DiskInfo.diskLength.sec  =qInfo.diskTime.sec;
+                 DiskInfo.diskLength.frame=qInfo.diskTime.frame;
+                 test=test|0x04;
+               }
+            if ((qInfo.pointIndex==DiskInfo.next)&&(test&0x01))   /*StartTime of Next Track*/
+               { DiskInfo.nextSession.min=qInfo.diskTime.min;
+                 DiskInfo.nextSession.sec=qInfo.diskTime.sec;
+                 DiskInfo.nextSession.frame=qInfo.diskTime.frame;
+                 test=test|0x08;
+               }
+            if (test==0x0F) break;
+          }
+#ifdef AZT_DEBUG_MULTISESSION
+       printk ("MultiDisk Info: first %d next %d last %d length %02x:%02x.%02x dez  first %02x:%02x.%02x dez  next %02x:%02x.%02x dez\n",
+               DiskInfo.first,
+               DiskInfo.next,
+               DiskInfo.last,
+               DiskInfo.diskLength.min,
+               DiskInfo.diskLength.sec,
+               DiskInfo.diskLength.frame,
+               DiskInfo.firstTrack.min,
+               DiskInfo.firstTrack.sec,
+               DiskInfo.firstTrack.frame,
+               DiskInfo.nextSession.min,
+               DiskInfo.nextSession.sec,
+               DiskInfo.nextSession.frame);
 #endif
-         return;
+       if (test!=0x0F) 
+           break;
+       else 
+           DiskInfo.multi=1;   /*found TOC of more than one session*/
+       aztGetToc(1);
+     } while(--k);
 
-       case AZT_S_START:
-#ifdef AZT_TEST3
-         if (azt_state!=azt_state_old) {
-           azt_state_old=azt_state;
-           printk("AZT_S_START\n");
-         }
+#ifdef AZT_DEBUG
+  printk ("aztcd: exiting aztGetMultiDiskInfo  Time:%li\n",jiffies);
+#endif
+  return 0;
+}
 #endif
-         if(aztSendCmd(ACMD_GET_STATUS)) RETURN("azt_poll 2");  /*result will be checked by aztStatus() */
-         azt_state = azt_mode == 1 ? AZT_S_READ : AZT_S_MODE;
-         AztTimeout = 3000;
-         break;
 
-       case AZT_S_MODE:
-#ifdef AZT_TEST3
-         if (azt_state!=azt_state_old) {
-           azt_state_old=azt_state;
-           printk("AZT_S_MODE\n");
-         }
+/*
+ * Read the table of contents (TOC)
+ */
+static int aztGetToc(int multi)
+{ int i, px;
+  int limit;
+  struct azt_Toc qInfo;
+
+#ifdef AZT_DEBUG
+  printk("aztcd: starting aztGetToc  Time:%li\n",jiffies);
 #endif
-         if (!skip) {
-           if ((st = aztStatus()) != -1) {
-             if ((st & AST_DSK_CHG)||(st & AST_NOT_READY)) {
-               aztDiskChanged = 1;
-               aztTocUpToDate = 0;
-               azt_invalidate_buffers();
-               end_request(0);
-               printk("aztcd: Disk Changed or Not Ready 1 - Unmount Disk!\n");
-             }
-           } else break;
-         }
-         skip = 0;
+  if (!multi)
+     { for (i = 0; i < MAX_TRACKS; i++)
+           Toc[i].pointIndex = 0;
+       i = DiskInfo.last + 3;
+     }
+  else
+     { for (i = DiskInfo.next; i < MAX_TRACKS; i++)
+           Toc[i].pointIndex = 0; 
+       i = DiskInfo.last + 4 - DiskInfo.next;
+     }
 
-         if ((st & AST_DOOR_OPEN)||(st & AST_NOT_READY)) {
-           aztDiskChanged = 1;
-           aztTocUpToDate = 0;
-            printk("aztcd: Disk Changed or Not Ready 2 - Unmount Disk!\n");
-            end_request(0);
-           printk((st & AST_DOOR_OPEN) ? "aztcd: door open\n" : "aztcd: disk removed\n");
-           if (azt_transfer_is_active) {
-             azt_state = AZT_S_START;
-             loop_ctl = 1;   /* goto immediately */
-             break;
-           }
-           azt_state = AZT_S_IDLE;
-           while (CURRENT_VALID)
-             end_request(0);
-           return;
-         }
-                               
-/*       if (aztSendCmd(ACMD_SET_MODE)) RETURN("azt_poll 3");
-         outb(0x01, DATA_PORT);          
-         PA_OK;
-         STEN_LOW;
-*/        if (aztSendCmd(ACMD_GET_STATUS)) RETURN("azt_poll 4");
-         STEN_LOW;
-         azt_mode = 1;
-         azt_state = AZT_S_READ;
-         AztTimeout = 3000;
+/*Is there a good reason to stop motor before TOC read?
+  if (aztSendCmd(ACMD_STOP)) RETURNM("aztGetToc 1",-1);
+      STEN_LOW_WAIT;
+*/
 
-         break;
+  if (!multi)
+     { azt_mode = 0x05;
+       if (aztSendCmd(ACMD_SEEK_TO_LEADIN)) RETURNM("aztGetToc 2",-1);
+       STEN_LOW_WAIT;
+     }
+  for (limit = 300; limit > 0; limit--)
+      { if (multi)
+           { if (++azt_Play.start.sec > 59)
+                { azt_Play.start.sec=0;
+                  azt_Play.start.min++;
+                }
+             if (aztSeek(&azt_Play)) RETURNM("aztGetToc 3",-1);
+           }
+       if (aztGetQChannelInfo(&qInfo) < 0)
+           break;
 
+       px = azt_bcd2bin(qInfo.pointIndex);
 
-       case AZT_S_READ:
-#ifdef AZT_TEST3
-         if (azt_state!=azt_state_old)  {
-           azt_state_old=azt_state;
-           printk("AZT_S_READ\n");
-         }
-#endif
-         if (!skip) {
-             if ((st = aztStatus()) != -1) {
-               if ((st & AST_DSK_CHG)||(st & AST_NOT_READY)) {
-               aztDiskChanged = 1;
-               aztTocUpToDate = 0;
-               azt_invalidate_buffers();
-               printk("aztcd: Disk Changed or Not Ready 3 - Unmount Disk!\n");
-                end_request(0);               
-               }
-             } else break;
-         } 
-           
-         skip = 0;
-         if ((st & AST_DOOR_OPEN)||(st & AST_NOT_READY)) {
-           aztDiskChanged = 1;
-           aztTocUpToDate = 0;
-           printk((st & AST_DOOR_OPEN) ? "aztcd: door open\n" : "aztcd: disk removed\n");
-           if (azt_transfer_is_active) {
-             azt_state = AZT_S_START;
-             loop_ctl = 1;
-             break;
-           }
-           azt_state = AZT_S_IDLE;
-           while (CURRENT_VALID)
-           end_request(0);
-           return;
-         }
+       if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
+           if (Toc[px].pointIndex == 0)
+              { Toc[px] = qInfo;
+                i--;
+              }
 
-         if (CURRENT_VALID) {
-           struct azt_Play_msf msf;
-           int i;
-           azt_next_bn = CURRENT -> sector / 4;
-           azt_hsg2msf(azt_next_bn, &msf.start);
-           i = 0;
-           /* find out in which track we are */
-           while (azt_msf2hsg(&msf.start)>azt_msf2hsg(&Toc[++i].trackTime)) {};
-           if (azt_msf2hsg(&msf.start)<azt_msf2hsg(&Toc[i].trackTime)-AZT_BUF_SIZ)
-               { azt_read_count=AZT_BUF_SIZ;  /*fast, because we read ahead*/
-               /*azt_read_count=CURRENT->nr_sectors;    slow, no read ahead*/
-               }
-           else /* don't read beyond end of track */           
-#if AZT_MULTISESSION 
-               { azt_read_count=(azt_msf2hsg(&Toc[i].trackTime)/4)*4-azt_msf2hsg(&msf.start);  
-                 if (azt_read_count < 0) azt_read_count=0;
-                if (azt_read_count > AZT_BUF_SIZ) azt_read_count=AZT_BUF_SIZ;
-                 printk("aztcd: warning - trying to read beyond end of track\n");
-/*               printk("%i %i %li %li\n",i,azt_read_count,azt_msf2hsg(&msf.start),azt_msf2hsg(&Toc[i].trackTime));
-*/             }
-#else
-              { azt_read_count=AZT_BUF_SIZ;
-              }
-#endif
-           msf.end.min = 0;
-           msf.end.sec = 0;            
-           msf.end.frame = azt_read_count ;/*Mitsumi here reads 0xffffff sectors*/
-#ifdef AZT_TEST3
-           printk("---reading msf-address %x:%x:%x  %x:%x:%x\n",msf.start.min,msf.start.sec,msf.start.frame,msf.end.min,msf.end.sec,msf.end.frame);
-           printk("azt_next_bn:%x  azt_buf_in:%x azt_buf_out:%x  azt_buf_bn:%x\n", \
-                   azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]);
-#endif 
-            if (azt_read_mode==AZT_MODE_2)
-               { sendAztCmd(ACMD_PLAY_READ_RAW, &msf); /*XA disks in raw mode*/
-               }
-            else
-               { sendAztCmd(ACMD_PLAY_READ, &msf);     /*others in cooked mode*/
-               }
-           azt_state = AZT_S_DATA;
-           AztTimeout = READ_TIMEOUT;
-         } else {
-           azt_state = AZT_S_STOP;
-           loop_ctl = 1;
+       if (i <= 0)
            break;
-         }
-
-         break;
+      }
 
+  Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
+  Toc[DiskInfo.last].trackTime    = DiskInfo.diskLength;
 
-       case AZT_S_DATA:
-#ifdef AZT_TEST3
-         if (azt_state!=azt_state_old)  {
-           azt_state_old=azt_state;
-           printk("AZT_S_DATA\n");
-         }
+#ifdef AZT_DEBUG_MULTISESSION 
+  printk("aztcd: exiting aztGetToc\n");
+  for (i = 1; i <= DiskInfo.last+1; i++)
+       printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X dez  %02X:%02X.%02X dez\n",
+               i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
+               Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
+               Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
+  for (i = 100; i < 103; i++)
+       printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X dez  %02X:%02X.%02X dez\n",
+               i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
+               Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
+               Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
 #endif
 
-         st = inb(STATUS_PORT) & AFL_STATUSorDATA; 
+  return limit > 0 ? 0 : -1;
+}
 
-         switch (st) {
 
-           case AFL_DATA:
-#ifdef AZT_TEST3
-             if (st!=azt_st_old)  {
-               azt_st_old=st; 
-               printk("---AFL_DATA st:%x\n",st);
-             }
+/*##########################################################################
+  Kernel Interface Functions
+  ##########################################################################
+*/
+void aztcd_setup(char *str, int *ints)
+{  if (ints[0] > 0)
+      azt_port = ints[1];
+   if (ints[0] > 1)
+      azt_cont = ints[2];
+}
+
+/* 
+ * Checking if the media has been changed not yet implemented
+*/
+static int check_aztcd_media_change(kdev_t full_dev)
+{ return 0;
+}
+
+/*
+ * Kernel IO-controls
+*/
+static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg)
+{       int i, st;
+       struct azt_Toc qInfo;
+       struct cdrom_ti ti;
+       struct cdrom_tochdr tocHdr;
+       struct cdrom_msf msf;
+       struct cdrom_tocentry entry;
+       struct azt_Toc *tocPtr;            
+       struct cdrom_subchnl subchnl;
+        struct cdrom_volctrl volctrl;
+
+#ifdef AZT_DEBUG
+       printk("aztcd: starting aztcd_ioctl - Command:%x   Time: %li\n",cmd, jiffies);
+        printk("aztcd Status %x\n", getAztStatus());
 #endif
-             if (!AztTries--) {
-               printk("aztcd: Read of Block %d Failed, Maybe Audio Disk ? Giving up\n", azt_next_bn);
-               if (azt_transfer_is_active) {
-                 AztTries = 0;
-                 break;
+       if (!ip) RETURNM("aztcd_ioctl 1",-EINVAL);
+       if (getAztStatus()<0) RETURNM("aztcd_ioctl 2", -EIO);
+       if ((!aztTocUpToDate)||(aztDiskChanged))
+       { if ((i=aztUpdateToc())<0) RETURNM("aztcd_ioctl 3", i); /* error reading TOC */
+       }
+
+       switch (cmd)
+       {
+       case CDROMSTART:     /* Spin up the drive. Don't know, what to do,
+                               at least close the tray */
+#if AZT_PRIVATE_IOCTLS 
+               if (aztSendCmd(ACMD_CLOSE)) RETURNM("aztcd_ioctl 4",-1);
+               STEN_LOW_WAIT;
+#endif
+               break;
+       case CDROMSTOP:      /* Spin down the drive */
+               if (aztSendCmd(ACMD_STOP)) RETURNM("aztcd_ioctl 5",-1);
+               STEN_LOW_WAIT;
+               /* should we do anything if it fails? */
+               aztAudioStatus = CDROM_AUDIO_NO_STATUS;
+               break;
+       case CDROMPAUSE:     /* Pause the drive */
+                if (aztAudioStatus != CDROM_AUDIO_PLAY) return -EINVAL; 
+
+               if (aztGetQChannelInfo(&qInfo) < 0)
+               { /* didn't get q channel info */
+                 aztAudioStatus = CDROM_AUDIO_NO_STATUS;
+                 RETURNM("aztcd_ioctl 7",0);
                }
-               if (CURRENT_VALID)
-                 end_request(0);
-               AztTries = 5;
-             }
-             azt_state = AZT_S_START;
-             AztTimeout = READ_TIMEOUT;
-             loop_ctl = 1;
-             break;
+               azt_Play.start = qInfo.diskTime;        /* remember restart point */
 
-           case AFL_STATUSorDATA:
-#ifdef AZT_TEST3
-             if (st!=azt_st_old)  {
-               azt_st_old=st;
-               printk("---AFL_STATUSorDATA st:%x\n",st);
-             }
+               if (aztSendCmd(ACMD_PAUSE)) RETURNM("aztcd_ioctl 8",-1);
+               STEN_LOW_WAIT;
+               aztAudioStatus = CDROM_AUDIO_PAUSED;
+               break;
+       case CDROMRESUME:    /* Play it again, Sam */
+               if (aztAudioStatus != CDROM_AUDIO_PAUSED) return -EINVAL;
+               /* restart the drive at the saved position. */
+               i = aztPlay(&azt_Play);
+               if (i < 0)
+               { aztAudioStatus = CDROM_AUDIO_ERROR;
+                 return -EIO;
+               }
+               aztAudioStatus = CDROM_AUDIO_PLAY;
+               break;
+       case CDROMMULTISESSION: /*multisession support -- experimental*/
+               { struct cdrom_multisession ms;
+#ifdef AZT_DEBUG
+                 printk("aztcd ioctl MULTISESSION\n");
 #endif
-             break;
+                 st = verify_area(VERIFY_READ, (void*) arg, sizeof(struct cdrom_multisession));
+                 if (st) return st;
+                 memcpy_fromfs(&ms, (void*) arg, sizeof(struct cdrom_multisession));
+                 if (ms.addr_format == CDROM_MSF) 
+                    { ms.addr.msf.minute = azt_bcd2bin(DiskInfo.lastSession.min);
+                      ms.addr.msf.second = azt_bcd2bin(DiskInfo.lastSession.sec);
+                      ms.addr.msf.frame  = azt_bcd2bin(DiskInfo.lastSession.frame);
+                    } 
+                 else if (ms.addr_format == CDROM_LBA)
+                      ms.addr.lba = azt_msf2hsg(&DiskInfo.lastSession);
+                 else
+                      return -EINVAL;
+                 ms.xa_flag = DiskInfo.xa;
+                 st = verify_area(VERIFY_WRITE, (void*) arg, sizeof(struct cdrom_multisession));
+                 if (st) return st;
+                 memcpy_tofs((void*) arg, &ms, sizeof(struct cdrom_multisession));
+#ifdef AZT_DEBUG 
+                 if (ms.addr_format == CDROM_MSF) 
+                      printk("aztcd multisession xa:%d, msf:%02x:%02x.%02x [%02x:%02x.%02x])\n",
+                             ms.xa_flag, ms.addr.msf.minute, ms.addr.msf.second, 
+                             ms.addr.msf.frame, DiskInfo.lastSession.min,
+                             DiskInfo.lastSession.sec, DiskInfo.lastSession.frame);
+                 else
+                     printk("aztcd multisession %d, lba:0x%08x [%02x:%02x.%02x])\n",
+                             ms.xa_flag, ms.addr.lba, DiskInfo.lastSession.min,
+                             DiskInfo.lastSession.sec, DiskInfo.lastSession.frame);
+#endif
+                 return 0;
+               }
+       case CDROMPLAYTRKIND:     /* Play a track.  This currently ignores index. */
+               st = verify_area(VERIFY_READ, (void *) arg, sizeof ti);
+               if (st) return st;
+               memcpy_fromfs(&ti, (void *) arg, sizeof ti);
+               if (ti.cdti_trk0 < DiskInfo.first
+                       || ti.cdti_trk0 > DiskInfo.last
+                       || ti.cdti_trk1 < ti.cdti_trk0)
+               { return -EINVAL;
+               }
+               if (ti.cdti_trk1 > DiskInfo.last)
+                   ti.cdti_trk1 = DiskInfo.last;
+               azt_Play.start = Toc[ti.cdti_trk0].diskTime;
+               azt_Play.end = Toc[ti.cdti_trk1 + 1].diskTime;
+#ifdef AZT_DEBUG
+printk("aztcd play: %02x:%02x.%02x to %02x:%02x.%02x\n",
+       azt_Play.start.min, azt_Play.start.sec, azt_Play.start.frame,
+       azt_Play.end.min, azt_Play.end.sec, azt_Play.end.frame);
+#endif
+               i = aztPlay(&azt_Play);
+               if (i < 0)
+               { aztAudioStatus = CDROM_AUDIO_ERROR;
+                 return -EIO;
+               }
+               aztAudioStatus = CDROM_AUDIO_PLAY;
+               break;
+       case CDROMPLAYMSF:   /* Play starting at the given MSF address. */
+/*              if (aztAudioStatus == CDROM_AUDIO_PLAY) 
+               { if (aztSendCmd(ACMD_STOP)) RETURNM("aztcd_ioctl 9",-1);
+                 STEN_LOW;
+                 aztAudioStatus = CDROM_AUDIO_NO_STATUS;
+               }
+*/
+               st = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
+               if (st) return st;
+               memcpy_fromfs(&msf, (void *) arg, sizeof msf);
+               /* convert to bcd */
+               azt_bin2bcd(&msf.cdmsf_min0);
+               azt_bin2bcd(&msf.cdmsf_sec0);
+               azt_bin2bcd(&msf.cdmsf_frame0);
+               azt_bin2bcd(&msf.cdmsf_min1);
+               azt_bin2bcd(&msf.cdmsf_sec1);
+               azt_bin2bcd(&msf.cdmsf_frame1);
+               azt_Play.start.min = msf.cdmsf_min0;
+               azt_Play.start.sec = msf.cdmsf_sec0;
+               azt_Play.start.frame = msf.cdmsf_frame0;
+               azt_Play.end.min = msf.cdmsf_min1;
+               azt_Play.end.sec = msf.cdmsf_sec1;
+               azt_Play.end.frame = msf.cdmsf_frame1;
+#ifdef AZT_DEBUG
+printk("aztcd play: %02x:%02x.%02x to %02x:%02x.%02x\n",
+azt_Play.start.min, azt_Play.start.sec, azt_Play.start.frame,
+azt_Play.end.min, azt_Play.end.sec, azt_Play.end.frame);
+#endif
+               i = aztPlay(&azt_Play);
+               if (i < 0)
+               { aztAudioStatus = CDROM_AUDIO_ERROR;
+                 return -EIO;
+               }
+               aztAudioStatus = CDROM_AUDIO_PLAY;
+               break;
 
-           default:
-#ifdef AZT_TEST3
-             if (st!=azt_st_old)  {
-               azt_st_old=st;
-               printk("---default: st:%x\n",st);
-             }
+       case CDROMREADTOCHDR:        /* Read the table of contents header */
+               st = verify_area(VERIFY_WRITE, (void *) arg, sizeof tocHdr);
+               if (st) return st;
+               tocHdr.cdth_trk0 = DiskInfo.first;
+               tocHdr.cdth_trk1 = DiskInfo.last;
+               memcpy_tofs((void *) arg, &tocHdr, sizeof tocHdr);
+               break;
+       case CDROMREADTOCENTRY:      /* Read an entry in the table of contents */
+               st = verify_area(VERIFY_READ, (void *) arg, sizeof entry);
+               if (st) return st;
+               st = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry);
+               if (st) return st;
+               memcpy_fromfs(&entry, (void *) arg, sizeof entry);
+               if ((!aztTocUpToDate)||aztDiskChanged) aztUpdateToc();
+               if (entry.cdte_track == CDROM_LEADOUT)
+                 tocPtr = &Toc[DiskInfo.last + 1];
+               else if (entry.cdte_track > DiskInfo.last
+                               || entry.cdte_track < DiskInfo.first)
+               { return -EINVAL;
+               }
+               else 
+                 tocPtr = &Toc[entry.cdte_track];
+               entry.cdte_adr = tocPtr -> ctrl_addr;
+               entry.cdte_ctrl = tocPtr -> ctrl_addr >> 4;
+               if (entry.cdte_format == CDROM_LBA)
+                 entry.cdte_addr.lba = azt_msf2hsg(&tocPtr -> diskTime);
+               else if (entry.cdte_format == CDROM_MSF)
+               { entry.cdte_addr.msf.minute = azt_bcd2bin(tocPtr -> diskTime.min);
+                 entry.cdte_addr.msf.second = azt_bcd2bin(tocPtr -> diskTime.sec);
+                 entry.cdte_addr.msf.frame  = azt_bcd2bin(tocPtr -> diskTime.frame);
+               }
+               else
+               { return -EINVAL;
+               }
+               memcpy_tofs((void *) arg, &entry, sizeof entry);
+               break;
+       case CDROMSUBCHNL:   /* Get subchannel info */
+               st = verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_subchnl));
+               if (st) { 
+#ifdef AZT_DEBUG
+                         printk("aztcd: exiting aztcd_ioctl - Error 1 - Command:%x\n",cmd);
 #endif
-             AztTries = 5;
-             if (!CURRENT_VALID && azt_buf_in == azt_buf_out) {
-               azt_state = AZT_S_STOP;
-               loop_ctl = 1;
+                         return st;
+                       }  
+               st = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_subchnl));
+               if (st) { 
+#ifdef AZT_DEBUG
+                         printk("aztcd: exiting aztcd_ioctl - Error 2 - Command:%x\n",cmd);
+#endif
+                         return st;
+                       }  
+               memcpy_fromfs(&subchnl, (void *) arg, sizeof (struct cdrom_subchnl));
+               if (aztGetQChannelInfo(&qInfo) < 0)
+               if (st) { 
+#ifdef AZT_DEBUG
+                         printk("aztcd: exiting aztcd_ioctl - Error 3 - Command:%x\n",cmd);
+#endif
+                         return -EIO;
+                       }  
+               subchnl.cdsc_audiostatus = aztAudioStatus;
+               subchnl.cdsc_adr = qInfo.ctrl_addr;
+               subchnl.cdsc_ctrl = qInfo.ctrl_addr >> 4;
+               subchnl.cdsc_trk = azt_bcd2bin(qInfo.track);
+               subchnl.cdsc_ind = azt_bcd2bin(qInfo.pointIndex);
+               if (subchnl.cdsc_format == CDROM_LBA)
+               { subchnl.cdsc_absaddr.lba = azt_msf2hsg(&qInfo.diskTime);
+                 subchnl.cdsc_reladdr.lba = azt_msf2hsg(&qInfo.trackTime);
+               }
+               else  /*default*/
+               { subchnl.cdsc_format = CDROM_MSF;
+                 subchnl.cdsc_absaddr.msf.minute = azt_bcd2bin(qInfo.diskTime.min);
+                 subchnl.cdsc_absaddr.msf.second = azt_bcd2bin(qInfo.diskTime.sec);
+                 subchnl.cdsc_absaddr.msf.frame  = azt_bcd2bin(qInfo.diskTime.frame);
+                 subchnl.cdsc_reladdr.msf.minute = azt_bcd2bin(qInfo.trackTime.min);
+                 subchnl.cdsc_reladdr.msf.second = azt_bcd2bin(qInfo.trackTime.sec);
+                 subchnl.cdsc_reladdr.msf.frame  = azt_bcd2bin(qInfo.trackTime.frame);
+               }
+               memcpy_tofs((void *) arg, &subchnl, sizeof (struct cdrom_subchnl));
                break;
-             }
-             if (azt_read_count<=0)
-               printk("aztcd: warning - try to read 0 frames\n");
-             while (azt_read_count)      /*??? fast read ahead loop*/
-              { azt_buf_bn[azt_buf_in] = -1;
-                DTEN_LOW;                      /*??? unsolved problem, very
-                                                     seldom we get timeouts
-                                                     here, don't now the real
-                                                     reason. With my drive this
-                                                     sometimes also happens with
-                                                     Aztech's original driver under
-                                                     DOS. Is it a hardware bug? 
-                                                     I tried to recover from such
-                                                     situations here. Zimmermann*/
-                if (aztTimeOutCount>=AZT_TIMEOUT) 
-                 { printk("read_count:%d CURRENT->nr_sectors:%ld azt_buf_in:%d\n", azt_read_count,CURRENT->nr_sectors,azt_buf_in);
-                   printk("azt_transfer_is_active:%x\n",azt_transfer_is_active);
-                   azt_read_count=0;
-                   azt_state = AZT_S_STOP;
-                   loop_ctl = 1;
-                   end_request(1);  /*should we have here (1) or (0)? */
-                 }
-                else
-                 { if (azt_read_mode==AZT_MODE_2)
-                      { insb(DATA_PORT, azt_buf + CD_FRAMESIZE_RAW * azt_buf_in, CD_FRAMESIZE_RAW);
+       case CDROMVOLCTRL:   /* Volume control 
+        * With my Aztech CD268-01A volume control does not work, I can only
+          turn the channels on (any value !=0) or off (value==0). Maybe it
+           works better with your drive */
+                st=verify_area(VERIFY_READ,(void *) arg, sizeof(volctrl));
+                if (st) return (st);
+                memcpy_fromfs(&volctrl,(char *) arg,sizeof(volctrl));
+               azt_Play.start.min = 0x21;
+               azt_Play.start.sec = 0x84;
+               azt_Play.start.frame = volctrl.channel0;
+               azt_Play.end.min =     volctrl.channel1;
+               azt_Play.end.sec =     volctrl.channel2;
+               azt_Play.end.frame =   volctrl.channel3;
+                sendAztCmd(ACMD_SET_VOLUME, &azt_Play);
+                STEN_LOW_WAIT;
+                break;
+       case CDROMEJECT:
+                aztUnlockDoor(); /* Assume user knows what they're doing */
+              /* all drives can at least stop! */
+               if (aztAudioStatus == CDROM_AUDIO_PLAY) 
+               { if (aztSendCmd(ACMD_STOP)) RETURNM("azt_ioctl 10",-1);
+                 STEN_LOW_WAIT;
+               }
+               if (aztSendCmd(ACMD_EJECT)) RETURNM("azt_ioctl 11",-1);
+               STEN_LOW_WAIT;
+               aztAudioStatus = CDROM_AUDIO_NO_STATUS;
+               break;
+       case CDROMEJECT_SW:
+               azt_auto_eject = (char) arg;
+               break;  
+        case CDROMRESET:
+               outb(ACMD_SOFT_RESET,CMD_PORT);   /*send reset*/
+               STEN_LOW;
+               if (inb(DATA_PORT)!=AFL_OP_OK)    /*OP_OK?*/
+                 { printk("aztcd: AZTECH CD-ROM drive does not respond\n");
+                  }
+                break;
+/*Take care, the following code is not compatible with other CD-ROM drivers,
+  use it at your own risk with cdplay.c. Set AZT_PRIVATE_IOCTLS to 0 in aztcd.h,
+  if you do not want to use it!
+*/                  
+#if AZT_PRIVATE_IOCTLS 
+       case CDROMREADCOOKED: /*read data in mode 1 (2048 Bytes)*/
+       case CDROMREADRAW:    /*read data in mode 2 (2336 Bytes)*/
+               { st = verify_area(VERIFY_READ,  (void *) arg, sizeof msf);
+                 if (st) return st;
+                 st = verify_area(VERIFY_WRITE, (void *) arg, sizeof buf);
+                 if (st) return st;
+                 memcpy_fromfs(&msf, (void *) arg, sizeof msf);
+                 /* convert to bcd */
+                 azt_bin2bcd(&msf.cdmsf_min0);
+                 azt_bin2bcd(&msf.cdmsf_sec0);
+                 azt_bin2bcd(&msf.cdmsf_frame0);
+                 msf.cdmsf_min1=0;
+                 msf.cdmsf_sec1=0;
+                 msf.cdmsf_frame1=1; /*read only one frame*/
+                 azt_Play.start.min = msf.cdmsf_min0;
+                 azt_Play.start.sec = msf.cdmsf_sec0;
+                 azt_Play.start.frame = msf.cdmsf_frame0;
+                 azt_Play.end.min = msf.cdmsf_min1;
+                 azt_Play.end.sec = msf.cdmsf_sec1;
+                 azt_Play.end.frame = msf.cdmsf_frame1;
+                 if (cmd==CDROMREADRAW)
+                 { if (DiskInfo.xa)
+                      { return -1;         /*XA Disks can't be read raw*/
                       }
-                   else
-                      { insb(DATA_PORT, azt_buf + CD_FRAMESIZE * azt_buf_in, CD_FRAMESIZE);
-                       }
-                   azt_read_count--;
-#ifdef AZT_TEST3
-                   printk("AZT_S_DATA; ---I've read data- read_count: %d\n",azt_read_count);
-                   printk("azt_next_bn:%d  azt_buf_in:%d azt_buf_out:%d  azt_buf_bn:%d\n", \
-                        azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]);
-#endif
-                   azt_buf_bn[azt_buf_in] = azt_next_bn++;
-                   if (azt_buf_out == -1)
-                     azt_buf_out = azt_buf_in;
-                   azt_buf_in = azt_buf_in + 1 == AZT_BUF_SIZ ? 0 : azt_buf_in + 1;
+                   else   
+                      { if (sendAztCmd(ACMD_PLAY_READ_RAW, &azt_Play)) return -1;
+                        DTEN_LOW;
+                        insb(DATA_PORT,buf,CD_FRAMESIZE_RAW);
+                        memcpy_tofs((void *) arg, &buf, CD_FRAMESIZE_RAW);
+                      }  
+                 }
+                 else /*CDROMREADCOOKED*/
+                 { if (sendAztCmd(ACMD_PLAY_READ, &azt_Play)) return -1;
+                   DTEN_LOW;
+                   insb(DATA_PORT,buf,CD_FRAMESIZE);
+                   memcpy_tofs((void *) arg, &buf, CD_FRAMESIZE);
                  }
-              }
-             if (!azt_transfer_is_active) {
-               while (CURRENT_VALID) {
-                 azt_transfer();
-                 if (CURRENT -> nr_sectors == 0)
-                   end_request(1);
-                 else
-                   break;
-               }
-             }
-
-             if (CURRENT_VALID
-               && (CURRENT -> sector / 4 < azt_next_bn ||
-               CURRENT -> sector / 4 > azt_next_bn + AZT_BUF_SIZ)) {
-               azt_state = AZT_S_STOP;
-               loop_ctl = 1;
-               break;
-             }
-             AztTimeout = READ_TIMEOUT;   
-             if (azt_read_count==0) {
-               azt_state = AZT_S_STOP; 
-               loop_ctl = 1;
-               break;           
-             } 
-             break;
-           }
-    break;
-
-
-       case AZT_S_STOP:
-#ifdef AZT_TEST3
-         if (azt_state!=azt_state_old) {
-           azt_state_old=azt_state;
-           printk("AZT_S_STOP\n");
-         }
+                } 
+                break;
+       case CDROMSEEK:    /*seek msf address*/
+               st = verify_area(VERIFY_READ,  (void *) arg, sizeof msf);
+               if (st) return st;
+               memcpy_fromfs(&msf, (void *) arg, sizeof msf);
+               /* convert to bcd */
+               azt_bin2bcd(&msf.cdmsf_min0);
+               azt_bin2bcd(&msf.cdmsf_sec0);
+               azt_bin2bcd(&msf.cdmsf_frame0);
+               azt_Play.start.min = msf.cdmsf_min0;
+               azt_Play.start.sec = msf.cdmsf_sec0;
+               azt_Play.start.frame = msf.cdmsf_frame0;
+               if (aztSeek(&azt_Play)) return -1;
+                break;
+#endif /*end of incompatible code*/       
+       case CDROMREADMODE1: /*set read data in mode 1*/
+                return aztSetDiskType(AZT_MODE_1);
+       case CDROMREADMODE2: /*set read data in mode 2*/
+                return aztSetDiskType(AZT_MODE_2);         
+       default:
+               return -EINVAL;
+       }
+#ifdef AZT_DEBUG
+        printk("aztcd: exiting aztcd_ioctl Command:%x  Time:%li\n",cmd,jiffies);
 #endif
-         if (azt_read_count!=0) printk("aztcd: discard data=%x frames\n",azt_read_count);
-         while (azt_read_count!=0) {
-           int i;
-           if ( !(inb(STATUS_PORT) & AFL_DATA) ) {
-             if (azt_read_mode==AZT_MODE_2)
-                for (i=0; i<CD_FRAMESIZE_RAW; i++) inb(DATA_PORT);
-             else   
-                for (i=0; i<CD_FRAMESIZE; i++) inb(DATA_PORT);
-           }
-           azt_read_count--;
-         }  
-         if (aztSendCmd(ACMD_GET_STATUS)) RETURN("azt_poll 5");
-         azt_state = AZT_S_STOPPING;
-         AztTimeout = 1000;
-         break;
+       return 0;
+}
 
-       case AZT_S_STOPPING:
-#ifdef AZT_TEST3
-         if (azt_state!=azt_state_old) {
-           azt_state_old=azt_state;
-           printk("AZT_S_STOPPING\n");
-         }
+/*
+ * Take care of the different block sizes between cdrom and Linux.
+ * When Linux gets variable block sizes this will probably go away.
+ */
+static void azt_transfer(void)
+{ 
+#ifdef AZT_TEST
+  printk("aztcd: executing azt_transfer Time:%li\n",jiffies);
 #endif
-
-         if ((st = aztStatus()) == -1 && AztTimeout)
-           break;
-
-         if ((st != -1) && ((st & AST_DSK_CHG)||(st & AST_NOT_READY))) {
-           aztDiskChanged = 1;
-           aztTocUpToDate = 0;
-           azt_invalidate_buffers();
-           printk("aztcd: Disk Changed or Not Ready 4 - Unmount Disk!\n");
-           end_request(0);
+  if (CURRENT_VALID) {
+    while (CURRENT -> nr_sectors) {
+      int bn = CURRENT -> sector / 4;
+      int i;
+      for (i = 0; i < AZT_BUF_SIZ && azt_buf_bn[i] != bn; ++i)
+       ;
+      if (i < AZT_BUF_SIZ) {
+       int offs = (i * 4 + (CURRENT -> sector & 3)) * 512;
+       int nr_sectors = 4 - (CURRENT -> sector & 3);
+       if (azt_buf_out != i) {
+         azt_buf_out = i;
+         if (azt_buf_bn[i] != bn) {
+           azt_buf_out = -1;
+           continue;
          }
+       }
+       if (nr_sectors > CURRENT -> nr_sectors)
+         nr_sectors = CURRENT -> nr_sectors;
+       memcpy(CURRENT -> buffer, azt_buf + offs, nr_sectors * 512);
+       CURRENT -> nr_sectors -= nr_sectors;
+       CURRENT -> sector += nr_sectors;
+       CURRENT -> buffer += nr_sectors * 512;
+      } else {
+       azt_buf_out = -1;
+       break;
+      }
+    }
+  }
+}
 
-
-#ifdef AZT_TEST3
-         printk("CURRENT_VALID %d azt_mode %d\n",
-            CURRENT_VALID, azt_mode);
+static void do_aztcd_request(void)
+{
+#ifdef AZT_TEST
+  printk(" do_aztcd_request(%ld+%ld) Time:%li\n", CURRENT -> sector, CURRENT -> nr_sectors,jiffies);
 #endif
-
-         if (CURRENT_VALID) {
-           if (st != -1) {
-             if (azt_mode == 1) {
-               azt_state = AZT_S_READ;
-               loop_ctl = 1;
-               skip = 1;
-               break;
-             } else {
-               azt_state = AZT_S_MODE;
-               loop_ctl = 1;
-               skip = 1;
-               break;
-             }
-           } else {
-             azt_state = AZT_S_START;
-             AztTimeout = 1;
-           }
-         } else {
-           azt_state = AZT_S_IDLE;
-           return;
+  if (DiskInfo.audio) 
+    { printk("aztcd: Error, tried to mount an Audio CD\n");
+      end_request(0);
+      return;
+    }
+  azt_transfer_is_active = 1;
+  while (CURRENT_VALID) {
+    if (CURRENT->bh) {
+      if (!buffer_locked(CURRENT->bh))
+       panic(DEVICE_NAME ": block not locked");
+    }
+    azt_transfer();
+    if (CURRENT -> nr_sectors == 0) {
+      end_request(1);
+    } else {
+      azt_buf_out = -1;         /* Want to read a block not in buffer */
+      if (azt_state == AZT_S_IDLE) {
+       if ((!aztTocUpToDate)||aztDiskChanged) {
+         if (aztUpdateToc() < 0) {
+           while (CURRENT_VALID)
+             end_request(0);
+           break;
          }
-         break;
-
-       default:
-         printk("aztcd: invalid state %d\n", azt_state);
-         return;
-      }  /* case */
-    } /* while */
-  
-
-   if (!AztTimeout--) 
-    { printk("aztcd: timeout in state %d\n", azt_state);
-      azt_state = AZT_S_STOP;
-      if (aztSendCmd(ACMD_STOP)) RETURN("azt_poll 6"); 
-      STEN_LOW_WAIT;     
-    };
-
-  SET_TIMER(azt_poll, HZ/100);
+       }
+       azt_state = AZT_S_START;
+       AztTries = 5;
+       SET_TIMER(azt_poll, HZ/100);
+      }
+      break;
+    }
+  }
+  azt_transfer_is_active = 0;
+#ifdef AZT_TEST2
+  printk("azt_next_bn:%x  azt_buf_in:%x azt_buf_out:%x  azt_buf_bn:%x\n", \
+         azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]);
+  printk(" do_aztcd_request ends  Time:%li\n",jiffies);
+#endif
 }
 
+
 static void azt_invalidate_buffers(void)
 { int i;
 
@@ -1531,21 +1566,6 @@ static void aztcd_release(struct inode * inode, struct file * file)
 }
 
 
-static struct file_operations azt_fops = {
-       NULL,                   /* lseek - default */
-       block_read,             /* read - general block-dev read */
-       block_write,            /* write - general block-dev write */
-       NULL,                   /* readdir - bad */
-       NULL,                   /* select */
-       aztcd_ioctl,            /* ioctl */
-       NULL,                   /* mmap */
-       aztcd_open,             /* open */
-       aztcd_release,          /* release */
-       NULL,                   /* fsync */
-       NULL,                   /* fasync*/
-       check_aztcd_media_change, /*media change*/
-       NULL                    /* revalidate*/
-};
 
 /*
  * Test for presence of drive and initialize it.  Called at boot time.
@@ -1703,432 +1723,482 @@ int aztcd_init(void)
         if ((azt_port==0x1f0)||(azt_port==0x170))  
           request_region(azt_port, 8, "aztcd");  /*IDE-interface*/
         else
-          request_region(azt_port, 4, "aztcd");  /*proprietary inferface*/
+          request_region(azt_port, 4, "aztcd");  /*proprietary interface*/
         
        azt_invalidate_buffers();
-       aztPresent = 1;
-       aztCloseDoor();
-/*     printk("aztcd: End Init\n");
-*/      return (0);
-}
-
-
-static void azt_hsg2msf(long hsg, struct msf *msf)
-{       hsg += 150;
-       msf -> min = hsg / 4500;
-       hsg %= 4500;
-       msf -> sec = hsg / 75;
-       msf -> frame = hsg % 75;
-#ifdef AZT_DEBUG
-       if (msf->min  >=70) printk("aztcd: Error hsg2msf address Minutes\n");
-       if (msf->sec  >=60) printk("aztcd: Error hsg2msf address Seconds\n");
-       if (msf->frame>=75) printk("aztcd: Error hsg2msf address Frames\n");
-#endif
-       azt_bin2bcd(&msf -> min);           /* convert to BCD */
-       azt_bin2bcd(&msf -> sec);
-       azt_bin2bcd(&msf -> frame);
-}
-
-static long azt_msf2hsg(struct msf *mp)
-{ return azt_bcd2bin(mp -> frame) + azt_bcd2bin(mp -> sec) * 75
-                                 + azt_bcd2bin(mp -> min) * 4500 - CD_BLOCK_OFFSET;
+       aztPresent = 1;
+       aztCloseDoor();
+/*     printk("aztcd: End Init\n");
+*/      return (0);
 }
 
-static void azt_bin2bcd(unsigned char *p)
-{       int u, t;
+#ifdef MODULE
 
-       u = *p % 10;
-       t = *p / 10;
-       *p = u | (t << 4);
+int init_module(void)
+{
+       return aztcd_init();
 }
 
-static int azt_bcd2bin(unsigned char bcd)
-{       return (bcd >> 4) * 10 + (bcd & 0xF);
-}
+void cleanup_module(void)
+{
+  if ((unregister_blkdev(MAJOR_NR, "aztcd") == -EINVAL))    
+    { printk("What's that: can't unregister aztcd\n");
+      return;
+    }
+  if ((azt_port==0x1f0)||(azt_port==0x170))  
+    { SWITCH_IDE_MASTER;
+      release_region(azt_port,8);  /*IDE-interface*/
+    }
+  else
+      release_region(azt_port,4);  /*proprietary interface*/
+  printk(KERN_INFO "aztcd module released.\n");
+}   
+#endif MODULE
 
-/*
- * Read a value from the drive.  Should return quickly, so a busy wait
- * is used to avoid excessive rescheduling. The read command itself must
- * be issued with aztSendCmd() directly before
- */
-static int aztGetValue(unsigned char *result)
-{       int s;
 
+/*##########################################################################
+  Aztcd State Machine: Controls Drive Operating State
+  ##########################################################################
+*/
+static void azt_poll(void)
+{
+    int st = 0;
+    int loop_ctl = 1;
+    int skip = 0;
+
+    if (azt_error) {                            
+       if (aztSendCmd(ACMD_GET_ERROR)) RETURN("azt_poll 1");
        STEN_LOW;
-       if (aztTimeOutCount>=AZT_TIMEOUT)
-       {       printk("aztcd: aztGetValue timeout\n");
-               return -1;
+       azt_error=inb(DATA_PORT)&0xFF;
+       printk("aztcd: I/O error 0x%02x\n", azt_error);
+       azt_invalidate_buffers();
+#ifdef WARN_IF_READ_FAILURE
+       if (AztTries == 5)
+         printk("aztcd: Read of Block %d Failed - Maybe Audio Disk?\n", azt_next_bn);
+#endif
+       if (!AztTries--) {
+         printk("aztcd: Read of Block %d Failed, Maybe Audio Disk? Giving up\n", azt_next_bn);
+         if (azt_transfer_is_active) {
+           AztTries = 0;
+           loop_ctl = 0;
+         }
+         if (CURRENT_VALID)
+           end_request(0);
+         AztTries = 5;
        }
-       s = inb(DATA_PORT) & 0xFF;
-       *result = (unsigned char) s;
-       return 0;
-}
-
+    azt_error = 0;
+    azt_state = AZT_S_STOP;
+    }
 
-/*
- * Read the current Q-channel info.  Also used for reading the
- * table of contents.
- */
-int aztGetQChannelInfo(struct azt_Toc *qp)
-{       unsigned char notUsed;
-       int st;
+    while (loop_ctl)
+    {
+      loop_ctl = 0;   /* each case must flip this back to 1 if we want
+                        to come back up here */
+      switch (azt_state) {
 
-#ifdef AZT_DEBUG
-       printk("aztcd: starting aztGetQChannelInfo  Time:%li\n",jiffies);
-#endif
-       if ((st=getAztStatus())==-1)        RETURNM("aztGetQChannelInfo 1",-1);
-       if (aztSendCmd(ACMD_GET_Q_CHANNEL)) RETURNM("aztGetQChannelInfo 2",-1);
-       /*STEN_LOW_WAIT; ??? Dosemu0.60's cdrom.c does not like STEN_LOW_WAIT here*/
-       if (aztGetValue(&notUsed)) RETURNM("aztGetQChannelInfo 3",-1); /*??? Nullbyte einlesen*/
-       if ((st&AST_MODE_BITS)==AST_INITIAL)
-        { qp->ctrl_addr=0;      /* when audio stop ACMD_GET_Q_CHANNEL returns */
-          qp->track=0;          /* only one byte with Aztech drives */
-          qp->pointIndex=0;
-          qp->trackTime.min=0;
-          qp->trackTime.sec=0;
-          qp->trackTime.frame=0;
-          qp->diskTime.min=0;
-          qp->diskTime.sec=0;
-          qp->diskTime.frame=0;
-          return 0;  
-        }
-       else
-        { if (aztGetValue(&qp -> ctrl_addr) < 0)       RETURNM("aztGetQChannelInfo 4",-1);
-          if (aztGetValue(&qp -> track) < 0)           RETURNM("aztGetQChannelInfo 4",-1);
-          if (aztGetValue(&qp -> pointIndex) < 0)      RETURNM("aztGetQChannelInfo 4",-1);
-          if (aztGetValue(&qp -> trackTime.min) < 0)   RETURNM("aztGetQChannelInfo 4",-1);
-          if (aztGetValue(&qp -> trackTime.sec) < 0)   RETURNM("aztGetQChannelInfo 4",-1);
-          if (aztGetValue(&qp -> trackTime.frame) < 0) RETURNM("aztGetQChannelInfo 4",-1);
-          if (aztGetValue(&notUsed) < 0)               RETURNM("aztGetQChannelInfo 4",-1);
-          if (aztGetValue(&qp -> diskTime.min) < 0)    RETURNM("aztGetQChannelInfo 4",-1);
-          if (aztGetValue(&qp -> diskTime.sec) < 0)    RETURNM("aztGetQChannelInfo 4",-1);
-          if (aztGetValue(&qp -> diskTime.frame) < 0)  RETURNM("aztGetQChannelInfo 4",-1);
-        }
-#ifdef AZT_DEBUG
-       printk("aztcd: exiting aztGetQChannelInfo  Time:%li\n",jiffies);
+       case AZT_S_IDLE:
+#ifdef AZT_TEST3
+         if (azt_state!=azt_state_old) {
+           azt_state_old=azt_state;
+           printk("AZT_S_IDLE\n");
+           }
 #endif
-       return 0;
-}
+         return;
 
-/*
- * Read the table of contents (TOC) and TOC header if necessary
- */
-static int aztUpdateToc()
-{       int st;
+       case AZT_S_START:
+#ifdef AZT_TEST3
+         if (azt_state!=azt_state_old) {
+           azt_state_old=azt_state;
+           printk("AZT_S_START\n");
+         }
+#endif
+         if(aztSendCmd(ACMD_GET_STATUS)) RETURN("azt_poll 2");  /*result will be checked by aztStatus() */
+         azt_state = azt_mode == 1 ? AZT_S_READ : AZT_S_MODE;
+         AztTimeout = 3000;
+         break;
 
-#ifdef AZT_DEBUG
-       printk("aztcd: starting aztUpdateToc  Time:%li\n",jiffies);
-#endif  
-       if (aztTocUpToDate)
-               return 0;
+       case AZT_S_MODE:
+#ifdef AZT_TEST3
+         if (azt_state!=azt_state_old) {
+           azt_state_old=azt_state;
+           printk("AZT_S_MODE\n");
+         }
+#endif
+         if (!skip) {
+           if ((st = aztStatus()) != -1) {
+             if ((st & AST_DSK_CHG)||(st & AST_NOT_READY)) {
+               aztDiskChanged = 1;
+               aztTocUpToDate = 0;
+               azt_invalidate_buffers();
+               end_request(0);
+               printk("aztcd: Disk Changed or Not Ready 1 - Unmount Disk!\n");
+             }
+           } else break;
+         }
+         skip = 0;
 
-       if (aztGetDiskInfo() < 0)
-               return -EIO;
+         if ((st & AST_DOOR_OPEN)||(st & AST_NOT_READY)) {
+           aztDiskChanged = 1;
+           aztTocUpToDate = 0;
+            printk("aztcd: Disk Changed or Not Ready 2 - Unmount Disk!\n");
+            end_request(0);
+           printk((st & AST_DOOR_OPEN) ? "aztcd: door open\n" : "aztcd: disk removed\n");
+           if (azt_transfer_is_active) {
+             azt_state = AZT_S_START;
+             loop_ctl = 1;   /* goto immediately */
+             break;
+           }
+           azt_state = AZT_S_IDLE;
+           while (CURRENT_VALID)
+             end_request(0);
+           return;
+         }
+                               
+/*       if (aztSendCmd(ACMD_SET_MODE)) RETURN("azt_poll 3");
+         outb(0x01, DATA_PORT);          
+         PA_OK;
+         STEN_LOW;
+*/        if (aztSendCmd(ACMD_GET_STATUS)) RETURN("azt_poll 4");
+         STEN_LOW;
+         azt_mode = 1;
+         azt_state = AZT_S_READ;
+         AztTimeout = 3000;
 
-       if (aztGetToc(0) < 0)
-               return -EIO;
+         break;
 
-        /*audio disk detection
-          with my Aztech drive there is no audio status bit, so I use the copy
-          protection bit of the first track. If this track is copy protected 
-          (copy bit = 0), I assume, it's an audio  disk. Strange, but works ??? */
-        if (!(Toc[DiskInfo.first].ctrl_addr & 0x40)) 
-           DiskInfo.audio=1;
-        else 
-           DiskInfo.audio=0;
 
-        /* XA detection */
-       if (! DiskInfo.audio) 
-          { azt_Play.start.min   = 0;  /*XA detection only seems to work*/
-             azt_Play.start.sec   = 2;  /*when we play a track*/
-            azt_Play.start.frame = 0;
-            azt_Play.end.min     = 0;
-            azt_Play.end.sec     = 0;
-            azt_Play.end.frame   = 1;
-            if (sendAztCmd(ACMD_PLAY_READ, &azt_Play)) return -1;
-            DTEN_LOW;
-            for (st=0;st<CD_FRAMESIZE;st++) inb(DATA_PORT);
-           } 
-        DiskInfo.xa = getAztStatus() & AST_MODE;
-        if (DiskInfo.xa) 
-           { printk("aztcd: XA support experimental - mail results to zimmerma@rz.fht-esslingen.de\n");
-           }
-        
-        /*multisession detection
-          support for multisession CDs is done automatically with Aztech drives,
-          we don't have to take care about TOC redirection; if we want the isofs
-          to take care about redirection, we have to set AZT_MULTISESSION to 1*/
-        DiskInfo.multi=0;
-#if AZT_MULTISESSION
-       if (DiskInfo.xa) 
-          { aztGetMultiDiskInfo(); /*here Disk.Info.multi is set*/
-          }
+       case AZT_S_READ:
+#ifdef AZT_TEST3
+         if (azt_state!=azt_state_old)  {
+           azt_state_old=azt_state;
+           printk("AZT_S_READ\n");
+         }
 #endif
-        if (DiskInfo.multi)
-           { DiskInfo.lastSession.min  = Toc[DiskInfo.next].diskTime.min;
-            DiskInfo.lastSession.sec  = Toc[DiskInfo.next].diskTime.sec;
-             DiskInfo.lastSession.frame= Toc[DiskInfo.next].diskTime.frame;
-             printk("aztcd: Multisession support experimental\n");
-           }
-        else
-           { DiskInfo.lastSession.min  = Toc[DiskInfo.first].diskTime.min;
-            DiskInfo.lastSession.sec  = Toc[DiskInfo.first].diskTime.sec;
-             DiskInfo.lastSession.frame= Toc[DiskInfo.first].diskTime.frame;
-           }
+         if (!skip) {
+             if ((st = aztStatus()) != -1) {
+               if ((st & AST_DSK_CHG)||(st & AST_NOT_READY)) {
+               aztDiskChanged = 1;
+               aztTocUpToDate = 0;
+               azt_invalidate_buffers();
+               printk("aztcd: Disk Changed or Not Ready 3 - Unmount Disk!\n");
+                end_request(0);               
+               }
+             } else break;
+         } 
+           
+         skip = 0;
+         if ((st & AST_DOOR_OPEN)||(st & AST_NOT_READY)) {
+           aztDiskChanged = 1;
+           aztTocUpToDate = 0;
+           printk((st & AST_DOOR_OPEN) ? "aztcd: door open\n" : "aztcd: disk removed\n");
+           if (azt_transfer_is_active) {
+             azt_state = AZT_S_START;
+             loop_ctl = 1;
+             break;
+           }
+           azt_state = AZT_S_IDLE;
+           while (CURRENT_VALID)
+           end_request(0);
+           return;
+         }
 
-       aztTocUpToDate = 1;
-#ifdef AZT_DEBUG
-       printk("aztcd: exiting aztUpdateToc  Time:%li\n",jiffies);
+         if (CURRENT_VALID) {
+           struct azt_Play_msf msf;
+           int i;
+           azt_next_bn = CURRENT -> sector / 4;
+           azt_hsg2msf(azt_next_bn, &msf.start);
+           i = 0;
+           /* find out in which track we are */
+           while (azt_msf2hsg(&msf.start)>azt_msf2hsg(&Toc[++i].trackTime)) {};
+           if (azt_msf2hsg(&msf.start)<azt_msf2hsg(&Toc[i].trackTime)-AZT_BUF_SIZ)
+               { azt_read_count=AZT_BUF_SIZ;  /*fast, because we read ahead*/
+               /*azt_read_count=CURRENT->nr_sectors;    slow, no read ahead*/
+               }
+           else /* don't read beyond end of track */           
+#if AZT_MULTISESSION 
+               { azt_read_count=(azt_msf2hsg(&Toc[i].trackTime)/4)*4-azt_msf2hsg(&msf.start);  
+                 if (azt_read_count < 0) azt_read_count=0;
+                if (azt_read_count > AZT_BUF_SIZ) azt_read_count=AZT_BUF_SIZ;
+                 printk("aztcd: warning - trying to read beyond end of track\n");
+/*               printk("%i %i %li %li\n",i,azt_read_count,azt_msf2hsg(&msf.start),azt_msf2hsg(&Toc[i].trackTime));
+*/             }
+#else
+              { azt_read_count=AZT_BUF_SIZ;
+              }
 #endif
-       return 0;
-}
+           msf.end.min = 0;
+           msf.end.sec = 0;            
+           msf.end.frame = azt_read_count ;/*Mitsumi here reads 0xffffff sectors*/
+#ifdef AZT_TEST3
+           printk("---reading msf-address %x:%x:%x  %x:%x:%x\n",msf.start.min,msf.start.sec,msf.start.frame,msf.end.min,msf.end.sec,msf.end.frame);
+           printk("azt_next_bn:%x  azt_buf_in:%x azt_buf_out:%x  azt_buf_bn:%x\n", \
+                   azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]);
+#endif 
+            if (azt_read_mode==AZT_MODE_2)
+               { sendAztCmd(ACMD_PLAY_READ_RAW, &msf); /*XA disks in raw mode*/
+               }
+            else
+               { sendAztCmd(ACMD_PLAY_READ, &msf);     /*others in cooked mode*/
+               }
+           azt_state = AZT_S_DATA;
+           AztTimeout = READ_TIMEOUT;
+         } else {
+           azt_state = AZT_S_STOP;
+           loop_ctl = 1;
+           break;
+         }
 
+         break;
 
-/* Read the table of contents header, i.e. no. of tracks and start of first 
- * track
- */
-static int aztGetDiskInfo()
-{ int limit;
-  unsigned char test;
-  struct azt_Toc qInfo;
 
-#ifdef AZT_DEBUG
-  printk("aztcd: starting aztGetDiskInfo  Time:%li\n",jiffies);
-#endif
-  if (aztSendCmd(ACMD_SEEK_TO_LEADIN)) RETURNM("aztGetDiskInfo 1",-1);
-  STEN_LOW_WAIT;
-  test=0;
-  for (limit=300;limit>0;limit--)
-   {  if (aztGetQChannelInfo(&qInfo)<0) RETURNM("aztGetDiskInfo 2",-1);
-      if (qInfo.pointIndex==0xA0)   /*Number of FirstTrack*/
-       { DiskInfo.first = qInfo.diskTime.min;
-         DiskInfo.first = azt_bcd2bin(DiskInfo.first);
-         test=test|0x01;
-       }
-      if (qInfo.pointIndex==0xA1)   /*Number of LastTrack*/
-       { DiskInfo.last  = qInfo.diskTime.min;
-         DiskInfo.last  = azt_bcd2bin(DiskInfo.last);
-         test=test|0x02;
-       }
-      if (qInfo.pointIndex==0xA2)   /*DiskLength*/
-       { DiskInfo.diskLength.min=qInfo.diskTime.min;
-         DiskInfo.diskLength.sec=qInfo.diskTime.sec;
-         DiskInfo.diskLength.frame=qInfo.diskTime.frame;
-         test=test|0x04;
-       }
-      if ((qInfo.pointIndex==DiskInfo.first)&&(test&0x01))   /*StartTime of First Track*/
-       { DiskInfo.firstTrack.min=qInfo.diskTime.min;
-         DiskInfo.firstTrack.sec=qInfo.diskTime.sec;
-         DiskInfo.firstTrack.frame=qInfo.diskTime.frame;
-         test=test|0x08;
-       }
-      if (test==0x0F) break;
-   }
-#ifdef AZT_DEBUG
-  printk ("aztcd: exiting aztGetDiskInfo  Time:%li\n",jiffies);
-  printk("Disk Info: first %d last %d length %02X:%02X.%02X dez  first %02X:%02X.%02X dez\n",
-         DiskInfo.first,
-         DiskInfo.last,
-         DiskInfo.diskLength.min,
-         DiskInfo.diskLength.sec,
-         DiskInfo.diskLength.frame,
-         DiskInfo.firstTrack.min,
-         DiskInfo.firstTrack.sec,
-         DiskInfo.firstTrack.frame);
+       case AZT_S_DATA:
+#ifdef AZT_TEST3
+         if (azt_state!=azt_state_old)  {
+           azt_state_old=azt_state;
+           printk("AZT_S_DATA\n");
+         }
 #endif
-  if (test!=0x0F) return -1;
-  return 0;
-}
 
-#if AZT_MULTISESSION
-/*
- * Get Multisession Disk Info
- */
-static int aztGetMultiDiskInfo(void)
-{ int limit, k=5;
-  unsigned char test;
-  struct azt_Toc qInfo;
+         st = inb(STATUS_PORT) & AFL_STATUSorDATA; 
 
-#ifdef AZT_DEBUG
-  printk("aztcd: starting aztGetMultiDiskInfo\n");
+         switch (st) {
+
+           case AFL_DATA:
+#ifdef AZT_TEST3
+             if (st!=azt_st_old)  {
+               azt_st_old=st; 
+               printk("---AFL_DATA st:%x\n",st);
+             }
 #endif
+             if (!AztTries--) {
+               printk("aztcd: Read of Block %d Failed, Maybe Audio Disk ? Giving up\n", azt_next_bn);
+               if (azt_transfer_is_active) {
+                 AztTries = 0;
+                 break;
+               }
+               if (CURRENT_VALID)
+                 end_request(0);
+               AztTries = 5;
+             }
+             azt_state = AZT_S_START;
+             AztTimeout = READ_TIMEOUT;
+             loop_ctl = 1;
+             break;
 
-  do { azt_Play.start.min   = Toc[DiskInfo.last+1].diskTime.min;
-       azt_Play.start.sec   = Toc[DiskInfo.last+1].diskTime.sec;
-       azt_Play.start.frame = Toc[DiskInfo.last+1].diskTime.frame;
-       test=0;
+           case AFL_STATUSorDATA:
+#ifdef AZT_TEST3
+             if (st!=azt_st_old)  {
+               azt_st_old=st;
+               printk("---AFL_STATUSorDATA st:%x\n",st);
+             }
+#endif
+             break;
 
-       for (limit=30;limit>0;limit--)   /*Seek for LeadIn of next session*/
-           { if (aztSeek(&azt_Play)) RETURNM("aztGetMultiDiskInfo 1",-1);
-             if (aztGetQChannelInfo(&qInfo)<0) RETURNM("aztGetMultiDiskInfo 2",-1);
-             if ((qInfo.track==0)&&(qInfo.pointIndex)) break;  /*LeadIn found*/
-             if ((azt_Play.start.sec+=10) > 59)
-                { azt_Play.start.sec=0;
-                  azt_Play.start.min++;
-                }
-           }
-       if (!limit) break;  /*Check, if a leadin track was found, if not we're
-                             at the end of the disk*/
-#ifdef AZT_DEBUG_MULTISESSION
-       printk("leadin found track %d  pointIndex %x  limit %d\n",qInfo.track,qInfo.pointIndex,limit);
+           default:
+#ifdef AZT_TEST3
+             if (st!=azt_st_old)  {
+               azt_st_old=st;
+               printk("---default: st:%x\n",st);
+             }
 #endif
-       for (limit=300;limit>0;limit--)
-           { if (++azt_Play.start.frame>74)
-                { azt_Play.start.frame=0;
-                  if (azt_Play.start.sec > 59)
-                     { azt_Play.start.sec=0;
-                       azt_Play.start.min++;
-                     }
-                }     
-             if (aztSeek(&azt_Play)) RETURNM("aztGetMultiDiskInfo 3",-1);
-             if (aztGetQChannelInfo(&qInfo)<0) RETURNM("aztGetMultiDiskInfo 4",-1);
-             if (qInfo.pointIndex==0xA0)   /*Number of NextTrack*/
-               { DiskInfo.next = qInfo.diskTime.min;
-                 DiskInfo.next = azt_bcd2bin(DiskInfo.next);
-                 test=test|0x01;
-               }
-             if (qInfo.pointIndex==0xA1)   /*Number of LastTrack*/
-               { DiskInfo.last  = qInfo.diskTime.min;
-                 DiskInfo.last  = azt_bcd2bin(DiskInfo.last);
-                 test=test|0x02;
-               }
-            if (qInfo.pointIndex==0xA2)   /*DiskLength*/
-               { DiskInfo.diskLength.min  =qInfo.diskTime.min;
-                 DiskInfo.diskLength.sec  =qInfo.diskTime.sec;
-                 DiskInfo.diskLength.frame=qInfo.diskTime.frame;
-                 test=test|0x04;
-               }
-            if ((qInfo.pointIndex==DiskInfo.next)&&(test&0x01))   /*StartTime of Next Track*/
-               { DiskInfo.nextSession.min=qInfo.diskTime.min;
-                 DiskInfo.nextSession.sec=qInfo.diskTime.sec;
-                 DiskInfo.nextSession.frame=qInfo.diskTime.frame;
-                 test=test|0x08;
-               }
-            if (test==0x0F) break;
-          }
-#ifdef AZT_DEBUG_MULTISESSION
-       printk ("MultiDisk Info: first %d next %d last %d length %02x:%02x.%02x dez  first %02x:%02x.%02x dez  next %02x:%02x.%02x dez\n",
-               DiskInfo.first,
-               DiskInfo.next,
-               DiskInfo.last,
-               DiskInfo.diskLength.min,
-               DiskInfo.diskLength.sec,
-               DiskInfo.diskLength.frame,
-               DiskInfo.firstTrack.min,
-               DiskInfo.firstTrack.sec,
-               DiskInfo.firstTrack.frame,
-               DiskInfo.nextSession.min,
-               DiskInfo.nextSession.sec,
-               DiskInfo.nextSession.frame);
+             AztTries = 5;
+             if (!CURRENT_VALID && azt_buf_in == azt_buf_out) {
+               azt_state = AZT_S_STOP;
+               loop_ctl = 1;
+               break;
+             }
+             if (azt_read_count<=0)
+               printk("aztcd: warning - try to read 0 frames\n");
+             while (azt_read_count)      /*??? fast read ahead loop*/
+              { azt_buf_bn[azt_buf_in] = -1;
+                DTEN_LOW;                      /*??? unsolved problem, very
+                                                     seldom we get timeouts
+                                                     here, don't now the real
+                                                     reason. With my drive this
+                                                     sometimes also happens with
+                                                     Aztech's original driver under
+                                                     DOS. Is it a hardware bug? 
+                                                     I tried to recover from such
+                                                     situations here. Zimmermann*/
+                if (aztTimeOutCount>=AZT_TIMEOUT) 
+                 { printk("read_count:%d CURRENT->nr_sectors:%ld azt_buf_in:%d\n", azt_read_count,CURRENT->nr_sectors,azt_buf_in);
+                   printk("azt_transfer_is_active:%x\n",azt_transfer_is_active);
+                   azt_read_count=0;
+                   azt_state = AZT_S_STOP;
+                   loop_ctl = 1;
+                   end_request(1);  /*should we have here (1) or (0)? */
+                 }
+                else
+                 { if (azt_read_mode==AZT_MODE_2)
+                      { insb(DATA_PORT, azt_buf + CD_FRAMESIZE_RAW * azt_buf_in, CD_FRAMESIZE_RAW);
+                      }
+                   else
+                      { insb(DATA_PORT, azt_buf + CD_FRAMESIZE * azt_buf_in, CD_FRAMESIZE);
+                       }
+                   azt_read_count--;
+#ifdef AZT_TEST3
+                   printk("AZT_S_DATA; ---I've read data- read_count: %d\n",azt_read_count);
+                   printk("azt_next_bn:%d  azt_buf_in:%d azt_buf_out:%d  azt_buf_bn:%d\n", \
+                        azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]);
 #endif
-       if (test!=0x0F) 
-           break;
-       else 
-           DiskInfo.multi=1;   /*found TOC of more than one session*/
-       aztGetToc(1);
-     } while(--k);
+                   azt_buf_bn[azt_buf_in] = azt_next_bn++;
+                   if (azt_buf_out == -1)
+                     azt_buf_out = azt_buf_in;
+                   azt_buf_in = azt_buf_in + 1 == AZT_BUF_SIZ ? 0 : azt_buf_in + 1;
+                 }
+              }
+             if (!azt_transfer_is_active) {
+               while (CURRENT_VALID) {
+                 azt_transfer();
+                 if (CURRENT -> nr_sectors == 0)
+                   end_request(1);
+                 else
+                   break;
+               }
+             }
 
-#ifdef AZT_DEBUG
-  printk ("aztcd: exiting aztGetMultiDiskInfo  Time:%li\n",jiffies);
-#endif
-  return 0;
-}
-#endif
+             if (CURRENT_VALID
+               && (CURRENT -> sector / 4 < azt_next_bn ||
+               CURRENT -> sector / 4 > azt_next_bn + AZT_BUF_SIZ)) {
+               azt_state = AZT_S_STOP;
+               loop_ctl = 1;
+               break;
+             }
+             AztTimeout = READ_TIMEOUT;   
+             if (azt_read_count==0) {
+               azt_state = AZT_S_STOP; 
+               loop_ctl = 1;
+               break;           
+             } 
+             break;
+           }
+    break;
 
-/*
- * Read the table of contents (TOC)
- */
-static int aztGetToc(int multi)
-{ int i, px;
-  int limit;
-  struct azt_Toc qInfo;
 
-#ifdef AZT_DEBUG
-  printk("aztcd: starting aztGetToc  Time:%li\n",jiffies);
+       case AZT_S_STOP:
+#ifdef AZT_TEST3
+         if (azt_state!=azt_state_old) {
+           azt_state_old=azt_state;
+           printk("AZT_S_STOP\n");
+         }
 #endif
-  if (!multi)
-     { for (i = 0; i < MAX_TRACKS; i++)
-           Toc[i].pointIndex = 0;
-       i = DiskInfo.last + 3;
-     }
-  else
-     { for (i = DiskInfo.next; i < MAX_TRACKS; i++)
-           Toc[i].pointIndex = 0; 
-       i = DiskInfo.last + 4 - DiskInfo.next;
-     }
+         if (azt_read_count!=0) printk("aztcd: discard data=%x frames\n",azt_read_count);
+         while (azt_read_count!=0) {
+           int i;
+           if ( !(inb(STATUS_PORT) & AFL_DATA) ) {
+             if (azt_read_mode==AZT_MODE_2)
+                for (i=0; i<CD_FRAMESIZE_RAW; i++) inb(DATA_PORT);
+             else   
+                for (i=0; i<CD_FRAMESIZE; i++) inb(DATA_PORT);
+           }
+           azt_read_count--;
+         }  
+         if (aztSendCmd(ACMD_GET_STATUS)) RETURN("azt_poll 5");
+         azt_state = AZT_S_STOPPING;
+         AztTimeout = 1000;
+         break;
 
-/*Is there a good reason to stop motor before TOC read?
-  if (aztSendCmd(ACMD_STOP)) RETURNM("aztGetToc 1",-1);
-      STEN_LOW_WAIT;
-*/
+       case AZT_S_STOPPING:
+#ifdef AZT_TEST3
+         if (azt_state!=azt_state_old) {
+           azt_state_old=azt_state;
+           printk("AZT_S_STOPPING\n");
+         }
+#endif
 
-  if (!multi)
-     { azt_mode = 0x05;
-       if (aztSendCmd(ACMD_SEEK_TO_LEADIN)) RETURNM("aztGetToc 2",-1);
-       STEN_LOW_WAIT;
-     }
-  for (limit = 300; limit > 0; limit--)
-      { if (multi)
-           { if (++azt_Play.start.sec > 59)
-                { azt_Play.start.sec=0;
-                  azt_Play.start.min++;
-                }
-             if (aztSeek(&azt_Play)) RETURNM("aztGetToc 3",-1);
-           }
-       if (aztGetQChannelInfo(&qInfo) < 0)
+         if ((st = aztStatus()) == -1 && AztTimeout)
            break;
 
-       px = azt_bcd2bin(qInfo.pointIndex);
+         if ((st != -1) && ((st & AST_DSK_CHG)||(st & AST_NOT_READY))) {
+           aztDiskChanged = 1;
+           aztTocUpToDate = 0;
+           azt_invalidate_buffers();
+           printk("aztcd: Disk Changed or Not Ready 4 - Unmount Disk!\n");
+           end_request(0);
+         }
 
-       if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
-           if (Toc[px].pointIndex == 0)
-              { Toc[px] = qInfo;
-                i--;
-              }
 
-       if (i <= 0)
-           break;
-      }
+#ifdef AZT_TEST3
+         printk("CURRENT_VALID %d azt_mode %d\n",
+            CURRENT_VALID, azt_mode);
+#endif
 
-  Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
-  Toc[DiskInfo.last].trackTime    = DiskInfo.diskLength;
+         if (CURRENT_VALID) {
+           if (st != -1) {
+             if (azt_mode == 1) {
+               azt_state = AZT_S_READ;
+               loop_ctl = 1;
+               skip = 1;
+               break;
+             } else {
+               azt_state = AZT_S_MODE;
+               loop_ctl = 1;
+               skip = 1;
+               break;
+             }
+           } else {
+             azt_state = AZT_S_START;
+             AztTimeout = 1;
+           }
+         } else {
+           azt_state = AZT_S_IDLE;
+           return;
+         }
+         break;
 
-#ifdef AZT_DEBUG_MULTISESSION 
-  printk("aztcd: exiting aztGetToc\n");
-  for (i = 1; i <= DiskInfo.last+1; i++)
-       printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X dez  %02X:%02X.%02X dez\n",
-               i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
-               Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
-               Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
-  for (i = 100; i < 103; i++)
-       printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X dez  %02X:%02X.%02X dez\n",
-               i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
-               Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
-               Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
+       default:
+         printk("aztcd: invalid state %d\n", azt_state);
+         return;
+      }  /* case */
+    } /* while */
+  
+
+   if (!AztTimeout--) 
+    { printk("aztcd: timeout in state %d\n", azt_state);
+      azt_state = AZT_S_STOP;
+      if (aztSendCmd(ACMD_STOP)) RETURN("azt_poll 6"); 
+      STEN_LOW_WAIT;     
+    };
+
+  SET_TIMER(azt_poll, HZ/100);
+}
+
+
+/*###########################################################################
+ * Miscellaneous support functions
+  ###########################################################################
+*/
+static void azt_hsg2msf(long hsg, struct msf *msf)
+{       hsg += 150;
+       msf -> min = hsg / 4500;
+       hsg %= 4500;
+       msf -> sec = hsg / 75;
+       msf -> frame = hsg % 75;
+#ifdef AZT_DEBUG
+       if (msf->min  >=70) printk("aztcd: Error hsg2msf address Minutes\n");
+       if (msf->sec  >=60) printk("aztcd: Error hsg2msf address Seconds\n");
+       if (msf->frame>=75) printk("aztcd: Error hsg2msf address Frames\n");
 #endif
+       azt_bin2bcd(&msf -> min);           /* convert to BCD */
+       azt_bin2bcd(&msf -> sec);
+       azt_bin2bcd(&msf -> frame);
+}
 
-  return limit > 0 ? 0 : -1;
+static long azt_msf2hsg(struct msf *mp)
+{ return azt_bcd2bin(mp -> frame) + azt_bcd2bin(mp -> sec) * 75
+                                 + azt_bcd2bin(mp -> min) * 4500 - CD_BLOCK_OFFSET;
 }
 
-#ifdef MODULE
+static void azt_bin2bcd(unsigned char *p)
+{       int u, t;
 
-int init_module(void)
-{
-       return aztcd_init();
+       u = *p % 10;
+       t = *p / 10;
+       *p = u | (t << 4);
 }
 
-void cleanup_module(void)
-{
-  if ((unregister_blkdev(MAJOR_NR, "aztcd") == -EINVAL))    
-    { printk("What's that: can't unregister aztcd\n");
-      return;
-    }
-  if ((azt_port==0x1f0)||(azt_port==0x170))  
-    { SWITCH_IDE_MASTER;
-      release_region(azt_port,8);  /*IDE-interface*/
-    }
-  else
-      release_region(azt_port,4);  /*proprietary interface*/
-  printk(KERN_INFO "aztcd module released.\n");
-}   
-#endif MODULE
+static int azt_bcd2bin(unsigned char bcd)
+{       return (bcd >> 4) * 10 + (bcd & 0xF);
+}
+
+
index 4a5e82bd0141d9d1d57913becece66255a481990..d517ac47cd04f7103c474bae8006bbf3cedeb4bd 100644 (file)
@@ -1,3 +1,34 @@
+Wed Apr 24 14:02:04 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+       * random.c (add_timer_randomness): Use 2nd derivitive as well to
+               better estimate entropy.
+
+               (rand_initialize): Explicitly initialize all the pointers
+               to NULL.  (Clearing pointers using memset isn't portable.)
+               Initialize the random pool with OS-dependent data.
+
+               (random_write): Add sanity checking to the arguments to
+               random_write(), so that bad arguments won't cause a kernel
+               SEGV. 
+
+               (random_read): Update the access time of the device inode
+               when you return data to the user.
+
+               (random_ioctl): Wake up the random_wait channel when there
+               are only WAIT_INPUT_BITS available.  Add more paranoia
+               checks to make sure entropy_count doesn't go beyond the
+               bounds of (0, POOLSIZE).  Add a few missing verify_area
+               checks.  Add support for the RNDCLEARPOOL ioctl, which
+               zaps the random pool.
+
+               (add_timer_randomness): Wake up the random_wait
+               channel only when there are WAIT_INPUT_BITS available.
+
+               (random_select): Allow a random refresh daemon process to
+               select on /dev/random for writing; wake up the daemon when
+               there are less than WAIT_OUTPUT_BITS bits of randomness
+               available.
+
 Tue Apr 23 22:56:07 1996    <tytso@rsts-11.mit.edu>
 
        * tty_io.c (init_dev): Change return code when user attempts to
index c0256442c929a81d7473847c6d88463a47c6a947..4a1f1d50535e6befa513d7c378e73035f04efea2 100644 (file)
@@ -46,10 +46,11 @@ if [ "$CONFIG_APM" = "y" ]; then
   bool '   Enable PM at boot time' CONFIG_APM_DO_ENABLE
   bool '   Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE
   bool '   Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK
+  bool '   Power off on shutdown' CONFIG_APM_POWER_OFF
 fi
 bool 'Watchdog Timer Support'  CONFIG_WATCHDOG
 if [ "$CONFIG_WATCHDOG" != "n" ]; then
-  bool '    Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
+  bool '   Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
   tristate '   WDT Watchdog timer' CONFIG_WDT
   if [ "$CONFIG_WDT" = "y" ]; then
      bool '       WDT501 features' CONFIG_WDT_501
index 2e3b58207b781002a71b0849f6e648c9dff4c0a0..4864f77fab0892389c0553b2ad3f8fcd4f793110 100644 (file)
  *    Prohibit APM BIOS calls unless apm_enabled.
  *    (Thanks to Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de>)
  * April 1996, Stephen Rothwell (Stephen.Rothwell@canb.auug.org.au)
- *    Version 1.0
+ *    Version 1.0 and 1.1
  *
  * History:
  *    0.6b: first version in official kernel, Linux 1.3.46
  *    0.7: changed /proc/apm format, Linux 1.3.58
  *    0.8: fixed gcc 2.7.[12] compilation problems, Linux 1.3.59
  *    0.9: only call bios if bios is present, Linux 1.3.72
- *    1.0: use fixed device number, consolidate /proc/apm into
- *         this file, Linux 1.3.85
+ *    1.0: use fixed device number, consolidate /proc/apm into this file,
+ *         Linux 1.3.85
+ *    1.1: support user-space standby and suspend, power off after system
+ *         halted, Linux 1.3.98
  *
  * Reference:
  *
@@ -113,7 +115,9 @@ extern unsigned long get_cmos_time(void);
  * CONFIG_APM_DISPLAY_BLANK: enable console blanking using the APM.  Some
  * laptops can use this to turn of the LCD backlight when the VC screen
  * blanker blanks the screen.  Note that this is only used by the VC screen
- * blanker, and probably won't turn off the backlight when using X11.
+ * blanker, and probably won't turn off the backlight when using X11.  Some
+ * problems have been reported when using this option with gpm (if you'd
+ * like to debug this, please do so).
  *
  * If you are debugging the APM support for your laptop, note that code for
  * all of these options is contained in this file, so you can #define or
@@ -330,7 +334,7 @@ static struct apm_bios_struct *     user_list = NULL;
 
 static struct timer_list       apm_timer;
 
-static char                    driver_version[] = "1.0";/* no spaces */
+static char                    driver_version[] = "1.1";/* no spaces */
 
 #ifdef APM_DEBUG
 static char *  apm_event_name[] = {
@@ -427,7 +431,7 @@ static int apm_get_event(apm_event_t *event)
        return APM_SUCCESS;
 }
 
-static int apm_set_power_state(u_short state)
+int apm_set_power_state(u_short state)
 {
        u_short error;
 
@@ -567,13 +571,15 @@ static apm_event_t get_queued_event(struct apm_bios_struct * as)
        return as->events[as->event_tail];
 }
 
-static int queue_event(apm_event_t event)
+static int queue_event(apm_event_t event, struct apm_bios_struct *sender)
 {
        struct apm_bios_struct *        as;
        
        if (user_list == NULL)
                return 0;
        for (as = user_list; as != NULL; as = as->next) {
+               if (as == sender)
+                       continue;
                as->event_head = (as->event_head + 1) % APM_MAX_EVENTS;
                if (as->event_head == as->event_tail)
                        as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
@@ -656,7 +662,8 @@ static apm_event_t get_event(void)
        return 0;
 }
 
-static void send_event(apm_event_t event, apm_event_t undo)
+static void send_event(apm_event_t event, apm_event_t undo,
+                      struct apm_bios_struct *sender)
 {
        callback_list_t *       call;
        callback_list_t *       fix;
@@ -671,7 +678,7 @@ static void send_event(apm_event_t event, apm_event_t undo)
                }
        }
 
-       queue_event(event);
+       queue_event(event, sender);
 }
 
 static void check_events(void)
@@ -682,18 +689,19 @@ static void check_events(void)
                switch (event) {
                case APM_SYS_STANDBY:
                case APM_USER_STANDBY:
-                       send_event(event, APM_STANDBY_RESUME);
+                       send_event(event, APM_STANDBY_RESUME, NULL);
                        if (standbys_pending <= 0)
                                standby();
                        break;
 
                case APM_USER_SUSPEND:
 #ifdef CONFIG_APM_IGNORE_USER_SUSPEND
-                       apm_set_power_state(APM_STATE_REJECT);
+                       if (apm_bios_info.version > 0x100)
+                               apm_set_power_state(APM_STATE_REJECT);
                        break;
 #endif
                case APM_SYS_SUSPEND:
-                       send_event(event, APM_NORMAL_RESUME);
+                       send_event(event, APM_NORMAL_RESUME, NULL);
                        if (suspends_pending <= 0)
                                suspend();
                        break;
@@ -702,12 +710,12 @@ static void check_events(void)
                case APM_CRITICAL_RESUME:
                case APM_STANDBY_RESUME:
                        set_time();
-                       send_event(event, 0);
+                       send_event(event, 0, NULL);
                        break;
 
                case APM_LOW_BATTERY:
                case APM_POWER_STATUS_CHANGE:
-                       send_event(event, 0);
+                       send_event(event, 0, NULL);
                        break;
 
                case APM_UPDATE_TIME:
@@ -833,6 +841,17 @@ repeat:
        while ((i >= sizeof(event)) && !queue_empty(as)) {
                event = get_queued_event(as);
                memcpy_tofs(buf, &event, sizeof(event));
+               switch (event) {
+               case APM_SYS_SUSPEND:
+               case APM_USER_SUSPEND:
+                       as->suspends_read++;
+                       break;
+
+               case APM_SYS_STANDBY:
+               case APM_USER_STANDBY:
+                       as->standbys_read++;
+                       break;
+               }
                buf += sizeof(event);
                i -= sizeof(event);
        }
@@ -867,22 +886,30 @@ static int do_ioctl(struct inode * inode, struct file *filp,
        as = filp->private_data;
        if (check_apm_bios_struct(as, "ioctl"))
                return -EIO;
+       if (!as->suser)
+               return -EPERM;
        switch (cmd) {
        case APM_IOC_STANDBY:
-               if (as->standbys_pending > 0) {
+               if (as->standbys_read > 0) {
+                       as->standbys_read--;
                        as->standbys_pending--;
                        standbys_pending--;
-                       if (standbys_pending <= 0)
-                               standby();
                }
+               else
+                       send_event(APM_USER_STANDBY, APM_STANDBY_RESUME, as);
+               if (standbys_pending <= 0)
+                       standby();
                break;
        case APM_IOC_SUSPEND:
-               if (as->suspends_pending > 0) {
+               if (as->suspends_read > 0) {
+                       as->suspends_read--;
                        as->suspends_pending--;
                        suspends_pending--;
-                       if (suspends_pending <= 0)
-                               suspend();
                }
+               else
+                       send_event(APM_USER_SUSPEND, APM_NORMAL_RESUME, as);
+               if (suspends_pending <= 0)
+                       suspend();
                break;
        default:
                return -EINVAL;
@@ -938,6 +965,7 @@ static int do_open(struct inode * inode, struct file * filp)
        as->magic = APM_BIOS_MAGIC;
        as->event_tail = as->event_head = 0;
        as->suspends_pending = as->standbys_pending = 0;
+       as->suspends_read = as->standbys_read = 0;
        as->suser = suser();
        as->next = user_list;
        user_list = as;
index 1c4742fdd4773b6b5dd3f994a68419fbb1042244..deb7c3544c0169cbc3416483da95c165eb944026 100644 (file)
@@ -183,14 +183,14 @@ static inline int lp_write_interrupt(unsigned int minor, const char * buf, int c
                                if (lp_table[minor].runchars > LP_STAT(minor).maxrun)
                                         LP_STAT(minor).maxrun = lp_table[minor].runchars;
                                status = LP_S(minor);
-                               if ((status & LP_POUTPA)) {
-                                       printk(KERN_INFO "lp%d out of paper\n", minor);
-                                       if (LP_F(minor) & LP_ABORT)
-                                               return rc?rc:-ENOSPC;
-                               } else if (!(status & LP_PSELECD)) {
+                               if ((status & LP_OFFL) || !(status & LP_PSELECD)) {
                                        printk(KERN_INFO "lp%d off-line\n", minor);
                                        if (LP_F(minor) & LP_ABORT)
                                                return rc?rc:-EIO;
+                               } else if ((status & LP_POUTPA)) {
+                                       printk(KERN_INFO "lp%d out of paper\n", minor);
+                                       if (LP_F(minor) & LP_ABORT)
+                                               return rc?rc:-ENOSPC;
                                } else if (!(status & LP_PERRORP)) {
                                        printk(KERN_ERR "lp%d printer error\n", minor);
                                        if (LP_F(minor) & LP_ABORT)
@@ -248,18 +248,18 @@ static inline int lp_write_polled(unsigned int minor, const char * buf, int coun
                                 LP_STAT(minor).maxrun = lp_table[minor].runchars;
                        status = LP_S(minor);
 
-                       if (status & LP_POUTPA) {
-                               printk(KERN_INFO "lp%d out of paper\n", minor);
+                       if ((status & LP_OFFL) || !(status & LP_PSELECD)) {
+                               printk(KERN_INFO "lp%d off-line\n", minor);
                                if(LP_F(minor) & LP_ABORT)
-                                       return temp-buf?temp-buf:-ENOSPC;
+                                       return temp-buf?temp-buf:-EIO;
                                current->state = TASK_INTERRUPTIBLE;
                                current->timeout = jiffies + LP_TIMEOUT_POLLED;
                                schedule();
                        } else
-                       if (!(status & LP_PSELECD)) {
-                               printk(KERN_INFO "lp%d off-line\n", minor);
+                       if (status & LP_POUTPA) {
+                               printk(KERN_INFO "lp%d out of paper\n", minor);
                                if(LP_F(minor) & LP_ABORT)
-                                       return temp-buf?temp-buf:-EIO;
+                                       return temp-buf?temp-buf:-ENOSPC;
                                current->state = TASK_INTERRUPTIBLE;
                                current->timeout = jiffies + LP_TIMEOUT_POLLED;
                                schedule();
index cb7996de9cae34bb0ad45064ac44bb107e7a6d7d..262d3201fab7b9a8d1f5a469a3e587581299593f 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * random.c -- A strong random number generator
  *
- * Version 0.96, last modified 29-Dec-95
+ * Version 0.97, last modified 24-Apr-96
  * 
- * Copyright Theodore Ts'o, 1994, 1995.  All rights reserved.
+ * Copyright Theodore Ts'o, 1994, 1995, 1996.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * particular randomness source.  They do this by keeping track of the
  * first and second order deltas of the event timings.
  *
+ * Ensuring unpredictability at system startup
+ * ============================================
+ * 
+ * When any operating system starts up, it will go through a sequence
+ * of actions that are fairly predictable by an adversary, especially
+ * if the start-up does not involve interaction with a human operator.
+ * This reduces the actual number of bits of unpredictability in the
+ * entropy pool below the value in entropy_count.  In order to
+ * counteract this effect, it helps to carry information in the
+ * entropy pool across shut-downs and start-ups.  To do this, put the
+ * following lines an appropriate script which is run during the boot
+ * sequence: 
+ *
+ *     echo "Initializing random number generator..."
+ *     # Carry a random seed from start-up to start-up
+ *     # Load and then save 512 bytes, which is the size of the entropy pool
+ *     if [ -f /etc/random-seed ]; then
+ *             cat /etc/random-seed >/dev/urandom
+ *     fi
+ *     dd if=/dev/urandom of=/etc/random-seed count=1
+ *
+ * and the following lines in an approproate script which is run as
+ * the system is shutdown:
+ * 
+ *     # Carry a random seed from shut-down to start-up
+ *     # Save 512 bytes, which is the size of the entropy pool
+ *     echo "Saving random seed..."
+ *     dd if=/dev/urandom of=/etc/random-seed count=1
+ * 
+ * For example, on many Linux systems, the appropriate scripts are
+ * usually /etc/rc.d/rc.local and /etc/rc.d/rc.0, respectively.
+ * 
+ * Effectively, these commands cause the contents of the entropy pool
+ * to be saved at shut-down time and reloaded into the entropy pool at
+ * start-up.  (The 'dd' in the addition to the bootup script is to
+ * make sure that /etc/random-seed is different for every start-up,
+ * even if the system crashes without executing rc.0.)  Even with
+ * complete knowledge of the start-up activities, predicting the state
+ * of the entropy pool requires knowledge of the previous history of
+ * the system.
+ *
+ * Configuring the /dev/random driver under Linux
+ * ==============================================
+ *
+ * The /dev/random driver under Linux uses minor numbers 8 and 9 of
+ * the /dev/mem major number (#1).  So if your system does not have
+ * /dev/random and /dev/urandom created already, they can be created
+ * by using the commands:
+ *
+ *     mknod /dev/random c 1 8
+ *     mknod /dev/urandom c 1 9
+ * 
  * Acknowledgements:
  * =================
  *
  * entropy pool, taken from PGP 3.0 (under development).  It has since
  * been modified by myself to provide better mixing in the case where
  * the input values to add_entropy_word() are mostly small numbers.
+ * Dale Worley has also contributed many useful ideas and suggestions
+ * to improve this driver.
  * 
  * Any flaws in the design are solely my responsibility, and should
  * not be attributed to the Phil, Colin, or any of authors of PGP.
  */
 
 #include <linux/sched.h>
+#include <linux/utsname.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/string.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 
+/*
+ * Configuration information
+ */
+
 /*
  * The pool is stirred with a primitive polynomial of degree 128
  * over GF(2), namely x^128 + x^99 + x^59 + x^31 + x^9 + x^7 + 1.
 #error No primitive polynomial available for chosen POOLWORDS
 #endif
 
+/*
+ * The minimum number of bits to release a "wait on input".  Should
+ * probably always be 8, since a /dev/random read can return a single
+ * byte.
+ */
+#define WAIT_INPUT_BITS 8
+/* 
+ * The limit number of bits under which to release a "wait on
+ * output".  Should probably always be the same as WAIT_INPUT_BITS, so
+ * that an output wait releases when and only when a wait on input
+ * would block.
+ */
+#define WAIT_OUTPUT_BITS WAIT_INPUT_BITS
+
 /* There is actually only one of these, globally. */
 struct random_bucket {
        unsigned add_ptr;
@@ -218,7 +291,7 @@ struct random_bucket {
 /* There is one of these per entropy source */
 struct timer_rand_state {
        unsigned long   last_time;
-       int             last_delta;
+       int             last_delta,last_delta2;
        int             dont_count_entropy:1;
 };
 
@@ -242,18 +315,55 @@ static int random_write(struct inode * inode, struct file * file,
 static int random_ioctl(struct inode * inode, struct file * file,
                        unsigned int cmd, unsigned long arg);
 
+static inline void add_entropy_word(struct random_bucket *r,
+                                   const __u32 input);
 
 #ifndef MIN
 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
 #endif
        
-void rand_initialize(void)
+/*
+ * Initialize the random pool with standard stuff.
+ *
+ * NOTE: This is an OS-dependent function.
+ */
+static void init_std_data(struct random_bucket *r)
+{
+       __u32 word, *p;
+       int i;
+       
+       add_entropy_word(r, xtime.tv_sec);
+       add_entropy_word(r, xtime.tv_usec);
+
+       for (p = (__u32 *) &system_utsname,
+            i = sizeof(system_utsname) / sizeof(__u32);
+            i ; i--, p++) {
+               memcpy(&word, p, sizeof(__u32));
+               add_entropy_word(r, word);
+       }
+       
+}
+
+/* Clear the entropy pool and associated counters. */
+static void rand_clear_pool(void)
 {
        random_state.add_ptr = 0;
        random_state.entropy_count = 0;
        random_state.pool = random_pool;
-       memset(irq_timer_state, 0, sizeof(irq_timer_state));
-       memset(blkdev_timer_state, 0, sizeof(blkdev_timer_state));
+       random_state.input_rotate = 0;
+       memset(random_pool, 0, sizeof(random_pool));
+       init_std_data(&random_state);
+}
+
+void rand_initialize(void)
+{
+       int i;
+
+       rand_clear_pool();
+       for (i = 0; i < NR_IRQS; i++)
+               irq_timer_state[i] = NULL;
+       for (i = 0; i < MAX_BLKDEV; i++)
+               blkdev_timer_state[i] = NULL;
        extract_timer_state.dont_count_entropy = 1;
        random_wait = NULL;
 }
@@ -353,7 +463,7 @@ static inline void add_entropy_word(struct random_bucket *r,
 static void add_timer_randomness(struct random_bucket *r,
                                 struct timer_rand_state *state, unsigned num)
 {
-       int     delta, delta2;
+       int     delta, delta2, delta3;
        unsigned        nbits;
        __u32           time;
 
@@ -397,24 +507,30 @@ static void add_timer_randomness(struct random_bucket *r,
        if (!state->dont_count_entropy) {
                delta = time - state->last_time;
                state->last_time = time;
+               if (delta < 0) delta = -delta;
 
                delta2 = delta - state->last_delta;
                state->last_delta = delta;
-
-               if (delta < 0) delta = -delta;
                if (delta2 < 0) delta2 = -delta2;
-               delta = MIN(delta, delta2) >> 1;
+
+               delta3 = delta2 - state->last_delta2;
+               state->last_delta2 = delta2;
+               if (delta3 < 0) delta3 = -delta3;
+
+               delta = MIN(MIN(delta, delta2), delta3) >> 1;
                for (nbits = 0; delta; nbits++)
                        delta >>= 1;
 
                r->entropy_count += nbits;
-       
+
                /* Prevent overflow */
                if (r->entropy_count > POOLBITS)
                        r->entropy_count = POOLBITS;
        }
                
-       wake_up_interruptible(&random_wait);    
+       /* Wake up waiting processes, if we have enough entropy. */
+       if (r->entropy_count >= WAIT_INPUT_BITS)
+               wake_up_interruptible(&random_wait);    
 }
 
 void add_keyboard_randomness(unsigned char scancode)
@@ -450,6 +566,152 @@ void add_blkdev_randomness(int major)
                             0x200+major);
 }
 
+#define USE_SHA
+
+#ifdef USE_SHA
+
+#define HASH_BUFFER_SIZE 5
+#define HASH_TRANSFORM SHATransform
+
+/*
+ * SHA transform algorith, taken from code written by Peter Gutman,
+ * and apparently in the public domain.
+ */
+
+/* The SHA f()-functions.  */
+
+#define f1(x,y,z)   ( z ^ ( x & ( y ^ z ) ) )           /* Rounds  0-19 */
+#define f2(x,y,z)   ( x ^ y ^ z )                       /* Rounds 20-39 */
+#define f3(x,y,z)   ( ( x & y ) | ( z & ( x | y ) ) )   /* Rounds 40-59 */
+#define f4(x,y,z)   ( x ^ y ^ z )                       /* Rounds 60-79 */
+
+/* The SHA Mysterious Constants */
+
+#define K1  0x5A827999L                                 /* Rounds  0-19 */
+#define K2  0x6ED9EBA1L                                 /* Rounds 20-39 */
+#define K3  0x8F1BBCDCL                                 /* Rounds 40-59 */
+#define K4  0xCA62C1D6L                                 /* Rounds 60-79 */
+
+#define ROTL(n,X)  ( ( ( X ) << n ) | ( ( X ) >> ( 32 - n ) ) )
+
+#define expand(W,i) ( W[ i & 15 ] = \
+                    ROTL( 1, ( W[ i & 15 ] ^ W[ (i - 14) & 15 ] ^ \
+                               W[ (i - 8) & 15 ] ^ W[ (i - 3) & 15 ] ) ) )
+
+#define subRound(a, b, c, d, e, f, k, data) \
+    ( e += ROTL( 5, a ) + f( b, c, d ) + k + data, b = ROTL( 30, b ) )
+
+
+void SHATransform(__u32 *digest, __u32 *data)
+    {
+    __u32 A, B, C, D, E;     /* Local vars */
+    __u32 eData[ 16 ];       /* Expanded data */
+
+    /* Set up first buffer and local data buffer */
+    A = digest[ 0 ];
+    B = digest[ 1 ];
+    C = digest[ 2 ];
+    D = digest[ 3 ];
+    E = digest[ 4 ];
+    memcpy( eData, data, 16*sizeof(__u32));
+
+    /* Heavy mangling, in 4 sub-rounds of 20 interations each. */
+    subRound( A, B, C, D, E, f1, K1, eData[  0 ] );
+    subRound( E, A, B, C, D, f1, K1, eData[  1 ] );
+    subRound( D, E, A, B, C, f1, K1, eData[  2 ] );
+    subRound( C, D, E, A, B, f1, K1, eData[  3 ] );
+    subRound( B, C, D, E, A, f1, K1, eData[  4 ] );
+    subRound( A, B, C, D, E, f1, K1, eData[  5 ] );
+    subRound( E, A, B, C, D, f1, K1, eData[  6 ] );
+    subRound( D, E, A, B, C, f1, K1, eData[  7 ] );
+    subRound( C, D, E, A, B, f1, K1, eData[  8 ] );
+    subRound( B, C, D, E, A, f1, K1, eData[  9 ] );
+    subRound( A, B, C, D, E, f1, K1, eData[ 10 ] );
+    subRound( E, A, B, C, D, f1, K1, eData[ 11 ] );
+    subRound( D, E, A, B, C, f1, K1, eData[ 12 ] );
+    subRound( C, D, E, A, B, f1, K1, eData[ 13 ] );
+    subRound( B, C, D, E, A, f1, K1, eData[ 14 ] );
+    subRound( A, B, C, D, E, f1, K1, eData[ 15 ] );
+    subRound( E, A, B, C, D, f1, K1, expand( eData, 16 ) );
+    subRound( D, E, A, B, C, f1, K1, expand( eData, 17 ) );
+    subRound( C, D, E, A, B, f1, K1, expand( eData, 18 ) );
+    subRound( B, C, D, E, A, f1, K1, expand( eData, 19 ) );
+
+    subRound( A, B, C, D, E, f2, K2, expand( eData, 20 ) );
+    subRound( E, A, B, C, D, f2, K2, expand( eData, 21 ) );
+    subRound( D, E, A, B, C, f2, K2, expand( eData, 22 ) );
+    subRound( C, D, E, A, B, f2, K2, expand( eData, 23 ) );
+    subRound( B, C, D, E, A, f2, K2, expand( eData, 24 ) );
+    subRound( A, B, C, D, E, f2, K2, expand( eData, 25 ) );
+    subRound( E, A, B, C, D, f2, K2, expand( eData, 26 ) );
+    subRound( D, E, A, B, C, f2, K2, expand( eData, 27 ) );
+    subRound( C, D, E, A, B, f2, K2, expand( eData, 28 ) );
+    subRound( B, C, D, E, A, f2, K2, expand( eData, 29 ) );
+    subRound( A, B, C, D, E, f2, K2, expand( eData, 30 ) );
+    subRound( E, A, B, C, D, f2, K2, expand( eData, 31 ) );
+    subRound( D, E, A, B, C, f2, K2, expand( eData, 32 ) );
+    subRound( C, D, E, A, B, f2, K2, expand( eData, 33 ) );
+    subRound( B, C, D, E, A, f2, K2, expand( eData, 34 ) );
+    subRound( A, B, C, D, E, f2, K2, expand( eData, 35 ) );
+    subRound( E, A, B, C, D, f2, K2, expand( eData, 36 ) );
+    subRound( D, E, A, B, C, f2, K2, expand( eData, 37 ) );
+    subRound( C, D, E, A, B, f2, K2, expand( eData, 38 ) );
+    subRound( B, C, D, E, A, f2, K2, expand( eData, 39 ) );
+
+    subRound( A, B, C, D, E, f3, K3, expand( eData, 40 ) );
+    subRound( E, A, B, C, D, f3, K3, expand( eData, 41 ) );
+    subRound( D, E, A, B, C, f3, K3, expand( eData, 42 ) );
+    subRound( C, D, E, A, B, f3, K3, expand( eData, 43 ) );
+    subRound( B, C, D, E, A, f3, K3, expand( eData, 44 ) );
+    subRound( A, B, C, D, E, f3, K3, expand( eData, 45 ) );
+    subRound( E, A, B, C, D, f3, K3, expand( eData, 46 ) );
+    subRound( D, E, A, B, C, f3, K3, expand( eData, 47 ) );
+    subRound( C, D, E, A, B, f3, K3, expand( eData, 48 ) );
+    subRound( B, C, D, E, A, f3, K3, expand( eData, 49 ) );
+    subRound( A, B, C, D, E, f3, K3, expand( eData, 50 ) );
+    subRound( E, A, B, C, D, f3, K3, expand( eData, 51 ) );
+    subRound( D, E, A, B, C, f3, K3, expand( eData, 52 ) );
+    subRound( C, D, E, A, B, f3, K3, expand( eData, 53 ) );
+    subRound( B, C, D, E, A, f3, K3, expand( eData, 54 ) );
+    subRound( A, B, C, D, E, f3, K3, expand( eData, 55 ) );
+    subRound( E, A, B, C, D, f3, K3, expand( eData, 56 ) );
+    subRound( D, E, A, B, C, f3, K3, expand( eData, 57 ) );
+    subRound( C, D, E, A, B, f3, K3, expand( eData, 58 ) );
+    subRound( B, C, D, E, A, f3, K3, expand( eData, 59 ) );
+
+    subRound( A, B, C, D, E, f4, K4, expand( eData, 60 ) );
+    subRound( E, A, B, C, D, f4, K4, expand( eData, 61 ) );
+    subRound( D, E, A, B, C, f4, K4, expand( eData, 62 ) );
+    subRound( C, D, E, A, B, f4, K4, expand( eData, 63 ) );
+    subRound( B, C, D, E, A, f4, K4, expand( eData, 64 ) );
+    subRound( A, B, C, D, E, f4, K4, expand( eData, 65 ) );
+    subRound( E, A, B, C, D, f4, K4, expand( eData, 66 ) );
+    subRound( D, E, A, B, C, f4, K4, expand( eData, 67 ) );
+    subRound( C, D, E, A, B, f4, K4, expand( eData, 68 ) );
+    subRound( B, C, D, E, A, f4, K4, expand( eData, 69 ) );
+    subRound( A, B, C, D, E, f4, K4, expand( eData, 70 ) );
+    subRound( E, A, B, C, D, f4, K4, expand( eData, 71 ) );
+    subRound( D, E, A, B, C, f4, K4, expand( eData, 72 ) );
+    subRound( C, D, E, A, B, f4, K4, expand( eData, 73 ) );
+    subRound( B, C, D, E, A, f4, K4, expand( eData, 74 ) );
+    subRound( A, B, C, D, E, f4, K4, expand( eData, 75 ) );
+    subRound( E, A, B, C, D, f4, K4, expand( eData, 76 ) );
+    subRound( D, E, A, B, C, f4, K4, expand( eData, 77 ) );
+    subRound( C, D, E, A, B, f4, K4, expand( eData, 78 ) );
+    subRound( B, C, D, E, A, f4, K4, expand( eData, 79 ) );
+
+    /* Build message digest */
+    digest[ 0 ] += A;
+    digest[ 1 ] += B;
+    digest[ 2 ] += C;
+    digest[ 3 ] += D;
+    digest[ 4 ] += E;
+    }
+
+#else
+#define HASH_BUFFER_SIZE 4
+#define HASH_TRANSFORM MD5Transform
+       
 /*
  * MD5 transform algorithm, taken from code written by Colin Plumb,
  * and put into the public domain
@@ -565,6 +827,8 @@ static void MD5Transform(__u32 buf[4],
 #undef F4
 #undef MD5STEP
 
+#endif
+
 
 #if POOLWORDS % 16
 #error extract_entropy() assumes that POOLWORDS is a multiple of 16 words.
@@ -579,7 +843,7 @@ static inline int extract_entropy(struct random_bucket *r, char * buf,
                                  int nbytes, int to_user)
 {
        int ret, i;
-       __u32 tmp[4];
+       __u32 tmp[HASH_BUFFER_SIZE];
        
        add_timer_randomness(r, &extract_timer_state, nbytes);
        
@@ -602,22 +866,28 @@ static inline int extract_entropy(struct random_bucket *r, char * buf,
                tmp[1] = 0xefcdab89;
                tmp[2] = 0x98badcfe;
                tmp[3] = 0x10325476;
+#ifdef USE_SHA
+               tmp[4] = 0xc3d2e1f0;
+#endif
                for (i = 0; i < POOLWORDS; i += 16)
-                       MD5Transform(tmp, r->pool+i);
+                       HASH_TRANSFORM(tmp, r->pool+i);
                /* Modify pool so next hash will produce different results */
                add_entropy_word(r, tmp[0]);
                add_entropy_word(r, tmp[1]);
                add_entropy_word(r, tmp[2]);
                add_entropy_word(r, tmp[3]);
+#ifdef USE_SHA
+               add_entropy_word(r, tmp[4]);
+#endif
                /*
-                * Run the MD5 Transform one more time, since we want
+                * Run the hash transform one more time, since we want
                 * to add at least minimal obscuring of the inputs to
-                * add_entropy_word().  --- TYT
+                * add_entropy_word().
                 */
-               MD5Transform(tmp, r->pool);
+               HASH_TRANSFORM(tmp, r->pool);
                
                /* Copy data to destination buffer */
-               i = MIN(nbytes, 16);
+               i = MIN(nbytes, HASH_BUFFER_SIZE*sizeof(__u32));
                if (to_user)
                        memcpy_tofs(buf, (__u8 const *)tmp, i);
                else
@@ -682,6 +952,15 @@ random_read(struct inode * inode, struct file * file, char * buf, int nbytes)
        current->state = TASK_RUNNING;
        remove_wait_queue(&random_wait, &wait);
 
+       /*
+        * If we gave the user some bytes and we have an inode pointer,
+        * update the access time.
+        */
+       if (inode && count != 0) {
+               inode->i_atime = CURRENT_TIME;
+               inode->i_dirt = 1;
+       }
+       
        return (count ? count : retval);
 }
 
@@ -696,10 +975,17 @@ static int
 random_select(struct inode *inode, struct file *file,
                      int sel_type, select_table * wait)
 {
-       if (sel_type == SEL_IN) {
+       switch (sel_type) {
+       case SEL_IN:
                if (random_state.entropy_count >= 8)
                        return 1;
                select_wait(&random_wait, wait);
+               break;
+       case SEL_OUT:
+               if (random_state.entropy_count < WAIT_OUTPUT_BITS)
+                       return 1;
+               select_wait(&random_wait, wait);
+               break;
        }
        return 0;
 }
@@ -711,6 +997,13 @@ random_write(struct inode * inode, struct file * file,
        int i;
        __u32 word, *p;
 
+       if (count < 0)
+               return -EINVAL;
+
+       i = verify_area(VERIFY_READ, (void *) buffer, count);
+       if (i)
+               return i;
+
        for (i = count, p = (__u32 *)buffer;
             i >= sizeof(__u32);
             i-= sizeof(__u32), p++) {
@@ -722,8 +1015,10 @@ random_write(struct inode * inode, struct file * file,
                memcpy_fromfs(&word, p, i);
                add_entropy_word(&random_state, word);
        }
-       if (inode)
+       if (inode) {
                inode->i_mtime = CURRENT_TIME;
+               inode->i_dirt = 1;
+       }
        return count;
 }
 
@@ -739,7 +1034,8 @@ random_ioctl(struct inode * inode, struct file * file,
                retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
                if (retval)
                        return(retval);
-               put_user(random_state.entropy_count, (int *) arg);
+               ent_count = random_state.entropy_count;
+               put_user(ent_count, (int *) arg);
                return 0;
        case RNDADDTOENTCNT:
                if (!suser())
@@ -747,9 +1043,28 @@ random_ioctl(struct inode * inode, struct file * file,
                retval = verify_area(VERIFY_READ, (void *) arg, sizeof(int));
                if (retval)
                        return(retval);
-               random_state.entropy_count += get_user((int *) arg);
-               if (random_state.entropy_count > POOLBITS)
+               ent_count = get_user((int *) arg);
+               /*
+                * Add i to entropy_count, limiting the result to be
+                * between 0 and POOLBITS.
+                */
+               if (ent_count < -random_state.entropy_count)
+                       random_state.entropy_count = 0;
+               else if (ent_count > POOLBITS)
                        random_state.entropy_count = POOLBITS;
+               else {
+                       random_state.entropy_count += ent_count;
+                       if (random_state.entropy_count > POOLBITS)
+                               random_state.entropy_count = POOLBITS;
+                       if (random_state.entropy_count < 0)
+                               random_state.entropy_count = 0;
+               }
+               /*
+                * Wake up waiting processes if we have enough
+                * entropy.
+                */
+               if (random_state.entropy_count >= WAIT_INPUT_BITS)
+                       wake_up_interruptible(&random_wait);
                return 0;
        case RNDGETPOOL:
                if (!suser())
@@ -758,18 +1073,22 @@ random_ioctl(struct inode * inode, struct file * file,
                retval = verify_area(VERIFY_WRITE, (void *) p, sizeof(int));
                if (retval)
                        return(retval);
-               put_user(random_state.entropy_count, p++);
-               retval = verify_area(VERIFY_READ, (void *) p, sizeof(int));
+               ent_count = random_state.entropy_count;
+               put_user(ent_count, p++);
+               retval = verify_area(VERIFY_WRITE, (void *) p, sizeof(int));
                if (retval)
                        return(retval);
                size = get_user(p);
-               put_user(POOLWORDS, p);
+               put_user(POOLWORDS, p++);
                if (size < 0)
                        return -EINVAL;
                if (size > POOLWORDS)
                        size = POOLWORDS;
-               memcpy_tofs(++p, random_state.pool,
-                           size*sizeof(__u32));
+               retval = verify_area(VERIFY_WRITE, (void *) p,
+                                    size * sizeof(__u32));
+               if (retval)
+                       return retval;
+               memcpy_tofs(p, random_state.pool, size*sizeof(__u32));
                return 0;
        case RNDADDENTROPY:
                if (!suser())
@@ -779,17 +1098,43 @@ random_ioctl(struct inode * inode, struct file * file,
                if (retval)
                        return(retval);
                ent_count = get_user(p++);
+               if (ent_count < 0)
+                       return -EINVAL;
                size = get_user(p++);
-               (void) random_write(0, file, (const char *) p, size);
-               random_state.entropy_count += ent_count;
-               if (random_state.entropy_count > POOLBITS)
+               retval = random_write(0, file, (const char *) p, size);
+               if (retval)
+                       return retval;
+               /*
+                * Add ent_count to entropy_count, limiting the result to be
+                * between 0 and POOLBITS.
+                */
+               if (ent_count > POOLBITS)
                        random_state.entropy_count = POOLBITS;
+               else {
+                       random_state.entropy_count += ent_count;
+                       if (random_state.entropy_count > POOLBITS)
+                               random_state.entropy_count = POOLBITS;
+                       if (random_state.entropy_count < 0)
+                               random_state.entropy_count = 0;
+               }
+               /*
+                * Wake up waiting processes if we have enough
+                * entropy.
+                */
+               if (random_state.entropy_count >= WAIT_INPUT_BITS)
+                       wake_up_interruptible(&random_wait);
                return 0;
        case RNDZAPENTCNT:
                if (!suser())
                        return -EPERM;
                random_state.entropy_count = 0;
                return 0;
+       case RNDCLEARPOOL:
+               /* Clear the entropy pool and associated counters. */
+               if (!suser())
+                       return -EPERM;
+               rand_clear_pool();
+               return 0;
        default:
                return -EINVAL;
        }
index fb3fb6ef001ad1b78bfe16a06815ee20aa858e9c..5e18b961aa3cfd5bee29b25dff8c0903ea41c379 100644 (file)
@@ -30,7 +30,7 @@
  *
  */
 
-#define RTC_VERSION            "1.04"
+#define RTC_VERSION            "1.05"
 
 #define RTC_IRQ        8       /* Can't see this changing soon.        */
 #define RTC_IO_BASE    0x70    /* Or this...                           */
@@ -67,6 +67,8 @@
 
 static struct wait_queue *rtc_wait;
 
+static struct timer_list rtc_irq_timer;
+
 static int rtc_lseek(struct inode *inode, struct file *file, off_t offset,
                        int origin);
 
@@ -81,6 +83,7 @@ static int rtc_select(struct inode *inode, struct file *file,
 
 void get_rtc_time (struct tm *rtc_tm);
 void get_rtc_alm_time (struct tm *alm_tm);
+void rtc_dropped_irq(unsigned long data);
 
 inline void set_rtc_irq_bit(unsigned char bit);
 inline void mask_rtc_irq_bit(unsigned char bit);
@@ -92,8 +95,10 @@ unsigned char rtc_is_updating(void);
  */
 
 #define RTC_IS_OPEN            0x01    /* means /dev/rtc is in use     */
+#define RTC_TIMER_ON           0x02    /* missed irq timer active      */
 
 unsigned char rtc_status = 0;          /* bitmapped status byte.       */
+unsigned long rtc_freq = 0;            /* Current periodic IRQ rate    */
 unsigned long rtc_irq_data = 0;                /* our output to the world      */
 
 unsigned char days_in_mo[] = 
@@ -119,6 +124,12 @@ static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        rtc_irq_data &= ~0xff;
        rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
        wake_up_interruptible(&rtc_wait);       
+
+       if (rtc_status & RTC_TIMER_ON) {
+               del_timer(&rtc_irq_timer);
+               rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100;
+               add_timer(&rtc_irq_timer);
+       }
 }
 
 /*
@@ -157,12 +168,16 @@ static int rtc_read(struct inode *inode, struct file *file, char *buf, int count
                        break;
                }
                schedule();
-               continue;
        }
 
        if (retval == 0) {
-               memcpy_tofs(buf, &rtc_irq_data, sizeof(unsigned long));
+               unsigned long data, flags;
+               save_flags(flags);
+               cli();
+               data = rtc_irq_data;
                rtc_irq_data = 0;
+               restore_flags(flags);
+               memcpy_tofs(buf, &data, sizeof(unsigned long));
                retval = sizeof(unsigned long);
        }
 
@@ -192,27 +207,30 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                case RTC_PIE_OFF:       /* Mask periodic int. enab. bit */
                {
                        mask_rtc_irq_bit(RTC_PIE);
+                       if (rtc_status & RTC_TIMER_ON) {
+                               del_timer(&rtc_irq_timer);
+                               rtc_status &= ~RTC_TIMER_ON;
+                       }
                        return 0;
                }
                case RTC_PIE_ON:        /* Allow periodic ints          */
                {
-                       unsigned int hz;
-                       unsigned char tmp;
-
-                       save_flags(flags);
-                       cli();
-                       tmp = CMOS_READ(RTC_FREQ_SELECT) & 0x0f;
-                       restore_flags(flags);
-
-                       hz = (tmp ? (65536/(1<<tmp)) : 0);
 
                        /*
                         * We don't really want Joe User enabling more
                         * than 64Hz of interrupts on a multi-user machine.
                         */
-                       if ((hz > 64) && (!suser()))
+                       if ((rtc_freq > 64) && (!suser()))
                                return -EPERM;
 
+                       if (rtc_freq == 0)
+                               return -EINVAL;
+
+                       if (!(rtc_status & RTC_TIMER_ON)) {
+                               rtc_status |= RTC_TIMER_ON;
+                               rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100;
+                               add_timer(&rtc_irq_timer);
+                       }
                        set_rtc_irq_bit(RTC_PIE);
                        return 0;
                }
@@ -382,19 +400,13 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                }
                case RTC_IRQP_READ:     /* Read the periodic IRQ rate.  */
                {
-                       unsigned long hz;
                        int retval;
 
                        retval = verify_area(VERIFY_WRITE, (unsigned long*)arg, sizeof(unsigned long));
                        if (retval != 0)
                                return retval;
 
-                       save_flags(flags);
-                       cli();
-                       retval = CMOS_READ(RTC_FREQ_SELECT) & 0x0f;
-                       restore_flags(flags);
-                       hz = (retval ? (65536/(1<<retval)) : 0);
-                       memcpy_tofs((unsigned long*)arg, &hz, sizeof(unsigned long));
+                       memcpy_tofs((unsigned long*)arg, &rtc_freq, sizeof(unsigned long));
                        return 0;
                }
                case RTC_IRQP_SET:      /* Set periodic IRQ rate.       */
@@ -405,7 +417,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                        /* 
                         * The max we can do is 8192Hz.
                         */
-                       if (arg > 8192)
+                       if ((arg < 2) || (arg > 8192))
                                return -EINVAL;
                        /*
                         * We don't really want Joe User generating more
@@ -423,6 +435,8 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                        if ((arg != 0) && (arg != (1<<tmp)))
                                return -EINVAL;
 
+                       rtc_freq = arg;
+
                        save_flags(flags);
                        cli();
                        val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
@@ -480,6 +494,12 @@ static void rtc_release(struct inode *inode, struct file *file)
        CMOS_WRITE(tmp, RTC_CONTROL);
        CMOS_READ(RTC_INTR_FLAGS);
        restore_flags(flags);
+
+       if (rtc_status & RTC_TIMER_ON) {
+               rtc_status &= ~RTC_TIMER_ON;
+               del_timer(&rtc_irq_timer);
+       }
+
        rtc_irq_data = 0;
        rtc_status &= ~RTC_IS_OPEN;
 }
@@ -520,6 +540,8 @@ static struct miscdevice rtc_dev=
 
 int rtc_init(void)
 {
+       unsigned long flags;
+
        printk("Real Time Clock Driver v%s\n", RTC_VERSION);
        if(request_irq(RTC_IRQ, rtc_interrupt, SA_INTERRUPT, "rtc", NULL))
        {
@@ -530,10 +552,46 @@ int rtc_init(void)
        misc_register(&rtc_dev);
        /* Check region? Naaah! Just snarf it up. */
        request_region(RTC_IO_BASE, RTC_IO_EXTENT, "rtc");
+       init_timer(&rtc_irq_timer);
+       rtc_irq_timer.function = rtc_dropped_irq;
        rtc_wait = NULL;
+       save_flags(flags);
+       cli();
+       rtc_freq = CMOS_READ(RTC_FREQ_SELECT) & 0x0F;
+       restore_flags(flags);
+       rtc_freq = (rtc_freq ? (65536/(1<<rtc_freq)) : 0);
        return 0;
 }
 
+/*
+ *     At IRQ rates >= 4096Hz, an interrupt may get lost altogether.
+ *     (usually during an IDE disk interrupt, with IRQ unmasking off)
+ *     Since the interrupt handler doesn't get called, the IRQ status
+ *     byte doesn't get read, and the RTC stops generating interrupts.
+ *     A timer is set, and will call this function if/when that happens.
+ *     To get it out of this stalled state, we just read the status.
+ *     At least a jiffy of interrupts (rtc_freq/HZ) will have been lost.
+ *     (You *really* shouldn't be trying to use a non-realtime system 
+ *     for something that requires a steady > 1KHz signal anyways.)
+ */
+
+void rtc_dropped_irq(unsigned long data)
+{
+       unsigned long flags;
+
+       printk(KERN_INFO "rtc: lost some interrupts at %ldHz.\n", rtc_freq);
+       del_timer(&rtc_irq_timer);
+       rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100;
+       add_timer(&rtc_irq_timer);
+
+       save_flags(flags);
+       cli();
+       rtc_irq_data += ((rtc_freq/HZ)<<8);
+       rtc_irq_data &= ~0xff;
+       rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);     /* restart */
+       restore_flags(flags);
+}
+
 /*
  *     Info exported via "/proc/rtc".
  */
@@ -542,11 +600,11 @@ int get_rtc_status(char *buf)
 {
        char *p;
        struct tm tm;
-       unsigned char freq, batt, ctrl;
+       unsigned char batt, ctrl;
        unsigned long flags;
 
        save_flags(flags);
-       freq = CMOS_READ(RTC_FREQ_SELECT) & 0x0F;
+       cli();
        batt = CMOS_READ(RTC_VALID) & RTC_VRT;
        ctrl = CMOS_READ(RTC_CONTROL);
        restore_flags(flags);
@@ -559,10 +617,11 @@ int get_rtc_status(char *buf)
         * There is no way to tell if the luser has the RTC set for local
         * time or for Universal Standard Time (GMT). Probably local though.
         */
-       p += sprintf(p, "date          : %04d-%02d-%02d\n",
+       p += sprintf(p,
+               "rtc_time\t: %02d:%02d:%02d\n"
+               "rtc_date\t: %04d-%02d-%02d\n",
+               tm.tm_hour, tm.tm_min, tm.tm_sec,
                tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
-       p += sprintf(p, "time          : %02d-%02d-%02d\n",
-               tm.tm_hour, tm.tm_min, tm.tm_sec);
 
        get_rtc_alm_time(&tm);
 
@@ -571,44 +630,41 @@ int get_rtc_status(char *buf)
         * match any value for that particular field. Values that are
         * greater than a valid time, but less than 0xc0 shouldn't appear.
         */
-       p += sprintf(p, "alarm         : ");
+       p += sprintf(p, "alarm\t\t: ");
        if (tm.tm_hour <= 24)
-               p += sprintf(p, "%02d", tm.tm_hour);
+               p += sprintf(p, "%02d:", tm.tm_hour);
        else
-               p += sprintf(p, "**");
-       p += sprintf(p, "-");
+               p += sprintf(p, "**:");
+
        if (tm.tm_min <= 59)
-               p += sprintf(p, "%02d", tm.tm_min);
+               p += sprintf(p, "%02d:", tm.tm_min);
        else
-               p += sprintf(p, "**");
-       p += sprintf(p, "-");
+               p += sprintf(p, "**:");
+
        if (tm.tm_sec <= 59)
-               p += sprintf(p, "%02d", tm.tm_sec);
+               p += sprintf(p, "%02d\n", tm.tm_sec);
        else
-               p += sprintf(p, "**");
-       p += sprintf(p, "\n");
-
-       p += sprintf(p, "daylight      : %s\n",
-               ((ctrl & RTC_DST_EN) ? "yes" : "no" ));
-       p += sprintf(p, "bcd           : %s\n",
-               ((ctrl & RTC_DM_BINARY) ? "no" : "yes" ));
-       p += sprintf(p, "24hr          : %s\n",
-               ((ctrl & RTC_24H) ? "yes" : "no" ));
-       p += sprintf(p, "sqwave        : %s\n",
-               ((ctrl & RTC_SQWE) ? "yes" : "no" ));
-
-       p += sprintf(p, "alarm_int     : %s\n",
-               ((ctrl & RTC_AIE) ? "yes" : "no" ));
-       p += sprintf(p, "update_int    : %s\n",
-               ((ctrl & RTC_UIE) ? "yes" : "no" ));
-       p += sprintf(p, "periodic_int  : %s\n",
-               ((ctrl & RTC_PIE) ? "yes" : "no" ));
-
-       p += sprintf(p, "periodic_freq : %d\n",
-               (freq ? (65536/(1<<freq)) : 0));
-
-       p += sprintf(p, "battery_ok    : %s\n",
-               (batt ? "yes" : "no"));
+               p += sprintf(p, "**\n");
+
+       p += sprintf(p,
+               "DST_enable\t: %s\n"
+               "BCD\t\t: %s\n"
+               "24hr\t\t: %s\n"
+               "sqare_wave\t: %s\n"
+               "alarm_IRQ\t: %s\n"
+               "update_IRQ\t: %s\n"
+               "periodic_IRQ\t: %s\n"
+               "periodic_freq\t: %ld\n"
+               "batt_status\t: %s\n",
+               (ctrl & RTC_DST_EN) ? "yes" : "no",
+               (ctrl & RTC_DM_BINARY) ? "no" : "yes",
+               (ctrl & RTC_24H) ? "yes" : "no",
+               (ctrl & RTC_SQWE) ? "yes" : "no",
+               (ctrl & RTC_AIE) ? "yes" : "no",
+               (ctrl & RTC_UIE) ? "yes" : "no",
+               (ctrl & RTC_PIE) ? "yes" : "no",
+               rtc_freq,
+               batt ? "okay" : "dead");
 
        return  p - buf;
 }
@@ -622,6 +678,7 @@ inline unsigned char rtc_is_updating(void)
        unsigned char uip;
 
        save_flags(flags);
+       cli();
        uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
        restore_flags(flags);
        return uip;
@@ -744,7 +801,7 @@ inline void set_rtc_irq_bit(unsigned char bit)
        val |= bit;
        CMOS_WRITE(val, RTC_CONTROL);
        CMOS_READ(RTC_INTR_FLAGS);
-       restore_flags(flags);
        rtc_irq_data = 0;
+       restore_flags(flags);
 }
 
index 1af12d559aca3e942a76df593f9a2ec24d5a41f7..bcd8b2ebcf1b3105a3ffdb3f1bc8f1f8dfae9f32 100644 (file)
@@ -1610,7 +1610,7 @@ check_and_exit:
  *         release the bus after transmitting. This must be done when
  *         the transmit shift register is empty, not be done when the
  *         transmit holding register is empty.  This functionality
- *         allows RS485 driver to be written in user space. 
+ *         allows an RS485 driver to be written in user space. 
  */
 static int get_lsr_info(struct async_struct * info, unsigned int *value)
 {
index 5c9012559558975c85a590b82eba6aca3c381270..3dec452a06add84c6326a4b65291a784f94b9ace 100644 (file)
 # Network device configuration
 #
 tristate 'Dummy net driver support' CONFIG_DUMMY
-tristate 'SLIP (serial line) support' CONFIG_SLIP
-if [ "$CONFIG_SLIP" != "n" ]; then
-  bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED
-  bool ' Keepalive and linefill' CONFIG_SLIP_SMART
+tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  tristate 'Frame relay DLCI support (EXPERIMENTAL)' CONFIG_DLCI
+  if [ "$CONFIG_DLCI" = "y" -o "$CONFIG_DLCI" = "m" ]; then
+    int '  Max open DLCI' CONFIG_DLCI_COUNT 24
+    int '  Max DLCI per device' CONFIG_DLCI_MAX 8
+    dep_tristate '  SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI
+  fi
 fi
+tristate 'PLIP (parallel port) support' CONFIG_PLIP
 tristate 'PPP (point-to-point) support' CONFIG_PPP
 if [ ! "$CONFIG_PPP" = "n" ]; then
   comment 'CCP compressors for PPP are only built as modules.'
 fi
-tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP
-tristate 'WIC (Radio IP bridge)' CONFIG_WIC
-tristate 'Z8530 SCC kiss emulation driver for AX.25' CONFIG_SCC
-tristate 'PLIP (parallel port) support' CONFIG_PLIP
-tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
-
-tristate 'DLCI (Frame relay) support' CONFIG_DLCI
-if [ "$CONFIG_DLCI" = "y" -o "$CONFIG_DLCI" = "m" ]; then
-  int '  Max open DLCI' CONFIG_DLCI_COUNT 24
-  int '  Max DLCI per device' CONFIG_DLCI_MAX 8
-  tristate '  SDLA (Sangoma S502/S508) support' CONFIG_SDLA
-fi
-
-bool 'Do you want to be offered ALPHA test drivers' CONFIG_NET_ALPHA
-bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC
-if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
-  tristate 'WD80*3 support' CONFIG_WD80x3
-  tristate 'SMC Ultra support' CONFIG_ULTRA
-  tristate 'SMC 9194 support' CONFIG_SMC9194
-fi
-bool 'AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE
-if [ "$CONFIG_LANCE" = "y" ]; then
-  bool 'AMD PCInet32 (VLB and PCI) support' CONFIG_LANCE32
-fi  
-bool '3COM cards' CONFIG_NET_VENDOR_3COM
-if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
-  tristate '3c501 support' CONFIG_EL1
-  tristate '3c503 support' CONFIG_EL2
-  if [ "$CONFIG_NET_ALPHA" = "y" ]; then
-    tristate '3c505 support' CONFIG_ELPLUS
-    tristate '3c507 support' CONFIG_EL16
-  fi
-  tristate '3c509/3c579 support' CONFIG_EL3
-  tristate '3c590 series (592/595/597) "Vortex" support' CONFIG_VORTEX
+tristate 'SLIP (serial line) support' CONFIG_SLIP
+if [ "$CONFIG_SLIP" != "n" ]; then
+  bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED
+  bool ' Keepalive and linefill' CONFIG_SLIP_SMART
 fi
-bool 'Other ISA cards' CONFIG_NET_ISA
-if [ "$CONFIG_NET_ISA" = "y" ]; then
-  tristate 'Cabletron E21xx support' CONFIG_E2100
-  tristate 'DEPCA support' CONFIG_DEPCA
-  tristate 'EtherWorks 3 support' CONFIG_EWRK3
-  tristate 'EtherExpress 16 support' CONFIG_EEXPRESS
-  if [ "$CONFIG_NET_ALPHA" = "y" ]; then
-    bool 'SEEQ8005 support' CONFIG_SEEQ8005
-    tristate 'AT1700 support' CONFIG_AT1700
-    tristate 'FMV-181/182 support' CONFIG_FMV18X
-    tristate 'EtherExpressPro support' CONFIG_EEXPRESS_PRO
-    tristate 'NI5210 support' CONFIG_NI52
-    bool 'NI6510 support' CONFIG_NI65
-    tristate 'WaveLAN support' CONFIG_WAVELAN
-    tristate 'ICL EtherTeam 16i/32 support' CONFIG_ETH16I
-  fi
-  tristate 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS
-  tristate 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN
-  tristate 'HP 10/100VG PCLAN (ISA, EISA, PCI) support' CONFIG_HP100
-  tristate 'NE2000/NE1000 support' CONFIG_NE2000
+bool 'Radio network interfaces' CONFIG_NET_RADIO
+if [ "$CONFIG_NET_RADIO" != "n" ]; then
   if [ "$CONFIG_AX25" = "y" ]; then
-    bool 'Ottawa PI and PI/2 support' CONFIG_PI
     bool 'Gracilis PackeTwin support' CONFIG_PT
+    bool 'Ottawa PI and PI/2 support' CONFIG_PI
   fi
-  bool 'SK_G16 support' CONFIG_SK_G16
-fi
-bool 'EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA
-if [ "$CONFIG_NET_EISA" = "y" ]; then
-  if [ "$CONFIG_NET_ALPHA" = "y" ]; then
-    tristate 'Ansel Communications EISA 3200 support' CONFIG_AC3200
+  tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP
+  tristate 'WaveLAN support' CONFIG_WAVELAN
+  tristate 'WIC Radio IP bridge (EXPERIMENTAL)' CONFIG_WIC
+  if [ "$CONFIG_AX25" = "y" ]; then
+    tristate 'Z8530 SCC kiss emulation driver for AX.25' CONFIG_SCC
   fi
-  tristate 'Apricot Xen-II on board ethernet' CONFIG_APRICOT
-  tristate 'DE425, DE434, DE435, DE500 support' CONFIG_DE4X5
-  tristate 'DECchip Tulip (dc21x4x) PCI support' CONFIG_DEC_ELCP
-  tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
-# bool 'LPL T100V 100Mbs support' CONFIG_LPL_T100
-# bool 'PCnet32 (32 bit VLB and PCI LANCE) support' CONFIG_PCNET32
-  bool 'Zenith Z-Note support' CONFIG_ZNET
 fi
-bool 'Pocket and portable adaptors' CONFIG_NET_POCKET
-if [ "$CONFIG_NET_POCKET" = "y" ]; then
-  bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP
-  tristate 'D-Link DE600 pocket adaptor support' CONFIG_DE600
-  tristate 'D-Link DE620 pocket adaptor support' CONFIG_DE620
-# bool 'Silicom pocket adaptor support' CONFIG_SILICOM_PEA
-# bool 'WaveLAN PCMCIA support' CONFIG_WaveLAN
-# bool '3 Com 3c589 PCMCIA support' CONFIG_3C589
+#
+#      Ethernet
+#
+bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
+if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
+  bool '3COM cards' CONFIG_NET_VENDOR_3COM
+  if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
+    tristate '3c501 support' CONFIG_EL1
+    tristate '3c503 support' CONFIG_EL2
+    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      tristate '3c505 support' CONFIG_ELPLUS
+      tristate '3c507 support' CONFIG_EL16
+    fi
+    tristate '3c509/3c579 support' CONFIG_EL3
+    tristate '3c590 series (592/595/597) "Vortex" support' CONFIG_VORTEX
+  fi
+  bool 'AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE
+  if [ "$CONFIG_LANCE" = "y" ]; then
+    bool 'AMD PCInet32 (VLB and PCI) support' CONFIG_LANCE32
+  fi  
+  bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC
+  if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
+    tristate 'WD80*3 support' CONFIG_WD80x3
+    tristate 'SMC Ultra support' CONFIG_ULTRA
+    tristate 'SMC 9194 support' CONFIG_SMC9194
+  fi
+  bool 'Other ISA cards' CONFIG_NET_ISA
+  if [ "$CONFIG_NET_ISA" = "y" ]; then
+    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      tristate 'AT1700 support (EXPERIMENTAL)' CONFIG_AT1700
+    fi
+    tristate 'Cabletron E21xx support' CONFIG_E2100
+    tristate 'DEPCA support' CONFIG_DEPCA
+    tristate 'EtherWorks 3 support' CONFIG_EWRK3
+    tristate 'EtherExpress 16 support' CONFIG_EEXPRESS
+    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      tristate 'EtherExpressPro support' CONFIG_EEXPRESS_PRO
+      tristate 'FMV-181/182 support' CONFIG_FMV18X
+    fi
+    tristate 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS
+    tristate 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN
+    tristate 'HP 10/100VG PCLAN (ISA, EISA, PCI) support' CONFIG_HP100
+    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      tristate 'ICL EtherTeam 16i/32 support' CONFIG_ETH16I
+    fi
+    tristate 'NE2000/NE1000 support' CONFIG_NE2000
+    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      tristate 'NI5210 support' CONFIG_NI52
+      bool 'NI6510 support' CONFIG_NI65
+    fi
+    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      bool 'SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005
+    fi
+    bool 'SK_G16 support' CONFIG_SK_G16
+  fi
+  bool 'EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA
+  if [ "$CONFIG_NET_EISA" = "y" ]; then
+    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200
+    fi
+    tristate 'Apricot Xen-II on board ethernet' CONFIG_APRICOT
+    tristate 'DE425, DE434, DE435, DE500 support' CONFIG_DE4X5
+    tristate 'DECchip Tulip (dc21x4x) PCI support' CONFIG_DEC_ELCP
+    tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
+    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      bool 'Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET
+    fi
+  fi
+  bool 'Pocket and portable adaptors' CONFIG_NET_POCKET
+  if [ "$CONFIG_NET_POCKET" = "y" ]; then
+    bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP
+    tristate 'D-Link DE600 pocket adaptor support' CONFIG_DE600
+    tristate 'D-Link DE620 pocket adaptor support' CONFIG_DE620
+  fi
 fi
+
 bool 'Token Ring driver support' CONFIG_TR
 if [ "$CONFIG_TR" = "y" ]; then
   tristate 'IBM Tropic chipset based adaptor support' CONFIG_IBMTR
index 62b15f52b56131229b338e2a023861c71099ce87..b0915a32c929f985b625ac952724f9b4b0d32ba7 100644 (file)
@@ -266,7 +266,7 @@ printk("Required room: %d, Tunnel hlen: %d\n", max_headroom, TUNL_HLEN);
                new_skb->h.iph = (struct iphdr *) skb_push(new_skb, tunnel_hlen);
 
                /* Free the old packet, we no longer need it */
-               kfree_skb(skb, FREE_WRITE);
+               dev_kfree_skb(skb, FREE_WRITE);
                skb = new_skb;
        }
 
index 890b45a8e66bff94b226d7fbe6a6bcfedff062f0..d52a3b574a00e08420096f4721e658876d28d12e 100644 (file)
@@ -653,7 +653,7 @@ static void boot_it(void)
 
        if (!obp_system_intr())
                ctrl_alt_del();
-       /* sigh.. atempt to prevent multiple entry */
+       /* sigh.. attempt to prevent multiple entry */
        last_keycode=1;
        rep = 0;
 }
index 6f5d9fc3948d92802b0ce3920f6f8d8296ffe3f9..c4c7797b3be0a5343d341dbe03ade9801da0acc0 100644 (file)
@@ -154,7 +154,8 @@ static int baud_table[] = {
        0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
        9600, 19200, 38400, 57600, 115200, 0 };
 
-/* Reading and writing Zilog8530 registers.  The delays are to make this
+/* 
+ * Reading and writing Zilog8530 registers.  The delays are to make this
  * driver work on the Sun4 which needs a settling delay after each chip
  * register access, other machines handle this in hardware via auxiliary
  * flip-flops which implement the settle time we do in software.
@@ -674,10 +675,9 @@ static void do_serial_hangup(void *private_)
 /*
  * This subroutine is called when the RS_TIMER goes off.  It is used
  * by the serial driver to handle ports that do not have an interrupt
- * (irq=0).  This doesn't work very well for 16450's, but gives barely
- * passable results for a 16550A.  (Although at the expense of much
- * CPU overhead).
+ * (irq=0).  This doesn't work at all for 16450's, as a sun has a Z8530.
  */
 static void rs_timer(void)
 {
        printk("rs_timer called\n");
@@ -1009,7 +1009,7 @@ static void rs_fair_output(void)
                left = MIN(info->xmit_cnt, left-1);
        }
 
-       /* Last character is being transmitted now (hopefuly). */
+       /* Last character is being transmitted now (hopefully). */
        zs_conschan->control = RES_Tx_P;
        udelay(5);
 
@@ -1302,7 +1302,7 @@ check_and_exit:
  *         release the bus after transmitting. This must be done when
  *         the transmit shift register is empty, not be done when the
  *         transmit holding register is empty.  This functionality
- *         allows RS485 driver to be written in user space. 
+ *         allows an RS485 driver to be written in user space. 
  */
 static int get_lsr_info(struct sun_serial * info, unsigned int *value)
 {
index 44a504900a492b8357ac75035530fa32351b9ecf..3380a0ea7f440f5a08c2815aebd88c16f4dfa15b 100644 (file)
@@ -54,7 +54,7 @@
  */
 
 #if defined(HOSTS_C) || defined(MODULE)
-#include <linux/scsicam.h>
+#include <scsi/scsicam.h>
 
 extern int NCR53c7xx_abort(Scsi_Cmnd *);
 extern int NCR53c7xx_detect(Scsi_Host_Template *tpnt);
index 67f2ecd4755a2df71a1886abea4c0d3a7cb57dd2..8481e5e06468ec780a4c22fbc71417ffa81b2611 100644 (file)
@@ -27,7 +27,7 @@
 #ifndef AM53C974_H
 #define AM53C974_H
 
-#include <linux/scsicam.h>
+#include <scsi/scsicam.h>
 
 /***************************************************************************************
 * Default setting of the controller's SCSI id. Edit and uncomment this only if your    *
index 67793cf3d190227a1e70439956187bd7428ea773..71b41a1799fede08737b3681df37572d1681f979 100644 (file)
@@ -1,5 +1,5 @@
 This file contains brief information about the SCSI tape driver.
-Last modified: Sun Apr 21 21:19:22 1996 by root@kai.makisara.fi
+Last modified: Wed May  1 11:51:35 1996 by root@kai.makisara.fi
 
 
 BASICS
@@ -62,6 +62,11 @@ The driver supports fixed and variable block size (within buffer
 limits). Both the auto-rewind (minor equals device number) and
 non-rewind devices (minor is 128 + device number) are implemented.
 
+Support is provided for changing the tape partition and partitioning
+of the tape with one or two partitions. By default support for
+partitioned tape is disabled for each driver and it can be enabled
+with the ioctl MTSETDRVBUFFER.
+
 By default the driver writes one filemark when the device is closed after
 writing and the last operation has been a write. Two filemarks can be
 optionally written. In both cases end of data is signified by
@@ -181,7 +186,20 @@ MTCOMPRESSION Sets compressing or uncompressing drive mode using the
        SCSI mode page 15. Note that some drives other methods for
        control of compression. Some drives (like the Exabytes) use
        density codes for compression control. Some drives use another
-       mode page but this page has not been implemented in the driver.
+       mode page but this page has not been implemented in the
+       driver.
+MTSETPART Moves the tape to the partition given by the argument at the
+       next tape operation. The block at which the tape is positioned
+       is the block where the tape was previously positioned in the
+       new active partition unless the next tape operation is
+       MTSEEK. In this case the tape is moved directly to the block
+       specified by MTSEEK. MTSETPART is inactive unless
+       MT_ST_CAN_PARTITIONS set.
+MTMKPART Formats the tape with one partition (argument zero) or two
+       partitions (the argument gives in megabytes the size of
+       partition 1 that is physically the first partition of the
+       tape). The drive has to support partitions with size specified
+       by the initiator. Inactive unless MT_ST_CAN_PARTITIONS set.
 MTSETDRVBUFFER
        Is used for several purposes. The command is obtained from count
         with mask MT_SET_OPTIONS, the low order bits are used as argument.
@@ -202,11 +220,18 @@ MTSETDRVBUFFER
             MT_ST_FAST_EOM using the SCSI spacing to EOD (global)
             MT_ST_AUTO_LOCK automatic locking of the drive door (global)
              MT_ST_DEF_WRITES the defaults are meant only for writes (mode)
-            MT_ST_CAN_BSR backspacing over records can be used for
-               repositioning the tape (global)
+            MT_ST_CAN_BSR backspacing over more than one records can
+               be used for repositioning the tape (global)
             MT_ST_NO_BLKLIMS the driver does not ask the block limits
                from the drive (block size can be changed only to
                variable) (global)
+            MT_ST_CAN_PARTITIONS enables support for partitioned
+               tapes (global)
+            MT_ST_SCSI2LOGICAL the logical block number is used in
+               the MTSEEK and MTIOCPOS for SCSI-2 drives instead of
+               the device dependent address. It is recommended to set
+               this flag unless there are tapes using the device
+               dependent (from the old times) (global)
             MT_ST_DEBUGGING debugging (global; debugging must be
                compiled into the driver)
        MT_ST_SETBOOLEANS
@@ -246,6 +271,15 @@ MTIOCGET Returns some status information.
        is set if there is no tape in the drive. GMT_EOD means either
        end of recorded data or end of tape. GMT_EOT means end of tape.
 
+The following ioctls use the structure mtlocation that contains both
+the block number and the partition number. These ioctls are available
+only for SCSI-2 tape drives and the block number is the
+device-indepent logical block number defined by the standard.
+
+MTGETLOC Returns the current block and partition number.
+MTSETLOC Sets the tape to the block and partition specified by the
+       arguments.
+
 
 MISCELLANEOUS COMPILE OPTIONS
 
@@ -257,7 +291,11 @@ ST_MAX_TAPES. If more tapes are detected at driver initialization, the
 maximum is adjusted accordingly.
 
 Immediate return from tape positioning SCSI commands can be enabled by
-defining ST_NOWAIT.
+defining ST_NOWAIT. If this is defined, the user should take care that
+the next tape operation is not started before the previous one has
+finished. The drives and SCSI adapters should handle this condition
+gracefully, but some drive/adapter combinations are known to hang the
+SCSI bus in this case.
 
 The MTEOM command is by default implemented as spacing over 32767
 filemarks. With this method the file number in the status is
@@ -268,8 +306,9 @@ number will be invalid.
 When using read ahead or buffered writes the position within the file
 may not be correct after the file is closed (correct position may
 require backspacing over more than one record). The correct position
-within file can be obtained if ST_IN_FILE_POS is defined. (The
-driver always backs over a filemark crossed by read ahead if the user
-does not request data that far.)
+within file can be obtained if ST_IN_FILE_POS is defined at compile
+time or the MT_ST_CAN_BSR bit is set for the drive with an ioctl.
+(The driver always backs over a filemark crossed by read ahead if the
+user does not request data that far.)
 
 Kai M{kisara
index 1cdad2c0dd3f93fd03e3a3483f5a2147d49b81af..bdd3f9285fab9a57d2ad2b0dda91b03c3c09094f 100644 (file)
@@ -1,6 +1,6 @@
 /* aha152x.c -- Adaptec AHA-152x driver
  * Author: Juergen E. Fischer, fischer@et-inf.fho-emden.de
- * Copyright 1993, 1994, 1995 Juergen E. Fischer
+ * Copyright 1993, 1994, 1995, 1996 Juergen E. Fischer
  *
  *
  * This driver is based on
  * General Public License for more details.
  *
  *
- * $Id: aha152x.c,v 1.14 1996/01/17 15:11:20 fischer Exp fischer $
+ * $Id: aha152x.c,v 1.15 1996/04/30 14:52:06 fischer Exp fischer $
  *
  * $Log: aha152x.c,v $
+ * Revision 1.15  1996/04/30 14:52:06  fischer
+ * - proc info fixed
+ * - support for extended translation for >1GB disks
+ *
  * Revision 1.14  1996/01/17  15:11:20  fischer
  * - fixed lockup in MESSAGE IN phase after reconnection
  *
@@ -1205,18 +1209,23 @@ int aha152x_reset(Scsi_Cmnd *SCpnt)
  */
 int aha152x_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array)
 {
-  int size = disk->capacity;
-
 #if defined(DEBUG_BIOSPARAM)
   if(HOSTDATA(shpnt)->debug & debug_biosparam)
-    printk("aha152x_biosparam: dev=%s, size=%d, ", kdevname(dev), size);
-#endif
-  
-/* I took this from other SCSI drivers, since it provides
-   the correct data for my devices. */
-  info_array[0]=64;
-  info_array[1]=32;
-  info_array[2]=size>>11;
+    printk("aha152x_biosparam: dev=%s, size=%d, ",
+           kdevname(dev), disk->capacity);
+#endif
+  
+  if(disk->capacity<=1024*64*32) {
+    info_array[0]=64;
+    info_array[1]=32;
+    info_array[2]=disk->capacity / (64 * 32);
+  } else {
+    info_array[0] = 256;
+    info_array[1] = 63;
+    info_array[2] = disk->capacity / (256 * 63);
+    if(info_array[2] > 1023)
+      info_array[2]=1023;
+  }
 
 #if defined(DEBUG_BIOSPARAM)
   if(HOSTDATA(shpnt)->debug & debug_biosparam)
index 0b2bb3bdb638fe24408a6369faa67d206b58299e..46c384adf8863d041459c008c6b7865d621d6eef 100644 (file)
@@ -2,7 +2,7 @@
 #define _AHA152X_H
 
 /*
- * $Id: aha152x.h,v 1.14 1996/01/17 15:13:36 fischer Exp fischer $
+ * $Id: aha152x.h,v 1.15 1996/04/30 14:59:35 fischer Exp $
  */
 
 #if defined(__KERNEL__)
@@ -23,7 +23,7 @@ int aha152x_proc_info(char *buffer, char **start, off_t offset, int length, int
    (unless we support more than 1 cmd_per_lun this should do) */
 #define AHA152X_MAXQUEUE       7               
 
-#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.14 $"
+#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.15 $"
 
 extern struct proc_dir_entry proc_scsi_aha152x;
 
index 0ad5eea77833024d82d785334fdba84758c671fc..fc0702b624f5dd087da9003bdc0fc04c3daf1cbc 100644 (file)
@@ -1686,6 +1686,9 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, char channel,
     {
       aic7xxx_reset_current_bus(base);
     }
+    /* Ensure we don't get a RSTI interrupt from this. */
+    outb(CLRSCSIRSTI | CLRSELTIMEO, CLRSINT1 + base);
+    outb(CLRSCSIINT, CLRINT + base);
     outb(sblkctl, SBLKCTL + base);
 
     UNPAUSE_SEQUENCER(p);
@@ -1703,6 +1706,10 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, char channel,
     {
       aic7xxx_reset_current_bus(base);
     }
+    /* Ensure we don't get a RSTI interrupt from this. */
+    outb(CLRSCSIRSTI | CLRSELTIMEO, CLRSINT1 + base);
+    outb(CLRSCSIINT, CLRINT + base);
+
     RESTART_SEQUENCER(p);
 #ifdef AIC7XXX_DEBUG_ABORT
     printk ("aic7xxx: (reset_channel) Channel reset, sequencer restarted\n");
@@ -3320,19 +3327,27 @@ aic7xxx_register(Scsi_Host_Template *template,
        * so we default it to 100%.
        */
       config->bus_speed = DFTHRSH_100;
-      scsi_conf = config->scsi_id | config->bus_speed;
+      scsi_conf = config->scsi_id | DFTHRSH_100;
+#if 0
       if (config->parity == AIC_ENABLED)
       {
         scsi_conf |= ENSPCHK;
       }
-
+#endif
       outb(scsi_conf, SCSICONF + base);
-      outb(config->bus_speed, DSPCISTATUS + base);
+      outb(DFTHRSH_100, DSPCISTATUS + base);
 
       /*
        * In case we are a wide card...
        */
-      outb(scsi_conf, (SCSICONF + base + 1));
+/*
+ * Try the following:
+ *
+ * 1) outb(config->scsi_id, SCSICONF + base + 1);
+ * 2) outb(scsiconf, SCSICONF + base + 1);
+ *
+ */
+      outb(config->scsi_id, SCSICONF + base + 1);
 
       printk("aic7xxx: Extended translation %sabled.\n",
             config->extended ? "en" : "dis");
@@ -3578,7 +3593,7 @@ aic7xxx_register(Scsi_Host_Template *template,
     outb(config->scsi_id_b, SCSIID + base);
     scsi_conf = inb(SCSICONF + base + 1) & (ENSPCHK | STIMESEL);
     outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base);
-    outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1 + base);
+    outb(ENSELTIMO, SIMODE1 + base);
     if (p->ultra_enabled)
     {
       outb(DFON | SPIOEN | ULTRAEN, SXFRCTL0 + base);
@@ -3596,7 +3611,7 @@ aic7xxx_register(Scsi_Host_Template *template,
   outb(config->scsi_id, SCSIID + base);
   scsi_conf = inb(SCSICONF + base) & (ENSPCHK | STIMESEL);
   outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base);
-  outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1 + base);
+  outb(ENSELTIMO, SIMODE1 + base);
   if (p->ultra_enabled)
   {
     outb(DFON | SPIOEN | ULTRAEN, SXFRCTL0 + base);
@@ -3773,6 +3788,10 @@ aic7xxx_register(Scsi_Host_Template *template,
       udelay(1000);
       outb(0, SCSISEQ + base);
 
+      /* Ensure we don't get a RSTI interrupt from this. */
+      outb(CLRSCSIRSTI, CLRSINT1 + base);
+      outb(CLRSCSIINT, CLRINT + base);
+
       /*
        * Select Channel A.
        */
@@ -3783,6 +3802,10 @@ aic7xxx_register(Scsi_Host_Template *template,
     udelay(1000);
     outb(0, SCSISEQ + base);
 
+    /* Ensure we don't get a RSTI interrupt from this. */
+    outb(CLRSCSIRSTI, CLRSINT1 + base);
+    outb(CLRSCSIINT, CLRINT + base);
+
     aic7xxx_delay(AIC7XXX_RESET_DELAY);
 
     printk("done.\n");
index b2d727133c070b2e90d095cbf1ef07a702030bdc..139a88ec001543a2d549c6abf9de3139ce965c2b 100644 (file)
@@ -4,7 +4,7 @@
 #ifndef _EATA_H
 #define _EATA_H
 
-#include <linux/scsicam.h>
+#include <scsi/scsicam.h>
 
 int eata2x_detect(Scsi_Host_Template *);
 int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
index efb5565e1ca89e25ac546c10931c6cebabb5ab15..43e75f949fb1a0c7e8374e118c345dbe5138b78a 100644 (file)
@@ -48,7 +48,7 @@
  * Thanks also to Greg Hosler who did a lot of testing and  *
  * found quite a number of bugs during the development.            *
  ************************************************************
- *  last change: 95/11/29                 OS: Linux 1.3.45  *
+ *  last change: 95/04/27                 OS: Linux 1.3.95  *
  ************************************************************/
 
 /* Look in eata_dma.h for configuration and revision information */
@@ -71,7 +71,6 @@
 #include "scsi.h"
 #include "sd.h"
 #include "hosts.h"
-#include <linux/scsicam.h>
 #include "eata_dma.h"
 #include "eata_dma_proc.h" 
 
@@ -371,28 +370,13 @@ int eata_queue(Scsi_Cmnd * cmd, void (* done) (Scsi_Cmnd *))
     hd->last_ccb = y;
 
     if (x >= sh->can_queue) { 
-       uint z;
-       
-       printk(KERN_EMERG "eata_dma: run out of queue slots cmdno:%ld"
-              " intrno: %ld, can_queue: %d, x: %d, y: %d\n", 
-              queue_counter, int_counter, sh->can_queue, x, y);
-       printk(KERN_EMERG "Status of queueslots:");
-       for(z = 0; z < sh->can_queue; z +=2) {
-           switch(hd->ccb[z].status) {
-           case FREE:
-               printk(KERN_EMERG "Slot %2d is FREE  \t", z);
-               break;
-           case USED:
-               printk(KERN_EMERG "Slot %2d is USED  \t", z);
-               break;
-           case LOCKED:
-               printk(KERN_EMERG "Slot %2d is LOCKED\t", z);
-               break;
-           default:
-               printk(KERN_EMERG "Slot %2d is UNKNOWN\t", z);
-           }
-           panic("\nSystem halted.\n");
-       }
+       cmd->result = DID_BUS_BUSY << 16;
+       DBG(DBG_QUEUE && DBG_ABNORM, 
+           printk(KERN_CRIT "eata_queue pid %ld, HBA QUEUE FULL..., "
+                  "returning DID_BUS_BUSY\n", cmd->pid));
+       done(cmd);
+       restore_flags(flags);
+       return(0);
     }
     cp = &hd->ccb[y];
     
@@ -573,7 +557,7 @@ int eata_abort(Scsi_Cmnd * cmd)
     panic("eata_dma: abort: invalid slot status\n");
 }
 
-int eata_reset(Scsi_Cmnd * cmd)
+int eata_reset(Scsi_Cmnd * cmd, int resetflags)
 {
     ushort x, z; 
     ulong time, limit = 0;
@@ -688,6 +672,87 @@ int eata_reset(Scsi_Cmnd * cmd)
     }
 }
 
+/* Here we try to determine the optimum queue depth for
+ * each attached device.
+ *
+ * At the moment the algorithm is rather simple
+ */
+static void eata_select_queue_depths(struct Scsi_Host *host, Scsi_Device *devicelist)
+{
+    Scsi_Device *device;
+    int devcount = 0; 
+    int factor = 0;
+    
+    
+    /* First we do a sample run go find out what we have */
+    for(device = devicelist; device != NULL; device = device->next) {
+        if (device->host == host) {
+           devcount++;
+           switch(device->type) {
+           case TYPE_DISK:
+           case TYPE_MOD:
+               factor += TYPE_DISK_QUEUE;
+               break;
+           case TYPE_TAPE:
+               factor += TYPE_TAPE_QUEUE;
+               break;
+           case TYPE_WORM:
+           case TYPE_ROM:
+               factor += TYPE_ROM_QUEUE;
+               break;
+           case TYPE_PROCESSOR:
+           case TYPE_SCANNER:
+           default:
+               factor += TYPE_OTHER_QUEUE;
+               break;
+           }
+       }
+    }
+
+    DBG(DBG_REGISTER, printk(KERN_DEBUG "scsi%d: needed queueslots %d\n", 
+                            host->host_no, factor));
+
+    if(factor == 0)    /* We don't want to get a DIV BY ZERO error */
+        factor = 1;
+
+    factor = (SD(host)->queuesize * 10) / factor;
+
+    DBG(DBG_REGISTER, printk(KERN_DEBUG "scsi%d: using factor %dE-1\n", 
+                            host->host_no, factor));
+
+    /* Now that have the factor we can set the individual queuesizes */
+    for(device = devicelist; device != NULL; device = device->next) {
+        if(device->host == host) {
+           if(SD(device->host)->bustype != IS_ISA){
+               switch(device->type) {
+               case TYPE_DISK:
+               case TYPE_MOD:
+                   device->queue_depth = (TYPE_DISK_QUEUE * factor) / 10;
+                   break;
+               case TYPE_TAPE:
+                   device->queue_depth = (TYPE_TAPE_QUEUE * factor) / 10;
+                   break;
+               case TYPE_WORM:
+               case TYPE_ROM:
+                   device->queue_depth = (TYPE_ROM_QUEUE * factor) / 10;
+                   break;
+               case TYPE_PROCESSOR:
+               case TYPE_SCANNER:
+               default:
+                   device->queue_depth = (TYPE_OTHER_QUEUE * factor) / 10;
+                   break;
+               }
+           } else /* ISA forces us to limit the QS because of bounce buffers*/
+               device->queue_depth = 2; /* I know this is cruel */
+
+           printk(KERN_INFO "scsi%d: queue depth for target %d on channel %d set "
+                  "to %d\n", host->host_no, device->id, device->channel,
+                  device->queue_depth);
+       }
+    }
+}
+
+
 char * get_board_data(u32 base, u32 irq, u32 id)
 {
     struct eata_ccb *cp;
@@ -1040,17 +1105,11 @@ short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt,
      * SCSI midlevel code should support different HBA ids on every channel
      */
     sh->this_id = gc->scsi_id[3];
+
+    hd->queuesize = ntohs(gc->queuesiz);
     sh->can_queue = ntohs(gc->queuesiz);
-    
-    if (gc->OCS_enabled == TRUE) {
-       if(hd->bustype != IS_ISA)
-           sh->cmd_per_lun = sh->can_queue/C_P_L_DIV; 
-       else
-           sh->cmd_per_lun = 8; /* We artificially limit this to conserve 
-                                 * memory, which would be needed for ISA 
-                                 * bounce buffers */
-    } else 
-       sh->cmd_per_lun = 1;
+    sh->cmd_per_lun = 0;
+    sh->select_queue_depths = eata_select_queue_depths;
     
     /* FIXME:
      * SG should be allocated more dynamically 
@@ -1062,7 +1121,7 @@ short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt,
      */
     if (gc->SG_64K == TRUE && ntohs(gc->SGsiz) == 64 && hd->bustype != IS_ISA){
        sh->sg_tablesize = SG_SIZE_BIG;
-       sh->use_clustering = FALSE;
+       sh->use_clustering = TRUE;
     } else {
        sh->sg_tablesize = ntohs(gc->SGsiz);
        sh->use_clustering = TRUE;
index 41504673a5dd86e45a829d0ed9b86e985dac9d39..7aec03e5bb45848c80c6c140406b5e8c94112125 100644 (file)
@@ -73,7 +73,7 @@ int eata_release(struct Scsi_Host *);
 #define eata_release NULL  
 #endif
 
-#include <linux/scsicam.h>
+#include <scsi/scsicam.h>
 
 #define EATA_DMA {                   \
         NULL, NULL,                  \
index 4d9fc497496a1825155e73c5175aff1f73c73500..b68e329b48426e02224059093645cce301f7feef 100644 (file)
 #define MAX_PCI_BUS    16             /* Maximum # Of Busses Allowed    */
 
 #define SG_SIZE                64 
-#define SG_SIZE_BIG    509            /* max. 509 elements, one 4k page */
-
-#define C_P_L_DIV      2 /* 1 <= C_P_L_DIV <= 8            
-                          * You can use this parameter to fine-tune
-                          * the driver. Depending on the number of 
-                          * devices and their speed and ability to queue 
-                          * commands, you will get the best results with a
-                          * value
-                          * ~= numdevices-(devices_unable_to_queue_commands/2)
-                          * The reason for this is that the disk driver 
-                          * tends to flood the queue, so that other 
-                          * drivers have problems to queue commands 
-                          * themselves. This can for example result in 
-                          * the effect that the tape stops during disk 
-                          * accesses. 
-                          */
+#define SG_SIZE_BIG    252            /* max. 8096 elements, 64k */
+
+#define TYPE_DISK_QUEUE  16
+#define TYPE_TAPE_QUEUE  4
+#define TYPE_ROM_QUEUE   4
+#define TYPE_OTHER_QUEUE 2
 
 #define FREE      0
 #define OK        0
@@ -350,6 +340,7 @@ typedef struct hstd {
     __u32  last_ccb;            /* Last used ccb              */
     __u32  cplen;               /* size of CP in words        */
     __u16  cppadlen;            /* pad length of cp in words  */
+    int    queuesize;
     __u8   hostid;              /* SCSI ID of HBA             */
     __u8   devflags;            /* bits set for detected devices */
     __u8   moresupport;                 /* HBA supports MORE flag     */
index e48b3b06b17b04e80bd98fb58e07518f05c513a8..e6740c098154af7d7cc6c3656c358ae501efeb33 100644 (file)
@@ -10,9 +10,9 @@
  *      -supports all EATA-PIO boards                       *
  *      -only supports DASD devices                         *
  *                                                          *
- *  (c)1993,94,95 Michael Neuffer, Alfred Arnold            *
- *                neuffer@goofy.zdv.uni-mainz.de            *
- *                a.arnold@kfa-juelich.de                   * 
+ *  (c)1993-96 Michael Neuffer, Alfred Arnold               *
+ *             neuffer@goofy.zdv.uni-mainz.de               *
+ *             a.arnold@kfa-juelich.de                      * 
  *                                                          *
  *  This program is free software; you can redistribute it  *
  *  and/or modify it under the terms of the GNU General     *
@@ -32,7 +32,7 @@
  *  Cambridge, MA 02139, USA.                               *
  *                                                          *
  ************************************************************
- *  last change: 95/08/04                 OS: Linux 1.3.15  *
+ *  last change: 95/03/28                 OS: Linux 1.3.80  *
  ************************************************************/
 
 /* Look in eata_pio.h for configuration information */
@@ -240,7 +240,8 @@ void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs * regs)
        if (cp->status == LOCKED) {
            cp->status = FREE;
            eata_stat = inb(base + HA_RSTATUS);
-           printk("eata_pio: int_handler, freeing locked queueslot\n");
+           printk(KERN_NOTICE "eata_pio: int_handler, freeing locked "
+                   "queueslot\n");
            DBG(DBG_INTR&&DBG_DELAY,DEL2(800));
            restore_flags(flags);
            return;
@@ -248,7 +249,8 @@ void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs * regs)
        
 #if DBG_INTR2
        if (stat != 0x50) 
-           printk("stat: %#.2x, result: %#.8x\n", stat, cmd->result); 
+           printk(KERN_DEBUG "stat: %#.2x, result: %#.8x\n", stat, 
+                   cmd->result); 
        DBG(DBG_INTR&&DBG_DELAY,DEL2(800));
 #endif
        
@@ -301,12 +303,13 @@ int eata_pio_queue(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
     
     if (hd->ccb[y].status!=FREE) { 
        
-       DBG(DBG_QUEUE, printk("can_queue %d, x %d, y %d\n",sh->can_queue,x,y));
+       DBG(DBG_QUEUE, printk(KERN_EMERG "can_queue %d, x %d, y %d\n",
+                              sh->can_queue,x,y));
 #if DEBUG_EATA
-       panic("eata_pio: run out of queue slots cmdno:%ld intrno: %ld\n", 
-             queue_counter, int_counter);
+       panic(KERN_EMERG "eata_pio: run out of queue slots cmdno:%ld "
+              "intrno: %ld\n", queue_counter, int_counter);
 #else
-       panic("eata_pio: run out of queue slots....\n");
+       panic(KERN_EMERG "eata_pio: run out of queue slots....\n");
 #endif
     }
     
@@ -317,8 +320,8 @@ int eata_pio_queue(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
        
     cp->status = USED;      /* claim free slot */
 
-    DBG(DBG_QUEUE, printk("eata_pio_queue pid %ld, target: %x, lun: %x, y %d\n",
-                         cmd->pid, cmd->target, cmd->lun, y));
+    DBG(DBG_QUEUE, printk(KERN_DEBUG "eata_pio_queue pid %ld, target: %x, lun:"
+                          " %x, y %d\n", cmd->pid, cmd->target, cmd->lun, y));
     DBG(DBG_QUEUE && DBG_DELAY, DEL2(250));
     
     cmd->scsi_done = (void *)done;
@@ -378,8 +381,8 @@ int eata_pio_queue(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
     if (eata_pio_send_command(base, EATA_CMD_PIO_SEND_CP)) 
     {
        cmd->result = DID_BUS_BUSY << 16;
-       printk("eata_pio_queue target %d, pid %ld, HBA busy, returning "
-               "DID_BUS_BUSY, done.\n", cmd->target, cmd->pid);
+       printk(KERN_NOTICE "eata_pio_queue target %d, pid %ld, HBA busy, "
+               "returning DID_BUS_BUSY, done.\n", cmd->target, cmd->pid);
         done(cmd);
         cp->status = FREE;      
         restore_flags(flags);
@@ -390,8 +393,8 @@ int eata_pio_queue(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
     outb(EATA_CMD_PIO_TRUNC, base + HA_WCOMMAND);
     for (x = 0; x < hd->cppadlen; x++) outw(0, base + HA_RDATA);
     
-    DBG(DBG_QUEUE,printk("Queued base %#.4lx pid: %ld target: %x lun: %x "
-                        "slot %d irq %d\n", (long)sh->base, cmd->pid, 
+    DBG(DBG_QUEUE,printk(KERN_DEBUG "Queued base %#.4lx pid: %ld target: %x "
+                         "lun: %x slot %d irq %d\n", (long)sh->base, cmd->pid, 
                         cmd->target, cmd->lun, y, sh->irq));
     DBG(DBG_QUEUE && DBG_DELAY, DEL2(200));
     
@@ -407,38 +410,39 @@ int eata_pio_abort(Scsi_Cmnd * cmd)
     save_flags(flags);
     cli();
     
-    DBG(DBG_ABNORM, printk("eata_pio_abort called pid: %ld target: %x lun: %x"
-                           " reason %x\n", cmd->pid, cmd->target, cmd->lun
-                           cmd->abort_reason));
+    DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_abort called pid: %ld "
+                           "target: %x lun: %x reason %x\n", cmd->pid
+                           cmd->target, cmd->lun, cmd->abort_reason));
     DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
     
     
     while (inb((uint)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY)
        if (--loop == 0) {
-           printk("eata_pio: abort, timeout error.\n");
+           printk(KERN_WARNING "eata_pio: abort, timeout error.\n");
            restore_flags(flags);
            DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
            return (SCSI_ABORT_ERROR);
        }
     if (CD(cmd)->status == FREE) {
-       DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_NOT_RUNNING\n")); 
+       DBG(DBG_ABNORM, printk(KERN_WARNING "Returning: SCSI_ABORT_NOT_RUNNING\n")); 
        restore_flags(flags);
        return (SCSI_ABORT_NOT_RUNNING);
     }
     if (CD(cmd)->status == USED) {
-       DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_BUSY\n"));
+       DBG(DBG_ABNORM, printk(KERN_WARNING "Returning: SCSI_ABORT_BUSY\n"));
        restore_flags(flags);
        return (SCSI_ABORT_BUSY);  /* SNOOZE */ 
     }
     if (CD(cmd)->status == RESET) {
        restore_flags(flags);
-       printk("eata_pio: abort, command reset error.\n");
+       printk(KERN_WARNING "eata_pio: abort, command reset error.\n");
        DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
        return (SCSI_ABORT_ERROR);
     }
     if (CD(cmd)->status == LOCKED) {
        restore_flags(flags);
-       DBG(DBG_ABNORM, printk("eata_pio: abort, queue slot locked.\n"));
+       DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio: abort, queue slot "
+                               "locked.\n"));
        DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
        return (SCSI_ABORT_NOT_RUNNING);
     }
@@ -446,7 +450,7 @@ int eata_pio_abort(Scsi_Cmnd * cmd)
     panic("eata_pio: abort: invalid slot status\n");
 }
 
-int eata_pio_reset(Scsi_Cmnd * cmd)
+int eata_pio_reset(Scsi_Cmnd * cmd, int dummy)
 {
     uint x, z, time, limit = 0;
     ulong flags;
@@ -456,12 +460,12 @@ int eata_pio_reset(Scsi_Cmnd * cmd)
     save_flags(flags);
     cli();
     hprint("reset");
-    DBG(DBG_ABNORM, printk("eata_pio_reset called pid:%ld target: %x lun: %x "
-                          "reason %x\n", cmd->pid, cmd->target, cmd->lun
-                          cmd->abort_reason));
+    DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset called pid:%ld target:"
+                           " %x lun: %x reason %x\n", cmd->pid, cmd->target
+                           cmd->lun, cmd->abort_reason));
 
     if (HD(cmd)->state == RESET) {
-       printk("eata_pio_reset: exit, already in reset.\n");
+       printk(KERN_WARNING "eata_pio_reset: exit, already in reset.\n");
        restore_flags(flags);
        DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
        return (SCSI_RESET_ERROR);
@@ -481,7 +485,8 @@ int eata_pio_reset(Scsi_Cmnd * cmd)
        
        sp = HD(cmd)->ccb[x].cmd;
        HD(cmd)->ccb[x].status = RESET;
-       printk("eata_pio_reset: slot %d in reset, pid %ld.\n", x, sp->pid);
+       printk(KERN_WARNING "eata_pio_reset: slot %d in reset, pid %ld.\n", x,
+               sp->pid);
        DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
        
        if (sp == NULL)
@@ -492,13 +497,14 @@ int eata_pio_reset(Scsi_Cmnd * cmd)
     /* hard reset the HBA  */
     outb((uint) cmd->host->base+HA_WCOMMAND, EATA_CMD_RESET);
     
-    DBG(DBG_ABNORM, printk("eata_pio_reset: board reset done.\n"));
+    DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: board reset done.\n"));
     HD(cmd)->state = RESET;
     
     time = jiffies;
     while (jiffies < (time + (3 * HZ)) && limit++ < 10000000);
     
-    DBG(DBG_ABNORM, printk("eata_pio_reset: interrupts disabled, loops %d.\n", limit));
+    DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: interrupts disabled, "
+                           "loops %d.\n", limit));
     DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
     
     for (x = 0; x < cmd->host->can_queue; x++) {
@@ -511,7 +517,7 @@ int eata_pio_reset(Scsi_Cmnd * cmd)
        sp->result = DID_RESET << 16;
        
        /* This mailbox is terminated */
-       printk("eata_pio_reset: reset ccb %d.\n",x);
+       printk(KERN_WARNING "eata_pio_reset: resetted ccb %d.\n",x);
        HD(cmd)->ccb[x].status = FREE;
        
        restore_flags(flags);
@@ -523,11 +529,11 @@ int eata_pio_reset(Scsi_Cmnd * cmd)
     restore_flags(flags);
     
     if (success) { /* hmmm... */
-       DBG(DBG_ABNORM, printk("eata_pio_reset: exit, success.\n"));
+       DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: exit, success.\n"));
        DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
        return (SCSI_RESET_SUCCESS);
     } else {
-       DBG(DBG_ABNORM, printk("eata_pio_reset: exit, wakeup.\n"));
+       DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: exit, wakeup.\n"));
        DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
        return (SCSI_RESET_PUNT);
     }
@@ -594,7 +600,7 @@ int get_pio_conf_PIO(u32 base, struct get_conf *buf)
            return (FALSE);
     
     DBG(DBG_PIO && DBG_PROBE,
-       printk("Issuing PIO READ CONFIG to HBA at %#x\n", base));
+       printk(KERN_DEBUG "Issuing PIO READ CONFIG to HBA at %#x\n", base));
     eata_pio_send_command(base, EATA_CMD_PIO_READ_CONFIG);
 
     loop = R_LIMIT;
@@ -609,8 +615,8 @@ int get_pio_conf_PIO(u32 base, struct get_conf *buf)
     }
     if (!(inb(base + HA_RSTATUS) & HA_SERROR)) {            /* Error ? */
        if (htonl(EATA_SIGNATURE) == buf->signature) {
-           DBG(DBG_PIO&&DBG_PROBE, printk("EATA Controller found at %#4x "
-                                          "EATA Level: %x\n", base, 
+           DBG(DBG_PIO&&DBG_PROBE, printk(KERN_NOTICE "EATA Controller found "
+                                           "at %#4x EATA Level: %x\n", base, 
                                           (uint) (buf->version)));
            
            while (inb(base + HA_RSTATUS) & HA_SDRQ) 
@@ -852,7 +858,8 @@ void find_pio_EISA(struct get_conf *buf, Scsi_Host_Template * tpnt)
            if (((pal1 == 0x12) && (pal2 == 0x14)) ||
                ((pal1 == 0x38) && (pal2 == 0xa3) && (pal3 == 0x82)) ||
                ((pal1 == 0x06) && (pal2 == 0x94) && (pal3 == 0x24))) {
-               DBG(DBG_PROBE, printk("EISA EATA id tags found: %x %x %x \n",
+               DBG(DBG_PROBE, printk(KERN_NOTICE "EISA EATA id tags found: "
+                                      "%x %x %x \n",
                                      (int)pal1, (int)pal2, (int)pal3));
 #endif
                if (get_pio_conf_PIO(base, buf) == TRUE) {
@@ -860,7 +867,8 @@ void find_pio_EISA(struct get_conf *buf, Scsi_Host_Template * tpnt)
                    if (buf->IRQ) {
                        register_pio_HBA(base, buf, tpnt);
                    } else
-                       printk("eata_dma: No valid IRQ. HBA removed from list\n");
+                       printk(KERN_NOTICE "eata_dma: No valid IRQ. HBA "
+                               "removed from list\n");
                }
                /* Nothing found here so we take it from the list */
                EISAbases[i] = 0;
@@ -876,7 +884,8 @@ void find_pio_PCI(struct get_conf *buf, Scsi_Host_Template * tpnt)
 {
 
 #ifndef CONFIG_PCI
-    printk("eata_pio: kernel PCI support not enabled. Skipping scan for PCI HBAs.\n");
+    printk(KERN_ERR "eata_pio: kernel PCI support not enabled. Skipping scan "
+           "for PCI HBAs.\n");
 #else
     
     u8 pci_bus, pci_device_fn;
index 8a626e0be548c800124696a984986350ed95c7f0..3c25bf51e497b38ebc75b2b62d02055841e4f8d4 100644 (file)
@@ -1,6 +1,6 @@
 /********************************************************
 * Header file for eata_pio.c Linux EATA-PIO SCSI driver *
-* (c) 1993,94,95 Michael Neuffer                       *
+* (c) 1993-96 Michael Neuffer                                  *
 *********************************************************
 * last change: 95/06/21                                        *
 ********************************************************/
@@ -12,7 +12,7 @@
 #include <linux/blk.h>
 #include "scsi.h"
 #include "hosts.h"
-#include <linux/scsicam.h>
+#include <scsi/scsicam.h>
 
 #ifndef HOSTS_C
 #include "eata_generic.h"
index b863bf2e88f0e6d4ef60bd0621ca91454a3594c0..03585b00ca51c52c8223d54db15558c158071d6a 100644 (file)
@@ -1913,7 +1913,7 @@ int fdomain_16x0_reset( Scsi_Cmnd *SCpnt )
 }
 
 #include "sd.h"
-#include "scsi_ioctl.h"
+#include <scsi/scsi_ioctl.h>
 
 int fdomain_16x0_biosparam( Scsi_Disk *disk, kdev_t dev, int *info_array )
 {
index c9c2a5f6f6d59f71539169a95c51962a5c8a3784..c7b1f47d9a2252e66c49c79880a68c8aa3964bdc 100644 (file)
@@ -29,9 +29,9 @@
  * Bill Earnest, Larry Doolittle, Roger Sunshine, John Luckey,
  * Matt Postiff, Peter Lu, zerucha@shell.portal.com, and Eric
  * Youngdale). I should also mention the driver written by
- * Hamish Mcdonald for the (GASP!) Amiga A2091 card, included
+ * Hamish Macdonald for the (GASP!) Amiga A2091 card, included
  * in the Linux-m68k distribution; it gave me a good initial
- * understandng of the proper way to run a WD33c93 chip, and I
+ * understanding of the proper way to run a WD33c93 chip, and I
  * ended up stealing lots of code from it.
  *
  * _This_ driver is (I feel) an improvement over the old one in
@@ -663,7 +663,7 @@ no:
             if ((i = cmd->SCp.this_residual) > (IN2000_FIFO_SIZE - 16) )
                i = IN2000_FIFO_SIZE - 16;
             cmd->SCp.have_data_in = i;    /* this much data in fifo */
-            i >>= 1;                      /* Gulp. Assumimg modulo 2. */
+            i >>= 1;                      /* Gulp. Assuming modulo 2. */
             sp = (unsigned short *)cmd->SCp.ptr;
             f = hostdata->io_base + IO_FIFO;
 
@@ -1035,7 +1035,7 @@ DB(DB_FIFO,printk("{W:%02x} ",read1_io(IO_FIFO_COUNT)))
 DB(DB_INTR,printk("{%02x:%02x-",asr,sr))
 
 /* After starting a FIFO-based transfer, the next _WD3393_ interrupt is
- * guarenteed to be in response to the completion of the transfer.
+ * guaranteed to be in response to the completion of the transfer.
  * If we were reading, there's probably data in the fifo that needs
  * to be copied into RAM - do that here. Also, we have to update
  * 'this_residual' and 'ptr' based on the contents of the
@@ -1851,7 +1851,7 @@ unsigned long timeout;
  *
  * We probably reached this point because of an unlikely race condition
  * between the command completing successfully and the abortion code,
- * so we won't panic, but we will notify the user in case somethign really
+ * so we won't panic, but we will notify the user in case something really
  * broke.
  */
 
index 89ba63ff5f44a8d64b3833269d2fd25002e804fb..6280b039035ac52cfe0669b189469a75cbd36752 100644 (file)
@@ -17,7 +17,7 @@ UPDATE NEWS: version 1.28 - 27 Apr 96
 
 UPDATE NEWS: version 1.27 - 10 Apr 96
 
-   Fixed a well-hidden bug in the adapative-disconnect code
+   Fixed a well-hidden bug in the adaptive-disconnect code
    that would show up every now and then during extreme
    heavy loads involving 2 or more simultaneously active
    devices. Thanks to Joe Mack for keeping my nose to the
@@ -152,14 +152,14 @@ line with the 'period' keyword.
    I should mention that Drew Eckhardt's 'Generic NCR5380' sources
    were my main inspiration, with lots of reference to the IN2000
    driver currently distributed in the kernel source. I also owe
-   much to a driver written by Hamish Mcdonald for Linux-m68k(!).
+   much to a driver written by Hamish Macdonald for Linux-m68k(!).
    And to Eric Wright for being an ALPHA guinea pig. And to Bill
    Earnest for 2 tons of great input and information. And to David
    Willmore for extensive 'bonnie' testing.
 
    Be forewarned that while I've had good luck with it, this
    is the first time it's been loose out in the wide world.
-   It wouldn't suprise me if people uncover problems that
+   It wouldn't surprise me if people uncover problems that
    I haven't caught....
 
    Please try the driver out. Test it, beat on it. And PLEASE get back
index 57bc3fc500a4c05884ed6b8b60a96d73364f8ffe..4bf48ec78a18c576db3be75814d51fde238963f5 100644 (file)
@@ -193,7 +193,7 @@ static void scsi_dump_status(void);
 #ifdef DEBUG
     #define SCSI_TIMEOUT (5*HZ)
 #else
-    #define SCSI_TIMEOUT (1*HZ)
+    #define SCSI_TIMEOUT (2*HZ)
 #endif
 
 #ifdef DEBUG
@@ -201,15 +201,15 @@ static void scsi_dump_status(void);
     #define ABORT_TIMEOUT SCSI_TIMEOUT
     #define RESET_TIMEOUT SCSI_TIMEOUT
 #else
-    #define SENSE_TIMEOUT (5*HZ/10)
-    #define RESET_TIMEOUT (5*HZ/10)
-    #define ABORT_TIMEOUT (5*HZ/10)
+    #define SENSE_TIMEOUT (1*HZ)
+    #define RESET_TIMEOUT (5*HZ)
+    #define ABORT_TIMEOUT (5*HZ)
 #endif
 
-#define MIN_RESET_DELAY (1*HZ)
+#define MIN_RESET_DELAY (3*HZ)
 
 /* Do not call reset on error if we just did a reset within 10 sec. */
-#define MIN_RESET_PERIOD (10*HZ)
+#define MIN_RESET_PERIOD (15*HZ)
 
 /* The following devices are known not to tolerate a lun != 0 scan for
  * one reason or another.  Some will respond to all luns, others will
@@ -580,7 +580,7 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
   printk("\n");
 #endif
 
-  if (SCpnt->result) {
+if (host_byte(SCpnt->result) != DID_OK) {
     if (((driver_byte (SCpnt->result) & DRIVER_SENSE) ||
          (status_byte (SCpnt->result) & CHECK_CONDITION)) &&
         ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) {
@@ -816,9 +816,10 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
  *  Flag bits for the internal_timeout array
  */
 #define NORMAL_TIMEOUT 0
-#define IN_ABORT 1
-#define IN_RESET 2
+#define IN_ABORT  1
+#define IN_RESET  2
 #define IN_RESET2 4
+#define IN_RESET3 8
 
 /*
  * This is our time out function, called when the timer expires for a
@@ -829,7 +830,7 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
 static void scsi_times_out (Scsi_Cmnd * SCpnt)
 {
     
-    switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET | IN_RESET2))
+    switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET | IN_RESET2 | IN_RESET3))
     {
     case NORMAL_TIMEOUT:
        {
@@ -851,14 +852,28 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt)
         * you might conceivably want the machine up and running
         * esp if you have an ide disk. 
         */
-       printk("SCSI host %d reset (pid %ld) timed out - trying harder\n",
-              SCpnt->host->host_no, SCpnt->pid);
+       printk("SCSI host %d channel %d reset (pid %ld) timed out - "
+               "trying harder\n",
+              SCpnt->host->host_no, SCpnt->channel, SCpnt->pid);
        SCpnt->internal_timeout &= ~IN_RESET;
        SCpnt->internal_timeout |= IN_RESET2;
         scsi_reset (SCpnt,
                    SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_BUS_RESET);
        return;
        
+    case (IN_ABORT | IN_RESET | IN_RESET2):
+       /* Obviously the bus reset didn't work.
+        * Let's try even harder and call for an HBA reset.
+         * Maybe the HBA itself crashed and this will shake it loose.
+        */
+       printk("SCSI host %d reset (pid %ld) timed out - trying to shake it loose\n",
+              SCpnt->host->host_no, SCpnt->pid);
+       SCpnt->internal_timeout &= ~(IN_RESET | IN_RESET2);
+       SCpnt->internal_timeout |= IN_RESET3;
+        scsi_reset (SCpnt,
+                   SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_HOST_RESET);
+       return;
+               
     default:
        printk("SCSI host %d reset (pid %ld) timed out again -\n",
               SCpnt->host->host_no, SCpnt->pid);
@@ -1946,7 +1961,7 @@ void scsi_mark_host_reset(struct Scsi_Host *Host)
 {
   Scsi_Cmnd *SCpnt;
   for (SCpnt = Host->host_queue; SCpnt; SCpnt = SCpnt->next)
-    scsi_mark_device_reset(SCpnt->device);
+      scsi_mark_device_reset(SCpnt->device);
 }
 
 
@@ -1968,8 +1983,8 @@ int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
     Scsi_Cmnd * SCpnt1;
     struct Scsi_Host * host = SCpnt->host;
 
-    printk("SCSI bus is being reset for host %d.\n",
-          host->host_no);
+    printk("SCSI bus is being reset for host %d channel %d.\n",
+          host->host_no, SCpnt->channel);
  
 #if 0
     /*
@@ -2096,7 +2111,7 @@ int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
                else scsi_mark_device_reset(SCpnt->device);
                save_flags(flags);
                cli();
-               SCpnt->internal_timeout &= ~IN_RESET;
+               SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
                restore_flags(flags);
                return 0;
            case SCSI_RESET_PENDING:
@@ -2108,7 +2123,7 @@ int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
            case SCSI_RESET_NOT_RUNNING:
                return 0;
            case SCSI_RESET_PUNT:
-                SCpnt->internal_timeout &= ~IN_RESET;
+               SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
                 scsi_request_sense (SCpnt);
                 return 0;
            case SCSI_RESET_WAKEUP:
@@ -2117,14 +2132,15 @@ int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
                else if (temp & SCSI_RESET_BUS_RESET)
                  scsi_mark_bus_reset(host, SCpnt->channel);
                else scsi_mark_device_reset(SCpnt->device);
-               SCpnt->internal_timeout &= ~IN_RESET;
+               SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
                scsi_request_sense (SCpnt);
                 /*
-                 * Since a bus reset was performed, we
+                 * If a bus reset was performed, we
                  * need to wake up each and every command
-                 * that was active on the bus.
+                 * that was active on the bus or if it was a HBA
+                 * reset all active commands on all channels
                  */
-                if( temp & SCSI_RESET_BUS_RESET )
+                if( temp & SCSI_RESET_HOST_RESET )
                 {
                    SCpnt1 = host->host_queue;
                    while(SCpnt1) {
@@ -2133,6 +2149,15 @@ int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
                            scsi_request_sense (SCpnt1);
                        SCpnt1 = SCpnt1->next;
                     }
+                } else if( temp & SCSI_RESET_BUS_RESET ) {
+                    SCpnt1 = host->host_queue;
+                    while(SCpnt1) {
+                        if(SCpnt1->request.rq_status != RQ_INACTIVE
+                           && SCpnt1 != SCpnt 
+                           && SCpnt1->channel == SCpnt->channel)
+                            scsi_request_sense (SCpnt);
+                        SCpnt1 = SCpnt1->next;
+                    }
                 }
                return 0;
            case SCSI_RESET_SNOOZE:
@@ -2143,7 +2168,7 @@ int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
                 */
                save_flags(flags);
                cli();
-               SCpnt->internal_timeout &= ~IN_RESET;
+               SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
                update_timeout(SCpnt, 0);
                restore_flags(flags);
                /* If you snooze, you lose... */
index e65bfcd1475d52ed7050491cfb80fe97f5531085..b6acbd57aa88b8331914a299ff1d108b6c72eb0f 100644 (file)
@@ -19,7 +19,7 @@
  * Some of the public constants are being moved to this file.
  * We include it here so that what came from where is transparent.
  */
-#include <linux/scsi.h>
+#include <scsi/scsi.h>
 
 
 /*
index 15c981ba2af68f2de2a1d4ea4f902621eeab48a4..e3453d1e9ddbbf3d34c7824fdc11f27dc32c7965 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/blk.h>
 #include "scsi.h"
 #include "hosts.h"
-#include "scsi_ioctl.h"
+#include <scsi/scsi_ioctl.h>
 
 #define MAX_RETRIES 5   
 #define MAX_TIMEOUT 900
diff --git a/drivers/scsi/scsi_ioctl.h b/drivers/scsi/scsi_ioctl.h
deleted file mode 100644 (file)
index a42fed0..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef _SCSI_IOCTL_H
-#define _SCSI_IOCTL_H 
-
-#define SCSI_IOCTL_SEND_COMMAND 1
-#define SCSI_IOCTL_TEST_UNIT_READY 2
-#define SCSI_IOCTL_BENCHMARK_COMMAND 3
-#define SCSI_IOCTL_SYNC 4                      /* Request synchronous parameters */
-/* The door lock/unlock constants are compatible with Sun constants for
-   the cdrom */
-#define SCSI_IOCTL_DOORLOCK 0x5380             /* lock the eject mechanism */
-#define SCSI_IOCTL_DOORUNLOCK 0x5381           /* unlock the mechanism   */
-
-#define        SCSI_REMOVAL_PREVENT    1
-#define        SCSI_REMOVAL_ALLOW      0
-
-extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
-extern int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
-
-#endif
-
-
index deab5c75a604398a378f775ea208e8863d62806c..a9d14f3b2aae237dad7abe5c6c9fd36c9598c2ca 100644 (file)
@@ -21,7 +21,7 @@
 #include <asm/dma.h>
 
 #include "scsi.h"
-#include "scsi_ioctl.h"
+#include <scsi/scsi_ioctl.h>
 #include "hosts.h"
 #include "constants.h"
 
index 9a446d3bde844982abc449e583114938a3962f7f..be690c0392d51993aae64ef393204be244c38f5e 100644 (file)
@@ -41,7 +41,7 @@
 #include "scsi.h"
 #include "hosts.h"
 #include "sd.h"
-#include "scsi_ioctl.h"
+#include <scsi/scsi_ioctl.h>
 #include "constants.h"
 
 #include <linux/genhd.h>
index 96ce7dda90613ea737e004bd4b30d5b3f025b872..bff43d9fdfebf07ba0ffab86eface4fd8dfe7a1b 100644 (file)
 
 #include <linux/blk.h>
 #include "scsi.h"
-#include "scsi_ioctl.h"
+#include <scsi/scsi_ioctl.h>
 #include "hosts.h"
 #include "sd.h"
-#include <linux/scsicam.h>     /* must follow "hosts.h" */
+#include <scsi/scsicam.h>     /* must follow "hosts.h" */
 
 int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
 {
index 91d68fc1c13ed2194c978f23da9caccbe29ae065..88aa97986e3b47cd907d4aa46b9ec190d1e3992a 100644 (file)
@@ -1632,7 +1632,7 @@ int seagate_st0x_reset (Scsi_Cmnd * SCpnt)
 
 #include <asm/segment.h>
 #include "sd.h"
-#include "scsi_ioctl.h"
+#include <scsi/scsi_ioctl.h>
 
 int seagate_st0x_biosparam(Disk * disk, kdev_t dev, int* ip) {
   unsigned char buf[256 + sizeof(int) * 2], cmd[6], *data, *page;
index a55e30b2e6db119ad7dd0168c0dab6eda5c7bede..bb1ff5bb3f8b9dbc754f2618b0d0e7ae0522227c 100644 (file)
@@ -24,8 +24,8 @@
 #include <linux/blk.h>
 #include "scsi.h"
 #include "hosts.h"
-#include "scsi_ioctl.h"
-#include "sg.h"
+#include <scsi/scsi_ioctl.h>
+#include <scsi/sg.h>
 
 static int sg_init(void);
 static int sg_attach(Scsi_Device *);
diff --git a/drivers/scsi/sg.h b/drivers/scsi/sg.h
deleted file mode 100644 (file)
index dc7d946..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-   History:
-    Started: Aug 9 by Lawrence Foard (entropy@world.std.com), to allow user 
-     process control of SCSI devices.
-    Development Sponsored by Killy Corp. NY NY
-*/
-
-/* 
- An SG device is accessed by writing "packets" to it, the replies
- are then read using the read call. The same header is used for 
- reply, just ignore reply_len field.
-*/
-
-struct sg_header
- {
-  int pack_len;    /* length of incoming packet <4096 (including header) */
-  int reply_len;   /* maximum length <4096 of expected reply */
-  int pack_id;     /* id number of packet */
-  int result;      /* 0==ok, otherwise refer to errno codes */
-  unsigned int twelve_byte:1; /* Force 12 byte command length for group 6 & 7 commands  */
-  unsigned int other_flags:31;                 /* for future use */
-  unsigned char sense_buffer[16]; /* used only by reads */
-  /* command follows then data for command */
- };
-
-/* ioctl's */
-#define SG_SET_TIMEOUT 0x2201  /* set timeout *(int *)arg==timeout */
-#define SG_GET_TIMEOUT 0x2202  /* get timeout return timeout */
-
-#define SG_DEFAULT_TIMEOUT (60*HZ) /* 1 minute timeout */
-#define SG_DEFAULT_RETRIES 1
-
-#define SG_MAX_QUEUE 4 /* maximum outstanding request, arbitrary, may be
-                         changed if sufficient DMA buffer room available */
-
-#define SG_BIG_BUFF 32768
index f7a9ea83d0eec44dabcf80c744eb4ccd5c72b158..783d9ba4e9d98bdcae676c0ef551df70e06207a2 100644 (file)
@@ -35,7 +35,7 @@
 #include "scsi.h"
 #include "hosts.h"
 #include "sr.h"
-#include "scsi_ioctl.h"   /* For the door lock/unlock commands */
+#include <scsi/scsi_ioctl.h>   /* For the door lock/unlock commands */
 #include "constants.h"
 
 #define MAX_RETRIES 3
index 6106fc9343a14e7df1d7a8d500ebbdc7f2cdf66a..26d2b36e729d11bc1823f15a99f183243205e315 100644 (file)
@@ -10,7 +10,7 @@
 #include "scsi.h"
 #include "hosts.h"
 #include "sr.h"
-#include "scsi_ioctl.h"
+#include <scsi/scsi_ioctl.h>
 
 #include <linux/cdrom.h>
 
@@ -555,12 +555,21 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
     }
        
     case BLKRASET:
+    {
        if(!suser())  return -EACCES;
        if(!(inode->i_rdev)) return -EINVAL;
        if(arg > 0xff) return -EINVAL;
        read_ahead[MAJOR(inode->i_rdev)] = arg;
        return 0;
        RO_IOCTLS(dev,arg);
+    }
+
+    case CDROMRESET:
+    {
+       invalidate_buffers(MKDEV(MAJOR(inode->i_rdev),MINOR(inode->i_rdev)));
+       return 0;
+    }
+
     default:
        return scsi_ioctl(scsi_CDs[target].device,cmd,(void *) arg);
     }
index e6e51c610405df14094c092c6d6a5a9c948ba543..b0aa76a1448da02b79a2d0669312b041687ebbde 100644 (file)
@@ -5,13 +5,13 @@
   History:
   Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.
   Contribution and ideas from several people including (in alphabetical
-  order) Klaus Ehrenfried, Steve Hirsch, Wolfgang Denk, Andreas Koppenh"ofer,
-  J"org Weule, and Eric Youngdale.
+  order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer,
+  Eyal Lebedinsky, J"org Weule, and Eric Youngdale.
 
   Copyright 1992 - 1996 Kai Makisara
                 email Kai.Makisara@metla.fi
 
-  Last modified: Wed Apr 24 09:53:23 1996 by root@kai.makisara.fi
+  Last modified: Thu May  2 19:41:34 1996 by makisara@kai.makisara.fi
   Some small formal changes - aeb, 950809
 */
 
@@ -43,7 +43,7 @@
 #include <linux/blk.h>
 #include "scsi.h"
 #include "hosts.h"
-#include "scsi_ioctl.h"
+#include <scsi/scsi_ioctl.h>
 #include "st.h"
 #include "constants.h"
 
@@ -72,7 +72,7 @@ static int debugging = 1;
 #define NO_TAPE  NOT_READY
 
 #define ST_TIMEOUT (900 * HZ)
-#define ST_LONG_TIMEOUT (2000 * HZ)
+#define ST_LONG_TIMEOUT (14000 * HZ)
 
 #define TAPE_NR(x) (MINOR(x) & ~(128 | ST_MODE_MASK))
 #define TAPE_MODE(x) ((MINOR(x) & ST_MODE_MASK) >> ST_MODE_SHIFT)
@@ -107,8 +107,11 @@ struct Scsi_Device_Template st_template = {NULL, "tape", "st", NULL, TYPE_TAPE,
 
 static int st_compression(Scsi_Tape *, int);
 
-static int st_int_ioctl(struct inode * inode,struct file * file,
-            unsigned int cmd_in, unsigned long arg);
+static int find_partition(struct inode *);
+static int update_partition(struct inode *);
+
+static int st_int_ioctl(struct inode * inode, unsigned int cmd_in,
+                       unsigned long arg);
 
 
 
@@ -424,11 +427,14 @@ flush_buffer(struct inode * inode, struct file * filp, int seek_next)
   if (STp->ready != ST_READY)
     return 0;
 
-  if (STp->rw == ST_WRITING)  /* Writing */
+  if (STp->ps[STp->partition].rw == ST_WRITING)  /* Writing */
     return flush_write_buffer(STp);
 
-  if (STp->block_size == 0)
+  if (STp->block_size == 0) {
+    STp->eof = ST_NOEOF;
+    STp->eof_hit = 0;
     return 0;
+  }
 
   backspace = ((STp->buffer)->buffer_bytes +
     (STp->buffer)->read_pointer) / STp->block_size -
@@ -446,7 +452,7 @@ flush_buffer(struct inode * inode, struct file * filp, int seek_next)
       }
     }
     if (!result && backspace > 0)
-      result = st_int_ioctl(inode, filp, MTBSR, backspace);
+      result = st_int_ioctl(inode, MTBSR, backspace);
   }
   else if ((STp->eof == ST_FM) && !STp->eof_hit) {
     (STp->mt_status)->mt_fileno++;
@@ -457,14 +463,49 @@ flush_buffer(struct inode * inode, struct file * filp, int seek_next)
 
 }
 
+\f/* Set the mode parameters */
+       static int
+set_mode_densblk(struct inode * inode, Scsi_Tape *STp, ST_mode *STm)
+{
+    int set_it = FALSE;
+    unsigned long arg;
+    int dev = TAPE_NR(inode->i_rdev);
+
+    if (!STp->density_changed &&
+       STm->default_density >= 0 &&
+       STm->default_density != STp->density) {
+      arg = STm->default_density;
+      set_it = TRUE;
+    }
+    else
+      arg = STp->density;
+    arg <<= MT_ST_DENSITY_SHIFT;
+    if (!STp->blksize_changed &&
+       STm->default_blksize >= 0 &&
+       STm->default_blksize != STp->block_size) {
+      arg |= STm->default_blksize;
+      set_it = TRUE;
+    }
+    else
+      arg |= STp->block_size;
+    if (set_it &&
+       st_int_ioctl(inode, SET_DENS_AND_BLK, arg)) {
+      printk(KERN_WARNING
+            "st%d: Can't set default block size to %d bytes and density %x.\n",
+            dev, STm->default_blksize, STm->default_density);
+      if (modes_defined)
+       return (-EINVAL);
+    }
+    return 0;
+}
+
 \f
 /* Open the device */
        static int
 scsi_tape_open(struct inode * inode, struct file * filp)
 {
     unsigned short flags;
-    int i, need_dma_buffer, new_session = FALSE, set_it;
-    unsigned int arg;
+    int i, need_dma_buffer, new_session = FALSE;
     unsigned char cmd[10];
     Scsi_Cmnd * SCpnt;
     Scsi_Tape * STp;
@@ -513,13 +554,13 @@ scsi_tape_open(struct inode * inode, struct file * filp)
       STp->buffer = st_buffers[i];
     (STp->buffer)->in_use = 1;
     (STp->buffer)->writing = 0;
-    STp->in_use = 1;
 
     flags = filp->f_flags;
     STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
 
     STp->dirty = 0;
-    STp->rw = ST_IDLE;
+    for (i=0; i < ST_NBR_PARTITIONS; i++)
+      STp->ps[i].rw = ST_IDLE;
     STp->ready = ST_READY;
     if (STp->eof != ST_EOD)  /* Save EOD across opens */
       STp->eof = ST_NOEOF;
@@ -547,6 +588,15 @@ scsi_tape_open(struct inode * inode, struct file * filp)
       (STp->mt_status)->mt_fileno = STp->drv_block = 0;
       STp->eof = ST_NOEOF;
       (STp->device)->was_reset = 0;
+      STp->partition = STp->new_partition = 0;
+      if (STp->can_partitions)
+       STp->nbr_partitions = 1;  /* This guess will be updated later if necessary */
+      for (i=0; i < ST_NBR_PARTITIONS; i++) {
+       STp->ps[i].rw = ST_IDLE;
+       STp->ps[i].moves_after_eof = 1;
+       STp->ps[i].at_sm = 0;
+       STp->ps[i].last_block_valid = FALSE;
+      }
       new_session = TRUE;
     }
 
@@ -566,7 +616,9 @@ scsi_tape_open(struct inode * inode, struct file * filp)
       STp->block_size = 0;
       STp->eof = ST_NOEOF;
       (STp->mt_status)->mt_fileno = STp->drv_block = 0;
+      STp->partition = STp->new_partition = 0;
       STp->door_locked = ST_UNLOCKED;
+      STp->in_use = 1;
       if (scsi_tapes[dev].device->host->hostt->usage_count)
        (*scsi_tapes[dev].device->host->hostt->usage_count)++;
       if(st_template.usage_count) (*st_template.usage_count)++;
@@ -645,7 +697,7 @@ scsi_tape_open(struct inode * inode, struct file * filp)
        printk(KERN_NOTICE "st%d: Blocksize %d too large for buffer.\n", dev,
               STp->block_size);
        (STp->buffer)->in_use = 0;
-       STp->in_use = 0;
+       STp->buffer = NULL;
        return (-EIO);
       }
       STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0;
@@ -673,52 +725,45 @@ scsi_tape_open(struct inode * inode, struct file * filp)
 #endif
       if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
        (STp->buffer)->in_use = 0;
-       STp->buffer = 0;
-       STp->in_use = 0;
+       STp->buffer = NULL;
        return (-EROFS);
       }
     }
 
-    if (new_session) {
+    if (STp->can_partitions && STp->nbr_partitions < 1) {
+      /* This code is reached when the device is opened for the first time
+        after the driver has been initialized with tape in the drive and the
+        partition support has been enabled. */
+#if DEBUG
+      if (debugging)
+       printk(ST_DEB_MSG "st%d: Updating partition number in status.\n", dev);
+#endif
+      if ((STp->partition = find_partition(inode)) < 0) {
+       (STp->buffer)->in_use = 0;
+       STp->buffer = NULL;
+       return STp->partition;
+      }
+      STp->new_partition = STp->partition;
+      STp->nbr_partitions = 1;  /* This guess will be updated when necessary */
+    }
+
+    if (new_session) {  /* Change the drive parameters for the new mode */
       STp->density_changed = STp->blksize_changed = FALSE;
       STp->compression_changed = FALSE;
-      if (!(STm->defaults_for_writes)) {
-       set_it = FALSE;
-       if (STm->default_density >= 0 &&
-           STm->default_density != STp->density) {
-         arg = STm->default_density;
-         set_it = TRUE;
-       }
-       else
-         arg = STp->density;
-       arg <<= MT_ST_DENSITY_SHIFT;
-       if (STm->default_blksize >= 0 &&
-           STm->default_blksize != STp->block_size) {
-         arg |= STm->default_blksize;
-         set_it = TRUE;
-       }
-       else
-         arg |= STp->block_size;
-       if (set_it &&
-           st_int_ioctl(inode, filp, SET_DENS_AND_BLK, arg)) {
-         printk(KERN_WARNING
-                "st%d: Can't set default block size to %d bytes and density %x.\n",
-                dev, STm->default_blksize, STm->default_density);
-         if (modes_defined) {
-           (STp->buffer)->in_use = 0;
-           STp->buffer = 0;
-           STp->in_use = 0;
-           return (-EINVAL);
-         }
-       }
+      if (!(STm->defaults_for_writes) &&
+         (i = set_mode_densblk(inode, STp, STm)) < 0) {
+       (STp->buffer)->in_use = 0;
+       STp->buffer = NULL;
+       return i;
       }
       if (STp->default_drvbuffer != 0xff) {
-       if (st_int_ioctl(inode, filp, MTSETDRVBUFFER, STp->default_drvbuffer))
+       if (st_int_ioctl(inode, MTSETDRVBUFFER, STp->default_drvbuffer))
          printk(KERN_WARNING "st%d: Can't set default drive buffering to %d.\n",
                 dev, STp->default_drvbuffer);
       }
     }
 
+    STp->in_use = 1;
     if (scsi_tapes[dev].device->host->hostt->usage_count)
       (*scsi_tapes[dev].device->host->hostt->usage_count)++;
     if(st_template.usage_count) (*st_template.usage_count)++;
@@ -741,7 +786,16 @@ scsi_tape_close(struct inode * inode, struct file * filp)
     dev = TAPE_NR(devt);
     STp = &(scsi_tapes[dev]);
 
-    if ( STp->rw == ST_WRITING && !(STp->device)->was_reset) {
+    if (STp->can_partitions &&
+       update_partition(inode) < 0) {
+#if DEBUG
+      if (debugging)
+       printk(ST_DEB_MSG "st%d: update_partition at close failed.\n", dev);
+#endif
+      goto out;
+    }
+
+    if ( STp->ps[STp->partition].rw == ST_WRITING && !(STp->device)->was_reset) {
 
       result = flush_write_buffer(STp);
 
@@ -762,7 +816,7 @@ scsi_tape_close(struct inode * inode, struct file * filp)
 
        SCpnt = st_do_scsi(NULL, STp, cmd, 0, ST_TIMEOUT, MAX_WRITE_RETRIES);
        if (!SCpnt)
-         return;
+         goto out;
 
        SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
 
@@ -790,18 +844,19 @@ scsi_tape_close(struct inode * inode, struct file * filp)
        back_over_eof(STp);
     }
 
+out:
     if (STp->rew_at_close)
-      st_int_ioctl(inode, filp, MTREW, 1);
+      st_int_ioctl(inode, MTREW, 1);
 
     if (STp->door_locked == ST_LOCKED_AUTO)
-      st_int_ioctl(inode, filp, MTUNLOCK, 0);
+      st_int_ioctl(inode, MTUNLOCK, 0);
 
     if (STp->buffer != NULL) {
       normalize_buffer(STp->buffer);
       (STp->buffer)->in_use = 0;
     }
-    STp->in_use = 0;
 
+    STp->in_use = 0;
     if (scsi_tapes[dev].device->host->hostt->usage_count)
       (*scsi_tapes[dev].device->host->hostt->usage_count)--;
     if(st_template.usage_count) (*st_template.usage_count)--;
@@ -816,13 +871,13 @@ st_write(struct inode * inode, struct file * filp, const char * buf, int count)
 {
     int total, do_count, blks, retval, transfer;
     int write_threshold;
-    int doing_write = 0, set_it;
-    unsigned int arg;
+    int doing_write = 0;
     static unsigned char cmd[10];
     const char *b_point;
     Scsi_Cmnd * SCpnt = NULL;
     Scsi_Tape * STp;
     ST_mode * STm;
+    ST_partstat * STps;
     int dev = TAPE_NR(inode->i_rdev);
 
     STp = &(scsi_tapes[dev]);
@@ -846,6 +901,11 @@ st_write(struct inode * inode, struct file * filp, const char * buf, int count)
     }
 #endif
 
+    if (STp->can_partitions &&
+       (retval = update_partition(inode)) < 0)
+      return retval;
+    STps = &(STp->ps[STp->partition]);
+
     if (STp->write_prot)
       return (-EACCES);
 
@@ -855,42 +915,19 @@ st_write(struct inode * inode, struct file * filp, const char * buf, int count)
       return (-EOVERFLOW);
 
     if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
-       !st_int_ioctl(inode, filp, MTLOCK, 0))
+       !st_int_ioctl(inode, MTLOCK, 0))
       STp->door_locked = ST_LOCKED_AUTO;
 
-    if (STp->rw == ST_READING) {
+    if (STps->rw == ST_READING) {
       retval = flush_buffer(inode, filp, 0);
       if (retval)
-       return retval;
-      STp->rw = ST_WRITING;
+       return retval;
+      STps->rw = ST_WRITING;
     }
-    else if (STp->rw != ST_WRITING &&
+    else if (STps->rw != ST_WRITING &&
             (STp->mt_status)->mt_fileno == 0 && STp->drv_block == 0) {
-      set_it = FALSE;
-      if (!STp->density_changed && STm->default_density >= 0 &&
-         STm->default_density != STp->density) {
-         arg = STm->default_density;
-         set_it = TRUE;
-      }
-      else
-       arg = STp->density;
-      arg <<= MT_ST_DENSITY_SHIFT;
-      if (!STp->blksize_changed && STm->default_blksize >= 0 &&
-         STm->default_blksize != STp->block_size) {
-       arg |= STm->default_blksize;
-       set_it = TRUE;
-      }
-      else
-       arg |= STp->block_size;
-      if (set_it &&
-         st_int_ioctl(inode, filp, SET_DENS_AND_BLK, arg)) {
-       printk(KERN_WARNING
-              "st%d: Can't set default block size to %d bytes and density %x.\n",
-              dev, STm->default_blksize, STm->default_density);
-       if (modes_defined)
-         return (-EINVAL);
-      }
-
+      if ((retval = set_mode_densblk(inode, STp, STm)) < 0)
+       return retval;
       if (STm->default_compression != ST_DONT_TOUCH &&
          !(STp->compression_changed)) {
        if (st_compression(STp, (STm->default_compression == ST_YES))) {
@@ -902,8 +939,8 @@ st_write(struct inode * inode, struct file * filp, const char * buf, int count)
       }
     }
 
-    if (STp->moves_after_eof < 255)
-      STp->moves_after_eof++;
+    if (STps->moves_after_eof < 255)
+      STps->moves_after_eof++;
 
     if ((STp->buffer)->writing) {
       write_behind_check(STp);
@@ -943,7 +980,7 @@ st_write(struct inode * inode, struct file * filp, const char * buf, int count)
     cmd[0] = WRITE_6;
     cmd[1] = (STp->block_size != 0);
 
-    STp->rw = ST_WRITING;
+    STps->rw = ST_WRITING;
 
     b_point = buf;
     while((STp->block_size == 0 && !STm->do_async_writes && count > 0) ||
@@ -1101,7 +1138,7 @@ st_write(struct inode * inode, struct file * filp, const char * buf, int count)
     else if (SCpnt != NULL)
       SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
 
-    STp->at_sm &= (total != 0);
+    STps->at_sm &= (total == 0);
     return( total);
 }   
 
@@ -1116,6 +1153,7 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
     Scsi_Cmnd * SCpnt = NULL;
     Scsi_Tape * STp;
     ST_mode * STm;
+    ST_partstat * STps;
     int dev = TAPE_NR(inode->i_rdev);
 
     STp = &(scsi_tapes[dev]);
@@ -1131,6 +1169,11 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
     }
 #endif
 
+    if (STp->can_partitions &&
+       (total = update_partition(inode)) < 0)
+      return total;
+    STps = &(STp->ps[STp->partition]);
+
     if (STp->block_size == 0 &&
        count > (STp->buffer)->buffer_size &&
        !enlarge_buffer(STp->buffer, count, STp->restr_dma))
@@ -1141,17 +1184,17 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
       return (-EIO);   /* Read must be integral number of blocks */
 
     if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
-       !st_int_ioctl(inode, filp, MTLOCK, 0))
+       !st_int_ioctl(inode, MTLOCK, 0))
       STp->door_locked = ST_LOCKED_AUTO;
 
-    if (STp->rw == ST_WRITING) {
+    if (STps->rw == ST_WRITING) {
       transfer = flush_buffer(inode, filp, 0);
       if (transfer)
        return transfer;
-      STp->rw = ST_READING;
+      STps->rw = ST_READING;
     }
-    if (STp->moves_after_eof < 255)
-      STp->moves_after_eof++;
+    if (STps->moves_after_eof < 255)
+      STps->moves_after_eof++;
 
 #if DEBUG
     if (debugging && STp->eof != ST_NOEOF)
@@ -1162,7 +1205,7 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
        (STp->eof == ST_EOM_OK || STp->eof == ST_EOD))
       return (-EIO);  /* EOM or Blank Check */
 
-    STp->rw = ST_READING;
+    STps->rw = ST_READING;
 
     for (total = 0; total < count; ) {
 
@@ -1197,7 +1240,7 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
 
        (STp->buffer)->read_pointer = 0;
        STp->eof_hit = 0;
-       STp->at_sm = 0;
+       STps->at_sm = 0;
 
        if ((STp->buffer)->last_result_fatal) {
 #if DEBUG
@@ -1235,7 +1278,7 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
                    printk(KERN_NOTICE "st%d: Incorrect block size.\n", dev);
                    if (STp->drv_block >= 0)
                      STp->drv_block += blks - transfer + 1;
-                   st_int_ioctl(inode, filp, MTBSR, 1);
+                   st_int_ioctl(inode, MTBSR, 1);
                    return (-EIO);
                  }
                  /* We have some data, deliver it */
@@ -1249,7 +1292,7 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
                    count = total + (STp->buffer)->buffer_bytes;
                  if (STp->drv_block >= 0)
                    STp->drv_block += 1;
-                 if (st_int_ioctl(inode, filp, MTBSR, 1))
+                 if (st_int_ioctl(inode, MTBSR, 1))
                    return (-EIO);
                  SCpnt = NULL;
                }
@@ -1291,7 +1334,7 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
              STp->drv_block = (-1);
              if (total)
                return total;
-             else if (STp->moves_after_eof == 1 &&
+             else if (STps->moves_after_eof == 1 &&
                       (SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK) {
 #if DEBUG
                if (debugging)
@@ -1348,8 +1391,8 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
        if (total == 0 && STp->eof == ST_FM) {
          STp->eof = ST_NOEOF;
          STp->drv_block = 0;
-         if (STp->moves_after_eof > 1)
-           STp->moves_after_eof = 0;
+         if (STps->moves_after_eof > 1)
+           STps->moves_after_eof = 0;
          if ((STp->mt_status)->mt_fileno >= 0)
            (STp->mt_status)->mt_fileno++;
        }
@@ -1383,8 +1426,9 @@ st_log_options(Scsi_Tape *STp, ST_mode *STm, int dev)
 "st%d:    can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n",
         dev, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock);
   printk(KERN_INFO
-"st%d:    defs for wr: %d, no block limits: %d\n",
-        dev, STm->defaults_for_writes, STp->omit_blklims);
+"st%d:    defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n",
+        dev, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions,
+        STp->scsi2_logical);
 #if DEBUG
   printk(KERN_INFO
         "st%d:    debugging: %d\n",
@@ -1425,6 +1469,9 @@ st_set_options(struct inode * inode, long options)
     STp->do_auto_lock     = (options & MT_ST_AUTO_LOCK) != 0;
     STp->can_bsr          = (options & MT_ST_CAN_BSR) != 0;
     STp->omit_blklims    = (options & MT_ST_NO_BLKLIMS) != 0;
+    if ((STp->device)->scsi_level >= SCSI_2)
+      STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0;
+    STp->scsi2_logical    = (options & MT_ST_SCSI2LOGICAL) != 0;
 #if DEBUG
     debugging = (options & MT_ST_DEBUGGING) != 0;
 #endif
@@ -1450,6 +1497,11 @@ st_set_options(struct inode * inode, long options)
       STp->can_bsr = value;
     if ((options & MT_ST_NO_BLKLIMS) != 0)
       STp->omit_blklims = value;
+    if ((STp->device)->scsi_level >= SCSI_2 &&
+       (options & MT_ST_CAN_PARTITIONS) != 0)
+      STp->can_partitions = value;
+    if ((options & MT_ST_SCSI2LOGICAL) != 0)
+      STp->scsi2_logical = value;
 #if DEBUG
     if ((options & MT_ST_DEBUGGING) != 0)
       debugging = value;
@@ -1541,6 +1593,9 @@ st_compression(Scsi_Tape * STp, int state)
   unsigned char cmd[10];
   Scsi_Cmnd * SCpnt = NULL;
 
+  if (STp->ready != ST_READY)
+    return (-EIO);
+
   /* Read the current page contents */
   memset(cmd, 0, 10);
   cmd[0] = MODE_SENSE;
@@ -1549,6 +1604,8 @@ st_compression(Scsi_Tape * STp, int state)
   cmd[4] = COMPRESSION_PAGE_LENGTH + MODE_HEADER_LENGTH;
 
   SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], ST_TIMEOUT, 0);
+  if (SCpnt == NULL)
+    return (-EBUSY);
   dev = TAPE_NR(SCpnt->request.rq_dev);
 
   if ((STp->buffer)->last_result_fatal != 0) {
@@ -1614,24 +1671,26 @@ st_compression(Scsi_Tape * STp, int state)
 \f
 /* Internal ioctl function */
        static int
-st_int_ioctl(struct inode * inode,struct file * file,
+st_int_ioctl(struct inode * inode,
             unsigned int cmd_in, unsigned long arg)
 {
    int timeout = ST_LONG_TIMEOUT;
    long ltmp;
-   int ioctl_result;
+   int i, ioctl_result;
    unsigned char cmd[10];
    Scsi_Cmnd * SCpnt;
    Scsi_Tape * STp;
+   ST_partstat * STps;
    int fileno, blkno, at_sm, undone, datalen;
    int dev = TAPE_NR(inode->i_rdev);
 
    STp = &(scsi_tapes[dev]);
    if (STp->ready != ST_READY && cmd_in != MTLOAD)
      return (-EIO);
+   STps = &(STp->ps[STp->partition]);
    fileno = (STp->mt_status)->mt_fileno ;
    blkno = STp->drv_block;
-   at_sm = STp->at_sm;
+   at_sm = STps->at_sm;
 
    memset(cmd, 0, 10);
    datalen = 0;
@@ -1651,7 +1710,7 @@ st_int_ioctl(struct inode * inode,struct file * file,
        if (fileno >= 0)
         fileno += arg;
        blkno = 0;
-       at_sm &= (arg != 0);
+       at_sm &= (arg == 0);
        break; 
      case MTBSF:
      case MTBSFM:
@@ -1673,7 +1732,7 @@ st_int_ioctl(struct inode * inode,struct file * file,
        if (fileno >= 0)
         fileno -= arg;
        blkno = (-1);  /* We can't know the block number */
-       at_sm &= (arg != 0);
+       at_sm &= (arg == 0);
        break; 
      case MTFSR:
        cmd[0] = SPACE;
@@ -1688,7 +1747,7 @@ st_int_ioctl(struct inode * inode,struct file * file,
 #endif
        if (blkno >= 0)
         blkno += arg;
-       at_sm &= (arg != 0);
+       at_sm &= (arg == 0);
        break; 
      case MTBSR:
        cmd[0] = SPACE;
@@ -1707,7 +1766,7 @@ st_int_ioctl(struct inode * inode,struct file * file,
 #endif
        if (blkno >= 0)
         blkno -= arg;
-       at_sm &= (arg != 0);
+       at_sm &= (arg == 0);
        break; 
      case MTFSS:
        cmd[0] = SPACE;
@@ -1829,7 +1888,7 @@ st_int_ioctl(struct inode * inode,struct file * file,
      case MTEOM:
        if (!STp->fast_mteom) {
         /* space to the end of tape */
-        ioctl_result = st_int_ioctl(inode, file, MTFSF, 0x3fff);
+        ioctl_result = st_int_ioctl(inode, MTFSF, 0x3fff);
         fileno = (STp->mt_status)->mt_fileno ;
         if (STp->eof == ST_EOD || STp->eof == ST_EOM_OK)
           return 0;
@@ -1882,33 +1941,6 @@ st_int_ioctl(struct inode * inode,struct file * file,
         printk(ST_DEB_MSG "st%d: Unlocking drive door.\n", dev);
 #endif;
        break;
-     case MTSEEK:
-       if ((STp->device)->scsi_level < SCSI_2) {
-        cmd[0] = QFA_SEEK_BLOCK;
-        cmd[2] = (arg >> 16);
-        cmd[3] = (arg >> 8);
-        cmd[4] = arg;
-        cmd[5] = 0;
-       }
-       else {
-        cmd[0] = SEEK_10;
-        cmd[1] = 4;
-        cmd[3] = (arg >> 24);
-        cmd[4] = (arg >> 16);
-        cmd[5] = (arg >> 8);
-        cmd[6] = arg;
-       }
-#if ST_NOWAIT
-       cmd[1] |= 1;  /* Don't wait for completion */
-       timeout = ST_TIMEOUT;
-#endif
-#if DEBUG
-       if (debugging)
-        printk(ST_DEB_MSG "st%d: Seeking tape to block %ld.\n", dev, arg);
-#endif
-       fileno = blkno = (-1);
-       at_sm = 0;
-       break;
      case MTSETBLK:  /* Set block length */
      case MTSETDENSITY: /* Set tape density */
      case MTSETDRVBUFFER: /* Set drive buffering */
@@ -1981,27 +2013,21 @@ st_int_ioctl(struct inode * inode,struct file * file,
    SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
 
    if (cmd_in == MTFSF)
-     STp->moves_after_eof = 0;
-   else
-     STp->moves_after_eof = 1;
+     STps->moves_after_eof = 0;
+   else if (cmd_in != MTLOAD)
+     STps->moves_after_eof = 1;
    if (!ioctl_result) {  /* SCSI command successful */
-     if (cmd_in != MTSEEK) {
-       STp->drv_block = blkno;
-       (STp->mt_status)->mt_fileno = fileno;
-       STp->at_sm = at_sm;
-     }
-     else {
-       STp->drv_block = (STp->mt_status)->mt_fileno = (-1);
-       STp->at_sm = 0;
-     }
+     STp->drv_block = blkno;
+     (STp->mt_status)->mt_fileno = fileno;
+     STps->at_sm = at_sm;
      if (cmd_in == MTLOCK)
        STp->door_locked = ST_LOCKED_EXPLICIT;
      else if (cmd_in == MTUNLOCK)
        STp->door_locked = ST_UNLOCKED;
      if (cmd_in == MTBSFM)
-       ioctl_result = st_int_ioctl(inode, file, MTFSF, 1);
+       ioctl_result = st_int_ioctl(inode, MTFSF, 1);
      else if (cmd_in == MTFSFM)
-       ioctl_result = st_int_ioctl(inode, file, MTBSF, 1);
+       ioctl_result = st_int_ioctl(inode, MTBSF, 1);
      else if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) {
        STp->block_size = arg & MT_ST_BLKSIZE_MASK;
        if (STp->block_size != 0)
@@ -2025,8 +2051,15 @@ st_int_ioctl(struct inode * inode,struct file * file,
        STp->density = arg >> MT_ST_DENSITY_SHIFT;
      if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
        STp->rew_at_close = 0;
-     else if (cmd_in == MTLOAD)
+     else if (cmd_in == MTLOAD) {
        STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;
+       for (i=0; i < ST_NBR_PARTITIONS; i++) {
+        STp->ps[i].rw = ST_IDLE;
+        STp->ps[i].moves_after_eof = 1;
+        STp->ps[i].last_block_valid = FALSE;
+       }
+       STp->partition = 0;
+     }
    } else {  /* SCSI command was not completely successful */
      if (SCpnt->sense_buffer[2] & 0x40) {
        if (cmd_in != MTBSF && cmd_in != MTBSFM &&
@@ -2075,7 +2108,7 @@ st_int_ioctl(struct inode * inode,struct file * file,
           STp->drv_block = (-1);
        }
      }
-     else if (cmd_in == MTEOM || cmd_in == MTSEEK) {
+     else if (cmd_in == MTEOM) {
        (STp->mt_status)->mt_fileno = (-1);
        STp->drv_block = (-1);
      }
@@ -2090,19 +2123,351 @@ st_int_ioctl(struct inode * inode,struct file * file,
 }
 
 
+\f/* Get the tape position. If bt == 2, arg points into a kernel space mt_loc
+    structure. */
+
+       static int
+get_location(struct inode * inode, unsigned int *block, int *partition,
+            int logical)
+{
+    Scsi_Tape *STp;
+    int dev = TAPE_NR(inode->i_rdev);
+    int result;
+    unsigned char scmd[10];
+    Scsi_Cmnd *SCpnt;
+
+    STp = &(scsi_tapes[dev]);
+    if (STp->ready != ST_READY)
+      return (-EIO);
+
+    memset (scmd, 0, 10);
+    if ((STp->device)->scsi_level < SCSI_2) {
+      scmd[0] = QFA_REQUEST_BLOCK;
+      scmd[4] = 3;
+    }
+    else {
+      scmd[0] = READ_POSITION;
+      if (!logical && !STp->scsi2_logical)
+       scmd[1] = 1;
+    }
+    SCpnt = st_do_scsi(NULL, STp, scmd, 20, ST_TIMEOUT, MAX_READY_RETRIES);
+    if (!SCpnt)
+      return (-EBUSY);
+
+    if ((STp->buffer)->last_result_fatal != 0 ||
+       ((STp->buffer)->b_data[0] & 4)) {
+      *block = *partition = 0;
+#if DEBUG
+      if (debugging)
+       printk(ST_DEB_MSG "st%d: Can't read tape position.\n", dev);
+#endif
+      result = (-EIO);
+    }
+    else {
+      result = 0;
+      if ((STp->device)->scsi_level < SCSI_2) {
+       *block = ((STp->buffer)->b_data[0] << 16) 
+       + ((STp->buffer)->b_data[1] << 8) 
+       + (STp->buffer)->b_data[2];
+       *partition = 0;
+      }
+      else {
+       *block = ((STp->buffer)->b_data[4] << 24)
+         + ((STp->buffer)->b_data[5] << 16) 
+         + ((STp->buffer)->b_data[6] << 8) 
+         + (STp->buffer)->b_data[7];
+       *partition = (STp->buffer)->b_data[1];
+       if (((STp->buffer)->b_data[0] & 0x80) &&
+           (STp->buffer)->b_data[1] == 0) /* BOP of partition 0 */
+         STp->drv_block = (STp->mt_status)->mt_fileno = 0;
+      }
+#if DEBUG
+      if (debugging)
+       printk(ST_DEB_MSG "st%d: Got tape pos. blk %d part %d.\n", dev,
+              *block, *partition);
+#endif
+
+    }
+    SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+
+    return result;
+}
+
+
+/* Set the tape block and partition. Negative partition means that only the
+   block should be set in vendor specific way. */
+       static int
+set_location(struct inode * inode, unsigned int block, int partition,
+            int logical)
+{
+    Scsi_Tape *STp;
+    ST_partstat *STps;
+    int dev = TAPE_NR(inode->i_rdev);
+    int result, p;
+    unsigned int blk;
+    int timeout = ST_LONG_TIMEOUT;
+    unsigned char scmd[10];
+    Scsi_Cmnd *SCpnt;
+
+    STp = &(scsi_tapes[dev]);
+    if (STp->ready != ST_READY)
+      return (-EIO);
+    STps = &(STp->ps[STp->partition]);
+
+#if DEBUG
+    if (debugging)
+      printk(ST_DEB_MSG "st%d: Setting block to %d and partition to %d.\n",
+            dev, block, partition);
+    if (partition < 0)
+      return (-EIO);
+#endif
+
+    /* Update the location at the partition we are leaving */
+    if ((!STp->can_partitions && partition != 0) ||
+       partition >= ST_NBR_PARTITIONS)
+      return (-EINVAL);
+    if (partition != STp->partition) {
+      if (get_location(inode, &blk, &p, 1))
+       STps->last_block_valid = FALSE;
+      else {
+       STps->last_block_valid = TRUE;
+       STps->last_block_visited = blk;
+#if DEBUG
+       if (debugging)
+         printk(ST_DEB_MSG "st%d: Visited block %d for partition %d saved.\n",
+                dev, blk, STp->partition);
+#endif
+      }
+    }
+
+    memset (scmd, 0, 10);
+    if ((STp->device)->scsi_level < SCSI_2) {
+      scmd[0] = QFA_SEEK_BLOCK;
+      scmd[2] = (block >> 16);
+      scmd[3] = (block >> 8);
+      scmd[4] = block;
+      scmd[5] = 0;
+    }
+    else {
+      scmd[0] = SEEK_10;
+      scmd[3] = (block >> 24);
+      scmd[4] = (block >> 16);
+      scmd[5] = (block >> 8);
+      scmd[6] = block;
+      if (!logical && !STp->scsi2_logical)
+       scmd[1] = 4;
+      if (STp->partition != partition) {
+       scmd[1] |= 2;
+       scmd[8] = partition;
+#if DEBUG
+       if (debugging)
+         printk(ST_DEB_MSG "st%d: Trying to change partition from %d to %d\n",
+                dev, STp->partition, partition);
+#endif
+      }
+     }
+#if ST_NOWAIT
+    scmd[1] |= 1;  /* Don't wait for completion */
+    timeout = ST_TIMEOUT;
+#endif
+
+    SCpnt = st_do_scsi(NULL, STp, scmd, 20, timeout, MAX_READY_RETRIES);
+    if (!SCpnt)
+      return (-EBUSY);
+
+    STp->drv_block = (STp->mt_status)->mt_fileno = (-1);
+    if ((STp->buffer)->last_result_fatal != 0) {
+      result = (-EIO);
+      if (STp->can_partitions &&
+         (STp->device)->scsi_level >= SCSI_2 &&
+         (p = find_partition(inode)) >= 0)
+       STp->partition = p;
+    }
+    else {
+      if (STp->can_partitions) {
+       STp->partition = partition;
+       STps = &(STp->ps[partition]);
+       if (!STps->last_block_valid ||
+           STps->last_block_visited != block) {
+         STps->moves_after_eof = 1;
+         STps->at_sm = 0;
+         STps->rw = ST_IDLE;
+       }
+      }
+      else
+       STps->at_sm = 0;
+      if (block == 0)
+       STp->drv_block = (STp->mt_status)->mt_fileno = 0;
+      result = 0;
+    }
+    SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+
+    return result;
+}
+
+
+/* Find the current partition number for the drive status. Called from open and
+   returns either partition number of negative error code. */
+       static int
+find_partition(struct inode *inode)
+{
+    int i, partition;
+    unsigned int block;
+
+    if ((i = get_location(inode, &block, &partition, 1)) < 0)
+      return i;
+    if (partition >= ST_NBR_PARTITIONS)
+      return (-EIO);
+    return partition;
+}
+
+
+/* Change the partition if necessary */
+       static int
+update_partition(struct inode * inode)
+{
+    int dev = TAPE_NR(inode->i_rdev);
+    Scsi_Tape *STp;
+    ST_partstat *STps;
+
+    STp = &(scsi_tapes[dev]);
+    if (STp->partition == STp->new_partition)
+      return 0;
+    STps = &(STp->ps[STp->new_partition]);
+    if (!STps->last_block_valid)
+      STps->last_block_visited = 0;
+    return set_location(inode, STps->last_block_visited, STp->new_partition, 1);
+}
+
+\f/* Functions for reading and writing the medium partition mode page. These
+   seem to work with Wangtek 6200HS and HP C1533A. */
+
+#define PART_PAGE   0x11
+#define PART_PAGE_LENGTH 10
+
+/* Get the number of partitions on the tape. As a side effect reads the
+   mode page into the tape buffer. */
+       static int
+nbr_partitions(struct inode * inode)
+{
+    int dev = TAPE_NR(inode->i_rdev), result;
+    Scsi_Tape *STp;
+    Scsi_Cmnd * SCpnt = NULL;
+    unsigned char cmd[10];
+
+    STp = &(scsi_tapes[dev]);
+    if (STp->ready != ST_READY)
+      return (-EIO);
+
+    memset ((void *) &cmd[0], 0, 10);
+    cmd[0] = MODE_SENSE;
+    cmd[1] = 8;   /* Page format */
+    cmd[2] = PART_PAGE;
+    cmd[4] = 200;
+
+    SCpnt = st_do_scsi(SCpnt, STp, cmd, 200, ST_TIMEOUT, MAX_READY_RETRIES);
+    if (SCpnt == NULL)
+      return (-EBUSY);
+    SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+
+    if ((STp->buffer)->last_result_fatal != 0) {
+#if DEBUG
+      if (debugging)
+       printk(ST_DEB_MSG "st%d: Can't read medium partition page.\n", dev);
+#endif
+      result = (-EIO);
+    }
+    else {
+      result = (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] + 1;
+#if DEBUG
+      if (debugging)
+       printk(ST_DEB_MSG "st%d: Number of partitions %d.\n", dev, result);
+#endif
+    }
+
+    return result;
+}
+
+
+/* Partition the tape into two partitions if size > 0 or one partition if
+   size == 0 */
+       static int
+partition_tape(struct inode * inode, int size)
+{
+    int dev = TAPE_NR(inode->i_rdev), result;
+    int length;
+    Scsi_Tape *STp;
+    Scsi_Cmnd * SCpnt = NULL;
+    unsigned char cmd[10], *bp;
+
+    if ((result = nbr_partitions(inode)) < 0)
+      return result;
+    STp = &(scsi_tapes[dev]);
+
+    /* The mode page is in the buffer. Let's modify it and write it. */
+    bp = &((STp->buffer)->b_data[0]);
+    if (size <= 0) {
+      length = 8;
+      bp[MODE_HEADER_LENGTH + 3] = 0;
+#if DEBUG
+      if (debugging)
+       printk(ST_DEB_MSG "st%d: Formatting tape with one partition.\n", dev);
+#endif
+    }
+    else {
+      length = 10;
+      bp[MODE_HEADER_LENGTH + 3] = 1;
+      bp[MODE_HEADER_LENGTH + 8] = (size >> 8) & 0xff;
+      bp[MODE_HEADER_LENGTH + 9] = size & 0xff;
+#if DEBUG
+      if (debugging)
+       printk(ST_DEB_MSG "st%d: Formatting tape with two partition (1 = %d MB).\n",
+              dev, size);
+#endif
+    }
+    bp[MODE_HEADER_LENGTH + 6] = 0;
+    bp[MODE_HEADER_LENGTH + 7] = 0;
+    bp[MODE_HEADER_LENGTH + 4] = 0x30;   /* IDP | PSUM = MB */
+
+    bp[0] = 0;
+    bp[1] = 0;
+    bp[MODE_HEADER_LENGTH] &= 0x3f;
+    bp[MODE_HEADER_LENGTH + 1] = length - 2;
+
+    memset(cmd, 0, 10);
+    cmd[0] = MODE_SELECT;
+    cmd[1] = 0x10;
+    cmd[4] = length + MODE_HEADER_LENGTH;
+
+    SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], ST_LONG_TIMEOUT, MAX_READY_RETRIES);
+    if (SCpnt == NULL)
+      return (-EBUSY);
+    SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+
+    if ((STp->buffer)->last_result_fatal != 0) {
+      printk(KERN_INFO "st%d: Partitioning of tape failed.\n", dev);
+      result = (-EIO);
+    }
+    else
+      result = 0;
+
+    return result;
+}
+
+
 \f
 /* The ioctl command */
        static int
 st_ioctl(struct inode * inode,struct file * file,
         unsigned int cmd_in, unsigned long arg)
 {
-   int i, cmd_nr, cmd_type, result;
+   int i, cmd_nr, cmd_type, bt;
+   unsigned int blk;
    struct mtop mtc;
    struct mtpos mt_pos;
-   unsigned char scmd[10];
-   Scsi_Cmnd *SCpnt;
    Scsi_Tape *STp;
    ST_mode *STm;
+   ST_partstat *STps;
    int dev = TAPE_NR(inode->i_rdev);
 
    STp = &(scsi_tapes[dev]);
@@ -2113,18 +2478,11 @@ st_ioctl(struct inode * inode,struct file * file,
    }
 #endif
    STm = &(STp->modes[STp->current_mode]);
+   STps = &(STp->ps[STp->partition]);
 
-   /*
-    * If this is something intended for the lower layer, just pass it
-    * through.
-    */
-   if( cmd_in == SCSI_IOCTL_GET_IDLUN || cmd_in == SCSI_IOCTL_PROBE_HOST )
-     {
-       return scsi_ioctl(STp->device, cmd_in, (void *) arg);
-     }
-   
    cmd_type = _IOC_TYPE(cmd_in);
    cmd_nr   = _IOC_NR(cmd_in);
+
    if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
      if (_IOC_SIZE(cmd_in) != sizeof(mtc))
        return (-EINVAL);
@@ -2180,7 +2538,7 @@ st_ioctl(struct inode * inode,struct file * file,
        STp->device->was_reset = 0;
        if (STp->door_locked != ST_UNLOCKED &&
           STp->door_locked != ST_LOCK_FAILS) {
-        if (st_int_ioctl(inode, file, MTLOCK, 0)) {
+        if (st_int_ioctl(inode, MTLOCK, 0)) {
           printk(KERN_NOTICE "st%d: Could not relock door after bus reset.\n",
                  dev);
           STp->door_locked = ST_UNLOCKED;
@@ -2190,24 +2548,69 @@ st_ioctl(struct inode * inode,struct file * file,
 
      if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
         mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTWSM &&
-        mtc.mt_op != MTSETDRVBUFFER)
-       STp->rw = ST_IDLE;  /* Prevent automatic WEOF */
+        mtc.mt_op != MTSETDRVBUFFER && mtc.mt_op != MTSEEK &&
+        mtc.mt_op != MTSETPART)
+       STps->rw = ST_IDLE;  /* Prevent automatic WEOF */
 
      if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
-       st_int_ioctl(inode, file, MTUNLOCK, 0);  /* Ignore result! */
+       st_int_ioctl(inode, MTUNLOCK, 0);  /* Ignore result! */
 
      if (mtc.mt_op == MTSETDRVBUFFER &&
         (mtc.mt_count & MT_ST_OPTIONS) != 0)
        return st_set_options(inode, mtc.mt_count);
-     else if (mtc.mt_op == MTCOMPRESSION)
+     if (mtc.mt_op == MTSETPART) {
+       if (!STp->can_partitions ||
+          mtc.mt_count < 0 || mtc.mt_count >= ST_NBR_PARTITIONS)
+        return (-EINVAL);
+       if (mtc.mt_count >= STp->nbr_partitions &&
+          (STp->nbr_partitions = nbr_partitions(inode)) < 0)
+        return (-EIO);
+       if (mtc.mt_count >= STp->nbr_partitions)
+        return (-EINVAL);
+       STp->new_partition = mtc.mt_count;
+       return 0;
+     }
+     if (mtc.mt_op == MTMKPART) {
+       if (!STp->can_partitions)
+        return (-EINVAL);
+       if ((i = st_int_ioctl(inode, MTREW, 0)) < 0 ||
+          (i = partition_tape(inode, mtc.mt_count)) < 0)
+        return i;
+       for (i=0; i < ST_NBR_PARTITIONS; i++) {
+        STp->ps[i].rw = ST_IDLE;
+        STp->ps[i].moves_after_eof = 1;
+        STp->ps[i].at_sm = 0;
+        STp->ps[i].last_block_valid = FALSE;
+       }
+       STp->partition = STp->new_partition = 0;
+       STp->nbr_partitions = 1;  /* Bad guess ?-) */
+       STp->drv_block = (STp->mt_status)->mt_fileno = 0;
+       return 0;
+     }
+     if (mtc.mt_op == MTSEEK) {
+       i = set_location(inode, mtc.mt_count, STp->new_partition, 0);
+       if (!STp->can_partitions)
+          STp->ps[0].rw = ST_IDLE;
+       return i;
+     }
+     if (STp->can_partitions && STp->ready == ST_READY &&
+        (i = update_partition(inode)) < 0)
+       return i;
+     if (mtc.mt_op == MTCOMPRESSION)
        return st_compression(STp, (mtc.mt_count & 1));
      else
-       return st_int_ioctl(inode, file, mtc.mt_op, mtc.mt_count);
+       return st_int_ioctl(inode, mtc.mt_op, mtc.mt_count);
    }
 
    if (!STm->defined)
      return (-ENXIO);
 
+   if ((i = flush_buffer(inode, file, FALSE)) < 0)
+     return i;
+   if (STp->can_partitions &&
+       (i = update_partition(inode)) < 0)
+     return i;
+
    if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
 
      if (_IOC_SIZE(cmd_in) != sizeof(struct mtget))
@@ -2216,19 +2619,15 @@ st_ioctl(struct inode * inode,struct file * file,
      if (i)
        return i;
 
-     i = flush_buffer(inode, file, FALSE);
-     if (i < 0)
-       return i;
-
      (STp->mt_status)->mt_dsreg =
        ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) |
        ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK);
      (STp->mt_status)->mt_blkno = STp->drv_block;
      if (STp->block_size != 0) {
-       if (STp->rw == ST_WRITING)
+       if (STps->rw == ST_WRITING)
         (STp->mt_status)->mt_blkno +=
           (STp->buffer)->buffer_bytes / STp->block_size;
-       else if (STp->rw == ST_READING)
+       else if (STps->rw == ST_READING)
         (STp->mt_status)->mt_blkno -= ((STp->buffer)->buffer_bytes +
           STp->block_size - 1) / STp->block_size;
      }
@@ -2242,6 +2641,7 @@ st_ioctl(struct inode * inode,struct file * file,
        else
         (STp->mt_status)->mt_gstat |= GMT_EOF(0xffffffff);
      }
+     (STp->mt_status)->mt_resid = STp->partition;
      if (STp->eof == ST_EOM_OK || STp->eof == ST_EOM_ERROR)
        (STp->mt_status)->mt_gstat |= GMT_EOT(0xffffffff);
      else if (STp->eof == ST_EOD)
@@ -2256,7 +2656,7 @@ st_ioctl(struct inode * inode,struct file * file,
        (STp->mt_status)->mt_gstat |= GMT_ONLINE(0xffffffff);
      if (STp->ready == ST_NO_TAPE)
        (STp->mt_status)->mt_gstat |= GMT_DR_OPEN(0xffffffff);
-     if (STp->at_sm)
+     if (STps->at_sm)
        (STp->mt_status)->mt_gstat |= GMT_SM(0xffffffff);
 
      memcpy_tofs((char *)arg, (char *)(STp->mt_status),
@@ -2264,67 +2664,22 @@ st_ioctl(struct inode * inode,struct file * file,
 
      (STp->mt_status)->mt_erreg = 0;  /* Clear after read */
      return 0;
-   }
-   else if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
-     if (STp->ready != ST_READY)
-       return (-EIO);
-#if DEBUG
-     if (debugging)
-       printk(ST_DEB_MSG "st%d: get tape position.\n", dev);
-#endif
+   } /* End of MTIOCGET */
+
+   if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
      if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos))
        return (-EINVAL);
-
-     i = flush_buffer(inode, file, 0);
-     if (i < 0)
+     if ((i = get_location(inode, &blk, &bt, 0)) < 0)
        return i;
-
-     i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct mtpos));
+     i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(mt_pos));
      if (i)
-       return i;
-
-     memset (scmd, 0, 10);
-     if ((STp->device)->scsi_level < SCSI_2) {
-       scmd[0] = QFA_REQUEST_BLOCK;
-       scmd[4] = 3;
-     }
-     else {
-       scmd[0] = READ_POSITION;
-       scmd[1] = 1;
-     }
-     SCpnt = st_do_scsi(NULL, STp, scmd, 20, ST_TIMEOUT, MAX_READY_RETRIES);
-     if (!SCpnt)
-       return (-EBUSY);
-
-     if ((STp->buffer)->last_result_fatal != 0) {
-       mt_pos.mt_blkno = (-1);
-#if DEBUG
-       if (debugging)
-        printk(ST_DEB_MSG "st%d: Can't read tape position.\n", dev);
-#endif
-       result = (-EIO);
-     }
-     else {
-       result = 0;
-       if ((STp->device)->scsi_level < SCSI_2)
-        mt_pos.mt_blkno = ((STp->buffer)->b_data[0] << 16) 
-          + ((STp->buffer)->b_data[1] << 8) 
-            + (STp->buffer)->b_data[2];
-       else
-        mt_pos.mt_blkno = ((STp->buffer)->b_data[4] << 24)
-          + ((STp->buffer)->b_data[5] << 16) 
-            + ((STp->buffer)->b_data[6] << 8) 
-              + (STp->buffer)->b_data[7];
-
-     }
-
-     SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
-
+       return i;
+     mt_pos.mt_blkno = blk;
      memcpy_tofs((char *)arg, (char *) (&mt_pos), sizeof(struct mtpos));
-     return result;
+     return 0;
    }
-   else
-     return scsi_ioctl(STp->device, cmd_in, (void *) arg);
+
+   return scsi_ioctl(STp->device, cmd_in, (void *) arg);
 }
 
 \f
@@ -2464,6 +2819,8 @@ static struct file_operations st_fops = {
 
 static int st_attach(Scsi_Device * SDp){
    Scsi_Tape * tpnt;
+   ST_mode * STm;
+   ST_partstat * STps;
    int i;
 
    if(SDp->type != TYPE_TAPE) return 1;
@@ -2487,7 +2844,6 @@ static int st_attach(Scsi_Device * SDp){
 
    tpnt->devt = MKDEV(SCSI_TAPE_MAJOR, i);
    tpnt->dirty = 0;
-   tpnt->rw = ST_IDLE;
    tpnt->eof = ST_NOEOF;
    tpnt->waiting = NULL;
    tpnt->in_use = 0;
@@ -2496,25 +2852,38 @@ static int st_attach(Scsi_Device * SDp){
    tpnt->density = 0;
    tpnt->do_auto_lock = ST_AUTO_LOCK;
    tpnt->can_bsr = ST_IN_FILE_POS;
+   tpnt->can_partitions = 0;
    tpnt->two_fm = ST_TWO_FM;
    tpnt->fast_mteom = ST_FAST_MTEOM;
+   tpnt->scsi2_logical = 0;
    tpnt->write_threshold = st_write_threshold;
    tpnt->default_drvbuffer = 0xff; /* No forced buffering */
+   tpnt->partition = 0;
+   tpnt->new_partition = 0;
+   tpnt->nbr_partitions = 0;
    tpnt->drv_block = (-1);
-   tpnt->moves_after_eof = 1;
-   tpnt->at_sm = 0;
    (tpnt->mt_status)->mt_fileno = (tpnt->mt_status)->mt_blkno = (-1);
 
    for (i=0; i < ST_NBR_MODES; i++) {
-     tpnt->modes[i].defined = FALSE;
-     tpnt->modes[i].defaults_for_writes = 0;
-     tpnt->modes[i].do_async_writes = ST_ASYNC_WRITES;
-     tpnt->modes[i].do_buffer_writes = ST_BUFFER_WRITES;
-     tpnt->modes[i].do_read_ahead = ST_READ_AHEAD;
-     tpnt->modes[i].default_compression = ST_DONT_TOUCH;
-     tpnt->modes[i].default_blksize = (-1);  /* No forced size */
-     tpnt->modes[i].default_density = (-1);  /* No forced density */
+     STm = &(tpnt->modes[i]);
+     STm->defined = FALSE;
+     STm->defaults_for_writes = 0;
+     STm->do_async_writes = ST_ASYNC_WRITES;
+     STm->do_buffer_writes = ST_BUFFER_WRITES;
+     STm->do_read_ahead = ST_READ_AHEAD;
+     STm->default_compression = ST_DONT_TOUCH;
+     STm->default_blksize = (-1);  /* No forced size */
+     STm->default_density = (-1);  /* No forced density */
    }
+
+   for (i=0; i < ST_NBR_PARTITIONS; i++) {
+     STps = &(tpnt->ps[i]);
+     STps->rw = ST_IDLE;
+     STps->moves_after_eof = 1;
+     STps->at_sm = 0;
+     STps->last_block_valid = FALSE;
+   }
+
    tpnt->current_mode = 0;
    tpnt->modes[0].defined = TRUE;
 
@@ -2529,7 +2898,8 @@ static int st_detect(Scsi_Device * SDp)
 {
   if(SDp->type != TYPE_TAPE) return 0;
 
-  printk("Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n", 
+  printk(KERN_INFO
+        "Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n", 
         st_template.dev_noticed++,
         SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); 
   
index 545bbdb747ee22662988c77d3b03e50db142ad83..dd1158a1ebe08b7000215a6c34a35b471416af03 100644 (file)
@@ -43,6 +43,17 @@ typedef struct {
 #define ST_MODE_SHIFT (7 - ST_NBR_MODE_BITS)
 #define ST_MODE_MASK ((ST_NBR_MODES - 1) << ST_MODE_SHIFT)
 
+/* The status related to each partition */
+typedef struct {
+  unsigned char rw;
+  unsigned char moves_after_eof;
+  unsigned char at_sm;
+  unsigned char last_block_valid;
+  u32 last_block_visited;
+} ST_partstat;
+
+#define ST_NBR_PARTITIONS 4
+
 /* The tape drive descriptor */
 typedef struct {
   kdev_t devt;
@@ -57,9 +68,11 @@ typedef struct {
   unsigned char omit_blklims;
   unsigned char do_auto_lock;
   unsigned char can_bsr;
+  unsigned char can_partitions;
   unsigned char two_fm;
   unsigned char fast_mteom;
   unsigned char restr_dma;
+  unsigned char scsi2_logical;
   unsigned char default_drvbuffer;  /* 0xff = don't touch, value 3 bits */
   int write_threshold;
 
@@ -68,16 +81,17 @@ typedef struct {
   int current_mode;
 
   /* Status variables */
+  int partition;
+  int new_partition;
+  int nbr_partitions;    /* zero until partition support enabled */
+  ST_partstat ps[ST_NBR_PARTITIONS];
   unsigned char dirty;
-  unsigned char rw;
   unsigned char ready;
   unsigned char eof;
   unsigned char write_prot;
   unsigned char drv_write_prot;
   unsigned char in_use;
   unsigned char eof_hit;
-  unsigned char moves_after_eof;
-  unsigned char at_sm;
   unsigned char blksize_changed;
   unsigned char density_changed;
   unsigned char compression_changed;
index c0cafa5a88e05790b3c57da7e1d6064898e59656..fa43592c87449b5e87230d19f7bd784997849916 100644 (file)
@@ -31,7 +31,7 @@
  *          will benefit from this. The driver defaults to what I'm
  *          'adaptive disconnect' - meaning that each command is
  *          evaluated individually as to whether or not it should
- *          be run with the option to disconnect/reslect (if the
+ *          be run with the option to disconnect/reselect (if the
  *          device chooses), or as a "SCSI-bus-hog".
  *
  *    -  Synchronous data transfers are now supported. Because of
  * -  nosync:bitmask -bitmask is a byte where the 1st 7 bits correspond with
  *                    the 7 possible SCSI devices. Set a bit to prevent sync
  *                    negotiation on that device. To maintain backwards
- *                    compatability, a command-line such as "wd33c93=255" will
+ *                    compatibility, a command-line such as "wd33c93=255" will
  *                    be automatically translated to "wd33c93=nosync:0xff".
  * -  period:ns      -ns is the minimum # of nanoseconds in a SCSI data transfer
  *                    period. Default is 500; acceptable values are 250 - 1000.
index 0447a9c5da445f71df29910a4a4fa32705af9a19..be203265ba29bc24a65ca794270a85f29c8bf809 100644 (file)
@@ -5,7 +5,7 @@ mainmenu_option next_comment
 comment 'Filesystems'
 
 bool    'Quota support' CONFIG_QUOTA
-tristate 'Standard (minix) fs support' CONFIG_MINIX_FS
+tristate 'Minix fs support' CONFIG_MINIX_FS
 tristate 'Extended fs support' CONFIG_EXT_FS
 tristate 'Second extended fs support' CONFIG_EXT2_FS
 tristate 'xiafs filesystem support' CONFIG_XIA_FS
index bd2c299a6c6dca07a315a45bf81447420c33cb3e..c75c5ae1c4ffa07e4b72937405f167f368554933 100644 (file)
@@ -721,11 +721,17 @@ repeat0:
        
        /* Too bad, that was not enough. Try a little harder to grow some. */
        
-       if (grow_buffers(GFP_ATOMIC, size)) {
-                needed -= PAGE_SIZE;
-               goto repeat0;
+       if (nr_free_pages > min_free_pages + 5) {
+               if (grow_buffers(GFP_BUFFER, size)) {
+                       needed -= PAGE_SIZE;
+                       goto repeat0;
+               };
        }
-       wakeup_bdflush(1);
+       
+       /* and repeat until we find something good */
+       if (!grow_buffers(GFP_ATOMIC, size))
+               wakeup_bdflush(1);
+       needed -= PAGE_SIZE;
        goto repeat0;
 }
 
@@ -1062,11 +1068,11 @@ static struct buffer_head * get_unused_buffer_head(void)
 static struct buffer_head * create_buffers(unsigned long page, unsigned long size)
 {
        struct buffer_head *bh, *head;
-       unsigned long offset;
+       long offset;
 
        head = NULL;
        offset = PAGE_SIZE;
-       while ((offset -= size) < PAGE_SIZE) {
+       while ((offset -= size) >= 0) {
                bh = get_unused_buffer_head();
                if (!bh)
                        goto no_grow;
@@ -1222,21 +1228,18 @@ void mark_buffer_uptodate(struct buffer_head * bh, int on)
 {
        if (on) {
                struct buffer_head *tmp = bh;
-               int page_uptodate = 1;
                set_bit(BH_Uptodate, &bh->b_state);
                /* If a page has buffers and all these buffers are uptodate,
                 * then the page is uptodate. */
                do {
-                       if (!test_bit(BH_Uptodate, &tmp->b_state)) {
-                               page_uptodate = 0;
-                               break;
-                       }
+                       if (!test_bit(BH_Uptodate, &tmp->b_state))
+                               return;
                        tmp=tmp->b_this_page;
                } while (tmp && tmp != bh);
-               if (page_uptodate)
-                       set_bit(PG_uptodate, &mem_map[MAP_NR(bh->b_data)].flags);
-       } else
-               clear_bit(BH_Uptodate, &bh->b_state);
+               set_bit(PG_uptodate, &mem_map[MAP_NR(bh->b_data)].flags);
+               return;
+       }
+       clear_bit(BH_Uptodate, &bh->b_state);
 }
 
 /*
@@ -1360,9 +1363,9 @@ static int grow_buffers(int pri, int size)
                else
                        break;
        }
+       tmp->b_this_page = bh;
        free_list[isize] = bh;
        mem_map[MAP_NR(page)].buffers = bh;
-       tmp->b_this_page = bh;
        buffermem += PAGE_SIZE;
        return 1;
 }
@@ -1818,14 +1821,17 @@ void buffer_init(void)
        int isize = BUFSIZE_INDEX(BLOCK_SIZE);
        long memsize = MAP_NR(high_memory) << PAGE_SHIFT;
 
-       if (memsize >= 4*1024*1024) {
-               if(memsize >= 16*1024*1024)
-                        nr_hash = 16381;
-               else
-                        nr_hash = 4093;
-       } else {
-               nr_hash = 997;
-       };
+       if (memsize >= 64*1024*1024)
+               nr_hash = 65521;
+       else if (memsize >= 32*1024*1024)
+               nr_hash = 32749;
+       else if (memsize >= 16*1024*1024)
+               nr_hash = 16381;
+       else if (memsize >= 8*1024*1024)
+               nr_hash = 8191;
+       else if (memsize >= 4*1024*1024)
+               nr_hash = 4093;
+       else nr_hash = 997;
        
        hash_table = (struct buffer_head **) vmalloc(nr_hash * 
                                                     sizeof(struct buffer_head *));
index cb0a486f13ca31de684920e546111f937a40072e..35435d4adb7d75cb83a224f3735043cb37342dff 100644 (file)
@@ -151,41 +151,6 @@ static int load_inode_bitmap (struct super_block * sb,
        return 0;
 }
 
-/*
- * This function sets the deletion time for the inode
- *
- * This may be used one day by an 'undelete' program
- */
-static void set_inode_dtime (struct inode * inode,
-                            struct ext2_group_desc * gdp)
-{
-       unsigned long inode_block;
-       struct buffer_head * bh;
-       struct ext2_inode * raw_inode;
-
-       inode_block = gdp->bg_inode_table + (((inode->i_ino - 1) %
-                       EXT2_INODES_PER_GROUP(inode->i_sb)) /
-                       EXT2_INODES_PER_BLOCK(inode->i_sb));
-       bh = bread (inode->i_sb->s_dev, inode_block, inode->i_sb->s_blocksize);
-       if (!bh)
-               ext2_panic (inode->i_sb, "set_inode_dtime",
-                           "Cannot load inode table block - "
-                           "inode=%lu, inode_block=%lu",
-                           inode->i_ino, inode_block);
-       raw_inode = ((struct ext2_inode *) bh->b_data) +
-                       (((inode->i_ino - 1) %
-                       EXT2_INODES_PER_GROUP(inode->i_sb)) %
-                       EXT2_INODES_PER_BLOCK(inode->i_sb));
-       raw_inode->i_links_count = 0;
-       raw_inode->i_dtime = CURRENT_TIME;
-       mark_buffer_dirty(bh, 1);
-       if (IS_SYNC(inode)) {
-               ll_rw_block (WRITE, 1, &bh);
-               wait_on_buffer (bh);
-       }
-       brelse (bh);
-}
-
 void ext2_free_inode (struct inode * inode)
 {
        struct super_block * sb;
@@ -222,7 +187,7 @@ void ext2_free_inode (struct inode * inode)
 
        sb = inode->i_sb;
        lock_super (sb);
-       if (inode->i_ino < EXT2_FIRST_INO ||
+       if (inode->i_ino < EXT2_FIRST_INO(sb) ||
            inode->i_ino > sb->u.ext2_sb.s_es->s_inodes_count) {
                ext2_error (sb, "free_inode",
                            "reserved inode or nonexistent inode");
@@ -246,7 +211,6 @@ void ext2_free_inode (struct inode * inode)
                es->s_free_inodes_count++;
                mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
                inode->i_dirt = 0;
-               set_inode_dtime (inode, gdp);
        }
        mark_buffer_dirty(bh, 1);
        if (sb->s_flags & MS_SYNCHRONOUS) {
@@ -269,30 +233,10 @@ static void inc_inode_version (struct inode * inode,
                               struct ext2_group_desc *gdp,
                               int mode)
 {
-       unsigned long inode_block;
-       struct buffer_head * bh;
-       struct ext2_inode * raw_inode;
+       inode->u.ext2_i.i_version++;
+       inode->i_dirt = 1;
 
-       inode_block = gdp->bg_inode_table + (((inode->i_ino - 1) %
-                       EXT2_INODES_PER_GROUP(inode->i_sb)) /
-                       EXT2_INODES_PER_BLOCK(inode->i_sb));
-       bh = bread (inode->i_sb->s_dev, inode_block, inode->i_sb->s_blocksize);
-       if (!bh) {
-               ext2_error (inode->i_sb, "inc_inode_version",
-                           "Cannot load inode table block - "
-                           "inode=%lu, inode_block=%lu\n",
-                           inode->i_ino, inode_block);
-               inode->u.ext2_i.i_version = 1;
-               return;
-       }
-       raw_inode = ((struct ext2_inode *) bh->b_data) +
-                       (((inode->i_ino - 1) %
-                       EXT2_INODES_PER_GROUP(inode->i_sb)) %
-                       EXT2_INODES_PER_BLOCK(inode->i_sb));
-       raw_inode->i_version++;
-       inode->u.ext2_i.i_version = raw_inode->i_version;
-       mark_buffer_dirty(bh, 1);
-       brelse (bh);
+       return;
 }
 
 /*
@@ -434,7 +378,7 @@ repeat:
                goto repeat;
        }
        j += i * EXT2_INODES_PER_GROUP(sb) + 1;
-       if (j < EXT2_FIRST_INO || j > es->s_inodes_count) {
+       if (j < EXT2_FIRST_INO(sb) || j > es->s_inodes_count) {
                ext2_error (sb, "ext2_new_inode",
                            "reserved inode or inode > inodes count - "
                            "block_group = %d,inode=%d", i, j);
@@ -468,6 +412,7 @@ repeat:
        inode->i_blksize = PAGE_SIZE;   /* This is the optimal IO size (for stat), not the fs block size */
        inode->i_blocks = 0;
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+       inode->u.ext2_i.i_new_inode = 1;
        inode->u.ext2_i.i_flags = dir->u.ext2_i.i_flags;
        if (S_ISLNK(mode))
                inode->u.ext2_i.i_flags &= ~(EXT2_IMMUTABLE_FL | EXT2_APPEND_FL);
index 0838d2431ad005eef64bc4a4d771136c559c310a..6d36f11c1b46ca056edd7cbd490d3dc422633c5e 100644 (file)
 #include <linux/locks.h>
 #include <linux/mm.h>
 
+static int ext2_update_inode(struct inode * inode, int do_sync);
+
 void ext2_put_inode (struct inode * inode)
 {
        ext2_discard_prealloc (inode);
        if (inode->i_nlink || inode->i_ino == EXT2_ACL_IDX_INO ||
            inode->i_ino == EXT2_ACL_DATA_INO)
                return;
+       inode->u.ext2_i.i_dtime = CURRENT_TIME;
+       inode->i_dirt = 1;
+       ext2_update_inode(inode, IS_SYNC(inode));
        inode->i_size = 0;
        if (inode->i_blocks)
                ext2_truncate (inode);
@@ -495,10 +500,12 @@ void ext2_read_inode (struct inode * inode)
        unsigned long group_desc;
        unsigned long desc;
        unsigned long block;
+       unsigned long offset;
        struct ext2_group_desc * gdp;
 
        if ((inode->i_ino != EXT2_ROOT_INO && inode->i_ino != EXT2_ACL_IDX_INO &&
-            inode->i_ino != EXT2_ACL_DATA_INO && inode->i_ino < EXT2_FIRST_INO) ||
+            inode->i_ino != EXT2_ACL_DATA_INO &&
+            inode->i_ino < EXT2_FIRST_INO(inode->i_sb)) ||
            inode->i_ino > inode->i_sb->u.ext2_sb.s_es->s_inodes_count) {
                ext2_error (inode->i_sb, "ext2_read_inode",
                            "bad inode number: %lu", inode->i_ino);
@@ -515,15 +522,20 @@ void ext2_read_inode (struct inode * inode)
                ext2_panic (inode->i_sb, "ext2_read_inode",
                            "Descriptor not loaded");
        gdp = (struct ext2_group_desc *) bh->b_data;
+       /*
+        * Figure out the offset within the block group inode table
+        */
+       offset = ((inode->i_ino - 1) % EXT2_INODES_PER_GROUP(inode->i_sb)) *
+               EXT2_INODE_SIZE(inode->i_sb);
        block = gdp[desc].bg_inode_table +
-               (((inode->i_ino - 1) % EXT2_INODES_PER_GROUP(inode->i_sb))
-                >> EXT2_INODES_PER_BLOCK_BITS(inode->i_sb));
+               (offset >> EXT2_BLOCK_SIZE_BITS(inode->i_sb));
        if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize)))
                ext2_panic (inode->i_sb, "ext2_read_inode",
                            "unable to read i-node block - "
                            "inode=%lu, block=%lu", inode->i_ino, block);
-       raw_inode = ((struct ext2_inode *) bh->b_data) +
-               ((inode->i_ino - 1) & (EXT2_INODES_PER_BLOCK(inode->i_sb) - 1));
+       offset &= (EXT2_BLOCK_SIZE(inode->i_sb) - 1);
+       raw_inode = (struct ext2_inode *) (bh->b_data + offset);
+
        inode->i_mode = raw_inode->i_mode;
        inode->i_uid = raw_inode->i_uid;
        inode->i_gid = raw_inode->i_gid;
@@ -536,6 +548,7 @@ void ext2_read_inode (struct inode * inode)
        inode->i_blksize = PAGE_SIZE;   /* This is the optimal IO size (for stat), not the fs block size */
        inode->i_blocks = raw_inode->i_blocks;
        inode->i_version = ++event;
+       inode->u.ext2_i.i_new_inode = 0;
        inode->u.ext2_i.i_flags = raw_inode->i_flags;
        inode->u.ext2_i.i_faddr = raw_inode->i_faddr;
        inode->u.ext2_i.i_frag_no = raw_inode->i_frag;
@@ -579,7 +592,7 @@ void ext2_read_inode (struct inode * inode)
                inode->i_flags |= S_IMMUTABLE;
 }
 
-static struct buffer_head * ext2_update_inode (struct inode * inode)
+static int ext2_update_inode(struct inode * inode, int do_sync)
 {
        struct buffer_head * bh;
        struct ext2_inode * raw_inode;
@@ -587,9 +600,12 @@ static struct buffer_head * ext2_update_inode (struct inode * inode)
        unsigned long group_desc;
        unsigned long desc;
        unsigned long block;
+       unsigned long offset;
+       int err = 0;
        struct ext2_group_desc * gdp;
 
-       if ((inode->i_ino != EXT2_ROOT_INO && inode->i_ino < EXT2_FIRST_INO) ||
+       if ((inode->i_ino != EXT2_ROOT_INO &&
+            inode->i_ino < EXT2_FIRST_INO(inode->i_sb)) ||
            inode->i_ino > inode->i_sb->u.ext2_sb.s_es->s_inodes_count) {
                ext2_error (inode->i_sb, "ext2_write_inode",
                            "bad inode number: %lu", inode->i_ino);
@@ -606,15 +622,20 @@ static struct buffer_head * ext2_update_inode (struct inode * inode)
                ext2_panic (inode->i_sb, "ext2_write_inode",
                            "Descriptor not loaded");
        gdp = (struct ext2_group_desc *) bh->b_data;
+       /*
+        * Figure out the offset within the block group inode table
+        */
+       offset = ((inode->i_ino - 1) % EXT2_INODES_PER_GROUP(inode->i_sb)) *
+               EXT2_INODE_SIZE(inode->i_sb);
        block = gdp[desc].bg_inode_table +
-               (((inode->i_ino - 1) % EXT2_INODES_PER_GROUP(inode->i_sb))
-                >> EXT2_INODES_PER_BLOCK_BITS(inode->i_sb));
+               (offset >> EXT2_BLOCK_SIZE_BITS(inode->i_sb));
        if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize)))
                ext2_panic (inode->i_sb, "ext2_write_inode",
                            "unable to read i-node block - "
                            "inode=%lu, block=%lu", inode->i_ino, block);
-       raw_inode = ((struct ext2_inode *)bh->b_data) +
-               (inode->i_ino - 1) % EXT2_INODES_PER_BLOCK(inode->i_sb);
+       offset &= EXT2_BLOCK_SIZE(inode->i_sb) - 1;
+       raw_inode = (struct ext2_inode *) (bh->b_data + offset);
+
        raw_inode->i_mode = inode->i_mode;
        raw_inode->i_uid = inode->i_uid;
        raw_inode->i_gid = inode->i_gid;
@@ -638,36 +659,27 @@ static struct buffer_head * ext2_update_inode (struct inode * inode)
                raw_inode->i_block[block] = inode->u.ext2_i.i_data[block];
        mark_buffer_dirty(bh, 1);
        inode->i_dirt = 0;
-       return bh;
-}
-
-void ext2_write_inode (struct inode * inode)
-{
-       struct buffer_head * bh;
-       bh = ext2_update_inode (inode);
-       brelse (bh);
-}
-
-int ext2_sync_inode (struct inode *inode)
-{
-       int err = 0;
-       struct buffer_head *bh;
-
-       bh = ext2_update_inode (inode);
-       if (bh && buffer_dirty(bh))
-       {
+       if (do_sync) {
                ll_rw_block (WRITE, 1, &bh);
                wait_on_buffer (bh);
-               if (buffer_req(bh) && !buffer_uptodate(bh))
-               {
+               if (buffer_req(bh) && !buffer_uptodate(bh)) {
                        printk ("IO error syncing ext2 inode ["
                                "%s:%08lx]\n",
                                kdevname(inode->i_dev), inode->i_ino);
                        err = -1;
                }
        }
-       else if (!bh)
-               err = -1;
        brelse (bh);
        return err;
 }
+
+void ext2_write_inode (struct inode * inode)
+{
+       ext2_update_inode (inode, 0);
+}
+
+int ext2_sync_inode (struct inode *inode)
+{
+       return ext2_update_inode (inode, 1);
+}
+
index bb755710d6e9aa04bcb814fe0687fab0206de3d2..3bf8b567119ecbe7c368ccbeb124d8a7ae4fd848 100644 (file)
@@ -270,7 +270,7 @@ static int parse_options (char * options, unsigned long * sb_block,
 static void ext2_setup_super (struct super_block * sb,
                              struct ext2_super_block * es)
 {
-       if (es->s_rev_level > EXT2_CURRENT_REV) {
+       if (es->s_rev_level > EXT2_MAX_SUPP_REV) {
                        printk ("EXT2-fs warning: revision level too high, "
                                "forcing read/only mode\n");
                        sb->s_flags |= MS_RDONLY;
@@ -400,14 +400,23 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
        sb->u.ext2_sb.s_es = es;
        sb->s_magic = es->s_magic;
        if (sb->s_magic != EXT2_SUPER_MAGIC) {
-               sb->s_dev = 0;
-               unlock_super (sb);
-               brelse (bh);
                if (!silent)
                        printk ("VFS: Can't find an ext2 filesystem on dev "
                                "%s.\n", kdevname(dev));
+       failed_mount:
+               sb->s_dev = 0;
+               unlock_super (sb);
+               if (bh)
+                       brelse(bh);
+               MOD_DEC_USE_COUNT;
                return NULL;
        }
+       if ((es->s_rev_level > EXT2_GOOD_OLD_REV) &&
+           (es->s_feature_incompat & !EXT2_FEATURE_INCOMPAT_SUPP)) {
+               printk("EXT2-fs: %s: couldn't mount because of "
+                      "unsupported optional features.\n", kdevname(dev));
+               goto failed_mount;
+       }
        sb->s_blocksize_bits = sb->u.ext2_sb.s_es->s_log_block_size + 10;
        sb->s_blocksize = 1 << sb->s_blocksize_bits;
        if (sb->s_blocksize != BLOCK_SIZE && 
@@ -421,18 +430,27 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
                offset = (sb_block*BLOCK_SIZE) % sb->s_blocksize;
                bh = bread (dev, logic_sb_block, sb->s_blocksize);
                if(!bh) {
-                       MOD_DEC_USE_COUNT;
-                       return NULL;
-                     }
+                       printk("EXT2-fs: Couldn't read superblock on "
+                              "2nd try.\n");
+                       goto failed_mount;
+               }
                es = (struct ext2_super_block *) (((char *)bh->b_data) + offset);
                sb->u.ext2_sb.s_es = es;
                if (es->s_magic != EXT2_SUPER_MAGIC) {
-                       sb->s_dev = 0;
-                       unlock_super (sb);
-                       brelse (bh);
                        printk ("EXT2-fs: Magic mismatch, very weird !\n");
-                       MOD_DEC_USE_COUNT;
-                       return NULL;
+                       goto failed_mount;
+               }
+       }
+       if (es->s_rev_level == EXT2_GOOD_OLD_REV) {
+               sb->u.ext2_sb.s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
+               sb->u.ext2_sb.s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
+       } else {
+               sb->u.ext2_sb.s_inode_size = es->s_inode_size;
+               sb->u.ext2_sb.s_first_ino = es->s_first_ino;
+               if (sb->u.ext2_sb.s_inode_size != EXT2_GOOD_OLD_INODE_SIZE) {
+                       printk ("EXT2-fs: unsupported inode size: %d\n",
+                               sb->u.ext2_sb.s_inode_size);
+                       goto failed_mount;
                }
        }
        sb->u.ext2_sb.s_frag_size = EXT2_MIN_FRAG_SIZE <<
@@ -446,7 +464,7 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
        sb->u.ext2_sb.s_frags_per_group = es->s_frags_per_group;
        sb->u.ext2_sb.s_inodes_per_group = es->s_inodes_per_group;
        sb->u.ext2_sb.s_inodes_per_block = sb->s_blocksize /
-                                          sizeof (struct ext2_inode);
+                                          EXT2_INODE_SIZE(sb);
        sb->u.ext2_sb.s_itb_per_group = sb->u.ext2_sb.s_inodes_per_group /
                                        sb->u.ext2_sb.s_inodes_per_block;
        sb->u.ext2_sb.s_desc_per_block = sb->s_blocksize /
@@ -465,68 +483,42 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
        sb->u.ext2_sb.s_rename_wait = NULL;
        sb->u.ext2_sb.s_addr_per_block_bits =
                log2 (EXT2_ADDR_PER_BLOCK(sb));
-       sb->u.ext2_sb.s_inodes_per_block_bits =
-               log2 (EXT2_INODES_PER_BLOCK(sb));
        sb->u.ext2_sb.s_desc_per_block_bits =
                log2 (EXT2_DESC_PER_BLOCK(sb));
        if (sb->s_magic != EXT2_SUPER_MAGIC) {
-               sb->s_dev = 0;
-               unlock_super (sb);
-               brelse (bh);
                if (!silent)
                        printk ("VFS: Can't find an ext2 filesystem on dev "
                                "%s.\n",
                                kdevname(dev));
-               MOD_DEC_USE_COUNT;
-               return NULL;
+               goto failed_mount;
        }
        if (sb->s_blocksize != bh->b_size) {
-               sb->s_dev = 0;
-               unlock_super (sb);
-               brelse (bh);
                if (!silent)
                        printk ("VFS: Unsupported blocksize on dev "
                                "%s.\n", kdevname(dev));
-               MOD_DEC_USE_COUNT;
-               return NULL;
+               goto failed_mount;
        }
 
        if (sb->s_blocksize != sb->u.ext2_sb.s_frag_size) {
-               sb->s_dev = 0;
-               unlock_super (sb);
-               brelse (bh);
                printk ("EXT2-fs: fragsize %lu != blocksize %lu (not supported yet)\n",
                        sb->u.ext2_sb.s_frag_size, sb->s_blocksize);
-               MOD_DEC_USE_COUNT;
-               return NULL;
+               goto failed_mount;
        }
 
        if (sb->u.ext2_sb.s_blocks_per_group > sb->s_blocksize * 8) {
-               sb->s_dev = 0;
-               unlock_super (sb);
-               brelse (bh);
                printk ("EXT2-fs: #blocks per group too big: %lu\n",
                        sb->u.ext2_sb.s_blocks_per_group);
-               MOD_DEC_USE_COUNT;
-               return NULL;
+               goto failed_mount;
        }
        if (sb->u.ext2_sb.s_frags_per_group > sb->s_blocksize * 8) {
-               sb->s_dev = 0;
-               unlock_super (sb);
-               brelse (bh);
                printk ("EXT2-fs: #fragments per group too big: %lu\n",
                        sb->u.ext2_sb.s_frags_per_group);
-               MOD_DEC_USE_COUNT;
-               return NULL;
+               goto failed_mount;
        }
        if (sb->u.ext2_sb.s_inodes_per_group > sb->s_blocksize * 8) {
-               sb->s_dev = 0;
-               unlock_super (sb);
-               brelse (bh);
                printk ("EXT2-fs: #inodes per group too big: %lu\n",
                        sb->u.ext2_sb.s_inodes_per_group);
-               MOD_DEC_USE_COUNT;
-               return NULL;
+               goto failed_mount;
        }
 
        sb->u.ext2_sb.s_groups_count = (es->s_blocks_count -
@@ -537,40 +529,28 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
                   EXT2_DESC_PER_BLOCK(sb);
        sb->u.ext2_sb.s_group_desc = kmalloc (db_count * sizeof (struct buffer_head *), GFP_KERNEL);
        if (sb->u.ext2_sb.s_group_desc == NULL) {
-               sb->s_dev = 0;
-               unlock_super (sb);
-               brelse (bh);
                printk ("EXT2-fs: not enough memory\n");
-               MOD_DEC_USE_COUNT;
-               return NULL;
+               goto failed_mount;
        }
        for (i = 0; i < db_count; i++) {
                sb->u.ext2_sb.s_group_desc[i] = bread (dev, logic_sb_block + i + 1,
                                                       sb->s_blocksize);
                if (!sb->u.ext2_sb.s_group_desc[i]) {
-                       sb->s_dev = 0;
-                       unlock_super (sb);
                        for (j = 0; j < i; j++)
                                brelse (sb->u.ext2_sb.s_group_desc[j]);
                        kfree_s (sb->u.ext2_sb.s_group_desc,
                                 db_count * sizeof (struct buffer_head *));
-                       brelse (bh);
                        printk ("EXT2-fs: unable to read group descriptors\n");
-                       MOD_DEC_USE_COUNT;
-                       return NULL;
+                       goto failed_mount;
                }
        }
        if (!ext2_check_descriptors (sb)) {
-               sb->s_dev = 0;
-               unlock_super (sb);
                for (j = 0; j < db_count; j++)
                        brelse (sb->u.ext2_sb.s_group_desc[j]);
                kfree_s (sb->u.ext2_sb.s_group_desc,
                         db_count * sizeof (struct buffer_head *));
-               brelse (bh);
                printk ("EXT2-fs: group descriptors corrupted !\n");
-               MOD_DEC_USE_COUNT;
-               return NULL;
+               goto failed_mount;
        }
        for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) {
                sb->u.ext2_sb.s_inode_bitmap_number[i] = 0;
index 6f19c71fd5b5787185bdf52d1e4073debd581d98..ee7daeeea464309f165df485e6daee39174cd1b6 100644 (file)
@@ -85,7 +85,7 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
                        if (!(arg & FASYNC) && (filp->f_flags & FASYNC) &&
                            filp->f_op->fasync)
                                filp->f_op->fasync(filp->f_inode, filp, 0);
-                       /* requiered for SunOS emulation */
+                       /* required for SunOS emulation */
                        if (O_NONBLOCK != O_NDELAY)
                               if (arg & O_NDELAY)
                                   arg |= O_NONBLOCK;
index d73d26bd1b74c53f44ccd8cd1e08924c290e56dd..5d7ecc4659f2683242951f61cb499cdfdb754761 100644 (file)
  *  Manual, Section 2.
  *  Andy Walker (andy@lysaker.kvaerner.no), April 09, 1996.
  *
- *  Tidied up block list handling.
+ *  Tidied up block list handling. Added '/proc/locks' interface.
  *  Andy Walker (andy@lysaker.kvaerner.no), April 24, 1996.
+ *
+ *  Fixed deadlock condition for pathological code that mixes calls to
+ *  flock() and fcntl().
+ *  Andy Walker (andy@lysaker.kvaerner.no), April 29, 1996.
  */
 
 #include <linux/malloc.h>
@@ -97,13 +101,14 @@ static int flock_lock_file(struct file *filp, struct file_lock *caller,
                           unsigned int wait);
 static int posix_lock_file(struct file *filp, struct file_lock *caller,
                           unsigned int wait);
-static int posix_locks_deadlock(struct task_struct *my_task,
-                               struct task_struct *blocked_task);
+static int locks_deadlock(struct task_struct *my_task,
+                         struct task_struct *blocked_task);
 static int locks_overlap(struct file_lock *fl1, struct file_lock *fl2);
 
 static struct file_lock *locks_alloc_lock(struct file_lock *fl);
 static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl);
 static void locks_delete_lock(struct file_lock **fl, unsigned int wait);
+static char *lock_get_status(struct file_lock *fl, char *p, int id, char *pfx);
 
 static struct file_lock *file_lock_table = NULL;
 
@@ -308,8 +313,8 @@ void locks_remove_locks(struct task_struct *task, struct file *filp)
         */
        before = &filp->f_inode->i_flock;
        while ((fl = *before) != NULL) {
-               if (((fl->fl_flags == F_POSIX) && (fl->fl_owner == task)) ||
-                   ((fl->fl_flags == F_FLOCK) && (fl->fl_file == filp) &&
+               if (((fl->fl_flags & F_POSIX) && (fl->fl_owner == task)) ||
+                   ((fl->fl_flags & F_FLOCK) && (fl->fl_file == filp) &&
                     (filp->f_count == 1)))
                        locks_delete_lock(before, 0);
                else
@@ -336,7 +341,7 @@ int locks_mandatory_locked(struct inode *inode)
        /* Search the lock list for this inode for any POSIX locks.
         */
        for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
-               if (fl->fl_flags == F_POSIX && fl->fl_owner != current)
+               if ((fl->fl_flags & F_POSIX) && (fl->fl_owner != current))
                        return (-EAGAIN);
        }
        return (0);
@@ -366,8 +371,8 @@ repeat:
         * the proposed read/write.
         */
        for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
-               if (fl->fl_flags == F_FLOCK ||
-                   (fl->fl_flags == F_POSIX && fl->fl_owner == current))
+               if ((fl->fl_flags & F_FLOCK) ||
+                   ((fl->fl_flags & F_POSIX) && (fl->fl_owner == current)))
                        continue;
                if (fl->fl_end < offset ||
                    fl->fl_start >= offset + count)
@@ -382,7 +387,7 @@ repeat:
                                return (-EAGAIN);
                        if (current->signal & ~current->blocked)
                                return (-ERESTARTSYS);
-                       if (posix_locks_deadlock(current, fl->fl_owner))
+                       if (locks_deadlock(current, fl->fl_owner))
                                return (-EDEADLOCK);
                        interruptible_sleep_on(&fl->fl_wait);
                        if (current->signal & ~current->blocked)
@@ -407,6 +412,8 @@ static int posix_make_lock(struct file *filp, struct file_lock *fl,
 {
        off_t start;
 
+       fl->fl_flags = F_POSIX;
+
        switch (l->l_type) {
        case F_RDLCK :
        case F_WRLCK :
@@ -415,9 +422,11 @@ static int posix_make_lock(struct file *filp, struct file_lock *fl,
                break;
        case F_SHLCK :
                fl->fl_type = F_RDLCK;
+               fl->fl_flags |= F_BROKEN;
                break;
        case F_EXLCK :
                fl->fl_type = F_WRLCK;
+               fl->fl_flags |= F_BROKEN;
                break;
        default :
                return (0);
@@ -443,7 +452,6 @@ static int posix_make_lock(struct file *filp, struct file_lock *fl,
        if ((l->l_len == 0) || ((fl->fl_end = start + l->l_len - 1) < 0))
                fl->fl_end = OFFSET_MAX;
        
-       fl->fl_flags = F_POSIX;
        fl->fl_file = filp;
        fl->fl_owner = current;
        fl->fl_wait = NULL;             /* just for cleanliness */
@@ -492,7 +500,7 @@ static int posix_locks_conflict(struct file_lock *caller_fl, struct file_lock *s
        /* POSIX locks owned by the same process do not conflict with
         * each other.
         */
-       if ((sys_fl->fl_flags == F_POSIX) &&
+       if ((sys_fl->fl_flags & F_POSIX) &&
            (caller_fl->fl_owner == sys_fl->fl_owner))
                return (0);
 
@@ -507,7 +515,7 @@ static int flock_locks_conflict(struct file_lock *caller_fl, struct file_lock *s
        /* FLOCK locks referring to the same filp do not conflict with
         * each other.
         */
-       if ((sys_fl->fl_flags == F_FLOCK) &&
+       if ((sys_fl->fl_flags & F_FLOCK) &&
            (caller_fl->fl_file == sys_fl->fl_file))
                return (0);
 
@@ -555,13 +563,15 @@ static int locks_overlap(struct file_lock *fl1, struct file_lock *fl2)
  * with blocked_task equal to that queue's owner, until either blocked_task
  * isn't found, or blocked_task is found on a queue owned by my_task.
  */
-static int posix_locks_deadlock(struct task_struct *my_task,
-                               struct task_struct *blocked_task)
+static int locks_deadlock(struct task_struct *my_task,
+                         struct task_struct *blocked_task)
 {
        struct wait_queue *dlock_wait;
        struct file_lock *fl;
 
 next_task:
+       if (my_task == blocked_task)
+               return (1);
        for (fl = file_lock_table; fl != NULL; fl = fl->fl_nextlink) {
                if (fl->fl_owner == NULL || fl->fl_wait == NULL)
                        continue;
@@ -569,7 +579,7 @@ next_task:
                do {
                        if (dlock_wait->task == blocked_task) {
                                if (fl->fl_owner == my_task) {
-                                       return(-EDEADLOCK);
+                                       return (1);
                                }
                                blocked_task = fl->fl_owner;
                                goto next_task;
@@ -596,7 +606,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *caller,
         * locks at the front of the list.
         */
        before = &filp->f_inode->i_flock;
-       while ((fl = *before) && (fl->fl_flags == F_FLOCK)) {
+       while ((fl = *before) && (fl->fl_flags & F_FLOCK)) {
                if (caller->fl_file == fl->fl_file) {
                        if (caller->fl_type == fl->fl_type)
                                return (0);
@@ -622,24 +632,31 @@ static int flock_lock_file(struct file *filp, struct file_lock *caller,
                if (wait) {
                        if (current->signal & ~current->blocked) {
                                /* Note: new_fl is not in any queue at this
-                                * point. So we must use locks_free_lock()
+                                * point, so we must use locks_free_lock()
                                 * instead of locks_delete_lock()
                                 *      Dmitry Gorodchanin 09/02/96.
                                 */
                                locks_free_lock(new_fl);
                                return (-ERESTARTSYS);
                        }
+                       /* Try to avoid deadlocks due to pathalogical programs that
+                        * mix calls to flock() and fcntl(). Return EAGAIN, because
+                        * EDEADLOCK isn't a documented return value for flock().
+                        */
+                       if (locks_deadlock(new_fl->fl_owner, fl->fl_owner)) {
+                               locks_free_lock(new_fl);
+                               return (-EAGAIN);
+                       }
                        locks_insert_block(fl, new_fl);
                        interruptible_sleep_on(&new_fl->fl_wait);
                        wake_up(&new_fl->fl_wait);
                        if (current->signal & ~current->blocked) {
-                               /* If we are here, than we were awaken
-                                * by signal, so new_fl is still in 
-                                * block queue of fl. We need remove 
-                                * new_fl and then free it. 
+                               /* If we are here, than we were awakened
+                                * by a signal, so new_fl is still in the
+                                * block queue of fl. We need to remove 
+                                * new_fl and then free it.
                                 *      Dmitry Gorodchanin 09/02/96.
                                 */
-
                                locks_delete_block(fl, new_fl);
                                locks_free_lock(new_fl);
                                return (-ERESTARTSYS);
@@ -684,9 +701,8 @@ repeat:
                        if (wait) {
                                if (current->signal & ~current->blocked)
                                        return (-ERESTARTSYS);
-                               if (fl->fl_flags == F_POSIX)
-                                       if (posix_locks_deadlock(caller->fl_owner, fl->fl_owner))
-                                               return (-EDEADLOCK);
+                               if (locks_deadlock(caller->fl_owner, fl->fl_owner))
+                                       return (-EDEADLOCK);
                                interruptible_sleep_on(&fl->fl_wait);
                                if (current->signal & ~current->blocked)
                                        return (-ERESTARTSYS);
@@ -703,7 +719,7 @@ repeat:
 
        /* First skip FLOCK locks and locks owned by other processes.
         */
-       while ((fl = *before) && ((fl->fl_flags == F_FLOCK) ||
+       while ((fl = *before) && ((fl->fl_flags & F_FLOCK) ||
                                  (caller->fl_owner != fl->fl_owner))) {
                before = &fl->fl_next;
        }
@@ -786,7 +802,7 @@ repeat:
                /* Go on to next lock.
                 */
        next_lock:
-               before = &(*before)->fl_next;
+               before = &fl->fl_next;
        }
 
        if (!added) {
@@ -795,7 +811,6 @@ repeat:
                if ((new_fl = locks_alloc_lock(caller)) == NULL)
                        return (-ENOLCK);
                locks_insert_lock(before, new_fl);
-
        }
        if (right) {
                if (left == right) {
@@ -904,3 +919,53 @@ static void locks_delete_lock(struct file_lock **fl_p, unsigned int wait)
 
        return;
 }
+
+
+static char *lock_get_status(struct file_lock *fl, char *p, int id, char *pfx)
+{
+       struct wait_queue *wt;
+
+       p += sprintf(p, "%d:%s ", id, pfx);
+       if (fl->fl_flags & F_POSIX) {
+               p += sprintf(p, "%s %s ",
+                            (fl->fl_flags & F_BROKEN) ? "BROKEN" : "POSIX ",
+                            ((fl->fl_file->f_inode->i_mode & (S_IXGRP | S_ISGID))
+                             == S_ISGID) ? "MANDATORY" : "ADVISORY ");
+       }
+       else {
+               p += sprintf(p, "FLOCK  ADVISORY  ");
+       }
+       p += sprintf(p, "%s ", (fl->fl_type == F_RDLCK) ? "READ " : "WRITE");
+       p += sprintf(p, "%d %04x:%ld %ld %ld ",
+                    fl->fl_owner->pid, fl->fl_file->f_inode->i_dev,
+                    fl->fl_file->f_inode->i_ino, fl->fl_start,
+                    fl->fl_end);
+       p += sprintf(p, "%08lx %08lx %08lx %08lx %08lx\n%d:%s",
+                    (long)fl, (long)fl->fl_prevlink, (long)fl->fl_nextlink,
+                    (long)fl->fl_next, (long)fl->fl_block, id, pfx);
+       if ((wt = fl->fl_wait) != NULL) {
+               do {
+                       p += sprintf(p, " %d", wt->task->pid);
+                       wt = wt->next;
+               } while (wt != fl->fl_wait);
+       }
+       p += sprintf(p, "\n");
+       return (p);
+}
+
+int get_locks_status(char *buf)
+{
+       struct file_lock *fl;
+       struct file_lock *bfl;
+       char *p;
+       int i;
+
+       p = buf;
+       for (fl = file_lock_table, i = 1; fl != NULL; fl = fl->fl_nextlink, i++) {
+               p = lock_get_status(fl, p, i, "");
+               for (bfl = fl; bfl->fl_block != NULL; bfl = bfl->fl_block)
+                       p = lock_get_status(bfl->fl_block, p, i, " ->");
+       }
+       return  (p - buf);
+}
+
index 0cc6e5ea109d5045c1509740c2097ab6703541f1..1c81c2341003a96f414730093bfb2f187504097c 100644 (file)
@@ -51,6 +51,8 @@
  *                             without giving a path name. Fix BOOTP request
  *                             for domainname (domainname is NIS domain, not
  *                             DNS domain!). Skip dummy devices for BOOTP.
+ *     Jacek Zapala    :       Fixed a bug which prevented server-ip address
+ *                             from nfsroot parameter from being used.
  *
  */
 
@@ -1060,6 +1062,8 @@ static int root_nfs_name(char *name)
                        break;
                if (*cp == '.' || octets == 3)
                        octets++;
+               if (octets < 4)
+                       cp++;
                cq = cp;
        }
        if (octets == 4 && (*cp == ':' || *cp == '\0')) {
index 2b88747f4569e18af7be38e7f78fd5857e668bc8..b5af9973e97e509ea23db51947c95d3349bd71a3 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -161,7 +161,7 @@ static int pipe_select(struct inode * inode, struct file * filp, int sel_type, s
                        select_wait(&PIPE_WAIT(*inode), wait);
                        return 0;
                case SEL_OUT:
-                       if (!PIPE_FULL(*inode) || !PIPE_READERS(*inode))
+                       if (PIPE_EMPTY(*inode) || !PIPE_READERS(*inode))
                                return 1;
                        select_wait(&PIPE_WAIT(*inode), wait);
                        return 0;
index f63ab6af239c408db54da566a15af16fe4a520af..3a1c426ebc877ab420390af10f116f858eb2e5e0 100644 (file)
@@ -967,6 +967,7 @@ extern int get_cpuinfo(char *);
 extern int get_pci_list(char*);
 extern int get_md_status (char *);
 extern int get_rtc_status (char *);
+extern int get_locks_status (char *);
 #ifdef __SMP_PROF__
 extern int get_smp_prof_list(char *);
 #endif
@@ -1041,6 +1042,8 @@ static int get_root_array(char * page, int type, char **start, off_t offset, int
                case PROC_RTC:
                        return get_rtc_status(page);
 #endif
+               case PROC_LOCKS:
+                       return get_locks_status(page);
        }
        return -EBADF;
 }
index 8e3969ca798b05ff3b140fefff3327631cf4a436..e3c8482e7867d8b0abcd3cb22cc54337283852cf 100644 (file)
@@ -50,6 +50,32 @@ static int check_range(struct task_struct * tsk, unsigned long addr, int count)
        return retval;
 }
 
+static struct task_struct * get_task(int pid)
+{
+       struct task_struct * tsk = current;
+
+       if (pid != tsk->pid) {
+               int i;
+               tsk = NULL;
+               for (i = 1 ; i < NR_TASKS ; i++)
+                       if (task[i] && task[i]->pid == pid) {
+                               tsk = task[i];
+                               break;
+                       }
+               /*
+                * allow accesses only under the same circumstances
+                * that we would allow ptrace to work
+                */
+               if (tsk) {
+                       if (!(tsk->flags & PF_PTRACED)
+                           || tsk->state != TASK_STOPPED
+                           || tsk->p_pptr != current)
+                               tsk = NULL;
+               }
+       }
+       return tsk;
+}
+
 static int mem_read(struct inode * inode, struct file * file,char * buf, int count)
 {
        pgd_t *page_dir;
@@ -57,17 +83,15 @@ static int mem_read(struct inode * inode, struct file * file,char * buf, int cou
        pte_t pte;
        char * page;
        struct task_struct * tsk;
-       unsigned long addr, pid;
+       unsigned long addr;
        char *tmp;
        int i;
 
        if (count < 0)
                return -EINVAL;
-       pid = inode->i_ino;
-       pid >>= 16;
-       if (pid != current->pid)
-               return -EACCES;
-       tsk = current;
+       tsk = get_task(inode->i_ino >> 16);
+       if (!tsk)
+               return -ESRCH;
        addr = file->f_pos;
        count = check_range(tsk, addr, count);
        if (count < 0)
@@ -117,18 +141,16 @@ static int mem_write(struct inode * inode, struct file * file,char * buf, int co
        pte_t pte;
        char * page;
        struct task_struct * tsk;
-       unsigned long addr, pid;
+       unsigned long addr;
        char *tmp;
        int i;
 
        if (count < 0)
                return -EINVAL;
        addr = file->f_pos;
-       pid = inode->i_ino;
-       pid >>= 16;
-       if (pid != current->pid)
-               return -EACCES;
-       tsk = current;
+       tsk = get_task(inode->i_ino >> 16);
+       if (!tsk)
+               return -ESRCH;
        tmp = buf;
        while (count > 0) {
                if (current->signal & ~current->blocked)
@@ -199,19 +221,13 @@ int mem_mmap(struct inode * inode, struct file * file,
        pte_t *src_table, *dest_table;
        unsigned long stmp, dtmp;
        struct vm_area_struct *src_vma = NULL;
-       int i;
 
        /* Get the source's task information */
 
-       tsk = NULL;
-       for (i = 1 ; i < NR_TASKS ; i++)
-               if (task[i] && task[i]->pid == (inode->i_ino >> 16)) {
-                       tsk = task[i];
-                       break;
-               }
+       tsk = get_task(inode->i_ino >> 16);
 
        if (!tsk)
-               return -EACCES;
+               return -ESRCH;
 
        /* Ensure that we have a valid source area.  (Has to be mmap'ed and
         have valid page information.)  We can't map shared memory at the
index 267222e31bad59716f940d22a88a2bf474ef839e..962f428a0a1648ab65448b660639eb5a42efce1e 100644 (file)
@@ -358,6 +358,10 @@ void proc_root_init(void)
                S_IFREG | S_IRUGO, 1, 0, 0,
        });
 #endif
+       proc_register(&proc_root, &(struct proc_dir_entry) {
+               PROC_LOCKS, 5, "locks",
+               S_IFREG | S_IRUGO, 1, 0, 0,
+       });
 
        proc_register( &proc_root, &(struct proc_dir_entry)
           { PROC_MTAB, 6, "mounts", S_IFREG | S_IRUGO, 1, 0, 0, } );
index 09ed06ecf94db57596f76e63317955aa1e218a42..cb0e3af0f395fcf51815b2c7c11982bb3df0c427 100644 (file)
@@ -52,6 +52,7 @@
 #ifdef __KERNEL__
 #define F_POSIX                1
 #define F_FLOCK                2
+#define F_BROKEN       4       /* broken flock() emulation */
 #endif /* __KERNEL__ */
 
 struct flock {
index cecc05c39bf253a40f83462114236daafbec5f45..cbc2615d0e07568723408490cd5298339c61ea4b 100644 (file)
@@ -65,14 +65,30 @@ static inline unsigned short ip_fast_csum(unsigned char * iph,
            notl %0
 2:
            "
-       : "=&r" (sum), "=&r" (iph), "=&r" (ihl)
+       /* Since the input registers which are loaded with iph and ipl
+          are modified, we must also specify them as outputs, or gcc
+          will assume they contain their original values. */
+       : "=r" (sum), "=r" (iph), "=r" (ihl)
        : "1" (iph), "2" (ihl));
        return(sum);
 }
 
+/*
+ *     Fold a partial checksum
+ */
 
-
-
+static inline unsigned int csum_fold(unsigned int sum)
+{
+       __asm__("
+               addl %1, %0
+               adcl $0xffff, %0
+               "
+               : "=r" (sum)
+               : "r" (sum << 16), "0" (sum & 0xffff0000)
+       );
+       return (~sum) >> 16;
+}
 /*
  * computes the checksum of the TCP/UDP pseudo-header
  * returns a 16-bit checksum, already complemented
@@ -85,55 +101,21 @@ static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
                                                   unsigned int sum) {
     __asm__("
        addl %1, %0
-       adcl %4, %0
-       adcl %5, %0
-       adcl $0, %0
-       movl %0, %1
-       shrl $16, %1
-       addw %w1, %w0
+       adcl %2, %0
+       adcl %3, %0
        adcl $0, %0
-       notl %0
        "
-       : "=&r" (sum), "=&r" (saddr)
-       : "0" (daddr), "1"(saddr), "r"((ntohs(len)<<16)+proto*256), "r"(sum));
-       return((unsigned short)sum);
-}
-
-/*
- *     Fold a partial checksum without adding pseudo headers
- */
-
-static inline unsigned int csum_fold(unsigned int sum)
-{
-       __asm__("
-               addl %1, %0
-               adcl $0xffff, %0
-               "
-               : "=r" (sum)
-               : "r" (sum << 16), "0" (sum & 0xffff0000)
-       );
-       return (~sum) >> 16;
+       : "=r" (sum)
+       : "g" (daddr), "g"(saddr), "g"((ntohs(len)<<16)+proto*256), "0"(sum));
+       return csum_fold(sum);
 }
 /*
  * this routine is used for miscellaneous IP-like checksums, mainly
  * in icmp.c
  */
 
 static inline unsigned short ip_compute_csum(unsigned char * buff, int len) {
-    unsigned int sum;
-
-    unsigned int scratch;
-    __asm__("
-       movl %0, %1
-       shrl $16, %1
-       addw %w1, %w0
-       adcl $0, %0
-       notl %0
-       "
-       : "=a"(sum), "=r" (scratch)
-       : "0" (csum_partial(buff, len, 0)));
-       return(sum);
+    return csum_fold (csum_partial(buff, len, 0));
 }
 
 #endif
index 0cb8fcdba96b6efb12625b609863a60fa8af4e64..8db6b6070c0b3d7154a6296cd074a4f9f8c9546c 100644 (file)
@@ -51,6 +51,7 @@
 #ifdef __KERNEL__
 #define F_POSIX                1
 #define F_FLOCK                2
+#define F_BROKEN       4       /* broken flock() emulation */
 #endif /* __KERNEL__ */
 
 struct flock {
index 07b1babaa7b77010a76c3b518ad24354b3d50972..fa40da33589db0aa25fffd5c9562a3834708804d 100644 (file)
@@ -51,6 +51,7 @@
 #ifdef __KERNEL__
 #define F_POSIX                1
 #define F_FLOCK                2
+#define F_BROKEN       4       /* broken flock() emulation */
 #endif /* __KERNEL__ */
 
 struct flock {
index a524af6d3af54d34aad02785ff82f469f81504e0..223967ae456e5384f854610d3a96a7a78b4500a5 100644 (file)
@@ -52,6 +52,7 @@
 #ifdef __KERNEL__
 #define F_POSIX                1
 #define F_FLOCK                2
+#define F_BROKEN       4       /* broken flock() emulation */
 #endif /* __KERNEL__ */
 
 typedef struct flock {
index 8c714d51f6f1273286770e885a84712efeedc2eb..61d0fa703f745249b8087ee4e1e7eb04888d89c4 100644 (file)
@@ -51,6 +51,7 @@
 #ifdef __KERNEL__
 #define F_POSIX                1
 #define F_FLOCK                2
+#define F_BROKEN       4       /* broken flock() emulation */
 #endif /* __KERNEL__ */
 
 struct flock {
index 22ea2ae9ad8697fd1162babf4ad3c52a6a88ba67..de42f13046e8300850499879ccff940df8aa9305 100644 (file)
@@ -51,6 +51,7 @@
 #ifdef __KERNEL__
 #define F_POSIX                1
 #define F_FLOCK                2
+#define F_BROKEN       4       /* broken flock() emulation */
 #endif /* __KERNEL__ */
 
 struct flock {
index 49edb1d136f503ea95d1d89d2de44619750ce4fe..3264451109771d824414571bc7d7f3edb1bb8955 100644 (file)
@@ -61,6 +61,8 @@ struct apm_bios_struct {
        int             suser;
        int             suspends_pending;
        int             standbys_pending;
+       int             suspends_read;
+       int             standbys_read;
        int             event_head;
        int             event_tail;
        apm_event_t     events[APM_MAX_EVENTS];
@@ -81,6 +83,7 @@ extern void           apm_bios_init(void);
 extern int             apm_register_callback(int (*callback)(apm_event_t));
 extern void            apm_unregister_callback(int (*callback)(apm_event_t));
 
+extern int             apm_set_power_state(ushort state);
 extern int             apm_display_blank(void);
 extern int             apm_display_unblank(void);
 
index f57398e533234b10418fadf91ab325694c146f54..d3632092a6d55a97cececa0f2b3562a2b052c4e0 100644 (file)
@@ -9,11 +9,11 @@
  * PCI System Design Guide
  *
  * PCI Special Interest Group
- * M/S HF3-15A
- * 5200 N.E. Elam Young Parkway
- * Hillsboro, Oregon 97124-6497
- * +1 (503) 696-2000 
- * +1 (800) 433-5177
+ * P.O. Box 14070
+ * Portland, OR 97214
+ * U. S. A.
+ * Phone: 800-433-5177 / +1-503-797-4207
+ * Fax: +1-503-234-6762 
  * 
  * Manuals are $25 each or $50 for all three, plus $7 shipping 
  * within the United States, $35 abroad.
index 208cf46af363c40fead29e6d1441badb4a6bad77..896438e610f17da62f2e2bddad98974f7b56337b 100644 (file)
@@ -60,7 +60,9 @@
 #define EXT2_ACL_DATA_INO       4      /* ACL inode */
 #define EXT2_BOOT_LOADER_INO    5      /* Boot loader inode */
 #define EXT2_UNDEL_DIR_INO      6      /* Undelete directory inode */
-#define EXT2_FIRST_INO         11      /* First non reserved inode */
+
+/* First non-reserved inode for old ext2 filesystems */
+#define EXT2_GOOD_OLD_FIRST_INO        11
 
 /*
  * The second extended file system magic number
 #else
 # define EXT2_BLOCK_SIZE_BITS(s)       ((s)->s_log_block_size + 10)
 #endif
-#define        EXT2_INODES_PER_BLOCK(s)        (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_inode))
 #ifdef __KERNEL__
 #define        EXT2_ADDR_PER_BLOCK_BITS(s)     ((s)->u.ext2_sb.s_addr_per_block_bits)
-#define        EXT2_INODES_PER_BLOCK_BITS(s)   ((s)->u.ext2_sb.s_inodes_per_block_bits)
+#define EXT2_INODE_SIZE(s)             ((s)->u.ext2_sb.s_inode_size)
+#define EXT2_FIRST_INO(s)              ((s)->u.ext2_sb.s_first_ino)
+#else
+#define EXT2_INODE_SIZE(s)     (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
+                                EXT2_GOOD_OLD_INODE_SIZE : \
+                                (s)->s_inode_size)
+#define EXT2_FIRST_INO(s)      (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
+                                EXT2_GOOD_OLD_FIRST_INO : \
+                                (s)->s_first_ino)
 #endif
 
 /*
@@ -180,7 +189,8 @@ struct ext2_group_desc
 #define EXT2_IMMUTABLE_FL              0x00000010 /* Immutable file */
 #define EXT2_APPEND_FL                 0x00000020 /* writes to file may only append */
 #define EXT2_NODUMP_FL                 0x00000040 /* do not dump file */
-
+#define EXT2_RESERVED_FL               0x80000000 /* reserved for ext2 lib */
+       
 /*
  * ioctl commands
  */
@@ -327,14 +337,32 @@ struct ext2_super_block {
        __u16   s_magic;                /* Magic signature */
        __u16   s_state;                /* File system state */
        __u16   s_errors;               /* Behaviour when detecting errors */
-       __u16   s_pad;
+       __u16   s_minor_rev_level;      /* minor revision level */
        __u32   s_lastcheck;            /* time of last check */
        __u32   s_checkinterval;        /* max. time between checks */
        __u32   s_creator_os;           /* OS */
        __u32   s_rev_level;            /* Revision level */
        __u16   s_def_resuid;           /* Default uid for reserved blocks */
        __u16   s_def_resgid;           /* Default gid for reserved blocks */
-       __u32   s_reserved[235];        /* Padding to the end of the block */
+       /*
+        * These fields are for EXT2_DYNAMIC_REV superblocks only.
+        *
+        * Note: the difference between the compatible feature set and
+        * the incompatible feature set is that if there is a bit set
+        * in the incompatible feature set that the kernel doesn't
+        * know about, it should refuse to mount the filesystem.
+        * 
+        * e2fsck's requirements are more strict; if it doesn't know
+        * about a feature in either the compatible or incompatible
+        * feature set, it must abort and not try to meddle with
+        * things it doesn't understand...
+        */
+       __u32   s_first_ino;            /* First non-reserved inode */
+       __u16   s_inode_size;           /* size of inode structure */
+       __u16   s_block_group_nr;       /* block group # of this superblock */
+       __u32   s_feature_compat;       /* compatible feature set */
+       __u32   s_feature_incompat;     /* incompatible feature set */
+       __u32   s_reserved[231];        /* Padding to the end of the block */
 };
 
 /*
@@ -350,8 +378,12 @@ struct ext2_super_block {
  * Revision levels
  */
 #define EXT2_GOOD_OLD_REV      0       /* The good old (original) format */
+#define EXT2_DYNAMIC_REV       1       /* V2 format w/ dynamic inode sizes */
 
 #define EXT2_CURRENT_REV       EXT2_GOOD_OLD_REV
+#define EXT2_MAX_SUPP_REV      EXT2_DYNAMIC_REV
+
+#define EXT2_GOOD_OLD_INODE_SIZE 128
 
 /*
  * Default values for user and/or group using reserved blocks
@@ -381,6 +413,12 @@ struct ext2_dir_entry {
 #define EXT2_DIR_REC_LEN(name_len)     (((name_len) + 8 + EXT2_DIR_ROUND) & \
                                         ~EXT2_DIR_ROUND)
 
+/*
+ * Feature set definitions --- none are defined as of now
+ */
+#define EXT2_FEATURE_COMPAT_SUPP       0
+#define EXT2_FEATURE_INCOMPAT_SUPP     0
+
 #ifdef __KERNEL__
 /*
  * Function prototypes
index f3eca4480a1bbc6a68aab8ea56a8c4dba960713b..7df902135323d84664d6298623449fd641a5073c 100644 (file)
@@ -35,6 +35,7 @@ struct ext2_inode_info {
        __u32   i_next_alloc_goal;
        __u32   i_prealloc_block;
        __u32   i_prealloc_count;
+       int     i_new_inode:1;  /* Is a freshly allocated inode */
 };
 
 #endif /* _LINUX_EXT2_FS_I */
index 5a33f3c1c18978b066d9e4eb2cb73c1b58b28a6a..dd064b86a8aa13b1b244d9f3ffca24d2ba7eb597 100644 (file)
@@ -57,8 +57,9 @@ struct ext2_sb_info {
        unsigned short s_mount_state;
        unsigned short s_pad;
        int s_addr_per_block_bits;
-       int s_inodes_per_block_bits;
        int s_desc_per_block_bits;
+       int s_inode_size;
+       int s_first_ino;
 };
 
 #endif /* _LINUX_EXT2_FS_SB */
index e8fa91e6af7648554dccb7059424112f7f958d62..e07049f6ad7aa9d65261df97c4bb672cf6d03966 100644 (file)
@@ -57,6 +57,12 @@ extern int kill_sl(int sess, int sig, int priv);
 asmlinkage int printk(const char * fmt, ...)
        __attribute__ ((format (printf, 1, 2)));
 
+#define pr_debug(show,fmt,arg...) \
+       do { if (show) printk(KERN_DEBUG fmt,##arg); } while (0)
+
+#define pr_info(fmt,arg...) \
+       printk(KERN_INFO fmt,##arg)
+
 /*
  * "suser()" checks against the effective user id, while "fsuser()"
  * is used for file permission checking and checks against the fsuid..
index 4b75bbe6c3d440f27762878c5e7b3e04ef29c93a..35fcfc4d120b8dfa773b2b3d82e828c6ab7a0d92 100644 (file)
@@ -57,6 +57,8 @@ struct        mtop {
 #define MTLOAD  30     /* execute the SCSI load command */
 #define MTUNLOAD 31    /* execute the SCSI unload command */
 #define MTCOMPRESSION 32/* control compression with SCSI mode page 15 */
+#define MTSETPART 33   /* Change the active tape partition */
+#define MTMKPART  34   /* Format the tape with one or two partitions */
 
 /* structure for MTIOCGET - mag tape get status command */
 
@@ -180,7 +182,6 @@ struct mtconfiginfo {
 #define        MTIOCGETCONFIG  _IOR('m', 4, struct mtconfiginfo) /* get tape config */
 #define        MTIOCSETCONFIG  _IOW('m', 5, struct mtconfiginfo) /* set tape config */
 
-
 /* Generic Mag Tape (device independent) status macros for examining
  * mt_gstat -- HP-UX compatible.
  * There is room for more generic status bits here, but I don't
@@ -235,6 +236,8 @@ struct mtconfiginfo {
 #define MT_ST_DEF_WRITES       0x80
 #define MT_ST_CAN_BSR          0x100
 #define MT_ST_NO_BLKLIMS       0x200
+#define MT_ST_CAN_PARTITIONS    0x400
+#define MT_ST_SCSI2LOGICAL      0x800
 
 /* The mode parameters to be controlled. Parameter chosen with bits 20-28 */
 #define MT_ST_CLEAR_DEFAULT    0xfffff
index 9164d5553a9484de754196639cf89b5397056a0c..d5a7688678edade60839961667ef82b529db1867 100644 (file)
@@ -42,7 +42,8 @@ enum root_directory_inos {
        PROC_SYS,
        PROC_MTAB,
        PROC_MD,
-       PROC_RTC
+       PROC_RTC,
+       PROC_LOCKS
 };
 
 enum pid_directory_inos {
index 8fce34d59afccbeac684468395ff6c5bb556a0ab..00bc0183c44d94860aee2012be20d3816a2dc498 100644 (file)
@@ -9,12 +9,27 @@
 
 /* ioctl()'s for the random number generator */
 
+/* Get the entropy count. */
 #define RNDGETENTCNT   0x01080000
+
+/* Add to (or subtract from) the entropy count.  (Superuser only.) */
 #define RNDADDTOENTCNT 0x01080001
+
+/* Get the contents of the entropy pool.  (Superuser only.) */
 #define RNDGETPOOL     0x01080002
+
+/* 
+ * Write bytes into the entropy pool and add to the entropy count.
+ * (Superuser only.)
+ */
 #define RNDADDENTROPY  0x01080003
+
+/* Clear entropy count to 0.  (Superuser only.) */
 #define RNDZAPENTCNT   0x01080004
 
+/* Clear the entropy pool and associated counters.  (Superuser only.) */
+#define RNDCLEARPOOL   0x01080006
+
 struct rand_pool_info {
        int     entropy_count;
        int     buf_size;
diff --git a/include/linux/scsi.h b/include/linux/scsi.h
deleted file mode 100644 (file)
index 05c2ba8..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-#ifndef _LINUX_SCSI_H
-#define _LINUX_SCSI_H
-
-/*
- * This header file contains public constants and structures used by
- * the scsi code for linux.
- */
-
-/*
-    $Header: /usr/src/linux/include/linux/RCS/scsi.h,v 1.3 1993/09/24 12:20:33 drew Exp $
-
-    For documentation on the OPCODES, MESSAGES, and SENSE values,
-    please consult the SCSI standard.
-
-*/
-
-/*
- *      SCSI opcodes
- */
-
-#define TEST_UNIT_READY       0x00
-#define REZERO_UNIT           0x01
-#define REQUEST_SENSE         0x03
-#define FORMAT_UNIT           0x04
-#define READ_BLOCK_LIMITS     0x05
-#define REASSIGN_BLOCKS       0x07
-#define READ_6                0x08
-#define WRITE_6               0x0a
-#define SEEK_6                0x0b
-#define READ_REVERSE          0x0f
-#define WRITE_FILEMARKS       0x10
-#define SPACE                 0x11
-#define INQUIRY               0x12
-#define RECOVER_BUFFERED_DATA 0x14
-#define MODE_SELECT           0x15
-#define RESERVE               0x16
-#define RELEASE               0x17
-#define COPY                  0x18
-#define ERASE                 0x19
-#define MODE_SENSE            0x1a
-#define START_STOP            0x1b
-#define RECEIVE_DIAGNOSTIC    0x1c
-#define SEND_DIAGNOSTIC       0x1d
-#define ALLOW_MEDIUM_REMOVAL  0x1e
-
-#define SET_WINDOW            0x24
-#define READ_CAPACITY         0x25
-#define READ_10               0x28
-#define WRITE_10              0x2a
-#define SEEK_10               0x2b
-#define WRITE_VERIFY          0x2e
-#define VERIFY                0x2f
-#define SEARCH_HIGH           0x30
-#define SEARCH_EQUAL          0x31
-#define SEARCH_LOW            0x32
-#define SET_LIMITS            0x33
-#define PRE_FETCH             0x34
-#define READ_POSITION         0x34
-#define SYNCHRONIZE_CACHE     0x35
-#define LOCK_UNLOCK_CACHE     0x36
-#define READ_DEFECT_DATA      0x37
-#define MEDIUM_SCAN           0x38
-#define COMPARE               0x39
-#define COPY_VERIFY           0x3a
-#define WRITE_BUFFER          0x3b
-#define READ_BUFFER           0x3c
-#define UPDATE_BLOCK          0x3d
-#define READ_LONG             0x3e
-#define WRITE_LONG            0x3f
-#define CHANGE_DEFINITION     0x40
-#define WRITE_SAME            0x41
-#define LOG_SELECT            0x4c
-#define LOG_SENSE             0x4d
-#define MODE_SELECT_10        0x55
-#define MODE_SENSE_10         0x5a
-#define READ_12               0xa8
-#define WRITE_12              0xaa
-#define WRITE_VERIFY_12       0xae
-#define SEARCH_HIGH_12        0xb0
-#define SEARCH_EQUAL_12       0xb1
-#define SEARCH_LOW_12         0xb2
-#define SEND_VOLUME_TAG       0xb6
-#define WRITE_LONG_2          0xea
-
-/*
- *  Status codes
- */
-
-#define GOOD                 0x00
-#define CHECK_CONDITION      0x01
-#define CONDITION_GOOD       0x02
-#define BUSY                 0x04
-#define INTERMEDIATE_GOOD    0x08
-#define INTERMEDIATE_C_GOOD  0x0a
-#define RESERVATION_CONFLICT 0x0c
-#define QUEUE_FULL           0x1a
-
-#define STATUS_MASK          0x1e
-
-/*
- *  SENSE KEYS
- */
-
-#define NO_SENSE            0x00
-#define RECOVERED_ERROR     0x01
-#define NOT_READY           0x02
-#define MEDIUM_ERROR        0x03
-#define HARDWARE_ERROR      0x04
-#define ILLEGAL_REQUEST     0x05
-#define UNIT_ATTENTION      0x06
-#define DATA_PROTECT        0x07
-#define BLANK_CHECK         0x08
-#define COPY_ABORTED        0x0a
-#define ABORTED_COMMAND     0x0b
-#define VOLUME_OVERFLOW     0x0d
-#define MISCOMPARE          0x0e
-
-
-/*
- *  DEVICE TYPES
- */
-
-#define TYPE_DISK           0x00
-#define TYPE_TAPE           0x01
-#define TYPE_PROCESSOR      0x03    /* HP scanners use this */
-#define TYPE_WORM           0x04    /* Treated as ROM by our system */
-#define TYPE_ROM            0x05
-#define TYPE_SCANNER        0x06
-#define TYPE_MOD            0x07    /* Magneto-optical disk - 
-                                    * - treated as TYPE_DISK */
-#define TYPE_NO_LUN         0x7f
-
-
-/*
- *  MESSAGE CODES
- */
-
-#define COMMAND_COMPLETE    0x00
-#define EXTENDED_MESSAGE    0x01
-#define     EXTENDED_MODIFY_DATA_POINTER    0x00
-#define     EXTENDED_SDTR                   0x01
-#define     EXTENDED_EXTENDED_IDENTIFY      0x02    /* SCSI-I only */
-#define     EXTENDED_WDTR                   0x03
-#define SAVE_POINTERS       0x02
-#define RESTORE_POINTERS    0x03
-#define DISCONNECT          0x04
-#define INITIATOR_ERROR     0x05
-#define ABORT               0x06
-#define MESSAGE_REJECT      0x07
-#define NOP                 0x08
-#define MSG_PARITY_ERROR    0x09
-#define LINKED_CMD_COMPLETE 0x0a
-#define LINKED_FLG_CMD_COMPLETE 0x0b
-#define BUS_DEVICE_RESET    0x0c
-
-#define INITIATE_RECOVERY   0x0f            /* SCSI-II only */
-#define RELEASE_RECOVERY    0x10            /* SCSI-II only */
-
-#define SIMPLE_QUEUE_TAG    0x20
-#define HEAD_OF_QUEUE_TAG   0x21
-#define ORDERED_QUEUE_TAG   0x22
-
-/*
- * Here are some scsi specific ioctl commands which are sometimes useful.
- */
-/* These are a few other constants  only used by scsi  devices */
-
-#define SCSI_IOCTL_GET_IDLUN 0x5382
-
-/* Used to turn on and off tagged queuing for scsi devices */
-
-#define SCSI_IOCTL_TAGGED_ENABLE 0x5383
-#define SCSI_IOCTL_TAGGED_DISABLE 0x5384
-
-/* Used to obtain the host number of a device. */
-#define SCSI_IOCTL_PROBE_HOST 0x5385
-
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4 
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
-
-#endif
diff --git a/include/linux/scsicam.h b/include/linux/scsicam.h
deleted file mode 100644 (file)
index 954e140..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * scsicam.h - SCSI CAM support functions, use for HDIO_GETGEO, etc.
- *
- * Copyright 1993, 1994 Drew Eckhardt
- *      Visionary Computing 
- *      (Unix and Linux consulting and custom programming)
- *      drew@Colorado.EDU
- *     +1 (303) 786-7975
- *
- * For more information, please consult the SCSI-CAM draft.
- */
-
-#ifndef SCSICAM_H
-#define SCSICAM_H
-#include <linux/kdev_t.h>
-extern int scsicam_bios_param (Disk *disk, kdev_t dev, int *ip);
-#endif /* def SCSICAM_H */
index c532629e318d678f1e07ab85c3d2365a200562b5..9a0270bcdc552229e1a12acdba7521402bbb82c0 100644 (file)
@@ -222,7 +222,7 @@ struct timex {
 #define TIME_INS       1       /* insert leap second */
 #define TIME_DEL       2       /* delete leap second */
 #define TIME_OOP       3       /* leap second in progress */
-#define TIME_WAIT      4       /* leap second has occured */
+#define TIME_WAIT      4       /* leap second has occurred */
 #define TIME_ERROR     5       /* clock not synchronized */
 #define TIME_BAD       TIME_ERROR /* bw compat */
 
index 77c79d5e77f3b8f258eaf74b269b0045f9c0700a..b805f38bbb1382ec6674ec7adfeecea63505a803 100644 (file)
@@ -15,7 +15,6 @@
  *             Alexey Kuznetsov:       Major changes for new routing code.
  *
  *     FIXME:
- *             Modules stuff is broken at the moment.
  *             Make atomic ops more generic and hide them in asm/...
  *
  *             This program is free software; you can redistribute it and/or
@@ -33,7 +32,7 @@
  * 1 - rare events and bugs situations (default)
  * 2 - trace mode.
  */
-#define RT_CACHE_DEBUG         1
+#define RT_CACHE_DEBUG         0
 
 #define RT_HASH_DIVISOR                256
 #define RT_CACHE_SIZE_MAX      256
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
new file mode 100644 (file)
index 0000000..05c2ba8
--- /dev/null
@@ -0,0 +1,198 @@
+#ifndef _LINUX_SCSI_H
+#define _LINUX_SCSI_H
+
+/*
+ * This header file contains public constants and structures used by
+ * the scsi code for linux.
+ */
+
+/*
+    $Header: /usr/src/linux/include/linux/RCS/scsi.h,v 1.3 1993/09/24 12:20:33 drew Exp $
+
+    For documentation on the OPCODES, MESSAGES, and SENSE values,
+    please consult the SCSI standard.
+
+*/
+
+/*
+ *      SCSI opcodes
+ */
+
+#define TEST_UNIT_READY       0x00
+#define REZERO_UNIT           0x01
+#define REQUEST_SENSE         0x03
+#define FORMAT_UNIT           0x04
+#define READ_BLOCK_LIMITS     0x05
+#define REASSIGN_BLOCKS       0x07
+#define READ_6                0x08
+#define WRITE_6               0x0a
+#define SEEK_6                0x0b
+#define READ_REVERSE          0x0f
+#define WRITE_FILEMARKS       0x10
+#define SPACE                 0x11
+#define INQUIRY               0x12
+#define RECOVER_BUFFERED_DATA 0x14
+#define MODE_SELECT           0x15
+#define RESERVE               0x16
+#define RELEASE               0x17
+#define COPY                  0x18
+#define ERASE                 0x19
+#define MODE_SENSE            0x1a
+#define START_STOP            0x1b
+#define RECEIVE_DIAGNOSTIC    0x1c
+#define SEND_DIAGNOSTIC       0x1d
+#define ALLOW_MEDIUM_REMOVAL  0x1e
+
+#define SET_WINDOW            0x24
+#define READ_CAPACITY         0x25
+#define READ_10               0x28
+#define WRITE_10              0x2a
+#define SEEK_10               0x2b
+#define WRITE_VERIFY          0x2e
+#define VERIFY                0x2f
+#define SEARCH_HIGH           0x30
+#define SEARCH_EQUAL          0x31
+#define SEARCH_LOW            0x32
+#define SET_LIMITS            0x33
+#define PRE_FETCH             0x34
+#define READ_POSITION         0x34
+#define SYNCHRONIZE_CACHE     0x35
+#define LOCK_UNLOCK_CACHE     0x36
+#define READ_DEFECT_DATA      0x37
+#define MEDIUM_SCAN           0x38
+#define COMPARE               0x39
+#define COPY_VERIFY           0x3a
+#define WRITE_BUFFER          0x3b
+#define READ_BUFFER           0x3c
+#define UPDATE_BLOCK          0x3d
+#define READ_LONG             0x3e
+#define WRITE_LONG            0x3f
+#define CHANGE_DEFINITION     0x40
+#define WRITE_SAME            0x41
+#define LOG_SELECT            0x4c
+#define LOG_SENSE             0x4d
+#define MODE_SELECT_10        0x55
+#define MODE_SENSE_10         0x5a
+#define READ_12               0xa8
+#define WRITE_12              0xaa
+#define WRITE_VERIFY_12       0xae
+#define SEARCH_HIGH_12        0xb0
+#define SEARCH_EQUAL_12       0xb1
+#define SEARCH_LOW_12         0xb2
+#define SEND_VOLUME_TAG       0xb6
+#define WRITE_LONG_2          0xea
+
+/*
+ *  Status codes
+ */
+
+#define GOOD                 0x00
+#define CHECK_CONDITION      0x01
+#define CONDITION_GOOD       0x02
+#define BUSY                 0x04
+#define INTERMEDIATE_GOOD    0x08
+#define INTERMEDIATE_C_GOOD  0x0a
+#define RESERVATION_CONFLICT 0x0c
+#define QUEUE_FULL           0x1a
+
+#define STATUS_MASK          0x1e
+
+/*
+ *  SENSE KEYS
+ */
+
+#define NO_SENSE            0x00
+#define RECOVERED_ERROR     0x01
+#define NOT_READY           0x02
+#define MEDIUM_ERROR        0x03
+#define HARDWARE_ERROR      0x04
+#define ILLEGAL_REQUEST     0x05
+#define UNIT_ATTENTION      0x06
+#define DATA_PROTECT        0x07
+#define BLANK_CHECK         0x08
+#define COPY_ABORTED        0x0a
+#define ABORTED_COMMAND     0x0b
+#define VOLUME_OVERFLOW     0x0d
+#define MISCOMPARE          0x0e
+
+
+/*
+ *  DEVICE TYPES
+ */
+
+#define TYPE_DISK           0x00
+#define TYPE_TAPE           0x01
+#define TYPE_PROCESSOR      0x03    /* HP scanners use this */
+#define TYPE_WORM           0x04    /* Treated as ROM by our system */
+#define TYPE_ROM            0x05
+#define TYPE_SCANNER        0x06
+#define TYPE_MOD            0x07    /* Magneto-optical disk - 
+                                    * - treated as TYPE_DISK */
+#define TYPE_NO_LUN         0x7f
+
+
+/*
+ *  MESSAGE CODES
+ */
+
+#define COMMAND_COMPLETE    0x00
+#define EXTENDED_MESSAGE    0x01
+#define     EXTENDED_MODIFY_DATA_POINTER    0x00
+#define     EXTENDED_SDTR                   0x01
+#define     EXTENDED_EXTENDED_IDENTIFY      0x02    /* SCSI-I only */
+#define     EXTENDED_WDTR                   0x03
+#define SAVE_POINTERS       0x02
+#define RESTORE_POINTERS    0x03
+#define DISCONNECT          0x04
+#define INITIATOR_ERROR     0x05
+#define ABORT               0x06
+#define MESSAGE_REJECT      0x07
+#define NOP                 0x08
+#define MSG_PARITY_ERROR    0x09
+#define LINKED_CMD_COMPLETE 0x0a
+#define LINKED_FLG_CMD_COMPLETE 0x0b
+#define BUS_DEVICE_RESET    0x0c
+
+#define INITIATE_RECOVERY   0x0f            /* SCSI-II only */
+#define RELEASE_RECOVERY    0x10            /* SCSI-II only */
+
+#define SIMPLE_QUEUE_TAG    0x20
+#define HEAD_OF_QUEUE_TAG   0x21
+#define ORDERED_QUEUE_TAG   0x22
+
+/*
+ * Here are some scsi specific ioctl commands which are sometimes useful.
+ */
+/* These are a few other constants  only used by scsi  devices */
+
+#define SCSI_IOCTL_GET_IDLUN 0x5382
+
+/* Used to turn on and off tagged queuing for scsi devices */
+
+#define SCSI_IOCTL_TAGGED_ENABLE 0x5383
+#define SCSI_IOCTL_TAGGED_DISABLE 0x5384
+
+/* Used to obtain the host number of a device. */
+#define SCSI_IOCTL_PROBE_HOST 0x5385
+
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4 
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
+
+#endif
diff --git a/include/scsi/scsi_ioctl.h b/include/scsi/scsi_ioctl.h
new file mode 100644 (file)
index 0000000..a42fed0
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef _SCSI_IOCTL_H
+#define _SCSI_IOCTL_H 
+
+#define SCSI_IOCTL_SEND_COMMAND 1
+#define SCSI_IOCTL_TEST_UNIT_READY 2
+#define SCSI_IOCTL_BENCHMARK_COMMAND 3
+#define SCSI_IOCTL_SYNC 4                      /* Request synchronous parameters */
+/* The door lock/unlock constants are compatible with Sun constants for
+   the cdrom */
+#define SCSI_IOCTL_DOORLOCK 0x5380             /* lock the eject mechanism */
+#define SCSI_IOCTL_DOORUNLOCK 0x5381           /* unlock the mechanism   */
+
+#define        SCSI_REMOVAL_PREVENT    1
+#define        SCSI_REMOVAL_ALLOW      0
+
+extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
+extern int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
+
+#endif
+
+
diff --git a/include/scsi/scsicam.h b/include/scsi/scsicam.h
new file mode 100644 (file)
index 0000000..954e140
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * scsicam.h - SCSI CAM support functions, use for HDIO_GETGEO, etc.
+ *
+ * Copyright 1993, 1994 Drew Eckhardt
+ *      Visionary Computing 
+ *      (Unix and Linux consulting and custom programming)
+ *      drew@Colorado.EDU
+ *     +1 (303) 786-7975
+ *
+ * For more information, please consult the SCSI-CAM draft.
+ */
+
+#ifndef SCSICAM_H
+#define SCSICAM_H
+#include <linux/kdev_t.h>
+extern int scsicam_bios_param (Disk *disk, kdev_t dev, int *ip);
+#endif /* def SCSICAM_H */
diff --git a/include/scsi/sg.h b/include/scsi/sg.h
new file mode 100644 (file)
index 0000000..ff6cfbe
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+   History:
+    Started: Aug 9 by Lawrence Foard (entropy@world.std.com), to allow user 
+     process control of SCSI devices.
+    Development Sponsored by Killy Corp. NY NY
+*/
+
+#ifndef _SCSI_GENERIC_H
+#define _SCSI_GENERIC_H
+
+/* 
+ An SG device is accessed by writing "packets" to it, the replies
+ are then read using the read call. The same header is used for 
+ reply, just ignore reply_len field.
+*/
+
+struct sg_header
+ {
+  int pack_len;    /* length of incoming packet <4096 (including header) */
+  int reply_len;   /* maximum length <4096 of expected reply */
+  int pack_id;     /* id number of packet */
+  int result;      /* 0==ok, otherwise refer to errno codes */
+  unsigned int twelve_byte:1; /* Force 12 byte command length for group 6 & 7 commands  */
+  unsigned int other_flags:31;                 /* for future use */
+  unsigned char sense_buffer[16]; /* used only by reads */
+  /* command follows then data for command */
+ };
+
+/* ioctl's */
+#define SG_SET_TIMEOUT 0x2201  /* set timeout *(int *)arg==timeout */
+#define SG_GET_TIMEOUT 0x2202  /* get timeout return timeout */
+
+#define SG_DEFAULT_TIMEOUT (60*HZ) /* 1 minute timeout */
+#define SG_DEFAULT_RETRIES 1
+
+#define SG_MAX_QUEUE 4 /* maximum outstanding request, arbitrary, may be
+                         changed if sufficient DMA buffer room available */
+
+#define SG_BIG_BUFF 32768
+
+#endif
index 756a5e4773100626e4b7f30b076bf3f7d9e2e61a..987eed9716645320de5505dea2689f159880b649 100644 (file)
@@ -4,6 +4,7 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -22,6 +23,9 @@
 #include <linux/fcntl.h>
 #include <linux/acct.h>
 #include <linux/tty.h>
+#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF)
+#include <linux/apm_bios.h>
+#endif
 
 #include <asm/segment.h>
 #include <asm/io.h>
@@ -193,6 +197,9 @@ asmlinkage int sys_reboot(int magic, int magic_too, int flag)
        else if (flag == 0xCDEF0123) {
                printk(KERN_EMERG "System halted\n");
                sys_kill(-1, SIGKILL);
+#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF)
+               apm_set_power_state(APM_STATE_OFF);
+#endif
                do_exit(0);
        } else
                return -EINVAL;
index 0bebb3c5ac796bf0d009234a14ea3184c97e2de2..f46751270a0769a0e7010ff5a695e2efe8b06012 100644 (file)
@@ -422,7 +422,7 @@ static void profile_readahead(int async, struct file *filp)
  * - The number of effective pending IO read requests.
  *   ONE seems to be the only reasonable value.
  * - The total memory pool usage for the file access stream.
- *   This maximum memory usage is implicitely 2 IO read chunks:
+ *   This maximum memory usage is implicitly 2 IO read chunks:
  *   2*(MAX_READAHEAD + PAGE_SIZE) = 156K if CONFIG_READA_SMALL is undefined,
  *   64k if defined.
  */
index fceccde8eb304a46f8bf91c52a812c5eb67559e5..bc6e936e20107bf772173c5ceac371e7ed26a5b9 100644 (file)
@@ -20,8 +20,10 @@ if [ "$CONFIG_AX25" = "y" ]; then
   bool 'AX.25 over Ethernet' CONFIG_BPQETHER
   bool 'Amateur Radio NET/ROM' CONFIG_NETROM
 fi
-bool 'Bridging (test)' CONFIG_BRIDGE
-bool 'Kernel/User network link driver(ALPHA)' CONFIG_NETLINK
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  bool 'Bridging (EXPERIMENTAL)' CONFIG_BRIDGE
+fi
+bool 'Kernel/User network link driver' CONFIG_NETLINK
 if [ "$CONFIG_NETLINK" = "y" ]; then
   bool 'Routing messages' CONFIG_RTNETLINK
 fi
index fd0f7cfa4bbff8baacf8bbe880020b032897341b..396c62c1e8d7276710336fa22b1d0b71c41a6665 100644 (file)
@@ -405,6 +405,9 @@ void dama_enquiry_response(ax25_cb *ax25)
        /* gives better performance on FLEXNET nodes. (Why, Gunter?)      */
 
        for (ax25o = ax25_list; ax25o != NULL; ax25o = ax25o->next) {
+               if (ax25o == ax25)
+                       continue;
+
                if (ax25o->device != ax25->device)
                        continue;
 
index c4d69d8708513ce6e1feca24a1a9d61c0500103e..e0f49ce71477609a5ccb72cdf49b91640ab04a86 100644 (file)
@@ -488,7 +488,7 @@ static struct ax25_route * ax25_find_route(ax25_address *addr)
        
        /*
         *      Bind to the physical interface we heard them on, or the default
-        *      route if non is found;
+        *      route if none is found;
         */
        for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
                if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev != NULL)
index 7ada1a7b4447d9d8888fdd7c9894cc0fa2ae3155..d068ec47afe5bbec133819b7c3e9f70073a346a1 100644 (file)
@@ -549,7 +549,7 @@ void dev_transmit(void)
 
 /*
  *     When we are called the queue is ready to grab, the interrupts are
- *     on and hardware can interrupt and queue to the receive queue a we
+ *     on and hardware can interrupt and queue to the receive queue as we
  *     run with no problems.
  *     This is run as a bottom half after an interrupt handler that does
  *     mark_bh(NET_BH);
index 5ada6f5c1bd4fac912754046dde2ff633f2a2a99..7c88999a2502d12fd8dcd0ad72b16a52f8f9a2c1 100644 (file)
@@ -15,15 +15,17 @@ if [ "$CONFIG_IP_FORWARD" = "y" ]; then
     bool 'IP: masquerading (ALPHA)' CONFIG_IP_MASQUERADE
   fi
   if [ "$CONFIG_IP_MULTICAST" = "y" ]; then
-    bool 'IP: multicast routing(in progress)' CONFIG_IP_MROUTE
+    bool 'IP: multicast routing (EXPERIMENTAL)' CONFIG_IP_MROUTE
   fi
 fi
 if [ "$CONFIG_NET_ALIAS" = "y" ]; then
        tristate 'IP: aliasing support' CONFIG_IP_ALIAS
 fi
-#if [ "$CONFIG_KERNELD" = "y" ]; then
-#      bool 'IP: ARP daemon support (experimental)' CONFIG_ARPD
-#fi
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  if [ "$CONFIG_KERNELD" = "y" ]; then
+    bool 'IP: ARP daemon support (EXPERIMENTAL)' CONFIG_ARPD
+  fi
+fi
 comment '(it is safe to leave these untouched)'
 bool 'IP: PC/TCP compatibility mode' CONFIG_INET_PCTCP
 tristate 'IP: Reverse ARP' CONFIG_INET_RARP
index 7f11c19f30b2a61348f02aaa02c6986bf8389b0a..007c70ff1a6f13747064fdafeefd5405eacdf28f 100644 (file)
@@ -417,8 +417,11 @@ void destroy_sock(struct sock *sk)
        {
                /* this should never happen. */
                /* actually it can if an ack has just been sent. */
-               printk("Socket destroy delayed (r=%d w=%d)\n",
-                       sk->rmem_alloc, sk->wmem_alloc);
+               /*
+                *      Make this a NETDEBUG at 2.0pre
+                */
+               /*NETDEBUG(*/printk("Socket destroy delayed (r=%d w=%d)\n",
+                       sk->rmem_alloc, sk->wmem_alloc)/*)*/;
                sk->destroy = 1;
                sk->ack_backlog = 0;
                release_sock(sk);
index 713d141fd36f42fcfcdabe7b4d8fda233cef9397..0fcb357304a14cc45b30dbfed17478bd81f20027 100644 (file)
@@ -10,7 +10,7 @@
  * Fixes:
  *             Many            :       Split from ip.c , see ip.c for history.
  *             Martin Mares    :       TOS setting fixed.
- *             Alan Cox        :       Fixed a couple of oopses in Martins 
+ *             Alan Cox        :       Fixed a couple of oopses in Martin'
  *                                     TOS tweaks.
  */
 
index 543701c4ed9761cc70b4cfa02d82abdfe562c4eb..cfcf67f16a30801840bdf36e8817b38dbf30722d 100644 (file)
@@ -222,6 +222,7 @@ function extract_help () {
                         /^$var[        ]*\$/d
                         /^#.*/d
                        /^[     ]*\$/q
+                        s/^  //
                         p
                     }" Documentation/Configure.help)