From aa66269c3825870b281f07ea83485458d1d8696f Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:10:56 -0500 Subject: [PATCH] Import 1.3.98 --- Documentation/Configure.help | 97 +- Documentation/locks.txt | 56 + Documentation/networking/ncsa-telnet | 16 + Documentation/oops-tracing.txt | 72 + Documentation/ramdisk.txt | 2 +- Documentation/rtc.txt | 10 +- MAINTAINERS | 4 +- Makefile | 2 +- arch/alpha/config.in | 5 + arch/alpha/defconfig | 24 +- arch/alpha/kernel/ptrace.c | 2 + arch/i386/config.in | 5 + arch/i386/defconfig | 23 +- arch/i386/kernel/ptrace.c | 2 + arch/i386/kernel/time.c | 8 +- arch/sparc/kernel/ptrace.c | 2 +- drivers/block/README.fd | 6 +- drivers/block/README.ide | 1 + drivers/block/cmd640.c | 2 +- drivers/block/dtc2278.c | 1 + drivers/block/floppy.c | 10 +- drivers/block/ide-cd.c | 13 +- drivers/block/ide-tape.c | 3 +- drivers/block/ide-tape.h | 4 +- drivers/block/ide.c | 54 +- drivers/block/ide.h | 2 + drivers/block/qd6580.c | 4 + drivers/cdrom/aztcd.c | 2558 ++++++++++++------------ drivers/char/ChangeLog | 31 + drivers/char/Config.in | 3 +- drivers/char/apm_bios.c | 68 +- drivers/char/lp.c | 22 +- drivers/char/random.c | 407 +++- drivers/char/rtc.c | 175 +- drivers/char/serial.c | 2 +- drivers/net/Config.in | 176 +- drivers/net/new_tunnel.c | 2 +- drivers/sbus/char/sunkbd.c | 2 +- drivers/sbus/char/sunserial.c | 12 +- drivers/scsi/53c7,8xx.h | 2 +- drivers/scsi/AM53C974.h | 2 +- drivers/scsi/README.st | 55 +- drivers/scsi/aha152x.c | 33 +- drivers/scsi/aha152x.h | 4 +- drivers/scsi/aic7xxx.c | 35 +- drivers/scsi/eata.h | 2 +- drivers/scsi/eata_dma.c | 131 +- drivers/scsi/eata_dma.h | 2 +- drivers/scsi/eata_generic.h | 23 +- drivers/scsi/eata_pio.c | 91 +- drivers/scsi/eata_pio.h | 4 +- drivers/scsi/fdomain.c | 2 +- drivers/scsi/in2000.c | 10 +- drivers/scsi/in2000.readme | 6 +- drivers/scsi/scsi.c | 69 +- drivers/scsi/scsi.h | 2 +- drivers/scsi/scsi_ioctl.c | 2 +- drivers/scsi/scsi_syms.c | 2 +- drivers/scsi/sd.c | 2 +- drivers/scsi/sd_ioctl.c | 4 +- drivers/scsi/seagate.c | 2 +- drivers/scsi/sg.c | 4 +- drivers/scsi/sr.c | 2 +- drivers/scsi/sr_ioctl.c | 11 +- drivers/scsi/st.c | 862 +++++--- drivers/scsi/st.h | 20 +- drivers/scsi/wd33c93.c | 4 +- fs/Config.in | 2 +- fs/buffer.c | 54 +- fs/ext2/ialloc.c | 67 +- fs/ext2/inode.c | 78 +- fs/ext2/super.c | 100 +- fs/fcntl.c | 2 +- fs/locks.c | 121 +- fs/nfs/nfsroot.c | 4 + fs/pipe.c | 2 +- fs/proc/array.c | 3 + fs/proc/mem.c | 56 +- fs/proc/root.c | 4 + include/asm-alpha/fcntl.h | 1 + include/asm-i386/checksum.h | 68 +- include/asm-i386/fcntl.h | 1 + include/asm-m68k/fcntl.h | 1 + include/asm-mips/fcntl.h | 1 + include/asm-ppc/fcntl.h | 1 + include/asm-sparc/fcntl.h | 1 + include/linux/apm_bios.h | 3 + include/linux/bios32.h | 10 +- include/linux/ext2_fs.h | 50 +- include/linux/ext2_fs_i.h | 1 + include/linux/ext2_fs_sb.h | 3 +- include/linux/kernel.h | 6 + include/linux/mtio.h | 5 +- include/linux/proc_fs.h | 3 +- include/linux/random.h | 15 + include/linux/timex.h | 2 +- include/net/route.h | 3 +- include/{linux => scsi}/scsi.h | 0 {drivers => include}/scsi/scsi_ioctl.h | 0 include/{linux => scsi}/scsicam.h | 0 {drivers => include}/scsi/sg.h | 5 + kernel/sys.c | 7 + mm/filemap.c | 2 +- net/Config.in | 6 +- net/ax25/ax25_out.c | 3 + net/ax25/ax25_route.c | 2 +- net/core/dev.c | 2 +- net/ipv4/Config.in | 10 +- net/ipv4/af_inet.c | 7 +- net/ipv4/ip_sockglue.c | 2 +- scripts/Menuconfig | 1 + 111 files changed, 3707 insertions(+), 2284 deletions(-) create mode 100644 Documentation/locks.txt create mode 100644 Documentation/networking/ncsa-telnet create mode 100644 Documentation/oops-tracing.txt rename include/{linux => scsi}/scsi.h (100%) rename {drivers => include}/scsi/scsi_ioctl.h (100%) rename include/{linux => scsi}/scsicam.h (100%) rename {drivers => include}/scsi/sg.h (95%) diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 9dce6c1811eb..a984a50baebb 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -31,6 +31,24 @@ # 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=,,, - 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 index 000000000000..ab136d44491d --- /dev/null +++ b/Documentation/locks.txt @@ -0,0 +1,56 @@ + File Locking Release Notes + + Andy Walker + + 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 index 000000000000..d77d28b09093 --- /dev/null +++ b/Documentation/networking/ncsa-telnet @@ -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 + +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 index 000000000000..5d8a42f20d76 --- /dev/null +++ b/Documentation/oops-tracing.txt @@ -0,0 +1,72 @@ +From: Linus Torvalds + +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 + +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 + diff --git a/Documentation/ramdisk.txt b/Documentation/ramdisk.txt index 05a42ee9fa0a..881b671fdf39 100644 --- a/Documentation/ramdisk.txt +++ b/Documentation/ramdisk.txt @@ -36,7 +36,7 @@ uses minor #1, so start with ram2 and go from there. The old "ramdisk=" has been changed to "ramdisk_size=" to make it clearer. The original "ramdisk=" 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 diff --git a/Documentation/rtc.txt b/Documentation/rtc.txt index 9eeb4258d559..ba9362faedfb 100644 --- a/Documentation/rtc.txt +++ b/Documentation/rtc.txt @@ -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 diff --git a/MAINTAINERS b/MAINTAINERS index feb4014654df..1b18d7655b48 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -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 diff --git a/Makefile b/Makefile index 03337a4950d5..614339fb9e28 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 3 -SUBLEVEL = 97 +SUBLEVEL = 98 ARCH = i386 diff --git a/arch/alpha/config.in b/arch/alpha/config.in index 487ee1a3aa28..7bc03bf6efd7 100644 --- a/arch/alpha/config.in +++ b/arch/alpha/config.in @@ -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 diff --git a/arch/alpha/defconfig b/arch/alpha/defconfig index 26031b05ab87..a1069c8b724a 100644 --- a/arch/alpha/defconfig +++ b/arch/alpha/defconfig @@ -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 diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c index d5e36e316291..d4dbdeb66962 100644 --- a/arch/alpha/kernel/ptrace.c +++ b/arch/alpha/kernel/ptrace.c @@ -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 */ diff --git a/arch/i386/config.in b/arch/i386/config.in index d1f8672b8741..8d04799902f2 100644 --- a/arch/i386/config.in +++ b/arch/i386/config.in @@ -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 diff --git a/arch/i386/defconfig b/arch/i386/defconfig index bc4b04906fd7..b92b21ff09c7 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -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 diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c index ce4fdf3affad..3f901264c388 100644 --- a/arch/i386/kernel/ptrace.c +++ b/arch/i386/kernel/ptrace.c @@ -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 */ diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index e9e1215ae18d..b80c2c8d029e 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c @@ -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 diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c index ceb464aafa74..e2be0e34ad95 100644 --- a/arch/sparc/kernel/ptrace.c +++ b/arch/sparc/kernel/ptrace.c @@ -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 diff --git a/drivers/block/README.fd b/drivers/block/README.fd index 028ed5974715..11e1455b6e0c 100644 --- a/drivers/block/README.fd +++ b/drivers/block/README.fd @@ -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. diff --git a/drivers/block/README.ide b/drivers/block/README.ide index 9f4ddbe6278a..781258153d95 100644 --- a/drivers/block/README.ide +++ b/drivers/block/README.ide @@ -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 diff --git a/drivers/block/cmd640.c b/drivers/block/cmd640.c index 050a92d501c8..5647f0575b7e 100644 --- a/drivers/block/cmd640.c +++ b/drivers/block/cmd640.c @@ -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; diff --git a/drivers/block/dtc2278.c b/drivers/block/dtc2278.c index 31bed884db34..489a99c55935 100644 --- a/drivers/block/dtc2278.c +++ b/drivers/block/dtc2278.c @@ -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 * * There may be a fourth controller type. The S and D versions use the * Winbond chip, and I think the E version does also. diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 146c1e272897..0fd8d2a04fdb 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -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(); diff --git a/drivers/block/ide-cd.c b/drivers/block/ide-cd.c index 10ab19815d76..db6fa33ef129 100644 --- a/drivers/block/ide-cd.c +++ b/drivers/block/ide-cd.c @@ -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 + * 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; diff --git a/drivers/block/ide-tape.c b/drivers/block/ide-tape.c index 5f4e64e572b3..3083a9dbd8e0 100644 --- a/drivers/block/ide-tape.c +++ b/drivers/block/ide-tape.c @@ -1,7 +1,7 @@ /* * linux/drivers/block/ide-tape.c Version 1.5 - ALPHA Apr 12, 1996 * - * Copyright (C) 1995, 1996 Gadi Oxman + * Copyright (C) 1995, 1996 Gadi Oxman * * 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); diff --git a/drivers/block/ide-tape.h b/drivers/block/ide-tape.h index ee71f66a088a..ff9cbf5ed19d 100644 --- a/drivers/block/ide-tape.h +++ b/drivers/block/ide-tape.h @@ -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 + * Copyright (C) 1995, 1996 Gadi Oxman */ /* diff --git a/drivers/block/ide.c b/drivers/block/ide.c index c4a3ea6fee73..84bed2ee7504 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -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) */ @@ -227,6 +227,10 @@ * 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; } } } diff --git a/drivers/block/ide.h b/drivers/block/ide.h index 4a664e7f39f1..5241b7a8e4c3 100644 --- a/drivers/block/ide.h +++ b/drivers/block/ide.h @@ -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 */ diff --git a/drivers/block/qd6580.c b/drivers/block/qd6580.c index d11e9d96cd9d..4a928d1af468 100644 --- a/drivers/block/qd6580.c +++ b/drivers/block/qd6580.c @@ -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; } diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c index b3bdeb08b27d..9c25513672f8 100644 --- a/drivers/cdrom/aztcd.c +++ b/drivers/cdrom/aztcd.c @@ -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) @@ -148,7 +148,9 @@ 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 #include @@ -171,6 +173,10 @@ #include #include +/*########################################################################### + Defines + ########################################################################### +*/ #define SET_TIMER(func, jifs) delay_timer.expires = jiffies + (jifs); \ delay_timer.function = (void *) (func); \ add_timer(&delay_timer); @@ -189,7 +195,6 @@ 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(¬Used)) 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(¬Used) < 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> 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)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 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(¬Used)) 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(¬Used) < 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 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)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 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); +} + + diff --git a/drivers/char/ChangeLog b/drivers/char/ChangeLog index 4a5e82bd0141..d517ac47cd04 100644 --- a/drivers/char/ChangeLog +++ b/drivers/char/ChangeLog @@ -1,3 +1,34 @@ +Wed Apr 24 14:02:04 1996 Theodore Ts'o + + * 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 * tty_io.c (init_dev): Change return code when user attempts to diff --git a/drivers/char/Config.in b/drivers/char/Config.in index c0256442c929..4a1f1d50535e 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -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 diff --git a/drivers/char/apm_bios.c b/drivers/char/apm_bios.c index 2e3b58207b78..4864f77fab08 100644 --- a/drivers/char/apm_bios.c +++ b/drivers/char/apm_bios.c @@ -24,15 +24,17 @@ * Prohibit APM BIOS calls unless apm_enabled. * (Thanks to Ulrich Windl ) * 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; diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 1c4742fdd477..deb7c3544c01 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -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(); diff --git a/drivers/char/random.c b/drivers/char/random.c index cb7996de9cae..262d3201fab7 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -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 @@ -148,6 +148,58 @@ * 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: * ================= * @@ -158,6 +210,8 @@ * 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. @@ -173,6 +227,7 @@ */ #include +#include #include #include #include @@ -184,6 +239,10 @@ #include #include +/* + * 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. @@ -207,6 +266,20 @@ #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; } diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index fb3fb6ef001a..5e18b961aa3c 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -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< 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< 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<= 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<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; } diff --git a/drivers/sbus/char/sunkbd.c b/drivers/sbus/char/sunkbd.c index 890b45a8e66b..d52a3b574a00 100644 --- a/drivers/sbus/char/sunkbd.c +++ b/drivers/sbus/char/sunkbd.c @@ -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; } diff --git a/drivers/sbus/char/sunserial.c b/drivers/sbus/char/sunserial.c index 6f5d9fc3948d..c4c7797b3be0 100644 --- a/drivers/sbus/char/sunserial.c +++ b/drivers/sbus/char/sunserial.c @@ -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) { diff --git a/drivers/scsi/53c7,8xx.h b/drivers/scsi/53c7,8xx.h index 44a504900a49..3380a0ea7f44 100644 --- a/drivers/scsi/53c7,8xx.h +++ b/drivers/scsi/53c7,8xx.h @@ -54,7 +54,7 @@ */ #if defined(HOSTS_C) || defined(MODULE) -#include +#include extern int NCR53c7xx_abort(Scsi_Cmnd *); extern int NCR53c7xx_detect(Scsi_Host_Template *tpnt); diff --git a/drivers/scsi/AM53C974.h b/drivers/scsi/AM53C974.h index 67f2ecd4755a..8481e5e06468 100644 --- a/drivers/scsi/AM53C974.h +++ b/drivers/scsi/AM53C974.h @@ -27,7 +27,7 @@ #ifndef AM53C974_H #define AM53C974_H -#include +#include /*************************************************************************************** * Default setting of the controller's SCSI id. Edit and uncomment this only if your * diff --git a/drivers/scsi/README.st b/drivers/scsi/README.st index 67793cf3d190..71b41a1799fe 100644 --- a/drivers/scsi/README.st +++ b/drivers/scsi/README.st @@ -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 diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index 1cdad2c0dd3f..bdd3f9285fab 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -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 @@ -20,9 +20,13 @@ * 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) diff --git a/drivers/scsi/aha152x.h b/drivers/scsi/aha152x.h index 0b2bb3bdb638..46c384adf886 100644 --- a/drivers/scsi/aha152x.h +++ b/drivers/scsi/aha152x.h @@ -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; diff --git a/drivers/scsi/aic7xxx.c b/drivers/scsi/aic7xxx.c index 0ad5eea77833..fc0702b624f5 100644 --- a/drivers/scsi/aic7xxx.c +++ b/drivers/scsi/aic7xxx.c @@ -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"); diff --git a/drivers/scsi/eata.h b/drivers/scsi/eata.h index b2d727133c07..139a88ec0015 100644 --- a/drivers/scsi/eata.h +++ b/drivers/scsi/eata.h @@ -4,7 +4,7 @@ #ifndef _EATA_H #define _EATA_H -#include +#include int eata2x_detect(Scsi_Host_Template *); int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); diff --git a/drivers/scsi/eata_dma.c b/drivers/scsi/eata_dma.c index efb5565e1ca8..43e75f949fb1 100644 --- a/drivers/scsi/eata_dma.c +++ b/drivers/scsi/eata_dma.c @@ -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 #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; diff --git a/drivers/scsi/eata_dma.h b/drivers/scsi/eata_dma.h index 41504673a5dd..7aec03e5bb45 100644 --- a/drivers/scsi/eata_dma.h +++ b/drivers/scsi/eata_dma.h @@ -73,7 +73,7 @@ int eata_release(struct Scsi_Host *); #define eata_release NULL #endif -#include +#include #define EATA_DMA { \ NULL, NULL, \ diff --git a/drivers/scsi/eata_generic.h b/drivers/scsi/eata_generic.h index 4d9fc497496a..b68e329b4842 100644 --- a/drivers/scsi/eata_generic.h +++ b/drivers/scsi/eata_generic.h @@ -64,22 +64,12 @@ #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 */ diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c index e48b3b06b17b..e6740c098154 100644 --- a/drivers/scsi/eata_pio.c +++ b/drivers/scsi/eata_pio.c @@ -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; diff --git a/drivers/scsi/eata_pio.h b/drivers/scsi/eata_pio.h index 8a626e0be548..3c25bf51e497 100644 --- a/drivers/scsi/eata_pio.h +++ b/drivers/scsi/eata_pio.h @@ -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 #include "scsi.h" #include "hosts.h" -#include +#include #ifndef HOSTS_C #include "eata_generic.h" diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index b863bf2e88f0..03585b00ca51 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -1913,7 +1913,7 @@ int fdomain_16x0_reset( Scsi_Cmnd *SCpnt ) } #include "sd.h" -#include "scsi_ioctl.h" +#include int fdomain_16x0_biosparam( Scsi_Disk *disk, kdev_t dev, int *info_array ) { diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c index c9c2a5f6f6d5..c7b1f47d9a22 100644 --- a/drivers/scsi/in2000.c +++ b/drivers/scsi/in2000.c @@ -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. */ diff --git a/drivers/scsi/in2000.readme b/drivers/scsi/in2000.readme index 89ba63ff5f44..6280b039035a 100644 --- a/drivers/scsi/in2000.readme +++ b/drivers/scsi/in2000.readme @@ -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 diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 57bc3fc500a4..4bf48ec78a18 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -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... */ diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h index e65bfcd1475d..b6acbd57aa88 100644 --- a/drivers/scsi/scsi.h +++ b/drivers/scsi/scsi.h @@ -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 +#include /* diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 15c981ba2af6..e3453d1e9ddb 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -19,7 +19,7 @@ #include #include "scsi.h" #include "hosts.h" -#include "scsi_ioctl.h" +#include #define MAX_RETRIES 5 #define MAX_TIMEOUT 900 diff --git a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c index deab5c75a604..a9d14f3b2aae 100644 --- a/drivers/scsi/scsi_syms.c +++ b/drivers/scsi/scsi_syms.c @@ -21,7 +21,7 @@ #include #include "scsi.h" -#include "scsi_ioctl.h" +#include #include "hosts.h" #include "constants.h" diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 9a446d3bde84..be690c0392d5 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -41,7 +41,7 @@ #include "scsi.h" #include "hosts.h" #include "sd.h" -#include "scsi_ioctl.h" +#include #include "constants.h" #include diff --git a/drivers/scsi/sd_ioctl.c b/drivers/scsi/sd_ioctl.c index 96ce7dda9061..bff43d9fdfeb 100644 --- a/drivers/scsi/sd_ioctl.c +++ b/drivers/scsi/sd_ioctl.c @@ -15,10 +15,10 @@ #include #include "scsi.h" -#include "scsi_ioctl.h" +#include #include "hosts.h" #include "sd.h" -#include /* must follow "hosts.h" */ +#include /* must follow "hosts.h" */ int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) { diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c index 91d68fc1c13e..88aa97986e3b 100644 --- a/drivers/scsi/seagate.c +++ b/drivers/scsi/seagate.c @@ -1632,7 +1632,7 @@ int seagate_st0x_reset (Scsi_Cmnd * SCpnt) #include #include "sd.h" -#include "scsi_ioctl.h" +#include int seagate_st0x_biosparam(Disk * disk, kdev_t dev, int* ip) { unsigned char buf[256 + sizeof(int) * 2], cmd[6], *data, *page; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index a55e30b2e6db..bb1ff5bb3f8b 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -24,8 +24,8 @@ #include #include "scsi.h" #include "hosts.h" -#include "scsi_ioctl.h" -#include "sg.h" +#include +#include static int sg_init(void); static int sg_attach(Scsi_Device *); diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index f7a9ea83d0ee..783d9ba4e9d9 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -35,7 +35,7 @@ #include "scsi.h" #include "hosts.h" #include "sr.h" -#include "scsi_ioctl.h" /* For the door lock/unlock commands */ +#include /* For the door lock/unlock commands */ #include "constants.h" #define MAX_RETRIES 3 diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index 6106fc9343a1..26d2b36e729d 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -10,7 +10,7 @@ #include "scsi.h" #include "hosts.h" #include "sr.h" -#include "scsi_ioctl.h" +#include #include @@ -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); } diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index e6e51c610405..b0aa76a1448d 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -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 #include "scsi.h" #include "hosts.h" -#include "scsi_ioctl.h" +#include #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) } + /* 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; +} + /* 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) /* 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, } + /* 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); +} + + /* 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; +} + + /* 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); } @@ -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); diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h index 545bbdb747ee..dd1158a1ebe0 100644 --- a/drivers/scsi/st.h +++ b/drivers/scsi/st.h @@ -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; diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c index c0cafa5a88e0..fa43592c8744 100644 --- a/drivers/scsi/wd33c93.c +++ b/drivers/scsi/wd33c93.c @@ -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 @@ -121,7 +121,7 @@ * - 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. diff --git a/fs/Config.in b/fs/Config.in index 0447a9c5da44..be203265ba29 100644 --- a/fs/Config.in +++ b/fs/Config.in @@ -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 diff --git a/fs/buffer.c b/fs/buffer.c index bd2c299a6c6d..c75c5ae1c4ff 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -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 *)); diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c index cb0a486f13ca..35435d4adb7d 100644 --- a/fs/ext2/ialloc.c +++ b/fs/ext2/ialloc.c @@ -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); diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 0838d2431ad0..6d36f11c1b46 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -27,12 +27,17 @@ #include #include +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); +} + diff --git a/fs/ext2/super.c b/fs/ext2/super.c index bb755710d6e9..3bf8b567119e 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -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; diff --git a/fs/fcntl.c b/fs/fcntl.c index 6f19c71fd5b5..ee7daeeea464 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -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; diff --git a/fs/locks.c b/fs/locks.c index d73d26bd1b74..5d7ecc4659f2 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -69,8 +69,12 @@ * 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 @@ -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); +} + diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index 0cc6e5ea109d..1c81c2341003 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -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')) { diff --git a/fs/pipe.c b/fs/pipe.c index 2b88747f4569..b5af9973e97e 100644 --- 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; diff --git a/fs/proc/array.c b/fs/proc/array.c index f63ab6af239c..3a1c426ebc87 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -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; } diff --git a/fs/proc/mem.c b/fs/proc/mem.c index 8e3969ca798b..e3c8482e7867 100644 --- a/fs/proc/mem.c +++ b/fs/proc/mem.c @@ -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 diff --git a/fs/proc/root.c b/fs/proc/root.c index 267222e31bad..962f428a0a16 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -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, } ); diff --git a/include/asm-alpha/fcntl.h b/include/asm-alpha/fcntl.h index 09ed06ecf94d..cb0e3af0f395 100644 --- a/include/asm-alpha/fcntl.h +++ b/include/asm-alpha/fcntl.h @@ -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 { diff --git a/include/asm-i386/checksum.h b/include/asm-i386/checksum.h index cecc05c39bf2..cbc2615d0e07 100644 --- a/include/asm-i386/checksum.h +++ b/include/asm-i386/checksum.h @@ -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 diff --git a/include/asm-i386/fcntl.h b/include/asm-i386/fcntl.h index 0cb8fcdba96b..8db6b6070c0b 100644 --- a/include/asm-i386/fcntl.h +++ b/include/asm-i386/fcntl.h @@ -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 { diff --git a/include/asm-m68k/fcntl.h b/include/asm-m68k/fcntl.h index 07b1babaa7b7..fa40da33589d 100644 --- a/include/asm-m68k/fcntl.h +++ b/include/asm-m68k/fcntl.h @@ -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 { diff --git a/include/asm-mips/fcntl.h b/include/asm-mips/fcntl.h index a524af6d3af5..223967ae456e 100644 --- a/include/asm-mips/fcntl.h +++ b/include/asm-mips/fcntl.h @@ -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 { diff --git a/include/asm-ppc/fcntl.h b/include/asm-ppc/fcntl.h index 8c714d51f6f1..61d0fa703f74 100644 --- a/include/asm-ppc/fcntl.h +++ b/include/asm-ppc/fcntl.h @@ -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 { diff --git a/include/asm-sparc/fcntl.h b/include/asm-sparc/fcntl.h index 22ea2ae9ad86..de42f13046e8 100644 --- a/include/asm-sparc/fcntl.h +++ b/include/asm-sparc/fcntl.h @@ -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 { diff --git a/include/linux/apm_bios.h b/include/linux/apm_bios.h index 49edb1d136f5..326445110977 100644 --- a/include/linux/apm_bios.h +++ b/include/linux/apm_bios.h @@ -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); diff --git a/include/linux/bios32.h b/include/linux/bios32.h index f57398e53323..d3632092a6d5 100644 --- a/include/linux/bios32.h +++ b/include/linux/bios32.h @@ -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. diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h index 208cf46af363..896438e610f1 100644 --- a/include/linux/ext2_fs.h +++ b/include/linux/ext2_fs.h @@ -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 @@ -90,10 +92,17 @@ #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 diff --git a/include/linux/ext2_fs_i.h b/include/linux/ext2_fs_i.h index f3eca4480a1b..7df902135323 100644 --- a/include/linux/ext2_fs_i.h +++ b/include/linux/ext2_fs_i.h @@ -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 */ diff --git a/include/linux/ext2_fs_sb.h b/include/linux/ext2_fs_sb.h index 5a33f3c1c189..dd064b86a8aa 100644 --- a/include/linux/ext2_fs_sb.h +++ b/include/linux/ext2_fs_sb.h @@ -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 */ diff --git a/include/linux/kernel.h b/include/linux/kernel.h index e8fa91e6af76..e07049f6ad7a 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -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.. diff --git a/include/linux/mtio.h b/include/linux/mtio.h index 4b75bbe6c3d4..35fcfc4d120b 100644 --- a/include/linux/mtio.h +++ b/include/linux/mtio.h @@ -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 diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 9164d5553a94..d5a7688678ed 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -42,7 +42,8 @@ enum root_directory_inos { PROC_SYS, PROC_MTAB, PROC_MD, - PROC_RTC + PROC_RTC, + PROC_LOCKS }; enum pid_directory_inos { diff --git a/include/linux/random.h b/include/linux/random.h index 8fce34d59afc..00bc0183c44d 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -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/timex.h b/include/linux/timex.h index c532629e318d..9a0270bcdc55 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h @@ -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 */ diff --git a/include/net/route.h b/include/net/route.h index 77c79d5e77f3..b805f38bbb13 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -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/linux/scsi.h b/include/scsi/scsi.h similarity index 100% rename from include/linux/scsi.h rename to include/scsi/scsi.h diff --git a/drivers/scsi/scsi_ioctl.h b/include/scsi/scsi_ioctl.h similarity index 100% rename from drivers/scsi/scsi_ioctl.h rename to include/scsi/scsi_ioctl.h diff --git a/include/linux/scsicam.h b/include/scsi/scsicam.h similarity index 100% rename from include/linux/scsicam.h rename to include/scsi/scsicam.h diff --git a/drivers/scsi/sg.h b/include/scsi/sg.h similarity index 95% rename from drivers/scsi/sg.h rename to include/scsi/sg.h index dc7d94684faf..ff6cfbe93bdb 100644 --- a/drivers/scsi/sg.h +++ b/include/scsi/sg.h @@ -5,6 +5,9 @@ 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 @@ -34,3 +37,5 @@ struct sg_header changed if sufficient DMA buffer room available */ #define SG_BIG_BUFF 32768 + +#endif diff --git a/kernel/sys.c b/kernel/sys.c index 756a5e477310..987eed971664 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -4,6 +4,7 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ +#include #include #include #include @@ -22,6 +23,9 @@ #include #include #include +#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF) +#include +#endif #include #include @@ -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; diff --git a/mm/filemap.c b/mm/filemap.c index 0bebb3c5ac79..f46751270a07 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -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. */ diff --git a/net/Config.in b/net/Config.in index fceccde8eb30..bc6e936e2010 100644 --- a/net/Config.in +++ b/net/Config.in @@ -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 diff --git a/net/ax25/ax25_out.c b/net/ax25/ax25_out.c index fd0f7cfa4bbf..396c62c1e8d7 100644 --- a/net/ax25/ax25_out.c +++ b/net/ax25/ax25_out.c @@ -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; diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c index c4d69d870851..e0f49ce71477 100644 --- a/net/ax25/ax25_route.c +++ b/net/ax25/ax25_route.c @@ -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) diff --git a/net/core/dev.c b/net/core/dev.c index 7ada1a7b4447..d068ec47afe5 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -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); diff --git a/net/ipv4/Config.in b/net/ipv4/Config.in index 5ada6f5c1bd4..7c88999a2502 100644 --- a/net/ipv4/Config.in +++ b/net/ipv4/Config.in @@ -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 diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 7f11c19f30b2..007c70ff1a6f 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -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); diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 713d141fd36f..0fcb357304a1 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -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's * TOS tweaks. */ diff --git a/scripts/Menuconfig b/scripts/Menuconfig index 543701c4ed97..cfcf67f16a30 100644 --- a/scripts/Menuconfig +++ b/scripts/Menuconfig @@ -222,6 +222,7 @@ function extract_help () { /^$var[ ]*\$/d /^#.*/d /^[ ]*\$/q + s/^ // p }" Documentation/Configure.help) -- 2.39.5