diff -u --recursive --new-file v1.3.97/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v1.3.97/linux/Documentation/Configure.help Mon Apr 29 18:05:15 1996 +++ linux/Documentation/Configure.help Fri May 3 11:11:16 1996 @@ -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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ # 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 -u --recursive --new-file v1.3.97/linux/Documentation/locks.txt linux/Documentation/locks.txt --- v1.3.97/linux/Documentation/locks.txt Thu Jan 1 02:00:00 1970 +++ linux/Documentation/locks.txt Tue Apr 30 13:07:51 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/Documentation/networking/ncsa-telnet linux/Documentation/networking/ncsa-telnet --- v1.3.97/linux/Documentation/networking/ncsa-telnet Thu Jan 1 02:00:00 1970 +++ linux/Documentation/networking/ncsa-telnet Tue Apr 30 12:42:36 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/Documentation/oops-tracing.txt linux/Documentation/oops-tracing.txt --- v1.3.97/linux/Documentation/oops-tracing.txt Thu Jan 1 02:00:00 1970 +++ linux/Documentation/oops-tracing.txt Tue Apr 30 12:42:36 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/Documentation/ramdisk.txt linux/Documentation/ramdisk.txt --- v1.3.97/linux/Documentation/ramdisk.txt Sat Apr 27 15:19:44 1996 +++ linux/Documentation/ramdisk.txt Sat May 4 19:39:23 1996 @@ -36,7 +36,7 @@ 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 -u --recursive --new-file v1.3.97/linux/Documentation/rtc.txt linux/Documentation/rtc.txt --- v1.3.97/linux/Documentation/rtc.txt Mon Apr 15 12:20:16 1996 +++ linux/Documentation/rtc.txt Tue Apr 30 12:48:50 1996 @@ -45,7 +45,15 @@ 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 -u --recursive --new-file v1.3.97/linux/MAINTAINERS linux/MAINTAINERS --- v1.3.97/linux/MAINTAINERS Mon Apr 29 18:05:15 1996 +++ linux/MAINTAINERS Wed May 1 11:45:38 1996 @@ -65,8 +65,8 @@ 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 -u --recursive --new-file v1.3.97/linux/Makefile linux/Makefile --- v1.3.97/linux/Makefile Mon Apr 29 18:05:15 1996 +++ linux/Makefile Mon Apr 29 18:10:40 1996 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 3 -SUBLEVEL = 97 +SUBLEVEL = 98 ARCH = i386 diff -u --recursive --new-file v1.3.97/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v1.3.97/linux/arch/alpha/config.in Sun Apr 21 12:39:00 1996 +++ linux/arch/alpha/config.in Tue Apr 30 12:55:53 1996 @@ -10,6 +10,11 @@ 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 if [ "$CONFIG_MODULES" = "y" ]; then diff -u --recursive --new-file v1.3.97/linux/arch/alpha/defconfig linux/arch/alpha/defconfig --- v1.3.97/linux/arch/alpha/defconfig Wed Apr 24 17:00:33 1996 +++ linux/arch/alpha/defconfig Fri May 3 15:51:32 1996 @@ -3,6 +3,11 @@ # # +# Code maturity level options +# +# CONFIG_EXPERIMENTAL is not set + +# # Loadable module support # CONFIG_MODULES=y @@ -75,7 +80,6 @@ # 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_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 -u --recursive --new-file v1.3.97/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c --- v1.3.97/linux/arch/alpha/kernel/ptrace.c Wed Apr 3 16:06:55 1996 +++ linux/arch/alpha/kernel/ptrace.c Fri May 3 15:55:57 1996 @@ -510,8 +510,10 @@ 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 -u --recursive --new-file v1.3.97/linux/arch/i386/config.in linux/arch/i386/config.in --- v1.3.97/linux/arch/i386/config.in Mon Feb 26 11:58:03 1996 +++ linux/arch/i386/config.in Tue Apr 30 12:55:42 1996 @@ -5,6 +5,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 if [ "$CONFIG_MODULES" = "y" ]; then diff -u --recursive --new-file v1.3.97/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v1.3.97/linux/arch/i386/defconfig Wed Apr 24 17:00:34 1996 +++ linux/arch/i386/defconfig Tue Apr 30 13:50:47 1996 @@ -3,6 +3,11 @@ # # +# Code maturity level options +# +# CONFIG_EXPERIMENTAL is not set + +# # Loadable module support # CONFIG_MODULES=y @@ -74,7 +79,6 @@ # 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_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 -u --recursive --new-file v1.3.97/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c --- v1.3.97/linux/arch/i386/kernel/ptrace.c Wed Apr 3 16:06:55 1996 +++ linux/arch/i386/kernel/ptrace.c Thu May 2 16:11:56 1996 @@ -320,8 +320,10 @@ 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 -u --recursive --new-file v1.3.97/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c --- v1.3.97/linux/arch/i386/kernel/time.c Sun Mar 17 08:54:33 1996 +++ linux/arch/i386/kernel/time.c Fri May 3 12:00:45 1996 @@ -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 @@ 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 @@ xtime = *tv; time_state = TIME_BAD; - time_maxerror = 0x70000000; - time_esterror = 0x70000000; + time_maxerror = MAXPHASE; + time_esterror = MAXPHASE; sti(); } @@ -271,6 +273,7 @@ } +#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 @@ "=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 -u --recursive --new-file v1.3.97/linux/arch/sparc/kernel/ptrace.c linux/arch/sparc/kernel/ptrace.c --- v1.3.97/linux/arch/sparc/kernel/ptrace.c Sat Apr 27 15:19:48 1996 +++ linux/arch/sparc/kernel/ptrace.c Sat May 4 19:39:23 1996 @@ -340,7 +340,7 @@ 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 -u --recursive --new-file v1.3.97/linux/drivers/block/README.fd linux/drivers/block/README.fd --- v1.3.97/linux/drivers/block/README.fd Mon Apr 29 18:05:15 1996 +++ linux/drivers/block/README.fd Sat May 4 19:39:22 1996 @@ -99,7 +99,7 @@ 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 @@ 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 -u --recursive --new-file v1.3.97/linux/drivers/block/README.ide linux/drivers/block/README.ide --- v1.3.97/linux/drivers/block/README.ide Fri Apr 12 15:51:49 1996 +++ linux/drivers/block/README.ide Fri May 3 11:07:24 1996 @@ -210,6 +210,7 @@ "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 -u --recursive --new-file v1.3.97/linux/drivers/block/cmd640.c linux/drivers/block/cmd640.c --- v1.3.97/linux/drivers/block/cmd640.c Fri Apr 12 15:51:49 1996 +++ linux/drivers/block/cmd640.c Fri May 3 11:07:23 1996 @@ -110,7 +110,7 @@ /* 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 -u --recursive --new-file v1.3.97/linux/drivers/block/dtc2278.c linux/drivers/block/dtc2278.c --- v1.3.97/linux/drivers/block/dtc2278.c Sat Mar 16 13:52:13 1996 +++ linux/drivers/block/dtc2278.c Fri May 3 11:07:23 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v1.3.97/linux/drivers/block/floppy.c Mon Apr 29 18:05:16 1996 +++ linux/drivers/block/floppy.c Tue Apr 30 11:41:25 1996 @@ -1734,9 +1734,6 @@ #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) { printk("reset set in interrupt, calling %p\n", cont->error); @@ -4004,6 +4001,10 @@ 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 @@ 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 @@ { 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 -u --recursive --new-file v1.3.97/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c --- v1.3.97/linux/drivers/block/ide-cd.c Fri Apr 12 15:51:49 1996 +++ linux/drivers/block/ide-cd.c Wed May 1 13:29:14 1996 @@ -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 @@ 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 @@ 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 @@ 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 @@ 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 -u --recursive --new-file v1.3.97/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c --- v1.3.97/linux/drivers/block/ide-tape.c Wed Apr 24 17:00:36 1996 +++ linux/drivers/block/ide-tape.c Fri May 3 11:07:24 1996 @@ -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 @@ } #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 -u --recursive --new-file v1.3.97/linux/drivers/block/ide-tape.h linux/drivers/block/ide-tape.h --- v1.3.97/linux/drivers/block/ide-tape.h Fri Apr 12 15:51:50 1996 +++ linux/drivers/block/ide-tape.h Fri May 3 11:07:24 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v1.3.97/linux/drivers/block/ide.c Wed Apr 24 17:00:36 1996 +++ linux/drivers/block/ide.c Fri May 3 15:56:48 1996 @@ -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 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ * "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 @@ * 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 @@ } #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 @@ */ 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 -u --recursive --new-file v1.3.97/linux/drivers/block/ide.h linux/drivers/block/ide.h --- v1.3.97/linux/drivers/block/ide.h Fri Apr 12 15:51:50 1996 +++ linux/drivers/block/ide.h Fri May 3 16:19:49 1996 @@ -313,6 +313,7 @@ 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 @@ 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 -u --recursive --new-file v1.3.97/linux/drivers/block/qd6580.c linux/drivers/block/qd6580.c --- v1.3.97/linux/drivers/block/qd6580.c Mon Feb 12 07:04:03 1996 +++ linux/drivers/block/qd6580.c Fri May 3 11:07:24 1996 @@ -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 @@ void init_qd6580 (void) { ide_hwifs[0].chipset = ide_qd6580; + ide_hwifs[1].chipset = ide_qd6580; ide_hwifs[0].tuneproc = &tune_qd6580; } diff -u --recursive --new-file v1.3.97/linux/drivers/cdrom/aztcd.c linux/drivers/cdrom/aztcd.c --- v1.3.97/linux/drivers/cdrom/aztcd.c Mon Apr 29 18:05:17 1996 +++ linux/drivers/cdrom/aztcd.c Sat May 4 19:39:23 1996 @@ -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 @@ #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 @@ 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 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 @@ 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 @@ } -/* - * 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 @@ 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 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 @@ 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 -u --recursive --new-file v1.3.97/linux/drivers/char/ChangeLog linux/drivers/char/ChangeLog --- v1.3.97/linux/drivers/char/ChangeLog Wed Apr 24 17:00:37 1996 +++ linux/drivers/char/ChangeLog Sat May 4 10:02:51 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v1.3.97/linux/drivers/char/Config.in Tue Apr 23 13:57:09 1996 +++ linux/drivers/char/Config.in Thu May 2 08:06:31 1996 @@ -46,10 +46,11 @@ 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 -u --recursive --new-file v1.3.97/linux/drivers/char/apm_bios.c linux/drivers/char/apm_bios.c --- v1.3.97/linux/drivers/char/apm_bios.c Fri Apr 19 10:07:58 1996 +++ linux/drivers/char/apm_bios.c Thu May 2 08:06:31 1996 @@ -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 @@ * 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 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 @@ 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 @@ 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 @@ 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 @@ } } - queue_event(event); + queue_event(event, sender); } static void check_events(void) @@ -682,18 +689,19 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 -u --recursive --new-file v1.3.97/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v1.3.97/linux/drivers/char/lp.c Tue Apr 2 13:32:20 1996 +++ linux/drivers/char/lp.c Fri May 3 11:57:38 1996 @@ -183,14 +183,14 @@ 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 @@ 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 -u --recursive --new-file v1.3.97/linux/drivers/char/random.c linux/drivers/char/random.c --- v1.3.97/linux/drivers/char/random.c Fri Apr 12 15:51:52 1996 +++ linux/drivers/char/random.c Sat May 4 10:02:51 1996 @@ -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 @@ -185,6 +240,10 @@ #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. * For a pool of size 64, try x^64+x^62+x^38+x^10+x^6+x+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 @@ /* 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_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 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 @@ 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 @@ 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 @@ #undef F4 #undef MD5STEP +#endif + #if POOLWORDS % 16 #error extract_entropy() assumes that POOLWORDS is a multiple of 16 words. @@ -579,7 +843,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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,16 +1098,42 @@ 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 -u --recursive --new-file v1.3.97/linux/drivers/char/rtc.c linux/drivers/char/rtc.c --- v1.3.97/linux/drivers/char/rtc.c Tue Apr 23 13:57:09 1996 +++ linux/drivers/char/rtc.c Fri May 3 11:09:58 1996 @@ -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 @@ 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 @@ */ #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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ { 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 @@ * 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 @@ * 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, "**\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 -u --recursive --new-file v1.3.97/linux/drivers/sbus/char/sunkbd.c linux/drivers/sbus/char/sunkbd.c --- v1.3.97/linux/drivers/sbus/char/sunkbd.c Sat Apr 27 15:19:53 1996 +++ linux/drivers/sbus/char/sunkbd.c Sat May 4 19:39:23 1996 @@ -653,7 +653,7 @@ 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 -u --recursive --new-file v1.3.97/linux/drivers/sbus/char/sunserial.c linux/drivers/sbus/char/sunserial.c --- v1.3.97/linux/drivers/sbus/char/sunserial.c Sat Apr 27 15:19:56 1996 +++ linux/drivers/sbus/char/sunserial.c Sat May 4 19:39:23 1996 @@ -154,7 +154,8 @@ 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 @@ /* * 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 @@ 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 @@ * 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 -u --recursive --new-file v1.3.97/linux/drivers/scsi/53c7,8xx.h linux/drivers/scsi/53c7,8xx.h --- v1.3.97/linux/drivers/scsi/53c7,8xx.h Fri Apr 12 15:51:58 1996 +++ linux/drivers/scsi/53c7,8xx.h Thu May 2 07:48:53 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/drivers/scsi/AM53C974.h linux/drivers/scsi/AM53C974.h --- v1.3.97/linux/drivers/scsi/AM53C974.h Fri Apr 12 15:51:58 1996 +++ linux/drivers/scsi/AM53C974.h Thu May 2 07:48:53 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/drivers/scsi/README.st linux/drivers/scsi/README.st --- v1.3.97/linux/drivers/scsi/README.st Tue Apr 23 13:57:10 1996 +++ linux/drivers/scsi/README.st Fri May 3 10:12:17 1996 @@ -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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 -u --recursive --new-file v1.3.97/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c --- v1.3.97/linux/drivers/scsi/aha152x.c Fri Mar 1 07:50:51 1996 +++ linux/drivers/scsi/aha152x.c Thu May 2 07:27:10 1996 @@ -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_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); + printk("aha152x_biosparam: dev=%s, size=%d, ", + kdevname(dev), disk->capacity); #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; + 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 -u --recursive --new-file v1.3.97/linux/drivers/scsi/aha152x.h linux/drivers/scsi/aha152x.h --- v1.3.97/linux/drivers/scsi/aha152x.h Tue Jan 23 21:20:34 1996 +++ linux/drivers/scsi/aha152x.h Thu May 2 07:28:01 1996 @@ -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 @@ (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 -u --recursive --new-file v1.3.97/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c --- v1.3.97/linux/drivers/scsi/aic7xxx.c Sun Apr 21 19:22:11 1996 +++ linux/drivers/scsi/aic7xxx.c Thu May 2 08:13:50 1996 @@ -1686,6 +1686,9 @@ { 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_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 @@ * 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 @@ 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 @@ 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 @@ 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. */ @@ -3782,6 +3801,10 @@ outb(SCSIRSTO, SCSISEQ + base); 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); diff -u --recursive --new-file v1.3.97/linux/drivers/scsi/eata.h linux/drivers/scsi/eata.h --- v1.3.97/linux/drivers/scsi/eata.h Fri Apr 19 10:07:59 1996 +++ linux/drivers/scsi/eata.h Thu May 2 07:48:53 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/drivers/scsi/eata_dma.c linux/drivers/scsi/eata_dma.c --- v1.3.97/linux/drivers/scsi/eata_dma.c Fri Apr 12 15:52:00 1996 +++ linux/drivers/scsi/eata_dma.c Thu May 2 07:48:53 1996 @@ -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 @@ 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 @@ 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 @@ } } +/* 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 @@ * 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 @@ */ 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 -u --recursive --new-file v1.3.97/linux/drivers/scsi/eata_dma.h linux/drivers/scsi/eata_dma.h --- v1.3.97/linux/drivers/scsi/eata_dma.h Mon Dec 11 07:27:14 1995 +++ linux/drivers/scsi/eata_dma.h Thu May 2 07:48:53 1996 @@ -73,7 +73,7 @@ #define eata_release NULL #endif -#include +#include #define EATA_DMA { \ NULL, NULL, \ diff -u --recursive --new-file v1.3.97/linux/drivers/scsi/eata_generic.h linux/drivers/scsi/eata_generic.h --- v1.3.97/linux/drivers/scsi/eata_generic.h Mon Dec 11 07:27:14 1995 +++ linux/drivers/scsi/eata_generic.h Thu May 2 07:48:53 1996 @@ -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 SG_SIZE_BIG 252 /* max. 8096 elements, 64k */ -#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 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 @@ __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 -u --recursive --new-file v1.3.97/linux/drivers/scsi/eata_pio.c linux/drivers/scsi/eata_pio.c --- v1.3.97/linux/drivers/scsi/eata_pio.c Fri Apr 12 15:52:00 1996 +++ linux/drivers/scsi/eata_pio.c Thu May 2 07:48:53 1996 @@ -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 @@ 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 @@ #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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ { #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 -u --recursive --new-file v1.3.97/linux/drivers/scsi/eata_pio.h linux/drivers/scsi/eata_pio.h --- v1.3.97/linux/drivers/scsi/eata_pio.h Sat Nov 11 13:04:40 1995 +++ linux/drivers/scsi/eata_pio.h Thu May 2 07:48:53 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c --- v1.3.97/linux/drivers/scsi/fdomain.c Fri Apr 12 15:52:00 1996 +++ linux/drivers/scsi/fdomain.c Thu May 2 07:48:53 1996 @@ -1913,7 +1913,7 @@ } #include "sd.h" -#include "scsi_ioctl.h" +#include int fdomain_16x0_biosparam( Scsi_Disk *disk, kdev_t dev, int *info_array ) { diff -u --recursive --new-file v1.3.97/linux/drivers/scsi/in2000.c linux/drivers/scsi/in2000.c --- v1.3.97/linux/drivers/scsi/in2000.c Mon Apr 29 18:05:18 1996 +++ linux/drivers/scsi/in2000.c Sat May 4 19:39:23 1996 @@ -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 @@ 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_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 @@ * * 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 -u --recursive --new-file v1.3.97/linux/drivers/scsi/in2000.readme linux/drivers/scsi/in2000.readme --- v1.3.97/linux/drivers/scsi/in2000.readme Mon Apr 29 18:05:18 1996 +++ linux/drivers/scsi/in2000.readme Sat May 4 19:39:23 1996 @@ -17,7 +17,7 @@ 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 @@ 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 -u --recursive --new-file v1.3.97/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v1.3.97/linux/drivers/scsi/scsi.c Sat Apr 27 15:19:57 1996 +++ linux/drivers/scsi/scsi.c Thu May 2 07:48:54 1996 @@ -193,7 +193,7 @@ #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 @@ #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 @@ 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 @@ * 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 @@ 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 @@ * 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 @@ { 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ */ 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 -u --recursive --new-file v1.3.97/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h --- v1.3.97/linux/drivers/scsi/scsi.h Fri Apr 19 10:08:00 1996 +++ linux/drivers/scsi/scsi.h Thu May 2 07:48:54 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c --- v1.3.97/linux/drivers/scsi/scsi_ioctl.c Mon Apr 8 19:01:44 1996 +++ linux/drivers/scsi/scsi_ioctl.c Thu May 2 07:48:54 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/drivers/scsi/scsi_ioctl.h linux/drivers/scsi/scsi_ioctl.h --- v1.3.97/linux/drivers/scsi/scsi_ioctl.h Sun Sep 10 09:37:22 1995 +++ linux/drivers/scsi/scsi_ioctl.h Thu Jan 1 02:00:00 1970 @@ -1,21 +0,0 @@ -#ifndef _SCSI_IOCTL_H -#define _SCSI_IOCTL_H - -#define SCSI_IOCTL_SEND_COMMAND 1 -#define SCSI_IOCTL_TEST_UNIT_READY 2 -#define SCSI_IOCTL_BENCHMARK_COMMAND 3 -#define SCSI_IOCTL_SYNC 4 /* Request synchronous parameters */ -/* The door lock/unlock constants are compatible with Sun constants for - the cdrom */ -#define SCSI_IOCTL_DOORLOCK 0x5380 /* lock the eject mechanism */ -#define SCSI_IOCTL_DOORUNLOCK 0x5381 /* unlock the mechanism */ - -#define SCSI_REMOVAL_PREVENT 1 -#define SCSI_REMOVAL_ALLOW 0 - -extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg); -extern int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg); - -#endif - - diff -u --recursive --new-file v1.3.97/linux/drivers/scsi/scsi_syms.c linux/drivers/scsi/scsi_syms.c --- v1.3.97/linux/drivers/scsi/scsi_syms.c Fri Apr 19 10:08:00 1996 +++ linux/drivers/scsi/scsi_syms.c Thu May 2 07:48:54 1996 @@ -21,7 +21,7 @@ #include #include "scsi.h" -#include "scsi_ioctl.h" +#include #include "hosts.h" #include "constants.h" diff -u --recursive --new-file v1.3.97/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v1.3.97/linux/drivers/scsi/sd.c Wed Apr 17 09:06:32 1996 +++ linux/drivers/scsi/sd.c Thu May 2 07:48:54 1996 @@ -41,7 +41,7 @@ #include "scsi.h" #include "hosts.h" #include "sd.h" -#include "scsi_ioctl.h" +#include #include "constants.h" #include diff -u --recursive --new-file v1.3.97/linux/drivers/scsi/sd_ioctl.c linux/drivers/scsi/sd_ioctl.c --- v1.3.97/linux/drivers/scsi/sd_ioctl.c Sun Apr 21 12:39:02 1996 +++ linux/drivers/scsi/sd_ioctl.c Thu May 2 07:48:54 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/drivers/scsi/seagate.c linux/drivers/scsi/seagate.c --- v1.3.97/linux/drivers/scsi/seagate.c Tue Apr 2 13:32:21 1996 +++ linux/drivers/scsi/seagate.c Thu May 2 07:48:54 1996 @@ -1632,7 +1632,7 @@ #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 -u --recursive --new-file v1.3.97/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c --- v1.3.97/linux/drivers/scsi/sg.c Tue Jan 9 11:33:30 1996 +++ linux/drivers/scsi/sg.c Thu May 2 07:48:54 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/drivers/scsi/sg.h linux/drivers/scsi/sg.h --- v1.3.97/linux/drivers/scsi/sg.h Thu Jun 29 11:19:13 1995 +++ linux/drivers/scsi/sg.h Thu Jan 1 02:00:00 1970 @@ -1,36 +0,0 @@ -/* - History: - Started: Aug 9 by Lawrence Foard (entropy@world.std.com), to allow user - process control of SCSI devices. - Development Sponsored by Killy Corp. NY NY -*/ - -/* - An SG device is accessed by writing "packets" to it, the replies - are then read using the read call. The same header is used for - reply, just ignore reply_len field. -*/ - -struct sg_header - { - int pack_len; /* length of incoming packet <4096 (including header) */ - int reply_len; /* maximum length <4096 of expected reply */ - int pack_id; /* id number of packet */ - int result; /* 0==ok, otherwise refer to errno codes */ - unsigned int twelve_byte:1; /* Force 12 byte command length for group 6 & 7 commands */ - unsigned int other_flags:31; /* for future use */ - unsigned char sense_buffer[16]; /* used only by reads */ - /* command follows then data for command */ - }; - -/* ioctl's */ -#define SG_SET_TIMEOUT 0x2201 /* set timeout *(int *)arg==timeout */ -#define SG_GET_TIMEOUT 0x2202 /* get timeout return timeout */ - -#define SG_DEFAULT_TIMEOUT (60*HZ) /* 1 minute timeout */ -#define SG_DEFAULT_RETRIES 1 - -#define SG_MAX_QUEUE 4 /* maximum outstanding request, arbitrary, may be - changed if sufficient DMA buffer room available */ - -#define SG_BIG_BUFF 32768 diff -u --recursive --new-file v1.3.97/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v1.3.97/linux/drivers/scsi/sr.c Fri Apr 12 15:52:01 1996 +++ linux/drivers/scsi/sr.c Thu May 2 07:48:54 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c --- v1.3.97/linux/drivers/scsi/sr_ioctl.c Tue Apr 2 13:32:21 1996 +++ linux/drivers/scsi/sr_ioctl.c Thu May 2 07:48:54 1996 @@ -10,7 +10,7 @@ #include "scsi.h" #include "hosts.h" #include "sr.h" -#include "scsi_ioctl.h" +#include #include @@ -555,12 +555,21 @@ } 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 -u --recursive --new-file v1.3.97/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v1.3.97/linux/drivers/scsi/st.c Wed Apr 24 17:00:41 1996 +++ linux/drivers/scsi/st.c Fri May 3 10:12:16 1996 @@ -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 @@ #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 @@ 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 @@ 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 @@ } } 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 @@ } + /* 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 @@ 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 @@ (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 @@ 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 @@ 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 @@ #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 @@ 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 @@ 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 @@ 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 @@ { 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 @@ } #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 @@ 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 @@ } } - 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 @@ 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 @@ 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 @@ 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 @@ } #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 @@ 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 @@ (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 @@ (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 @@ 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 @@ 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 @@ 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 @@ 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%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 @@ 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 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ if (fileno >= 0) fileno += arg; blkno = 0; - at_sm &= (arg != 0); + at_sm &= (arg == 0); break; case MTBSF: case MTBSFM: @@ -1673,7 +1732,7 @@ 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 @@ #endif if (blkno >= 0) blkno += arg; - at_sm &= (arg != 0); + at_sm &= (arg == 0); break; case MTBSR: cmd[0] = SPACE; @@ -1707,7 +1766,7 @@ #endif if (blkno >= 0) blkno -= arg; - at_sm &= (arg != 0); + at_sm &= (arg == 0); break; case MTFSS: cmd[0] = SPACE; @@ -1829,7 +1888,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } + /* 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 @@ } #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 @@ 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 @@ 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 @@ 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 @@ 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 @@ (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 @@ (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 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 @@ 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 @@ 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 @@ { 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 -u --recursive --new-file v1.3.97/linux/drivers/scsi/st.h linux/drivers/scsi/st.h --- v1.3.97/linux/drivers/scsi/st.h Tue Apr 23 13:57:10 1996 +++ linux/drivers/scsi/st.h Fri May 3 10:12:16 1996 @@ -43,6 +43,17 @@ #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 @@ 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 @@ 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 -u --recursive --new-file v1.3.97/linux/drivers/scsi/wd33c93.c linux/drivers/scsi/wd33c93.c --- v1.3.97/linux/drivers/scsi/wd33c93.c Sat Apr 27 15:19:57 1996 +++ linux/drivers/scsi/wd33c93.c Sat May 4 19:39:23 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/fs/Config.in linux/fs/Config.in --- v1.3.97/linux/fs/Config.in Sat Apr 27 15:19:57 1996 +++ linux/fs/Config.in Tue Apr 30 12:42:37 1996 @@ -5,7 +5,7 @@ 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 -u --recursive --new-file v1.3.97/linux/fs/buffer.c linux/fs/buffer.c --- v1.3.97/linux/fs/buffer.c Sat Apr 27 15:19:57 1996 +++ linux/fs/buffer.c Sat May 4 09:27:58 1996 @@ -721,11 +721,17 @@ /* 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 * 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 @@ { 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 @@ 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 @@ 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 -u --recursive --new-file v1.3.97/linux/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c --- v1.3.97/linux/fs/ext2/ialloc.c Mon Feb 26 08:36:27 1996 +++ linux/fs/ext2/ialloc.c Sat May 4 10:06:18 1996 @@ -151,41 +151,6 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 -u --recursive --new-file v1.3.97/linux/fs/ext2/inode.c linux/fs/ext2/inode.c --- v1.3.97/linux/fs/ext2/inode.c Sat Jan 6 13:12:52 1996 +++ linux/fs/ext2/inode.c Sat May 4 10:06:18 1996 @@ -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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 -u --recursive --new-file v1.3.97/linux/fs/ext2/super.c linux/fs/ext2/super.c --- v1.3.97/linux/fs/ext2/super.c Wed Apr 24 17:00:41 1996 +++ linux/fs/ext2/super.c Sat May 4 10:07:07 1996 @@ -270,7 +270,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 -u --recursive --new-file v1.3.97/linux/fs/fcntl.c linux/fs/fcntl.c --- v1.3.97/linux/fs/fcntl.c Sat Apr 27 15:19:58 1996 +++ linux/fs/fcntl.c Sat May 4 19:39:22 1996 @@ -85,7 +85,7 @@ 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 -u --recursive --new-file v1.3.97/linux/fs/locks.c linux/fs/locks.c --- v1.3.97/linux/fs/locks.c Sat Apr 27 15:19:58 1996 +++ linux/fs/locks.c Tue Apr 30 13:44:00 1996 @@ -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 @@ 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 @@ */ 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 @@ /* 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 @@ * 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 @@ 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 @@ { off_t start; + fl->fl_flags = F_POSIX; + switch (l->l_type) { case F_RDLCK : case F_WRLCK : @@ -415,9 +422,11 @@ 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 @@ 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 @@ /* 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 @@ /* 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 @@ * 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 @@ 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 @@ * 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 @@ 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 @@ 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 @@ /* 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 @@ /* Go on to next lock. */ next_lock: - before = &(*before)->fl_next; + before = &fl->fl_next; } if (!added) { @@ -795,7 +811,6 @@ 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 @@ 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 -u --recursive --new-file v1.3.97/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c --- v1.3.97/linux/fs/nfs/nfsroot.c Sun Apr 21 12:39:02 1996 +++ linux/fs/nfs/nfsroot.c Wed May 1 10:26:55 1996 @@ -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 @@ break; if (*cp == '.' || octets == 3) octets++; + if (octets < 4) + cp++; cq = cp; } if (octets == 4 && (*cp == ':' || *cp == '\0')) { diff -u --recursive --new-file v1.3.97/linux/fs/pipe.c linux/fs/pipe.c --- v1.3.97/linux/fs/pipe.c Wed Apr 24 17:00:41 1996 +++ linux/fs/pipe.c Fri May 3 10:24:07 1996 @@ -161,7 +161,7 @@ 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 -u --recursive --new-file v1.3.97/linux/fs/proc/array.c linux/fs/proc/array.c --- v1.3.97/linux/fs/proc/array.c Sat Apr 27 15:19:59 1996 +++ linux/fs/proc/array.c Tue Apr 30 13:09:45 1996 @@ -967,6 +967,7 @@ 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 @@ case PROC_RTC: return get_rtc_status(page); #endif + case PROC_LOCKS: + return get_locks_status(page); } return -EBADF; } diff -u --recursive --new-file v1.3.97/linux/fs/proc/mem.c linux/fs/proc/mem.c --- v1.3.97/linux/fs/proc/mem.c Sat Apr 27 15:19:59 1996 +++ linux/fs/proc/mem.c Thu May 2 16:00:28 1996 @@ -50,6 +50,32 @@ 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 @@ 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 @@ 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 @@ 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 -u --recursive --new-file v1.3.97/linux/fs/proc/root.c linux/fs/proc/root.c --- v1.3.97/linux/fs/proc/root.c Mon Apr 15 12:20:21 1996 +++ linux/fs/proc/root.c Tue Apr 30 13:09:45 1996 @@ -358,6 +358,10 @@ 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 -u --recursive --new-file v1.3.97/linux/include/asm-alpha/fcntl.h linux/include/asm-alpha/fcntl.h --- v1.3.97/linux/include/asm-alpha/fcntl.h Fri Jun 16 20:03:02 1995 +++ linux/include/asm-alpha/fcntl.h Tue Apr 30 13:09:45 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/include/asm-i386/checksum.h linux/include/asm-i386/checksum.h --- v1.3.97/linux/include/asm-i386/checksum.h Tue Oct 3 11:45:59 1995 +++ linux/include/asm-i386/checksum.h Thu May 2 06:44:19 1996 @@ -65,14 +65,30 @@ 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 @@ 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 -u --recursive --new-file v1.3.97/linux/include/asm-i386/fcntl.h linux/include/asm-i386/fcntl.h --- v1.3.97/linux/include/asm-i386/fcntl.h Sun Jun 11 19:01:08 1995 +++ linux/include/asm-i386/fcntl.h Tue Apr 30 13:09:45 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/include/asm-m68k/fcntl.h linux/include/asm-m68k/fcntl.h --- v1.3.97/linux/include/asm-m68k/fcntl.h Tue Apr 23 13:57:12 1996 +++ linux/include/asm-m68k/fcntl.h Tue Apr 30 13:09:45 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/include/asm-mips/fcntl.h linux/include/asm-mips/fcntl.h --- v1.3.97/linux/include/asm-mips/fcntl.h Wed Dec 13 12:39:45 1995 +++ linux/include/asm-mips/fcntl.h Tue Apr 30 13:09:45 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/include/asm-ppc/fcntl.h linux/include/asm-ppc/fcntl.h --- v1.3.97/linux/include/asm-ppc/fcntl.h Sat Nov 25 19:49:06 1995 +++ linux/include/asm-ppc/fcntl.h Tue Apr 30 13:09:45 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/include/asm-sparc/fcntl.h linux/include/asm-sparc/fcntl.h --- v1.3.97/linux/include/asm-sparc/fcntl.h Mon Mar 4 08:50:00 1996 +++ linux/include/asm-sparc/fcntl.h Tue Apr 30 13:09:45 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/include/linux/apm_bios.h linux/include/linux/apm_bios.h --- v1.3.97/linux/include/linux/apm_bios.h Mon Apr 8 19:01:46 1996 +++ linux/include/linux/apm_bios.h Fri May 3 16:19:14 1996 @@ -61,6 +61,8 @@ 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 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 -u --recursive --new-file v1.3.97/linux/include/linux/bios32.h linux/include/linux/bios32.h --- v1.3.97/linux/include/linux/bios32.h Tue Nov 14 07:35:31 1995 +++ linux/include/linux/bios32.h Fri May 3 15:40:09 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h --- v1.3.97/linux/include/linux/ext2_fs.h Mon Mar 25 10:22:43 1996 +++ linux/include/linux/ext2_fs.h Sat May 4 10:06:18 1996 @@ -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 @@ #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 @@ __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 @@ * 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 @@ -380,6 +412,12 @@ #define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1) #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__ /* diff -u --recursive --new-file v1.3.97/linux/include/linux/ext2_fs_i.h linux/include/linux/ext2_fs_i.h --- v1.3.97/linux/include/linux/ext2_fs_i.h Wed Mar 22 10:33:59 1995 +++ linux/include/linux/ext2_fs_i.h Sat May 4 10:06:18 1996 @@ -35,6 +35,7 @@ __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 -u --recursive --new-file v1.3.97/linux/include/linux/ext2_fs_sb.h linux/include/linux/ext2_fs_sb.h --- v1.3.97/linux/include/linux/ext2_fs_sb.h Mon Mar 25 10:22:43 1996 +++ linux/include/linux/ext2_fs_sb.h Sat May 4 10:06:18 1996 @@ -57,8 +57,9 @@ 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 -u --recursive --new-file v1.3.97/linux/include/linux/kernel.h linux/include/linux/kernel.h --- v1.3.97/linux/include/linux/kernel.h Mon Mar 11 09:39:34 1996 +++ linux/include/linux/kernel.h Wed May 1 11:47:47 1996 @@ -57,6 +57,12 @@ 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 -u --recursive --new-file v1.3.97/linux/include/linux/mtio.h linux/include/linux/mtio.h --- v1.3.97/linux/include/linux/mtio.h Tue Apr 23 13:57:13 1996 +++ linux/include/linux/mtio.h Fri May 3 10:12:17 1996 @@ -57,6 +57,8 @@ #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 @@ #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 @@ #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 -u --recursive --new-file v1.3.97/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h --- v1.3.97/linux/include/linux/proc_fs.h Sat Apr 27 15:20:07 1996 +++ linux/include/linux/proc_fs.h Fri May 3 16:19:04 1996 @@ -42,7 +42,8 @@ PROC_SYS, PROC_MTAB, PROC_MD, - PROC_RTC + PROC_RTC, + PROC_LOCKS }; enum pid_directory_inos { diff -u --recursive --new-file v1.3.97/linux/include/linux/random.h linux/include/linux/random.h --- v1.3.97/linux/include/linux/random.h Sun Feb 11 12:41:34 1996 +++ linux/include/linux/random.h Sat May 4 10:02:51 1996 @@ -9,11 +9,26 @@ /* 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; diff -u --recursive --new-file v1.3.97/linux/include/linux/scsi.h linux/include/linux/scsi.h --- v1.3.97/linux/include/linux/scsi.h Sun Sep 10 09:37:21 1995 +++ linux/include/linux/scsi.h Thu Jan 1 02:00:00 1970 @@ -1,198 +0,0 @@ -#ifndef _LINUX_SCSI_H -#define _LINUX_SCSI_H - -/* - * This header file contains public constants and structures used by - * the scsi code for linux. - */ - -/* - $Header: /usr/src/linux/include/linux/RCS/scsi.h,v 1.3 1993/09/24 12:20:33 drew Exp $ - - For documentation on the OPCODES, MESSAGES, and SENSE values, - please consult the SCSI standard. - -*/ - -/* - * SCSI opcodes - */ - -#define TEST_UNIT_READY 0x00 -#define REZERO_UNIT 0x01 -#define REQUEST_SENSE 0x03 -#define FORMAT_UNIT 0x04 -#define READ_BLOCK_LIMITS 0x05 -#define REASSIGN_BLOCKS 0x07 -#define READ_6 0x08 -#define WRITE_6 0x0a -#define SEEK_6 0x0b -#define READ_REVERSE 0x0f -#define WRITE_FILEMARKS 0x10 -#define SPACE 0x11 -#define INQUIRY 0x12 -#define RECOVER_BUFFERED_DATA 0x14 -#define MODE_SELECT 0x15 -#define RESERVE 0x16 -#define RELEASE 0x17 -#define COPY 0x18 -#define ERASE 0x19 -#define MODE_SENSE 0x1a -#define START_STOP 0x1b -#define RECEIVE_DIAGNOSTIC 0x1c -#define SEND_DIAGNOSTIC 0x1d -#define ALLOW_MEDIUM_REMOVAL 0x1e - -#define SET_WINDOW 0x24 -#define READ_CAPACITY 0x25 -#define READ_10 0x28 -#define WRITE_10 0x2a -#define SEEK_10 0x2b -#define WRITE_VERIFY 0x2e -#define VERIFY 0x2f -#define SEARCH_HIGH 0x30 -#define SEARCH_EQUAL 0x31 -#define SEARCH_LOW 0x32 -#define SET_LIMITS 0x33 -#define PRE_FETCH 0x34 -#define READ_POSITION 0x34 -#define SYNCHRONIZE_CACHE 0x35 -#define LOCK_UNLOCK_CACHE 0x36 -#define READ_DEFECT_DATA 0x37 -#define MEDIUM_SCAN 0x38 -#define COMPARE 0x39 -#define COPY_VERIFY 0x3a -#define WRITE_BUFFER 0x3b -#define READ_BUFFER 0x3c -#define UPDATE_BLOCK 0x3d -#define READ_LONG 0x3e -#define WRITE_LONG 0x3f -#define CHANGE_DEFINITION 0x40 -#define WRITE_SAME 0x41 -#define LOG_SELECT 0x4c -#define LOG_SENSE 0x4d -#define MODE_SELECT_10 0x55 -#define MODE_SENSE_10 0x5a -#define READ_12 0xa8 -#define WRITE_12 0xaa -#define WRITE_VERIFY_12 0xae -#define SEARCH_HIGH_12 0xb0 -#define SEARCH_EQUAL_12 0xb1 -#define SEARCH_LOW_12 0xb2 -#define SEND_VOLUME_TAG 0xb6 -#define WRITE_LONG_2 0xea - -/* - * Status codes - */ - -#define GOOD 0x00 -#define CHECK_CONDITION 0x01 -#define CONDITION_GOOD 0x02 -#define BUSY 0x04 -#define INTERMEDIATE_GOOD 0x08 -#define INTERMEDIATE_C_GOOD 0x0a -#define RESERVATION_CONFLICT 0x0c -#define QUEUE_FULL 0x1a - -#define STATUS_MASK 0x1e - -/* - * SENSE KEYS - */ - -#define NO_SENSE 0x00 -#define RECOVERED_ERROR 0x01 -#define NOT_READY 0x02 -#define MEDIUM_ERROR 0x03 -#define HARDWARE_ERROR 0x04 -#define ILLEGAL_REQUEST 0x05 -#define UNIT_ATTENTION 0x06 -#define DATA_PROTECT 0x07 -#define BLANK_CHECK 0x08 -#define COPY_ABORTED 0x0a -#define ABORTED_COMMAND 0x0b -#define VOLUME_OVERFLOW 0x0d -#define MISCOMPARE 0x0e - - -/* - * DEVICE TYPES - */ - -#define TYPE_DISK 0x00 -#define TYPE_TAPE 0x01 -#define TYPE_PROCESSOR 0x03 /* HP scanners use this */ -#define TYPE_WORM 0x04 /* Treated as ROM by our system */ -#define TYPE_ROM 0x05 -#define TYPE_SCANNER 0x06 -#define TYPE_MOD 0x07 /* Magneto-optical disk - - * - treated as TYPE_DISK */ -#define TYPE_NO_LUN 0x7f - - -/* - * MESSAGE CODES - */ - -#define COMMAND_COMPLETE 0x00 -#define EXTENDED_MESSAGE 0x01 -#define EXTENDED_MODIFY_DATA_POINTER 0x00 -#define EXTENDED_SDTR 0x01 -#define EXTENDED_EXTENDED_IDENTIFY 0x02 /* SCSI-I only */ -#define EXTENDED_WDTR 0x03 -#define SAVE_POINTERS 0x02 -#define RESTORE_POINTERS 0x03 -#define DISCONNECT 0x04 -#define INITIATOR_ERROR 0x05 -#define ABORT 0x06 -#define MESSAGE_REJECT 0x07 -#define NOP 0x08 -#define MSG_PARITY_ERROR 0x09 -#define LINKED_CMD_COMPLETE 0x0a -#define LINKED_FLG_CMD_COMPLETE 0x0b -#define BUS_DEVICE_RESET 0x0c - -#define INITIATE_RECOVERY 0x0f /* SCSI-II only */ -#define RELEASE_RECOVERY 0x10 /* SCSI-II only */ - -#define SIMPLE_QUEUE_TAG 0x20 -#define HEAD_OF_QUEUE_TAG 0x21 -#define ORDERED_QUEUE_TAG 0x22 - -/* - * Here are some scsi specific ioctl commands which are sometimes useful. - */ -/* These are a few other constants only used by scsi devices */ - -#define SCSI_IOCTL_GET_IDLUN 0x5382 - -/* Used to turn on and off tagged queuing for scsi devices */ - -#define SCSI_IOCTL_TAGGED_ENABLE 0x5383 -#define SCSI_IOCTL_TAGGED_DISABLE 0x5384 - -/* Used to obtain the host number of a device. */ -#define SCSI_IOCTL_PROBE_HOST 0x5385 - - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 4 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -4 - * c-argdecl-indent: 4 - * c-label-offset: -4 - * c-continued-statement-offset: 4 - * c-continued-brace-offset: 0 - * indent-tabs-mode: nil - * tab-width: 8 - * End: - */ - -#endif diff -u --recursive --new-file v1.3.97/linux/include/linux/scsicam.h linux/include/linux/scsicam.h --- v1.3.97/linux/include/linux/scsicam.h Thu Sep 21 08:59:23 1995 +++ linux/include/linux/scsicam.h Thu Jan 1 02:00:00 1970 @@ -1,17 +0,0 @@ -/* - * scsicam.h - SCSI CAM support functions, use for HDIO_GETGEO, etc. - * - * Copyright 1993, 1994 Drew Eckhardt - * Visionary Computing - * (Unix and Linux consulting and custom programming) - * drew@Colorado.EDU - * +1 (303) 786-7975 - * - * For more information, please consult the SCSI-CAM draft. - */ - -#ifndef SCSICAM_H -#define SCSICAM_H -#include -extern int scsicam_bios_param (Disk *disk, kdev_t dev, int *ip); -#endif /* def SCSICAM_H */ diff -u --recursive --new-file v1.3.97/linux/include/linux/timex.h linux/include/linux/timex.h --- v1.3.97/linux/include/linux/timex.h Sat Apr 27 15:20:07 1996 +++ linux/include/linux/timex.h Sat May 4 19:39:22 1996 @@ -222,7 +222,7 @@ #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 -u --recursive --new-file v1.3.97/linux/include/net/route.h linux/include/net/route.h --- v1.3.97/linux/include/net/route.h Fri Apr 12 15:52:09 1996 +++ linux/include/net/route.h Fri May 3 16:24:02 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/include/scsi/scsi.h linux/include/scsi/scsi.h --- v1.3.97/linux/include/scsi/scsi.h Thu Jan 1 02:00:00 1970 +++ linux/include/scsi/scsi.h Thu May 2 07:48:55 1996 @@ -0,0 +1,198 @@ +#ifndef _LINUX_SCSI_H +#define _LINUX_SCSI_H + +/* + * This header file contains public constants and structures used by + * the scsi code for linux. + */ + +/* + $Header: /usr/src/linux/include/linux/RCS/scsi.h,v 1.3 1993/09/24 12:20:33 drew Exp $ + + For documentation on the OPCODES, MESSAGES, and SENSE values, + please consult the SCSI standard. + +*/ + +/* + * SCSI opcodes + */ + +#define TEST_UNIT_READY 0x00 +#define REZERO_UNIT 0x01 +#define REQUEST_SENSE 0x03 +#define FORMAT_UNIT 0x04 +#define READ_BLOCK_LIMITS 0x05 +#define REASSIGN_BLOCKS 0x07 +#define READ_6 0x08 +#define WRITE_6 0x0a +#define SEEK_6 0x0b +#define READ_REVERSE 0x0f +#define WRITE_FILEMARKS 0x10 +#define SPACE 0x11 +#define INQUIRY 0x12 +#define RECOVER_BUFFERED_DATA 0x14 +#define MODE_SELECT 0x15 +#define RESERVE 0x16 +#define RELEASE 0x17 +#define COPY 0x18 +#define ERASE 0x19 +#define MODE_SENSE 0x1a +#define START_STOP 0x1b +#define RECEIVE_DIAGNOSTIC 0x1c +#define SEND_DIAGNOSTIC 0x1d +#define ALLOW_MEDIUM_REMOVAL 0x1e + +#define SET_WINDOW 0x24 +#define READ_CAPACITY 0x25 +#define READ_10 0x28 +#define WRITE_10 0x2a +#define SEEK_10 0x2b +#define WRITE_VERIFY 0x2e +#define VERIFY 0x2f +#define SEARCH_HIGH 0x30 +#define SEARCH_EQUAL 0x31 +#define SEARCH_LOW 0x32 +#define SET_LIMITS 0x33 +#define PRE_FETCH 0x34 +#define READ_POSITION 0x34 +#define SYNCHRONIZE_CACHE 0x35 +#define LOCK_UNLOCK_CACHE 0x36 +#define READ_DEFECT_DATA 0x37 +#define MEDIUM_SCAN 0x38 +#define COMPARE 0x39 +#define COPY_VERIFY 0x3a +#define WRITE_BUFFER 0x3b +#define READ_BUFFER 0x3c +#define UPDATE_BLOCK 0x3d +#define READ_LONG 0x3e +#define WRITE_LONG 0x3f +#define CHANGE_DEFINITION 0x40 +#define WRITE_SAME 0x41 +#define LOG_SELECT 0x4c +#define LOG_SENSE 0x4d +#define MODE_SELECT_10 0x55 +#define MODE_SENSE_10 0x5a +#define READ_12 0xa8 +#define WRITE_12 0xaa +#define WRITE_VERIFY_12 0xae +#define SEARCH_HIGH_12 0xb0 +#define SEARCH_EQUAL_12 0xb1 +#define SEARCH_LOW_12 0xb2 +#define SEND_VOLUME_TAG 0xb6 +#define WRITE_LONG_2 0xea + +/* + * Status codes + */ + +#define GOOD 0x00 +#define CHECK_CONDITION 0x01 +#define CONDITION_GOOD 0x02 +#define BUSY 0x04 +#define INTERMEDIATE_GOOD 0x08 +#define INTERMEDIATE_C_GOOD 0x0a +#define RESERVATION_CONFLICT 0x0c +#define QUEUE_FULL 0x1a + +#define STATUS_MASK 0x1e + +/* + * SENSE KEYS + */ + +#define NO_SENSE 0x00 +#define RECOVERED_ERROR 0x01 +#define NOT_READY 0x02 +#define MEDIUM_ERROR 0x03 +#define HARDWARE_ERROR 0x04 +#define ILLEGAL_REQUEST 0x05 +#define UNIT_ATTENTION 0x06 +#define DATA_PROTECT 0x07 +#define BLANK_CHECK 0x08 +#define COPY_ABORTED 0x0a +#define ABORTED_COMMAND 0x0b +#define VOLUME_OVERFLOW 0x0d +#define MISCOMPARE 0x0e + + +/* + * DEVICE TYPES + */ + +#define TYPE_DISK 0x00 +#define TYPE_TAPE 0x01 +#define TYPE_PROCESSOR 0x03 /* HP scanners use this */ +#define TYPE_WORM 0x04 /* Treated as ROM by our system */ +#define TYPE_ROM 0x05 +#define TYPE_SCANNER 0x06 +#define TYPE_MOD 0x07 /* Magneto-optical disk - + * - treated as TYPE_DISK */ +#define TYPE_NO_LUN 0x7f + + +/* + * MESSAGE CODES + */ + +#define COMMAND_COMPLETE 0x00 +#define EXTENDED_MESSAGE 0x01 +#define EXTENDED_MODIFY_DATA_POINTER 0x00 +#define EXTENDED_SDTR 0x01 +#define EXTENDED_EXTENDED_IDENTIFY 0x02 /* SCSI-I only */ +#define EXTENDED_WDTR 0x03 +#define SAVE_POINTERS 0x02 +#define RESTORE_POINTERS 0x03 +#define DISCONNECT 0x04 +#define INITIATOR_ERROR 0x05 +#define ABORT 0x06 +#define MESSAGE_REJECT 0x07 +#define NOP 0x08 +#define MSG_PARITY_ERROR 0x09 +#define LINKED_CMD_COMPLETE 0x0a +#define LINKED_FLG_CMD_COMPLETE 0x0b +#define BUS_DEVICE_RESET 0x0c + +#define INITIATE_RECOVERY 0x0f /* SCSI-II only */ +#define RELEASE_RECOVERY 0x10 /* SCSI-II only */ + +#define SIMPLE_QUEUE_TAG 0x20 +#define HEAD_OF_QUEUE_TAG 0x21 +#define ORDERED_QUEUE_TAG 0x22 + +/* + * Here are some scsi specific ioctl commands which are sometimes useful. + */ +/* These are a few other constants only used by scsi devices */ + +#define SCSI_IOCTL_GET_IDLUN 0x5382 + +/* Used to turn on and off tagged queuing for scsi devices */ + +#define SCSI_IOCTL_TAGGED_ENABLE 0x5383 +#define SCSI_IOCTL_TAGGED_DISABLE 0x5384 + +/* Used to obtain the host number of a device. */ +#define SCSI_IOCTL_PROBE_HOST 0x5385 + + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 4 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -4 + * c-argdecl-indent: 4 + * c-label-offset: -4 + * c-continued-statement-offset: 4 + * c-continued-brace-offset: 0 + * indent-tabs-mode: nil + * tab-width: 8 + * End: + */ + +#endif diff -u --recursive --new-file v1.3.97/linux/include/scsi/scsi_ioctl.h linux/include/scsi/scsi_ioctl.h --- v1.3.97/linux/include/scsi/scsi_ioctl.h Thu Jan 1 02:00:00 1970 +++ linux/include/scsi/scsi_ioctl.h Thu May 2 07:48:55 1996 @@ -0,0 +1,21 @@ +#ifndef _SCSI_IOCTL_H +#define _SCSI_IOCTL_H + +#define SCSI_IOCTL_SEND_COMMAND 1 +#define SCSI_IOCTL_TEST_UNIT_READY 2 +#define SCSI_IOCTL_BENCHMARK_COMMAND 3 +#define SCSI_IOCTL_SYNC 4 /* Request synchronous parameters */ +/* The door lock/unlock constants are compatible with Sun constants for + the cdrom */ +#define SCSI_IOCTL_DOORLOCK 0x5380 /* lock the eject mechanism */ +#define SCSI_IOCTL_DOORUNLOCK 0x5381 /* unlock the mechanism */ + +#define SCSI_REMOVAL_PREVENT 1 +#define SCSI_REMOVAL_ALLOW 0 + +extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg); +extern int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg); + +#endif + + diff -u --recursive --new-file v1.3.97/linux/include/scsi/scsicam.h linux/include/scsi/scsicam.h --- v1.3.97/linux/include/scsi/scsicam.h Thu Jan 1 02:00:00 1970 +++ linux/include/scsi/scsicam.h Thu May 2 07:48:55 1996 @@ -0,0 +1,17 @@ +/* + * scsicam.h - SCSI CAM support functions, use for HDIO_GETGEO, etc. + * + * Copyright 1993, 1994 Drew Eckhardt + * Visionary Computing + * (Unix and Linux consulting and custom programming) + * drew@Colorado.EDU + * +1 (303) 786-7975 + * + * For more information, please consult the SCSI-CAM draft. + */ + +#ifndef SCSICAM_H +#define SCSICAM_H +#include +extern int scsicam_bios_param (Disk *disk, kdev_t dev, int *ip); +#endif /* def SCSICAM_H */ diff -u --recursive --new-file v1.3.97/linux/include/scsi/sg.h linux/include/scsi/sg.h --- v1.3.97/linux/include/scsi/sg.h Thu Jan 1 02:00:00 1970 +++ linux/include/scsi/sg.h Thu May 2 07:48:55 1996 @@ -0,0 +1,41 @@ +/* + History: + Started: Aug 9 by Lawrence Foard (entropy@world.std.com), to allow user + process control of SCSI devices. + Development Sponsored by Killy Corp. NY NY +*/ + +#ifndef _SCSI_GENERIC_H +#define _SCSI_GENERIC_H + +/* + An SG device is accessed by writing "packets" to it, the replies + are then read using the read call. The same header is used for + reply, just ignore reply_len field. +*/ + +struct sg_header + { + int pack_len; /* length of incoming packet <4096 (including header) */ + int reply_len; /* maximum length <4096 of expected reply */ + int pack_id; /* id number of packet */ + int result; /* 0==ok, otherwise refer to errno codes */ + unsigned int twelve_byte:1; /* Force 12 byte command length for group 6 & 7 commands */ + unsigned int other_flags:31; /* for future use */ + unsigned char sense_buffer[16]; /* used only by reads */ + /* command follows then data for command */ + }; + +/* ioctl's */ +#define SG_SET_TIMEOUT 0x2201 /* set timeout *(int *)arg==timeout */ +#define SG_GET_TIMEOUT 0x2202 /* get timeout return timeout */ + +#define SG_DEFAULT_TIMEOUT (60*HZ) /* 1 minute timeout */ +#define SG_DEFAULT_RETRIES 1 + +#define SG_MAX_QUEUE 4 /* maximum outstanding request, arbitrary, may be + changed if sufficient DMA buffer room available */ + +#define SG_BIG_BUFF 32768 + +#endif diff -u --recursive --new-file v1.3.97/linux/kernel/sys.c linux/kernel/sys.c --- v1.3.97/linux/kernel/sys.c Wed Apr 17 09:06:33 1996 +++ linux/kernel/sys.c Thu May 2 08:06:31 1996 @@ -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 @@ 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 -u --recursive --new-file v1.3.97/linux/mm/filemap.c linux/mm/filemap.c --- v1.3.97/linux/mm/filemap.c Mon Apr 29 18:05:21 1996 +++ linux/mm/filemap.c Sat May 4 19:39:22 1996 @@ -422,7 +422,7 @@ * - 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 -u --recursive --new-file v1.3.97/linux/net/Config.in linux/net/Config.in --- v1.3.97/linux/net/Config.in Wed Apr 10 17:02:26 1996 +++ linux/net/Config.in Tue Apr 30 13:45:06 1996 @@ -20,8 +20,10 @@ 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 -u --recursive --new-file v1.3.97/linux/net/ax25/ax25_out.c linux/net/ax25/ax25_out.c --- v1.3.97/linux/net/ax25/ax25_out.c Sat Apr 27 15:20:10 1996 +++ linux/net/ax25/ax25_out.c Tue Apr 30 12:42:37 1996 @@ -405,6 +405,9 @@ /* 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 -u --recursive --new-file v1.3.97/linux/net/ax25/ax25_route.c linux/net/ax25/ax25_route.c --- v1.3.97/linux/net/ax25/ax25_route.c Fri Apr 12 15:52:11 1996 +++ linux/net/ax25/ax25_route.c Tue Apr 30 12:42:37 1996 @@ -488,7 +488,7 @@ /* * 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 -u --recursive --new-file v1.3.97/linux/net/core/dev.c linux/net/core/dev.c --- v1.3.97/linux/net/core/dev.c Sat Apr 27 15:20:10 1996 +++ linux/net/core/dev.c Tue Apr 30 12:42:37 1996 @@ -549,7 +549,7 @@ /* * 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 -u --recursive --new-file v1.3.97/linux/net/ipv4/Config.in linux/net/ipv4/Config.in --- v1.3.97/linux/net/ipv4/Config.in Mon Apr 29 18:05:21 1996 +++ linux/net/ipv4/Config.in Tue Apr 30 13:46:21 1996 @@ -15,15 +15,17 @@ 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 -u --recursive --new-file v1.3.97/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- v1.3.97/linux/net/ipv4/af_inet.c Fri Apr 12 15:52:11 1996 +++ linux/net/ipv4/af_inet.c Tue Apr 30 12:42:37 1996 @@ -417,8 +417,11 @@ { /* 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 -u --recursive --new-file v1.3.97/linux/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c --- v1.3.97/linux/net/ipv4/ip_sockglue.c Sat Apr 27 15:20:10 1996 +++ linux/net/ipv4/ip_sockglue.c Sat May 4 19:39:22 1996 @@ -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 -u --recursive --new-file v1.3.97/linux/scripts/Menuconfig linux/scripts/Menuconfig --- v1.3.97/linux/scripts/Menuconfig Tue Apr 23 13:57:14 1996 +++ linux/scripts/Menuconfig Fri May 3 11:55:12 1996 @@ -222,6 +222,7 @@ /^$var[ ]*\$/d /^#.*/d /^[ ]*\$/q + s/^ // p }" Documentation/Configure.help)