diff -u --recursive --new-file v1.3.45/linux/CREDITS linux/CREDITS --- v1.3.45/linux/CREDITS Mon Nov 27 12:48:25 1995 +++ linux/CREDITS Mon Dec 11 09:55:42 1995 @@ -2,7 +2,8 @@ contributed to the linux project. It is sorted by name, and formatted in a format that allows for easy grepping and beautification by scripts. The fields are: name (N), email (E), - description (D) and snail-mail address (S). Thanks, + web-address (W), description (D) and snail-mail address (S). + Thanks, Linus ---------- @@ -286,7 +287,10 @@ N: Rik Faith E: faith@cs.unc.edu -D: Future Domain TMC-16x0 SCSI driver +E: r.faith@ieee.org +D: Author: Future Domain TMC-16x0 SCSI driver +D: Debugging: SCSI code; Cyclades serial driver; APM driver +D: Debugging: XFree86 Mach 32 server, accelerated server code N: Juergen Fischer E: fischer@server.et-inf.fho-emden.de @@ -420,6 +424,13 @@ S: D-69126 Heidelberg S: Germany +N: Miguel de Icaza Amozurrutia +E: miguel@nuclecu.unam.mx +D: Linux/SPARC team, Midnight Commander maintainer +S: Avenida Copilco 162, 22-1003 +S: Mexico, DF +S: Mexico + N: Ian Jackson E: iwj10@cus.cam.ac.uk E: ijackson@nyx.cs.du.edu @@ -794,6 +805,18 @@ S: San Jose, California 95129 S: USA +N: Eric S. Raymond +E: esr@thyrsus.com +W: http://www.ccil.org/~esr/home.html +S: 22 South Warren Avenue +S: Malvern, PA 19355 USA +D: ncurses library co-maintainer +D: terminfo master file maintainer +D: Distributions HOWTO editor +D: Instigator, FHS standard +D: Keeper of the Jargon File and curator of the Retrocomputing Museum +D: Author, Emacs VC and GUD modes + N: Florian La Roche E: rzsfl@rz.uni-sb.de E: flla@stud.uni-sb.de @@ -803,8 +826,9 @@ S: Germany N: Stephen Rothwell -E: sfr@pdact.pd.necisa.oz.au +E: Stephen.Rothwell@nec.com.au D: Boot/setup/build work for setup > 2K +D: Author, APM driver S: 59 Bugden Avenue S: Gowrie ACT 2904 S: Australia @@ -1098,4 +1122,22 @@ D: Miscellaneous kernel fixes S: 3078 Sulphur Spring Court S: San Jose, California 95148 +S: USA + +N: Chih-Jen Chang +E: chihjenc@scf.usc.edu +E: chihjen@iis.sinica.edu.tw +D: IGMP(Internet Group Management Protocol) version 2 +S: 3F, 65 Tajen street +S: Tamsui town, Taipei county, +S: Taiwan 251, Republic of China + +N: Tsu-Sheng Tsao +E: tsusheng@scf.usc.edu +D: IGMP(Internet Group Management Protocol) version 2 +S: 2F 14 ALY 31 LN 166 SEC 1 SHIH-PEI RD +S: Taipei +S: Taiwan 112, Republic of China +S: 24335 Delta Drive +S: Diamond Bar, CA 91765 S: USA diff -u --recursive --new-file v1.3.45/linux/Documentation/cdrom/aztcd linux/Documentation/cdrom/aztcd --- v1.3.45/linux/Documentation/cdrom/aztcd Sat Nov 25 19:04:35 1995 +++ linux/Documentation/cdrom/aztcd Mon Dec 11 11:18:47 1995 @@ -1,4 +1,4 @@ -$Id: README.aztcd,v 2.0 1995/11/10 19:37:18 root Exp root $ +$Id: README.aztcd,v 2.10 1995/12/03 11:55:14 root Exp root $ Readme-File /usr/src/Documentation/cdrom/aztcd for Aztech CD-ROM CDA268-01A, ORCHID CD-3110, OKANO/WEARNES CDD110, Conrad TXC @@ -460,7 +460,7 @@ Reinhard Max delivered the information for the CDROM-interface of the SoundWave32 soundcards. -Jochen Koch and Olaf Koluza delivered the information for supporting Conrad's TXC +Jochen Koch and Olaf Kaluza delivered the information for supporting Conrad's TXC drive. Anybody, who is interested in these items should have a look at 'ftp.gwdg.de', diff -u --recursive --new-file v1.3.45/linux/Documentation/devices.tex linux/Documentation/devices.tex --- v1.3.45/linux/Documentation/devices.tex Tue Nov 21 13:22:04 1995 +++ linux/Documentation/devices.tex Mon Dec 11 10:46:30 1995 @@ -42,7 +42,7 @@ % \title{{\bf Linux Allocated Devices}} \author{Maintained by H. Peter Anvin $<$hpa@storm.net$>$} -\date{Last revised: November 17, 1995} +\date{Last revised: December 4, 1995} \maketitle % \noindent @@ -77,12 +77,12 @@ \section{Major numbers} \begin{devicelist} -\major{ 0}{}{ }{Unnamed devices (NFS mounts, loopback devices)} +\major{ 0}{}{ }{Unnamed devices (e.g. non-device mounts)} \major{ 1}{}{char }{Memory devices} \major{ }{}{block}{RAM disk} -\major{ 2}{}{char }{Reserved for PTY's $<$tytso@athena.mit.edu$>$} +\major{ 2}{}{char }{Pseudo-TTY masters} \major{ }{}{block}{Floppy disks} -\major{ 3}{}{char }{Reserved for PTY's $<$tytso@athena.mit.edu$>$} +\major{ 3}{}{char }{Pseudo-TTY slaves} \major{ }{}{block}{First MFM, RLL and IDE hard disk/CD-ROM interface} \major{ 4}{}{char }{TTY devices} \major{ 5}{}{char }{Alternate TTY devices} @@ -142,7 +142,8 @@ \major{ }{}{block}{Modular RAM disk} \major{36}{}{char }{Netlink support} \major{ }{}{block}{MCA ESDI hard disk} -\major{37}{--41}{}{Unallocated} +\major{37}{}{char }{IDE tape} +\major{38}{--41}{}{Unallocated} \major{42}{}{}{Demo/sample use} \major{43}{--223}{}{Unallocated} \major{224}{--239}{}{SEE NOTE} @@ -154,7 +155,7 @@ \begin{devicelist} -\major{0}{}{}{Unnamed devices (NFS mounts, loopback devices)} +\major{0}{}{}{Unnamed devices (e.g. non-device mounts)} \minor{0}{}{reserved as null device number} \end{devicelist} @@ -175,7 +176,24 @@ \end{devicelist} \begin{devicelist} -\major{2}{}{char}{Reserved for PTY's $<$tytso@athena.mit.edu$>$} +\major{2}{}{char}{Pseudo-TTY masters} + \minor{0}{/dev/ptyp0}{First PTY master} + \minor{1}{/dev/ptyp1}{Second PTY master} + \minordots + \minor{255}{/dev/ptyef}{256th PTY master} +\end{devicelist} + +\noindent +Pseudo-TTY's are named as follows: +\begin{itemize} +\item Masters are {\file pty}, slaves are {\file tty}; +\item the fourth letter is one of {\file pqrstuvwxyzabcde} indicating +the 1st through 16th series of 16 pseudo-ttys each, and +\item the fifth letter is one of {\file 0123456789abcdef} indicating +the position within the series. +\end{itemize} + +\begin{devicelist} \major{}{}{block}{Floppy disks} \minor{0}{/dev/fd0}{Controller 1, drive 1 autodetect} \minor{1}{/dev/fd1}{Controller 1, drive 2 autodetect} @@ -235,7 +253,12 @@ been deprecated, since the drive type is insignificant for these devices. \begin{devicelist} -\major{3}{}{char}{Reserved for PTY's $<$tytso@athena.mit.edu$>$} +\major{3}{}{char}{Pseudo-TTY slaves} + \minor{0}{/dev/ttyp0}{First PTY slave} + \minor{1}{/dev/ttyp1}{Second PTY slave} + \minordots + \minor{255}{/dev/ttyef}{256th PTY slave} +\\ \major{}{}{block}{First MFM, RLL and IDE hard disk/CD-ROM interface} \minor{0}{/dev/hda}{Master: whole disk (or CD-ROM)} \minor{64}{/dev/hdb}{Slave: whole disk (or CD-ROM)} @@ -271,14 +294,10 @@ \end{devicelist} \noindent -Pseudo-tty's are named as follows: -\begin{itemize} -\item Masters are {\file pty}, slaves are {\file tty}; -\item the fourth letter is one of {\file pqrs} indicating -the 1st, 2nd, 3rd, 4th series of 16 pseudo-ttys each, and -\item the fifth letter is one of {\file 0123456789abcdef} indicating -the position within the series. -\end{itemize} +For compatibility with previous versions of Linux, the first 64 PTYs +are replicated under this device number. This use will be obsolescent +with the release of Linux 1.4 and may be removed in a future version +of Linux. \begin{devicelist} \major{ 5}{}{char }{Alternate TTY devices} @@ -358,6 +377,10 @@ \minor{5}{/dev/atarimouse}{Atari Mouse (68k)} \minor{128}{/dev/beep}{Fancy beep device} \minor{129}{/dev/modreq}{Kernel module load request} + \minor{130}{/dev/watchdog}{Watchdog timer port} + \minor{131}{/dev/temperature}{Machine internal temperature} + \minor{132}{/dev/hwtrap}{Hardware fault trap} + \minor{133}{/dev/exttrp}{External device trap} \end{devicelist} \begin{devicelist} @@ -730,16 +753,16 @@ \begin{devicelist} \major{34}{}{char }{Z8530 HDLC driver} - \minor{0}{/dev/sc1}{First Z8530, first port} - \minor{1}{/dev/sc2}{First Z8530, second port} - \minor{2}{/dev/sc3}{Second Z8530, first port} - \minor{3}{/dev/sc4}{Second Z8530, second port} + \minor{0}{/dev/scc0}{First Z8530, first port} + \minor{1}{/dev/scc1}{First Z8530, second port} + \minor{2}{/dev/scc2}{Second Z8530, first port} + \minor{3}{/dev/scc3}{Second Z8530, second port} \minordots \end{devicelist} \noindent -The author has indicated that the device names will change in a -subsequent version; {\file /dev/sc1} will become {\file /dev/scc0} etc. +In a previous version these files were named {\file /dev/sc1} for +{\file /dev/scc0}, {\file /dev/sc2} for {\file /dev/scc1}, and so on. \begin{devicelist} \major{ }{}{block}{Fourth IDE hard disk/CD-ROM interface} @@ -789,7 +812,16 @@ 3). \begin{devicelist} -\major{37}{--41}{}{Unallocated} +\major{37}{}{char }{IDE tape} + \minor{0}{/dev/ht0}{First IDE tape} + \minor{128}{/dev/nht0}{First IDE tape, no rewind-on-close} +\end{devicelist} + +\noindent +Currently, only one IDE tape drive is supported. + +\begin{devicelist} +\major{38}{--41}{}{Unallocated} \end{devicelist} \begin{devicelist} diff -u --recursive --new-file v1.3.45/linux/Documentation/devices.txt linux/Documentation/devices.txt --- v1.3.45/linux/Documentation/devices.txt Tue Nov 21 13:22:04 1995 +++ linux/Documentation/devices.txt Mon Dec 11 10:46:30 1995 @@ -2,7 +2,7 @@ Maintained by H. Peter Anvin - Last revised: September 20, 1995 + Last revised: December 4, 1995 This list is the successor to Rick Miller's Linux Device List, which he stopped maintaining when he lost network access in 1993. It is a @@ -31,7 +31,7 @@ permission of the author, assuming the author can be contacted without an unreasonable effort. - 0 Unnamed devices (NFS mounts, loopback devices) + 0 Unnamed devices (e.g. non-device mounts) 0 = reserved as null device number 1 char Memory devices @@ -46,8 +46,20 @@ 9 = /dev/urandom Faster, less secure random number gen. block RAM disk 1 = /dev/ramdisk RAM disk + + 2 char Pseudo-TTY masters + 0 = /dev/ptyp0 First PTY master + 1 = /dev/ptyp1 Second PTY master + ... + 256 = /dev/ptyef 256th PTY master - 2 char Reserved for PTY's + Pseudo-tty's are named as follows: + * Masters are "pty", slaves are "tty"; + * the fourth letter is one of pqrstuvwxyzabcde indicating + the 1st through 16th series of 16 pseudo-ttys each, and + * the fifth letter is one of 0123456789abcdef indicating + the position within the series. + block Floppy disks 0 = /dev/fd0 First floppy disk autodetect 1 = /dev/fd1 Second floppy disk autodetect @@ -100,7 +112,12 @@ and E for the 3.5" models have been deprecated, since the drive type is insignificant for these devices. - 3 char Reserved for pty's + 3 char Pseudo-TTY slaves + 0 = /dev/ttyp0 First PTY slave + 1 = /dev/ttyp1 Second PTY slave + ... + 256 = /dev/ttyef 256th PTY slave + block First MFM, RLL and IDE hard disk/CD-ROM interface 0 = /dev/hda Master: whole disk (or CD-ROM) 64 = /dev/hdb Slave: whole disk (or CD-ROM) @@ -133,12 +150,11 @@ ... 255 = /dev/ttysf 64th pseudo-tty slave - Pseudo-tty's are named as follows: - * Masters are "pty", slaves are "tty"; - * the fourth letter is one of p, q, r, s indicating - the 1st, 2nd, 3rd, 4th series of 16 pseudo-ttys each, and - * the fifth letter is one of 0123456789abcdef indicating - the position within the series. + For compatibility with previous versions of Linux, the + first 64 PTYs are replicated under this device + number. This use will be obsolescent with the release + of Linux 1.4 and may be removed in a future version of + Linux. 5 char Alternate TTY devices 0 = /dev/tty Current TTY device @@ -203,9 +219,10 @@ 5 = /dev/atarimouse Atari Mouse (68k) 128 = /dev/beep Fancy beep device 129 = /dev/modreq Kernel module load request - - The use of the suffix -mouse instead of -bm or -aux - has also been used. + 130 = /dev/watchdog Watchdog timer port + 131 = /dev/temperature Machine internal temperature + 132 = /dev/hwtrap Hardware fault trap + 133 = /dev/exttrp External device trap 11 block SCSI CD-ROM devices 0 = /dev/sr0 First SCSI CD-ROM @@ -533,7 +550,13 @@ Partitions are handled in the same way as IDE disks (see major number 3). - 37-41 UNALLOCATED + 37 char IDE tape + 0 = /dev/ht0 First IDE tape + 128 = /dev/nht0 First IDE tape, no rewind-on-close + + Currently, only one IDE tape drive is supported. + + 38-41 UNALLOCATED 42 Demo/sample use diff -u --recursive --new-file v1.3.45/linux/Documentation/networking/arcnet-hardware.txt linux/Documentation/networking/arcnet-hardware.txt --- v1.3.45/linux/Documentation/networking/arcnet-hardware.txt Sat Sep 9 15:26:50 1995 +++ linux/Documentation/networking/arcnet-hardware.txt Thu Nov 30 14:05:22 1995 @@ -39,7 +39,8 @@ but which makes transfers much more reliable than with ethernet. In fact, ARCnet will guarantee that a packet arrives safely at the destination, and even if it can't possibly be delivered properly (ie. because of a cable -break) it will at least tell the sender about it. +break, or because the destination computer does not exist) it will at least +tell the sender about it. In addition, all known ARCnet cards have an (almost) identical programming interface. This means that with one "arcnet" driver you can support any @@ -54,9 +55,9 @@ limit on their packet sizes; standard ARCnet can only send packets that are up to 508 bytes in length. This is smaller than the internet "bare minimum" of 576 bytes, let alone the ethernet MTU of 1500. To compensate, an extra -level of encapsulation is defined by RFC1201 called "packet splitting" which -allows "virtual packets" to grow as large as 64K each, although they are -generally kept down to the ethernet-style 1500 bytes. +level of encapsulation is defined by RFC1201, which I call "packet +splitting," which allows "virtual packets" to grow as large as 64K each, +although they are generally kept down to the ethernet-style 1500 bytes. CABLING ARCNET NETWORKS @@ -69,7 +70,7 @@ - I, Avery Pennarun, tried to arrange it into something that makes sense when all put together. All mistakes, then, are most likely my fault. - Bug me about them. + Bug me about them, and they will probably get fixed. Ideally, according to documentation, ARCnet networks should be connected with 93 Ohm cables with 93 Ohm resistors as terminators. I use TV cable and @@ -86,7 +87,9 @@ IBM Typ 3 100 Ohm up to 100 m So you can see that while 93 Ohms is ideal, you can still go half a -kilometer with 75 Ohm TV cable. +kilometer with 75 Ohm TV cable. A rule of thumb might be handy here, to +help you remember: + Basically any coax cable, up to a ridiculously large distance. The above applies to all known ARCnet cards. Specific to STAR cards, though, Stephen A. Wood has some information: @@ -131,7 +134,7 @@ According to Vojtech Pavlik, there shouldn't be more than one passive hub between two "active ends", an active end being an active hub or an ARCnet -card. +card. That makes sense to me. As for BUS cards, they're even easier (for more than two cards, anyway; you can't get much simpler than direct-connecting two STAR cards with a TV @@ -195,18 +198,20 @@ All ARCnet cards should have a total of four or five different settings: - the I/O address: this is the "port" your ARCnet card is on. Probed - values, as of v0.14, are only from 0x200 through 0x3F0. (If your card - has additional ones, which is possible, please tell me.) This should not - be the same as any other device on your system. According to a doc I - got from Novell, MS Windows prefers values of 0x300 or more, eating - netconnections on my system otherwise. + values in the Linux ARCnet driver are only from 0x200 through 0x3F0. (If + your card has additional ones, which is possible, please tell me.) This + should not be the same as any other device on your system. According to + a doc I got from Novell, MS Windows prefers values of 0x300 or more, + eating netconnections on my system (at least) otherwise. My guess is + this may be because, if your card is at 0x2E0, probing for a serial port + at 0x2E8 will reset the card and probably mess things up royally. - Avery's favourite: 0x300. - - the IRQ: on 8-bit cards, it might be 2 (9), 3, 4, 5, or 7. + - the IRQ: on 8-bit cards, it might be 2 (9), 3, 4, 5, or 7. on 16-bit cards, it might be 2 (9), 3, 4, 5, 7, or 10-15. Make sure this is different from any other card on your system. Note that IRQ2 is the same as IRQ9, as far as Linux is concerned. - - Avery's favourite: IRQ2. + - Avery's favourite: IRQ2 (actually IRQ9). - the memory address: Unlike most cards, ARCnets use "shared memory" for copying buffers around. Make SURE it doesn't conflict with any other @@ -223,31 +228,33 @@ - the station address: Every ARCnet card has its own "unique" network address from 0 to 255. Unlike ethernet, you can set this address - yourself with a jumper. Since it's only 8 bits, you can only have 254 - ARCnet cards on a network. DON'T use 0 or 255, since these are - reserved. (although neat stuff will probably happen if you DO use them). - By the way, if you haven't already guessed, don't set this the same as - any other ARCnet on your network! + yourself with a jumper or switch (or on some cards, with special + software). Since it's only 8 bits, you can only have 254 ARCnet cards + on a network. DON'T use 0 or 255, since these are reserved. (although + neat stuff will probably happen if you DO use them). By the way, if you + haven't already guessed, don't set this the same as any other ARCnet on + your network! - Avery's favourite: 3 and 4. Not that it matters. - There may be ETS1 and ETS2 settings. These may or may not make a - difference, but are used to change the delays used when powering up - a computer on the network. This is only necessary when wiring VERY - long range ARCnet networks, on the order of 4km or so; in any case, - the only real requirement here is that all cards on the network with - ETS1 and ETS2 jumpers have them in the same position. + difference on your card, but are used to change the delays used when + powering up a computer on the network. This is only necessary when + wiring VERY long range ARCnet networks, on the order of 4km or so; in + any case, the only real requirement here is that all cards on the + network with ETS1 and ETS2 jumpers have them in the same position. Here's the all the jumper information I could obtain for individual card -types. Unfortunately, there is a lot of duplicated information here. -Someday, I may get around to actually organizing it. Until then... too much -is better than too little, I say :) +types. The format of this list has changed somewhat; I finally got around +to unduplicating some of the information and making a few other changes, but +didn't get very far yet. If you notice any problems with the info, it's now +officially my fault :( The model # is listed right above specifics for that card, so you should be able to use your text viewer's "search" function to find the entry you want. -If your model isn't listed, and has different settings, PLEASE PLEASE tell -me. I had to figure mine out without the manual, and it WASN'T FUN! +If your model isn't listed and/or has different settings, PLEASE PLEASE +tell me. I had to figure mine out without the manual, and it WASN'T FUN! Even if your ARCnet model isn't listed, but has the same jumpers as another model that is, please e-mail me to say so. @@ -266,7 +273,7 @@ SMC PC550Longboard 16 SMC PC600 16 SMC? LCS-8830-T 16? - Puredata PDI507 16 + Puredata PDI507 8 CNet Tech CN120-Series 8 CNet Tech CN160-Series 16 No Name -- 8/16 @@ -311,9 +318,6 @@ 130, 500, and 600 all have the same switches as Avery's PC100. PC500/600 have several extra, undocumented pins though. (?) - PC110 settings were verified by Stephen A. Wood - - On the other hand, John Edward Bauer said - the PC110 settings are all wrong. In his case, you need to switch all - the 1's with 0's. If you're having problems, try that. - Also, the JP- and S-numbers probably don't match your card exactly. Try to find jumpers/switches with the same number of settings - it's probably more reliable. @@ -323,12 +327,20 @@ (IRQ Setting) IRQ2 IRQ3 IRQ4 IRQ5 IRQ7 Put exactly one jumper on exactly one set of pins. + 1 2 3 4 5 6 7 8 9 10 S1 /----------------------------------\ (I/O and Memory | 1 1 * 0 0 0 0 * 1 1 0 1 | addresses) \----------------------------------/ |--| |--------| |--------| (a) (b) (m) + + WARNING. It's very important when setting these which way + you're holding the card, and which way you think is '1'! + + If you suspect that your settings are not being made + correctly, try reversing the direction or inverting the + switch positions. a: The first digit of the I/O address. Setting Value @@ -473,40 +485,8 @@ ------------------- The eight switches in group S2 are used to set the node ID. -Each node attached to the network must have an unique node ID which -must be diffrent from 0. -Switch 1 serves as the least significant bit (LSB). - -The node ID is the sum of the values of all switches set to "1" -These values are: - Switch | Value - -------|------- - 1 | 1 - 2 | 2 - 3 | 4 - 4 | 8 - 5 | 16 - 6 | 32 - 7 | 64 - 8 | 128 - -Some Examples: - - Switch | Hex | Decimal - 8 7 6 5 4 3 2 1 | Node ID | Node ID - ----------------|---------|--------- - 0 0 0 0 0 0 0 0 | not allowed - 0 0 0 0 0 0 0 1 | 1 | 1 - 0 0 0 0 0 0 1 0 | 2 | 2 - 0 0 0 0 0 0 1 1 | 3 | 3 - . . . | | - 0 1 0 1 0 1 0 1 | 55 | 85 - . . . | | - 1 0 1 0 1 0 1 0 | AA | 170 - . . . | | - 1 1 1 1 1 1 0 1 | FD | 253 - 1 1 1 1 1 1 1 0 | FE | 254 - 1 1 1 1 1 1 1 1 | FF | 255 +These switches work in a way similar to the PC100-series cards; see that +entry for more information. Setting the I/O Base Address @@ -556,7 +536,7 @@ 0 1 0 1 0 | CD000 | CE000 0 1 0 1 1 | CD800 | CE000 | | - 0 1 1 0 0 | D0000 | D2000 (Manufactor's default) + 0 1 1 0 0 | D0000 | D2000 (Manufacturer's default) 0 1 1 0 1 | D0800 | D2000 0 1 1 1 0 | D1000 | D2000 0 1 1 1 1 | D1800 | D2000 @@ -590,10 +570,9 @@ The jumpers labeled EXT1 and EXT2 are used to determine the timeout parameters. These two jumpers are normally left open. -Refer to the COM9026 Data Sheet for alternate configurations. To select a hardware interrupt level set one (only one!) of the jumpers -IRQ2, IRQ3, IRQ4, IRQ5, IRQ7. The Manufactor's default is IRQ2. +IRQ2, IRQ3, IRQ4, IRQ5, IRQ7. The Manufacturer's default is IRQ2. Configuring the PC130E for Star or Bus Topology @@ -658,7 +637,7 @@ The PC550 is equipped with two modular RJ11-type jacks for connection to twisted pair wiring. -It can be used in a star or a daisy-chained network. +It can be used in a star or a daisy-chained (BUS) network. 1 0 9 8 7 6 5 4 3 2 1 6 5 4 3 2 1 @@ -847,7 +826,7 @@ ** Possibly SMC ** LCS-8830-T (16-bit card) ------------------------ - - from Mathias Katzer + - from Mathias Katzer This is a LCS-8830-T made by SMC, I think ('SMC' only appears on one PLCC, nowhere else, not even on the few xeroxed sheets from the manual). @@ -954,11 +933,9 @@ ***************************************************************************** ** PureData Corp ** -PDI507 (16-bit card) +PDI507 (8-bit card) -------------------- - - from Mark Rejhon (slight modifications by - Avery) - - Send questions/suggestions/etc about this text to Mark. + - from Mark Rejhon (slight modifications by Avery) Jumpers: @@ -1868,7 +1845,7 @@ ** No Name ** 8-bit cards ("Made in Taiwan R.O.C.") ----------- - - from Vojtech Pavlik + - from Vojtech Pavlik I have named this ARCnet card "NONAME", since I got only the card with no manual at all and the only text identifying the manufacturer is diff -u --recursive --new-file v1.3.45/linux/Documentation/networking/arcnet.txt linux/Documentation/networking/arcnet.txt --- v1.3.45/linux/Documentation/networking/arcnet.txt Sun Oct 29 11:38:47 1995 +++ linux/Documentation/networking/arcnet.txt Thu Nov 30 14:05:11 1995 @@ -58,8 +58,15 @@ BOINGY - the linux-arcnet@807-city.on.ca mailing list is now so unstable that I can't recommend people even bother with it. I no longer have an account on 807-CITY (though they still graciously forward my mail to me) so -there's not much I can do. If there's sufficient interest (e-mail me!) I -will set one up at my new address, Foxnet. +there's not much I can do. + +However, Tomasz Motylewski has been so kind as to set up a new and improved +mailing list; subscribe by sending a message with the BODY "subscribe +linux-arcnet YOUR REAL NAME" to listserv@tichy.ch.uj.edu.pl. Then, to +submit messages to the list, mail to linux-arcnet@tichy.ch.uj.edu.pl. + +There are mailing list archives at: + http://tichy.ch.uj.edu.pl/lists/linux-arcnet Send all bug (or success) reports to me, then, not the list, since (as I mentioned) the list doesn't work. diff -u --recursive --new-file v1.3.45/linux/MAGIC linux/MAGIC --- v1.3.45/linux/MAGIC Sat Nov 25 19:04:35 1995 +++ linux/MAGIC Mon Dec 11 09:55:42 1995 @@ -50,6 +50,7 @@ Magic Name Number Structure File =========================================================================== +APM_BIOS_MAGIC 0x4101 struct apm_struct include/linux/apm_bios.h CYCLADES_MAGIC 0x4359 struct cyclades_port include/linux/cyclades.h FASYNC_MAGIC 0x4601 struct fasync_struct include/linux/fs.h PTY_MAGIC 0x5001 struct pty_struct drivers/char/pty.c @@ -73,6 +74,7 @@ 0x06 linux/lp.h 0x12 linux/fs.h 0x20 linux/cm206.h +'A' linux/apm_bios.h 'C' linux/soundcard.h 'K' linux/kd.h 'M' linux/soundcard.h diff -u --recursive --new-file v1.3.45/linux/Makefile linux/Makefile --- v1.3.45/linux/Makefile Mon Nov 27 12:48:26 1995 +++ linux/Makefile Mon Dec 11 08:52:55 1995 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 3 -SUBLEVEL = 45 +SUBLEVEL = 46 ARCH = i386 @@ -171,9 +171,11 @@ oldconfig: symlinks $(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.in -xconfig: symlinks - ( cd scripts ; make kconfig.tk) - ./scripts/kconfig.tk +xconfig: symlinks scripts/kconfig.tk + wish -f scripts/kconfig.tk + +scripts/kconfig.tk: + $(MAKE) -C scripts kconfig.tk config: symlinks $(CONFIG_SHELL) scripts/Configure arch/$(ARCH)/config.in @@ -294,7 +296,8 @@ rm -f $(TOPDIR)/include/linux/modules/* distclean: mrproper - rm -f core `find . -name '*.orig' -print` + rm -f core `find . \( -name '*.orig' -o -name '*~' -o -name '*.bak' \ + -o -name '#*#' -o -name '.*.orig' \) -print` backup: mrproper diff -u --recursive --new-file v1.3.45/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v1.3.45/linux/arch/alpha/kernel/entry.S Wed Nov 8 07:11:29 1995 +++ linux/arch/alpha/kernel/entry.S Mon Dec 11 06:56:35 1995 @@ -624,7 +624,7 @@ .quad sys_ftruncate, do_entSys, sys_setgid, sys_sendto, sys_shutdown .quad sys_socketpair, sys_mkdir, sys_rmdir, sys_utimes, do_entSys .quad do_entSys, sys_getpeername, do_entSys, do_entSys, sys_getrlimit - .quad sys_setrlimit, do_entSys, sys_setsid, do_entSys, do_entSys + .quad sys_setrlimit, do_entSys, sys_setsid, sys_quotactl, do_entSys /*150*/ .quad sys_getsockname, do_entSys, do_entSys, do_entSys, do_entSys .quad do_entSys, sys_sigaction, do_entSys, do_entSys, osf_getdirentries .quad osf_statfs, osf_fstatfs, do_entSys, do_entSys, do_entSys diff -u --recursive --new-file v1.3.45/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c --- v1.3.45/linux/arch/alpha/kernel/osf_sys.c Mon Sep 18 14:53:48 1995 +++ linux/arch/alpha/kernel/osf_sys.c Mon Dec 11 06:56:35 1995 @@ -32,7 +32,7 @@ #include #include -extern int do_mount(kdev_t, const char *, char *, int, void *); +extern int do_mount(kdev_t, const char *, const char *, char *, int, void *); extern int do_pipe(int *); extern struct file_operations * get_blkfops(unsigned int); @@ -308,7 +308,7 @@ retval = getdev(tmp.devname, 0, &inode); if (retval) return retval; - retval = do_mount(inode->i_rdev, dirname, "ext2", flags, NULL); + retval = do_mount(inode->i_rdev, tmp.devname, dirname, "ext2", flags, NULL); if (retval) putdev(inode); iput(inode); @@ -328,7 +328,7 @@ retval = getdev(tmp.devname, 1, &inode); if (retval) return retval; - retval = do_mount(inode->i_rdev, dirname, "iso9660", flags, NULL); + retval = do_mount(inode->i_rdev, tmp.devname, dirname, "iso9660", flags, NULL); if (retval) putdev(inode); iput(inode); @@ -348,7 +348,7 @@ dev = get_unnamed_dev(); if (!dev) return -ENODEV; - retval = do_mount(dev, dirname, "proc", flags, NULL); + retval = do_mount(dev, "", dirname, "proc", flags, NULL); if (retval) put_unnamed_dev(dev); return retval; diff -u --recursive --new-file v1.3.45/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S --- v1.3.45/linux/arch/i386/boot/setup.S Fri Nov 17 08:42:24 1995 +++ linux/arch/i386/boot/setup.S Mon Dec 11 09:55:42 1995 @@ -1,32 +1,34 @@ ! ! setup.S Copyright (C) 1991, 1992 Linus Torvalds ! -! This code performs all initialization procedures that should be done -! before entering the protected mode. It's responsible for getting of all -! system data offered by BIOS and for detection / selection of video -! mode. All information is put in a "safe" place: 0x90000-0x901FF, i. e. -! where the boot-block used to be. It is then up to the protected mode +! setup.s is responsible for getting the system data from the BIOS, +! and putting them into the appropriate places in system memory. +! both setup.s and system has been loaded by the bootblock. +! +! This code asks the bios for memory/disk/other parameters, and +! puts them in a "safe" place: 0x90000-0x901FF, ie where the +! boot-block used to be. It is then up to the protected mode ! system to read them from there before the area is overwritten ! for buffer-blocks. ! ! Move PS/2 aux init code to psaux.c ! (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92 ! -! Some changes and additional features by Christoph Niemann, +! some changes and additional features by Christoph Niemann, ! March 1993/June 1994 (Christoph.Niemann@linux.org) ! -! Completely new video-mode handling code, VESA mode detection, support -! for new Cirrus Logic cards and some additional changes -! by Martin Mares , October 1995. +! add APM BIOS checking by Stephen Rothwell, May 1994 +! (Stephen.Rothwell@pd.necisa.oz.au) ! -! NOTE! These had better be the same as in bootsect.S! +! NOTE! These had better be the same as in bootsect.s! #define __ASSEMBLY__ #include #include -! Uncomment this if you want the BIOS mode numbers to be listed -!#define SHOW_BIOS_MODES +#ifndef SVGA_MODE +#define SVGA_MODE ASK_VGA +#endif ! Signature words to ensure LILO loaded us right #define SIG1 0xAA55 @@ -47,7 +49,6 @@ entry start start: - ! Bootlin depends on this being done early mov ax,#0x01500 mov dl,#0x81 @@ -74,14 +75,12 @@ ! Part of above routine, this one just prints ascii al prnt1: push ax - push bx push cx xor bh,bh mov cx,#0x01 mov ah,#0x0e int 0x10 pop cx - pop bx pop ax ret @@ -149,10 +148,43 @@ xor bx,bx ! clear bx int 0x16 -! Check for video adapter and its parameters -! Video mode selection is also handled here +! check for EGA/VGA and some config parameters - call video + mov ah,#0x12 + mov bl,#0x10 + int 0x10 + mov [8],ax + mov [10],bx + mov [12],cx + mov ax,#0x5019 + cmp bl,#0x10 + je novga + mov ax,#0x1a00 ! Added check for EGA/VGA discrimination + int 0x10 + mov bx,ax + mov ax,#0x5019 + movb [15],#0 ! by default, no VGA + cmp bl,#0x1a ! 1a means VGA, anything else EGA or lower + jne novga + movb [15],#1 ! we've detected a VGA + call chsvga +novga: mov [14],al + mov ah,#0x03 ! read cursor pos + xor bh,bh ! clear bh + int 0x10 ! save it in known place, con_init fetches + mov [0],dx ! it from 0x90000. + +! Get video-card data: + + mov ah,#0x0f + int 0x10 + mov [4],bx ! bh = display page + mov [6],ax ! al = video mode, ah = window width + xor ax,ax + mov es,ax ! Access low memory + seg es + mov ax,[0x485] ! POINTS - Height of character matrix + mov [16],ax ! Get hd0 data @@ -209,6 +241,48 @@ jz no_psmouse mov [0x1ff],#0xaa ! device present no_psmouse: + +#ifdef CONFIG_APM +! check for APM BIOS + + mov [64],#0 ! version == 0 means no APM BIOS + + mov ax,#0x05300 ! APM BIOS installation check + xor bx,bx + int 0x15 + jc done_apm_bios ! error -> no APM BIOS + + cmp bx,#0x0504d ! check for "PM" signature + jne done_apm_bios ! no signature -> no APM BIOS + + mov [64],ax ! record the APM BIOS version + mov [76],cx ! and flags + and cx,#0x02 ! Is 32 bit supported? + je done_apm_bios ! no ... + + mov ax,#0x05304 ! Disconnect first just in case + xor bx,bx + int 0x15 ! ignore return code + + mov ax,#0x05303 ! 32 bit connect + xor bx,bx + int 0x15 + jc no_32_apm_bios ! error + + mov [66],ax ! BIOS code segment + mov [68],ebx ! BIOS entry point offset + mov [72],cx ! BIOS 16 bit code segment + mov [74],dx ! BIOS data segment + mov [78],si ! BIOS code segment length + mov [80],di ! BIOS data segment length + jmp done_apm_bios + +no_32_apm_bios: + and [76], #0xfffd ! remove 32 bit support bit + +done_apm_bios: +#endif + ! now we want to move to protected mode ... cli ! no interrupts allowed ! @@ -305,16 +379,17 @@ ! Well, now's the time to actually move into protected mode. To make ! things as simple as possible, we do no register set-up or anything, ! we let the gnu-compiled 32-bit programs do that. We just jump to -! absolute address 0x10000, in 32-bit protected mode. +! absolute address 0x00000, in 32-bit protected mode. ! ! Note that the short jump isn't strictly needed, although there are ! reasons why it might be a good idea. It won't hurt in any case. ! - mov ax,#1 ! protected mode (PE) bit + xor ax,ax + inc ax ! protected mode (PE) bit lmsw ax ! This is it! jmp flush_instr flush_instr: - xor bx,bx ! Flag to indicate a boot + mov bx,#0 ! Flag to indicate a boot jmpi 0x1000,KERNEL_CS ! jmp offset 1000 of segment 0x10 (cs) ! This routine checks that the keyboard command queue is empty @@ -334,6 +409,61 @@ test al,#2 ! is input buffer full? jnz empty_8042 ! yes - loop ret +! +! Read a key and return the (US-)ascii code in al, scan code in ah +! +getkey: + xor ah,ah + int 0x16 + ret + +! +! Read a key with a timeout of 30 seconds. The cmos clock is used to get +! the time. +! +getkt: + call gettime + add al,#30 ! wait 30 seconds + cmp al,#60 + jl lminute + sub al,#60 +lminute: + mov cl,al +again: mov ah,#0x01 + int 0x16 + jnz getkey ! key pressed, so get it + call gettime + cmp al,cl + jne again + mov al,#0x20 ! timeout, return default char `space' + ret + +! +! Flush the keyboard buffer +! +flush: mov ah,#0x01 + int 0x16 + jz empty + xor ah,ah + int 0x16 + jmp flush +empty: ret + +! +! Read the cmos clock. Return the seconds in al +! +gettime: + push cx + mov ah,#0x02 + int 0x1a + mov al,dh ! dh contains the seconds + and al,#0x0f + mov ah,dh + mov cl,#0x04 + shr ah,cl + aad + pop cx + ret ! ! Delay is needed after doing i/o @@ -342,199 +472,43 @@ .word 0x00eb ! jmp $+2 ret -! -! Video card / mode detection. We do some hardware testing and build -! a video mode list (placed directly after our code and data). Then we -! choose the right mode given in the configuration or ask the user if -! we are requested to do so. After all, all video parameters are stored -! for later perusal by the kernel. -! +! Routine trying to recognize type of SVGA-board present (if any) +! and if it recognize one gives the choices of resolution it offers. +! If one is found the resolution chosen is given by al,ah (rows,cols). -video: movb [15],#0 ! Default is no VGA - mov ax,[0x01fa] +chsvga: cld push ds - push ds - pop fs ! In this routine: FS=orig. DS - push cs - pop ds ! ES=DS=CS push cs - pop es + mov ax,[0x01fa] + pop ds mov modesave,ax - lea di,modelist ! ES:DI points to current item in our mode list - mov eax,#0x50190000 ! Store current mode: 80x25 - cld - stosd - - mov ah,#0x12 ! Check EGA/VGA - mov bl,#0x10 - int 0x10 - seg fs - mov [10],bx ! Used for identification of VGA in the kernel - cmp bl,#0x10 ! Not EGA nor VGA -> 80x25 only - je selmd1 - - mov eax,#0x5032FFFF ! EGA or VGA: 80x50 supported - stosd - - mov ax,#0x1a00 ! Added check for EGA/VGA discrimination - int 0x10 - cmp al,#0x1a ! 1a means VGA, anything else EGA - jne selmd1 - seg fs - movb [15],#1 ! We've detected a VGA - - mov eax,#0x501cFFFE ! VGA: 80x28 supported - stosd - - lea si,vgatable ! Test all known SVGA adapters -dosvga: lodsw - mov bp,ax ! Default mode table - or ax,ax - jz didsv - lodsw ! Pointer to test routine - push si - push di - push es - mov bx,#0xc000 - mov es,bx - call ax ! Call test routine - pop es - pop di - pop si - or bp,bp - jz dosvga - mov si,bp ! Found, copy the modes - mov ah,#0 -cpsvga: lodsb - or al,al - jz didsv - stosw - movsw - jmp cpsvga - -selmd1: jmp selmd - -didsv: mov ax,#0x4f00 ! Fetch VESA information to ES:DI+0x400 - add di,#0x400 - int 0x10 - sub di,#0x400 - cmp al,#0x4f - jne selmd - lgs bx,(di+0x40e) - cmp (di+0x400),#0x4556 - jne selmd - cmp (di+0x402),#0x4153 - jne selmd - -vesa1: seg gs - mov cx,(bx) - add bx,#2 - cmp cx,#0xffff - je selmd - mov ax,#0x4f01 - add di,#0xc00 - int 0x10 - sub di,#0xc00 - cmp al,#0x4f - jne selmd - testb (di+0xc00),#0x10 ! Is it a text mode? - jne vesa1 - testb (di+0xc00),#0x08 ! Has it colors? - je vesa1 - mov dh,(di+0xc12) ! DX=dimensions, CX=mode - mov dl,(di+0xc14) - - lea si,modelist ! Check if it's already on the list -vesa2: lodsw - lodsw - cmp ax,dx - je vesa1 - cmp si,di - jc vesa2 - - mov ax,cx ! New mode, store it - stosw - mov ax,dx - stosw - jmp vesa1 - -! -! Video mode table built. Determine the mode we should use and set it. -! -selmd: mov ax,modesave - cmp ax,#NORMAL_VGA ! Current mode (80x25) - je defmd1 - cmp ax,#EXTENDED_VGA ! 80x50 mode - je try50 + mov ax,#0xc000 + mov es,ax + mov ax,modesave + cmp ax,#NORMAL_VGA + je defvga + cmp ax,#EXTENDED_VGA + je vga50 cmp ax,#ASK_VGA - jne usemd -banner: lea si,keymsg + jne svga + lea si,msg1 call prtstr call flush nokey: call getkt - cmp al,#0x0d ! ENTER ? - je listm ! yes - manual mode selection - cmp al,#0x20 ! SPACE ? - je defmd1 ! no - repeat + cmp al,#0x0d ! enter ? + je svga ! yes - svga selection + cmp al,#0x20 ! space ? + je defvga ! no - repeat call beep jmp nokey - -defmd1: br defmd - -listm: call listmodes ! List all available modes -keymd: call getkey ! Get key representing mode ID - xor ah,ah - sub al,#0x30 - jc keymd - cmp al,#10 - jc usemd - sub al,#39 - cmp al,#10 - jc keymd - cmp al,#26 - jnc keymd - jmp usemd - -try50: mov ax,#1 ! 80x50 is mode #1 -usemd: shl ax,#2 ! We're requested to set mode in AX - lea si,modelist - add si,ax - cmp si,di - jc mdok - cmp modesave,#ASK_VGA - je keymd - lea si,undefd - call prtstr - jmp banner - -mdok: lodsw ! AX=mode number - cmp ah,#0xff - jz mdspec - or ax,ax - jz mdsetd - or ah,ah - jz mdset - mov bx,ax - mov ax,#0x4f02 -mdset: int 0x10 -mdsetd: lodsb ! AL=number of lines - jmp getpar - -mdspec: inc ax ! Special modes - jz m80x50 - -m80x28: mov ax,#0x1111 ! Setting 80x28 (VGA with EGA font) - xor bl,bl - int 0x10 ! use 9x14 fontset (28 lines on VGA) - mov ah,#0x01 - mov cx,#0x0b0c - int 0x10 ! turn on cursor (scan lines 11 to 12) - mov al,#28 - jmp getpar - -m80x50: mov ax,#0x1112 ! Setting 80x50 (EGA/VGA) +defvga: mov ax,#0x5019 + pop ds + ret +/* extended vga mode: 80x50 */ +vga50: + mov ax,#0x1112 xor bl,bl - int 0x10 ! use 8x8 font set + int 0x10 ! use 8x8 font set (50 lines on VGA) mov ax,#0x1200 mov bl,#0x20 int 0x10 ! use alternate print screen @@ -544,65 +518,28 @@ mov ah,#0x01 mov cx,#0x0607 int 0x10 ! turn on cursor (scan lines 6 to 7) - mov al,#50 - jmp getpar - -defmd: mov al,#25 ! Default is 25 lines - -! -! Correct video mode set. Determine the remaining parameters. -! - -getpar: pop ds ! Restore original DS - mov [14],al ! Number of lines - - mov ah,#0x03 ! read cursor pos - xor bh,bh ! clear bh - int 0x10 ! save it in known place, con_init fetches - mov [0],dx ! it from 0x90000. - - mov ah,#0x0f - int 0x10 - mov [4],bx ! bh = display page - mov [6],ax ! al = video mode, ah = window width - xor ax,ax - mov es,ax ! Access low memory - seg es - mov ax,[0x485] ! POINTS - Height of character matrix - mov [16],ax - - ret ! Well done... - -! -! Table of all known SVGA cards. For each card, we store a pointer to -! a table of video modes supported by the card and a pointer to a routine -! used for testing of presence of the card. -! - -vgatable: - .word s3_md, s3_test - .word ati_md, ati_test - .word ahead_md, ahead_test - .word chips_md, chips_test - .word cirrus2_md, cirrus2_test - .word cirrus1_md, cirrus1_test - .word everex_md, everex_test - .word genoa_md, genoa_test - .word oak_md, oak_test - .word paradise_md, paradise_test - .word trident_md, trident_test - .word tseng_md, tseng_test - .word video7_md, video7_test - .word 0 - + pop ds + mov ax,#0x5032 ! return 80x50 + ret +/* extended vga mode: 80x28 */ +vga28: + pop ax ! clean the stack + mov ax,#0x1111 + xor bl,bl + int 0x10 ! use 9x14 fontset (28 lines on VGA) + mov ah, #0x01 + mov cx,#0x0b0c + int 0x10 ! turn on cursor (scan lines 11 to 12) + pop ds + mov ax,#0x501c ! return 80x28 + ret +/* svga modes */ ! -! Test routines and mode tables: +! test for presence of an S3 VGA chip. The algorithm was taken +! from the SuperProbe package of XFree86 1.2.1 +! report bugs to Christoph.Niemann@linux.org ! - -! S3 - The test algorithm was taken from the SuperProbe package -! for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org - -s3_test: +svga: cld mov cx,#0x0f35 ! we store some constants in cl/ch mov dx,#0x03d4 movb al,#0x38 @@ -667,64 +604,29 @@ repne scasb je no_s31 + lea si,dsc_S3 ! table of descriptions of video modes for BIOS + lea di,mo_S3 ! table of sizes of video modes for my BIOS movb ah,bh movb al,#0x38 - jmp s3rest + call outidx ! restore old value of CRT register 0x38 + br selmod ! go ask for video mode no_s3: movb al,#0x35 ! restore CRT register 0x35 movb ah,bl call outidx -no_s31: xor bp,bp ! Detection failed -s3rest: movb ah,bh - movb al,#0x38 ! restore old value of CRT register 0x38 -outidx: out dx,al ! Write to indexed VGA register - push ax ! AL=index, AH=data, DX=index reg port - mov al,ah - inc dx - out dx,al - dec dx - pop ax - ret - -tstidx: out dx,ax ! OUT DX,AX and inidx -inidx: out dx,al ! Read from indexed VGA register - inc dx ! AL=index, DX=index reg port -> AL=data - in al,dx - dec dx - ret - -idS3: .byte 0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95 - .byte 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0 - -s3_md: .byte 0x54, 0x2b, 0x84 - .byte 0x55, 0x19, 0x84 - .byte 0 - -! ATI cards. +no_s31: movb ah,bh + movb al,#0x38 + call outidx ! restore old value of CRT register 0x38 -ati_test: - lea si,idati + lea si,idati ! Check ATI 'clues' mov di,#0x31 mov cx,#0x09 repe cmpsb - je atiok - xor bp,bp -atiok: ret - -idati: .ascii "761295520" - -ati_md: .byte 0x23, 0x19, 0x84 - .byte 0x33, 0x2c, 0x84 - .byte 0x22, 0x1e, 0x64 - .byte 0x21, 0x19, 0x64 - .byte 0x58, 0x21, 0x50 - .byte 0x5b, 0x1e, 0x50 - .byte 0 - -! AHEAD - -ahead_test: - mov ax,#0x200f + jne noati + lea si,dscati + lea di,moati + br selmod +noati: mov ax,#0x200f ! Check Ahead 'clues' mov dx,#0x3ce out dx,ax inc dx @@ -732,23 +634,11 @@ cmp al,#0x20 je isahed cmp al,#0x21 - je isahed - xor bp,bp -isahed: ret - -ahead_md: - .byte 0x22, 0x2c, 0x84 - .byte 0x23, 0x19, 0x84 - .byte 0x24, 0x1c, 0x84 - .byte 0x2f, 0x32, 0xa0 - .byte 0x32, 0x22, 0x50 - .byte 0x34, 0x42, 0x50 - .byte 0 - -! Chips & Tech. - -chips_test: - mov dx,#0x3c3 + jne noahed +isahed: lea si,dscahead + lea di,moahead + br selmod +noahed: mov dx,#0x3c3 ! Check Chips & Tech. 'clues' in al,dx or al,#0x10 out dx,al @@ -759,20 +649,12 @@ in al,dx and al,#0xef out dx,al - cmp bl,#0xa5 - je cantok - xor bp,bp -cantok: ret - -chips_md: - .byte 0x60, 0x19, 0x84 - .byte 0x61, 0x32, 0x84 - .byte 0 - -! Cirrus Logic 5X0 - -cirrus1_test: - mov dx,#0x3d4 + cmp bl,[idcandt] + jne nocant + lea si,dsccandt + lea di,mocandt + br selmod +nocant: mov dx,#0x3d4 ! Check Cirrus 'clues' mov al,#0x0c out dx,al inc dx @@ -805,76 +687,19 @@ out dx,al in al,dx cmp al,#0x01 - je iscirr -nocirr: xor bp,bp -iscirr: mov dx,#0x3d4 + jne nocirr + call rst3d4 + lea si,dsccirrus + lea di,mocirrus + br selmod +rst3d4: mov dx,#0x3d4 mov al,bl xor ah,ah shl ax,#8 add ax,#0x0c out dx,ax - ret - -cirrus1_md: - .byte 0x1f, 0x19, 0x84 - .byte 0x20, 0x2c, 0x84 - .byte 0x22, 0x1e, 0x84 - .byte 0x31, 0x25, 0x64 - .byte 0 - -! Cirrus Logic 54XX - -cirrus2_test: - mov dx,#0x3c4 - mov al,#6 - call inidx - mov bl,al ! BL=backup - mov al,#6 - xor ah,ah - call tstidx - cmp al,#0x0f - jne c2fail - mov ax,#0x1206 - call tstidx - cmp al,#0x12 - jne c2fail - mov al,#0x1e - call inidx - mov bh,al - and bh,#0xc0 - mov ah,bh - mov al,#0x1e - call tstidx - xor al,bh - and al,#0x3f - jne c2xx - mov al,#0x1e - mov ah,bh - or ah,#0x3f - call tstidx - xor al,bh - xor al,#0x3f - and al,#0x3f -c2xx: pushf - mov al,#0x1e - mov ah,bh - out dx,ax - popf - je c2done -c2fail: xor bp,bp -c2done: mov al,#6 - mov ah,bl - out dx,ax - ret - -cirrus2_md: - .byte 0x14, 0x19, 0x84 - .byte 0x54, 0x2b, 0x84 - .byte 0 - -! Everex / Trident - -everex_test: + ret +nocirr: call rst3d4 ! Check Everex 'clues' mov ax,#0x7000 xor bx,bx int 0x10 @@ -882,32 +707,15 @@ jne noevrx shr dx,#4 cmp dx,#0x678 - je evtrid + je istrid cmp dx,#0x236 - jne evrxok -evtrid: lea bp,trident_md -evrxok: ret - -noevrx: xor bp,bp - ret - -everex_md: - .byte 0x03, 0x22, 0x50 - .byte 0x04, 0x3c, 0x50 - .byte 0x07, 0x2b, 0x64 - .byte 0x08, 0x4b, 0x64 - .byte 0x0a, 0x19, 0x84 - .byte 0x0b, 0x2c, 0x84 - .byte 0x16, 0x1e, 0x50 - .byte 0x18, 0x1b, 0x64 - .byte 0x21, 0x40, 0xa0 - .byte 0x40, 0x1e, 0x84 - .byte 0 - -! Genoa. - -genoa_test: - lea si,idgenoa ! Check Genoa 'clues' + je istrid + lea si,dsceverex + lea di,moeverex + br selmod +istrid: lea cx,ev2tri + jmp cx +noevrx: lea si,idgenoa ! Check Genoa 'clues' xor ax,ax seg es mov al,[0x37] @@ -923,72 +731,32 @@ seg es cmp al,(di) l2: loope l1 - or cx,cx - je isgen - xor bp,bp -isgen: ret - -idgenoa: .byte 0x77, 0x00, 0x99, 0x66 - -genoa_md: - .byte 0x58, 0x20, 0x50 - .byte 0x5a, 0x2a, 0x64 - .byte 0x60, 0x19, 0x84 - .byte 0x61, 0x1d, 0x84 - .byte 0x62, 0x20, 0x84 - .byte 0x63, 0x2c, 0x84 - .byte 0x64, 0x3c, 0x84 - .byte 0x6b, 0x4f, 0x64 - .byte 0x72, 0x3c, 0x50 - .byte 0x74, 0x42, 0x50 - .byte 0x78, 0x4b, 0x64 - .byte 0 - -! OAK - -oak_test: + cmp cx,#0x00 + jne nogen + lea si,dscgenoa + lea di,mogenoa + br selmod +nogen: cld lea si,idoakvga mov di,#0x08 mov cx,#0x08 repe cmpsb - je isoak - xor bp,bp -isoak: ret - -idoakvga: .ascii "OAK VGA " - -oak_md: .byte 0x4e, 0x3c, 0x50 - .byte 0x4f, 0x3c, 0x84 - .byte 0x50, 0x19, 0x84 - .byte 0x51, 0x2b, 0x84 - .byte 0 - -! WD Paradise. - -paradise_test: - lea si,idparadise + jne nooak + lea si,dscoakvga + lea di,mooakvga + br selmod +nooak: cld + lea si,idparadise ! Check Paradise 'clues' mov di,#0x7d mov cx,#0x04 repe cmpsb - je ispara - xor bp,bp -ispara: ret - -idparadise: .ascii "VGA=" - -paradise_md: - .byte 0x41, 0x22, 0x50 - .byte 0x47, 0x1c, 0x84 - .byte 0x55, 0x19, 0x84 - .byte 0x54, 0x2c, 0x84 - .byte 0 - -! Trident. - -trident_test: - mov dx,#0x3c4 + jne nopara + lea si,dscparadise + lea di,moparadise + br selmod +nopara: mov dx,#0x3c4 ! Check Trident 'clues' mov al,#0x0e out dx,al inc dx @@ -1007,24 +775,11 @@ clrb2: out dx,al and ah,#0x0f cmp ah,#0x02 - je istrid - xor bp,bp -istrid: ret - -trident_md: - .byte 0x50, 0x1e, 0x50 - .byte 0x51, 0x2b, 0x50 - .byte 0x52, 0x3c, 0x50 - .byte 0x57, 0x19, 0x84 - .byte 0x58, 0x1e, 0x84 - .byte 0x59, 0x2b, 0x84 - .byte 0x5a, 0x3c, 0x84 - .byte 0 - -! Tseng. - -tseng_test: - mov dx,#0x3cd + jne notrid +ev2tri: lea si,dsctrident + lea di,motrident + jmp selmod +notrid: mov dx,#0x3cd ! Check Tseng 'clues' in al,dx ! Could things be this simple ! :-) mov bl,al mov al,#0x55 @@ -1034,22 +789,11 @@ mov al,bl out dx,al cmp ah,#0x55 - je istsen - xor bp,bp -istsen: ret - -tseng_md: - .byte 0x26, 0x3c, 0x50 - .byte 0x2a, 0x28, 0x64 - .byte 0x23, 0x19, 0x84 - .byte 0x24, 0x1c, 0x84 - .byte 0x22, 0x2c, 0x84 - .byte 0 - -! Video7. - -video7_test: - mov dx,#0x3cc + jne notsen + lea si,dsctseng + lea di,motseng + jmp selmod +notsen: mov dx,#0x3cc ! Check Video7 'clues' in al,dx mov dx,#0x3b4 and al,#0x01 @@ -1078,78 +822,115 @@ mov al,#0x55 xor al,#0xea cmp al,bh - je isvid7 - xor bp,bp -isvid7: ret - -video7_md: - .byte 0x40, 0x2b, 0x50 - .byte 0x43, 0x3c, 0x50 - .byte 0x44, 0x3c, 0x64 - .byte 0x41, 0x19, 0x84 - .byte 0x42, 0x2c, 0x84 - .byte 0x45, 0x1c, 0x84 - .byte 0 - -! -! Displaying of the mode list. -! - -listmodes: - lea si,listhdr + jne novid7 + lea si,dscvideo7 + lea di,movideo7 + jmp selmod +novid7: lea si,dsunknown + lea di,mounknown +selmod: xor cx,cx + mov cl,(di) + mov ax,modesave + cmp ax,#ASK_VGA + je askmod + cmp ax,#NORMAL_VGA + je askmod + cmp al,cl + jl gotmode + push si + lea si,msg4 call prtstr - lea bx,modelist - mov cl,#0x30 -listm1: mov modenr,cl - lea si,modestring + pop si +askmod: push si + lea si,msg2 call prtstr - mov al,(bx+3) + pop si + push si + push cx +tbl: pop bx + push bx + mov al,bl + sub al,cl + call modepr + lodsw + xchg al,ah call dprnt + xchg ah,al + push ax mov al,#0x78 call prnt1 - mov al,(bx+2) + pop ax call dprnt -#ifdef SHOW_BIOS_MODES - mov al,#0x20 - call prnt1 - mov al,#0x28 - call prnt1 - mov al,(bx+1) - call prthex - mov al,(bx) - call prthex - mov al,#0x29 - call prnt1 -#endif - lea si,crlf + push si + lea si,crlf ! print CR+LF call prtstr - add bx,#4 - inc cl - cmp cl,#0x3a - jnz listm2 - mov cl,#0x61 -listm2: cmp bx,di - jc listm1 - lea si,prompt - br prtstr + pop si + loop tbl + pop cx + lea si,msg3 + call prtstr + pop si + add cl,#0x30 + jmp nonum +nonumb: call beep +nonum: call getkey + cmp al,#0x30 ! ascii `0' + jb nonumb + cmp al,#0x3a ! ascii `9' + jbe number + cmp al,#0x61 ! ascii `a' + jb nonumb + cmp al,#0x7a ! ascii `z' + ja nonumb + sub al,#0x27 + cmp al,cl + jae nonumb + sub al,#0x30 + jmp gotmode +number: cmp al,cl + jae nonumb + sub al,#0x30 +gotmode: xor ah,ah + or al,al + beq vga50 + push ax + dec ax + beq vga28 + add di,ax + mov al,(di) + int 0x10 + pop ax + shl ax,#1 + add si,ax + lodsw + pop ds + ret -! Routine to print a hexadecimal byte (AL) on screen. +! Routine to write al into a VGA-register that is +! accessed via an index register +! +! dx contains the address of the index register +! al contains the index +! ah contains the value to write to the data register (dx + 1) +! +! no registers are changed -#ifdef SHOW_BIOS_MODES -prthex: push ax - shr al,#4 - call prth1 +outidx: out dx,al + push ax + mov al,ah + inc dx + out dx,al + dec dx pop ax -prth1: and al,#15 - cmp al,#10 - jc prth2 - add al,#7 -prth2: add al,#0x30 - br prnt1 -#endif + ret +inidx: out dx,al + inc dx + in al,dx + dec dx + ret ! Routine to print a decimal value on screen, the value to be -! printed is put in AL (i.e 0-255). +! printed is put in al (i.e 0-255). dprnt: push ax push cx @@ -1170,65 +951,25 @@ ret ! -! Read a key and return the (US-)ascii code in al, scan code in ah +! Routine to print the mode number key on screen. Mode numbers +! 0-9 print the ascii values `0' to '9', 10-35 are represented by +! the letters `a' to `z'. This routine prints some spaces around the +! mode no. ! -getkey: - xor ah,ah - int 0x16 - ret -! -! Read a key with a timeout of 30 seconds. The cmos clock is used to get -! the time. -! -getkt: - call gettime - add al,#30 ! wait 30 seconds - cmp al,#60 - jl lminute - sub al,#60 -lminute: - mov cl,al -again: mov ah,#0x01 - int 0x16 - jnz getkey ! key pressed, so get it - call gettime - cmp al,cl - jne again - mov al,#0x20 ! timeout, return default char `space' - ret - -! -! Flush the keyboard buffer -! -flush: mov ah,#0x01 - int 0x16 - jz empty - xor ah,ah - int 0x16 - jmp flush -empty: ret - -! -! Read the cmos clock. Return the seconds in al -! -gettime: - push cx - mov ah,#0x02 - int 0x1a - mov al,dh ! dh contains the seconds - and al,#0x0f - mov ah,dh - mov cl,#0x04 - shr ah,cl - aad - pop cx +modepr: push ax + cmp al,#0x0a + jb digit ! Here is no check for number > 35 + add al,#0x27 +digit: add al,#0x30 + mov modenr, al + push si + lea si, modestring + call prtstr + pop si + pop ax ret -! -! Descriptor table for our protected mode transition. -! - gdt: .word 0,0,0,0 ! dummy @@ -1252,36 +993,68 @@ .word 0x800 ! gdt limit=2048, 256 GDT entries .word 512+gdt,0x9 ! gdt base = 0X9xxxx -! -! Assorted messages. -! - -keymsg: .ascii "Press to see video modes available, to continue or wait 30 secs" - db 0x0d, 0x0a, 0x00 -listhdr: .ascii "Mode: COLSxROWS:" +msg1: .ascii "Press to see SVGA-modes available, to continue or wait 30 secs." + db 0x0d, 0x0a, 0x0a, 0x00 +msg2: .ascii "Mode: COLSxROWS:" db 0x0d, 0x0a, 0x0a, 0x00 -prompt: db 0x0d, 0x0a +msg3: db 0x0d, 0x0a .ascii "Choose mode by pressing the corresponding number or letter." crlf: db 0x0d, 0x0a, 0x00 -undefd: .ascii "You passed an undefined mode number to setup. Please choose a new mode." +msg4: .ascii "You passed an undefined mode number to setup. Please choose a new mode." db 0x0d, 0x0a, 0x0a, 0x07, 0x00 modestring: .ascii " " modenr: db 0x00 ! mode number .ascii ": " db 0x00 - -modesave: .word 0 ! Requsted mode ID. + +idati: .ascii "761295520" +idcandt: .byte 0xa5 +idgenoa: .byte 0x77, 0x00, 0x99, 0x66 +idparadise: .ascii "VGA=" +idoakvga: .ascii "OAK VGA " +idS3: .byte 0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95 + .byte 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0 + +! Manufacturer: Numofmodes+2: Mode: +! Number of modes is the number of chip-specific svga modes plus the extended +! modes available on any vga (currently 2) + +moati: .byte 0x06, 0x23, 0x33, 0x22, 0x21 +moahead: .byte 0x07, 0x22, 0x23, 0x24, 0x2f, 0x34 +mocandt: .byte 0x04, 0x60, 0x61 +mocirrus: .byte 0x06, 0x1f, 0x20, 0x22, 0x31 +moeverex: .byte 0x0c, 0x03, 0x04, 0x07, 0x08, 0x0a, 0x0b, 0x16, 0x18, 0x21, 0x40 +mogenoa: .byte 0x0c, 0x58, 0x5a, 0x60, 0x61, 0x62, 0x63, 0x64, 0x72, 0x74, 0x78 +moparadise: .byte 0x04, 0x55, 0x54 +motrident: .byte 0x09, 0x50, 0x51, 0x52, 0x57, 0x58, 0x59, 0x5a +motseng: .byte 0x07, 0x26, 0x2a, 0x23, 0x24, 0x22 +movideo7: .byte 0x08, 0x40, 0x43, 0x44, 0x41, 0x42, 0x45 +mooakvga: .byte 0x08, 0x00, 0x07, 0x4e, 0x4f, 0x50, 0x51 +mo_S3: .byte 0x04, 0x54, 0x55 +mounknown: .byte 0x02 + +! msb = Cols lsb = Rows: +! The first two modes are standard vga modes available on any vga. +! mode 0 is 80x50 and mode 1 is 80x28 + +dscati: .word 0x5032, 0x501c, 0x8419, 0x842c, 0x641e, 0x6419 +dscahead: .word 0x5032, 0x501c, 0x842c, 0x8419, 0x841c, 0xa032, 0x5042 +dsccandt: .word 0x5032, 0x501c, 0x8419, 0x8432 +dsccirrus: .word 0x5032, 0x501c, 0x8419, 0x842c, 0x841e, 0x6425 +dsceverex: .word 0x5032, 0x501c, 0x5022, 0x503c, 0x642b, 0x644b, 0x8419, 0x842c, 0x501e, 0x641b, 0xa040, 0x841e +dscgenoa: .word 0x5032, 0x501c, 0x5020, 0x642a, 0x8419, 0x841d, 0x8420, 0x842c, 0x843c, 0x503c, 0x5042, 0x644b +dscparadise: .word 0x5032, 0x501c, 0x8419, 0x842c +dsctrident: .word 0x5032, 0x501c, 0x501e, 0x502b, 0x503c, 0x8419, 0x841e, 0x842b, 0x843c +dsctseng: .word 0x5032, 0x501c, 0x503c, 0x6428, 0x8419, 0x841c, 0x842c +dscvideo7: .word 0x5032, 0x501c, 0x502b, 0x503c, 0x643c, 0x8419, 0x842c, 0x841c +dscoakvga: .word 0x5032, 0x501c, 0x2819, 0x5019, 0x503c, 0x843c, 0x8419, 0x842b +dsc_S3: .word 0x5032, 0x501c, 0x842b, 0x8419 +dsunknown: .word 0x5032, 0x501c +modesave: .word SVGA_MODE ! This must be last setup_sig1: .word SIG1 setup_sig2: .word SIG2 - -! After our code and data, we'll store the mode list. -! Mode record: .word modenr -! .byte lines -! .byte columns -! Mode numbers used: 0=current, >=0x100=VESA, -1=80x50, -2=80x28 -modelist: .text endtext: diff -u --recursive --new-file v1.3.45/linux/arch/i386/config.in linux/arch/i386/config.in --- v1.3.45/linux/arch/i386/config.in Wed Nov 8 07:11:29 1995 +++ linux/arch/i386/config.in Mon Dec 11 08:49:35 1995 @@ -56,7 +56,7 @@ mainmenu_option next_comment comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)' -bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI +bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then source drivers/cdrom/Config.in fi diff -u --recursive --new-file v1.3.45/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v1.3.45/linux/arch/i386/defconfig Fri Nov 17 08:42:24 1995 +++ linux/arch/i386/defconfig Mon Dec 11 09:55:42 1995 @@ -31,7 +31,9 @@ # # CONFIG_BLK_DEV_HD is not set CONFIG_BLK_DEV_IDE=y +CONFIG_BLK_DEV_IDEATAPI=y CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_TRITON is not set # CONFIG_BLK_DEV_XD is not set @@ -119,6 +121,11 @@ # CONFIG_MS_BUSMOUSE is not set # CONFIG_ATIXL_BUSMOUSE is not set # CONFIG_QIC02_TAPE is not set +# CONFIG_APM is not set +# CONFIG_APM_IGNORE_USER_SUSPEND is not set +# CONFIG_APM_DO_ENABLE is not set +CONFIG_APM_CPU_IDLE=y +# CONFIG_APM_DISPLAY_BLANK is not set # # Sound diff -u --recursive --new-file v1.3.45/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S --- v1.3.45/linux/arch/i386/kernel/head.S Sat Nov 11 17:41:32 1995 +++ linux/arch/i386/kernel/head.S Mon Dec 11 09:55:42 1995 @@ -12,6 +12,7 @@ #include #include #include +#include #define CL_MAGIC_ADDR 0x90020 #define CL_MAGIC 0xA33F @@ -382,7 +383,11 @@ ALIGN .word 0 gdt_descr: +#ifdef CONFIG_APM + .word (11+2*NR_TASKS)*8-1 +#else .word (8+2*NR_TASKS)*8-1 +#endif .long 0xc0000000+SYMBOL_NAME(gdt) /* @@ -399,3 +404,8 @@ .quad 0x0000000000000000 /* not used */ .quad 0x0000000000000000 /* not used */ .fill 2*NR_TASKS,8,0 /* space for LDT's and TSS's etc */ +#ifdef CONFIG_APM + .quad 0x00c09a0000000000 /* APM CS code */ + .quad 0x00809a0000000000 /* APM CS 16 code (16 bit) */ + .quad 0x00c0920000000000 /* APM DS data */ +#endif diff -u --recursive --new-file v1.3.45/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v1.3.45/linux/arch/i386/kernel/process.c Tue Nov 21 13:22:05 1995 +++ linux/arch/i386/kernel/process.c Mon Dec 11 09:55:42 1995 @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include @@ -29,8 +31,15 @@ asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call"); +#ifdef CONFIG_APM +extern int apm_do_idle(void); +extern void apm_do_busy(void); +#endif + static int hlt_counter=0; +#define HARD_IDLE_TIMEOUT (HZ / 3) + void disable_hlt(void) { hlt_counter++; @@ -41,11 +50,41 @@ hlt_counter--; } +static void hard_idle(void) +{ + while (!need_resched) { + if (hlt_works_ok && !hlt_counter) { +#ifdef CONFIG_APM + /* If the APM BIOS is not enabled, or there + is an error calling the idle routine, we + should hlt if possible. We need to check + need_resched again because an interrupt + may have occured in apm_do_idle(). */ + start_bh_atomic(); + if (!apm_do_idle() && !need_resched) + __asm__("hlt"); + end_bh_atomic(); +#else + __asm__("hlt"); +#endif + } + if (need_resched) break; + schedule(); + } +#ifdef CONFIG_APM + apm_do_busy(); +#endif +} + /* * The idle loop on a i386.. */ asmlinkage int sys_idle(void) { +#ifndef __SMP__ + unsigned long start_idle = 0; +#endif + if (current->pid != 0) { /* printk("Wrong process idled\n"); SMP bug check */ @@ -78,10 +117,17 @@ for (;;) { #ifdef __SMP__ if (cpu_data[smp_processor_id()].hlt_works_ok && !hlt_counter && !need_resched) -#else - if (hlt_works_ok && !hlt_counter && !need_resched) -#endif __asm__("hlt"); +#else + if (!start_idle) start_idle = jiffies; + if (jiffies - start_idle > HARD_IDLE_TIMEOUT) { + hard_idle(); + } else { + if (hlt_works_ok && !hlt_counter && !need_resched) + __asm__("hlt"); + } + if (need_resched) start_idle = 0; +#endif schedule(); } } diff -u --recursive --new-file v1.3.45/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v1.3.45/linux/arch/i386/kernel/setup.c Tue Nov 21 13:22:05 1995 +++ linux/arch/i386/kernel/setup.c Mon Dec 11 09:55:42 1995 @@ -23,6 +23,9 @@ #include #include #include +#ifdef CONFIG_APM +#include +#endif #include #include @@ -54,6 +57,9 @@ */ struct drive_info_struct { char dummy[32]; } drive_info; struct screen_info screen_info; +#ifdef CONFIG_APM +struct apm_bios_info apm_bios_info; +#endif unsigned char aux_device_present; extern int ramdisk_size; @@ -67,6 +73,9 @@ */ #define PARAM empty_zero_page #define EXT_MEM_K (*(unsigned short *) (PARAM+2)) +#ifdef CONFIG_APM +#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+64)) +#endif #define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80)) #define SCREEN_INFO (*(struct screen_info *) (PARAM+0)) #define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2)) @@ -95,6 +104,9 @@ ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV); drive_info = DRIVE_INFO; screen_info = SCREEN_INFO; +#ifdef CONFIG_APM + apm_bios_info = APM_BIOS_INFO; +#endif aux_device_present = AUX_DEVICE_INFO; memory_end = (1<<20) + (EXT_MEM_K<<10); memory_end &= PAGE_MASK; diff -u --recursive --new-file v1.3.45/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c --- v1.3.45/linux/arch/i386/kernel/time.c Wed Oct 4 14:14:29 1995 +++ linux/arch/i386/kernel/time.c Mon Dec 11 09:55:42 1995 @@ -23,6 +23,7 @@ #include #include +#include #define TIMER_IRQ 0 @@ -313,9 +314,8 @@ )*60 + sec; /* finally seconds */ } -void time_init(void) +unsigned long get_cmos_time(void) { - void (*irq_handler)(int, struct pt_regs *); unsigned int year, mon, day, hour, min, sec; int i; @@ -350,11 +350,21 @@ } if ((year += 1900) < 1970) year += 100; - xtime.tv_sec = mktime(year, mon, day, hour, min, sec); + return mktime(year, mon, day, hour, min, sec); +} + +void time_init(void) +{ + void (*irq_handler)(int, struct pt_regs *); + xtime.tv_sec = get_cmos_time(); xtime.tv_usec = 0; /* If we have the CPU hardware time counters, use them */ - irq_handler = timer_interrupt; + irq_handler = timer_interrupt; +#ifndef CONFIG_APM + /* Don't use them if a suspend/resume could + corrupt the timer value. This problem + needs more debugging. */ if (x86_capability & 16) { irq_handler = pentium_timer_interrupt; do_gettimeoffset = do_fast_gettimeoffset; @@ -363,6 +373,7 @@ :"=a" (((unsigned long *) &init_timer_cc)[0]), "=d" (((unsigned long *) &init_timer_cc)[1])); } +#endif if (request_irq(TIMER_IRQ, irq_handler, 0, "timer") != 0) panic("Could not allocate timer IRQ!"); } diff -u --recursive --new-file v1.3.45/linux/drivers/block/Config.in linux/drivers/block/Config.in --- v1.3.45/linux/drivers/block/Config.in Wed Nov 8 07:11:30 1995 +++ linux/drivers/block/Config.in Mon Dec 11 08:49:35 1995 @@ -15,7 +15,11 @@ bool ' Use new IDE driver for primary/secondary i/f' CONFIG_BLK_DEV_IDE fi if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then - bool ' Include support for IDE/ATAPI CDROMs' CONFIG_BLK_DEV_IDECD + bool ' Include support for IDE/ATAPI CDROM or TAPE' CONFIG_BLK_DEV_IDEATAPI + if [ "$CONFIG_BLK_DEV_IDEATAPI" = "y" ]; then + bool ' Include support for IDE/ATAPI CDROM' CONFIG_BLK_DEV_IDECD + bool ' Include ALPHA support for IDE/ATAPI TAPE' CONFIG_BLK_DEV_IDETAPE + fi if [ "$CONFIG_PCI" = "y" ]; then bool ' PCI Triton IDE Bus Master DMA support' CONFIG_BLK_DEV_TRITON fi diff -u --recursive --new-file v1.3.45/linux/drivers/block/MAKEDEV.ide linux/drivers/block/MAKEDEV.ide --- v1.3.45/linux/drivers/block/MAKEDEV.ide Tue Aug 15 20:39:00 1995 +++ linux/drivers/block/MAKEDEV.ide Mon Dec 11 08:49:53 1995 @@ -27,3 +27,19 @@ makedevs hdf 33 64 makedevs hdg 34 0 makedevs hdh 34 64 + +# Create the ide-tape rewinding character device. + +rm -f /dev/ht0 +echo mknod /dev/ht0 c 37 0 + mknod /dev/ht0 c 37 0 +chown root:disk /dev/ht0 +chmod 660 /dev/ht0 + +# Create the ide-tape non rewinding character device. + +rm -f /dev/nht0 +echo mknod /dev/nht0 c 37 128 + mknod /dev/nht0 c 37 128 +chown root:disk /dev/nht0 +chmod 660 /dev/nht0 diff -u --recursive --new-file v1.3.45/linux/drivers/block/Makefile linux/drivers/block/Makefile --- v1.3.45/linux/drivers/block/Makefile Mon Oct 23 18:02:01 1995 +++ linux/drivers/block/Makefile Mon Dec 11 08:49:35 1995 @@ -44,6 +44,10 @@ L_OBJS += ide-cd.o endif +ifeq ($(CONFIG_BLK_DEV_IDETAPE),y) +L_OBJS += ide-tape.o +endif + ifeq ($(CONFIG_BLK_DEV_XD),y) L_OBJS += xd.o endif diff -u --recursive --new-file v1.3.45/linux/drivers/block/README.ide linux/drivers/block/README.ide --- v1.3.45/linux/drivers/block/README.ide Mon Nov 27 12:48:27 1995 +++ linux/drivers/block/README.ide Mon Dec 11 08:49:53 1995 @@ -1,4 +1,4 @@ -README.ide -- Information regarding ide.c and ide-cd.c (IDE driver in 1.3.x) +README.ide -- Information regarding ide.c and ide-cd.c (IDE driver in 1.3.xx) ================================================================================ Supported by: mlord@bnr.ca -- disks, interfaces, probing snyder@fnald0.fnal.gov -- cdroms, ATAPI, audio diff -u --recursive --new-file v1.3.45/linux/drivers/block/cmd640.c linux/drivers/block/cmd640.c --- v1.3.45/linux/drivers/block/cmd640.c Mon Nov 27 12:48:27 1995 +++ linux/drivers/block/cmd640.c Mon Dec 11 08:49:53 1995 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/cmd640.c Version 0.01 Nov 16, 1995 + * linux/drivers/block/cmd640.c Version 0.02 Nov 30, 1995 * * Copyright (C) 1995 Linus Torvalds & author (see below) */ @@ -13,8 +13,56 @@ * Version 0.01 Initial version, hacked out of ide.c, * and #include'd rather than compiled separately. * This will get cleaned up in a subsequent release. + * + * Version 0.02 Fixes for vlb initialization code, enable + * read-ahead for versions 'B' and 'C' of chip by + * default, some code cleanup. + * */ +/* + * CMD640 specific registers definition. + */ + +#define VID 0x00 +#define DID 0x02 +#define PCMD 0x04 +#define PSTTS 0x06 +#define REVID 0x08 +#define PROGIF 0x09 +#define SUBCL 0x0a +#define BASCL 0x0b +#define BaseA0 0x10 +#define BaseA1 0x14 +#define BaseA2 0x18 +#define BaseA3 0x1c +#define INTLINE 0x3c +#define INPINE 0x3d + +#define CFR 0x50 +#define CFR_DEVREV 0x03 +#define CFR_IDE01INTR 0x04 +#define CFR_DEVID 0x18 +#define CFR_AT_VESA_078h 0x20 +#define CFR_DSA1 0x40 +#define CFR_DSA0 0x80 + +#define CNTRL 0x51 +#define CNTRL_DIS_RA0 0x40 +#define CNTRL_DIS_RA1 0x80 +#define CNTRL_ENA_2ND 0x08 + +#define CMDTIM 0x52 +#define ARTTIM0 0x53 +#define DRWTIM0 0x54 +#define ARTTIM1 0x55 +#define DRWTIM1 0x56 +#define ARTTIM23 0x57 +#define DIS_RA2 0x04 +#define DIS_RA3 0x08 +#define DRWTIM23 0x58 +#define BRST 0x59 + /* Interface to access cmd640x registers */ static void (*put_cmd640_reg)(int key, int reg_no, int val); static byte (*get_cmd640_reg)(int key, int reg_no); @@ -24,6 +72,7 @@ static int cmd640_chip_version; static int cmd640_key; static byte is_cmd640[MAX_HWIFS]; +static int bus_speed; /* MHz */ /* * For some unknown reasons pcibios functions which read and write registers @@ -51,7 +100,7 @@ save_flags(flags); cli(); outl_p((reg_no & 0xfc) | key, 0xcf8); - b = inb(0xcfc + (reg_no & 3)); + b = inb_p(0xcfc + (reg_no & 3)); restore_flags(flags); return b; } @@ -78,7 +127,7 @@ save_flags(flags); cli(); outb_p(0x10, 0xcf8); - b = inb(key + reg_no); + b = inb_p(key + reg_no); outb_p(0, 0xcf8); restore_flags(flags); return b; @@ -92,8 +141,8 @@ save_flags(flags); cli(); - outb(reg_no, key + 8); - outb(val, key + 0xc); + outb_p(reg_no, key + 8); + outb_p(val, key + 0xc); restore_flags(flags); } @@ -104,8 +153,8 @@ save_flags(flags); cli(); - outb(reg_no, key + 8); - b = inb(key + 0xc); + outb_p(reg_no, key + 8); + b = inb_p(key + 0xc); restore_flags(flags); return b; } @@ -164,12 +213,12 @@ static int probe_for_cmd640_vlb(void) { byte b; - outb(0x50, 0x178); + outb(CFR, 0x178); b = inb(0x17c); - if (b == 0xff || b == 0 || (b & 0x20)) { - outb(0x50, 0xc78); + if (b == 0xff || b == 0 || (b & CFR_AT_VESA_078h)) { + outb(CFR, 0x78); b = inb(0x7c); - if (b == 0xff || b == 0 || !(b & 0x20)) + if (b == 0xff || b == 0 || !(b & CFR_AT_VESA_078h)) return 0; cmd640_key = 0x70; } else { @@ -186,7 +235,10 @@ int ide_probe_for_cmd640x(void) { - int i; + int i; + int second_port; + int read_ahead; + byte b; for (i = 0; i < MAX_HWIFS; i++) is_cmd640[i] = 0; @@ -217,19 +269,60 @@ * Documented magic. */ - cmd640_chip_version = get_cmd640_reg(cmd640_key, 0x50) & 3; + cmd640_chip_version = get_cmd640_reg(cmd640_key, CFR) & CFR_DEVREV; if (cmd640_chip_version == 0) { printk ("ide: wrong CMD640 version -- 0\n"); return 0; } - put_cmd640_reg(cmd640_key, 0x51, get_cmd640_reg(cmd640_key, 0x51) | 0xc8); - put_cmd640_reg(cmd640_key, 0x57, 0); - put_cmd640_reg(cmd640_key, 0x57, get_cmd640_reg(cmd640_key, 0x57) | 0x0c); + /* + * Do not initialize secondary controller for vlbus + */ + second_port = (bus_type != vlb); + + /* + * Set the maximum allowed bus speed (it is safest until we + * find how detect bus speed) + * Normally PCI bus runs at 33MHz, but often works overclocked to 40 + */ + bus_speed = (bus_type == vlb) ? 50 : 40; + +#if 0 /* don't know if this is reliable yet */ + /* + * Enable readahead for versions above 'A' + */ + read_ahead = (cmd640_chip_version > 1); +#else + read_ahead = 0; +#endif + /* + * Setup Control Register + */ + b = get_cmd640_reg(cmd640_key, CNTRL); + if (second_port) + b |= CNTRL_ENA_2ND; + else + b &= ~CNTRL_ENA_2ND; + if (read_ahead) + b &= ~(CNTRL_DIS_RA0 | CNTRL_DIS_RA1); + else + b |= (CNTRL_DIS_RA0 | CNTRL_DIS_RA1); + put_cmd640_reg(cmd640_key, CNTRL, b); + + /* + * Initialize 2nd IDE port, if required + */ + if (second_port) { + /* We reset timings, and setup read-ahead */ + b = read_ahead ? 0 : (DIS_RA2 | DIS_RA3); + put_cmd640_reg(cmd640_key, ARTTIM23, b); + put_cmd640_reg(cmd640_key, DRWTIM23, 0); + } serialized = 1; - printk("ide: buggy CMD640 interface at "); + printk("ide: buggy CMD640%c interface at ", + 'A' - 1 + cmd640_chip_version); switch (bus_type) { case vlb : printk("local bus, port 0x%x", cmd640_key); @@ -247,17 +340,17 @@ /* * Reset interface timings */ + put_cmd640_reg(cmd640_key, CMDTIM, 0); - put_cmd640_reg(cmd640_key, 0x58, 0); - put_cmd640_reg(cmd640_key, 0x52, 0); - - printk("\n ... serialized, disabled read-ahead, secondary interface enabled\n"); + printk("\n ... serialized, %s read-ahead, secondary interface %s\n", + read_ahead ? "enabled" : "disabled", + second_port ? "enabled" : "disabled"); return 1; } static int as_clocks(int a) { - switch (a & 0xf0) { + switch (a & 0xc0) { case 0 : return 4; case 0x40 : return 2; case 0x80 : return 3; @@ -274,42 +367,39 @@ int b_reg; byte b; int r52; + static int a = 0; - b_reg = if_num ? 0x57 : dr_num ? 0x55 : 0x53; + b_reg = if_num ? ARTTIM23 : dr_num ? ARTTIM1 : ARTTIM0; if (if_num == 0) { put_cmd640_reg(cmd640_key, b_reg, r1); put_cmd640_reg(cmd640_key, b_reg + 1, r2); } else { b = get_cmd640_reg(cmd640_key, b_reg); - if ((b&1) == 0) { - put_cmd640_reg(cmd640_key, b_reg, r1); - } else { - if (as_clocks(b) < as_clocks(r1)) - put_cmd640_reg(cmd640_key, b_reg, r1); - } - b = get_cmd640_reg(cmd640_key, b_reg + 1); - if (b == 0) { + if (a == 0 || as_clocks(b) < as_clocks(r1)) + put_cmd640_reg(cmd640_key, b_reg, (b & 0xc0) | r1); + + if (a == 0) { put_cmd640_reg(cmd640_key, b_reg + 1, r2); } else { - r52 = (b&0xf) < (r2&0xf) ? (r2&0xf) : (b&0xf); + b = get_cmd640_reg(cmd640_key, b_reg + 1); + r52 = (b&0x0f) < (r2&0x0f) ? (r2&0x0f) : (b&0x0f); r52 |= (b&0xf0) < (r2&0xf0) ? (r2&0xf0) : (b&0xf0); put_cmd640_reg(cmd640_key, b_reg+1, r52); } + a = 1; } - b = get_cmd640_reg(cmd640_key, 0x52); + b = get_cmd640_reg(cmd640_key, CMDTIM); if (b == 0) { - put_cmd640_reg(cmd640_key, 0x52, r2); + put_cmd640_reg(cmd640_key, CMDTIM, r2); } else { - r52 = (b&0xf) < (r2&0xf) ? (r2&0xf) : (b&0xf); + r52 = (b&0x0f) < (r2&0x0f) ? (r2&0x0f) : (b&0x0f); r52 |= (b&0xf0) < (r2&0xf0) ? (r2&0xf0) : (b&0xf0); - put_cmd640_reg(cmd640_key, 0x52, r52); + put_cmd640_reg(cmd640_key, CMDTIM, r52); } } -static int bus_speed = 33; /* MHz */ - struct pio_timing { int mc_time; /* Minimal cycle time (ns) */ int av_time; /* Address valid to DIOR-/DIOW- setup (ns) */ @@ -385,10 +475,10 @@ int i; p_base = if_num ? 0x170 : 0x1f0; - outb(3, p_base + 1); - outb(mode_num | 8, p_base + 2); - outb((drv_num | 0xa) << 4, p_base + 6); - outb(0xef, p_base + 7); + outb_p(3, p_base + 1); + outb_p(mode_num | 8, p_base + 2); + outb_p((drv_num | 0xa) << 4, p_base + 6); + outb_p(0xef, p_base + 7); for (i = 0; (i < 100) && (inb (p_base + 7) & 0x80); i++) delay_10ms(); } @@ -442,3 +532,4 @@ cmd640_set_timing(interface_number, drive_number, r1, r2); printk ("Mode and Timing set to PIO%d (0x%x 0x%x)\n", max_pio, r1, r2); } + diff -u --recursive --new-file v1.3.45/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c --- v1.3.45/linux/drivers/block/ide-cd.c Sat Nov 25 19:04:39 1995 +++ linux/drivers/block/ide-cd.c Mon Dec 11 08:49:35 1995 @@ -72,6 +72,7 @@ * 3.03 Oct 27, 1995 -- Some Creative drives have an id of just `CD'. * `DCI-2S10' drives are broken too. * 3.04 Nov 20, 1995 -- So are Vertros drives. + * 3.05 Dec 1, 1995 -- Changes to go with overhaul of ide.c and ide-tape.c * * 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. @@ -202,7 +203,7 @@ ide_input_data (drive, buffer, bytecount / 4); if ((bytecount & 0x03) >= 2) { - insw (IDE_DATA_REG, buffer + (bytecount & ~0x03), 1); + insw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1); } } @@ -214,7 +215,7 @@ ide_output_data (drive, buffer, bytecount / 4); if ((bytecount & 0x03) >= 2) { - outsw (IDE_DATA_REG, buffer + (bytecount & ~0x03), 1); + outsw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1); } } @@ -501,27 +502,8 @@ { struct request *rq; struct packet_command *pc; - unsigned long flags; int len; - int major = HWIF(drive)->major; - - save_flags (flags); - cli (); /* safety */ - - rq = HWGROUP(drive)->rq; - - /* If we're processing a request, put it back on the request queue. */ - if (rq != NULL) - { - restore_request (rq); - rq->next = blk_dev[major].current_request; - blk_dev[major].current_request = rq; - HWGROUP(drive)->rq = NULL; - } - - restore_flags (flags); - /* If the request didn't explicitly specify where to put the sense data, use the statically allocated structure. */ if (reqbuf == NULL) @@ -544,29 +526,15 @@ pc->buffer = (char *)reqbuf; pc->buflen = len; pc->sense_data = (struct atapi_request_sense *)failed_command; - + + /* stuff the sense request in front of our current request */ + rq = &HWIF(drive)->request_sense_request; - rq->rq_status = RQ_ACTIVE; - rq->rq_dev = MKDEV (major, (drive->select.b.unit) << PARTN_BITS); + ide_init_drive_cmd (rq); rq->cmd = REQUEST_SENSE_COMMAND; - rq->errors = 0; - rq->sector = 0; - rq->nr_sectors = 0; - rq->current_nr_sectors = 0; rq->buffer = (char *)pc; rq->sem = sem; - rq->bh = NULL; - rq->bhtail = NULL; - rq->next = NULL; - - save_flags (flags); - cli (); /* safety */ - - /* Stick it onto the front of the queue. */ - rq->next = blk_dev[major].current_request; - blk_dev[major].current_request = rq; - - restore_flags (flags); + (void) ide_do_drive_cmd (drive, rq, ide_preempt); } @@ -638,8 +606,8 @@ struct packet_command *pc = (struct packet_command *)rq->buffer; pc->stat = 1; cdrom_end_request (1, drive); - if (ide_error (drive, "request sense failure", stat)) - return 1; + ide_error (drive, "request sense failure", stat); + return 1; } else if (cmd == PACKET_COMMAND) @@ -734,8 +702,8 @@ /* If there were other errors, go to the default handler. */ else if ((err & ~ABRT_ERR) != 0) { - if (ide_error (drive, "cdrom_decode_status", stat)) - return 1; + ide_error (drive, "cdrom_decode_status", stat); + return 1; } /* Else, abort if we've racked up too many retries. */ @@ -752,7 +720,6 @@ } /* Retry, or handle the next request. */ - IDE_DO_REQUEST; return 1; } @@ -781,7 +748,7 @@ if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { - ide_set_handler (drive, handler); + ide_set_handler (drive, handler, WAIT_CMD); OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */ } else @@ -819,7 +786,7 @@ } /* Arm the interrupt handler. */ - ide_set_handler (drive, handler); + ide_set_handler (drive, handler, WAIT_CMD); /* Send the command to the device. */ cdrom_out_bytes (drive, cmd_buf, cmd_len); @@ -925,7 +892,6 @@ } cdrom_end_request (0, drive); - IDE_DO_REQUEST; return -1; } @@ -961,7 +927,6 @@ else cdrom_end_request (1, drive); - IDE_DO_REQUEST; return; } @@ -976,7 +941,6 @@ drive->name, len); printk (" This drive is not supported by this version of the driver\n"); cdrom_end_request (0, drive); - IDE_DO_REQUEST; return; } @@ -1040,7 +1004,7 @@ /* Done moving data! Wait for another interrupt. */ - ide_set_handler (drive, &cdrom_read_intr); + ide_set_handler (drive, &cdrom_read_intr, WAIT_CMD); } @@ -1138,7 +1102,6 @@ printk ("%s: cdrom_start_read_continuation: buffer botch (%ld)\n", drive->name, rq->current_nr_sectors); cdrom_end_request (0, drive); - IDE_DO_REQUEST; return; } @@ -1252,7 +1215,6 @@ pc->stat = 1; cdrom_end_request (1, drive); } - IDE_DO_REQUEST; return; } @@ -1327,7 +1289,7 @@ } /* Now we wait for another interrupt. */ - ide_set_handler (drive, &cdrom_pc_intr); + ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD); } @@ -1367,40 +1329,6 @@ schedule (); } - -static -void cdrom_queue_request (ide_drive_t *drive, struct request *req) -{ - unsigned long flags; - struct request **p, **pfirst; - int major = HWIF(drive)->major; - struct semaphore sem = MUTEX_LOCKED; - - req->rq_dev = MKDEV (major, (drive->select.b.unit) << PARTN_BITS); - req->rq_status = RQ_ACTIVE; - req->sem = &sem; - req->errors = 0; - req->next = NULL; - - save_flags (flags); - cli (); - - p = &blk_dev[major].current_request; - pfirst = p; - while ((*p) != NULL) - { - p = &((*p)->next); - } - *p = req; - if (p == pfirst) - blk_dev[major].request_fn (); - - down (&sem); - - restore_flags (flags); -} - - static int cdrom_queue_packet_command (ide_drive_t *drive, struct packet_command *pc) { @@ -1416,15 +1344,10 @@ /* Start of retry loop. */ do { + ide_init_drive_cmd (&req); req.cmd = PACKET_COMMAND; - req.sector = 0; - req.nr_sectors = 0; - req.current_nr_sectors = 0; req.buffer = (char *)pc; - req.bh = NULL; - req.bhtail = NULL; - - cdrom_queue_request (drive, &req); + (void) ide_do_drive_cmd (drive, &req, ide_wait); if (pc->stat != 0) { @@ -1491,8 +1414,8 @@ else if (rq -> cmd == RESET_DRIVE_COMMAND) { cdrom_end_request (1, drive); - if (ide_do_reset (drive)) - return; + ide_do_reset (drive); + return; } else if (rq -> cmd != READ) @@ -2434,10 +2357,9 @@ case CDROMRESET: { struct request req; - memset (&req, 0, sizeof (req)); + ide_init_drive_cmd (&req); req.cmd = RESET_DRIVE_COMMAND; - cdrom_queue_request (drive, &req); - return 0; + return ide_do_drive_cmd (drive, &req, ide_wait); } #endif diff -u --recursive --new-file v1.3.45/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c --- v1.3.45/linux/drivers/block/ide-tape.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/block/ide-tape.c Mon Dec 11 10:15:05 1995 @@ -0,0 +1,3313 @@ +/* + * linux/drivers/block/ide-tape.c Version 1.0 - ALPHA Dec 3, 1995 + * + * Copyright (C) 1995 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 + * Institute Of Technology, with the guide of Avner Lottem and Dr. Ilana David. + * + * It is hereby placed under the terms of the GNU general public license. + * (See linux/COPYING). + */ + +/* + * IDE ATAPI streaming tape driver. + * + * This driver is a part of the Linux ide driver and works in co-operation + * with linux/drivers/block/ide.c. + * + * This driver provides both a block device and a character device interface to + * the tape. The driver, in co-operation with ide.c, basically traverses the + * request-list for the block device interface. The character device interface, + * on the other hand, creates new requests, adds them to the request-list + * of the block device, and waits for their completion. + * + * The block device major and minor numbers are determined from the + * tape relative position in the ide interfaces, as explained in ide.c. + * + * The character device interface consists of two devices: + * + * ht0 major=37,minor=0 first IDE tape, rewind on close. + * nht0 major=37,minor=128 first IDE tape, no rewind on close. + * + * Run /usr/src/linux/drivers/block/MAKEDEV.ide to create the above entries. + * We currently support only one ide tape drive. + * + * Although we do support requests which originate from the buffer cache to + * some extent, it is recommended to use the character device interface when + * performing a long read or write operation (relative to the amount of free + * memory in your system). Otherwise, free memory will be used to cache tape + * blocks, those cached blocks won't be used, Linux's responsiveness will + * suffer as we start to swap. + * + * The general magnetic tape commands compatible interface, as defined by + * include/linux/mtio.h, is accessible through the character device. + * Our own ide-tape ioctl's can can be issued to either the block device or + * the character device. + * + * Opening the block device interface will be refused by default. + * + * Testing was done with a 2 GB CONNER CTMA 4000 IDE ATAPI Streaming Tape Drive. + * + * Ver 0.1 Nov 1 95 Pre-working code :-) + * Ver 0.2 Nov 23 95 A short backup (few megabytes) and restore procedure + * was successful ! (Using tar cvf ... on the block + * device interface). + * A longer backup resulted in major swapping, bad + * overall Linux performance and eventually failed as + * we received non serial read-ahead requests from the + * buffer cache. + * Ver 0.3 Nov 28 95 Long backups are now possible, thanks to the + * character device interface. Linux's responsiveness + * and performance doesn't seem to be much affected + * from the background backup procedure. + * Some general mtio.h magnetic tape operations are + * now supported by our character device. As a result, + * popular tape utilities are starting to work with + * ide tapes :-) + * The following configurations were tested: + * 1. An IDE ATAPI TAPE shares the same interface + * and irq with an IDE ATAPI CDROM. + * 2. An IDE ATAPI TAPE shares the same interface + * and irq with a normal IDE disk. + * Both configurations seemed to work just fine ! + * However, to be on the safe side, it is meanwhile + * recommended to give the IDE TAPE its own interface + * and irq. + * The one thing which needs to be done here is to + * add a "request postpone" feature to ide.c, + * so that we won't have to wait for the tape to finish + * performing a long media access (DSC) request (such + * as a rewind) before we can access the other device + * on the same interface. This effect doesn't disturb + * normal operation most of the time because read/write + * requests are relatively fast, and once we are + * performing one tape r/w request, a lot of requests + * from the other device can be queued and ide.c will + * service all of them after this single tape request. + * Ver 1.0 ??? Integrated into Linux 1.3.??? development tree. + * On each read / write request, we now ask the drive + * if we can transfer a constant number of bytes + * (a parameter of the drive) only to its buffers, + * without causing actual media access. If we can't, + * we just wait until we can by polling the DSC bit. + * This ensures that while we are not transferring + * more bytes than the constant reffered to above, the + * interrupt latency will not become too high and + * we won't cause an interrupt timeout, as happened + * occasionally in the previous version. + * While polling for DSC, the current request is + * postponed and ide.c is free to handle requests from + * the other device. This is handled transparently to + * ide.c. The hwgroup locking method which was used + * in the previous version was removed. + * Use of new general features which are provided by + * ide.c for use with atapi devices. + * (Programming done by Mark Lord) + * Few potential bug fixes (Again, suggested by Mark) + * Single character device data transfers are now + * not limited in size, as they were before. + * We are asking the tape about its recommended + * transfer unit and send a larger data transfer + * as several transfers of the above size. + * For best results, use an integral number of this + * basic unit (which is shown during driver + * initialization). I will soon add an ioctl to get + * this important parameter. + * Our data transfer buffer is allocated on startup, + * rather than before each data transfer. This should + * ensure that we will indeed have a data buffer. + * + * We are currently in an *alpha* stage. The driver is not complete and not + * much tested. I would strongly suggest to: + * + * 1. Connect the tape to a separate interface and irq. + * 2. Be truly prepared for a kernel crash and the resulting data loss. + * 3. Don't rely too much on the resulting backups. + * + * Other than that, enjoy ! + * + * Here are some words from the first releases of hd.c, which are quoted + * in ide.c and apply here as well: + * + * | Special care is recommended. Have Fun! + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define _IDE_TAPE_C /* For ide_end_request in blk.h */ + +/* + * Main Linux ide driver include file + * + * Automatically includes our first include file - ide-tape1.h. + */ + +#include "ide.h" + +/* + * Supported ATAPI tape drives packet commands + */ + +#define IDETAPE_TEST_UNIT_READY_CMD 0x00 +#define IDETAPE_REWIND_CMD 0x01 +#define IDETAPE_REQUEST_SENSE_CMD 0x03 +#define IDETAPE_READ_CMD 0x08 +#define IDETAPE_WRITE_CMD 0x0a +#define IDETAPE_WRITE_FILEMARK_CMD 0x10 +#define IDETAPE_SPACE_CMD 0x11 +#define IDETAPE_INQUIRY_CMD 0x12 +#define IDETAPE_ERASE_CMD 0x19 +#define IDETAPE_MODE_SENSE_CMD 0x1a +#define IDETAPE_LOCATE_CMD 0x2b +#define IDETAPE_READ_POSITION_CMD 0x34 + +/* + * Some defines for the SPACE command + * + * (The code field in the SPACE packet command). + */ + +#define IDETAPE_SPACE_OVER_FILEMARK 1 +#define IDETAPE_SPACE_TO_EOD 3 + +/* + * Our ioctls - We will use 0x034n and 0x035n + * + * Nothing special meanwhile. + * mtio.h MTIOCTOP compatible commands are supported on the character + * device interface. + */ + +#define IDETAPE_INQUIRY_IOCTL 0x0341 +#define IDETAPE_LOCATE_IOCTL 0x0342 + +#define IDETAPE_RESET_IOCTL 0x0350 + +/* + * Special requests for our block device strategy routine. + * + * In order to service a character device command, we add special + * requests to the tail of our block device request queue and wait + * for their completion. + * + */ + +/* + * IDETAPE_PACKET_COMMAND_REQUEST_TYPE1 is used to queue a packet command + * in the request queue. We will wait for DSC before issuing the command + * if it is still not set. In that case, we will temporary replace the + * cmd field to type 2 and restore it back to type 1 when we receive DSC + * and can start with sending the command. + */ + +#define IDETAPE_PACKET_COMMAND_REQUEST_TYPE1 90 +#define IDETAPE_PACKET_COMMAND_REQUEST_TYPE2 91 + +/* + * IDETAPE_READ_REQUEST and IDETAPE_WRITE_REQUEST are used by our + * character device interface to request read/write operations from + * our block device interface. + * + * In case a read or write request was requested by the buffer cache + * and not by our character device interface, the cmd field in the + * request will contain READ and WRITE instead. + * + * We handle both cases in a similar way. The main difference is that + * in our own requests, buffer head is NULL and idetape_end_request + * will update the errors field if the request was not completed. + */ + +#define IDETAPE_READ_REQUEST 92 +#define IDETAPE_WRITE_REQUEST 93 + +/* + * We are now able to postpone an idetape request in the stage + * where it is polling for DSC and service requests from the other + * ide device meanwhile. + */ + +#define IDETAPE_RQ_POSTPONED 0x1234 + +/* + * ATAPI Task File Registers (Re-definition of the ATA Task File + * Registers for an ATAPI packet command). + * From Table 3-2 of QIC-157C. + */ + +/* Read Access */ + +#define IDETAPE_DATA_OFFSET (0) +#define IDETAPE_ERROR_OFFSET (1) +#define IDETAPE_IREASON_OFFSET (2) +#define IDETAPE_RESERVED3_OFFSET (3) +#define IDETAPE_BCOUNTL_OFFSET (4) +#define IDETAPE_BCOUNTH_OFFSET (5) +#define IDETAPE_DRIVESEL_OFFSET (6) +#define IDETAPE_STATUS_OFFSET (7) + +#define IDETAPE_DATA_REG (HWIF(drive)->io_base+IDETAPE_DATA_OFFSET) +#define IDETAPE_ERROR_REG (HWIF(drive)->io_base+IDETAPE_ERROR_OFFSET) +#define IDETAPE_IREASON_REG (HWIF(drive)->io_base+IDETAPE_IREASON_OFFSET) +#define IDETAPE_RESERVED3_REG (HWIF(drive)->io_base+IDETAPE_RESERVED3_OFFSET) +#define IDETAPE_BCOUNTL_REG (HWIF(drive)->io_base+IDETAPE_BCOUNTL_OFFSET) +#define IDETAPE_BCOUNTH_REG (HWIF(drive)->io_base+IDETAPE_BCOUNTH_OFFSET) +#define IDETAPE_DRIVESEL_REG (HWIF(drive)->io_base+IDETAPE_DRIVESEL_OFFSET) +#define IDETAPE_STATUS_REG (HWIF(drive)->io_base+IDETAPE_STATUS_OFFSET) + +/* Write Access */ + +#define IDETAPE_FEATURES_OFFSET (1) +#define IDETAPE_ATACOMMAND_OFFSET (7) + +#define IDETAPE_FEATURES_REG (HWIF(drive)->io_base+IDETAPE_FEATURES_OFFSET) +#define IDETAPE_ATACOMMAND_REG (HWIF(drive)->io_base+IDETAPE_ATACOMMAND_OFFSET) +#define IDETAPE_CONTROL_REG (HWIF(drive)->ctl_port) + + +/* + * Structure of the various task file registers + */ + +/* + * The ATAPI Status Register. + */ + +typedef union { + unsigned all :8; + struct { + unsigned check :1; /* Error occured */ + unsigned idx :1; /* Reserved */ + unsigned corr :1; /* Correctable error occured */ + unsigned drq :1; /* Data is request by the device */ + unsigned dsc :1; /* Set when a media access command is finished */ + /* Reads / Writes are NOT media access commands */ + unsigned reserved5 :1; /* Reserved */ + unsigned drdy :1; /* Ignored for ATAPI commands */ + /* (The device is ready to accept ATA command) */ + unsigned bsy :1; /* The device has access to the command block */ + } b; +} idetape_status_reg_t; + +/* + * The ATAPI error register. + */ + +typedef union { + unsigned all :8; + struct { + unsigned ili :1; /* Illegal Length Indication */ + unsigned eom :1; /* End Of Media Detected */ + unsigned abrt :1; /* Aborted command - As defined by ATA */ + unsigned mcr :1; /* Media Change Requested - As defined by ATA */ + unsigned sense_key :4; /* Sense key of the last failed packet command */ + } b; +} idetape_error_reg_t; + +/* + * ATAPI Feature Register + */ + +typedef union { + unsigned all :8; + struct { + unsigned dma :1; /* Using DMA of PIO */ + unsigned reserved321 :3; /* Reserved */ + unsigned reserved654 :3; /* Reserved (Tag Type) */ + unsigned reserved7 :1; /* Reserved */ + } b; +} idetape_feature_reg_t; + +/* + * ATAPI Byte Count Register. + */ + +typedef union { + unsigned all :16; + struct { + unsigned low :8; /* LSB */ + unsigned high :8; /* MSB */ + } b; +} idetape_bcount_reg_t; + +/* + * ATAPI Interrupt Reason Register. + */ + +typedef union { + unsigned all :8; + struct { + unsigned cod :1; /* Information transferred is command (1) or data (0) */ + unsigned io :1; /* The device requests us to read (1) or write (0) */ + unsigned reserved :6; /* Reserved */ + } b; +} idetape_ireason_reg_t; + +/* + * ATAPI Drive Select Register + */ + +typedef union { + unsigned all :8; + struct { + unsigned sam_lun :4; /* Should be zero with ATAPI (not used) */ + unsigned drv :1; /* The responding drive will be drive 0 (0) or drive 1 (1) */ + unsigned one5 :1; /* Should be set to 1 */ + unsigned reserved6 :1; /* Reserved */ + unsigned one7 :1; /* Should be set to 1 */ + } b; +} idetape_drivesel_reg_t; + +/* + * ATAPI Device Control Register + */ + +typedef union { + unsigned all :8; + struct { + unsigned zero0 :1; /* Should be set to zero */ + unsigned nien :1; /* Device interrupt is disabled (1) or enabled (0) */ + unsigned srst :1; /* ATA software reset. ATAPI devices should use the new ATAPI srst. */ + unsigned one3 :1; /* Should be set to 1 */ + unsigned reserved4567 :4; /* Reserved */ + } b; +} idetape_control_reg_t; + +/* + * idetape_chrdev_t provides the link between out character device + * interface and our block device interface and the corresponding + * ide_drive_t structure. + * + * We currently support only one tape drive. + * + */ + +typedef struct { + ide_drive_t *drive; + int major,minor; + char name[4]; +} idetape_chrdev_t; + +/* + * The following is used to format the general configuration word of + * the ATAPI IDENTIFY DEVICE command. + */ + +struct idetape_id_gcw { + + unsigned packet_size :2; /* Packet Size */ + unsigned reserved2 :1; /* Reserved */ + unsigned reserved3 :1; /* Reserved */ + unsigned reserved4 :1; /* Reserved */ + unsigned drq_type :2; /* Command packet DRQ type */ + unsigned removable :1; /* Removable media */ + unsigned device_type :5; /* Device type */ + unsigned reserved13 :1; /* Reserved */ + unsigned protocol :2; /* Protocol type */ +}; + +/* + * INQUIRY packet command - Data Format (From Table 6-8 of QIC-157C) + */ + +typedef struct { + unsigned device_type :5; /* Peripheral Device Type */ + unsigned reserved0_765 :3; /* Peripheral Qualifier - Reserved */ + unsigned reserved1_6t0 :7; /* Reserved */ + unsigned rmb :1; /* Removable Medium Bit */ + unsigned ansi_version :3; /* ANSI Version */ + unsigned ecma_version :3; /* ECMA Version */ + unsigned iso_version :2; /* ISO Version */ + unsigned response_format :4; /* Response Data Format */ + unsigned reserved3_45 :2; /* Reserved */ + unsigned reserved3_6 :1; /* TrmIOP - Reserved */ + unsigned reserved3_7 :1; /* AENC - Reserved */ + byte additional_length; /* Additional Length (total_length-4) */ + byte reserved_5; /* Reserved */ + byte reserved_6; /* Reserved */ + unsigned reserved7_0 :1; /* SftRe - Reserved */ + unsigned reserved7_1 :1; /* CmdQue - Reserved */ + unsigned reserved7_2 :1; /* Reserved */ + unsigned reserved7_3 :1; /* Linked - Reserved */ + unsigned reserved7_4 :1; /* Sync - Reserved */ + unsigned reserved7_5 :1; /* WBus16 - Reserved */ + unsigned reserved7_6 :1; /* WBus32 - Reserved */ + unsigned reserved7_7 :1; /* RelAdr - Reserved */ + byte vendor_id [8]; /* Vendor Identification */ + byte product_id [16]; /* Product Identification */ + byte revision_level [4]; /* Revision Level */ + byte vendor_specific [20]; /* Vendor Specific - Optional */ + byte reserved56t95 [40]; /* Reserved - Optional */ + + /* Additional information may be returned */ +} idetape_inquiry_result_t; + +/* + * READ POSITION packet command - Data Format (From Table 6-57) + */ + +typedef struct { + unsigned reserved0_10 :2; /* Reserved */ + unsigned bpu :1; /* Block Position Unknown */ + unsigned reserved0_543 :3; /* Reserved */ + unsigned eop :1; /* End Of Partition */ + unsigned bop :1; /* Begining Of Partition */ + byte partition_num; /* Partition Number */ + byte reserved_2; /* Reserved */ + byte reserved_3; /* Reserved */ + unsigned long first_block; /* First Block Location */ + unsigned long last_block; /* Last Block Location (Optional) */ + byte reserved_12; /* Reserved */ + byte blocks_in_buffer_2; /* Blocks In Buffer - MSB (Optional) */ + byte blocks_in_buffer_1; + byte blocks_in_buffer_0; /* Blocks In Buffer - LSB (Optional) */ + unsigned long bytes_in_buffer; /* Bytes In Buffer (Optional) */ +} idetape_read_position_result_t; + +/* + * REQUEST SENSE packet command result - Data Format. + */ + +typedef struct { + unsigned error_code :7; /* Current of deferred errors */ + unsigned valid :1; /* The information field conforms to QIC-157C */ + byte reserved_1; /* Segment Number - Reserved */ + unsigned sense_key :4; /* Sense Key */ + unsigned reserved2_4 :1; /* Reserved */ + unsigned ili :1; /* Incorrect Length Indicator */ + unsigned eom :1; /* End Of Medium */ + unsigned filemark :1; /* Filemark */ + unsigned long information; /* Information - Command specific */ + byte asl; /* Additional sense length (n-7) */ + unsigned long command_specific; /* Additional command specific information */ + byte asc; /* Additional Sense Code */ + byte ascq; /* Additional Sense Code Qualifier */ + byte replaceable_unit_code; /* Field Replaceable Unit Code */ + unsigned sk_specific1 :7; /* Sense Key Specific */ + unsigned sksv :1; /* Sense Key Specific informatio is valid */ + byte sk_specific2; /* Sense Key Specific */ + byte sk_specific3; /* Sense Key Specific */ +} idetape_request_sense_result_t; + +/* + * Follows structures which are realted to the SELECT SENSE / MODE SENSE + * packet commands. Those packet commands are still not supported + * by ide-tape. + */ + +#define IDETAPE_CAPABILITIES_PAGE 0x2a + +/* + * Mode Parameter Header for the MODE SENSE packet command + */ + +typedef struct { + byte mode_data_length; /* The length of the following data that is */ + /* available to be transferred */ + byte medium_type; /* Medium Type */ + byte dsp; /* Device Specific Parameter */ + byte bdl; /* Block Descriptor Length */ +} idetape_mode_parameter_header_t; + +/* + * Mode Parameter Block Descriptor the MODE SENSE packet command + * + * Support for block descriptors is optional. + */ + +typedef struct { + byte density_code; /* Medium density code */ + byte blocks1; /* Number of blocks - MSB */ + byte blocks2; /* Number of blocks - Middle byte */ + byte blocks3; /* Number of blocks - LSB */ + byte reserved4; /* Reserved */ + byte length1; /* Block Length - MSB */ + byte length2; /* Block Length - Middle byte */ + byte length3; /* Block Length - LSB */ +} idetape_parameter_block_descriptor_t; + +/* + * The Data Compression Page, as returned by the MODE SENSE packet command. + */ + +typedef struct { + unsigned page_code :6; /* Page Code - Should be 0xf */ + unsigned reserved :1; /* Reserved */ + unsigned ps :1; + byte page_length; /* Page Length - Should be 14 */ + unsigned reserved2 :6; /* Reserved */ + unsigned dcc :1; /* Data Compression Capable */ + unsigned dce :1; /* Data Compression Enable */ + unsigned reserved3 :5; /* Reserved */ + unsigned red :2; /* Report Exception on Decompression */ + unsigned dde :1; /* Data Decompression Enable */ + unsigned long ca; /* Compression Algorithm */ + unsigned long da; /* Decompression Algorithm */ + byte reserved_12; /* Reserved */ + byte reserved_13; /* Reserved */ + byte reserved_14; /* Reserved */ + byte reserved_15; /* Reserved */ +} idetape_data_compression_page_t; + +/* + * The Medium Partition Page, as returned by the MODE SENSE packet command. + */ + +typedef struct { + unsigned page_code :6; /* Page Code - Should be 0x11 */ + unsigned reserved1_6 :1; /* Reserved */ + unsigned ps :1; + byte page_length; /* Page Length - Should be 6 */ + byte map; /* Maximum Additional Partitions - Should be 0 */ + byte apd; /* Additional Partitions Defined - Should be 0 */ + unsigned reserved4_012 :3; /* Reserved */ + unsigned psum :2; /* Should be 0 */ + unsigned idp :1; /* Should be 0 */ + unsigned sdp :1; /* Should be 0 */ + unsigned fdp :1; /* Fixed Data Partitions */ + byte mfr; /* Medium Format Recognition */ + byte reserved6; /* Reserved */ + byte reserved7; /* Reserved */ +} idetape_medium_partition_page_t; + +/* + * Prototypes of various functions in ide-tape.c + * + * The following functions are called from ide.c, and their prototypes + * are available in ide.h: + * + * idetape_identify_device + * idetape_setup + * idetape_blkdev_ioctl + * idetape_do_request + * idetape_blkdev_open + * idetape_blkdev_release + * idetape_register_chrdev (void); + */ + +/* + * The following functions are used to transfer data from / to the + * tape's data register. + */ + +void idetape_input_data (ide_drive_t *drive,void *buffer, unsigned long bcount); +void idetape_output_data (ide_drive_t *drive,void *buffer, unsigned long bcount); +void idetape_discard_data (ide_drive_t *drive, unsigned long bcount); + + +/* + * Packet command related functions. + */ + +void idetape_issue_packet_command (ide_drive_t *drive,idetape_packet_command_t *pc,ide_handler_t *handler); +void idetape_pc_intr (ide_drive_t *drive); + +/* + * DSC handling functions. + */ + +void idetape_postpone_request (ide_drive_t *drive); +void idetape_poll_for_dsc (unsigned long data); +void idetape_put_back_postponed_request (ide_drive_t *drive); +void idetape_media_access_finished (ide_drive_t *drive); + +/* + * Some more packet command related functions. + */ + +void idetape_pc_callback (ide_drive_t *drive); +void idetape_retry_pc (ide_drive_t *drive); +void idetape_zero_packet_command (idetape_packet_command_t *pc); +void idetape_queue_pc_head (ide_drive_t *drive,idetape_packet_command_t *pc,struct request *rq); + +idetape_packet_command_t *idetape_next_pc_storage (ide_drive_t *drive); +struct request *idetape_next_rq_storage (ide_drive_t *drive); + +void idetape_end_request (byte uptodate, ide_hwgroup_t *hwgroup); + +/* + * Various packet commands + */ + +void idetape_create_inquiry_cmd (idetape_packet_command_t *pc); +void idetape_inquiry_callback (ide_drive_t *drive); +void idetape_create_locate_cmd (idetape_packet_command_t *pc,unsigned long block,byte partition); +void idetape_create_rewind_cmd (idetape_packet_command_t *pc); +void idetape_create_write_filemark_cmd (idetape_packet_command_t *pc,int write_filemark); +void idetape_create_space_cmd (idetape_packet_command_t *pc,long count,byte cmd); +void idetape_create_erase_cmd (idetape_packet_command_t *pc); +void idetape_create_test_unit_ready_cmd (idetape_packet_command_t *pc); +void idetape_create_read_position_cmd (idetape_packet_command_t *pc); +void idetape_read_position_callback (ide_drive_t *drive); +void idetape_create_read_cmd (idetape_packet_command_t *pc,unsigned long length); +void idetape_read_callback (ide_drive_t *drive); +void idetape_create_write_cmd (idetape_packet_command_t *pc,unsigned long length); +void idetape_write_callback (ide_drive_t *drive); +void idetape_create_request_sense_cmd (idetape_packet_command_t *pc); +void idetape_create_mode_sense_cmd (idetape_packet_command_t *pc,byte page_code); +void idetape_request_sense_callback (ide_drive_t *drive); + +void idetape_display_inquiry_result (byte *buffer); +void idetape_analyze_error (ide_drive_t *drive,idetape_request_sense_result_t *result); + +/* + * Character device callback functions. + * + * We currently support: + * + * OPEN, RELEASE, READ, WRITE and IOCTL. + */ + +int idetape_chrdev_read (struct inode *inode, struct file *file, char *buf, int count); +int idetape_chrdev_read_remainder (struct inode *inode, struct file *file, char *buf, int count); +int idetape_chrdev_write (struct inode *inode, struct file *file, const char *buf, int count); +int idetape_chrdev_write_remainder (struct inode *inode, struct file *file, const char *buf, int count); +int idetape_chrdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); +int idetape_chrdev_open (struct inode *inode, struct file *file); +void idetape_chrdev_release (struct inode *inode,struct file *file); + +/* + * idetape_mtioctop implements general magnetic tape io control + * commands, as defined in include/linux/mtio.h. Those commands are + * accessed through the character device interface, using the MTIOCTOP + * ioctl. + */ + +int idetape_mtioctop (ide_drive_t *drive,short mt_op,int mt_count); +int idetape_queue_rw_tail (ide_drive_t *drive,int cmd,int blocks,char *buffer); +int idetape_queue_pc_tail (ide_drive_t *drive,idetape_packet_command_t *pc); + +void idetape_fake_read (ide_drive_t *drive); +int idetape_position_tape (ide_drive_t *drive,unsigned long block); +int idetape_rewind_tape (ide_drive_t *drive); + +/* + * Used to get device information + */ + +void idetape_get_mode_sense_results (ide_drive_t *drive); + +/* + * General utility functions + */ + +void idetape_fixstring (byte *s, const int bytecount, const int byteswap); +unsigned long idetape_swap_long (unsigned long temp); +unsigned short idetape_swap_short (unsigned short temp); + +/* + * For general magnetic tape device compatibility. + */ + +#include + +/* + * Global variables + * + * The variables below are used for the character device interface. + * + * Additional state variables are defined in our ide_drive_t structure. + */ + +idetape_chrdev_t idetape_chrdev; /* Character device interface information */ +byte idetape_drive_already_found=0; /* 1 when the above data structure is initialized */ + +/* + * Our character device supporting functions, passed to register_chrdev. + */ + +static struct file_operations idetape_fops = { + NULL, /* lseek - default */ + idetape_chrdev_read, /* read */ + idetape_chrdev_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* select */ + idetape_chrdev_ioctl, /* ioctl */ + NULL, /* mmap */ + idetape_chrdev_open, /* open */ + idetape_chrdev_release, /* release */ + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL /* revalidate */ +}; + + +/* + * idetape_identify_device is called by do_identify in ide.c during + * the device probing stage to check the contents of the ATAPI IDENTIFY + * command results, in case the device type is tape. We return: + * + * 1 If the tape can be supported by us, based on the information + * we have so far. + * + * 0 If this tape driver is not currently supported by us. + * + * In case we decide to support the tape, we store the current drive + * pointer in our character device global variables, so that we can + * pass between both interfaces. + */ + +int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id) + +{ + struct idetape_id_gcw gcw; + unsigned short *ptr; + int support=1; +#if IDETAPE_DEBUG + unsigned short mask,i; +#endif /* IDETAPE_DEBUG */ + + ptr=(unsigned short *) &gcw; + *ptr=id->config; + +#if IDETAPE_DEBUG + printk ("Dumping ATAPI Identify Device tape parameters\n"); + + printk ("Protocol Type: "); + switch (gcw.protocol) { + case 0: case 1: printk ("ATA\n");break; + case 2: printk ("ATAPI\n");break; + case 3: printk ("Reserved (Unknown to ide-tape)\n");break; + } + + printk ("Device Type: %x - ",gcw.device_type); + switch (gcw.device_type) { + case 0: printk ("Direct-access Device\n");break; + case 1: printk ("Streaming Tape Device\n");break; + case 2: case 3: case 4: printk ("Reserved\n");break; + case 5: printk ("CD-ROM Device\n");break; + case 6: printk ("Reserved\n"); + case 7: printk ("Optical memory Device\n");break; + case 0x1f: printk ("Unknown or no Device type\n");break; + default: printk ("Reserved\n"); + } + printk ("Removable: %s",gcw.removable ? "Yes\n":"No\n"); + + printk ("Command Packet DRQ Type: "); + switch (gcw.drq_type) { + case 0: printk ("Microprocessor DRQ\n");break; + case 1: printk ("Interrupt DRQ\n");break; + case 2: printk ("Accelerated DRQ\n");break; + case 3: printk ("Reserved\n");break; + } + + printk ("Command Packet Size: "); + switch (gcw.packet_size) { + case 0: printk ("12 bytes\n");break; + case 1: printk ("16 bytes\n");break; + default: printk ("Reserved\n");break; + } + printk ("Model: %s\n",id->model); + printk ("Firmware Revision: %s\n",id->fw_rev); + printk ("Serial Number: %s\n",id->serial_no); + printk ("Write buffer size: %d bytes\n",id->buf_size*512); + printk ("DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n"); + printk ("LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n"); + printk ("IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n"); + printk ("IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n"); + printk ("PIO Cycle Timing Category: %d\n",id->tPIO); + printk ("DMA Cycle Timing Category: %d\n",id->tDMA); + printk ("Single Word DMA supported modes: "); + for (i=0,mask=1;i<8;i++,mask=mask << 1) { + if (id->dma_1word & mask) + printk ("%d ",i); + if (id->dma_1word & (mask << 8)) + printk ("(active) "); + } + printk ("\n"); + + printk ("Multi Word DMA supported modes: "); + for (i=0,mask=1;i<8;i++,mask=mask << 1) { + if (id->dma_mword & mask) + printk ("%d ",i); + if (id->dma_mword & (mask << 8)) + printk ("(active) "); + } + printk ("\n"); + + if (id->field_valid & 0x0002) { + printk ("Enhanced PIO Modes: %s\n",id->eide_pio_modes & 1 ? "Mode 3":"None"); + printk ("Minimum Multi-word DMA cycle per word: "); + if (id->eide_dma_min == 0) + printk ("Not supported\n"); + else + printk ("%d ns\n",id->eide_dma_min); + + printk ("Manafactuer\'s Recommended Multi-word cycle: "); + if (id->eide_dma_time == 0) + printk ("Not supported\n"); + else + printk ("%d ns\n",id->eide_dma_time); + + printk ("Minimum PIO cycle without IORDY: "); + if (id->eide_pio == 0) + printk ("Not supported\n"); + else + printk ("%d ns\n",id->eide_pio); + + printk ("Minimum PIO cycle with IORDY: "); + if (id->eide_pio_iordy == 0) + printk ("Not supported\n"); + else + printk ("%d ns\n",id->eide_pio_iordy); + + } + + else { + printk ("According to the device, fields 64-70 are not valid.\n"); + } +#endif /* IDETAPE_DEBUG */ + + /* Check that we can support this device */ + + if (gcw.protocol !=2 ) { + printk ("ide-tape: Protocol is not ATAPI\n");support=0; + } + + if (gcw.device_type != 1) { + printk ("ide-tape: Device type is not set to tape\n");support=0; + } + + if (!gcw.removable) { + printk ("ide-tape: The removable flag is not set\n");support=0; + } + + if (gcw.drq_type != 2) { + printk ("ide-tape: Sorry, DRQ types other than Accelerated DRQ\n"); + printk ("ide-tape: are still not supproted by the driver\n");support=0; + } + + if (gcw.packet_size != 0) { + printk ("ide-tape: Packet size is not 12 bytes long\n"); + if (gcw.packet_size == 1) + printk ("ide-tape: Sorry, padding to 16 bytes is still not supported\n"); + support=0; + } + + if (idetape_drive_already_found) { + printk ("ide-tape: Sorry, only one ide tape drive is supported by the driver\n"); + support=0; + } + else { + idetape_drive_already_found=1; + idetape_chrdev.drive=drive; + idetape_chrdev.major=IDETAPE_MAJOR; + idetape_chrdev.minor=0; + idetape_chrdev.name[0]='h'; + idetape_chrdev.name[1]='t'; + idetape_chrdev.name[2]='0'; + idetape_chrdev.name[3]=0; + } + + return (support); /* In case support=0, we will not install the driver */ +} + +/* + * idetape_register_chrdev calls register_chrdev to register our character + * device interface. The connection to the ide_drive_t structure, which + * is used by the entire ide driver is provided by our global variable + * idetape_chrdev.drive, which was initialized earlier, during the device + * probing stage. + */ + +void idetape_register_chrdev (void) + +{ + int major,minor; + ide_drive_t *drive; + + if (!idetape_drive_already_found) + return; + + drive=idetape_chrdev.drive; + major=idetape_chrdev.major; + minor=idetape_chrdev.minor; + + if (register_chrdev (major,idetape_chrdev.name,&idetape_fops)) { + printk ("Unable to register character device interface !\n"); + /* ??? */ + } + else { + printk ("ide-tape: %s <-> %s : Character device interface on major = %d\n", + drive->name,idetape_chrdev.name,major); + } +} + +/* + * idetape_setup is called from the ide driver in the partition table + * identification stage, to: + * + * 1. Initialize our various state variables. + * 2. Ask the tape for its capabilities. + * 3. Allocate a buffer which will be used for data + * transfer. The buffer size is chosen based on + * the recommendation which we received in step (2). + * + * Note that at this point ide.c already assigned us an irq, so that + * we can queue requests here and wait for their completion. + */ + +void idetape_setup (ide_drive_t *drive) + +{ + int buffer_size; + idetape_tape_t *tape=&(drive->tape); + +#if IDETAPE_DEBUG + printk ("ide-tape: Reached idetape_setup\n"); +#endif /* IDETAPE_DEBUG */ + + drive->ready_stat = 0; /* With an ATAPI device, we can issue packet commands */ + /* regardless of the state of DRDY */ + tape->block_address=0; + tape->block_address_valid=0; + tape->locate_to=0; + tape->locate_retries=0; + tape->pc_stack_index=0; + tape->failed_pc=NULL; + tape->postponed_rq=NULL; + tape->last_written_valid=0; + tape->busy=0; + + idetape_get_mode_sense_results (drive); + + buffer_size=tape->capabilities.ctl*tape->tape_block_size; + tape->data_buffer=kmalloc (buffer_size,GFP_KERNEL); + if (tape->data_buffer == NULL) { + printk ("ide-tape: FATAL - Can not allocate %d bytes for data transfer buffer\n",buffer_size); + printk ("ide-tape: Aborting character device installation\n"); + idetape_drive_already_found=0; + unregister_chrdev (idetape_chrdev.major,idetape_chrdev.name); + return; + } + printk ("ide-tape: Speed - %d KBps. Recommended transfer unit - %d bytes.\n",tape->capabilities.speed,buffer_size); + return; +} + +/* + * idetape_get_mode_sense_results asks the tape about its various + * parameters. In particular, we will adjust our data transfer buffer + * size to the recommended value as returned by the tape. + */ + +void idetape_get_mode_sense_results (ide_drive_t *drive) + +{ + int retval; + idetape_tape_t *tape=&(drive->tape); + idetape_mode_parameter_header_t *header; + idetape_capabilities_page_t *capabilities; + idetape_packet_command_t pc; + + idetape_create_mode_sense_cmd (&pc,IDETAPE_CAPABILITIES_PAGE); + pc.buffer=pc.temp_buffer; + pc.buffer_size=IDETAPE_TEMP_BUFFER_SIZE; + pc.current_position=pc.temp_buffer; + retval=idetape_queue_pc_tail (drive,&pc); + + header=(idetape_mode_parameter_header_t *) pc.buffer; + capabilities=(idetape_capabilities_page_t *) (pc.buffer+sizeof (idetape_mode_parameter_header_t)); + + capabilities->max_speed=idetape_swap_short (capabilities->max_speed); + capabilities->ctl=idetape_swap_short (capabilities->ctl); + capabilities->speed=idetape_swap_short (capabilities->speed); + capabilities->buffer_size=idetape_swap_short (capabilities->buffer_size); + + tape->capabilities=*capabilities; /* Save us a copy */ + tape->tape_block_size=capabilities->blk512 ? 512:1024; + + if (retval) { + printk ("ide-tape: Can't get tape parameters\n"); + printk ("ide-tape: Assuming some default parameters\n"); + tape->tape_block_size=512; + tape->capabilities.ctl=26*1024; + return; + } + +#if IDETAPE_DEBUG + printk ("Dumping the results of the MODE SENSE packet command\n"); + printk ("Mode Parameter Header:\n"); + printk ("Mode Data Length - %d\n",header->mode_data_length); + printk ("Medium Type - %d\n",header->medium_type); + printk ("Device Specific Parameter - %d\n",header->dsp); + printk ("Block Descriptor Length - %d\n",header->bdl); + + printk ("Capabilities and Mechanical Status Page:\n"); + printk ("Page code - %d\n",capabilities->page_code); + printk ("Page length - %d\n",capabilities->page_length); + printk ("Read only - %s\n",capabilities->ro ? "Yes":"No"); + printk ("Supports reverse space - %s\n",capabilities->sprev ? "Yes":"No"); + printk ("Supports erase initiated formatting - %s\n",capabilities->efmt ? "Yes":"No"); + printk ("Supports QFA two Partition format - %s\n",capabilities->qfa ? "Yes":"No"); + printk ("Supports locking the medium - %s\n",capabilities->lock ? "Yes":"No"); + printk ("The volume is currently locked - %s\n",capabilities->locked ? "Yes":"No"); + printk ("The device defaults in the prevent state - %s\n",capabilities->prevent ? "Yes":"No"); + printk ("Supports ejecting the medium - %s\n",capabilities->eject ? "Yes":"No"); + printk ("Supports error correction - %s\n",capabilities->ecc ? "Yes":"No"); + printk ("Supports data compression - %s\n",capabilities->cmprs ? "Yes":"No"); + printk ("Supports 512 bytes block size - %s\n",capabilities->blk512 ? "Yes":"No"); + printk ("Supports 1024 bytes block size - %s\n",capabilities->blk1024 ? "Yes":"No"); + printk ("Restricted byte count for PIO transfers - %s\n",capabilities->slowb ? "Yes":"No"); + printk ("Maximum supported speed in KBps - %d\n",capabilities->max_speed); + printk ("Continuous transfer limits in blocks - %d\n",capabilities->ctl); + printk ("Current speed in KBps - %d\n",capabilities->speed); + printk ("Buffer size - %d\n",capabilities->buffer_size*512); +#endif /* IDETAPE_DEBUG */ +} + +/* + * Packet Command Interface + * + * The current Packet Command is available in tape->pc, and will not + * change until we finish handling it. Each packet command is associated + * with a callback function that will be called when the command is + * finished. + * + * The handling will be done in three stages: + * + * 1. idetape_issue_packet_command will send the packet command to the + * drive, and will set the interrupt handler to idetape_pc_intr. + * + * 2. On each interrupt, idetape_pc_intr will be called. This step + * will be repeated until the device signals us that no more + * interrupts will be issued. + * + * 3. ATAPI Tape media access commands have immediate status with a + * delayed process. In case of a successfull initiation of a + * media access packet command, the DSC bit will be set when the + * actual execution of the command is finished. + * Since the tape drive will not issue an interrupt, we have to + * poll for this event. In this case, we define the request as + * "low priority request" by setting rq_status to + * IDETAPE_RQ_POSTPONED, set a timer to poll for DSC and exit + * the driver. + * + * ide.c will then give higher priority to requests which + * originate from the other device, until will change rq_status + * to RQ_ACTIVE. + * + * 4. When the packet command is finished, it will be checked for errors. + * + * 5. In case an error was found, we queue a request sense packet command + * in front of the request queue and retry the operation up to + * IDETAPE_MAX_PC_RETRIES times. + * + * 6. In case no error was found, or we decided to give up and not + * to retry again, the callback function will be called and then + * we will handle the next request. + * + */ + +void idetape_issue_packet_command (ide_drive_t *drive,idetape_packet_command_t *pc,ide_handler_t *handler) + +{ + idetape_tape_t *tape; + idetape_bcount_reg_t bcount; + idetape_ireason_reg_t ireason; + + tape=&(drive->tape); + +#ifdef IDETAPE_DEBUG + if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) { + printk ("ide-tape: ide-tape.c bug - Two request sense in serial were issued\n"); + /* ??? Need to rethink about that */ + } +#endif /* IDETAPE_DEBUG */ + + if (tape->failed_pc == NULL && pc->c[0] != IDETAPE_REQUEST_SENSE_CMD) + tape->failed_pc=pc; + tape->pc=pc; /* Set the current packet command */ + + if (pc->retries > IDETAPE_MAX_PC_RETRIES) { + printk ("ide-tape: %s: I/O error, ",drive->name); + printk ("pc = %x, key = %x, asc = %x, ascq = %x\n",pc->c[0],tape->sense_key,tape->asc,tape->ascq); + printk ("ide-tape: Maximum retries reached - Giving up\n"); + pc->error=1; /* Giving up */ + pc->active=0; + tape->failed_pc=NULL; +#if IDETAPE_DEBUG + if (pc->callback==NULL) + printk ("ide-tape: ide-tape bug - Callback function not set !\n"); + else +#endif /* IDETAPE_DEBUG */ + (*pc->callback)(drive); + return; + } + +#if IDETAPE_DEBUG + printk ("Retry number - %d\n",pc->retries); +#endif /* IDETAPE_DEBUG */ + + pc->retries++; + +/* + * We no longer call ide_wait_stat to wait for the drive to be ready, + * as ide.c already does this for us in do_request. + */ + + pc->actually_transferred=0; /* We haven't transferred any data yet */ + pc->active=1; /* Packet command started */ + bcount.all=pc->request_transfer; /* Request to transfer the entire buffer at once */ + + /* Initialize the task file registers */ + OUT_BYTE (0,IDETAPE_FEATURES_REG); /* Use PIO data transger, No DMA */ + OUT_BYTE (bcount.b.high,IDETAPE_BCOUNTH_REG); + OUT_BYTE (bcount.b.low,IDETAPE_BCOUNTL_REG); + OUT_BYTE (drive->select.all,IDETAPE_DRIVESEL_REG); + + ide_set_handler (drive,handler,WAIT_CMD); /* Set the interrupt routine */ + OUT_BYTE (WIN_PACKETCMD,IDETAPE_ATACOMMAND_REG); /* Issue the packet command */ + if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { /* Wait for DRQ to be ready - Assuming Accelerated DRQ */ + /* + * We currently only support tape drives which report + * accelerated DRQ assertion. For this case, specs + * allow up to 50us. We really shouldn't get here. + * + * ??? Still needs to think what to do if we reach + * here anyway. + */ + + printk ("ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n"); + return; + } + + ireason.all=IN_BYTE (IDETAPE_IREASON_REG); + if (!ireason.b.cod || ireason.b.io) { + printk ("ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n"); + /* ??? */ + } + + ide_output_data (drive,pc->c,12/4); /* Send the actual packet */ +} + +/* + * idetape_pc_intr is the usual interrupt handler which will be called + * during a packet command. We will transfer some of the data (as + * requested by the drive) and will re-point interrupt handler to us. + * When data transfer is finished, we will act according to the + * algorithm described before idetape_issue_packet_command. + * + */ + + +void idetape_pc_intr (ide_drive_t *drive) + +{ + idetape_tape_t *tape; + idetape_status_reg_t status; + idetape_bcount_reg_t bcount; + idetape_ireason_reg_t ireason; + idetape_packet_command_t *pc; + + unsigned long temp; + + tape=&(drive->tape); + + status.all=IN_BYTE (IDETAPE_STATUS_REG); /* Clear the interrupt */ + +#if IDETAPE_DEBUG + printk ("ide-tape: Reached idetape_pc_intr interrupt handler\n"); +#endif /* IDETAPE_DEBUG */ + + pc=tape->pc; /* Current packet command */ + + if (!status.b.drq) { /* No more interrupts */ +#if IDETAPE_DEBUG + printk ("Packet command completed\n"); + printk ("Total bytes transferred: %lu\n",pc->actually_transferred); +#endif /* IDETAPE_DEBUG */ + if (status.b.check) { /* Error detected */ +#if IDETAPE_DEBUG + /* + * Without debugging, we only log an error if we decided to + * give up retrying. + */ + printk ("ide-tape: %s: I/O error, ",drive->name); +#endif /* IDETAPE_DEBUG */ + idetape_retry_pc (drive); /* Retry operation */ + return; + } + pc->error=0; + if (pc->wait_for_dsc && !status.b.dsc) { /* Media access command */ + tape->dsc_polling_frequency=IDETAPE_DSC_FAST_MEDIA_ACCESS_FREQUENCY; + idetape_postpone_request (drive); /* Allow ide.c to handle other requests */ + return; + } + pc->active=0; + if (tape->failed_pc == pc) + tape->failed_pc=NULL; +#if IDETAPE_DEBUG + if (pc->callback==NULL) + printk ("ide-tape: ide-tape bug - Callback function not set !\n"); + else +#endif IDETAPE_DEBUG + (*pc->callback)(drive); /* Command finished - Call the callback function */ + return; + } + + bcount.b.high=IN_BYTE (IDETAPE_BCOUNTH_REG); /* Get the number of bytes to transfer */ + bcount.b.low=IN_BYTE (IDETAPE_BCOUNTL_REG); /* on this interrupt */ + ireason.all=IN_BYTE (IDETAPE_IREASON_REG); /* Read the interrupt reason register */ + + if (ireason.b.cod) { + printk ("ide-tape: CoD != 0 in idetape_pc_intr\n"); + /* ??? */ + } + if (ireason.b.io != !(pc->writing)) { /* Hopefully, we will never get here */ + printk ("ide-tape: We wanted to %s, ",pc->writing ? "Write":"Read"); + printk ("but the tape wants us to %s !\n",ireason.b.io ? "Read":"Write"); + /* ??? */ + } + + if (!pc->writing) { /* Reading - Check that we have enough space */ + temp=(unsigned long) pc->actually_transferred + bcount.all; + if ( temp > pc->request_transfer) { + printk ("ide-tape: The tape wants to send us more data than requested - "); + if (temp > pc->buffer_size) { + printk ("Discarding data\n"); + idetape_discard_data (drive,bcount.all); + ide_set_handler (drive,&idetape_pc_intr,WAIT_CMD); + return; + } + else + printk ("Allowing transfer\n"); + } + } +#if IDETAPE_DEBUG + if (bcount.all && !pc->buffer) { + printk ("ide-tape: ide-tape.c bug - Buffer not set in idetape_pc_intr. Discarding data.\n"); + + if (!pc->writing) { + printk ("ide-tape: Discarding data\n"); + idetape_discard_data (drive,bcount.all); + ide_set_handler (drive,&idetape_pc_intr,WAIT_CMD); + return; + } + else { /* ??? */ + } + } +#endif /* IDETAPE_DEBUG */ + if (pc->writing) + idetape_output_data (drive,pc->current_position,bcount.all); /* Write the current buffer */ + else + idetape_input_data (drive,pc->current_position,bcount.all); /* Read the current buffer */ +#if IDETAPE_DEBUG + printk ("ide-tape: %s %d bytes\n",pc->writing ? "Wrote":"Received",bcount.all); +#endif /* IDETAPE_DEBUG */ + pc->actually_transferred+=bcount.all; /* Update the current position */ + pc->current_position+=bcount.all; + + ide_set_handler (drive,&idetape_pc_intr,WAIT_CMD); /* And set the interrupt handler again */ +} + +/* + * idetape_postpone_request postpones the current request so that + * ide.c will be able to service requests from another device on + * the same hwgroup while we are polling for DSC. + */ + +void idetape_postpone_request (ide_drive_t *drive) + +{ + idetape_tape_t *tape; + unsigned long flags; + struct request *rq; + + tape=&(drive->tape); + +#if IDETAPE_DEBUG + printk ("Reached idetape_postpone_request\n"); + if (tape->postponed_rq != NULL) + printk ("ide-tape.c bug - postponed_rq not NULL in idetape_postpone_request\n"); +#endif /* IDETAPE_DEBUG */ + + tape->dsc_count=0; + tape->dsc_timer.expires=jiffies + tape->dsc_polling_frequency; /* Set timer to poll for */ + tape->dsc_timeout=jiffies+IDETAPE_DSC_TIMEOUT; /* actual completion */ + tape->dsc_timer.data=(unsigned long) drive; + tape->dsc_timer.function=&idetape_poll_for_dsc; + init_timer (&(tape->dsc_timer)); + + /* + * Remove current request from the request queue: + */ + save_flags(flags); /* Let ide.c handle another request */ + cli(); + tape->postponed_rq = rq = HWGROUP(drive)->rq; + rq->rq_status = IDETAPE_RQ_POSTPONED; + blk_dev[MAJOR(rq->rq_dev)].current_request = rq->next; + HWGROUP(drive)->rq = NULL; + restore_flags(flags); + + tape->dsc_polling_start=jiffies; + add_timer(&(tape->dsc_timer)); /* Activate the polling timer */ +} + + +/* + * idetape_poll_for_dsc gets invoked by a timer (which was set + * by idetape_postpone_request) to poll for the DSC bit + * in the status register. When the DSC bit is set, or a timeout is + * reached, we put back the postponed request in front of the request + * queue. + */ + +void idetape_poll_for_dsc (unsigned long data) + +{ + ide_drive_t *drive; + idetape_tape_t *tape; + + idetape_status_reg_t status; + idetape_packet_command_t *pc; + + drive=(ide_drive_t *) data; + tape=&(drive->tape); + pc=tape->pc; + +#if IDETAPE_DEBUG + printk ("%s: idetape_poll_for_dsc called\n",drive->name); +#endif /* IDETAPE_DEBUG */ + + status.all=IN_BYTE (IDETAPE_STATUS_REG); + + if (status.b.dsc) + tape->dsc_count++; + else { + if (tape->dsc_count) + printk ("ide-tape: DSC fluctuation detected - Restarting DSC count\n"); + tape->dsc_count=0; + } + + if (tape->dsc_count == IDETAPE_DSC_COUNT) { /* DSC received */ + tape->dsc_received=1; + del_timer (&(tape->dsc_timer)); /* Stop polling and put back the postponed */ + idetape_put_back_postponed_request (drive); /* request in the request queue */ + return; + } + + if (jiffies > tape->dsc_timeout) { /* Timeout */ + tape->dsc_received=0; + del_timer (&(tape->dsc_timer)); + /* ??? */ + idetape_put_back_postponed_request (drive); + return; + } + + /* Poll again */ + + if (jiffies - tape->dsc_polling_start > IDETAPE_FAST_SLOW_THRESHOLD) + tape->dsc_timer.expires = jiffies + IDETAPE_DSC_SLOW_MEDIA_ACCESS_FREQUENCY; + else + tape->dsc_timer.expires = jiffies + tape->dsc_polling_frequency; +/* init_timer (&(tape->dsc_timer)); */ + add_timer(&(tape->dsc_timer)); + return; +} + +/* + * idetape_put_back_postponed_request gets called by + * idetape_poll_for_dsc when we decided to stop polling - Either + * becase we received DSC or because we decided to give up and + * stop waiting. + */ + +void idetape_put_back_postponed_request (ide_drive_t *drive) + +{ + idetape_tape_t *tape = &(drive->tape); + +#if IDETAPE_DEBUG + printk ("ide-tape: Putting back postponed request\n"); +#endif /* IDETAPE_DEBUG */ + + (void) ide_do_drive_cmd (drive, tape->postponed_rq, ide_next); + + /* + * Note that the procedure done here is differnet than the method + * we are using in idetape_queue_pc_head - There we are putting + * request(s) before our currently called request. + * + * Here, on the other hand, HWGROUP(drive)->rq is not our + * request but rather a request to another device. Therefore, + * we will let it finish and only then service our postponed + * request --> We don't touch HWGROUP(drive)->rq. + */ +} + +void idetape_media_access_finished (ide_drive_t *drive) + +{ + idetape_tape_t *tape=&(drive->tape); + idetape_status_reg_t status; + idetape_packet_command_t *pc; + + pc=tape->pc; + + status.all=IN_BYTE (IDETAPE_STATUS_REG); + + if (tape->dsc_received) { +#if IDETAPE_DEBUG + printk ("DSC received\n"); +#endif /* IDETAPE_DEBUG */ + pc->active=0; + if (status.b.check) { /* Error detected */ + printk ("ide-tape: %s: I/O error, ",drive->name); + idetape_retry_pc (drive); /* Retry operation */ + return; + } + pc->error=0; + if (tape->failed_pc == pc) + tape->failed_pc=NULL; +#if IDETAPE_DEBUG + if (pc->callback==NULL) + printk ("ide-tape: ide-tape bug - Callback function not set !\n"); + else +#endif /* IDETAPE_DEBUG */ + (*pc->callback)(drive); + + return; + } + else { + pc->active=0; + printk ("ide-tape: %s: DSC timeout.\n",drive->name); + /* ??? */ + pc->error=1; + tape->failed_pc=NULL; +#if IDETAPE_DEBUG + if (pc->callback==NULL) + printk ("ide-tape: ide-tape bug - Callback function not set !\n"); + else +#endif /* IDETAPE_DEBUG */ + (*pc->callback)(drive); + return; + } +} + + +/* + * idetape_retry_pc is called when an error was detected during the + * last packet command. We queue a request sense packet command in + * the head of the request list. + */ + +void idetape_retry_pc (ide_drive_t *drive) + +{ + idetape_packet_command_t *pc; + struct request *new_rq; + + idetape_error_reg_t error; + error.all=IN_BYTE (IDETAPE_ERROR_REG); + pc=idetape_next_pc_storage (drive); + new_rq=idetape_next_rq_storage (drive); + idetape_create_request_sense_cmd (pc); + pc->buffer=pc->temp_buffer; + pc->buffer_size=IDETAPE_TEMP_BUFFER_SIZE; + pc->current_position=pc->temp_buffer; + idetape_queue_pc_head (drive,pc,new_rq); +} + +/* + * General packet command callback function. + */ + +void idetape_pc_callback (ide_drive_t *drive) + +{ + idetape_tape_t *tape; + struct request *rq; + + tape=&(drive->tape); + rq=HWGROUP(drive)->rq; + +#if IDETAPE_DEBUG + printk ("ide-tape: Reached idetape_pc_callback\n"); +#endif /* IDETAPE_DEBUG */ + if (!tape->pc->error) { +#if IDETAPE_DEBUG + printk ("Request completed\n"); +#endif /* IDETAPE_DEBUG */ + idetape_end_request (1,HWGROUP (drive)); + } + else { + printk ("Aborting request\n"); + idetape_end_request (0,HWGROUP (drive)); + } + return; +} + + +void idetape_read_callback (ide_drive_t *drive) + +{ + idetape_tape_t *tape; + struct request *rq; + + tape=&(drive->tape); + rq=HWGROUP(drive)->rq; +#if IDETAPE_DEBUG + printk ("ide-tape: Reached idetape_read_callback\n"); +#endif /* IDETAPE_DEBUG */ + tape->block_address+=tape->pc->actually_transferred/512; + if (!tape->pc->error) { +#if IDETAPE_DEBUG + printk ("Request completed\n"); +#endif /* IDETAPE_DEBUG */ + rq->sector+=rq->current_nr_sectors; + rq->nr_sectors-=rq->current_nr_sectors; + rq->current_nr_sectors=0; + idetape_end_request (1,HWGROUP (drive)); + } + else { + printk ("Aborting request\n"); + idetape_end_request (0,HWGROUP (drive)); + } + return; +} + +void idetape_fake_read (ide_drive_t *drive) + +{ + idetape_tape_t *tape; + struct request *rq; + unsigned long i; + + tape=&(drive->tape); + rq=HWGROUP(drive)->rq; +#if IDETAPE_DEBUG + printk ("ide-tape: Reached idetape_fake_read\n"); +#endif /* IDETAPE_DEBUG */ + +#if IDETAPE_DEBUG + printk ("Request completed\n"); +#endif /* IDETAPE_DEBUG */ + + for (i=0;icurrent_nr_sectors*512;i++) + rq->buffer [i]=0; + + tape->block_address+=rq->current_nr_sectors; + rq->sector+=rq->current_nr_sectors; + rq->nr_sectors-=rq->current_nr_sectors; + rq->current_nr_sectors=0; + idetape_end_request (1,HWGROUP (drive)); +} + +void idetape_write_callback (ide_drive_t *drive) + +{ + idetape_tape_t *tape; + struct request *rq; + + tape=&(drive->tape); + rq=HWGROUP(drive)->rq; +#if IDETAPE_DEBUG + printk ("ide-tape: Reached idetape_write_callback\n"); +#endif /* IDETAPE_DEBUG */ + tape->block_address+=tape->pc->actually_transferred/512; + if (!tape->pc->error) { +#if IDETAPE_DEBUG + printk ("Request completed\n"); +#endif /* IDETAPE_DEBUG */ + rq->sector+=rq->current_nr_sectors; + rq->nr_sectors-=rq->current_nr_sectors; + rq->current_nr_sectors=0; + idetape_end_request (1,HWGROUP (drive)); + } + else { + printk ("Aborting request\n"); + idetape_end_request (0,HWGROUP (drive)); + } + return; +} + +void idetape_inquiry_callback (ide_drive_t *drive) + +{ + idetape_tape_t *tape; + + tape=&(drive->tape); + + idetape_display_inquiry_result (tape->pc->buffer); + idetape_pc_callback (drive); + return; +} + +/* + * idetape_input_data is called to read data from the tape's data + * register. We basically let ide_input_data do the job, but we also + * take care about the remaining bytes which can not be transferred + * in 32-bit data transfers. + */ + +void idetape_input_data (ide_drive_t *drive,void *buffer, unsigned long bcount) + +{ + unsigned long wcount; + + wcount=bcount >> 2; + bcount -= 4*wcount; + + if (wcount) + ide_input_data (drive,buffer,wcount); + + if (bcount) { + ((byte *)buffer) += 4*wcount; + insb (IDETAPE_DATA_REG,buffer,bcount); + } +} + +/* + * idetape_output_data is used to write data to the tape. + */ + +void idetape_output_data (ide_drive_t *drive,void *buffer, unsigned long bcount) + +{ + unsigned long wcount; + + wcount=bcount >> 2; + bcount -= 4*wcount; + + if (wcount) + ide_output_data (drive,buffer,wcount); + + if (bcount) { + ((byte *)buffer) += 4*wcount; + outsb (IDETAPE_DATA_REG,buffer,bcount); + } +} + +/* + * Too bad. The drive wants to send us data which we are not ready to accept. + * Just throw it away. + */ + +void idetape_discard_data (ide_drive_t *drive, unsigned long bcount) + +{ + unsigned long i; + + for (i=0;irequest_transfer=36; + pc->callback=&idetape_inquiry_callback; + pc->writing=0; + + idetape_zero_packet_command (pc); + pc->c[0]=IDETAPE_INQUIRY_CMD; + pc->c[4]=255; +} + +/* + * Format the INQUIRY command results. + */ + +void idetape_display_inquiry_result (byte *buffer) + +{ + idetape_inquiry_result_t *result; + + result=(idetape_inquiry_result_t *) buffer; + idetape_fixstring (result->vendor_id,8,0); + idetape_fixstring (result->product_id,16,0); + idetape_fixstring (result->revision_level,4,0); + + if (result->response_format != 2) { + printk ("The INQUIRY Data Format is unknown to us !\n"); + printk ("Assuming QIC-157C format.\n"); + } + +#if IDETAPE_DEBUG + printk ("Dumping INQUIRY command results:\n"); + printk ("Response Data Format: %d - ",result->response_format); + switch (result->response_format) { + case 2: + printk ("As specified in QIC-157 Revision C\n"); + break; + default: + printk ("Unknown\n"); + break; + } + + printk ("Device Type: %x - ",result->device_type); + switch (result->device_type) { + case 0: printk ("Direct-access Device\n");break; + case 1: printk ("Streaming Tape Device\n");break; + case 2: case 3: case 4: printk ("Reserved\n");break; + case 5: printk ("CD-ROM Device\n");break; + case 6: printk ("Reserved\n"); + case 7: printk ("Optical memory Device\n");break; + case 0x1f: printk ("Unknown or no Device type\n");break; + default: printk ("Reserved\n"); + } + + printk ("Removable Medium: %s",result->rmb ? "Yes\n":"No\n"); + + printk ("ANSI Version: %d - ",result->ansi_version); + switch (result->ansi_version) { + case 2: + printk ("QIC-157 Revision C\n"); + break; + default: + printk ("Unknown\n"); + break; + } + + printk ("ECMA Version: "); + if (result->ecma_version) + printk ("%d\n",result->ecma_version); + else + printk ("Not supported\n"); + + printk ("ISO Version: "); + if (result->iso_version) + printk ("%d\n",result->iso_version); + else + printk ("Not supported\n"); + + printk ("Additional Length: %d\n",result->additional_length); + printk ("Vendor Identification: %s\n",result->vendor_id); + printk ("Product Identification: %s\n",result->product_id); + printk ("Product Revision Level: %s\n",result->revision_level); +#endif /* IDETAPE_DEBUG */ + + if (result->device_type != 1) + printk ("Device type is not set to tape\n"); + + if (!result->rmb) + printk ("The removable flag is not set\n"); + + if (result->ansi_version != 2) { + printk ("The Ansi Version is unknown to us !\n"); + printk ("Assuming compliance with QIC-157C specification.\n"); + } +} + +void idetape_create_request_sense_cmd (idetape_packet_command_t *pc) + +{ +#if IDETAPE_DEBUG + printk ("ide-tape: Creating REQUEST SENSE packet command\n"); +#endif /* IDETAPE_DEBUG */ + pc->request_transfer=18; + pc->callback=&idetape_request_sense_callback; + pc->writing=0; + + idetape_zero_packet_command (pc); + pc->c[0]=IDETAPE_REQUEST_SENSE_CMD; + pc->c[4]=255; +} + +void idetape_request_sense_callback (ide_drive_t *drive) + +{ + idetape_tape_t *tape; + struct request *rq; + + tape=&(drive->tape); + rq=HWGROUP(drive)->rq; + +#if IDETAPE_DEBUG + printk ("ide-tape: Reached idetape_request_sense_callback\n"); +#endif /* IDETAPE_DEBUG */ + if (!tape->pc->error) { +#if IDETAPE_DEBUG + printk ("Request completed\n"); +#endif /* IDETAPE_DEBUG */ + idetape_analyze_error (drive,(idetape_request_sense_result_t *) tape->pc->buffer); + idetape_end_request (1,HWGROUP (drive)); + } + else { + printk ("Error in REQUEST SENSE itself - Aborting request!\n"); + idetape_end_request (0,HWGROUP (drive)); + } + return; +} + +/* + * idetape_analyze_error is called on each failed packet command retry + * to analyze the request sense. We currently do not utilize this + * information. + */ + +void idetape_analyze_error (ide_drive_t *drive,idetape_request_sense_result_t *result) + +{ + idetape_tape_t *tape; + + tape=&(drive->tape); + tape->sense_key=result->sense_key; + tape->asc=result->asc; + tape->ascq=result->ascq; +#if IDETAPE_DEBUG + /* + * Without debugging, we only log an error if we decided to + * give up retrying. + */ + printk ("ide-tape: sense key = %x, asc = %x, ascq = %x\n",result->sense_key,result->asc,result->ascq); +#endif /* IDETAPE_DEBUG */ + return; +} + +void idetape_create_test_unit_ready_cmd (idetape_packet_command_t *pc) + +{ +#if IDETAPE_DEBUG + printk ("ide-tape: Creating TEST UNIT READY packet command\n"); +#endif /* IDETAPE_DEBUG */ + pc->request_transfer=0; + pc->buffer=NULL; + pc->current_position=NULL; + pc->callback=&idetape_pc_callback; + pc->writing=0; + + idetape_zero_packet_command (pc); + pc->c[0]=IDETAPE_TEST_UNIT_READY_CMD; +} + +void idetape_create_locate_cmd (idetape_packet_command_t *pc,unsigned long block,byte partition) + +{ + unsigned long *ptr; + +#if IDETAPE_DEBUG + printk ("ide-tape: Creating LOCATE packet command\n"); +#endif /* IDETAPE_DEBUG */ + pc->request_transfer=0; + pc->buffer=NULL; + pc->current_position=NULL; + pc->buffer_size=0; + pc->wait_for_dsc=1; + pc->callback=&idetape_pc_callback; + pc->writing=0; + + idetape_zero_packet_command (pc); + pc->c [0]=IDETAPE_LOCATE_CMD; + pc->c [1]=2; + ptr=(unsigned long *) &(pc->c[3]); + *ptr=idetape_swap_long (block); + pc->c[8]=partition; +} + +void idetape_create_rewind_cmd (idetape_packet_command_t *pc) + +{ +#if IDETAPE_DEBUG + printk ("ide-tape: Creating REWIND packet command\n"); +#endif /* IDETAPE_DEBUG */ + pc->request_transfer=0; + pc->buffer=NULL; + pc->current_position=NULL; + pc->buffer_size=0; + pc->wait_for_dsc=1; + pc->callback=&idetape_pc_callback; + pc->writing=0; + + idetape_zero_packet_command (pc); + pc->c [0]=IDETAPE_REWIND_CMD; +} + +/* + * A mode sense command is used to "sense" tape parameters. + */ + +void idetape_create_mode_sense_cmd (idetape_packet_command_t *pc,byte page_code) + +{ +#if IDETAPE_DEBUG + printk ("ide-tape: Creating MODE SENSE packet command - Page %d\n",page_code); +#endif /* IDETAPE_DEBUG */ + + pc->wait_for_dsc=0; + pc->callback=&idetape_pc_callback; + pc->writing=0; + + switch (page_code) { + case IDETAPE_CAPABILITIES_PAGE: + pc->request_transfer=24; + } + + idetape_zero_packet_command (pc); + pc->c [0]=IDETAPE_MODE_SENSE_CMD; + pc->c [1]=8; /* DBD = 1 - Don't return block descriptors for now */ + pc->c [2]=page_code; + pc->c [3]=255; /* Don't limit the returned information */ + pc->c [4]=255; /* (We will just discard data in that case) */ +} + +/* + * idetape_create_write_filemark_cmd will: + * + * 1. Write a filemark if write_filemark=1. + * 2. Flush the device buffers without writing a filemark + * if write_filemark=0. + * + */ + +void idetape_create_write_filemark_cmd (idetape_packet_command_t *pc,int write_filemark) + +{ +#if IDETAPE_DEBUG + printk ("Creating WRITE FILEMARK packet command\n"); + if (!write_filemark) + printk ("which will only flush buffered data\n"); +#endif /* IDETAPE_DEBUG */ + pc->request_transfer=0; + pc->buffer=NULL; + pc->current_position=NULL; + pc->buffer_size=0; + pc->wait_for_dsc=1; + pc->callback=&idetape_pc_callback; + pc->writing=0; + + idetape_zero_packet_command (pc); + pc->c [0]=IDETAPE_WRITE_FILEMARK_CMD; + if (write_filemark) + pc->c [4]=1; +} + +void idetape_create_erase_cmd (idetape_packet_command_t *pc) + +{ + +#if IDETAPE_DEBUG + printk ("Creating ERASE command\n"); +#endif /* IDETAPE_DEBUG */ + + pc->request_transfer=0; + pc->buffer=NULL; + pc->current_position=NULL; + pc->buffer_size=0; + pc->wait_for_dsc=1; + pc->callback=&idetape_pc_callback; + pc->writing=0; + + idetape_zero_packet_command (pc); + pc->c [0]=IDETAPE_ERASE_CMD; + pc->c [1]=1; +} + +void idetape_create_read_cmd (idetape_packet_command_t *pc,unsigned long length) + +{ + union convert { + unsigned all :32; + struct { + unsigned b1 :8; + unsigned b2 :8; + unsigned b3 :8; + unsigned b4 :8; + } b; + } original; + +#if IDETAPE_DEBUG + printk ("ide-tape: Creating READ packet command\n"); +#endif /* IDETAPE_DEBUG */ + + original.all=length; + + pc->wait_for_dsc=0; + pc->callback=&idetape_read_callback; + pc->writing=0; + + idetape_zero_packet_command (pc); + pc->c [0]=IDETAPE_READ_CMD; + pc->c [1]=1; + pc->c [4]=original.b.b1; + pc->c [3]=original.b.b2; + pc->c [2]=original.b.b3; + + return; +} + +void idetape_create_space_cmd (idetape_packet_command_t *pc,long count,byte cmd) + +{ + union convert { + unsigned all :32; + struct { + unsigned b1 :8; + unsigned b2 :8; + unsigned b3 :8; + unsigned b4 :8; + } b; + } original; + +#if IDETAPE_DEBUG + printk ("ide-tape: Creating SPACE packet command\n"); +#endif /* IDETAPE_DEBUG */ + + original.all=count; + + pc->request_transfer=0; + pc->buffer=NULL; + pc->current_position=NULL; + pc->buffer_size=0; + pc->wait_for_dsc=1; + pc->callback=&idetape_pc_callback; + pc->writing=0; + + idetape_zero_packet_command (pc); + pc->c [0]=IDETAPE_SPACE_CMD; + pc->c [1]=cmd; + pc->c [4]=original.b.b1; + pc->c [3]=original.b.b2; + pc->c [2]=original.b.b3; + + return; +} + +void idetape_create_write_cmd (idetape_packet_command_t *pc,unsigned long length) + +{ + union convert { + unsigned all :32; + struct { + unsigned b1 :8; + unsigned b2 :8; + unsigned b3 :8; + unsigned b4 :8; + } b; + } original; + +#if IDETAPE_DEBUG + printk ("ide-tape: Creating WRITE packet command\n"); +#endif /* IDETAPE_DEBUG */ + + original.all=length; + + pc->wait_for_dsc=0; + pc->callback=&idetape_write_callback; + pc->writing=1; + + idetape_zero_packet_command (pc); + pc->c [0]=IDETAPE_WRITE_CMD; + pc->c [1]=1; + pc->c [4]=original.b.b1; + pc->c [3]=original.b.b2; + pc->c [2]=original.b.b3; + + return; +} + +void idetape_create_read_position_cmd (idetape_packet_command_t *pc) + +{ +#if IDETAPE_DEBUG + printk ("ide-tape: Creating READ POSITION packet command\n"); +#endif /* IDETAPE_DEBUG */ + + pc->request_transfer=20; + pc->wait_for_dsc=0; + pc->callback=&idetape_read_position_callback; + pc->writing=0; + + idetape_zero_packet_command (pc); + pc->c [0]=IDETAPE_READ_POSITION_CMD; + pc->c [1]=0; +} + +void idetape_read_position_callback (ide_drive_t *drive) + +{ + idetape_tape_t *tape; + struct request *rq; + idetape_read_position_result_t *result; + + tape=&(drive->tape); + +#if IDETAPE_DEBUG + printk ("ide-tape: Reached idetape_read_position_callback\n"); +#endif /* IDETAPE_DEBUG */ + + rq=HWGROUP(drive)->rq; + + if (!tape->pc->error) { + result=(idetape_read_position_result_t *) tape->pc->buffer; +#if IDETAPE_DEBUG + printk ("Request completed\n"); + printk ("Dumping the results of the READ POSITION command\n"); + printk ("BOP - %s\n",result->bop ? "Yes":"No"); + printk ("EOP - %s\n",result->eop ? "Yes":"No"); +#endif /* IDETAPE_DEBUG */ + if (result->bpu) { + printk ("ide-tape: Block location is unknown to the tape\n"); + printk ("Aborting request\n"); + tape->block_address_valid=0; + idetape_end_request (0,HWGROUP (drive)); + } + else { +#if IDETAPE_DEBUG + printk ("Block Location - %lu\n",idetape_swap_long (result->first_block)); +#endif /* IDETAPE_DEBUG */ + tape->block_address=idetape_swap_long (result->first_block); + tape->block_address_valid=1; + idetape_end_request (1,HWGROUP (drive)); + } + } + else { + printk ("Aborting request\n"); + idetape_end_request (0,HWGROUP (drive)); + } + return; +} + +/* + * Our special ide-tape ioctl's. + * + * Currently there aren't any significant ioctl's. + * mtio.h compatible commands should be issued to the character device + * interface. + */ + +int idetape_blkdev_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + idetape_packet_command_t pc; + int retval; + + pc.buffer=pc.temp_buffer; + pc.buffer_size=IDETAPE_TEMP_BUFFER_SIZE; + pc.current_position=pc.temp_buffer; + +#if IDETAPE_DEBUG + printk ("ide-tape: Reached idetape_blkdev_ioctl\n"); +#endif /* IDETAPE_DEBUG */ + switch (cmd) { + case IDETAPE_INQUIRY_IOCTL: +#if IDETAPE_DEBUG + printk ("Adding INQUIRY packet command to the tail of the request queue\n"); +#endif /* IDETAPE_DEBUG */ + idetape_create_inquiry_cmd (&pc); + pc.buffer=pc.temp_buffer; + pc.buffer_size=IDETAPE_TEMP_BUFFER_SIZE; + pc.current_position=pc.temp_buffer; + return (idetape_queue_pc_tail (drive,&pc)); + case IDETAPE_LOCATE_IOCTL: +#if IDETAPE_DEBUG + printk ("Adding LOCATE packet command to the tail of the request queue\n"); +#endif /* IDETAPE_DEBUG */ + idetape_create_locate_cmd (&pc,arg,0); + retval=idetape_queue_pc_tail (drive,&pc); + if (retval!=0) return (retval); + + idetape_create_read_position_cmd (&pc); + pc.buffer=pc.temp_buffer; + pc.buffer_size=IDETAPE_TEMP_BUFFER_SIZE; + pc.current_position=pc.temp_buffer; + return (idetape_queue_pc_tail (drive,&pc)); +/* + case IDETAPE_RESET_IOCTL: + printk ("Resetting drive\n"); + return (!ide_do_reset (drive)); +*/ + default: + return -EIO; + } +} + +/* + * Functions which handle requests. + */ + +/* + * idetape_end_request is used to end a request. + * + * It is very similiar to ide_end_request, with a major difference - If + * we are handling our own requests rather than requests which originate + * in the buffer cache, we set rq->errors to 1 if the request failed. + */ + +void idetape_end_request (byte uptodate, ide_hwgroup_t *hwgroup) + +{ + ide_drive_t *drive = hwgroup->drive; + struct request *rq = hwgroup->rq; + + if (rq->cmd == READ || rq->cmd == WRITE) { /* Buffer cache originated request */ + ide_end_request (uptodate,hwgroup); /* Let the common code handle it */ + return; + } + /* Our own originated request */ + rq->errors=!uptodate; /* rq->errors will tell us if the request was successfull */ + ide_end_drive_cmd (drive, 0, 0); + + /* The "up(rq->sem);" does the necessary "wake_up()" for us, + * providing we started sleeping with a "down()" call. + * This may not be the case if the driver converts a READ or WRITE + * request into a special internal rq->cmd type. -ml + */ + + /* + * As Mark explained, we do not need a "wake_up()" call here, + * since we are always sleeping with a "down()" call. + */ + +} + +/* + * idetape_do_request is our request handling function. + */ + +void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned long block) + +{ + idetape_tape_t *tape; + idetape_packet_command_t *pc; + struct request *new_rq; + idetape_status_reg_t status; + + tape=&(drive->tape); + +#if IDETAPE_DEBUG + printk ("Current request:\n"); + printk ("rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors); + printk ("sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors); +#endif /* IDETAPE_DEBUG */ + + /* Retry a failed packet command */ + + if (tape->failed_pc != NULL && tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) { + idetape_issue_packet_command (drive,tape->failed_pc,&idetape_pc_intr); + return; + } + + /* Check if we have a postponed request */ + + if (tape->postponed_rq != NULL) { +/* #if IDETAPE_DEBUG */ + if (tape->postponed_rq->rq_status != RQ_ACTIVE || rq != tape->postponed_rq) { + printk ("ide-tape: ide-tape.c bug - Two DSC requests were queued\n"); + idetape_end_request (0,HWGROUP (drive)); + return; + } +/* #endif */ /* IDETAPE_DEBUG */ + if (rq->cmd == IDETAPE_PACKET_COMMAND_REQUEST_TYPE1) { + + /* Media access command */ + + tape->postponed_rq = NULL; + idetape_media_access_finished (drive); + return; + } + + /* + * Read / Write command - DSC polling was done before the + * actual command - Continue normally so that the command + * will be performed below. + */ + + tape->postponed_rq = NULL; + } + + + if (rq->cmd == READ || rq->cmd == IDETAPE_READ_REQUEST || rq->cmd == WRITE || rq->cmd == IDETAPE_WRITE_REQUEST) { + + if (!tape->block_address_valid || tape->block_address!=rq->sector) { /* Re-position the tape */ + + if (tape->locate_to == rq->sector && tape->locate_retries > IDETAPE_LOCATE_RETRIES) { + printk ("ide-tape: Can not reach block %lu - Aborting request\n",rq->sector); + tape->locate_retries=0; + idetape_end_request (0,HWGROUP (drive)); + return; + } + + if (tape->locate_to == rq->sector) + tape->locate_retries++; + else { + tape->locate_to=rq->sector; + tape->locate_retries=1; + } +#if IDETAPE_DEBUG + printk ("ide-tape: We are not at the requested block\n"); + printk ("ide-tape: Re-positioning tape\n"); + printk ("ide-tape: Adding READ POSITION command to the head of the queue\n"); +#endif /* IDETAPE_DEBUG */ + pc=idetape_next_pc_storage (drive); + new_rq=idetape_next_rq_storage (drive); + idetape_create_read_position_cmd (pc); + pc->buffer=pc->temp_buffer; + pc->buffer_size=IDETAPE_TEMP_BUFFER_SIZE; + pc->current_position=pc->temp_buffer; + idetape_queue_pc_head (drive,pc,new_rq); +#if IDETAPE_DEBUG + printk ("ide-tape: Adding LOCATE %lu command to the head of the queue\n",rq->sector); +#endif /* IDETAPE_DEBUG */ + pc=idetape_next_pc_storage (drive); + new_rq=idetape_next_rq_storage (drive); + idetape_create_locate_cmd (pc,rq->sector,0); + idetape_queue_pc_head (drive,pc,new_rq); + + if (!tape->block_address_valid) { /* The tape doesn't know the position - help it */ + /* by rewinding the tape */ +#if IDETAPE_DEBUG + printk ("ide-tape: Adding LOCATE 0 command to the head of the queue\n"); +#endif /* IDETAPE_DEBUG */ + pc=idetape_next_pc_storage (drive); + new_rq=idetape_next_rq_storage (drive); + idetape_create_locate_cmd (pc,0,0); + idetape_queue_pc_head (drive,pc,new_rq); + } + + return; + } + else + tape->locate_retries=0; + } + + switch (rq->cmd) { + case READ: + case IDETAPE_READ_REQUEST: +#if IDETAPE_DEBUG + if (rq->cmd == READ) + printk ("ide-tape: Handling buffer cache READ request\n"); + else + printk ("ide-tape: Handling our own (not buffer cache originated) READ request\n"); +#endif /* IDETAPE_DEBUG */ + status.all=IN_BYTE (IDETAPE_STATUS_REG); + if (!status.b.dsc) { /* Tape buffer not ready to accept r/w command */ +#if IDETAPE_DEBUG + printk ("ide-tape: DSC != 1 - Postponing read request\n"); +#endif /* IDETAPE_DEBUG */ + tape->dsc_polling_frequency=IDETAPE_DSC_READ_WRITE_FREQUENCY; + idetape_postpone_request (drive); /* Allow ide.c to process requests from */ + return; + } + + tape->last_written_valid=0; + + pc=idetape_next_pc_storage (drive); + + idetape_create_read_cmd (pc,rq->current_nr_sectors); + + pc->buffer=rq->buffer; + pc->buffer_size=rq->current_nr_sectors*512; + pc->current_position=rq->buffer; + pc->request_transfer=rq->current_nr_sectors*512; + + idetape_issue_packet_command (drive,pc,&idetape_pc_intr); + return; + + case WRITE: + case IDETAPE_WRITE_REQUEST: +#if IDETAPE_DEBUG + if (rq->cmd == WRITE) + printk ("ide-tape: Handling buffer cache WRITE request\n"); + else + printk ("ide-tape: Handling our own (not buffer cache originated) WRITE request\n"); +#endif /* IDETAPE_DEBUG */ + + status.all=IN_BYTE (IDETAPE_STATUS_REG); + if (!status.b.dsc) { /* Tape buffer not ready to accept r/w command */ +#if IDETAPE_DEBUG + printk ("ide-tape: DSC != 1 - Postponing write request\n"); +#endif /* IDETAPE_DEBUG */ + tape->dsc_polling_frequency=IDETAPE_DSC_READ_WRITE_FREQUENCY; + idetape_postpone_request (drive); /* Allow ide.c to process requests from */ + return; + } + + tape->last_written_valid=1; + tape->last_written_block=rq->sector; + + pc=idetape_next_pc_storage (drive); + + idetape_create_write_cmd (pc,rq->current_nr_sectors); + + pc->buffer=rq->buffer; + pc->buffer_size=rq->current_nr_sectors*512; + pc->current_position=rq->buffer; + pc->request_transfer=rq->current_nr_sectors*512; + + idetape_issue_packet_command (drive,pc,&idetape_pc_intr); + return; + + case IDETAPE_PACKET_COMMAND_REQUEST_TYPE1: + case IDETAPE_PACKET_COMMAND_REQUEST_TYPE2: +/* + * This should be unnecessary (postponing of a general packet command), + * but I have occasionally missed DSC on a media access command otherwise. + * ??? Still have to figure it out ... + */ + status.all=IN_BYTE (IDETAPE_STATUS_REG); + if (!status.b.dsc) { /* Tape buffers are still not ready */ +#if IDETAPE_DEBUG + printk ("ide-tape: DSC != 1 - Postponing packet command request\n"); +#endif IDETAPE_DEBUG + rq->cmd=IDETAPE_PACKET_COMMAND_REQUEST_TYPE2; /* Note that we are waiting for DSC *before* we */ + /* even issued the command */ + tape->dsc_polling_frequency=IDETAPE_DSC_READ_WRITE_FREQUENCY; + idetape_postpone_request (drive); /* Allow ide.c to process requests from */ + return; + } + rq->cmd=IDETAPE_PACKET_COMMAND_REQUEST_TYPE1; + pc=(idetape_packet_command_t *) rq->buffer; + idetape_issue_packet_command (drive,pc,&idetape_pc_intr); + return; + + default: + printk ("ide-tape: Unknown command in request - Aborting request\n"); + idetape_end_request (0,HWGROUP (drive)); + } +} + +/* + * idetape_queue_pc_tail is based on the following functions: + * + * ide_do_drive_cmd from ide.c + * cdrom_queue_request and cdrom_queue_packet_command from ide-cd.c + * + * We add a special packet command request to the tail of the request queue, + * and wait for it to be serviced. + * + * This is not to be called from within the request handling part + * of the driver ! We allocate here data in the stack, and it is valid + * until the request is finished. This is not the case for the bottom + * part of the driver, where we are always leaving the functions to wait + * for an interrupt or a timer event. + * + * From the bottom part of the driver, we should allocate safe memory + * using idetape_next_pc_storage and idetape_next_rq_storage, and add + * the request to the request list without waiting for it to be serviced ! + * In that case, we usually use idetape_queue_pc_head. + */ + +int idetape_queue_pc_tail (ide_drive_t *drive,idetape_packet_command_t *pc) +{ + struct request rq; + + ide_init_drive_cmd (&rq); + rq.buffer = (char *) pc; + rq.cmd = IDETAPE_PACKET_COMMAND_REQUEST_TYPE1; + return ide_do_drive_cmd (drive, &rq, ide_wait); +} + +/* + * idetape_queue_pc_head generates a new packet command request in front + * of the request queue, before the current request, so that it will be + * processed immediately, on the next pass through the driver. + * + * idetape_queue_pc_head is called from the request handling part of + * the driver (the "bottom" part). Safe storage for the request should + * be allocated with idetape_next_pc_storage and idetape_next_rq_storage + * before calling idetape_queue_pc_head. + * + * Memory for those requests is pre-allocated at initialization time, and + * is limited to IDETAPE_PC_STACK requests. We assume that we have enough + * space for the maximum possible number of inter-dependent packet commands. + * + * The higher level of the driver - The ioctl handler and the character + * device handling functions should queue request to the lower level part + * and wait for their completion using idetape_queue_pc_tail or + * idetape_queue_rw_tail. + */ + +void idetape_queue_pc_head (ide_drive_t *drive,idetape_packet_command_t *pc,struct request *rq) + +{ + ide_init_drive_cmd (rq); + rq->buffer = (char *) pc; + rq->cmd = IDETAPE_PACKET_COMMAND_REQUEST_TYPE1; + (void) ide_do_drive_cmd (drive, rq, ide_preempt); +} + +/* + * idetape_queue_rw_tail is typically called from the character device + * interface to generate a read/write request for the block device interface + * and wait for it to be serviced. Note that cmd will be different than + * a buffer cache originated read/write request. This will be used + * in idetape_end_request. + * + * Returns 0 on success or -EIO if an error occured. + */ + +int idetape_queue_rw_tail (ide_drive_t *drive,int cmd,int blocks,char *buffer) + +{ + idetape_tape_t *tape = &(drive->tape); + struct request rq; + +#if IDETAPE_DEBUG + printk ("idetape_queue_rw_tail: cmd=%d\n",cmd); +#endif /* IDETAPE_DEBUG */ + /* build up a special read request, and add it to the queue */ + + ide_init_drive_cmd (&rq); + rq.buffer = buffer; + rq.cmd = cmd; + rq.sector = tape->block_address; + rq.nr_sectors = blocks; + rq.current_nr_sectors = blocks; + return ide_do_drive_cmd (drive, &rq, ide_wait); +} + +/* + * Copied from ide.c (declared static there) + */ + +void idetape_fixstring (byte *s, const int bytecount, const int byteswap) +{ + byte *p = s, *end = &s[bytecount & ~1]; /* bytecount must be even */ + + if (byteswap) { + /* convert from big-endian to host byte order */ + for (p = end ; p != s;) { + unsigned short *pp = (unsigned short *) (p -= 2); + *pp = ntohs(*pp); + } + } + + /* strip leading blanks */ + while (s != end && *s == ' ') + ++s; + + /* compress internal blanks and strip trailing blanks */ + while (s != end && *s) { + if (*s++ != ' ' || (s != end && *s && *s != ' ')) + *p++ = *(s-1); + } + + /* wipe out trailing garbage */ + while (p != end) + *p++ = '\0'; +} + +/* + * idetape_zero_packet_command just zeros a packet command and + * sets the number of retries to 0, as we haven't retried it yet. + */ + +void idetape_zero_packet_command (idetape_packet_command_t *pc) + +{ + int i; + + for (i=0;i<12;i++) + pc->c[i]=0; + pc->retries=0; +} + +/* + * idetape_swap_shorts converts a 16 bit number from little endian + * to big endian format. + */ + +unsigned short idetape_swap_short (unsigned short temp) + +{ + union convert { + unsigned all :16; + struct { + unsigned b1 :8; + unsigned b2 :8; + } b; + } original,converted; + + original.all=temp; + converted.b.b1=original.b.b2; + converted.b.b2=original.b.b1; + return (converted.all); +} + +/* + * idetape_swap_long converts from little endian to big endian format. + */ + +unsigned long idetape_swap_long (unsigned long temp) + +{ + union convert { + unsigned all :32; + struct { + unsigned b1 :8; + unsigned b2 :8; + unsigned b3 :8; + unsigned b4 :8; + } b; + } original,converted; + + original.all=temp; + converted.b.b1=original.b.b4; + converted.b.b2=original.b.b3; + converted.b.b3=original.b.b2; + converted.b.b4=original.b.b1; + return (converted.all); +} + + +/* + * idetape_next_pc_storage returns a pointer to a place in which we can + * safely store a packet command, even though we intend to leave the + * driver. A storage space for a maximum of IDETAPE_PC_STACK packet + * commands is allocated at initialization time. + */ + +idetape_packet_command_t *idetape_next_pc_storage (ide_drive_t *drive) + +{ + idetape_tape_t *tape; + + tape=&(drive->tape); +#if IDETAPE_DEBUG + printk ("ide-tape: pc_stack_index=%d\n",tape->pc_stack_index); +#endif /* IDETAPE_DEBUG */ + if (tape->pc_stack_index==IDETAPE_PC_STACK) + tape->pc_stack_index=0; + return (&(tape->pc_stack [tape->pc_stack_index++])); +} + +/* + * idetape_next_rq_storage is used along with idetape_next_pc_storage. + * Since we queue packet commands in the request queue, we need to + * allocate a request, along with the allocation of a packet command. + */ + +/************************************************************** + * * + * This should get fixed to use kmalloc(GFP_ATOMIC, ..) * + * followed later on by kfree(). -ml * + * * + **************************************************************/ + +struct request *idetape_next_rq_storage (ide_drive_t *drive) + +{ + idetape_tape_t *tape; + + tape=&(drive->tape); + +#if IDETAPE_DEBUG + printk ("ide-tape: rq_stack_index=%d\n",tape->rq_stack_index); +#endif /* IDETAPE_DEBUG */ + if (tape->rq_stack_index==IDETAPE_PC_STACK) + tape->rq_stack_index=0; + return (&(tape->rq_stack [tape->rq_stack_index++])); +} + +/* + * Block device interface functions + * + * The default action is not to allow direct access to the block device + * interface (-EBUSY will be returned on open). + */ + +int idetape_blkdev_open (struct inode *inode, struct file *filp, ide_drive_t *drive) + +{ +#if IDETAPE_ALLOW_OPENING_BLOCK_DEVICE + return (0); +#else + printk ("ide-tape: The block device interface should not be used.\n"); + printk ("ide-tape: Use the character device interfaces\n"); + printk ("ide-tape: /dev/ht0 and /dev/nht0 instead.\n"); + printk ("ide-tape: (Run linux/drivers/block/MAKEDEV.ide to create them)\n"); + printk ("ide-tape: Refusing open request.\n"); + return (-EBUSY); +#endif /* IDETAPE_ALLOW_OPENING_BLOCK_DEVICE */ +} + +void idetape_blkdev_release (struct inode *inode, struct file *filp, ide_drive_t *drive) + +{ + return; +} + +/* + * Character device interface functions + */ + +/* + * lseek is currently not installed. + */ + +int idetape_chrdev_lseek (struct inode *inode, struct file *file, off_t offset, int origin) + +{ + ide_drive_t *drive; + +#if IDETAPE_DEBUG + printk ("Reached idetape_chrdev_lseek\n"); +#endif /* IDETAPE_DEBUG */ + + drive=idetape_chrdev.drive; + if (idetape_position_tape (drive,offset) != 0) { + printk ("ide-tape: Rewinding tape failed\n"); + return (-1); + } + + return (0); +} + +/* + * Our character device read / write functions. + * + * The tape is optimized to maximize throughpot when it is transfering + * an integral number of the "continous transfer limit", which is + * a parameter of the specific tape (26 KB on my particular tape). The + * resulting increase in performance should be dramatical. In the + * character device read/write functions, we split the current + * request to units of the above size, and handle the remaining bytes + * in some other sub-functions. + * + * In case the count number is not even an integral number of the tape + * block size (usually 512 or 1024 bytes), we will pad the transfer with + * zeroes (write) or read the entire block and return only the requested + * bytes (but the tape will be in the "wrong" position). Do not supply + * such a count value unless you are going to close the device right + * after this request. + * + * Again, for best results use an integral number of the tape's parameter + * (which is displayed in the driver installation stage). I will soon + * add an ioctl to get this important parameter. + */ + +/* + * Our character device read function. + */ + +int idetape_chrdev_read (struct inode *inode, struct file *file, char *buf, int count) + +{ + ide_drive_t *drive; + idetape_tape_t *tape; + int blocks,remainder,retval,ctl_bytes; + char *buf_ptr; + unsigned long previous_block_address,actually_read; + +#if IDETAPE_DEBUG + printk ("Reached idetape_chrdev_read\n"); +#endif /* IDETAPE_DEBUG */ + + drive=idetape_chrdev.drive; + tape=&(drive->tape); + tape->last_dt_was_write=0; + + if (count==0) + return (0); + + actually_read=0; + buf_ptr=buf; + ctl_bytes=tape->capabilities.ctl*tape->tape_block_size; + blocks=count/ctl_bytes; + remainder=count%ctl_bytes; + + while (blocks) { +#if IDETAPE_DEBUG + printk ("Adding a READ request to the block device request queue\n"); +#endif /* IDETAPE_DEBUG */ + previous_block_address=tape->block_address; + retval=idetape_queue_rw_tail (drive,IDETAPE_READ_REQUEST,tape->capabilities.ctl,tape->data_buffer); + actually_read+=tape->tape_block_size*(tape->block_address-previous_block_address); + + if (retval) { + printk ("ide-tape: Error occured while reading\n"); + return (actually_read); + } +#if IDETAPE_DEBUG + printk ("Copying %d bytes to the user space memory\n",ctl_bytes); +#endif /* IDETAPE_DEBUG */ + + memcpy_tofs (buf_ptr,tape->data_buffer,ctl_bytes); + buf_ptr+=ctl_bytes; + blocks--; + } + if (remainder) + return (actually_read+idetape_chrdev_read_remainder (inode,file,buf_ptr,remainder)); + else + return (actually_read); +} + +int idetape_chrdev_read_remainder (struct inode *inode, struct file *file, char *buf, int count) + +{ + ide_drive_t *drive; + idetape_tape_t *tape; + int blocks,remainder,retval; + unsigned long previous_block_address,actually_read; + +#if IDETAPE_DEBUG + printk ("Reached idetape_chrdev_read_remainder\n"); +#endif /* IDETAPE_DEBUG */ + + drive=idetape_chrdev.drive; + tape=&(drive->tape); + + tape->last_dt_was_write=0; + + if (count==0) + return (0); + + + blocks=count/512; + remainder=count%512; + if (remainder) { +#if IDETAPE_DEBUG + printk ("ide-tape: Padding read to block boundary\n"); +#endif /* IDETAPE_DEBUG */ + blocks++; + } +#if IDETAPE_DEBUG + printk ("Adding a READ request to the block device request queue\n"); +#endif /* IDETAPE_DEBUG */ + previous_block_address=tape->block_address; + retval=idetape_queue_rw_tail (drive,IDETAPE_READ_REQUEST,blocks,tape->data_buffer); + if (retval) { + printk ("ide-tape: Error occured while reading\n"); + actually_read=512*(tape->block_address-previous_block_address); + if (actually_read > count) + actually_read=count; + if (actually_read != 0) + memcpy_tofs (buf,tape->data_buffer,actually_read); + return (actually_read); + } +#if IDETAPE_DEBUG + printk ("Copying %d bytes to the user space memory\n",count); +#endif /* IDETAPE_DEBUG */ + memcpy_tofs (buf,tape->data_buffer,count); + return (count); +} + +int idetape_chrdev_write (struct inode *inode, struct file *file, const char *buf, int count) + +{ + ide_drive_t *drive; + idetape_tape_t *tape; + int blocks,remainder,retval,ctl_bytes; + const char *buf_ptr; + unsigned long previous_block_address,actually_written; + +#if IDETAPE_DEBUG + printk ("Reached idetape_chrdev_write\n"); +#endif /* IDETAPE_DEBUG */ + + drive=idetape_chrdev.drive; + tape=&(drive->tape); + tape->last_dt_was_write=1; + + if (count==0) + return (0); + + actually_written=0; + buf_ptr=buf; + ctl_bytes=tape->capabilities.ctl*tape->tape_block_size; + blocks=count/ctl_bytes; + remainder=count%ctl_bytes; + + while (blocks) { +#if IDETAPE_DEBUG + printk ("Copying %d bytes from the user space memory\n",ctl_bytes); +#endif /* IDETAPE_DEBUG */ + memcpy_fromfs (tape->data_buffer,buf_ptr,ctl_bytes); + buf_ptr+=ctl_bytes; +#if IDETAPE_DEBUG + printk ("Adding a WRITE request to the block device request queue\n"); +#endif /* IDETAPE_DEBUG */ + previous_block_address=tape->block_address; + retval=idetape_queue_rw_tail (drive,IDETAPE_WRITE_REQUEST,tape->capabilities.ctl,tape->data_buffer); + actually_written+=tape->tape_block_size*(tape->block_address-previous_block_address); + + if (retval) { + printk ("ide-tape: Error occured while writing\n"); + return (actually_written); + } + blocks--; + } + if (remainder) + return (actually_written+idetape_chrdev_write_remainder (inode,file,buf_ptr,remainder)); + else + return (actually_written); +} + +int idetape_chrdev_write_remainder (struct inode *inode, struct file *file, const char *buf, int count) + +{ + ide_drive_t *drive; + idetape_tape_t *tape; + int blocks,remainder,retval; + char *ptr; + unsigned long previous_block_address,actually_written; + +#if IDETAPE_DEBUG + printk ("Reached idetape_chrdev_write_remainder\n"); +#endif /* IDETAPE_DEBUG */ + + drive=idetape_chrdev.drive; + tape=&(drive->tape); + + blocks=count/512; + remainder=count%512; + if (remainder) + blocks++; +#if IDETAPE_DEBUG + printk ("Copying %d bytes from the user space memory\n",count); +#endif /* IDETAPE_DEBUG */ + + memcpy_fromfs (tape->data_buffer,buf,count); + if (remainder) { +#if IDETAPE_DEBUG + printk ("ide-tape: Padding written data to block boundary\n"); +#endif /* IDETAPE_DEBUG */ + ptr=tape->data_buffer+(blocks-1)*512; + memset (ptr,0,remainder); + } +#if IDETAPE_DEBUG + printk ("Adding a WRITE request to the block device request queue\n"); +#endif /* IDETAPE_DEBUG */ + + previous_block_address=tape->block_address; + retval=idetape_queue_rw_tail (drive,IDETAPE_WRITE_REQUEST,blocks,tape->data_buffer); + if (retval) { + printk ("ide-tape: Error occured while writing\n"); + actually_written=512*(tape->block_address-previous_block_address); + if (actually_written > count) + actually_written=count; + return (actually_written); + } + return (count); +} + +/* + * Our character device ioctls. + * + * General mtio.h magnetic io commands are supported here, and not in + * the correspoding block interface. + * + * Our own ide-tape ioctls are supported on both interfaces. + */ + +int idetape_chrdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) + +{ + struct mtop mtop; + ide_drive_t *drive; + int retval; + +#if IDETAPE_DEBUG + printk ("Reached idetape_chrdev_ioctl, cmd=%u\n",cmd); +#endif + + drive=idetape_chrdev.drive; + + switch (cmd) { + case MTIOCTOP: + retval=verify_area (VERIFY_READ,(char *) arg,sizeof (struct mtop)); + if (retval) return (retval); + memcpy_fromfs ((char *) &mtop, (char *) arg, sizeof (struct mtop)); + return (idetape_mtioctop (drive,mtop.mt_op,mtop.mt_count)); + default: + return (idetape_blkdev_ioctl (drive,inode,file,cmd,arg)); + } +} + +/* + * idetape_mtioctop is called from idetape_chrdev_ioctl when + * the general mtio MTIOCTOP ioctl is requested. + * + * We currently support the following mtio.h operations: + * + * MTFSF - Space over mt_count filemarks in the positive direction. + * The tape is positioned after the last spaced filemark. + * + * MTFSFM - Same as MTFSF, but the tape is positioned before the + * last filemark. + * + * MTBSF - Steps background over mt_count filemarks, tape is + * positioned before the last filemark. + * + * MTBSFM - Like MTBSF, only tape is positioned after the last filemark. + * + * MTWEOF - Writes mt_count filemarks. Tape is positioned after + * the last written filemark. + * + * MTREW - Rewindes tape. + * + * MTNOP - Flushes tape buffers. + * + * MTEOM - Moves to the end of recorded data. + * + * MTERASE - Erases tape. + * + * The following commands are currently not supported: + * + * MTFSR, MTBSR, MTFSS, MTBSS, MTWSM, MTOFFL, MTRETEN, MTSEEK, MTSETBLK, + * MTSETDENSITY, MTSETDRVBUFFER, MT_ST_BOOLEANS, MT_ST_WRITE_THRESHOLD. + */ + +int idetape_mtioctop (ide_drive_t *drive,short mt_op,int mt_count) + +{ + int i,retval; + + idetape_packet_command_t pc; + + pc.buffer=pc.temp_buffer; + pc.buffer_size=IDETAPE_TEMP_BUFFER_SIZE; + pc.current_position=pc.temp_buffer; + + idetape_create_write_filemark_cmd (&pc,0); /* Flush buffers */ + retval=idetape_queue_pc_tail (drive,&pc); + if (retval) return (retval); + + switch (mt_op) { + case MTFSF: +#if IDETAPE_DEBUG + printk ("Handling MTFSF command\n"); +#endif /* IDETAPE_DEBUG */ + idetape_create_space_cmd (&pc,mt_count,IDETAPE_SPACE_OVER_FILEMARK); + return (idetape_queue_pc_tail (drive,&pc)); + case MTFSFM: +#if IDETAPE_DEBUG + printk ("Handling MTFSFM command\n"); +#endif /* IDETAPE_DEBUG */ + retval=idetape_mtioctop (drive,MTFSF,mt_count); + if (retval) return (retval); + return (idetape_mtioctop (drive,MTBSF,1)); + case MTBSF: +#if IDETAPE_DEBUG + printk ("Handling MTBSF command\n"); +#endif /* IDETAPE_DEBUG */ + idetape_create_space_cmd (&pc,-mt_count,IDETAPE_SPACE_OVER_FILEMARK); + return (idetape_queue_pc_tail (drive,&pc)); + case MTBSFM: +#if IDETAPE_DEBUG + printk ("Handling MTBSFM command\n"); +#endif /* IDETAPE_DEBUG */ + retval=idetape_mtioctop (drive,MTBSF,mt_count); + if (retval) return (retval); + return (idetape_mtioctop (drive,MTFSF,1)); + case MTWEOF: +#if IDETAPE_DEBUG + printk ("Handling MTWEOF command\n"); +#endif /* IDETAPE_DEBUG */ + + for (i=0;itape); + minor=MINOR (inode->i_rdev); + + if (minor!=0 && minor!=128) { /* Currently supporting only one */ + restore_flags (flags); /* tape drive */ + return (-ENXIO); + } + + if (tape->busy) { + restore_flags (flags); /* Allowing access only through one */ + return (-EBUSY); /* one file descriptor */ + } + + tape->busy=1; + restore_flags (flags); + + if (!tape->block_address_valid) { + if (idetape_rewind_tape (drive)) { + printk ("ide-tape: Rewinding tape failed\n"); + tape->busy=0; + return (-EIO); + } + } + + tape->last_dt_was_write=0; + + return (0); +} + +/* + * Our character device release function. + */ + +void idetape_chrdev_release (struct inode *inode, struct file *filp) + +{ + ide_drive_t *drive; + idetape_tape_t *tape; + + unsigned int minor; + idetape_packet_command_t pc; + unsigned long flags; + +#if IDETAPE_DEBUG + printk ("Reached idetape_chrdev_release\n"); +#endif /* IDETAPE_DEBUG */ + + drive=idetape_chrdev.drive; + tape=&(drive->tape); + minor=MINOR (inode->i_rdev); + + if (tape->last_dt_was_write) { + idetape_create_write_filemark_cmd (&pc,1); /* Write a filemark */ + if (idetape_queue_pc_tail (drive,&pc)) { + printk ("ide-tape: Couldn't write a filemark\n"); + /* ??? */ + } + } + else { + idetape_create_write_filemark_cmd (&pc,0); /* Flush buffers */ + if (idetape_queue_pc_tail (drive,&pc)) { + printk ("ide-tape: Couldn't flush buffers\n"); + /* ??? */ + } + } + + if (minor < 128) { + if (idetape_rewind_tape (drive)) { + printk ("ide-tape: Rewinding tape failed\n"); + /* ??? */ + } + } + + save_flags (flags); + cli(); + tape->busy=0; + restore_flags (flags); + + return; +} + +/* + * idetape_position_tape positions the tape to the requested block + * using the LOCATE packet command. A READ POSITION command is then + * issued to check where we are positioned. + * + * Like all higher level operations, we queue the commands at the tail + * of the request queue and wait for their completion. + * + */ + +int idetape_position_tape (ide_drive_t *drive,unsigned long block) + +{ + int retval; + idetape_packet_command_t pc; + + idetape_create_locate_cmd (&pc,block,0); + retval=idetape_queue_pc_tail (drive,&pc); + if (retval!=0) return (retval); + + idetape_create_read_position_cmd (&pc); + pc.buffer=pc.temp_buffer; + pc.buffer_size=IDETAPE_TEMP_BUFFER_SIZE; + pc.current_position=pc.temp_buffer; + return (idetape_queue_pc_tail (drive,&pc)); +} + +/* + * Rewinds the tape to the Begining Of the current Partition (BOP). + * + * We currently support only one partition. + */ + +int idetape_rewind_tape (ide_drive_t *drive) + +{ + int retval; + idetape_packet_command_t pc; +#if IDETAPE_DEBUG + printk ("Reached idetape_rewind_tape\n"); +#endif /* IDETAPE_DEBUG */ + + idetape_create_write_filemark_cmd (&pc,0); /* Flush buffers */ + retval=idetape_queue_pc_tail (drive,&pc); + if (retval) return (retval); + + idetape_create_rewind_cmd (&pc); + retval=idetape_queue_pc_tail (drive,&pc); + if (retval) return (retval); + + idetape_create_read_position_cmd (&pc); + pc.buffer=pc.temp_buffer; + pc.buffer_size=IDETAPE_TEMP_BUFFER_SIZE; + pc.current_position=pc.temp_buffer; + return (idetape_queue_pc_tail (drive,&pc)); +} diff -u --recursive --new-file v1.3.45/linux/drivers/block/ide-tape.h linux/drivers/block/ide-tape.h --- v1.3.45/linux/drivers/block/ide-tape.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/block/ide-tape.h Mon Dec 11 08:49:54 1995 @@ -0,0 +1,327 @@ +/* + * linux/drivers/block/ide-tape.h Version 1.0 - ALPHA Dec 3, 1995 + * + * Copyright (C) 1995 Gadi Oxman + */ + +/* + * Include file for the IDE ATAPI streaming tape driver. + * + * This file contains various ide-tape related structures and function + * prototypes which are already used in ide.h. + * + * The various compile time options are described below. + */ + +#ifndef IDETAPE_H +#define IDETAPE_H + +/**************************** Tunable parameters *****************************/ + +/* + * Setting IDETAPE_DEBUG to 1 will: + * + * 1. Generally log all driver actions. + * 2. Enable self-sanity checks in some places. + * + * Use IDETAPE_DEBUG when encountering a problem with the driver. + * + * Setting IDETAPE_DEBUG to 0 will restore normal operation mode: + * + * 1. Disable logging normal successful operations. + * 2. Disable self-sanity checks. + * 3. Errors will still be logged, of course. + */ + +#define IDETAPE_DEBUG 0 + +/* + * After each failed packet command we issue a request sense command + * and retry the packet command IDETAPE_MAX_PC_RETRIES times. + * + * Setting IDETAPE_MAX_PC_RETRIES to 0 will disable retries. + */ + +#define IDETAPE_MAX_PC_RETRIES 2 + +/* + * In case the tape is not at the requested block, we re-position the + * tape. Repeat the procedure for IDETAPE_LOCATE_RETRIES times before + * we give up and abort the request. Note that this should not usually + * happen when using only the character device interface. + */ + +#define IDETAPE_LOCATE_RETRIES 1 + +/* + * With each packet command, we allocate a buffer of + * IDETAPE_TEMP_BUFFER_SIZE bytes. This is used for several packet + * commands (Not for READ/WRITE commands). + * + * The default below is too high - We should be using around 100 bytes + * typically, but I didn't check all the cases, so I rather be on the + * safe size. + */ + +#define IDETAPE_TEMP_BUFFER_SIZE 256 + +/* + * In various places in the driver, we need to allocate storage + * for packet commands and requests, which will remain valid while + * we leave the driver to wait for an interrupt or a timeout event. + * + * In the corresponding ide_drive_t structure, we pre-allocate storage + * for IDETAPE_PC_STACK packet commands and requests. This storage is + * used as a circular array - Each time we reach the last entry, we + * warp around to the first. + * + * It is crucial that we have enough entries for the maximum number + * of packet commands / sub-requests which we need to allocate during + * the handling of a specific request. + * + * Follows a worse case calculation of the required storage, with a + * large safety margin. Hopefully. :-) + */ + +#define IDETAPE_PC_STACK 10+\ + IDETAPE_MAX_PC_RETRIES+\ + 3*IDETAPE_LOCATE_RETRIES*IDETAPE_MAX_PC_RETRIES +/* + * Media access packet command (like the LOCATE command) have immediate + * status with a delayed (and usually long) execution. The tape doesn't + * issue an interrupt when the command is actually complete (so that the + * bus is freed to use the other IDE device on the same interface), so we + * must for poll for this event. + * + * We set a timer with polling frequency of 1/IDETAPE_DSC_MEDIA_ACCESS_FREQUENCY + * in this case. We also poll for DSC *before* read/write commands. At + * this time the DSC role is changed and instead of signalling command + * completion, it will signal buffer availability. Since read/write + * commands are fast in comparision to media access commands, the polling + * frequency here should be much higher. + * + * We will insist of reading DSC=1 for IDETAPE_DSC_COUNT times in a row, + * to accommodate for random fluctuations in the sampling of DSC. + * We will also set IDETAPE_DSC_POLLING_FREQUENCY to a rather low + * frequency which besides freeing the CPU and the bus will let + * random fluctuations a time to settle down. + * + * We also set a timeout for the timer, in case something goes wrong. + * The timeout should be longer then the maximum execution time of a + * tape operation. I still have to measure exactly how much time does + * it take to space over a far filemark, etc. It seemed that 15 minutes + * was way too low, so I am meanwhile setting it to a rather large + * timeout - 2 Hours. + * + * Once we pass a threshold, the polling frequency will change to + * a slow frequency: On relatively fast operations, there is a point + * in polling fast, but if we sense that the operation is taking too + * much time, we will poll at a lower frequency. + */ + +#define IDETAPE_DSC_FAST_MEDIA_ACCESS_FREQUENCY 1*HZ /* 1 second */ +#define IDETAPE_FAST_SLOW_THRESHOLD 5*60*HZ /* 5 minutes */ +#define IDETAPE_DSC_SLOW_MEDIA_ACCESS_FREQUENCY 60*HZ /* 1 minute */ +#define IDETAPE_DSC_READ_WRITE_FREQUENCY HZ/20 /* 50 msec */ +#define IDETAPE_DSC_TIMEOUT 2*60*60*HZ /* 2 hours */ +#define IDETAPE_DSC_COUNT 1 /* Assume no DSC fluctuations */ + +/* + * As explained in many places through the code, we provide both a block + * device and a character device interface to the tape. The block device + * interface is needed for compatibility with ide.c. The character device + * interface is the higher level of the driver, and passes requests + * to the lower part of the driver which interfaces with ide.c. + * Using the block device interface, we can bypass this high level + * of the driver, talking directly with the lower level part. + * + * It is intended that the character device interface will be used by + * the user. To prevent mistakes in this regard, opening of the block + * device interface will be refused if ALLOW_OPENING_BLOCK_DEVICE is 0. + * + * Do not change the following parameter unless you are developing + * the driver itself. + */ + +#define IDETAPE_ALLOW_OPENING_BLOCK_DEVICE 0 + +/*************************** End of tunable parameters ***********************/ + +/* + * Definitions which are already needed in ide.h + */ + +/* + * The following is currently not used. + */ + +typedef enum {no_excess_data,excess_data_read,excess_data_write} excess_data_status_t; + + +struct ide_drive_s; /* Forward declaration - Will be defined later in ide.h */ +typedef void (idetape_pc_completed_t)(struct ide_drive_s *); + +/* + * Our view of a packet command. + */ + +typedef struct idetape_packet_command_s { + byte c [12]; /* Actual packet bytes */ + + byte retries; /* On each retry, we increment retries */ + byte error; /* Set when an error occured */ + byte active; /* Set when a packet command is in progress */ + byte wait_for_dsc; /* 1 When polling for DSC */ + byte dsc_count; + unsigned long request_transfer; /* Bytes to transfer */ + unsigned long actually_transferred; /* Bytes actually transferred */ + unsigned long buffer_size; /* Size of our data buffer */ + byte *buffer; /* Data buffer */ + byte *current_position; /* Pointer into the above buffer */ + byte writing; /* Data direction */ + idetape_pc_completed_t *callback; /* Called when this packet command is completed */ + byte temp_buffer [IDETAPE_TEMP_BUFFER_SIZE]; /* Temporary buffer */ +} idetape_packet_command_t; + +/* + * Capabilities and Mechanical Status Page + */ + +typedef struct { + unsigned page_code :6; /* Page code - Should be 0x2a */ + unsigned reserved1_67 :2; + byte page_length; /* Page Length - Should be 0x12 */ + byte reserved2; + byte reserved3; + unsigned ro :1; /* Read Only Mode */ + unsigned reserved4_1234 :4; + unsigned sprev :1; /* Supports SPACE in the reverse direction */ + unsigned reserved4_67 :2; + unsigned reserved5_012 :3; + unsigned efmt :1; /* Supports ERASE command initiated formatting */ + unsigned reserved5_4 :1; + unsigned qfa :1; /* Supports the QFA two partition formats */ + unsigned reserved5_67 :2; + unsigned lock :1; /* Supports locking the volume */ + unsigned locked :1; /* The volume is locked */ + unsigned prevent :1; /* The device defaults in the prevent state after power up */ + unsigned eject :1; /* The device can eject the volume */ + unsigned reserved6_45 :2; /* Reserved */ + unsigned ecc :1; /* Supports error correction */ + unsigned cmprs :1; /* Supports data compression */ + unsigned reserved7_0 :1; + unsigned blk512 :1; /* Supports 512 bytes block size */ + unsigned blk1024 :1; /* Supports 1024 bytes block size */ + unsigned reserved7_3_6 :4; + unsigned slowb :1; /* The device restricts the byte count for PIO */ + /* transfers for slow buffer memory ??? */ + unsigned short max_speed; /* Maximum speed supported in KBps */ + byte reserved10; + byte reserved11; + unsigned short ctl; /* Continuous Transfer Limit in blocks */ + unsigned short speed; /* Current Speed, in KBps */ + unsigned short buffer_size; /* Buffer Size, in 512 bytes */ + byte reserved18; + byte reserved19; +} idetape_capabilities_page_t; + +/* + * Most of our global data which we need to save even as we leave the + * driver due to an interrupt or a timer event is stored in a variable + * of type tape_info, defined below. + * + * Additional global variables which provide the link between the + * character device interface to this structure are defined in + * ide-tape.c + */ + +typedef struct { + + /* + * Since a typical character device operation requires more + * than one packet command, we provide here enough memory + * for the maximum of interconnected packet commands. + * The packet commands are stored in the circular array pc_stack. + * pc_stack_index points to the last used entry, and warps around + * to the start when we get to the last array entry. + * + * pc points to the current processed packet command. + * + * failed_pc points to the last failed packet command, or contains + * NULL if we do not need to retry any packet command. This is + * required since an additional packet command is needed before the + * retry, to get detailed information on what went wrong. + */ + + idetape_packet_command_t *pc; /* Current packet command */ + idetape_packet_command_t *failed_pc; /* Last failed packet command */ + idetape_packet_command_t pc_stack [IDETAPE_PC_STACK]; /* Packet command stack */ + byte pc_stack_index; /* Next free packet command storage space */ + + /* + * The Linux ide driver basically traverses the request lists + * of the ide block devices, finds the next request, completes + * it, and passes to the next one. This is done in ide_do_request. + * + * In this regard, ide-tape.c is fully compatible with the rest of + * the ide driver - From the point of view of ide.c, we are just + * another ide block device which receives requests and completes + * them. + * + * However, our requests usually don't originate in the buffer + * cache but rather in ide-tape.c itself. Here we provide safe + * storage for such requests. + */ + + struct request rq_stack [IDETAPE_PC_STACK]; + byte rq_stack_index; /* We implement a circular array */ + + /* + * While polling for DSC we use postponed_rq to postpone the + * current request so that ide.c will be able to service + * pending requests on the other device. + */ + + struct request *postponed_rq; + byte dsc_count; + unsigned long dsc_polling_start; + struct timer_list dsc_timer; /* Timer used to poll for dsc */ + unsigned long dsc_polling_frequency; + unsigned long dsc_timeout; /* Maximum waiting time */ + byte dsc_received; + + /* Position information */ + + byte partition_num; /* Currently not used */ + unsigned long block_address; /* Current block */ + byte block_address_valid; /* 0 When the tape position is unknown */ + /* (To the tape or to us) */ + unsigned long locate_to; /* We want to reach this block, as a part */ + /* of handling the current request */ + byte locate_retries; /* Each time, increase locate_retries */ + + unsigned long last_written_block; /* Once writing started, we don't allow read */ + byte last_written_valid; /* access beyond the last written block */ + /* ??? Should I remove this ? */ + + /* Last error information */ + + byte sense_key,asc,ascq; + + /* Character device operation */ + + unsigned char last_dt_was_write; /* Last character device data transfer was a write */ + byte busy; /* Device already opened */ + + /* Device information */ + + unsigned short tape_block_size; + idetape_capabilities_page_t capabilities; /* Capabilities and Mechanical Page */ + + /* Data buffer */ + + char *data_buffer; + +} idetape_tape_t; + +#endif /* IDETAPE_H */ diff -u --recursive --new-file v1.3.45/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v1.3.45/linux/drivers/block/ide.c Mon Nov 27 12:48:28 1995 +++ linux/drivers/block/ide.c Mon Dec 11 08:49:54 1995 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide.c Version 5.18 Nov 16, 1995 + * linux/drivers/block/ide.c Version 5.22 Dec 10, 1995 * * Copyright (C) 1994, 1995 Linus Torvalds & authors (see below) */ @@ -170,6 +170,14 @@ * Version 5.18 new CMD640 code, moved to cmd640.c, #include'd for now * new UMC8672 code, moved to umc8672.c, #include'd for now * disallow turning on DMA when h/w not capable of DMA + * Version 5.19 fix potential infinite timeout on resets + * extend reset poll into a general purpose polling scheme + * add atapi tape drive support from Gadi Oxman + * simplify exit from _intr routines -- no IDE_DO_REQUEST + * Version 5.20 leave current rq on blkdev request list during I/O + * generalized ide_do_drive_cmd() for tape/cdrom driver use + * Version 5.21 fix nasty cdrom/tape bug (ide_preempt was messed up) + * Version 5.22 fix ide_xlate_1024() to work with/without drive->id * * Driver compile-time options are in ide.h * @@ -179,7 +187,6 @@ * - add ioctls to get/set interface timings on various interfaces * - add Promise Caching controller support from peterd@pnd-pc.demon.co.uk * - modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f - * - find someone to work on IDE *tape drive* support */ #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -246,10 +253,16 @@ return (t - i); } -void ide_set_recovery_timer (ide_hwif_t *hwif) +static void set_recovery_timer (ide_hwif_t *hwif) { hwif->last_time = read_timer(); } +#define SET_RECOVERY_TIMER(drive) set_recovery_timer (drive) + +#else + +#define SET_RECOVERY_TIMER(drive) + #endif /* DISK_RECOVERY_TIME */ /* @@ -391,6 +404,10 @@ * Apparently, systems with multiple CMD640 chips may need something similar.. * * This algorithm courtesy of malafoss@snakemail.hut.fi + * + * At least one user has reported that this code can confuse the floppy + * controller and/or driver -- perhaps this should be changed to use + * a read-modify-write sequence, so as not to disturb other bits in the reg? */ void ide_hwif_select (ide_hwif_t *hwif) @@ -419,15 +436,17 @@ * timer is started to prevent us from waiting forever in case * something goes wrong (see the timer_expiry() handler later on). */ -void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler) +void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout) { ide_hwgroup_t *hwgroup = HWGROUP(drive); #ifdef DEBUG - if (hwgroup->handler != NULL) - printk("%s: ide_set_handler: old handler not null\n", drive->name); + if (hwgroup->handler != NULL) { + printk("%s: ide_set_handler: handler not null; old=%p, new=%p\n", + drive->name, hwgroup->handler, handler); + } #endif hwgroup->handler = handler; - hwgroup->timer.expires = jiffies + WAIT_CMD; + hwgroup->timer.expires = jiffies + timeout; add_timer(&(hwgroup->timer)); } @@ -468,8 +487,8 @@ if (!drive->present) return 0; - if (drive->media != disk) - return 0x1fffff; /* cdrom */ + if (drive->media != ide_disk) + return 0x7fffffff; /* cdrom or tape */ /* Determine capacity, and use LBA if the drive properly supports it */ if (id != NULL && (id->capability & 2) && lba_capacity_is_ok(id)) { drive->select.b.lba = 1; @@ -493,11 +512,15 @@ for (unit = 0; unit < gd->nr_real; ++unit) { ide_drive_t *drive = &hwif->drives[unit]; #ifdef CONFIG_BLK_DEV_IDECD - if (drive->present && drive->media == cdrom) + if (drive->present && drive->media == ide_cdrom) ide_cdrom_setup(drive); #endif /* CONFIG_BLK_DEV_IDECD */ +#ifdef CONFIG_BLK_DEV_IDETAPE + if (drive->present && drive->media == ide_tape) + idetape_setup(drive); +#endif /* CONFIG_BLK_DEV_IDETAPE */ drive->part[0].nr_sects = current_capacity(drive); - if (!drive->present || drive->media != disk) { + if (!drive->present || drive->media != ide_disk) { drive->part[0].start_sect = -1; /* skip partition check */ } } @@ -554,95 +577,54 @@ hwif->gd = gendisk_head = gd; } -static void unexpected_intr (int, ide_hwgroup_t *); -/* - * reset_ihandler() is a dummy interrupt handler which we install during - * an ide interface reset operation. This prevents other devices in the - * same hwgroup from being serviced while we play around with shared resources. - * If it ever gets invoked, we call unexpected_intr(), which treats the event - * the same as a timer_expiry(). - */ -static void reset_ihandler (ide_drive_t *drive) -{ - unsigned long flags; - - save_flags(flags); - cli(); - unexpected_intr (HWIF(drive)->irq, HWGROUP(drive)); - restore_flags(flags); -} - -/* - * start_reset_timer() sets up a timer event for 50ms in the future, - * to poll for completion of an ide reset operation (no interrupt to help us). - */ -static void start_reset_timer (ide_hwif_t *hwif) -{ - ide_hwgroup_t *hwgroup = hwif->hwgroup; +static void do_reset1 (ide_drive_t *, int); /* needed below */ - hwgroup->reset_timeout = jiffies + WAIT_WORSTCASE; /* max waiting time */ - hwgroup->handler = &reset_ihandler; /* dummy irq handler */ - hwgroup->timer.expires = jiffies + (HZ/20); /* polling interval */ - add_timer(&(hwgroup->timer)); -} - -#ifdef CONFIG_BLK_DEV_IDECD +#ifdef CONFIG_BLK_DEV_IDEATAPI /* - * atapi_reset_handler() gets invoked to poll the interface for completion every 50ms + * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms * during an atapi drive reset operation. If the drive has not yet responded, * and we have not yet hit our maximum waiting time, then the timer is restarted * for another 50ms. - * - * Returns 1 if waiting for another 50ms, returns 0 otherwise. */ -static int atapi_reset_handler (ide_hwgroup_t *hwgroup) +static void atapi_reset_pollfunc (ide_drive_t *drive) { - ide_hwif_t *hwif = hwgroup->hwif; - ide_drive_t *drive = hwgroup->drive; + ide_hwgroup_t *hwgroup = HWGROUP(drive); byte stat; OUT_BYTE (drive->select.all, IDE_SELECT_REG); udelay (10); - if (!OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) { - if (jiffies < hwgroup->reset_timeout) { - start_reset_timer (hwif); - return 1; + if (OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) { + printk("%s: ATAPI reset complete\n", drive->name); + } else { + if (jiffies < hwgroup->poll_timeout) { + ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20); + return; /* continue polling */ } + hwgroup->poll_timeout = 0; /* end of polling */ printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat); - return ide_do_reset (drive); /* do it the old fashioned way */ + do_reset1 (drive, 1); /* do it the old fashioned way */ } - hwgroup->doing_atapi_reset = 0; - hwgroup->handler = NULL; /* allow new requests to be processed */ - hwgroup->reset_timeout = 0; /* signal end of ide reset operation */ - printk("%s: ATAPI reset complete\n", drive->name); - return 0; + hwgroup->poll_timeout = 0; /* done polling */ } -#endif /* CONFIG_BLK_DEV_IDECD */ +#endif /* CONFIG_BLK_DEV_IDEATAPI */ /* - * reset_handler() gets invoked to poll the interface for completion every 50ms + * reset_pollfunc() gets invoked to poll the interface for completion every 50ms * during an ide reset operation. If the drives have not yet responded, * and we have not yet hit our maximum waiting time, then the timer is restarted * for another 50ms. - * - * Returns 1 if waiting for another 50ms, returns 0 otherwise. */ -static int reset_handler (ide_hwgroup_t *hwgroup) +static void reset_pollfunc (ide_drive_t *drive) { - ide_hwif_t *hwif = hwgroup->hwif; - ide_drive_t *drive = hwgroup->drive; + ide_hwgroup_t *hwgroup = HWGROUP(drive); + ide_hwif_t *hwif = HWIF(drive); byte tmp; -#ifdef CONFIG_BLK_DEV_IDECD - if (hwgroup->doing_atapi_reset) - return atapi_reset_handler(hwgroup); -#endif /* CONFIG_BLK_DEV_IDECD */ - if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) { - if (jiffies < hwgroup->reset_timeout) { - start_reset_timer (hwif); - return 1; + if (jiffies < hwgroup->poll_timeout) { + ide_set_handler (drive, &reset_pollfunc, HZ/20); + return; /* continue polling */ } printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp); } else { @@ -669,13 +651,11 @@ printk("\n"); } } - hwgroup->handler = NULL; /* allow new requests to be processed */ - hwgroup->reset_timeout = 0; /* signal end of ide reset operation */ - return 0; + hwgroup->poll_timeout = 0; /* done polling */ } /* - * ide_do_reset() attempts to recover a confused drive by resetting it. + * do_reset1() attempts to recover a confused drive by resetting it. * Unfortunately, resetting a disk drive actually resets all devices on * the same interface, so it can really be thought of as resetting the * interface rather than resetting the drive. @@ -689,7 +669,7 @@ * (up to 30 seconds worstcase). So, instead of busy-waiting here for it, * we set a timer to poll at 50ms intervals. */ -int ide_do_reset (ide_drive_t *drive) +static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi) { unsigned int unit; unsigned long flags; @@ -699,24 +679,22 @@ save_flags(flags); cli(); /* Why ? */ -#ifdef CONFIG_BLK_DEV_IDECD +#ifdef CONFIG_BLK_DEV_IDEATAPI /* For an ATAPI device, first try an ATAPI SRST. */ - if (drive->media == cdrom) { - if (!hwgroup->doing_atapi_reset) { - hwgroup->doing_atapi_reset = 1; + if (drive->media != ide_disk) { + if (!do_not_try_atapi) { if (!drive->keep_settings) drive->unmask = 0; OUT_BYTE (drive->select.all, IDE_SELECT_REG); udelay (20); OUT_BYTE (WIN_SRST, IDE_COMMAND_REG); - hwgroup->reset_timeout = jiffies + WAIT_WORSTCASE; - start_reset_timer (hwif); /* begin periodic polling */ + hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; + ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20); restore_flags (flags); - return 1; + return; } } - hwgroup->doing_atapi_reset = 0; -#endif /* CONFIG_BLK_DEV_IDECD */ +#endif /* CONFIG_BLK_DEV_IDEATAPI */ /* * First, reset any device state data we were maintaining @@ -749,33 +727,45 @@ 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 */ - hwgroup->reset_timeout = jiffies + WAIT_WORSTCASE; - start_reset_timer (hwif); /* begin periodic polling */ + hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; + ide_set_handler (drive, &reset_pollfunc, HZ/20); #endif /* OK_TO_RESET_CONTROLLER */ restore_flags (flags); - return OK_TO_RESET_CONTROLLER; /* 1 = we are waiting, 0 = done */ } /* - * Clean up after success/failure of an explicit (ioctl) drive cmd + * ide_do_reset() is the entry point to the drive/interface reset code. + */ +void ide_do_reset (ide_drive_t *drive) +{ + do_reset1 (drive, 0); +} + +/* + * Clean up after success/failure of an explicit drive cmd */ -static void end_drive_cmd (ide_drive_t *drive, byte stat, byte err) +void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err) { unsigned long flags; struct request *rq = HWGROUP(drive)->rq; - byte *args = (byte *) rq->buffer; - rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); - if (args) { - args[0] = stat; - args[1] = err; - args[2] = IN_BYTE(IDE_NSECTOR_REG); + if (rq->cmd == IDE_DRIVE_CMD) { + byte *args = (byte *) rq->buffer; + rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); + if (args) { + args[0] = stat; + args[1] = err; + args[2] = IN_BYTE(IDE_NSECTOR_REG); + } } save_flags(flags); cli(); - up(rq->sem); + blk_dev[MAJOR(rq->rq_dev)].current_request = rq->next; HWGROUP(drive)->rq = NULL; + rq->rq_status = RQ_INACTIVE; + if (rq->sem != NULL) + up(rq->sem); restore_flags(flags); } @@ -791,7 +781,7 @@ sti(); printk("%s: %s: status=0x%02x", drive->name, msg, stat); #if FANCY_STATUS_DUMPS - if (drive->media == disk) { + if (drive->media == ide_disk) { printk(" { "); if (stat & BUSY_STAT) printk("Busy "); @@ -812,7 +802,7 @@ err = GET_ERR(); printk("%s: %s: error=0x%02x", drive->name, msg, err); #if FANCY_STATUS_DUMPS - if (drive->media == disk) { + if (drive->media == ide_disk) { printk(" { "); if (err & BBD_ERR) printk("BadSector "); if (err & ECC_ERR) printk("UncorrectableError "); @@ -868,28 +858,25 @@ /* * ide_error() takes action based on the error returned by the controller. - * - * Returns 1 if an ide reset operation has been initiated, in which case - * the caller MUST simply return from the driver (through however many levels). - * Returns 0 otherwise. */ -int ide_error (ide_drive_t *drive, const char *msg, byte stat) +void ide_error (ide_drive_t *drive, const char *msg, byte stat) { struct request *rq; byte err; err = ide_dump_status(drive, msg, stat); if ((rq = HWGROUP(drive)->rq) == NULL || drive == NULL) - return 0; - if (rq->cmd == IDE_DRIVE_CMD) { /* never retry an explicit DRIVE_CMD */ - end_drive_cmd(drive, stat, err); - return 0; + return; + if (rq->cmd != READ && rq->cmd != WRITE) { /* retry only "normal" i/o */ + rq->errors = 1; + ide_end_drive_cmd(drive, stat, err); + return; } if (stat & BUSY_STAT) { /* other bits are useless when BUSY */ rq->errors |= ERROR_RESET; } else { - if (drive->media == disk && (stat & ERR_STAT)) { - /* err has different meaning on cdrom */ + if (drive->media == ide_disk && (stat & ERR_STAT)) { + /* err has different meaning on cdrom and tape */ if (err & BBD_ERR) /* retries won't help this! */ rq->errors = ERROR_MAX; else if (err & TRK0_ERR) /* help it find track zero */ @@ -906,7 +893,7 @@ drive->using_dma = 0; printk("%s: DMA disabled\n", drive->name); --rq->errors; - return 0; + return; } #endif /* CONFIG_BLK_DEV_TRITON */ if (rq->errors >= ERROR_MAX) @@ -914,12 +901,12 @@ else { if ((rq->errors & ERROR_RESET) == ERROR_RESET) { ++rq->errors; - return ide_do_reset(drive); + ide_do_reset(drive); + return; } else if ((rq->errors & ERROR_RECAL) == ERROR_RECAL) drive->special.b.recalibrate = 1; ++rq->errors; } - return 0; } /* @@ -933,9 +920,7 @@ struct request *rq; if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) { - sti(); - if (!ide_error(drive, "read_intr", stat)) - IDE_DO_REQUEST; + ide_error(drive, "read_intr", stat); return; } msect = drive->mult_count; @@ -962,10 +947,8 @@ if (i > 0) { if (msect) goto read_next; - ide_set_handler (drive, &read_intr); - return; + ide_set_handler (drive, &read_intr, WAIT_CMD); } - IDE_DO_REQUEST; } /* @@ -975,7 +958,8 @@ { byte stat; int i; - struct request *rq = HWGROUP(drive)->rq; + ide_hwgroup_t *hwgroup = HWGROUP(drive); + struct request *rq = hwgroup->rq; if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) { #ifdef DEBUG @@ -990,19 +974,15 @@ i = --rq->nr_sectors; --rq->current_nr_sectors; if (rq->current_nr_sectors <= 0) - ide_end_request(1, HWGROUP(drive)); + ide_end_request(1, hwgroup); if (i > 0) { ide_output_data (drive, rq->buffer, SECTOR_WORDS); - ide_set_handler (drive, &write_intr); - return; + ide_set_handler (drive, &write_intr, WAIT_CMD); } - IDE_DO_REQUEST; return; } } - sti(); - if (!ide_error(drive, "write_intr", stat)) - IDE_DO_REQUEST; + ide_error(drive, "write_intr", stat); } /* @@ -1049,30 +1029,28 @@ { byte stat; int i; - struct request *rq = &HWGROUP(drive)->wrq; + ide_hwgroup_t *hwgroup = HWGROUP(drive); + struct request *rq = &hwgroup->wrq; if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) { if (stat & DRQ_STAT) { if (rq->nr_sectors) { multwrite(drive); - ide_set_handler (drive, &multwrite_intr); + ide_set_handler (drive, &multwrite_intr, WAIT_CMD); return; } } else { if (!rq->nr_sectors) { /* all done? */ - rq = HWGROUP(drive)->rq; + rq = hwgroup->rq; for (i = rq->nr_sectors; i > 0;){ i -= rq->current_nr_sectors; - ide_end_request(1, HWGROUP(drive)); + ide_end_request(1, hwgroup); } - IDE_DO_REQUEST; return; } } } - sti(); - if (!ide_error(drive, "multwrite_intr", stat)) - IDE_DO_REQUEST; + ide_error(drive, "multwrite_intr", stat); } /* @@ -1081,7 +1059,7 @@ */ static void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler) { - ide_set_handler (drive, handler); + ide_set_handler (drive, handler, WAIT_CMD); OUT_BYTE(drive->ctl,IDE_CONTROL_REG); OUT_BYTE(nsect,IDE_NSECTOR_REG); OUT_BYTE(cmd,IDE_COMMAND_REG); @@ -1102,7 +1080,6 @@ drive->special.b.recalibrate = 1; (void) ide_dump_status(drive, "set_multmode", stat); } - IDE_DO_REQUEST; } /* @@ -1114,9 +1091,7 @@ sti(); if (!OK_STAT(stat,READY_STAT,BAD_STAT)) - if (ide_error(drive, "set_geometry_intr", stat)) - return; - IDE_DO_REQUEST; + ide_error(drive, "set_geometry_intr", stat); } /* @@ -1128,9 +1103,7 @@ sti(); if (!OK_STAT(stat,READY_STAT,BAD_STAT)) - if (ide_error(drive, "recal_intr", stat)) - return; - IDE_DO_REQUEST; + ide_error(drive, "recal_intr", stat); } /* @@ -1142,10 +1115,9 @@ sti(); if (OK_STAT(stat,READY_STAT,BAD_STAT)) - end_drive_cmd (drive, stat, GET_ERR()); - else if (ide_error(drive, "drive_cmd", stat)) /* calls end_drive_cmd */ - return; - IDE_DO_REQUEST; + ide_end_drive_cmd (drive, stat, GET_ERR()); + else + ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */ } /* @@ -1161,7 +1133,7 @@ #endif if (s->b.set_geometry) { s->b.set_geometry = 0; - if (drive->media == disk) { + if (drive->media == ide_disk) { OUT_BYTE(drive->sect,IDE_SECTOR_REG); OUT_BYTE(drive->cyl,IDE_LCYL_REG); OUT_BYTE(drive->cyl>>8,IDE_HCYL_REG); @@ -1170,12 +1142,12 @@ } } else if (s->b.recalibrate) { s->b.recalibrate = 0; - if (drive->media == disk) { + if (drive->media == ide_disk) { ide_cmd(drive, WIN_RESTORE, drive->sect, &recal_intr); } } else if (s->b.set_multmode) { s->b.set_multmode = 0; - if (drive->media == disk) { + if (drive->media == ide_disk) { if (drive->id && drive->mult_req > drive->id->max_multsect) drive->mult_req = drive->id->max_multsect; ide_cmd(drive, WIN_SETMULT, drive->mult_req, &set_multmode_intr); @@ -1191,23 +1163,24 @@ * This routine busy-waits for the drive status to be not "busy". * It then checks the status for all of the "good" bits and none * of the "bad" bits, and if all is okay it returns 0. All other - * cases return 1 after invoking ide_error() + * cases return 1 after invoking ide_error() -- caller should just return. * * This routine should get fixed to not hog the cpu during extra long waits.. * That could be done by busy-waiting for the first jiffy or two, and then * setting a timer to wake up at half second intervals thereafter, - * until WAIT_WORSTCASE is achieved, before timing out. + * until timeout is achieved, before timing out. */ int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout) { byte stat; unsigned long flags; + test: udelay(1); /* spec allows drive 400ns to change "BUSY" */ if (OK_STAT((stat = GET_STAT()), good, bad)) return 0; /* fast exit for most frequent case */ if (!(stat & BUSY_STAT)) { - (void) ide_error(drive, "status error", stat); + ide_error(drive, "status error", stat); return 1; } @@ -1222,7 +1195,7 @@ } while (jiffies <= timeout); restore_flags(flags); - (void) ide_error(drive, "status timeout", GET_STAT()); + ide_error(drive, "status timeout", GET_STAT()); return 1; } @@ -1268,7 +1241,7 @@ if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive))) return; #endif /* CONFIG_BLK_DEV_TRITON */ - ide_set_handler(drive, &read_intr); + ide_set_handler(drive, &read_intr, WAIT_CMD); OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, io_base+IDE_COMMAND_OFFSET); return; } @@ -1287,10 +1260,10 @@ cli(); if (drive->mult_count) { HWGROUP(drive)->wrq = *rq; /* scratchpad */ - ide_set_handler (drive, &multwrite_intr); + ide_set_handler (drive, &multwrite_intr, WAIT_CMD); multwrite(drive); } else { - ide_set_handler (drive, &write_intr); + ide_set_handler (drive, &write_intr, WAIT_CMD); ide_output_data(drive, rq->buffer, SECTOR_WORDS); } return; @@ -1311,7 +1284,7 @@ #ifdef DEBUG printk("%s: DRIVE_CMD (null)\n", drive->name); #endif - end_drive_cmd(drive, GET_STAT(), GET_ERR()); + ide_end_drive_cmd(drive, GET_STAT(), GET_ERR()); return; } } @@ -1330,7 +1303,7 @@ sti(); #ifdef DEBUG - printk("%s: ide_do_request: current=0x%08lx\n", hwif->name, (unsigned long) rq); + printk("%s: do_request: current=0x%08lx\n", hwif->name, (unsigned long) rq); #endif minor = MINOR(rq->rq_dev); unit = minor >> PARTN_BITS; @@ -1372,17 +1345,25 @@ if (ide_wait_stat(drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) { printk("%s: drive not ready for command\n", drive->name); return; - } if (!drive->special.all) { -#ifdef CONFIG_BLK_DEV_IDECD +#ifdef CONFIG_BLK_DEV_IDEATAPI switch (drive->media) { - case disk: + case ide_disk: do_rw_disk (drive, rq, block); return; - case cdrom: +#ifdef CONFIG_BLK_DEV_IDECD + case ide_cdrom: ide_do_rw_cdrom (drive, block); return; +#endif /* CONFIG_BLK_DEV_IDECD */ + +#ifdef CONFIG_BLK_DEV_IDETAPE + case ide_tape: + idetape_do_request (drive, rq, block); + return; +#endif /* CONFIG_BLK_DEV_IDETAPE */ + default: printk("%s: media type %d not supported\n", drive->name, drive->media); @@ -1391,7 +1372,7 @@ #else do_rw_disk (drive, rq, block); /* simpler and faster */ return; -#endif; +#endif /* CONFIG_BLK_DEV_IDEATAPI */; } do_special(drive); return; @@ -1425,16 +1406,14 @@ ide_hwif_t *hwif = hwgroup->hwif; struct request *rq; if ((rq = hwgroup->rq) == NULL) { - hwgroup->drive = NULL; /* paranoia */ do { rq = blk_dev[hwif->major].current_request; if (rq != NULL && rq->rq_status != RQ_INACTIVE) goto got_rq; } while ((hwif = hwif->next) != hwgroup->hwif); return; /* no work left for this hwgroup */ - got_rq: - blk_dev[hwif->major].current_request = rq->next; } + got_rq: do_request(hwgroup->hwif = hwif, hwgroup->rq = rq); cli(); } while (hwgroup->handler == NULL); @@ -1495,19 +1474,21 @@ save_flags(flags); cli(); - if (hwgroup->reset_timeout != 0) { /* ide reset in progress? */ - if (!reset_handler(hwgroup)) - do_hwgroup_request (hwgroup); + if (hwgroup->poll_timeout != 0) { /* polling in progress? */ + ide_handler_t *handler = hwgroup->handler; + hwgroup->handler = NULL; + handler(drive); } else if (hwgroup->handler == NULL) { /* not waiting for anything? */ sti(); /* drive must have responded just as the timer expired */ printk("%s: marginal timeout\n", drive->name); - } else { /* drive not responding */ - hwgroup->handler = NULL; + } else { + hwgroup->handler = NULL; /* abort the operation */ if (hwgroup->hwif->dmaproc) (void) hwgroup->hwif->dmaproc (ide_dma_abort, drive); - if (!ide_error(drive, "irq timeout", GET_STAT())) - do_hwgroup_request (hwgroup); + ide_error(drive, "irq timeout", GET_STAT()); } + if (hwgroup->handler == NULL) + do_hwgroup_request (hwgroup); restore_flags(flags); } @@ -1541,15 +1522,6 @@ ide_hwif_t *hwif = hwgroup->hwif; /* - * check for ide reset in progress - */ - if (hwgroup->reset_timeout != 0) { - if (!reset_handler(hwgroup)) - do_hwgroup_request (hwgroup); - return; - } - - /* * handle the unexpected interrupt */ do { @@ -1586,6 +1558,11 @@ if (drive->unmask) sti(); handler(drive); + cli(); /* this is necessary, as next rq may be different irq */ + if (hwgroup->handler == NULL) { + SET_RECOVERY_TIMER(HWIF(drive)); + ide_do_request(hwgroup); + } } else { unexpected_intr(irq, hwgroup); } @@ -1621,49 +1598,83 @@ } /* - * This function issues a specific IDE drive command onto the - * tail of the request queue, and waits for it to be completed. - * If arg is NULL, it goes through all the motions, - * but without actually sending a command to the drive. + * This function is intended to be used prior to invoking ide_do_drive_cmd(). */ -int ide_do_drive_cmd(kdev_t rdev, char *args) +void ide_init_drive_cmd (struct request *rq) +{ + rq->buffer = NULL; + rq->cmd = IDE_DRIVE_CMD; + rq->sector = 0; + rq->nr_sectors = 0; + rq->current_nr_sectors = 0; + rq->sem = NULL; + rq->bh = NULL; + rq->bhtail = NULL; + rq->next = NULL; + +#if 0 /* these are done each time through ide_do_drive_cmd() */ + rq->errors = 0; + rq->rq_status = RQ_ACTIVE; + rq->rq_dev = ????; +#endif +} + +/* + * This function issues a special IDE device request + * onto the request queue. + * + * If action is ide_wait, then then rq is queued at the end of + * the request queue, and the function sleeps until it has been + * processed. This is for use when invoked from an ioctl handler. + * + * If action is ide_preempt, then the rq is queued at the head of + * the request queue, displacing the currently-being-processed + * request and this function returns immediately without waiting + * for the new rq to be completed. This is VERY DANGEROUS, and is + * intended for careful use by the ATAPI tape/cdrom driver code. + * + * If action is ide_next, then the rq is queued immediately after + * the currently-being-processed-request (if any), and the function + * returns without waiting for the new rq to be completed. As above, + * This is VERY DANGEROUS, and is intended for careful use by the + * ATAPI tape/cdrom driver code. + */ +int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action) { unsigned long flags; - unsigned int major = MAJOR(rdev); - struct request rq, *cur_rq; - struct blk_dev_struct *bdev; + unsigned int major = HWIF(drive)->major; + struct request *cur_rq; + struct blk_dev_struct *bdev = &blk_dev[major]; struct semaphore sem = MUTEX_LOCKED; - /* build up a special request, and add it to the queue */ - rq.buffer = args; - rq.cmd = IDE_DRIVE_CMD; - rq.errors = 0; - rq.sector = 0; - rq.nr_sectors = 0; - rq.current_nr_sectors = 0; - rq.sem = &sem; - rq.bh = NULL; - rq.bhtail = NULL; - rq.next = NULL; - rq.rq_status = RQ_ACTIVE; - rq.rq_dev = rdev; - bdev = &blk_dev[major]; + rq->errors = 0; + rq->rq_status = RQ_ACTIVE; + rq->rq_dev = MKDEV(major,(drive->select.b.unit)<sem = &sem; save_flags(flags); cli(); cur_rq = bdev->current_request; - if (cur_rq == NULL) { /* empty request list? */ - bdev->current_request = &rq; /* service ours immediately */ - bdev->request_fn(); + + if (cur_rq == NULL || action == ide_preempt) { + rq->next = cur_rq; + bdev->current_request = rq; + HWGROUP(drive)->rq = NULL; + if (action != ide_preempt) + bdev->request_fn(); } else { - while (cur_rq->next != NULL) /* find end of request list */ - cur_rq = cur_rq->next; - cur_rq->next = &rq; /* add rq to the end */ + if (action == ide_wait) { + while (cur_rq->next != NULL) /* find end of list */ + cur_rq = cur_rq->next; + } + rq->next = cur_rq->next; + cur_rq->next = rq; } - - down(&sem); /* wait for it to be serviced */ + if (action == ide_wait) + down(&sem); /* wait for it to be serviced */ restore_flags(flags); - return rq.errors ? -EIO : 0; /* return -EIO if errors */ + return rq->errors ? -EIO : 0; /* return -EIO if errors */ } static int ide_open(struct inode * inode, struct file * filp) @@ -1680,13 +1691,20 @@ drive->usage++; restore_flags(flags); #ifdef CONFIG_BLK_DEV_IDECD - if (drive->media == cdrom) + if (drive->media == ide_cdrom) return ide_cdrom_open (inode, filp, drive); #endif /* CONFIG_BLK_DEV_IDECD */ +#ifdef CONFIG_BLK_DEV_IDETAPE + if (drive->media == ide_tape) + return idetape_blkdev_open (inode, filp, drive); +#endif /* CONFIG_BLK_DEV_IDETAPE */ if (drive->removeable) { byte door_lock[] = {WIN_DOORLOCK,0,0,0}; + struct request rq; check_disk_change(inode->i_rdev); - ide_do_drive_cmd(inode->i_rdev, door_lock); + ide_init_drive_cmd (&rq); + rq.buffer = door_lock; + return ide_do_drive_cmd(drive, &rq, ide_wait); } return 0; } @@ -1703,14 +1721,24 @@ sync_dev(inode->i_rdev); drive->usage--; #ifdef CONFIG_BLK_DEV_IDECD - if (drive->media == cdrom) + if (drive->media == ide_cdrom) { ide_cdrom_release (inode, file, drive); - else + return; + } #endif /* CONFIG_BLK_DEV_IDECD */ +#ifdef CONFIG_BLK_DEV_IDETAPE + if (drive->media == ide_tape) { + idetape_blkdev_release (inode, file, drive); + return; + } +#endif /* CONFIG_BLK_DEV_IDETAPE */ if (drive->removeable) { byte door_unlock[] = {WIN_DOORUNLOCK,0,0,0}; + struct request rq; invalidate_buffers(inode->i_rdev); - ide_do_drive_cmd(inode->i_rdev, door_unlock); + ide_init_drive_cmd (&rq); + rq.buffer = door_unlock; + (void) ide_do_drive_cmd(drive, &rq, ide_wait); } } } @@ -1755,7 +1783,7 @@ }; drive->part[0].nr_sects = current_capacity(drive); - if (drive->media == disk) + if (drive->media == ide_disk) resetup_one_dev(HWIF(drive)->gd, drive->select.b.unit); drive->busy = 0; @@ -1782,14 +1810,16 @@ int err; ide_drive_t *drive; unsigned long flags; + struct request rq; + ide_init_drive_cmd (&rq); if (!inode || !(inode->i_rdev)) return -EINVAL; if ((drive = get_info_ptr(inode->i_rdev)) == NULL) return -ENODEV; switch (cmd) { case HDIO_GETGEO: - if (!loc || drive->media != disk) return -EINVAL; + if (!loc || drive->media != ide_disk) return -EINVAL; err = verify_area(VERIFY_WRITE, loc, sizeof(*loc)); if (err) return err; put_user(drive->bios_head, (byte *) &loc->heads); @@ -1848,7 +1878,7 @@ return write_fs_long(arg, drive->bad_wstat == BAD_R_STAT); case HDIO_SET_DMA: - if (drive->media != disk) + if (drive->media != ide_disk) return -EPERM; if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc) return -EPERM; @@ -1914,7 +1944,7 @@ drive->mult_req = arg; drive->special.b.set_multmode = 1; restore_flags(flags); - ide_do_drive_cmd (inode->i_rdev, NULL); + (void) ide_do_drive_cmd (drive, &rq, ide_wait); return (drive->mult_count == arg) ? 0 : -EIO; case HDIO_DRIVE_CMD: @@ -1922,13 +1952,14 @@ unsigned long args; if (NULL == (long *) arg) - err = ide_do_drive_cmd(inode->i_rdev,NULL); + err = ide_do_drive_cmd(drive, &rq, ide_wait); else { if (!(err = verify_area(VERIFY_READ,(long *)arg,sizeof(long)))) { args = get_user((long *)arg); if (!(err = verify_area(VERIFY_WRITE,(long *)arg,sizeof(long)))) { - err = ide_do_drive_cmd(inode->i_rdev,(char *)&args); + rq.buffer = (char *) &args; + err = ide_do_drive_cmd(drive, &rq, ide_wait); put_user(args,(long *)arg); } } @@ -1940,9 +1971,13 @@ default: #ifdef CONFIG_BLK_DEV_IDECD - if (drive->media == cdrom) + if (drive->media == ide_cdrom) return ide_cdrom_ioctl(drive, inode, file, cmd, arg); #endif /* CONFIG_BLK_DEV_IDECD */ +#ifdef CONFIG_BLK_DEV_IDETAPE + if (drive->media == ide_tape) + return idetape_blkdev_ioctl(drive, inode, file, cmd, arg); +#endif /* CONFIG_BLK_DEV_IDETAPE */ return -EPERM; } } @@ -1954,7 +1989,7 @@ if ((drive = get_info_ptr(i_rdev)) == NULL) return -ENODEV; #ifdef CONFIG_BLK_DEV_IDECD - if (drive->media == cdrom) + if (drive->media == ide_cdrom) return ide_cdrom_check_media_change (drive); #endif /* CONFIG_BLK_DEV_IDECD */ if (drive->removeable) /* for disks */ @@ -2027,22 +2062,45 @@ /* * Check for an ATAPI device */ + if (cmd == WIN_PIDENTIFY) { + byte type = (id->config >> 8) & 0x1f; + printk("%s: %s, ATAPI ", drive->name, id->model); + switch (type) { + case 0: /* Early cdrom models used zero */ + case 5: #ifdef CONFIG_BLK_DEV_IDECD - byte type = (id->config >> 8) & 0x0f; -#endif /* CONFIG_BLK_DEV_IDECD */ - printk("%s: %s, ATAPI, ", drive->name, id->model); - drive->media = cdrom; -#ifdef CONFIG_BLK_DEV_IDECD - if (type == 0 || type == 5) - printk("CDROM drive\n"); - else - printk("UNKNOWN device\n"); - drive->present = 1; - drive->removeable = 1; + printk ("CDROM drive\n"); + drive->media = ide_cdrom; + drive->present = 1; + drive->removeable = 1; + return; #else - printk("not supported by this kernel\n"); -#endif /* CONFIG_BLK_DEV_IDECD */ + printk ("CDROM "); + break; +#endif /* CONFIG_BLK_DEV_IDECD */ + case 1: +#ifdef CONFIG_BLK_DEV_IDETAPE + printk ("TAPE drive\n"); + if (idetape_identify_device (drive,id)) { + drive->media = ide_tape; + drive->present = 1; + drive->removeable = 1; + } + else { + drive->present = 0; + printk ("ide-tape: The tape is not supported by this version of the driver\n"); + } + return; +#else + printk ("TAPE "); + break; +#endif /* CONFIG_BLK_DEV_IDETAPE */ + default: + printk("Type %d - Unknown device\n", type); + return; + } + printk("- not supported by this kernel\n"); return; } @@ -2052,7 +2110,7 @@ drive->removeable = 1; } - drive->media = disk; + drive->media = ide_disk; /* Extract geometry if we did not already have one for the drive */ if (!drive->present) { drive->present = 1; @@ -2211,15 +2269,15 @@ static int do_probe (ide_drive_t *drive, byte cmd) { int rc; -#ifdef CONFIG_BLK_DEV_IDECD +#ifdef CONFIG_BLK_DEV_IDEATAPI if (drive->present) { /* avoid waiting for inappropriate probes */ - if ((drive->media == cdrom) && (cmd == WIN_IDENTIFY)) + if ((drive->media != ide_disk) && (cmd == WIN_IDENTIFY)) return 4; } -#endif /* CONFIG_BLK_DEV_IDECD */ +#endif /* CONFIG_BLK_DEV_IDEATAPI */ #ifdef DEBUG - printk("probing for %s: present=%d, type=%s, probetype=%s\n", - drive->name, drive->present, drive->media ? "cdrom":"disk", + printk("probing for %s: present=%d, media=%d, probetype=%s\n", + drive->name, drive->present, drive->media, (cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI"); #endif #if SUPPORT_HT6560B @@ -2263,19 +2321,19 @@ if (drive->noprobe) /* skip probing? */ return drive->present; if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */ -#ifdef CONFIG_BLK_DEV_IDECD +#ifdef CONFIG_BLK_DEV_IDEATAPI (void) do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */ -#endif /* CONFIG_BLK_DEV_IDECD */ +#endif /* CONFIG_BLK_DEV_IDEATAPI */ } if (!drive->present) return 0; /* drive not found */ if (drive->id == NULL) { /* identification failed? */ - if (drive->media == disk) { + if (drive->media == ide_disk) { printk ("%s: non-IDE drive, CHS=%d/%d/%d\n", drive->name, drive->cyl, drive->head, drive->sect); } #ifdef CONFIG_BLK_DEV_IDECD - else if (drive->media == cdrom) { + else if (drive->media == ide_cdrom) { printk("%s: ATAPI cdrom (?)\n", drive->name); } #endif /* CONFIG_BLK_DEV_IDECD */ @@ -2284,7 +2342,7 @@ return 1; /* drive was found */ } } - if (drive->media == disk && !drive->select.b.lba) { + if (drive->media == ide_disk && !drive->select.b.lba) { if (!drive->head || drive->head > 16) { printk("%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head); @@ -2568,14 +2626,14 @@ goto done; case -3: /* "cdrom" */ drive->present = 1; - drive->media = cdrom; + drive->media = ide_cdrom; hwif->noprobe = 0; goto done; case -4: /* "serialize" */ printk(" -- USE \"ide%c=serialize\" INSTEAD", '0'+hw); goto do_serialize; case 3: /* cyl,head,sect */ - drive->media = disk; + drive->media = ide_disk; drive->cyl = drive->bios_cyl = vals[0]; drive->head = drive->bios_head = vals[1]; drive->sect = drive->bios_sect = vals[2]; @@ -2679,12 +2737,17 @@ const byte *heads = head_vals; unsigned long tracks; - if ((drive = get_info_ptr(i_rdev)) == NULL || drive->id == NULL) + if ((drive = get_info_ptr(i_rdev)) == NULL) return 0; - drive->cyl = drive->bios_cyl = drive->id->cyls; - drive->head = drive->bios_head = drive->id->heads; - drive->sect = drive->bios_sect = drive->id->sectors; + if (drive->id) { + drive->bios_cyl = drive->id->cyls; + drive->bios_head = drive->id->heads; + drive->bios_sect = drive->id->sectors; + } + drive->cyl = drive->bios_cyl; + drive->head = drive->bios_head; + drive->sect = drive->bios_sect; drive->special.b.set_geometry = 1; tracks = drive->bios_cyl * drive->bios_head * drive->bios_sect / 63; @@ -2801,11 +2864,8 @@ hwgroup->hwif = hwif->next = hwif; hwgroup->rq = NULL; hwgroup->handler = NULL; - hwgroup->drive = NULL; - hwgroup->reset_timeout = 0; -#ifdef CONFIG_BLK_DEV_IDECD - hwgroup->doing_atapi_reset = 0; -#endif /* CONFIG_BLK_DEV_IDECD */ + hwgroup->drive = &hwif->drives[0]; + hwgroup->poll_timeout = 0; init_timer(&hwgroup->timer); hwgroup->timer.function = &timer_expiry; hwgroup->timer.data = (unsigned long) hwgroup; @@ -3002,5 +3062,10 @@ hwif->present = 1; /* success */ } } + +#ifdef CONFIG_BLK_DEV_IDETAPE + idetape_register_chrdev(); /* Register character device interface to the ide tape */ +#endif /* CONFIG_BLK_DEV_IDETAPE */ + return 0; } diff -u --recursive --new-file v1.3.45/linux/drivers/block/ide.h linux/drivers/block/ide.h --- v1.3.45/linux/drivers/block/ide.h Mon Nov 27 12:48:29 1995 +++ linux/drivers/block/ide.h Mon Dec 11 11:28:22 1995 @@ -152,6 +152,10 @@ #define WAIT_WORSTCASE (30*HZ) /* 30sec - worst case when spinning up */ #define WAIT_CMD (10*HZ) /* 10sec - maximum wait for an IRQ to happen */ +#ifdef CONFIG_BLK_DEV_IDETAPE +#include "ide-tape.h" +#endif /* CONFIG_BLK_DEV_IDETAPE */ + #ifdef CONFIG_BLK_DEV_IDECD struct atapi_request_sense { @@ -234,7 +238,8 @@ /* * Now for the data we need to maintain per-drive: ide_drive_t */ -typedef enum {disk, cdrom} media_t; + +typedef enum {ide_disk, ide_cdrom, ide_tape} ide_media_t; typedef union { unsigned all : 8; /* all of the bits together */ @@ -271,7 +276,7 @@ unsigned removeable : 1; /* 1 if need to do check_media_change */ unsigned using_dma : 1; /* disk is using dma for read/write */ unsigned unmask : 1; /* flag: okay to unmask other irqs */ - media_t media; /* disk, cdrom, tape */ + ide_media_t media; /* disk, cdrom, tape */ select_t select; /* basic drive/head select reg value */ void *hwif; /* actually (ide_hwif_t *) */ byte ctl; /* "normal" value for IDE_CONTROL_REG */ @@ -295,6 +300,22 @@ #ifdef CONFIG_BLK_DEV_IDECD struct cdrom_info cdrom_info; /* from ide-cd.c */ #endif /* CONFIG_BLK_DEV_IDECD */ + +#ifdef CONFIG_BLK_DEV_IDETAPE /* ide-tape specific data */ + +/* + * Most of our global data which we need to save even as we leave the + * driver due to an interrupt or a timer event is stored here. + * + * Additional global variables which provide the link between the + * character device interface to this structure are defined in + * ide-tape.c + */ + + idetape_tape_t tape; + +#endif /* CONFIG_BLK_DEV_IDETAPE */ + } ide_drive_t; /* @@ -348,10 +369,7 @@ struct request *rq; /* current request */ struct timer_list timer; /* failsafe timer */ struct request wrq; /* local copy of current write rq */ - unsigned long reset_timeout; /* timeout value during ide resets */ -#ifdef CONFIG_BLK_DEV_IDECD - int doing_atapi_reset; -#endif /* CONFIG_BLK_DEV_IDECD */ + unsigned long poll_timeout; /* timeout value during long polls */ } ide_hwgroup_t; /* @@ -368,16 +386,6 @@ #endif /* - * The main (re-)entry point for handling a new request is IDE_DO_REQUEST. - * Note that IDE_DO_REQUEST should *only* ever be invoked from an interrupt - * handler. All others, such as a timer expiry handler, should call - * do_hwgroup_request() instead (currently local to ide.c). - */ -void ide_do_request (ide_hwgroup_t *); -#define IDE_DO_REQUEST { SET_RECOVERY_TIMER(HWIF(drive)); ide_do_request(HWGROUP(drive)); } - - -/* * This is used for (nearly) all data transfers from the IDE interface */ void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount); @@ -391,7 +399,7 @@ * This is used on exit from the driver, to designate the next irq handler * and also to start the safety timer. */ -void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler); +void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout); /* * Error reporting, in human readable form (luxurious, but a memory hog). @@ -400,18 +408,15 @@ /* * ide_error() takes action based on the error returned by the controller. - * - * Returns 1 if an ide reset operation has been initiated, in which case - * the caller MUST simply return from the driver (through however many levels). - * Returns 0 otherwise. + * The calling function must return afterwards, to restart the request. */ -int ide_error (ide_drive_t *drive, const char *msg, byte stat); +void ide_error (ide_drive_t *drive, const char *msg, byte stat); /* * This routine busy-waits for the drive status to be not "busy". * It then checks the status for all of the "good" bits and none * of the "bad" bits, and if all is okay it returns 0. All other - * cases return 1 after invoking ide_error() + * cases return 1 after invoking ide_error() -- caller should return. * */ int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout); @@ -423,31 +428,51 @@ /* * Start a reset operation for an IDE interface. - * Returns 0 if the reset operation is still in progress, - * in which case the drive MUST return, to await completion. - * Returns 1 if the reset is complete (success or failure). + * The caller should return immediately after invoking this. */ -int ide_do_reset (ide_drive_t *); +void ide_do_reset (ide_drive_t *); /* - * ide_alloc(): memory allocation for use *only* during driver initialization. - * If "within_area" is non-zero, the memory will be allocated such that - * it lies entirely within a "within_area" sized area (eg. 4096). This is - * needed for DMA stuff. "within_area" must be a power of two (not validated). - * All allocations are longword aligned. + * This function is intended to be used prior to invoking ide_do_drive_cmd(). */ -void *ide_alloc (unsigned long bytecount, unsigned long within_area); +void ide_init_drive_cmd (struct request *rq); /* - * This function issues a specific IDE drive command onto the - * tail of the request queue, and waits for it to be completed. - * If arg is NULL, it goes through all the motions, - * but without actually sending a command to the drive. - * - * The value of arg is passed to the internal handler as rq->buffer. + * "action" parameter type for ide_do_drive_cmd() below. */ -int ide_do_drive_cmd(kdev_t rdev, char *args); +typedef enum + {ide_wait, /* insert rq at end of list, and wait for it */ + ide_next, /* insert rq immediately after current request */ + ide_preempt} /* insert rq in front of current request */ + ide_action_t; +/* + * This function issues a special IDE device request + * onto the request queue. + * + * If action is ide_wait, then then rq is queued at the end of + * the request queue, and the function sleeps until it has been + * processed. This is for use when invoked from an ioctl handler. + * + * If action is ide_preempt, then the rq is queued at the head of + * the request queue, displacing the currently-being-processed + * request and this function returns immediately without waiting + * for the new rq to be completed. This is VERY DANGEROUS, and is + * intended for careful use by the ATAPI tape/cdrom driver code. + * + * If action is ide_next, then the rq is queued immediately after + * the currently-being-processed-request (if any), and the function + * returns without waiting for the new rq to be completed. As above, + * This is VERY DANGEROUS, and is intended for careful use by the + * ATAPI tape/cdrom driver code. + */ +int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action); + +/* + * Clean up after success/failure of an explicit drive cmd. + * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD). + */ +void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err); #ifdef CONFIG_BLK_DEV_IDECD /* @@ -460,6 +485,57 @@ void ide_cdrom_release (struct inode *, struct file *, ide_drive_t *); void ide_cdrom_setup (ide_drive_t *); #endif /* CONFIG_BLK_DEV_IDECD */ + +#ifdef CONFIG_BLK_DEV_IDETAPE + +/* + * Functions in ide-tape.c which are invoked from ide.c: + */ + +/* + * idetape_identify_device is called during device probing stage to + * probe for an ide atapi tape drive and to initialize global variables + * in ide-tape.c which provide the link between the character device + * and the correspoding block device. + * + * Returns 1 if an ide tape was detected and is supported. + * Returns 0 otherwise. + */ + +int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id); + +/* + * idetape_setup is called a bit later than idetape_identify_device, + * during the search for disk partitions, to initialize various tape + * state variables in ide_drive_t *drive. + */ + +void idetape_setup (ide_drive_t *drive); + +/* + * idetape_do_request is our request function. It is called by ide.c + * to process a new request. + */ + +void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned long block); + +/* + * Block device interface functions. + */ + +int idetape_blkdev_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); +int idetape_blkdev_open (struct inode *inode, struct file *filp, ide_drive_t *drive); +void idetape_blkdev_release (struct inode *inode, struct file *filp, ide_drive_t *drive); + +/* + * idetape_register_chrdev initializes the character device interface to + * the ide tape drive. + */ + +void idetape_register_chrdev (void); + +#endif /* CONFIG_BLK_DEV_IDETAPE */ #ifdef CONFIG_BLK_DEV_TRITON void ide_init_triton (byte, byte); diff -u --recursive --new-file v1.3.45/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v1.3.45/linux/drivers/block/ll_rw_blk.c Mon Nov 27 12:48:29 1995 +++ linux/drivers/block/ll_rw_blk.c Mon Dec 11 08:49:35 1995 @@ -232,20 +232,24 @@ static inline void drive_stat_acct(int cmd, unsigned long nr_sectors, short disk_index) { kstat.dk_drive[disk_index]++; - if (cmd == READ || cmd == READA) { + if (cmd == READ) { kstat.dk_drive_rio[disk_index]++; kstat.dk_drive_rblk[disk_index] += nr_sectors; } - else if (cmd == WRITE || cmd == WRITEA) { + else if (cmd == WRITE) { kstat.dk_drive_wio[disk_index]++; kstat.dk_drive_wblk[disk_index] += nr_sectors; - } + } else + printk("drive_stat_acct: cmd not R/W?\n"); } /* * add-request adds a request to the linked list. * It disables interrupts so that it can muck with the * request-lists in peace. + * + * By this point, req->cmd is always either READ/WRITE, never READA/WRITEA, + * which is important for drive_stat_acct() above. */ static void add_request(struct blk_dev_struct * dev, struct request * req) { @@ -302,21 +306,6 @@ struct request * req; int rw_ahead, max_req; -/* WRITEA/READA is special case - it is not really needed, so if the */ -/* buffer is locked, we just forget about it, else it's a normal read */ - rw_ahead = (rw == READA || rw == WRITEA); - if (rw_ahead) { - if (buffer_locked(bh)) - return; - if (rw == READA) - rw = READ; - else - rw = WRITE; - } - if (rw!=READ && rw!=WRITE) { - printk("Bad block dev command, must be R/W/RA/WA\n"); - return; - } count = bh->b_size >> 9; sector = bh->b_blocknr * count; if (blk_size[major]) @@ -330,21 +319,46 @@ return; /* Maybe the above fixes it, and maybe it doesn't boot. Life is interesting */ lock_buffer(bh); - if ((rw == WRITE && !buffer_dirty(bh)) || (rw == READ && buffer_uptodate(bh))) { - unlock_buffer(bh); - return; - } -/* we don't allow the write-requests to fill up the queue completely: - * we want some room for reads: they take precedence. The last third - * of the requests are only for reads. - */ - max_req = (rw == READ) ? NR_REQUEST : ((NR_REQUEST*2)/3); + rw_ahead = 0; /* normal case; gets changed below for READA/WRITEA */ + switch (rw) { + case READA: + rw_ahead = 1; + rw = READ; /* drop into READ */ + case READ: + if (buffer_uptodate(bh)) { + unlock_buffer(bh); /* Hmmph! Already have it */ + return; + } + kstat.pgpgin++; + max_req = NR_REQUEST; /* reads take precedence */ + break; + case WRITEA: + rw_ahead = 1; + rw = WRITE; /* drop into WRITE */ + case WRITE: + if (!buffer_dirty(bh)) { + unlock_buffer(bh); /* Hmmph! Nothing to write */ + return; + } + /* We don't allow the write-requests to fill up the + * queue completely: we want some room for reads, + * as they take precedence. The last third of the + * requests are only for reads. + */ + kstat.pgpgout++; + max_req = (NR_REQUEST * 2) / 3; + break; + default: + printk("make_request: bad block dev cmd, must be R/W/RA/WA\n"); + unlock_buffer(bh); + return; + } /* look for a free request. */ cli(); -/* The scsi disk drivers and the IDE driver completely remove the request +/* The scsi disk and cdrom drivers completely remove the request * from the queue when they start processing an entry. For this reason * it is safe to continue to add links to the top entry for those devices. */ @@ -357,11 +371,7 @@ || major == IDE3_MAJOR) && (req = blk_dev[major].current_request)) { -#ifdef CONFIG_BLK_DEV_HD - if (major == HD_MAJOR || major == FLOPPY_MAJOR) -#else - if (major == FLOPPY_MAJOR) -#endif CONFIG_BLK_DEV_HD + if (major != SCSI_DISK_MAJOR && major != SCSI_CDROM_MAJOR) req = req->next; while (req) { if (req->rq_dev == bh->b_dev && @@ -438,12 +448,18 @@ kdevname(dev), sector); return; } - if (rw!=READ && rw!=WRITE) - panic("Bad block dev command, must be R/W"); - if (rw == WRITE && is_read_only(dev)) { - printk("Can't page to read-only device %s\n", - kdevname(dev)); - return; + switch (rw) { + case READ: + break; + case WRITE: + if (is_read_only(dev)) { + printk("Can't page to read-only device %s\n", + kdevname(dev)); + return; + } + break; + default: + panic("ll_rw_page: bad block dev cmd, must be R/W"); } req = get_request_wait(NR_REQUEST, dev); /* fill up the request-info, and add it to the queue */ @@ -524,10 +540,6 @@ if (bh[i]) { set_bit(BH_Req, &bh[i]->b_state); make_request(major, rw, bh[i]); - if (rw == READ || rw == READA) - kstat.pgpgin++; - else - kstat.pgpgout++; } } unplug_device(dev); @@ -555,17 +567,19 @@ printk("ll_rw_swap_file: trying to swap nonexistent block-device\n"); return; } - - if (rw != READ && rw != WRITE) { - printk("ll_rw_swap: bad block dev command, must be R/W"); - return; - } - if (rw == WRITE && is_read_only(dev)) { - printk("Can't swap to read-only device %s\n", - kdevname(dev)); - return; + switch (rw) { + case READ: + break; + case WRITE: + if (is_read_only(dev)) { + printk("Can't swap to read-only device %s\n", + kdevname(dev)); + return; + } + break; + default: + panic("ll_rw_swap: bad block dev cmd, must be R/W"); } - buffersize = PAGE_SIZE / nb; for (j=0, i=0; i for researching this). + * + * And, yes, Intel Zappa boards really *do* use the Triton IDE ports. */ #define _TRITON_C #include @@ -141,14 +148,12 @@ i -= rq->current_nr_sectors; ide_end_request(1, HWGROUP(drive)); } - IDE_DO_REQUEST; return; } printk("%s: bad DMA status: 0x%02x\n", drive->name, dma_stat); } sti(); - if (!ide_error(drive, "dma_intr", stat)) - IDE_DO_REQUEST; + ide_error(drive, "dma_intr", stat); } /* @@ -269,7 +274,7 @@ outl(virt_to_bus (HWIF(drive)->dmatable), dma_base + 4); /* PRD table */ outb(reading, dma_base); /* specify r/w */ outb(0x26, dma_base+2); /* clear status bits */ - ide_set_handler (drive, &dma_intr); /* issue cmd to drive */ + ide_set_handler (drive, &dma_intr, WAIT_CMD); /* issue cmd to drive */ OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); outb(inb(dma_base)|1, dma_base); /* begin DMA */ return 0; @@ -307,7 +312,7 @@ int rc = 0, h; unsigned short bmiba, pcicmd; unsigned int timings; - unsigned char *dmatable = NULL; + unsigned long dmatable = 0; extern ide_hwif_t ide_hwifs[]; /* @@ -331,7 +336,7 @@ if ((rc = pcibios_read_config_dword(bus, fn, 0x40, &timings))) goto quit; if (!(timings & 0x80008000)) { - printk("ide: Triton IDE ports are not enabled\n"); + printk("ide: neither Triton IDE port is enabled\n"); goto quit; } printk("ide: Triton BM-IDE on PCI bus %d function %d\n", bus, fn); @@ -363,15 +368,15 @@ } else { request_region(base, 8, hwif->name); hwif->dma_base = base; - if (dmatable == NULL) { + if (!dmatable) { /* * Since we know we are on a PCI bus, we could * actually use __get_free_pages() here instead * of __get_dma_pages() -- no ISA limitations. */ - dmatable = (void *) __get_dma_pages(GFP_KERNEL, 0); + dmatable = __get_dma_pages(GFP_KERNEL, 0); } - if (dmatable != NULL) { + if (dmatable) { hwif->dmatable = (unsigned long *) dmatable; dmatable += (PRD_ENTRIES * PRD_BYTES); outl(virt_to_bus(hwif->dmatable), base + 4); diff -u --recursive --new-file v1.3.45/linux/drivers/cdrom/aztcd.c linux/drivers/cdrom/aztcd.c --- v1.3.45/linux/drivers/cdrom/aztcd.c Mon Nov 27 12:48:29 1995 +++ linux/drivers/cdrom/aztcd.c Mon Dec 11 11:18:47 1995 @@ -1,5 +1,5 @@ -#define AZT_VERSION "2.0" -/* $Id: aztcd.c,v 2.0 1995/11/10 19:33:41 root Exp root $ +#define AZT_VERSION "2.1" +/* $Id: aztcd.c,v 2.10 1995/12/03 11:55:09 root Exp root $ linux/drivers/block/aztcd.c - AztechCD268 CDROM driver Copyright (C) 1994,1995 Werner Zimmermann (zimmerma@rz.fht-esslingen.de) @@ -134,13 +134,15 @@ with kernel 1.3.33. Will definitely not work with older kernels. Programming done by Linus himself. Werner Zimmermann, October 11, 1995 - V1.90 Support for Conrad TXC drives, thank's to Jochen Koch and Olaf Koluza. + V1.90 Support for Conrad TXC drives, thank's to Jochen Koch and Olaf Kaluza. Werner Zimmermann, October 21, 1995 V2.00 Changed #include "blk.h" to as the directory structure was changed. README.aztcd is now /usr/src/docu- mentation/cdrom/aztcd Werner Zimmermann, November 10, 95 - + V2.10 Started to modify azt_poll to prevent reading beyond end of + tracks. + Werner Zimmermann, December 3, 95 NOTE: Points marked with ??? are questionable ! */ @@ -258,6 +260,7 @@ 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); @@ -604,10 +607,6 @@ } -long azt_msf2hsg(struct msf *mp) -{ return azt_bcd2bin(mp -> frame) + azt_bcd2bin(mp -> sec) * 75 - + azt_bcd2bin(mp -> min) * 4500 - CD_BLOCK_OFFSET; -} static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg) { int i, st; @@ -1180,11 +1179,28 @@ if (CURRENT_VALID) { struct azt_Play_msf msf; + int i; azt_next_bn = CURRENT -> sector / 4; azt_hsg2msf(azt_next_bn, &msf.start); - azt_read_count=AZT_BUF_SIZ; /*??? fast, because we read ahead*/ -/* azt_read_count= CURRENT->nr_sectors; slow -*/ + 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*/ @@ -1629,26 +1645,26 @@ else max_count=count; printk("aztcd: FirmwareVersion="); for (count=1;count> "); if ((result[1]=='A')&&(result[2]=='Z')&&(result[3]=='T')) - { printk("aztcd: AZTECH drive detected\n"); /*AZTECH*/ + { printk("AZTECH drive detected\n"); /*AZTECH*/ } else if ((result[2]=='C')&&(result[3]=='D')&&(result[4]=='D')) - { printk("aztcd: ORCHID or WEARNES drive detected\n"); /*ORCHID or WEARNES*/ + { printk("ORCHID or WEARNES drive detected\n"); /*ORCHID or WEARNES*/ } else if ((result[1]==0x03)&&(result[2]=='5')) - { printk("aztcd: TXC drive detected\n"); /*Conrad TXC*/ + { printk("TXC drive detected\n"); /*Conrad TXC*/ } else /*OTHERS or none*/ - { printk("aztcd: : unknown drive or firmware version detected\n"); - printk(" azt may not run stable, if you want to try anyhow,\n"); - printk(" boot with: aztcd=,0x79\n"); + { printk("\nunknown drive or firmware version detected\n"); + printk("aztcd may not run stable, if you want to try anyhow,\n"); + printk("boot with: aztcd=,0x79\n"); if ((azt_cont!=0x79)) { printk("aztcd: FirmwareVersion="); for (count=1;count<5;count++) printk("%c",result[count]); - printk("\n"); - printk("aztcd: Aborted\n"); + printk("<<>> "); + printk("Aborted\n"); return -EIO; } } @@ -1666,8 +1682,8 @@ azt_invalidate_buffers(); aztPresent = 1; aztCloseDoor(); - printk("aztcd: End Init\n"); - return (0); +/* printk("aztcd: End Init\n"); +*/ return (0); } @@ -1687,6 +1703,10 @@ 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; +} static void azt_bin2bcd(unsigned char *p) { int u, t; @@ -1700,8 +1720,6 @@ { return (bcd >> 4) * 10 + (bcd & 0xF); } - - /* * Read a value from the drive. Should return quickly, so a busy wait * is used to avoid excessive rescheduling. The read command itself must @@ -2047,7 +2065,7 @@ } Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength; - + Toc[DiskInfo.last].trackTime = DiskInfo.diskLength; #ifdef AZT_DEBUG_MULTISESSION printk("aztcd: exiting aztGetToc\n"); diff -u --recursive --new-file v1.3.45/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v1.3.45/linux/drivers/char/Config.in Mon Nov 13 12:36:43 1995 +++ linux/drivers/char/Config.in Mon Dec 11 09:55:42 1995 @@ -29,3 +29,10 @@ comment '>>> Which is available from ftp://ftp.funet.fi/pub/OS/Linux/BETA/QIC-02/' fi fi +bool 'Advanced Power Management BIOS support' CONFIG_APM +if [ "$CONFIG_APM" = "y" ]; then + bool ' Ignore USER SUSPEND' CONFIG_APM_IGNORE_USER_SUSPEND + 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 +fi diff -u --recursive --new-file v1.3.45/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v1.3.45/linux/drivers/char/Makefile Mon Nov 13 12:36:43 1995 +++ linux/drivers/char/Makefile Mon Dec 11 09:55:42 1995 @@ -19,6 +19,7 @@ L_OBJS := tty_io.o n_tty.o console.o keyboard.o serial.o \ tty_ioctl.o pty.o vt.o mem.o vc_screen.o random.o \ defkeymap.o consolemap.o selection.o +SYMTAB_OBJS := ifeq ($(CONFIG_CYCLADES),y) L_OBJS += cyclades.o @@ -94,6 +95,11 @@ ifdef CONFIG_QIC02_TAPE L_OBJS += tpqic02.o +endif + +ifdef CONFIG_APM +L_OBJS += apm_bios.o +SYMTAB_OBJS += apm_bios.o endif ifdef M diff -u --recursive --new-file v1.3.45/linux/drivers/char/apm_bios.c linux/drivers/char/apm_bios.c --- v1.3.45/linux/drivers/char/apm_bios.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/char/apm_bios.c Mon Dec 11 10:15:58 1995 @@ -0,0 +1,1086 @@ +/* + * APM BIOS driver for Linux + * Copyright 1994, 1995 Stephen Rothwell (Stephen.Rothwell@pd.necisa.oz.au) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * $Id: apm_bios.c,v 0.22 1995/03/09 14:12:02 sfr Exp $ + * + * October 1995, Rik Faith (faith@cs.unc.edu): + * Minor enhancements and updates (to the patch set) for 1.3.x + * + * Reference: + * + * Intel Corporation, Microsoft Corporation. Advanced Power Management + * (APM) BIOS Interface Specification, Revision 1.1, September 1993. + * Intel Order Number 241704-001. Microsoft Part Number 781-110-X01. + * + * [This document is available free from Intel by calling 800.628.8686 (fax + * 916.356.6100) or 800.548.4725. It is also available from Microsoft by + * calling 206.882.8080; and is ftpable from + * ftp://ftp.intel.com/pub/IAL/software_specs/apmv11.doc] + * + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static struct symbol_table apm_syms = { +#include + X(apm_register_callback), + X(apm_unregister_callback), +#include +}; + +extern unsigned long get_cmos_time(void); + +/* Configurable options: + * + * CONFIG_APM_IGNORE_USER_SUSPEND: define to ignore USER SUSPEND requests. + * This is necessary on the NEC Versa M series, which generates these when + * resuming from SYSTEM SUSPEND. However, enabling this on other laptops + * will cause the laptop to generate a CRITICAL SUSPEND when an appropriate + * USER SUSPEND is ignored -- this may prevent the APM driver from updating + * the system time on a RESUME. + * + * CONFIG_APM_DO_ENABLE: enable APM features at boot time. From page 36 of + * the specification: "When disabled, the APM BIOS does not automatically + * power manage devices, enter the Standby State, enter the Suspend State, + * or take power saving steps in response to CPU Idle calls." This driver + * will make CPU Idle calls when Linux is idle (unless this feature is + * turned off -- see below). This should always save battery power, but + * more complicated APM features will be dependent on your BIOS + * implementation. You may need to turn this option off if your computer + * hangs at boot time when using APM support, or if it beeps continuously + * instead of suspending. Turn this off if you have a NEC UltraLite Versa + * 33/C or a Toshiba T400CDT. This is off by default since most machines + * do fine without this feature. + * + * CONFIG_APM_CPU_IDLE: enable calls to APM CPU Idle/CPU Busy inside the + * idle loop. On some machines, this can activate improved power savings, + * such as a slowed CPU clock rate, when the machine is idle. These idle + * call is made after the idle loop has run for some length of time (e.g., + * 333 mS). On some machines, this will cause a hang at boot time or + * whenever the CPU becomes idle. + * + * 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. + * + * 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 + * #undef these on the next line to avoid recompiling the whole kernel. + * + */ + +/* KNOWN PROBLEM MACHINES: + * + * U: TI 4000M TravelMate: BIOS is *NOT* APM compliant + * [Confirmed by TI representative] + * U: ACER 486DX4/75: uses dseg 0040, in violation of APM specification + * [Confirmed by BIOS disassembly] + * P: Toshiba 1950S: battery life information only gets updated after resume + * + * Legend: U = unusable with APM patches + * P = partially usable with APM patches + */ + +/* + * define to have debug messages + */ +#undef APM_DEBUG + +/* + * define to always call the APM BIOS busy routine even if the clock was + * not slowed by the idle routine + */ +#define ALWAYS_CALL_BUSY + +/* + * define to disable interrupts in APM BIOS calls (the CPU Idle BIOS call + * should turn interrupts on before it does a 'hlt') + */ +#define APM_NOINTS + +/* + * define to make the APM BIOS calls zero all data segment registers (do + * that an incorrect BIOS implementation will cause a kernel panic if it + * tries to write to arbitrary memory) + */ +#define APM_ZERO_SEGS + +/* + * Need to poll the APM BIOS every second + */ +#define APM_CHECK_TIMEOUT (HZ) + +/* + * These are the actual BIOS calls in assembler. Depending on + * APM_ZERO_SEGS and APM_NOINTS, we are being really paranoid here! Not + * only are interrupts disabled, but all the segment registers (except SS) + * are saved and zeroed this means that if the BIOS tries to reference any + * data without explicitly loading the segment registers, the kernel will + * fault immediately rather than have some unforeseen circumstances for the + * rest of the kernel. And it will be very obvious! :-) Doing this + * depends on CS referring to the same physical memory as DS so that DS can + * be zeroed before the call. Unfortunately, we can't do anything about the + * stack segment/pointer. Also, we tell the compiler that everything could + * change. + */ +#ifdef APM_NOINTS +# define APM_DO_CLI "cli\n\t" +#else +# define APM_DO_CLI +#endif +#ifdef APM_ZERO_SEGS +# define APM_DO_ZERO_SEGS \ + "pushl %%ds\n\t" \ + "pushl %%es\n\t" \ + "pushl %%fs\n\t" \ + "pushl %%gs\n\t" \ + "xorl %%edx, %%edx\n\t" \ + "mov %%dx, %%ds\n\t" \ + "mov %%dx, %%es\n\t" \ + "mov %%dx, %%fs\n\t" \ + "mov %%dx, %%gs\n\t" +# define APM_DO_RESTORE_SEGS \ + "popl %%gs\n\t" \ + "popl %%fs\n\t" \ + "popl %%es\n\t" \ + "popl %%ds\n\t" +#else +# define APM_DO_ZERO_SEGS +# define APM_DO_RESTORE_SEGS +#endif + +#define APM_BIOS_CALL(error_reg) \ + __asm__ __volatile__( \ + APM_DO_ZERO_SEGS \ + "pushfl\n\t" \ + APM_DO_CLI \ + "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t" \ + "setc %%" # error_reg "\n\t" \ + "popfl\n\t" \ + APM_DO_RESTORE_SEGS +#define APM_BIOS_CALL_END \ + : "ax", "bx", "cx", "dx", "si", "di", "bp", "memory") + +#ifdef CONFIG_APM_CPU_IDLE +#define APM_SET_CPU_IDLE(error) \ + APM_BIOS_CALL(al) \ + : "=a" (error) \ + : "0" (0x5305) \ + APM_BIOS_CALL_END +#endif + +#define APM_SET_CPU_BUSY(error) \ + APM_BIOS_CALL(al) \ + : "=a" (error) \ + : "0" (0x5306) \ + APM_BIOS_CALL_END + +#define APM_SET_POWER_STATE(state, error) \ + APM_BIOS_CALL(al) \ + : "=a" (error) \ + : "0" (0x5307), "b" (0x0001), "c" (state) \ + APM_BIOS_CALL_END + +#ifdef CONFIG_APM_DISPLAY_BLANK +#define APM_SET_DISPLAY_POWER_STATE(state, error) \ + APM_BIOS_CALL(al) \ + : "=a" (error) \ + : "0" (0x5307), "b" (0x01ff), "c" (state) \ + APM_BIOS_CALL_END +#endif + +#ifdef CONFIG_APM_DO_ENABLE +#define APM_ENABLE_POWER_MANAGEMENT(device, error) \ + APM_BIOS_CALL(al) \ + : "=a" (error) \ + : "0" (0x5308), "b" (device), "c" (1) \ + APM_BIOS_CALL_END +#endif + +#define APM_GET_POWER_STATUS(bx, cx, dx, error) \ + APM_BIOS_CALL(al) \ + : "=a" (error), "=b" (bx), "=c" (cx), "=d" (dx) \ + : "0" (0x530a), "1" (1) \ + APM_BIOS_CALL_END + +#define APM_GET_EVENT(event, error) \ + APM_BIOS_CALL(al) \ + : "=a" (error), "=b" (event) \ + : "0" (0x530b) \ + APM_BIOS_CALL_END + +#define APM_DRIVER_VERSION(ver, ax, error) \ + APM_BIOS_CALL(bl) \ + : "=a" (ax), "=b" (error) \ + : "0" (0x530e), "1" (0), "c" (ver) \ + APM_BIOS_CALL_END + +#define APM_ENGAGE_POWER_MANAGEMENT(device, error) \ + APM_BIOS_CALL(al) \ + : "=a" (error) \ + : "0" (0x530f), "b" (device), "c" (1) \ + APM_BIOS_CALL_END + +/* + * Forward declarations + */ +static void suspend(void); +static void standby(void); +static void set_time(void); + +static void check_events(void); +static void do_apm_timer(unsigned long); + +static int do_open(struct inode *, struct file *); +static void do_release(struct inode *, struct file *); +static int do_read(struct inode *, struct file *, char *, int); +static int do_select(struct inode *, struct file *, int, + select_table *); +static int do_ioctl(struct inode *, struct file *, u_int, u_long); + +extern int apm_register_callback(int (*)(apm_event_t)); +extern void apm_unregister_callback(int (*)(apm_event_t)); + +/* + * Local variables + */ +static asmlinkage struct { + unsigned long offset; + unsigned short segment; +} apm_bios_entry; +static int apm_enabled = 0; +#ifdef CONFIG_APM_CPU_IDLE +static int clock_slowed = 0; +#endif +static int apm_major; +static int suspends_pending = 0; +static int standbys_pending = 0; + +static long clock_cmos_diff; +static int got_clock_diff = 0; + +static struct wait_queue * process_list = NULL; +static struct apm_bios_struct * user_list = NULL; + +static struct timer_list apm_timer; + +static char driver_version[] = "0.6b"; + +#ifdef APM_DEBUG +static char * apm_event_name[] = { + "system standby", + "system suspend", + "normal resume", + "critical resume", + "low battery", + "power status change", + "update time", + "critical suspend", + "user standby", + "user suspend", + "system standby resume" +}; +#define NR_APM_EVENT_NAME \ + (sizeof(apm_event_name) / sizeof(apm_event_name[0])) +#endif + +static struct file_operations apm_bios_fops = { + NULL, /* lseek */ + do_read, + NULL, /* write */ + NULL, /* readdir */ + do_select, + do_ioctl, + NULL, /* mmap */ + do_open, + do_release, + NULL, /* fsync */ + NULL /* fasync */ +}; + +typedef struct callback_list_t { + int (* callback)(apm_event_t); + struct callback_list_t * next; +} callback_list_t; + +static callback_list_t * callback_list = NULL; + +typedef struct lookup_t { + int key; + char * msg; +} lookup_t; + +static const lookup_t error_table[] = { +/* N/A { APM_SUCCESS, "Operation succeeded" }, */ + { APM_DISABLED, "Power management disabled" }, + { APM_CONNECTED, "Real mode interface already connected" }, + { APM_NOT_CONNECTED, "Interface not connected" }, + { APM_16_CONNECTED, "16 bit interface already connected" }, +/* N/A { APM_16_UNSUPPORTED, "16 bit interface not supported" }, */ + { APM_32_CONNECTED, "32 bit interface already connected" }, + { APM_32_UNSUPPORTED, "32 bit interface not supported" }, + { APM_BAD_DEVICE, "Unrecognized device ID" }, + { APM_BAD_PARAM, "Parameter out of range" }, + { APM_NOT_ENGAGED, "Interface not engaged" }, + { APM_BAD_STATE, "Unable to enter requested state" }, +/* N/A { APM_NO_EVENTS, "No events pending" }, */ + { APM_NOT_PRESENT, "No APM present" } +}; +#define ERROR_COUNT (sizeof(error_table)/sizeof(lookup_t)) + +static int apm_driver_version(u_short *val) +{ + u_short error; + + APM_DRIVER_VERSION(*val, *val, error); + + if (error & 0xff) + return (*val >> 8); + return APM_SUCCESS; +} + +static int apm_get_event(apm_event_t *event) +{ + u_short error; + + APM_GET_EVENT(*event, error); + if (error & 0xff) + return (error >> 8); + return APM_SUCCESS; +} + +static int apm_set_power_state(u_short state) +{ + u_short error; + + APM_SET_POWER_STATE(state, error); + if (error & 0xff) + return (error >> 8); + return APM_SUCCESS; +} + +#ifdef CONFIG_APM_DISPLAY_BLANK +static int apm_set_display_power_state(u_short state) +{ + u_short error; + + APM_SET_DISPLAY_POWER_STATE(state, error); + if (error & 0xff) + return (error >> 8); + return APM_SUCCESS; +} +#endif + +#ifdef CONFIG_APM_DO_ENABLE +static int apm_enable_power_management(void) +{ + u_short error; + + APM_ENABLE_POWER_MANAGEMENT((apm_bios_info.version > 0x100) + ? 0x0001 : 0xffff, + error); + if (error & 0xff) + return (error >> 8); + return APM_SUCCESS; +} +#endif + +static int apm_get_power_status(u_short *status, u_short *bat, u_short *life) +{ + u_short error; + + APM_GET_POWER_STATUS(*status, *bat, *life, error); + if (error & 0xff) + return (error >> 8); + return APM_SUCCESS; +} + +static int apm_engage_power_management(u_short device) +{ + u_short error; + + APM_ENGAGE_POWER_MANAGEMENT(device, error); + if (error & 0xff) + return (error >> 8); + return APM_SUCCESS; +} + +static void apm_error(char *str, int err) +{ + int i; + + for (i = 0; i < ERROR_COUNT; i++) + if (error_table[i].key == err) break; + if (i < ERROR_COUNT) + printk("apm_bios: %s: %s\n", str, error_table[i].msg); + else + printk("apm_bios: %s: unknown error code %#2.2x\n", str, err); +} + +int apm_display_blank(void) +{ +#ifdef CONFIG_APM_DISPLAY_BLANK + int error; + + if (apm_bios_info.version == 0) + return 0; + error = apm_set_display_power_state(APM_STATE_STANDBY); + if (error == APM_SUCCESS) + return 1; + apm_error("set display standby", error); +#endif + return 0; +} + +int apm_display_unblank(void) +{ +#ifdef CONFIG_APM_DISPLAY_BLANK + int error; + + if (apm_bios_info.version == 0) + return 0; + error = apm_set_display_power_state(APM_STATE_READY); + if (error == APM_SUCCESS) + return 1; + apm_error("set display ready", error); +#endif + return 0; +} + +int apm_register_callback(int (*callback)(apm_event_t)) +{ + callback_list_t * new; + + new = kmalloc(sizeof(callback_list_t), GFP_KERNEL); + if (new == NULL) + return -ENOMEM; + new->callback = callback; + new->next = callback_list; + callback_list = new; + return 0; +} + +void apm_unregister_callback(int (*callback)(apm_event_t)) +{ + callback_list_t ** ptr; + callback_list_t * old; + + ptr = &callback_list; + for (ptr = &callback_list; *ptr != NULL; ptr = &(*ptr)->next) + if ((*ptr)->callback == callback) + break; + old = *ptr; + *ptr = old->next; + kfree_s(old, sizeof(callback_list_t)); +} + +static int queue_empty(struct apm_bios_struct * as) +{ + return as->event_head == as->event_tail; +} + +static apm_event_t get_queued_event(struct apm_bios_struct * as) +{ + as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; + return as->events[as->event_tail]; +} + +static int queue_event(apm_event_t event) +{ + struct apm_bios_struct * as; + + if (user_list == NULL) + return 0; + for (as = user_list; as != NULL; as = as->next) { + 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; + as->events[as->event_head] = event; + if (!as->suser) + continue; + switch (event) { + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + as->suspends_pending++; + suspends_pending++; + break; + + case APM_SYS_STANDBY: + case APM_USER_STANDBY: + as->standbys_pending++; + standbys_pending++; + break; + } + } + wake_up_interruptible(&process_list); + return 1; +} + +static void set_time(void) +{ + unsigned long flags; + + if (!got_clock_diff) /* Don't know time zone, can't set clock */ + return; + + save_flags(flags); + cli(); + CURRENT_TIME = get_cmos_time() + clock_cmos_diff; + restore_flags(flags); +} + +static void suspend(void) +{ + unsigned long flags; + int err; + + /* Estimate time zone so that set_time can + update the clock */ + save_flags(flags); + cli(); + clock_cmos_diff = CURRENT_TIME - get_cmos_time(); + got_clock_diff = 1; + restore_flags(flags); + + err = apm_set_power_state(APM_STATE_SUSPEND); + if (err) + apm_error("suspend", err); + set_time(); +} + +static void standby(void) +{ + int err; + + err = apm_set_power_state(APM_STATE_STANDBY); + if (err) + apm_error("standby", err); +} + +static apm_event_t get_event(void) +{ + int error; + apm_event_t event; + + static int notified = 0; + + error = apm_get_event(&event); + if (error == APM_SUCCESS) + return event; + + if ((error != APM_NO_EVENTS) && (notified++ == 0)) + apm_error("get_event", error); + + return 0; +} + +static void send_event(apm_event_t event, apm_event_t undo) +{ + callback_list_t * call; + callback_list_t * fix; + + for (call = callback_list; call != NULL; call = call->next) { + if (call->callback(event) && undo) { + for (fix = callback_list; fix != call; fix = fix->next) + fix->callback(undo); + if (apm_bios_info.version > 0x100) + apm_set_power_state(APM_STATE_REJECT); + return; + } + } + + queue_event(event); +} + +static void check_events(void) +{ + apm_event_t event; + + while ((event = get_event()) != 0) { + switch (event) { + case APM_SYS_STANDBY: + case APM_USER_STANDBY: + send_event(event, APM_STANDBY_RESUME); + if (standbys_pending <= 0) + standby(); + break; + + case APM_USER_SUSPEND: +#ifdef CONFIG_APM_IGNORE_USER_SUSPEND + apm_set_power_state(APM_STATE_REJECT); + break; +#endif + case APM_SYS_SUSPEND: + send_event(event, APM_NORMAL_RESUME); + if (suspends_pending <= 0) + suspend(); + break; + + case APM_NORMAL_RESUME: + case APM_CRITICAL_RESUME: + case APM_STANDBY_RESUME: + set_time(); + send_event(event, 0); + break; + + case APM_LOW_BATTERY: + case APM_POWER_STATUS_CHANGE: + send_event(event, 0); + break; + + case APM_UPDATE_TIME: + set_time(); + break; + + case APM_CRITICAL_SUSPEND: + suspend(); + break; + } +#ifdef APM_DEBUG + if (event <= NR_APM_EVENT_NAME) + printk("APM BIOS received %s notify\n", + apm_event_name[event - 1]); + else + printk("APM BIOS received unknown event 0x%02x\n", + event); +#endif + } +} + +static void do_apm_timer(unsigned long unused) +{ + int err; + + static int pending_count = 0; + + if (((standbys_pending > 0) || (suspends_pending > 0)) + && (apm_bios_info.version > 0x100) + && (pending_count-- <= 0)) { + pending_count = 4; + + err = apm_set_power_state(APM_STATE_BUSY); + if (err) + apm_error("busy", err); + } + check_events(); + + init_timer(&apm_timer); + apm_timer.expires = APM_CHECK_TIMEOUT + jiffies; + add_timer(&apm_timer); +} + +int apm_do_idle(void) +{ +#ifdef CONFIG_APM_CPU_IDLE + unsigned short error; + + if (!apm_enabled) + return 0; + + APM_SET_CPU_IDLE(error); + if (error & 0xff) + return 0; + + clock_slowed = (apm_bios_info.flags & APM_IDLE_SLOWS_CLOCK) != 0; + return 1; +#else + return 0; +#endif +} + +void apm_do_busy(void) +{ +#ifdef CONFIG_APM_CPU_IDLE + unsigned short error; + +#ifndef ALWAYS_CALL_BUSY + if (!clock_slowed) + return; +#endif + + APM_SET_CPU_BUSY(error); + + clock_slowed = 0; +#endif +} + +static int check_apm_bios_struct(struct apm_bios_struct *as, const char *func) +{ + if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) { + printk("apm_bios: %s passed bad filp", func); + return 1; + } + return 0; +} + +static int do_read(struct inode *inode, struct file *fp, char *buf, int count) +{ + struct apm_bios_struct * as; + int i; + apm_event_t event; + struct wait_queue wait = { current, NULL }; + + as = fp->private_data; + if (check_apm_bios_struct(as, "read")) + return -EIO; + if (count < sizeof(apm_event_t)) + return -EINVAL; + if (queue_empty(as)) { + if (fp->f_flags & O_NONBLOCK) + return -EAGAIN; + add_wait_queue(&process_list, &wait); +repeat: + current->state = TASK_INTERRUPTIBLE; + if (queue_empty(as) + && !(current->signal & ~current->blocked)) { + schedule(); + goto repeat; + } + current->state = TASK_RUNNING; + remove_wait_queue(&process_list, &wait); + } + i = count; + while ((i >= sizeof(event)) && !queue_empty(as)) { + event = get_queued_event(as); + memcpy_tofs(buf, &event, sizeof(event)); + buf += sizeof(event); + i -= sizeof(event); + } + if (i < count) + return count - i; + if (current->signal & ~current->blocked) + return -ERESTARTSYS; + return 0; +} + +static int do_select(struct inode *inode, struct file *fp, int sel_type, + select_table * wait) +{ + struct apm_bios_struct * as; + + as = fp->private_data; + if (check_apm_bios_struct(as, "select")) + return 0; + if (sel_type != SEL_IN) + return 0; + if (!queue_empty(as)) + return 1; + select_wait(&process_list, wait); + return 0; +} + +static int do_ioctl(struct inode * inode, struct file *filp, + u_int cmd, u_long arg) +{ + struct apm_bios_struct * as; + + as = filp->private_data; + if (check_apm_bios_struct(as, "ioctl")) + return -EIO; + switch (cmd) { + case APM_IOC_STANDBY: + if (as->standbys_pending > 0) { + as->standbys_pending--; + standbys_pending--; + if (standbys_pending <= 0) + standby(); + } + break; + case APM_IOC_SUSPEND: + if (as->suspends_pending > 0) { + as->suspends_pending--; + suspends_pending--; + if (suspends_pending <= 0) + suspend(); + } + break; + default: + return -EINVAL; + } + return 0; +} + +static void do_release(struct inode * inode, struct file * filp) +{ + struct apm_bios_struct * as; + + as = filp->private_data; + filp->private_data = NULL; + if (check_apm_bios_struct(as, "release")) + return; + if (as->standbys_pending > 0) { + standbys_pending -= as->standbys_pending; + if (standbys_pending <= 0) + standby(); + } + if (as->suspends_pending > 0) { + suspends_pending -= as->suspends_pending; + if (suspends_pending <= 0) + suspend(); + } + if (user_list == as) + user_list = as->next; + else { + struct apm_bios_struct * as1; + + for (as1 = user_list; + (as1 != NULL) && (as1->next != as); + as1 = as1->next) + ; + if (as1 == NULL) + printk("apm_bios: filp not in user list"); + else + as1->next = as->next; + } + kfree_s(as, sizeof(*as)); +} + +static int do_open(struct inode * inode, struct file * filp) +{ + struct apm_bios_struct * as; + + as = (struct apm_bios_struct *)kmalloc(sizeof(*as), GFP_KERNEL); + if (as == NULL) { + printk("apm_bios: cannot allocate struct of size %d bytes", + sizeof(*as)); + return -ENOMEM; + } + as->magic = APM_BIOS_MAGIC; + as->event_tail = as->event_head = 0; + as->suspends_pending = as->standbys_pending = 0; + as->suser = suser(); + as->next = user_list; + user_list = as; + filp->private_data = as; + return 0; +} + +int apm_proc(char *buf) +{ + char * p; + char * power_stat; + char * bat_stat; + unsigned short bx; + unsigned short cx; + unsigned short dx; + unsigned short error; + + if (apm_bios_info.version == 0) + return 0; + p = buf; + p += sprintf(p, "BIOS version: %d.%d\nFlags: 0x%02x\n", + (apm_bios_info.version >> 8) & 0xff, + apm_bios_info.version & 0xff, + apm_bios_info.flags); + if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) + return p - buf; + p += sprintf(p, "Entry %x:%lx cseg16 %x dseg %x", + apm_bios_info.cseg, apm_bios_info.offset, + apm_bios_info.cseg_16, apm_bios_info.dseg); + if (apm_bios_info.version > 0x100) + p += sprintf(p, " cseg len %x, dseg len %x", + apm_bios_info.cseg_len, apm_bios_info.dseg_len); + *p++ = '\n'; + error = apm_get_power_status(&bx, &cx, &dx); + if (error) { + strcpy(p, "Power status not available\n"); + p += strlen(p); + return p - buf; + } + switch ((bx >> 8) & 0xff) { + case 0: power_stat = "off line"; break; + case 1: power_stat = "on line"; break; + case 2: power_stat = "on backup power"; break; + default: power_stat = "unknown"; break; + } + switch (bx & 0xff) { + case 0: bat_stat = "high"; break; + case 1: bat_stat = "low"; break; + case 2: bat_stat = "critical"; break; + case 3: bat_stat = "charging"; break; + default: bat_stat = "unknown"; break; + } + p += sprintf(p, "AC: %s\nBattery status: %s\nBattery life: ", + power_stat, bat_stat); + if ((cx & 0xff) == 0xff) { + strcpy(p, "unknown"); + p += strlen(p); + } else + p += sprintf(p, "%d%%", cx & 0xff); + *p++ = '\n'; + if (apm_bios_info.version > 0x100) { + p += sprintf(p, "Battery flag: 0x%02x\nBattery life: ", + (cx >> 8) & 0xff); + if (dx == 0xffff) { + strcpy(p, "unknown"); + p += strlen(p); + } + else + p += sprintf(p, "%d %s", dx & 0x7fff, + ((dx & 0x8000) == 0) + ? "seconds" : "minutes"); + *p++ = '\n'; + } + return p - buf; +} + +static int apm_setup(void) +{ + unsigned short bx; + unsigned short cx; + unsigned short dx; + unsigned short error; + char * power_stat; + char * bat_stat; + + if (apm_bios_info.version == 0) { + printk("APM BIOS not found.\n"); + return -1; + } + printk("APM BIOS version %c.%c Flags 0x%02x (Driver version %s)\n", + ((apm_bios_info.version >> 8) & 0xff) + '0', + (apm_bios_info.version & 0xff) + '0', + apm_bios_info.flags, + driver_version); + if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) { + printk(" No 32 bit BIOS support\n"); + return -1; + } + + /* + * Fix for the Compaq Contura 3/25c which reports BIOS version 0.1 + * but is reportedly a 1.0 BIOS. + */ + if (apm_bios_info.version == 0x001) + apm_bios_info.version = 0x100; + + printk(" Entry %x:%lx cseg16 %x dseg %x", + apm_bios_info.cseg, apm_bios_info.offset, + apm_bios_info.cseg_16, apm_bios_info.dseg); + if (apm_bios_info.version > 0x100) + printk(" cseg len %x, dseg len %x", + apm_bios_info.cseg_len, apm_bios_info.dseg_len); + printk("\n"); + + apm_bios_entry.offset = apm_bios_info.offset; + apm_bios_entry.segment = APM_CS; + set_base(gdt[APM_CS >> 3], + 0xc0000000 + ((unsigned long)apm_bios_info.cseg << 4)); + set_base(gdt[APM_CS_16 >> 3], + 0xc0000000 + ((unsigned long)apm_bios_info.cseg_16 << 4)); + set_base(gdt[APM_DS >> 3], + 0xc0000000 + ((unsigned long)apm_bios_info.dseg << 4)); + if (apm_bios_info.version == 0x100) { + set_limit(gdt[APM_CS >> 3], 64 * 1024); + set_limit(gdt[APM_CS_16 >> 3], 64 * 1024); + set_limit(gdt[APM_DS >> 3], 64 * 1024); + } else { + set_limit(gdt[APM_CS >> 3], apm_bios_info.cseg_len); + /* + * This is not clear from the spec, but at least one + * machine needs this to be a 64k segment. + */ + set_limit(gdt[APM_CS_16 >> 3], 64 * 1024); + set_limit(gdt[APM_DS >> 3], apm_bios_info.dseg_len); + apm_bios_info.version = 0x0101; + error = apm_driver_version(&apm_bios_info.version); + if (error != 0) + apm_bios_info.version = 0x100; + else { + apm_engage_power_management(0x0001); + printk( " Connection version %d.%d\n", + (apm_bios_info.version >> 8) & 0xff, + apm_bios_info.version & 0xff ); + apm_bios_info.version = 0x0101; + } + } + + error = apm_get_power_status(&bx, &cx, &dx); + if (error) + printk(" Power status not available\n"); + else { + switch ((bx >> 8) & 0xff) { + case 0: power_stat = "off line"; break; + case 1: power_stat = "on line"; break; + case 2: power_stat = "on backup power"; break; + default: power_stat = "unknown"; break; + } + switch (bx & 0xff) { + case 0: bat_stat = "high"; break; + case 1: bat_stat = "low"; break; + case 2: bat_stat = "critical"; break; + case 3: bat_stat = "charging"; break; + default: bat_stat = "unknown"; break; + } + printk(" AC %s, battery status %s, battery life ", + power_stat, bat_stat); + if ((cx & 0xff) == 0xff) + printk("unknown\n"); + else + printk("%d%%\n", cx & 0xff); + if (apm_bios_info.version > 0x100) { + printk(" battery flag 0x%02x, battery life ", + (cx >> 8) & 0xff); + if (dx == 0xffff) + printk("unknown\n"); + else + printk("%d %s\n", dx & 0x7fff, + ((dx & 0x8000) == 0) + ? "seconds" : "minutes"); + } + } + +#ifdef CONFIG_APM_DO_ENABLE + /* + * This call causes my NEC UltraLite Versa 33/C to hang if it is + * booted with PM disabled but not in the docking station. + * Unfortunate ... + */ + error = apm_enable_power_management(); + if (error) + apm_error("enable power management", error); +#endif + + init_timer(&apm_timer); + apm_timer.function = do_apm_timer; + apm_timer.expires = APM_CHECK_TIMEOUT + jiffies; + add_timer(&apm_timer); + + register_symtab(&apm_syms); + + apm_enabled = 1; + + if ((apm_major = register_chrdev(0, "apm_bios", &apm_bios_fops)) < 0) + printk("APM BIOS: Cannot allocate major device number\n"); + + return 0; +} + +void apm_bios_init(void) +{ + apm_setup(); +} diff -u --recursive --new-file v1.3.45/linux/drivers/char/console.c linux/drivers/char/console.c --- v1.3.45/linux/drivers/char/console.c Mon Nov 27 12:48:30 1995 +++ linux/drivers/char/console.c Mon Dec 11 09:55:42 1995 @@ -93,6 +93,9 @@ #include #include #include +#ifdef CONFIG_APM +#include +#endif #include #include @@ -2076,6 +2079,11 @@ { int currcons; +#ifdef CONFIG_APM + if (apm_display_blank()) + return; +#endif + if (console_blanked) return; @@ -2110,6 +2118,11 @@ int currcons; int resetorg; long offset; + +#ifdef CONFIG_APM + if (apm_display_unblank()) + return; +#endif if (!console_blanked) return; diff -u --recursive --new-file v1.3.45/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v1.3.45/linux/drivers/char/lp.c Thu Nov 9 11:23:48 1995 +++ linux/drivers/char/lp.c Thu Nov 30 14:03:38 1995 @@ -503,6 +503,16 @@ memset(&LP_STAT(minor), 0, sizeof(struct lp_stats)); } break; + case LPGETFLAGS: + retval = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(int)); + if (retval) + return retval; + else { + int status = LP_F(minor); + memcpy_tofs((int *) arg, &status, sizeof(int)); + } + break; default: retval = -EINVAL; } diff -u --recursive --new-file v1.3.45/linux/drivers/net/3c501.c linux/drivers/net/3c501.c --- v1.3.45/linux/drivers/net/3c501.c Sat Nov 25 19:04:40 1995 +++ linux/drivers/net/3c501.c Thu Nov 30 11:15:53 1995 @@ -79,9 +79,9 @@ "3c501.c: 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov).\n"; /* - Braindamage remaining: - The 3c501 board. - */ + * Braindamage remaining: + * The 3c501 board. + */ #include @@ -110,7 +110,10 @@ { 0x280, 0x300, 0}; -/* Index to functions. */ +/* + * Index to functions. + */ + int el1_probe(struct device *dev); static int el1_probe1(struct device *dev, int ioaddr); static int el_open(struct device *dev); @@ -129,8 +132,12 @@ #endif /* Anything above 5 is wordy death! */ static int el_debug = EL_DEBUG; -/* Board-specific info in dev->priv. */ -struct net_local { +/* + * Board-specific info in dev->priv. + */ + +struct net_local +{ struct enet_statistics stats; int tx_pkt_start; /* The length of the current Tx packet. */ int collisions; /* Tx collisions this packet */ @@ -158,7 +165,10 @@ #define EL1_SAPROM 0x0C #define EL1_DATAPORT 0x0f -/* Writes to the ax command register. */ +/* + * Writes to the ax command register. + */ + #define AX_OFF 0x00 /* Irq off, buffer access on */ #define AX_SYS 0x40 /* Load the buffer */ #define AX_XMIT 0x44 /* Transmit a packet */ @@ -166,14 +176,20 @@ #define AX_LOOP 0x0C /* Loopback mode */ #define AX_RESET 0x80 -/* Normal receive mode written to RX_STATUS. We must intr on short packets - to avoid bogus rx lockups. */ +/* + * Normal receive mode written to RX_STATUS. We must intr on short packets + * to avoid bogus rx lockups. + */ + #define RX_NORM 0xA8 /* 0x68 == all addrs, 0xA8 only to me. */ #define RX_PROM 0x68 /* Senior Prom, uhmm promiscuous mode. */ #define RX_MULT 0xE8 /* Accept multicast packets. */ -#define TX_NORM 0x0A /* Interrupt on everything that might hang the chip */ +#define TX_NORM 0x0A /* Interrupt on everything that might hang the chip */ -/* TX_STATUS register. */ +/* + * TX_STATUS register. + */ + #define TX_COLLISION 0x02 #define TX_16COLLISIONS 0x04 #define TX_READY 0x08 @@ -183,468 +199,551 @@ #define RX_GOOD 0x30 /* Good packet 0x20, or simple overflow 0x10. */ -/* The boilerplate probe code. */ +/* + * The boilerplate probe code. + */ + #ifdef HAVE_DEVLIST -struct netdev_entry el1_drv = -{"3c501", el1_probe1, EL1_IO_EXTENT, netcard_portlist}; +struct netdev_entry el1_drv = {"3c501", el1_probe1, EL1_IO_EXTENT, netcard_portlist}; #else -int -el1_probe(struct device *dev) + +int el1_probe(struct device *dev) { - int i; - int base_addr = dev ? dev->base_addr : 0; + int i; + int base_addr = dev ? dev->base_addr : 0; - if (base_addr > 0x1ff) /* Check a single specified location. */ - return el1_probe1(dev, base_addr); - else if (base_addr != 0) /* Don't probe at all. */ - return ENXIO; - - for (i = 0; netcard_portlist[i]; i++) { - int ioaddr = netcard_portlist[i]; - if (check_region(ioaddr, EL1_IO_EXTENT)) - continue; - if (el1_probe1(dev, ioaddr) == 0) - return 0; - } + if (base_addr > 0x1ff) /* Check a single specified location. */ + return el1_probe1(dev, base_addr); + else if (base_addr != 0) /* Don't probe at all. */ + return ENXIO; - return ENODEV; + for (i = 0; netcard_portlist[i]; i++) + { + int ioaddr = netcard_portlist[i]; + if (check_region(ioaddr, EL1_IO_EXTENT)) + continue; + if (el1_probe1(dev, ioaddr) == 0) + return 0; + } + + return ENODEV; } #endif -/* The actual probe. */ -static int -el1_probe1(struct device *dev, int ioaddr) -{ - #ifndef MODULE - - const char *mname; /* Vendor name */ - unsigned char station_addr[6]; - int autoirq = 0; - int i; - - /* Read the station address PROM data from the special port. */ - for (i = 0; i < 6; i++) { - outw(i, ioaddr + EL1_DATAPTR); - station_addr[i] = inb(ioaddr + EL1_SAPROM); - } - /* Check the first three octets of the S.A. for 3Com's prefix, or - for the Sager NP943 prefix. */ - if (station_addr[0] == 0x02 && station_addr[1] == 0x60 - && station_addr[2] == 0x8c) { - mname = "3c501"; - } else if (station_addr[0] == 0x00 && station_addr[1] == 0x80 - && station_addr[2] == 0xC8) { - mname = "NP943"; - } else - return ENODEV; +/* + * The actual probe. + */ - /* Grab the region so we can find the another board if autoIRQ fails. */ - request_region(ioaddr, EL1_IO_EXTENT,"3c501"); +static int el1_probe1(struct device *dev, int ioaddr) +{ +#ifndef MODULE - /* We auto-IRQ by shutting off the interrupt line and letting it float - high. */ - if (dev->irq < 2) { + const char *mname; /* Vendor name */ + unsigned char station_addr[6]; + int autoirq = 0; + int i; - autoirq_setup(2); + /* + * Read the station address PROM data from the special port. + */ + + for (i = 0; i < 6; i++) + { + outw(i, ioaddr + EL1_DATAPTR); + station_addr[i] = inb(ioaddr + EL1_SAPROM); + } + /* + * Check the first three octets of the S.A. for 3Com's prefix, or + * for the Sager NP943 prefix. + */ + + if (station_addr[0] == 0x02 && station_addr[1] == 0x60 + && station_addr[2] == 0x8c) + { + mname = "3c501"; + } else if (station_addr[0] == 0x00 && station_addr[1] == 0x80 + && station_addr[2] == 0xC8) + { + mname = "NP943"; + } + else + return ENODEV; - inb(RX_STATUS); /* Clear pending interrupts. */ - inb(TX_STATUS); - outb(AX_LOOP + 1, AX_CMD); + /* + * Grab the region so we can find the another board if autoIRQ fails. + */ - outb(0x00, AX_CMD); + request_region(ioaddr, EL1_IO_EXTENT,"3c501"); - autoirq = autoirq_report(1); + /* + * We auto-IRQ by shutting off the interrupt line and letting it float + * high. + */ - if (autoirq == 0) { - printk("%s probe at %#x failed to detect IRQ line.\n", - mname, ioaddr); - return EAGAIN; - } - } + if (dev->irq < 2) + { + autoirq_setup(2); + inb(RX_STATUS); /* Clear pending interrupts. */ + inb(TX_STATUS); + outb(AX_LOOP + 1, AX_CMD); + + outb(0x00, AX_CMD); + + autoirq = autoirq_report(1); - outb(AX_RESET+AX_LOOP, AX_CMD); /* Loopback mode. */ + if (autoirq == 0) + { + printk("%s probe at %#x failed to detect IRQ line.\n", + mname, ioaddr); + return EAGAIN; + } + } - dev->base_addr = ioaddr; - memcpy(dev->dev_addr, station_addr, ETH_ALEN); - if (dev->mem_start & 0xf) - el_debug = dev->mem_start & 0x7; - if (autoirq) - dev->irq = autoirq; + outb(AX_RESET+AX_LOOP, AX_CMD); /* Loopback mode. */ + dev->base_addr = ioaddr; + memcpy(dev->dev_addr, station_addr, ETH_ALEN); + + if (dev->mem_start & 0xf) + el_debug = dev->mem_start & 0x7; + if (autoirq) + dev->irq = autoirq; - printk("%s: %s EtherLink at %#lx, using %sIRQ %d.\n", - dev->name, mname, dev->base_addr, - autoirq ? "auto":"assigned ", dev->irq); + printk("%s: %s EtherLink at %#lx, using %sIRQ %d.\n", dev->name, mname, dev->base_addr, + autoirq ? "auto":"assigned ", dev->irq); #ifdef CONFIG_IP_MULTICAST - printk("WARNING: Use of the 3c501 in a multicast kernel is NOT recommended.\n"); + printk("WARNING: Use of the 3c501 in a multicast kernel is NOT recommended.\n"); #endif - if (el_debug) - printk("%s", version); + if (el_debug) + printk("%s", version); + + /* + * Initialize the device structure. + */ + + dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct net_local)); + + /* + * The EL1-specific entries in the device structure. + */ + + dev->open = &el_open; + dev->hard_start_xmit = &el_start_xmit; + dev->stop = &el1_close; + dev->get_stats = &el1_get_stats; + dev->set_multicast_list = &set_multicast_list; + + /* + * Setup the generic properties + */ - /* Initialize the device structure. */ - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_local)); - - /* The EL1-specific entries in the device structure. */ - dev->open = &el_open; - dev->hard_start_xmit = &el_start_xmit; - dev->stop = &el1_close; - dev->get_stats = &el1_get_stats; - dev->set_multicast_list = &set_multicast_list; - /* Setup the generic properties */ - ether_setup(dev); + ether_setup(dev); #endif /* !MODULE */ - return 0; + + return 0; } -/* Open/initialize the board. */ -static int -el_open(struct device *dev) +/* + * Open/initialize the board. + */ + +static int el_open(struct device *dev) { - int ioaddr = dev->base_addr; + int ioaddr = dev->base_addr; - if (el_debug > 2) - printk("%s: Doing el_open()...", dev->name); + if (el_debug > 2) + printk("%s: Doing el_open()...", dev->name); - if (request_irq(dev->irq, &el_interrupt, 0, "3c501")) { - return -EAGAIN; - } - irq2dev_map[dev->irq] = dev; + if (request_irq(dev->irq, &el_interrupt, 0, "3c501")) + return -EAGAIN; - el_reset(dev); + irq2dev_map[dev->irq] = dev; + el_reset(dev); - dev->start = 1; + dev->start = 1; - outb(AX_RX, AX_CMD); /* Aux control, irq and receive enabled */ - MOD_INC_USE_COUNT; - return 0; + outb(AX_RX, AX_CMD); /* Aux control, irq and receive enabled */ + MOD_INC_USE_COUNT; + return 0; } -static int -el_start_xmit(struct sk_buff *skb, struct device *dev) +static int el_start_xmit(struct sk_buff *skb, struct device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; - int ioaddr = dev->base_addr; - unsigned long flags; + struct net_local *lp = (struct net_local *)dev->priv; + int ioaddr = dev->base_addr; + unsigned long flags; - if (dev->tbusy) { - if (jiffies - dev->trans_start < 20) { - if (el_debug > 2) - printk(" transmitter busy, deferred.\n"); - return 1; + if (dev->tbusy) + { + if (jiffies - dev->trans_start < 20) + { + if (el_debug > 2) + printk(" transmitter busy, deferred.\n"); + return 1; + } + if (el_debug) + printk ("%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n", + dev->name, inb(TX_STATUS), inb(AX_STATUS), inb(RX_STATUS)); + lp->stats.tx_errors++; + outb(TX_NORM, TX_CMD); + outb(RX_NORM, RX_CMD); + outb(AX_OFF, AX_CMD); /* Just trigger a false interrupt. */ + outb(AX_RX, AX_CMD); /* Aux control, irq and receive enabled */ + dev->tbusy = 0; + dev->trans_start = jiffies; } - if (el_debug) - printk ("%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n", - dev->name, inb(TX_STATUS), inb(AX_STATUS), inb(RX_STATUS)); - lp->stats.tx_errors++; - outb(TX_NORM, TX_CMD); - outb(RX_NORM, RX_CMD); - outb(AX_OFF, AX_CMD); /* Just trigger a false interrupt. */ - outb(AX_RX, AX_CMD); /* Aux control, irq and receive enabled */ - dev->tbusy = 0; - dev->trans_start = jiffies; - } - if (skb == NULL) { - dev_tint(dev); - return 0; - } - - save_flags(flags); - /* Avoid incoming interrupts between us flipping tbusy and flipping - mode as the driver assumes tbusy is a faithful indicator of card - state */ - cli(); - /* Avoid timer-based retransmission conflicts. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) - { - restore_flags(flags); - printk("%s: Transmitter access conflict.\n", dev->name); - } - else { - int gp_start = 0x800 - (ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN); - unsigned char *buf = skb->data; + if (skb == NULL) + { + dev_tint(dev); + return 0; + } -load_it_again_sam: - lp->tx_pkt_start = gp_start; - lp->collisions = 0; + save_flags(flags); /* - * Command mode with status cleared should [in theory] - * mean no more interrupts can be pending on the card. + * Avoid incoming interrupts between us flipping tbusy and flipping + * mode as the driver assumes tbusy is a faithful indicator of card + * state */ - outb(AX_SYS, AX_CMD); - inb(RX_STATUS); - inb(TX_STATUS); + + cli(); + + /* + * Avoid timer-based retransmission conflicts. + */ + + if (set_bit(0, (void*)&dev->tbusy) != 0) + { + restore_flags(flags); + printk("%s: Transmitter access conflict.\n", dev->name); + } + else + { + int gp_start = 0x800 - (ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN); + unsigned char *buf = skb->data; + +load_it_again_sam: + lp->tx_pkt_start = gp_start; + lp->collisions = 0; + + /* + * Command mode with status cleared should [in theory] + * mean no more interrupts can be pending on the card. + */ - lp->loading=1; + outb(AX_SYS, AX_CMD); + inb(RX_STATUS); + inb(TX_STATUS); - /* - * Turn interrupts back on while we spend a pleasant afternoon - * loading bytes into the board - */ - restore_flags(flags); - outw(0x00, RX_BUF_CLR); /* Set rx packet area to 0. */ - outw(gp_start, GP_LOW); /* aim - packet will be loaded into buffer start */ - outsb(DATAPORT,buf,skb->len); /* load buffer (usual thing each byte increments the pointer) */ - outw(gp_start, GP_LOW); /* the board reuses the same register */ - if(lp->loading==2) /* A receive upset our load, despite our best efforts */ - { - if(el_debug>2) - printk("%s: burped during tx load.\n", dev->name); - goto load_it_again_sam; /* Sigh... */ - } - outb(AX_XMIT, AX_CMD); /* fire ... Trigger xmit. */ - dev->trans_start = jiffies; - } - - if (el_debug > 2) - printk(" queued xmit.\n"); - dev_kfree_skb (skb, FREE_WRITE); - return 0; + lp->loading=1; + + /* + * Turn interrupts back on while we spend a pleasant afternoon + * loading bytes into the board + */ + + restore_flags(flags); + outw(0x00, RX_BUF_CLR); /* Set rx packet area to 0. */ + outw(gp_start, GP_LOW); /* aim - packet will be loaded into buffer start */ + outsb(DATAPORT,buf,skb->len); /* load buffer (usual thing each byte increments the pointer) */ + outw(gp_start, GP_LOW); /* the board reuses the same register */ + if(lp->loading==2) /* A receive upset our load, despite our best efforts */ + { + if(el_debug>2) + printk("%s: burped during tx load.\n", dev->name); + goto load_it_again_sam; /* Sigh... */ + } + outb(AX_XMIT, AX_CMD); /* fire ... Trigger xmit. */ + dev->trans_start = jiffies; + } + + if (el_debug > 2) + printk(" queued xmit.\n"); + dev_kfree_skb (skb, FREE_WRITE); + return 0; } -/* The typical workload of the driver: - Handle the ether interface interrupts. */ -static void -el_interrupt(int irq, struct pt_regs *regs) -{ - struct device *dev = (struct device *)(irq2dev_map[irq]); - struct net_local *lp; - int ioaddr; - int axsr; /* Aux. status reg. */ +/* + * The typical workload of the driver: + * Handle the ether interface interrupts. + */ + +static void el_interrupt(int irq, struct pt_regs *regs) +{ + struct device *dev = (struct device *)(irq2dev_map[irq]); + struct net_local *lp; + int ioaddr; + int axsr; /* Aux. status reg. */ - if (dev == NULL || dev->irq != irq) { - printk ("3c501 driver: irq %d for unknown device.\n", irq); - return; - } + if (dev == NULL || dev->irq != irq) + { + printk ("3c501 driver: irq %d for unknown device.\n", irq); + return; + } + + ioaddr = dev->base_addr; + lp = (struct net_local *)dev->priv; + + /* + * What happened ? + */ + + axsr = inb(AX_STATUS); - ioaddr = dev->base_addr; - lp = (struct net_local *)dev->priv; - axsr = inb(AX_STATUS); - - if (el_debug > 3) - printk("%s: el_interrupt() aux=%#02x", dev->name, axsr); - if (dev->interrupt) - printk("%s: Reentering the interrupt driver!\n", dev->name); - dev->interrupt = 1; + /* + * Log it + */ + + if (el_debug > 3) + printk("%s: el_interrupt() aux=%#02x", dev->name, axsr); + if (dev->interrupt) + printk("%s: Reentering the interrupt driver!\n", dev->name); + dev->interrupt = 1; - lp->loading=2; /* So we can spot loading interruptions */ + lp->loading=2; /* So we can spot loading interruptions */ - if (dev->tbusy) { + if (dev->tbusy) + { - /* - * Board in transmit mode. - */ + /* + * Board in transmit mode. + */ - int txsr = inb(TX_STATUS); + int txsr = inb(TX_STATUS); - if (el_debug > 6) - printk(" txsr=%02x gp=%04x rp=%04x", txsr, inw(GP_LOW), - inw(RX_LOW)); - - if ((axsr & 0x80) && (txsr & TX_READY) == 0) { - /* - * FIXME: is there a logic to whether to keep on trying or - * reset immediately ? - */ - printk("%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x" - " gp=%03x rp=%03x.\n", dev->name, txsr, axsr, - inw(ioaddr + EL1_DATAPTR), inw(ioaddr + EL1_RXPTR)); - dev->tbusy = 0; - mark_bh(NET_BH); - } else if (txsr & TX_16COLLISIONS) { - /* - * Timed out - */ - if (el_debug) - printk("%s: Transmit failed 16 times, ethernet jammed?\n", - dev->name); - outb(AX_SYS, AX_CMD); - lp->stats.tx_aborted_errors++; - } else if (txsr & TX_COLLISION) { /* Retrigger xmit. */ - if (el_debug > 6) - printk(" retransmitting after a collision.\n"); - /* - * Poor little chip can't reset its own start pointer - */ - outb(AX_SYS, AX_CMD); - outw(lp->tx_pkt_start, GP_LOW); - outb(AX_XMIT, AX_CMD); - lp->stats.collisions++; - dev->interrupt = 0; - return; - } else { - /* - * It worked.. we will now fall through and receive - */ - lp->stats.tx_packets++; - if (el_debug > 6) - printk(" Tx succeeded %s\n", - (txsr & TX_RDY) ? "." : "but tx is busy!"); - /* - * This is safe the interrupt is atomic WRT itself. - */ - dev->tbusy = 0; - mark_bh(NET_BH); /* In case more to transmit */ + if (el_debug > 6) + printk(" txsr=%02x gp=%04x rp=%04x", txsr, inw(GP_LOW),inw(RX_LOW)); + + if ((axsr & 0x80) && (txsr & TX_READY) == 0) + { + /* + * FIXME: is there a logic to whether to keep on trying or + * reset immediately ? + */ + printk("%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x" + " gp=%03x rp=%03x.\n", dev->name, txsr, axsr, + inw(ioaddr + EL1_DATAPTR), inw(ioaddr + EL1_RXPTR)); + dev->tbusy = 0; + mark_bh(NET_BH); + } + else if (txsr & TX_16COLLISIONS) + { + /* + * Timed out + */ + if (el_debug) + printk("%s: Transmit failed 16 times, ethernet jammed?\n",dev->name); + outb(AX_SYS, AX_CMD); + lp->stats.tx_aborted_errors++; + } + else if (txsr & TX_COLLISION) + { + /* + * Retrigger xmit. + */ + + if (el_debug > 6) + printk(" retransmitting after a collision.\n"); + /* + * Poor little chip can't reset its own start pointer + */ + + outb(AX_SYS, AX_CMD); + outw(lp->tx_pkt_start, GP_LOW); + outb(AX_XMIT, AX_CMD); + lp->stats.collisions++; + dev->interrupt = 0; + return; + } + else + { + /* + * It worked.. we will now fall through and receive + */ + lp->stats.tx_packets++; + if (el_debug > 6) + printk(" Tx succeeded %s\n", + (txsr & TX_RDY) ? "." : "but tx is busy!"); + /* + * This is safe the interrupt is atomic WRT itself. + */ + + dev->tbusy = 0; + mark_bh(NET_BH); /* In case more to transmit */ + } } - } else { - - /* - * In receive mode. - */ + else + { + /* + * In receive mode. + */ - int rxsr = inb(RX_STATUS); - if (el_debug > 5) - printk(" rxsr=%02x txsr=%02x rp=%04x", rxsr, inb(TX_STATUS), - inw(RX_LOW)); - - /* - * Just reading rx_status fixes most errors. - */ - if (rxsr & RX_MISSED) - lp->stats.rx_missed_errors++; - if (rxsr & RX_RUNT) { /* Handled to avoid board lock-up. */ - lp->stats.rx_length_errors++; - if (el_debug > 5) printk(" runt.\n"); - } else if (rxsr & RX_GOOD) { - /* - * Receive worked. - */ - el_receive(dev); - } else { /* Nothing? Something is broken! */ - if (el_debug > 2) - printk("%s: No packet seen, rxsr=%02x **resetting 3c501***\n", - dev->name, rxsr); - el_reset(dev); + int rxsr = inb(RX_STATUS); + if (el_debug > 5) + printk(" rxsr=%02x txsr=%02x rp=%04x", rxsr, inb(TX_STATUS),inw(RX_LOW)); + /* + * Just reading rx_status fixes most errors. + */ + if (rxsr & RX_MISSED) + lp->stats.rx_missed_errors++; + if (rxsr & RX_RUNT) + { /* Handled to avoid board lock-up. */ + lp->stats.rx_length_errors++; + if (el_debug > 5) + printk(" runt.\n"); + } + else if (rxsr & RX_GOOD) + { + /* + * Receive worked. + */ + el_receive(dev); + } + else + { + /* + * Nothing? Something is broken! + */ + if (el_debug > 2) + printk("%s: No packet seen, rxsr=%02x **resetting 3c501***\n", + dev->name, rxsr); + el_reset(dev); + } + if (el_debug > 3) + printk(".\n"); } - if (el_debug > 3) - printk(".\n"); - } - /* - * Move into receive mode - */ - outb(AX_RX, AX_CMD); - outw(0x00, RX_BUF_CLR); - inb(RX_STATUS); /* Be certain that interrupts are cleared. */ - inb(TX_STATUS); - dev->interrupt = 0; - return; + /* + * Move into receive mode + */ + + outb(AX_RX, AX_CMD); + outw(0x00, RX_BUF_CLR); + inb(RX_STATUS); /* Be certain that interrupts are cleared. */ + inb(TX_STATUS); + dev->interrupt = 0; + return; } -/* We have a good packet. Well, not really "good", just mostly not broken. - We must check everything to see if it is good. */ -static void -el_receive(struct device *dev) +/* + * We have a good packet. Well, not really "good", just mostly not broken. + * We must check everything to see if it is good. + */ + +static void el_receive(struct device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; - int ioaddr = dev->base_addr; - int pkt_len; - struct sk_buff *skb; + struct net_local *lp = (struct net_local *)dev->priv; + int ioaddr = dev->base_addr; + int pkt_len; + struct sk_buff *skb; - pkt_len = inw(RX_LOW); + pkt_len = inw(RX_LOW); - if (el_debug > 4) - printk(" el_receive %d.\n", pkt_len); + if (el_debug > 4) + printk(" el_receive %d.\n", pkt_len); - if ((pkt_len < 60) || (pkt_len > 1536)) { - if (el_debug) - printk("%s: bogus packet, length=%d\n", dev->name, pkt_len); - lp->stats.rx_over_errors++; - return; - } + if ((pkt_len < 60) || (pkt_len > 1536)) + { + if (el_debug) + printk("%s: bogus packet, length=%d\n", dev->name, pkt_len); + lp->stats.rx_over_errors++; + return; + } - /* - * Command mode so we can empty the buffer - */ + /* + * Command mode so we can empty the buffer + */ - outb(AX_SYS, AX_CMD); - - skb = dev_alloc_skb(pkt_len+2); - /* - * Start of frame - */ - outw(0x00, GP_LOW); - if (skb == NULL) { - printk("%s: Memory squeeze, dropping packet.\n", dev->name); - lp->stats.rx_dropped++; - return; - } else { - skb_reserve(skb,2); /* Force 16 byte alignment */ - skb->dev = dev; + outb(AX_SYS, AX_CMD); + skb = dev_alloc_skb(pkt_len+2); /* - * The read increments through the bytes. The interrupt - * handler will fix the pointer when it returns to - * receive mode. + * Start of frame */ - - insb(DATAPORT, skb_put(skb,pkt_len), pkt_len); - skb->protocol=eth_type_trans(skb,dev); - netif_rx(skb); - lp->stats.rx_packets++; - } - return; -} - -static void -el_reset(struct device *dev) -{ - int ioaddr = dev->base_addr; - - if (el_debug> 2) - printk("3c501 reset..."); - outb(AX_RESET, AX_CMD); /* Reset the chip */ - outb(AX_LOOP, AX_CMD); /* Aux control, irq and loopback enabled */ - { - int i; - for (i = 0; i < 6; i++) /* Set the station address. */ - outb(dev->dev_addr[i], ioaddr + i); - } + + outw(0x00, GP_LOW); + if (skb == NULL) + { + printk("%s: Memory squeeze, dropping packet.\n", dev->name); + lp->stats.rx_dropped++; + return; + } + else + { + skb_reserve(skb,2); /* Force 16 byte alignment */ + skb->dev = dev; + /* + * The read increments through the bytes. The interrupt + * handler will fix the pointer when it returns to + * receive mode. + */ + insb(DATAPORT, skb_put(skb,pkt_len), pkt_len); + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + lp->stats.rx_packets++; + } + return; +} + +static void el_reset(struct device *dev) +{ + int ioaddr = dev->base_addr; + + if (el_debug> 2) + printk("3c501 reset..."); + outb(AX_RESET, AX_CMD); /* Reset the chip */ + outb(AX_LOOP, AX_CMD); /* Aux control, irq and loopback enabled */ + { + int i; + for (i = 0; i < 6; i++) /* Set the station address. */ + outb(dev->dev_addr[i], ioaddr + i); + } - outw(0, RX_BUF_CLR); /* Set rx packet area to 0. */ - cli(); /* Avoid glitch on writes to CMD regs */ - outb(TX_NORM, TX_CMD); /* tx irq on done, collision */ - outb(RX_NORM, RX_CMD); /* Set Rx commands. */ - inb(RX_STATUS); /* Clear status. */ - inb(TX_STATUS); - dev->interrupt = 0; - dev->tbusy = 0; - sti(); + outw(0, RX_BUF_CLR); /* Set rx packet area to 0. */ + cli(); /* Avoid glitch on writes to CMD regs */ + outb(TX_NORM, TX_CMD); /* tx irq on done, collision */ + outb(RX_NORM, RX_CMD); /* Set Rx commands. */ + inb(RX_STATUS); /* Clear status. */ + inb(TX_STATUS); + dev->interrupt = 0; + dev->tbusy = 0; + sti(); } -static int -el1_close(struct device *dev) +static int el1_close(struct device *dev) { - int ioaddr = dev->base_addr; + int ioaddr = dev->base_addr; - if (el_debug > 2) - printk("%s: Shutting down ethercard at %#x.\n", dev->name, ioaddr); + if (el_debug > 2) + printk("%s: Shutting down ethercard at %#x.\n", dev->name, ioaddr); - dev->tbusy = 1; - dev->start = 0; + dev->tbusy = 1; + dev->start = 0; - /* Free and disable the IRQ. */ - free_irq(dev->irq); - outb(AX_RESET, AX_CMD); /* Reset the chip */ - irq2dev_map[dev->irq] = 0; + /* + * Free and disable the IRQ. + */ - MOD_DEC_USE_COUNT; - return 0; + free_irq(dev->irq); + outb(AX_RESET, AX_CMD); /* Reset the chip */ + irq2dev_map[dev->irq] = 0; + + MOD_DEC_USE_COUNT; + return 0; } -static struct enet_statistics * -el1_get_stats(struct device *dev) +static struct enet_statistics *el1_get_stats(struct device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; - return &lp->stats; + struct net_local *lp = (struct net_local *)dev->priv; + return &lp->stats; } /* @@ -674,18 +773,21 @@ } #ifdef MODULE + static char devicename[9] = { 0, }; -static struct device dev_3c501 = { + +static struct device dev_3c501 = +{ devicename, /* device name is inserted by linux/drivers/net/net_init.c */ 0, 0, 0, 0, 0x280, 5, - 0, 0, 0, NULL, el1_probe }; + 0, 0, 0, NULL, el1_probe +}; static int io=0x280; static int irq=5; -int -init_module(void) +int init_module(void) { dev_3c501.irq=irq; dev_3c501.base_addr=io; @@ -694,19 +796,27 @@ return 0; } -void -cleanup_module(void) +void cleanup_module(void) { - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + /* + * No need to check MOD_IN_USE, as sys_delete_module() checks. + */ + unregister_netdev(&dev_3c501); - /* Free up the private structure, or leak memory :-) */ + /* + * Free up the private structure, or leak memory :-) + */ + kfree(dev_3c501.priv); dev_3c501.priv = NULL; /* gets re-allocated by el1_probe1 */ - /* If we don't do this, we can't re-insmod it later. */ + /* + * If we don't do this, we can't re-insmod it later. + */ release_region(dev_3c501.base_addr, EL1_IO_EXTENT); } + #endif /* MODULE */ /* diff -u --recursive --new-file v1.3.45/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c --- v1.3.45/linux/drivers/net/arcnet.c Mon Nov 27 12:48:30 1995 +++ linux/drivers/net/arcnet.c Thu Nov 30 14:05:00 1995 @@ -17,6 +17,22 @@ ********************** + v2.21 ALPHA (95/11/29) + - "Unknown protocol ID" messages now also indicate the station + which sent the unrecognized packet, to aid in debugging network + confusion. Also, if anyone knows why Novell servers send packets + with protocol ID 0xEC, be sure to tell me. For now they're + ignored. + - Rearranged ARC_P_* handling a bit, so it makes slightly more + sense. + - We were clearing irq2dev_map too soon, and causing spurious + "irq %d for unknown device" messages. Moved all the set/clear + irq2dev_map operations to more intelligent places. + - 1.2.x kernels really didn't work with 2.20 ALPHA. Maybe this + will fix it. + - Fixed the setting of set_multicast_list. Since we don't have + multicast support, there's no point in using this at all. + v2.20 ALPHA (95/11/12) - Added a bit of protocol confusion to the arc0 code to allow trxnet-compatible IPX support - and the use of all that new @@ -156,7 +172,7 @@ */ static const char *version = - "arcnet.c: v2.20 ALPHA 95/11/12 Avery Pennarun \n"; + "arcnet.c: v2.21 ALPHA 95/11/29 Avery Pennarun \n"; @@ -166,9 +182,20 @@ /* are we Linux 1.2.x? */ #if LINUX_VERSION_CODE < 0x10300 -#define LINUX12 +# define LINUX12 #endif +/* for older kernels with older module.h */ +#ifdef LINUX12 +# ifdef MODULE + char kernel_version[] = UTS_RELEASE; +# else +# undef MOD_INC_USE_COUNT +# define MOD_INC_USE_COUNT +# undef MOD_DEC_USE_COUNT +# define MOD_DEC_USE_COUNT +# endif +#endif #include #include @@ -414,6 +441,7 @@ #define ARC_P_ARP 213 /* 0xD5 */ #define ARC_P_RARP 214 /* 0xD6 */ #define ARC_P_IPX 250 /* 0xFA */ +#define ARC_P_NOVELL_EC 236 /* 0xEC */ /* Old RFC1051 Protocol ID's */ #define ARC_P_IP_RFC1051 240 /* 0xF0 */ @@ -575,8 +603,9 @@ int length,u_char saddr, u_char daddr); static struct enet_statistics *arcnet_get_stats(struct device *dev); +/* static void set_multicast_list(struct device *dev); - +*/ /* functions for header/arp/etc building */ #ifdef LINUX12 int arcnetA_header(unsigned char *buff,struct device *dev, @@ -745,8 +774,10 @@ printk("%6s: unable to get IRQ %d (irqval=%d).\n", dev->name,dev->irq, irqval); return EAGAIN; - } - } + } + + irq2dev_map[dev->irq]=dev; + } /* Grab the region so we can find another board if autoIRQ fails. */ request_region(dev->base_addr, ARCNET_TOTAL_SIZE,"arcnet"); @@ -765,9 +796,7 @@ dev->stop=arcnet_close; dev->hard_start_xmit=arcnetA_send_packet; dev->get_stats=arcnet_get_stats; -#ifdef HAVE_MULTICAST - dev->set_multicast_list = &set_multicast_list; -#endif + /*dev->set_multicast_list = &set_multicast_list;*/ /* Fill in the fields of the device structure with generic * values. @@ -1097,7 +1126,7 @@ #ifdef LINUX12 dev->type_trans=arcnetS_type_trans; #endif - BUGMSG(D_EXTRA,"ARCnet RFC1051 (NetBsd, AmiTCP) protocol initialized.\n"); + BUGMSG(D_EXTRA,"ARCnet RFC1051 (NetBSD, AmiTCP) protocol initialized.\n"); return 0; } @@ -1132,8 +1161,6 @@ BUGLVL(D_EXTRA) printk(version); - irq2dev_map[dev->irq] = dev; - BUGMSG(D_EXTRA,"arcnet_open: resetting card.\n"); /* try to reset - twice if it fails the first time */ @@ -1198,11 +1225,7 @@ TBUSY=1; START=0; - - /* very important! */ - irq2dev_map[dev->irq] = NULL; - /* Flush TX and disable RX */ outb(0,INTMASK); /* no IRQ's (except RESET, of course) */ outb(NOTXcmd,COMMAND); /* stop transmit */ @@ -1883,6 +1906,8 @@ arcnet_interrupt(int irq,struct pt_regs *regs) { struct device *dev = (struct device *)(irq2dev_map[irq]); + + BUGMSG(D_DURING,"in arcnet_interrupt\n"); if (dev==NULL) { @@ -1915,8 +1940,8 @@ outb(0,INTMASK); INTERRUPT = 1; - BUGMSG(D_DURING,"in net_interrupt (status=%Xh)\n",inb(STATUS)); - + BUGMSG(D_DURING,"in arcnet_inthandler (status=%Xh)\n",inb(STATUS)); + #if 1 /* Whatever you do, don't set this to 0. */ do { @@ -2212,6 +2237,7 @@ case ARC_P_ARP: case ARC_P_RARP: case ARC_P_IPX: + case ARC_P_NOVELL_EC: arcnetA_rx(lp->adev,arcsoft,length,saddr,daddr); break; case ARC_P_ETHER: @@ -2221,9 +2247,10 @@ case ARC_P_ARP_RFC1051: arcnetS_rx(lp->sdev,arcsoft,length,saddr,daddr); break; + case ARC_P_LANSOFT: /* don't understand. fall through. */ default: - printk("%6s: received unknown protocol %d (%Xh)\n", - dev->name,arcsoft[0],arcsoft[0]); + printk("%6s: received unknown protocol %d (%Xh) from station %d.\n", + dev->name,arcsoft[0],arcsoft[0],saddr); lp->stats.rx_errors++; lp->stats.rx_crc_errors++; break; @@ -2683,6 +2710,7 @@ return &lp->stats; } +#if 0 /* Set or clear the multicast filter for this adaptor. * num_addrs == -1 Promiscuous mode, receive all packets * num_addrs == 0 Normal mode, clear multicast list @@ -2692,7 +2720,7 @@ static void set_multicast_list(struct device *dev) { -#if 0 /* no promiscuous mode at all on most (all?) ARCnet models */ +#if 0 /* no promiscuous mode at all on most ARCnet models */ struct arcnet_local *lp=(struct arcnet_local *)(dev->priv); short ioaddr = dev->base_addr; @@ -2702,6 +2730,7 @@ outw(99, ioaddr); /* Disable promiscuous mode, use normal mode */ #endif } +#endif /* Create the ARCnet ClientData header for an arbitrary protocol layer * @@ -2962,9 +2991,10 @@ case ARC_P_IP: return htons(ETH_P_IP); case ARC_P_ARP: return htons(ETH_P_ARP); case ARC_P_RARP: return htons(ETH_P_RARP); - case ARC_P_IPX: return htons(ETH_P_802_3); - case ARC_P_ATALK: return htons(ETH_P_ATALK); /* untested appletalk */ - case ARC_P_LANSOFT: /* don't understand. fall through. */ + + case ARC_P_IPX: + case ARC_P_NOVELL_EC: + return htons(ETH_P_802_3); default: BUGMSG(D_EXTRA,"received packet of unknown protocol id %d (%Xh)\n", head->protocol_id,head->protocol_id); @@ -3005,6 +3035,7 @@ { case ARC_P_IP_RFC1051: return htons(ETH_P_IP); case ARC_P_ARP_RFC1051: return htons(ETH_P_ARP); + case ARC_P_ATALK: return htons(ETH_P_ATALK); /* untested appletalk */ default: BUGMSG(D_EXTRA,"received packet of unknown protocol id %d (%Xh)\n", head->protocol_id,head->protocol_id); @@ -3067,7 +3098,14 @@ cleanup_module(void) { if (thiscard.start) arcnet_close(&thiscard); - if (thiscard.irq) free_irq(thiscard.irq); + + if (thiscard.irq) + { + free_irq(thiscard.irq); + /* very important! */ + irq2dev_map[thiscard.irq] = NULL; + } + if (thiscard.base_addr) release_region(thiscard.base_addr, ARCNET_TOTAL_SIZE); unregister_netdev(&thiscard); diff -u --recursive --new-file v1.3.45/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v1.3.45/linux/drivers/net/de4x5.c Sat Nov 25 19:04:41 1995 +++ linux/drivers/net/de4x5.c Mon Dec 11 09:46:54 1995 @@ -435,7 +435,7 @@ /*static void srom_busy(u_int command, u_long address);*/ static void sendto_srom(u_int command, u_long addr); static int getfrom_srom(u_long addr); -static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs); +static void SetMulticastFilter(struct device *dev); static int get_hw_addr(struct device *dev); static void eisa_probe(struct device *dev, u_long iobase); @@ -901,7 +901,7 @@ barrier(); /* Build the setup frame depending on filtering mode */ - SetMulticastFilter(dev, 0, NULL); + SetMulticastFilter(dev); if (lp->chipset != DC21140) { load_packet(dev, lp->setup_frame, HASH_F|TD_SET|SETUP_FRAME_LEN, NULL); @@ -1386,40 +1386,33 @@ static void set_multicast_list(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + u_long iobase = dev->base_addr; - /* First, double check that the adapter is open */ - if (irq2dev_map[dev->irq] != NULL) - { - if (num_addrs >= 0) - { - SetMulticastFilter(dev); - if (lp->setup_f == HASH_PERF) - { - load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET | + /* First, double check that the adapter is open */ + if (irq2dev_map[dev->irq] != NULL) { + if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */ + u32 omr; + omr = inl(DE4X5_OMR); + omr |= OMR_PR; + outl(omr, DE4X5_OMR); + } else { + SetMulticastFilter(dev); + if (lp->setup_f == HASH_PERF) { + load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET | SETUP_FRAME_LEN, NULL); - } - else - { - load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | + } else { + load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | SETUP_FRAME_LEN, NULL); - } + } + + lp->tx_new = (++lp->tx_new) % lp->txRingSize; + outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */ + dev->trans_start = jiffies; + } + } - lp->tx_new = (++lp->tx_new) % lp->txRingSize; - outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */ - dev->trans_start = jiffies; - } - else - { - /* set promiscuous mode */ - u32 omr; - omr = inl(DE4X5_OMR); - omr |= OMR_PR; - outl(omr, DE4X5_OMR); - } - } - return; + return; } /* @@ -1439,76 +1432,49 @@ unsigned char *addrs; omr = inl(DE4X5_OMR); + omr &= ~OMR_PR; pa = build_setup_frame(dev, ALL); /* Build the basic frame */ - if (lp->setup_f == HASH_PERF) - { - if (num_addrs >= HASH_TABLE_LEN || (dev->flags&IFF_ALLMULTI)) - { - /* Pass all multicasts */ - omr |= OMR_PM; - } - else - { - omr &= ~OMR_PM; + if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 14)) { + omr |= OMR_PM; /* Pass all multicasts */ + } else if (lp->setup_f == HASH_PERF) { /* Now update the MCA table */ - for (i=0;idmi_addr; - dmi=dmi->next; - if ((*addrs & 0x01) == 1) - { - /* multicast address? */ - crc = 0xffffffff; /* init CRC for each address */ - for (byte=0;byte>=1) - { - crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0); - } - } - hashcode = crc & HASH_BITS; /* hashcode is 9 LSb of CRC */ - - byte = hashcode >> 3; /* bit[3-8] -> byte in filter */ - bit = 1 << (hashcode & 0x07); /* bit[0-2] -> bit in byte */ - - byte <<= 1; /* calc offset into setup frame */ - if (byte & 0x02) - { - byte -= 1; - } - lp->setup_frame[byte] |= bit; - - } - else - { /* skip this address */ - addrs += ETH_ALEN; - } - } + for (i=0;imc_count;i++) { /* for each address in the list */ + addrs=dmi->dmi_addr; + dmi=dmi->next; + if ((*addrs & 0x01) == 1) { /* multicast address? */ + crc = 0xffffffff; /* init CRC for each address */ + for (byte=0;byte>=1) { + crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0); + } } - else - { /* Perfect filtering */ - omr &= ~OMR_PM; - for (j=0; jmc_count; j++) - { - addrs=dmi->dmi_addr; - dmi=dmi->next; - for (i=0; i> 3; /* bit[3-8] -> byte in filter */ + bit = 1 << (hashcode & 0x07); /* bit[0-2] -> bit in byte */ + + byte <<= 1; /* calc offset into setup frame */ + if (byte & 0x02) { + byte -= 1; } + lp->setup_frame[byte] |= bit; + } + } + } else { /* Perfect filtering */ + for (j=0; jmc_count; j++) { + addrs=dmi->dmi_addr; + dmi=dmi->next; + for (i=0; imc_count == 0) - omr &= ~OMR_PR; - outl(omr, DE4X5_OMR); - - return; + return; } /* @@ -2616,10 +2582,10 @@ if (ioc->len != HASH_TABLE_LEN) { /* MCA changes */ if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN * ioc->len))) { memcpy_fromfs(tmp.addr, ioc->data, ETH_ALEN * ioc->len); - set_multicast_list(dev, ioc->len, tmp.addr); + set_multicast_list(dev); } } else { - set_multicast_list(dev, ioc->len, NULL); + set_multicast_list(dev); } } else { status = -EPERM; @@ -2628,7 +2594,7 @@ break; case DE4X5_CLR_MCA: /* Clear all multicast addresses */ if (suser()) { - set_multicast_list(dev, 0, NULL); + set_multicast_list(dev); } else { status = -EPERM; } diff -u --recursive --new-file v1.3.45/linux/drivers/net/ppp.c linux/drivers/net/ppp.c --- v1.3.45/linux/drivers/net/ppp.c Thu Nov 9 11:23:50 1995 +++ linux/drivers/net/ppp.c Thu Nov 30 15:59:40 1995 @@ -1846,8 +1846,8 @@ if (ppp->flags & SC_DEBUG) printk (KERN_DEBUG "ppp_tty_read: no data " - "(EWOULDBLOCK)\n"); - return -EWOULDBLOCK; + "(EAGAIN)\n"); + return -EAGAIN; } current->timeout = 0; @@ -3359,7 +3359,7 @@ status = register_netdev (dev); if (status == 0) { - printk ("registered device %s\n", dev->name); + printk (KERN_INFO "registered device %s\n", dev->name); return (ppp); } diff -u --recursive --new-file v1.3.45/linux/drivers/net/slhc.c linux/drivers/net/slhc.c --- v1.3.45/linux/drivers/net/slhc.c Thu Nov 9 11:23:50 1995 +++ linux/drivers/net/slhc.c Mon Dec 11 08:40:14 1995 @@ -131,7 +131,7 @@ kfree((unsigned char *)comp); return NULL; } - memset(comp->tstate, 0, rslots * sizeof(struct cstate)); + memset(comp->tstate, 0, tslots * sizeof(struct cstate)); comp->tslot_limit = tslots - 1; } diff -u --recursive --new-file v1.3.45/linux/drivers/net/tulip.c linux/drivers/net/tulip.c --- v1.3.45/linux/drivers/net/tulip.c Mon Nov 27 12:48:30 1995 +++ linux/drivers/net/tulip.c Thu Nov 30 11:15:53 1995 @@ -684,7 +684,7 @@ /* Log any net taps. */ printk("%s: Promiscuous mode enabled.\n", dev->name); } - else if (dev->mc_count > 15 || (dev->mc_flags&IFF_ALLMULTI)) + else if (dev->mc_count > 15 || (dev->flags&IFF_ALLMULTI)) { /* Too many to filter perfectly -- accept all multicasts. */ outl(csr6 | 0x0080, ioaddr + CSR6); @@ -727,11 +727,12 @@ set_mac_address(struct device *dev, void *addr) { int i; + struct sockaddr *sa=(struct sockaddr *)addr; if (dev->start) return -EBUSY; printk("%s: Setting MAC address to ", dev->name); for (i = 0; i < 6; i++) - printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]); + printk(" %2.2x", dev->dev_addr[i] = sa->sa_data[i]); printk(".\n"); return 0; } diff -u --recursive --new-file v1.3.45/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v1.3.45/linux/drivers/pci/pci.c Sat Nov 25 19:04:47 1995 +++ linux/drivers/pci/pci.c Mon Dec 11 07:27:14 1995 @@ -71,6 +71,7 @@ DEVICE( CIRRUS, CIRRUS_5434_8, "GD 5434"), DEVICE( CIRRUS, CIRRUS_6729, "CL 6729"), DEVICE( CIRRUS, CIRRUS_7542, "CL 7542"), + DEVICE( CIRRUS, CIRRUS_7543, "CL 7543"), DEVICE( AMD, AMD_LANCE, "79C970"), DEVICE( AMD, AMD_SCSI, "53C974"), DEVICE( TRIDENT, TRIDENT_9420, "TG 9420"), @@ -141,7 +142,8 @@ DEVICE( ALLIANCE, ALLIANCE_PROVIDEO, "Provideo"), DEVICE( MUTECH, MUTECH_MV1000, "MV-1000"), DEVICE( ZEITNET, ZEITNET_1221, "1221"), - DEVICE( HAL, HAL_RIO, "RIO host"), + DEVICE( SPECIALIX, SPECIALIX_XIO, "XIO/SIO host"), + DEVICE( SPECIALIX, SPECIALIX_RIO, "RIO host"), DEVICE( CYCLADES, CYCLADES_Y, "Cyclome-Y"), DEVICE( SYMPHONY, SYMPHONY_101, "82C101"), DEVICE( TEKRAM, TEKRAM_DC290, "DC-290"), @@ -422,7 +424,7 @@ case PCI_VENDOR_ID_ALLIANCE: return "Alliance"; case PCI_VENDOR_ID_MUTECH: return "Mutech"; case PCI_VENDOR_ID_ZEITNET: return "ZeitNet"; - case PCI_VENDOR_ID_HAL: return "HAL"; + case PCI_VENDOR_ID_SPECIALIX: return "Specialix"; case PCI_VENDOR_ID_CYCLADES: return "Cyclades"; case PCI_VENDOR_ID_SYMPHONY: return "Symphony"; case PCI_VENDOR_ID_TEKRAM: return "Tekram"; @@ -724,7 +726,7 @@ dev->device = (l >> 16) & 0xffff; /* - * Check to see if we now about this device and report + * Check to see if we know about this device and report * a message at boot time. This is the only way to * learn about new hardware... */ diff -u --recursive --new-file v1.3.45/linux/drivers/scsi/eata_dma.c linux/drivers/scsi/eata_dma.c --- v1.3.45/linux/drivers/scsi/eata_dma.c Wed Nov 8 07:11:34 1995 +++ linux/drivers/scsi/eata_dma.c Mon Dec 11 07:27:14 1995 @@ -48,13 +48,12 @@ * 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/03 OS: Linux 1.3.37 * + * last change: 95/11/29 OS: Linux 1.3.45 * ************************************************************/ /* Look in eata_dma.h for configuration and revision information */ #include - #include #include #include @@ -98,7 +97,7 @@ static struct eata_sp *status = 0; /* Statuspacket array */ static void *dma_scratch = 0; -static u32 fake_int_base; +static struct eata_register *fake_int_base; static int fake_int_result; static int fake_int_happened; @@ -117,9 +116,9 @@ void eata_fake_int_handler(s32 irq, struct pt_regs * regs) { - fake_int_result = inb(fake_int_base + HA_RSTATUS); + fake_int_result = inb((ulong)fake_int_base + HA_RSTATUS); fake_int_happened = TRUE; - DBG(DBG_INTR3, printk("eata_fake_int_handler called irq%d base %#x" + DBG(DBG_INTR3, printk("eata_fake_int_handler called irq%d base %p" " res %#x\n", irq, fake_int_base, fake_int_result)); return; } @@ -166,141 +165,141 @@ save_flags(flags); cli(); - for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->prev) { + for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) { if (sh->irq != irq) continue; - if (!(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ)) - continue; - - int_counter++; - - sp=&SD(sh)->sp; - - if((cp = sp->ccb) == NULL) { - eata_stat = inb(base + HA_RSTATUS); - printk("eata_dma: Board: %x Spurious IRQ %lx " - "received. CCB pointer not set.\n", base, (long)cp); - restore_flags(flags); - return; - } - cmd = cp->cmd; - base = (uint) cmd->host->base; - - hba_stat = sp->hba_stat; - - scsi_stat = (sp->scsi_stat >> 1) & 0x1f; - - if (sp->EOC == FALSE) { - eata_stat = inb(base + HA_RSTATUS); - printk("eata_dma: int_handler, board: %x cmd %lx returned " - "unfinished.\nEATA: %x HBA: %x SCSI: %x spadr %lx spadrirq " - "%lx, irq%d\n", base, (long)cp, eata_stat, hba_stat, - scsi_stat,(long)&status, (long)&status[irq], irq); - DBG(DBG_DELAY, DEL2(800)); - restore_flags(flags); - return; - } - - if (cp->status == LOCKED) { - cp->status = FREE; - eata_stat = inb(base + HA_RSTATUS); - printk("eata_dma: int_handler, freeing locked queueslot\n"); - DBG(DBG_INTR && DBG_DELAY, DEL2(800)); - restore_flags(flags); - return; - } - eata_stat = inb(base + HA_RSTATUS); - DBG(DBG_INTR, printk("IRQ %d received, base %#.4x, pid %ld, target: " - "%x, lun: %x, ea_s: %#.2x, hba_s: %#.2x \n", - irq, base, cmd->pid, cmd->target, cmd->lun, - eata_stat, hba_stat)); - - switch (hba_stat) { - case HA_NO_ERROR: /* NO Error */ - if (scsi_stat == CONDITION_GOOD - && cmd->device->type == TYPE_DISK - && (HD(cmd)->t_state[cp->cp_channel][cp->cp_id] == RESET)) - result = DID_BUS_BUSY << 16; - else if (scsi_stat == GOOD) { - HD(cmd)->t_state[cp->cp_channel][cp->cp_id] = OK; - if(HD(cmd)->do_latency == TRUE && cp->timestamp) { - uint time; - time = jiffies - cp->timestamp; - if((cp->rw_latency) == TRUE) { /* was WRITE */ - if(HD(cmd)->writes_lat[cp->sizeindex][1] > time) - HD(cmd)->writes_lat[cp->sizeindex][1] = time; - if(HD(cmd)->writes_lat[cp->sizeindex][2] < time) - HD(cmd)->writes_lat[cp->sizeindex][2] = time; - HD(cmd)->writes_lat[cp->sizeindex][3] += time; - HD(cmd)->writes_lat[cp->sizeindex][0]++; - } else { - if(HD(cmd)->reads_lat[cp->sizeindex][1] > time) - HD(cmd)->reads_lat[cp->sizeindex][1] = time; - if(HD(cmd)->reads_lat[cp->sizeindex][2] < time) - HD(cmd)->reads_lat[cp->sizeindex][2] = time; - HD(cmd)->reads_lat[cp->sizeindex][3] += time; - HD(cmd)->reads_lat[cp->sizeindex][0]++; + while(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ) { + + int_counter++; + + sp = &SD(sh)->sp; + cp = sp->ccb; + + if(cp == NULL) { + eata_stat = inb((uint)sh->base + HA_RSTATUS); + printk("eata_dma: int_handler, Spurious IRQ %d " + "received. CCB pointer not set.\n", irq); + break; + } + + cmd = cp->cmd; + base = (uint) cmd->host->base; + hba_stat = sp->hba_stat; + + scsi_stat = (sp->scsi_stat >> 1) & 0x1f; + + if (sp->EOC == FALSE) { + eata_stat = inb(base + HA_RSTATUS); + printk("eata_dma: int_handler, board: %x cmd %lx returned " + "unfinished.\nEATA: %x HBA: %x SCSI: %x spadr %lx " + "spadrirq %lx, irq%d\n", base, (long)cp, eata_stat, + hba_stat, scsi_stat,(long)&status, (long)&status[irq], + irq); + DBG(DBG_DELAY, DEL2(800)); + break; + } + + if (cp->status == LOCKED) { + cp->status = FREE; + eata_stat = inb(base + HA_RSTATUS); + printk("eata_dma: int_handler, freeing locked queueslot\n"); + DBG(DBG_INTR && DBG_DELAY, DEL2(800)); + break; + } + + eata_stat = inb(base + HA_RSTATUS); + DBG(DBG_INTR, printk("IRQ %d received, base %#.4x, pid %ld, " + "target: %x, lun: %x, ea_s: %#.2x, hba_s: " + "%#.2x \n", irq, base, cmd->pid, cmd->target, + cmd->lun, eata_stat, hba_stat)); + + switch (hba_stat) { + case HA_NO_ERROR: /* NO Error */ + if (scsi_stat == CONDITION_GOOD + && cmd->device->type == TYPE_DISK + && (HD(cmd)->t_state[cp->cp_channel][cp->cp_id] == RESET)) + result = DID_BUS_BUSY << 16; + else if (scsi_stat == GOOD) { + HD(cmd)->t_state[cp->cp_channel][cp->cp_id] = OK; + if(HD(cmd)->do_latency == TRUE && cp->timestamp) { + uint time; + time = jiffies - cp->timestamp; + if((cp->rw_latency) == TRUE) { /* was WRITE */ + if(HD(cmd)->writes_lat[cp->sizeindex][1] > time) + HD(cmd)->writes_lat[cp->sizeindex][1] = time; + if(HD(cmd)->writes_lat[cp->sizeindex][2] < time) + HD(cmd)->writes_lat[cp->sizeindex][2] = time; + HD(cmd)->writes_lat[cp->sizeindex][3] += time; + HD(cmd)->writes_lat[cp->sizeindex][0]++; + } else { + if(HD(cmd)->reads_lat[cp->sizeindex][1] > time) + HD(cmd)->reads_lat[cp->sizeindex][1] = time; + if(HD(cmd)->reads_lat[cp->sizeindex][2] < time) + HD(cmd)->reads_lat[cp->sizeindex][2] = time; + HD(cmd)->reads_lat[cp->sizeindex][3] += time; + HD(cmd)->reads_lat[cp->sizeindex][0]++; + } } } - } - else if (scsi_stat == CHECK_CONDITION - && cmd->device->type == TYPE_DISK - && (cmd->sense_buffer[2] & 0xf) == RECOVERED_ERROR) - result = DID_BUS_BUSY << 16; - else - result = DID_OK << 16; - HD(cmd)->t_timeout[cp->cp_channel][cp->cp_id] = OK; - break; - case HA_ERR_SEL_TO: /* Selection Timeout */ - result = DID_BAD_TARGET << 16; - break; - case HA_ERR_CMD_TO: /* Command Timeout */ - if (HD(cmd)->t_timeout[cp->cp_channel][cp->cp_id] > 1) + else if (scsi_stat == CHECK_CONDITION + && cmd->device->type == TYPE_DISK + && (cmd->sense_buffer[2] & 0xf) == RECOVERED_ERROR) + result = DID_BUS_BUSY << 16; + else + result = DID_OK << 16; + HD(cmd)->t_timeout[cp->cp_channel][cp->cp_id] = OK; + break; + case HA_ERR_SEL_TO: /* Selection Timeout */ + result = DID_BAD_TARGET << 16; + break; + case HA_ERR_CMD_TO: /* Command Timeout */ + if (HD(cmd)->t_timeout[cp->cp_channel][cp->cp_id] > 1) + result = DID_ERROR << 16; + else { + result = DID_TIME_OUT << 16; + HD(cmd)->t_timeout[cp->cp_channel][cp->cp_id]++; + } + break; + case HA_ERR_RESET: /* SCSI Bus Reset Received */ + case HA_INIT_POWERUP: /* Initial Controller Power-up */ + if (cmd->device->type != TYPE_TAPE) + result = DID_BUS_BUSY << 16; + else + result = DID_ERROR << 16; + + for (i = 0; i < MAXTARGET; i++) + HD(cmd)->t_state[cp->cp_channel][i] = RESET; + break; + case HA_UNX_BUSPHASE: /* Unexpected Bus Phase */ + case HA_UNX_BUS_FREE: /* Unexpected Bus Free */ + case HA_BUS_PARITY: /* Bus Parity Error */ + case HA_SCSI_HUNG: /* SCSI Hung */ + case HA_UNX_MSGRJCT: /* Unexpected Message Reject */ + case HA_RESET_STUCK: /* SCSI Bus Reset Stuck */ + case HA_RSENSE_FAIL: /* Auto Request-Sense Failed */ + case HA_PARITY_ERR: /* Controller Ram Parity */ + default: result = DID_ERROR << 16; - else { - result = DID_TIME_OUT << 16; - HD(cmd)->t_timeout[cp->cp_channel][cp->cp_id]++; + break; } - break; - case HA_ERR_RESET: /* SCSI Bus Reset Received */ - case HA_INIT_POWERUP: /* Initial Controller Power-up */ - if (cmd->device->type != TYPE_TAPE) - result = DID_BUS_BUSY << 16; - else - result = DID_ERROR << 16; + cmd->result = result | (scsi_stat << 1); - for (i = 0; i < MAXTARGET; i++) - HD(cmd)->t_state[cp->cp_channel][i] = RESET; - break; - case HA_UNX_BUSPHASE: /* Unexpected Bus Phase */ - case HA_UNX_BUS_FREE: /* Unexpected Bus Free */ - case HA_BUS_PARITY: /* Bus Parity Error */ - case HA_SCSI_HUNG: /* SCSI Hung */ - case HA_UNX_MSGRJCT: /* Unexpected Message Reject */ - case HA_RESET_STUCK: /* SCSI Bus Reset Stuck */ - case HA_RSENSE_FAIL: /* Auto Request-Sense Failed */ - case HA_PARITY_ERR: /* Controller Ram Parity */ - default: - result = DID_ERROR << 16; - break; - } - cmd->result = result | (scsi_stat << 1); - #if DBG_INTR2 - if (scsi_stat || result || hba_stat || eata_stat != 0x50 - || cmd->scsi_done == NULL || cmd->device->id == 7) - printk("HBA: %d, channel %d, id: %d, lun %d, pid %ld:\n" - "eata_stat %#x, hba_stat %#.2x, scsi_stat %#.2x, " - "sense_key: %#x, result: %#.8x\n", - x, cmd->device->channel, cmd->device->id, cmd->device->lun, - cmd->pid, eata_stat, hba_stat, scsi_stat, - cmd->sense_buffer[2] & 0xf, cmd->result); - DBG(DBG_INTR&&DBG_DELAY,DEL2(800)); + if (scsi_stat || result || hba_stat || eata_stat != 0x50 + || cmd->scsi_done == NULL || cmd->device->id == 7) + printk("HBA: %d, channel %d, id: %d, lun %d, pid %ld:\n" + "eata_stat %#x, hba_stat %#.2x, scsi_stat %#.2x, " + "sense_key: %#x, result: %#.8x\n", x, + cmd->device->channel, cmd->device->id, cmd->device->lun, + cmd->pid, eata_stat, hba_stat, scsi_stat, + cmd->sense_buffer[2] & 0xf, cmd->result); + DBG(DBG_INTR&&DBG_DELAY,DEL2(800)); #endif - - cp->status = FREE; /* now we can release the slot */ - cmd->scsi_done(cmd); + + cp->status = FREE; /* now we can release the slot */ + cmd->scsi_done(cmd); + } } restore_flags(flags); @@ -471,7 +470,7 @@ if (cmd->use_sg) { cp->scatter = TRUE; /* SG mode */ if (cp->sg_list == NULL) { - cp->sg_list = kmalloc(SG_SIZE_BIG*sizeof(struct eata_sg_list), + cp->sg_list = kmalloc(sh->sg_tablesize * sizeof(struct eata_sg_list), GFP_ATOMIC | GFP_DMA); } if (cp->sg_list == NULL) @@ -529,8 +528,8 @@ int eata_abort(Scsi_Cmnd * cmd) { - ulong flags; ulong loop = R_LIMIT; + ulong flags; save_flags(flags); cli(); @@ -539,24 +538,14 @@ " reason %x\n", cmd->pid, cmd->target, cmd->lun, cmd->abort_reason)); DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); - - - while (inb((u32)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY) + + while (inb((u32)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY) { if (--loop == 0) { printk("eata_dma: abort, timeout error.\n"); restore_flags(flags); DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); return (SCSI_ABORT_ERROR); } - if (CD(cmd)->status == USED) { - DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_BUSY\n")); - restore_flags(flags); - return (SCSI_ABORT_BUSY); /* SNOOZE */ - } - if (CD(cmd)->status == FREE) { - DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_NOT_RUNNING\n")); - restore_flags(flags); - return (SCSI_ABORT_NOT_RUNNING); } if (CD(cmd)->status == RESET) { restore_flags(flags); @@ -570,6 +559,16 @@ DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); return (SCSI_ABORT_NOT_RUNNING); } + if (CD(cmd)->status == USED) { + DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_BUSY\n")); + restore_flags(flags); + return (SCSI_ABORT_BUSY); /* SNOOZE */ + } + if (CD(cmd)->status == FREE) { + DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_NOT_RUNNING\n")); + restore_flags(flags); + return (SCSI_ABORT_NOT_RUNNING); + } restore_flags(flags); panic("eata_dma: abort: invalid slot status\n"); } @@ -728,7 +727,7 @@ cp->cp_cdb[4] = 56; cp->cp_cdb[5] = 0; - fake_int_base = base; + fake_int_base = (struct eata_register *) base; fake_int_result = FALSE; fake_int_happened = FALSE; @@ -828,7 +827,6 @@ void print_config(struct get_conf *gc) { - printk("Please check values: (read config data)\n"); printk("LEN: %d ver:%d OCS:%d TAR:%d TRNXFR:%d MORES:%d DMAS:%d\n", (u32) ntohl(gc->len), gc->version, gc->OCS_enabled, gc->TAR_support, gc->TRNXFR, gc->MORE_support, @@ -1075,7 +1073,7 @@ "This might be a PM2012 with a defective Firmware\n"); } } - + if (gc->SECOND) hd->primary = FALSE; else @@ -1193,7 +1191,7 @@ pci_index, &pci_bus, &pci_device_fn)) break; DBG(DBG_PROBE && DBG_PCI, - printk("eata_dma: HBA at bus %d, device %d," + printk("eata_dma: find_PCI, HBA at bus %d, device %d," " function %d, index %d\n", (s32)pci_bus, (s32)((pci_device_fn & 0xf8) >> 3), (s32)(pci_device_fn & 7), pci_index)); @@ -1206,17 +1204,17 @@ (u16 *) & com_adr))) { if (!((com_adr & PCI_COMMAND_IO) && (com_adr & PCI_COMMAND_MASTER))) { - printk("eata_dma: HBA has IO or BUSMASTER mode disabled\n"); + printk("eata_dma: find_PCI, HBA has IO or BUSMASTER mode disabled\n"); continue; } } else - printk("eata_dma: error %x while reading " + printk("eata_dma: find_PCI, error %x while reading " "PCI_COMMAND\n", error); } else - printk("eata_dma: DEVICECLASSID %x didn't match\n", + printk("eata_dma: find_PCI, DEVICECLASSID %x didn't match\n", rev_device); } else { - printk("eata_dma: error %x while reading PCI_CLASS_BASE\n", + printk("eata_dma: find_PCI, error %x while reading PCI_CLASS_BASE\n", error); continue; } diff -u --recursive --new-file v1.3.45/linux/drivers/scsi/eata_dma.h linux/drivers/scsi/eata_dma.h --- v1.3.45/linux/drivers/scsi/eata_dma.h Mon Sep 25 12:26:22 1995 +++ linux/drivers/scsi/eata_dma.h Mon Dec 11 07:27:14 1995 @@ -16,7 +16,7 @@ #define VER_MAJOR 2 #define VER_MINOR 5 -#define VER_SUB "8" +#define VER_SUB "8a" /************************************************************************ diff -u --recursive --new-file v1.3.45/linux/drivers/scsi/eata_generic.h linux/drivers/scsi/eata_generic.h --- v1.3.45/linux/drivers/scsi/eata_generic.h Wed Nov 8 07:11:34 1995 +++ linux/drivers/scsi/eata_generic.h Mon Dec 11 07:27:14 1995 @@ -3,7 +3,7 @@ * Linux EATA SCSI drivers * * (c) 1993,94,95 Michael Neuffer * ********************************************************* -* last change: 95/06/20 * +* last change: 95/11/07 * ********************************************************/ @@ -64,7 +64,7 @@ #define MAX_PCI_BUS 16 /* Maximum # Of Busses Allowed */ #define SG_SIZE 64 -#define SG_SIZE_BIG 509 /* max. 509 */ +#define SG_SIZE_BIG 509 /* max. 509 elements, one 4k page */ #define C_P_L_DIV 2 /* 1 <= C_P_L_DIV <= 8 * You can use this parameter to fine-tune diff -u --recursive --new-file v1.3.45/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c --- v1.3.45/linux/drivers/scsi/hosts.c Fri Nov 17 08:42:27 1995 +++ linux/drivers/scsi/hosts.c Mon Dec 11 07:27:13 1995 @@ -158,6 +158,10 @@ static Scsi_Host_Template builtin_scsi_hosts[] = { +/* BusLogic must come before aha1542.c */ +#ifdef CONFIG_SCSI_BUSLOGIC + BUSLOGIC, +#endif #ifdef CONFIG_SCSI_U14_34F ULTRASTOR_14_34F, #endif @@ -166,10 +170,6 @@ #endif #ifdef CONFIG_SCSI_AHA152X AHA152X, -#endif -/* BusLogic must come before aha1542.c */ -#ifdef CONFIG_SCSI_BUSLOGIC - BUSLOGIC, #endif #ifdef CONFIG_SCSI_AHA1542 AHA1542, diff -u --recursive --new-file v1.3.45/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v1.3.45/linux/drivers/scsi/scsi.c Tue Nov 21 13:22:10 1995 +++ linux/drivers/scsi/scsi.c Mon Dec 11 10:52:52 1995 @@ -62,6 +62,10 @@ static int update_timeout (Scsi_Cmnd *, int); static void print_inquiry(unsigned char *data); static void scsi_times_out (Scsi_Cmnd * SCpnt, int pid); +static int scan_scsis_single (int channel,int dev,int lun,int * max_scsi_dev , + Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt, + struct Scsi_Host *shpnt, char * scsi_result); + static unsigned char * dma_malloc_freelist = NULL; static int scsi_need_isa_bounce_buffers; @@ -371,392 +375,365 @@ * lun address of all sequential devices to the tape driver, all random * devices to the disk driver. */ -static -void scan_scsis (struct Scsi_Host * shpnt, unchar hardcoded, - unchar hchannel, unchar hid, unchar hlun) -{ - int dev, lun, type, channel; - unsigned char scsi_cmd [12]; - unsigned char scsi_result0 [256]; - unsigned char * scsi_result; - Scsi_Device * SDpnt, *SDtail; - struct Scsi_Device_Template * sdtpnt; - int bflags; - int max_dev_lun = 0; - Scsi_Cmnd *SCpnt; - - ++in_scan_scsis; - lun = 0; - type = -1; - SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd), GFP_ATOMIC|GFP_DMA); - SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), GFP_ATOMIC); - SDtail = scsi_devices; - - if(scsi_devices) while(SDtail->next) SDtail = SDtail->next; - - /* Make sure we have something that is valid for DMA purposes */ - scsi_result = ((!dma_malloc_freelist || !shpnt->unchecked_isa_dma) - ? &scsi_result0[0] : scsi_malloc(512)); - - if(scsi_result == NULL) { - printk("Unable to obtain scsi_result buffer\n"); - goto leave; - } - - shpnt->host_queue = SCpnt; /* We need this so that commands can time out */ +static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded, + unchar hchannel, unchar hid, unchar hlun) +{ + int dev, lun, channel; + unsigned char scsi_result0[256]; + unsigned char *scsi_result; + Scsi_Device *SDpnt; + int max_dev_lun; + Scsi_Cmnd *SCpnt; - if(hardcoded == 1) { - channel = hchannel; - dev = hid; - lun = hlun; - goto crude; /* Anyone remember good ol' BASIC ? :-) */ - } + in_scan_scsis++; + SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), GFP_ATOMIC | GFP_DMA); + SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC); + + /* Make sure we have something that is valid for DMA purposes */ + scsi_result = ((!dma_malloc_freelist || !shpnt->unchecked_isa_dma) + ? &scsi_result0[0] : scsi_malloc (512)); + + if (scsi_result == NULL) { + printk ("Unable to obtain scsi_result buffer\n"); + goto leave; + } + + shpnt->host_queue = SCpnt; /* We need this so that commands can time out */ + + if (hardcoded == 1) { + channel = hchannel; + if(channel > shpnt->max_channel) goto leave; + dev = hid; + if(dev >= shpnt->max_id) goto leave; + lun = hlun; + if(lun >= shpnt->max_lun) goto leave; + scan_scsis_single (channel, dev, lun, &max_dev_lun, + &SDpnt, SCpnt, shpnt, scsi_result); + } + else { + for (channel = 0; channel <= shpnt->max_channel; channel++) { + for (dev = 0; dev < shpnt->max_id; ++dev) { + if (shpnt->this_id != dev) { + /* + * We need the for so our continue, etc. work fine. We put this in + * a variable so that we can override it during the scan if we + * detect a device *KNOWN* to have multiple logical units. + */ + max_dev_lun = (max_scsi_luns < shpnt->max_lun ? + max_scsi_luns : shpnt->max_lun); + + for (lun = 0; lun < max_dev_lun; ++lun) { + + if (!scan_scsis_single (channel, dev, lun, &max_dev_lun, + &SDpnt, SCpnt, shpnt, scsi_result)) + break; /* break means don't probe for luns!=0 */ + } /* for lun ends */ + } /* if this_id != id ends */ + } /* for dev ends */ + } /* for channel ends */ + +leave: + shpnt->host_queue = NULL; /* No longer needed here */ + + /* Last device block does not exist. Free memory. */ + if (SDpnt != NULL) + scsi_init_free ((char *) SDpnt, sizeof (Scsi_Device)); - for (channel = 0; channel <= shpnt->max_channel; channel++) - { - for (dev = 0; dev < shpnt->max_id; ++dev) { - if (shpnt->this_id != dev) { - - /* - * We need the for so our continue, etc. work fine. - * We put this in a variable so that we can override - * it during the scan if we detect a device *KNOWN* - * to have multiple logical units. - */ - max_dev_lun = (max_scsi_luns < shpnt->max_lun ? - max_scsi_luns : shpnt->max_lun); + if (SCpnt != NULL) + scsi_init_free ((char *) SCpnt, sizeof (Scsi_Cmnd)); - for (lun = 0; lun < max_dev_lun; ++lun) - { - crude: - memset(SDpnt, 0, sizeof(Scsi_Device)); - SDpnt->host = shpnt; - SDpnt->id = dev; - SDpnt->lun = lun; - SDpnt->channel = channel; + /* If we allocated a buffer so we could do DMA, free it now */ + if (scsi_result != &scsi_result0[0] && scsi_result != NULL) + scsi_free (scsi_result, 512); - /* Some low level driver could use device->type (DB) */ - SDpnt->type = -1; - /* - * Assume that the device will have handshaking problems, - * and then fix this field later if it turns out it doesn't - */ - SDpnt->borken = 1; - SDpnt->was_reset = 0; - SDpnt->expecting_cc_ua = 0; - - scsi_cmd[0] = TEST_UNIT_READY; - scsi_cmd[1] = lun << 5; - scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0; - - memset(SCpnt, 0, sizeof(Scsi_Cmnd)); - SCpnt->host = SDpnt->host; - SCpnt->device = SDpnt; - SCpnt->target = SDpnt->id; - SCpnt->lun = SDpnt->lun; - SCpnt->channel = SDpnt->channel; + in_scan_scsis--; + } +} - { - /* - * Do the actual command, and wait for it to finish - */ - struct semaphore sem = MUTEX_LOCKED; - SCpnt->request.sem = &sem; - SCpnt->request.rq_status = RQ_SCSI_BUSY; - scsi_do_cmd (SCpnt, (void *) scsi_cmd, - (void *) scsi_result, - 256, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5); - down(&sem); - } +/* + * The worker for scan_scsis. + * Returning 0 means Please don't ask further for lun!=0, 1 means OK go on. + * Global variables used : scsi_devices(linked list), the_result + */ +int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun, + Scsi_Device **SDpnt2, Scsi_Cmnd * SCpnt, struct Scsi_Host * shpnt, + char *scsi_result) +{ + unsigned char scsi_cmd[12]; + struct Scsi_Device_Template *sdtpnt; + Scsi_Device * SDtail, *SDpnt=*SDpnt2; + int bflags, type=-1; + + SDtail = scsi_devices; + if (scsi_devices) + while (SDtail->next) + SDtail = SDtail->next; + + memset (SDpnt, 0, sizeof (Scsi_Device)); + SDpnt->host = shpnt; + SDpnt->id = dev; + SDpnt->lun = lun; + SDpnt->channel = channel; + + /* Some low level driver could use device->type (DB) */ + SDpnt->type = -1; + + /* + * Assume that the device will have handshaking problems, and then fix this + * field later if it turns out it doesn't + */ + SDpnt->borken = 1; + SDpnt->was_reset = 0; + SDpnt->expecting_cc_ua = 0; + + scsi_cmd[0] = TEST_UNIT_READY; + scsi_cmd[1] = lun << 5; + scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0; + + memset (SCpnt, 0, sizeof (Scsi_Cmnd)); + SCpnt->host = SDpnt->host; + SCpnt->device = SDpnt; + SCpnt->target = SDpnt->id; + SCpnt->lun = SDpnt->lun; + SCpnt->channel = SDpnt->channel; + { + struct semaphore sem = MUTEX_LOCKED; + SCpnt->request.sem = &sem; + SCpnt->request.rq_status = RQ_SCSI_BUSY; + scsi_do_cmd (SCpnt, (void *) scsi_cmd, + (void *) scsi_result, + 256, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5); + down (&sem); + } #if defined(DEBUG) || defined(DEBUG_INIT) - printk("scsi: scan SCSIS id %d lun %d\n", dev, lun); - printk("scsi: return code %08x\n", SCpnt->result); + printk ("scsi: scan_scsis_single id %d lun %d. Return code %d\n", + dev, lun, SCpnt->result); #endif - if(SCpnt->result) { - if (((driver_byte(SCpnt->result) & DRIVER_SENSE) || - (status_byte(SCpnt->result) & CHECK_CONDITION)) && - ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) { - if(((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) && - ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION)) - continue; - } - else - break; - } - + if (SCpnt->result) { + if (((driver_byte (SCpnt->result) & DRIVER_SENSE) || + (status_byte (SCpnt->result) & CHECK_CONDITION)) && + ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) { + if (((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) && + ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION)) + return 1; + } + else + return 0; + } + #if defined (DEBUG) || defined(DEBUG_INIT) - printk("scsi: performing INQUIRY\n"); + printk ("scsi: performing INQUIRY\n"); #endif + /* + * Build an INQUIRY command block. + */ + scsi_cmd[0] = INQUIRY; + scsi_cmd[1] = (lun << 5) & 0xe0; + scsi_cmd[2] = 0; + scsi_cmd[3] = 0; + scsi_cmd[4] = 255; + scsi_cmd[5] = 0; + SCpnt->cmd_len = 0; + { + struct semaphore sem = MUTEX_LOCKED; + SCpnt->request.sem = &sem; + SCpnt->request.rq_status = RQ_SCSI_BUSY; + scsi_do_cmd (SCpnt, (void *) scsi_cmd, + (void *) scsi_result, + 256, scan_scsis_done, SCSI_TIMEOUT, 3); + down (&sem); + } - /* - * Build an INQUIRY command block. - */ - scsi_cmd[0] = INQUIRY; - scsi_cmd[1] = (lun << 5) & 0xe0; - scsi_cmd[2] = 0; - scsi_cmd[3] = 0; - scsi_cmd[4] = 255; - scsi_cmd[5] = 0; - - SCpnt->cmd_len = 0; - - { - struct semaphore sem = MUTEX_LOCKED; - SCpnt->request.sem = &sem; - SCpnt->request.rq_status = RQ_SCSI_BUSY; - scsi_do_cmd (SCpnt, (void *) scsi_cmd, - (void *) scsi_result, - 256, scan_scsis_done, SCSI_TIMEOUT, 3); - down(&sem); - } - - the_result = SCpnt->result; - + the_result = SCpnt->result; #if defined(DEBUG) || defined(DEBUG_INIT) - if (!the_result) - printk("scsi: INQUIRY successful\n"); - else - printk("scsi: INQUIRY failed with code %08x\n", the_result); -#endif - - if(the_result) break; - - /* skip other luns on this device */ - - if (!the_result) - { - /* It would seem some TOSHIBA CDROM - * gets things wrong - */ - if (!strncmp(scsi_result+8,"TOSHIBA",7) && - !strncmp(scsi_result+16,"CD-ROM",6) && - scsi_result[0] == TYPE_DISK) { - scsi_result[0] = TYPE_ROM; - scsi_result[1] |= 0x80; /* removable */ - } - - if (!strncmp(scsi_result+8,"NEC",3)) { - if (!strncmp(scsi_result+16,"CD-ROM DRIVE:84 ",16) || - !strncmp(scsi_result+16,"CD-ROM DRIVE:25",15)) - SDpnt->manufacturer = SCSI_MAN_NEC_OLDCDR; - else - SDpnt->manufacturer = SCSI_MAN_NEC; - } else if (!strncmp(scsi_result+8,"TOSHIBA",7)) - SDpnt->manufacturer = SCSI_MAN_TOSHIBA; - else if (!strncmp(scsi_result+8,"SONY",4)) - SDpnt->manufacturer = SCSI_MAN_SONY; - else if (!strncmp(scsi_result+8, "PIONEER", 7)) - SDpnt->manufacturer = SCSI_MAN_PIONEER; - else - SDpnt->manufacturer = SCSI_MAN_UNKNOWN; - - memcpy(SDpnt->vendor, scsi_result+8, 8); - memcpy(SDpnt->model, scsi_result+16, 16); - memcpy(SDpnt->rev, scsi_result+32, 4); - - SDpnt->removable = (0x80 & scsi_result[1]) >> 7; - SDpnt->lockable = SDpnt->removable; - SDpnt->changed = 0; - SDpnt->access_count = 0; - SDpnt->busy = 0; - SDpnt->has_cmdblocks = 0; - /* - * Currently, all sequential devices are assumed to be - * tapes, all random devices disk, with the appropriate - * read only flags set for ROM / WORM treated as RO. - */ - - switch (type = (scsi_result[0] & 0x1f)) - { - case TYPE_TAPE : - case TYPE_DISK : - case TYPE_MOD : - case TYPE_PROCESSOR : - case TYPE_SCANNER : - SDpnt->writeable = 1; - break; - case TYPE_WORM : - case TYPE_ROM : - SDpnt->writeable = 0; - break; - default : -#if 0 -#ifdef DEBUG - printk("scsi: unknown type %d\n", type); - print_inquiry(scsi_result); -#endif - type = -1; + printk ("scsi: INQUIRY %s with code 0x%x\n", + the_result ? "failed" : "successful", the->result); #endif - } - - SDpnt->single_lun = 0; - SDpnt->soft_reset = - (scsi_result[7] & 1) && ((scsi_result[3] &7) == 2); - SDpnt->random = (type == TYPE_TAPE) ? 0 : 1; - SDpnt->type = (type & 0x1f); - - if (type != -1) - { - print_inquiry(scsi_result); - - for(sdtpnt = scsi_devicelist; sdtpnt; - sdtpnt = sdtpnt->next) - if(sdtpnt->detect) SDpnt->attached += - (*sdtpnt->detect)(SDpnt); - - SDpnt->scsi_level = scsi_result[2] & 0x07; - if (SDpnt->scsi_level >= 2 || - (SDpnt->scsi_level == 1 && - (scsi_result[3] & 0x0f) == 1)) - SDpnt->scsi_level++; - /* - * Set the tagged_queue flag for SCSI-II devices - * that purport to support - * tagged queuing in the INQUIRY data. - */ - - SDpnt->tagged_queue = 0; - - if ((SDpnt->scsi_level >= SCSI_2) && - (scsi_result[7] & 2)) { - SDpnt->tagged_supported = 1; - SDpnt->current_tag = 0; - } - - /* - * Accommodate drivers that want to sleep when - * they should be in a polling loop. - */ - - SDpnt->disconnect = 0; - - /* - * Get any flags for this device. - */ - bflags = get_device_flags(scsi_result); - - - /* - * Some revisions of the Texel CD ROM drives have - * handshaking problems when used with the Seagate - * controllers. Before we know what type of device - * we're talking to, we assume it's borken and then - * change it here if it turns out that it isn't - * a TEXEL drive. - */ - if( (bflags & BLIST_BORKEN) == 0 ) - { - SDpnt->borken = 0; - } - - - /* These devices need this "key" to unlock the - * devices so we can use it - */ - if( (bflags & BLIST_KEY) != 0 ) { - printk("Unlocked floptical drive.\n"); - SDpnt->lockable = 0; - scsi_cmd[0] = MODE_SENSE; - scsi_cmd[1] = (lun << 5) & 0xe0; - scsi_cmd[2] = 0x2e; - scsi_cmd[3] = 0; - scsi_cmd[4] = 0x2a; - scsi_cmd[5] = 0; - - SCpnt->cmd_len = 0; - { - struct semaphore sem = MUTEX_LOCKED; - SCpnt->request.rq_status = RQ_SCSI_BUSY; - SCpnt->request.sem = &sem; - scsi_do_cmd (SCpnt, (void *) scsi_cmd, - (void *) scsi_result, 0x2a, - scan_scsis_done, SCSI_TIMEOUT, 3); - down(&sem); - } - } - /* Add this device to the linked list at the end */ - if(SDtail) - SDtail->next = SDpnt; - else - scsi_devices = SDpnt; - SDtail = SDpnt; - - SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), GFP_ATOMIC); - /* Some scsi devices cannot be polled for lun != 0 - * due to firmware bugs - */ - if(bflags & BLIST_NOLUN) break; - - /* - * If we want to only allow I/O to one of the luns - * attached to this device at a time, then we set - * this flag. - */ - if(bflags & BLIST_SINGLELUN) - { - SDpnt->single_lun = 1; - } - - /* - * If this device is known to support multiple - * units, override the other settings, and scan - * all of them. - */ - if(bflags & BLIST_FORCELUN) - { - /* - * We probably want to make this a variable, - * but this will do for now. - */ - max_dev_lun = 8; - } - - /* Old drives like the MAXTOR XT-3280 say vers=0 */ - if ((scsi_result[2] & 0x07) == 0) - break; - /* Some scsi-1 peripherals do not handle lun != 0. - * I am assuming that scsi-2 peripherals do better - */ - if((scsi_result[2] & 0x07) == 1 && - (scsi_result[3] & 0x0f) == 0) break; - } - } /* if result == DID_OK ends */ + if (the_result) + return 0; /* assume no peripheral if any sort of error */ - /* - * This might screw us up with multi-lun devices, but the - * user can scan for them too. - */ - if(hardcoded == 1) - goto leave; - } /* for lun ends */ - } /* if this_id != id ends */ - } /* for dev ends */ - } /* for channel ends */ - - leave: - shpnt->host_queue = NULL; /* No longer needed here */ - - /* Last device block does not exist. Free memory. */ - if(SDpnt != NULL) - scsi_init_free((char *) SDpnt, sizeof(Scsi_Device)); - - if(SCpnt != NULL) - scsi_init_free((char *) SCpnt, sizeof(Scsi_Cmnd)); - - /* If we allocated a buffer so we could do DMA, free it now */ - if (scsi_result != &scsi_result0[0] && scsi_result != NULL) - scsi_free(scsi_result, 512); - - in_scan_scsis = 0; -} /* scan_scsis ends */ + /* + * It would seem some TOSHIBA CDROM gets things wrong + */ + if (!strncmp (scsi_result + 8, "TOSHIBA", 7) && + !strncmp (scsi_result + 16, "CD-ROM", 6) && + scsi_result[0] == TYPE_DISK) { + scsi_result[0] = TYPE_ROM; + scsi_result[1] |= 0x80; /* removable */ + } + + if (!strncmp (scsi_result + 8, "NEC", 3)) { + if (!strncmp (scsi_result + 16, "CD-ROM DRIVE:84 ", 16) || + !strncmp (scsi_result + 16, "CD-ROM DRIVE:25", 15)) + SDpnt->manufacturer = SCSI_MAN_NEC_OLDCDR; + else + SDpnt->manufacturer = SCSI_MAN_NEC; + } + else if (!strncmp (scsi_result + 8, "TOSHIBA", 7)) + SDpnt->manufacturer = SCSI_MAN_TOSHIBA; + else if (!strncmp (scsi_result + 8, "SONY", 4)) + SDpnt->manufacturer = SCSI_MAN_SONY; + else if (!strncmp (scsi_result + 8, "PIONEER", 7)) + SDpnt->manufacturer = SCSI_MAN_PIONEER; + else + SDpnt->manufacturer = SCSI_MAN_UNKNOWN; + + memcpy (SDpnt->vendor, scsi_result + 8, 8); + memcpy (SDpnt->model, scsi_result + 16, 16); + memcpy (SDpnt->rev, scsi_result + 32, 4); + + SDpnt->removable = (0x80 & scsi_result[1]) >> 7; + SDpnt->lockable = SDpnt->removable; + SDpnt->changed = 0; + SDpnt->access_count = 0; + SDpnt->busy = 0; + SDpnt->has_cmdblocks = 0; + /* + * Currently, all sequential devices are assumed to be tapes, all random + * devices disk, with the appropriate read only flags set for ROM / WORM + * treated as RO. + */ + switch (type = (scsi_result[0] & 0x1f)) { + case TYPE_TAPE: + case TYPE_DISK: + case TYPE_MOD: + case TYPE_PROCESSOR: + case TYPE_SCANNER: + SDpnt->writeable = 1; + break; + case TYPE_WORM: + case TYPE_ROM: + SDpnt->writeable = 0; + break; + default: + printk ("scsi: unknown type %d\n", type); + } + + SDpnt->single_lun = 0; + SDpnt->soft_reset = + (scsi_result[7] & 1) && ((scsi_result[3] & 7) == 2); + SDpnt->random = (type == TYPE_TAPE) ? 0 : 1; + SDpnt->type = (type & 0x1f); + + print_inquiry (scsi_result); + + for (sdtpnt = scsi_devicelist; sdtpnt; + sdtpnt = sdtpnt->next) + if (sdtpnt->detect) + SDpnt->attached += + (*sdtpnt->detect) (SDpnt); + + SDpnt->scsi_level = scsi_result[2] & 0x07; + if (SDpnt->scsi_level >= 2 || + (SDpnt->scsi_level == 1 && + (scsi_result[3] & 0x0f) == 1)) + SDpnt->scsi_level++; + + /* + * Set the tagged_queue flag for SCSI-II devices that purport to support + * tagged queuing in the INQUIRY data. + */ + SDpnt->tagged_queue = 0; + if ((SDpnt->scsi_level >= SCSI_2) && + (scsi_result[7] & 2)) { + SDpnt->tagged_supported = 1; + SDpnt->current_tag = 0; + } + + /* + * Accommodate drivers that want to sleep when they should be in a polling + * loop. + */ + SDpnt->disconnect = 0; + + /* + * Get any flags for this device. + */ + bflags = get_device_flags (scsi_result); + + /* + * Some revisions of the Texel CD ROM drives have handshaking problems when + * used with the Seagate controllers. Before we know what type of device + * we're talking to, we assume it's borken and then change it here if it + * turns out that it isn't a TEXEL drive. + */ + if ((bflags & BLIST_BORKEN) == 0) + SDpnt->borken = 0; + + /* + * These devices need this "key" to unlock the devices so we can use it + */ + if ((bflags & BLIST_KEY) != 0) { + printk ("Unlocked floptical drive.\n"); + SDpnt->lockable = 0; + scsi_cmd[0] = MODE_SENSE; + scsi_cmd[1] = (lun << 5) & 0xe0; + scsi_cmd[2] = 0x2e; + scsi_cmd[3] = 0; + scsi_cmd[4] = 0x2a; + scsi_cmd[5] = 0; + SCpnt->cmd_len = 0; + { + struct semaphore sem = MUTEX_LOCKED; + SCpnt->request.rq_status = RQ_SCSI_BUSY; + SCpnt->request.sem = &sem; + scsi_do_cmd (SCpnt, (void *) scsi_cmd, + (void *) scsi_result, 0x2a, + scan_scsis_done, SCSI_TIMEOUT, 3); + down (&sem); + } + } + /* Add this device to the linked list at the end */ + if (SDtail) + SDtail->next = SDpnt; + else + scsi_devices = SDpnt; + SDtail = SDpnt; + + SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC); + *SDpnt2=SDpnt; + if (!SDpnt) + printk ("scsi: scan_scsis_single: No memory\n"); + + + /* + * Some scsi devices cannot be polled for lun != 0 due to firmware bugs + */ + if (bflags & BLIST_NOLUN) + return 0; /* break; */ + + /* + * If we want to only allow I/O to one of the luns attached to this device + * at a time, then we set this flag. + */ + if (bflags & BLIST_SINGLELUN) + SDpnt->single_lun = 1; + + /* + * If this device is known to support multiple units, override the other + * settings, and scan all of them. + */ + if (bflags & BLIST_FORCELUN) + *max_dev_lun = 8; + /* + * We assume the device can't handle lun!=0 if: - it reports scsi-0 (ANSI + * SCSI Revision 0) (old drives like MAXTOR XT-3280) or - it reports scsi-1 + * (ANSI SCSI Revision 1) and Response Data Format 0 + */ + if (((scsi_result[2] & 0x07) == 0) + || + ((scsi_result[2] & 0x07) == 1 && + (scsi_result[3] & 0x0f) == 0)) + return 0; + return 1; +} /* * Flag bits for the internal_timeout array */ - #define NORMAL_TIMEOUT 0 #define IN_ABORT 1 #define IN_RESET 2 @@ -1153,8 +1130,8 @@ #ifdef DEBUG_DELAY clock = jiffies + 4 * HZ; while (jiffies < clock); - printk("done(host = %d, result = %04x) : routine at %08x\n", - host->host_no, temp); + printk("done(host = %d, result = %04x) : routine at %p\n", + host->host_no, temp, host->hostt->command); #endif scsi_done(SCpnt); } @@ -2413,7 +2390,7 @@ struct Scsi_Host *HBA_ptr; int parameter[4]; char *p; - int size, len = 0; + int i,size, len = 0; off_t begin = 0; off_t pos = 0; @@ -2458,21 +2435,29 @@ return (len); } + /* + * Usage: echo "scsi singledevice 0 1 2 3" >/proc/scsi/scsi + * with "0 1 2 3" replaced by your "Host Channel Id Lun". + * Consider this feature ALPHA, as you can easily hang your + * scsi system (depending on your low level driver). + */ if(!buffer || length < 25 || strncmp("scsi", buffer, 4)) return(-EINVAL); if(!strncmp("singledevice", buffer + 5, 12)) { p = buffer + 17; - parameter[0] = simple_strtoul(p , &p, 0); - parameter[1] = simple_strtoul(p , &p, 0); - parameter[2] = simple_strtoul(p , &p, 0); - parameter[3] = simple_strtoul(p , &p, 0); - - while(scd && scd->host->host_no != parameter[0] - && scd->channel != parameter[1] - && scd->id != parameter[2] - && scd->lun != parameter[3]) { + for(i=0; i<4; i++) { + p++; + parameter[i] = simple_strtoul(p, &p, 0); + } + printk("scsi singledevice %d %d %d %d\n", parameter[0], parameter[1], + parameter[2], parameter[3]); + + while(scd && (scd->host->host_no != parameter[0] + || scd->channel != parameter[1] + || scd->id != parameter[2] + || scd->lun != parameter[3])) { scd = scd->next; } if(scd) @@ -2484,7 +2469,7 @@ return(-ENXIO); scan_scsis (HBA_ptr, 1, parameter[1], parameter[2], parameter[3]); - return(0); + return(length); } return(-EINVAL); } @@ -3035,7 +3020,7 @@ for(SCpnt=shpnt->host_queue; SCpnt; SCpnt = SCpnt->next) { /* (0) 0:0:0:0 (802 123434 8 8 0) (3 3 2) (%d %d %d) %d %x */ - printk("(%d) %d:%d:%d:%d (%s %ld %ld %ld %ld) (%d %d %x) (%d %d %d) %x %x %x\n", + printk("(%d) %d:%d:%d:%d (%s %ld %ld %ld %d) (%d %d %x) (%d %d %d) %x %x %x\n", i++, SCpnt->host->host_no, SCpnt->channel, SCpnt->target, diff -u --recursive --new-file v1.3.45/linux/drivers/scsi/scsi_syms.c linux/drivers/scsi/scsi_syms.c --- v1.3.45/linux/drivers/scsi/scsi_syms.c Fri Nov 17 08:42:27 1995 +++ linux/drivers/scsi/scsi_syms.c Thu Nov 30 14:04:51 1995 @@ -59,6 +59,7 @@ X(kernel_scsi_ioctl), X(need_isa_buffer), X(request_queueable), + X(in_scan_scsis), #if defined(CONFIG_PROC_FS) X(proc_print_scsidevice), #endif diff -u --recursive --new-file v1.3.45/linux/drivers/scsi/scsicam.c linux/drivers/scsi/scsicam.c --- v1.3.45/linux/drivers/scsi/scsicam.c Sat Nov 11 17:41:33 1995 +++ linux/drivers/scsi/scsicam.c Thu Nov 30 14:04:51 1995 @@ -86,8 +86,8 @@ unsigned int *cyls, unsigned int *hds, unsigned int *secs) { struct partition *p, *largest = NULL; int i, largest_cyl; - int cyl, end_head, end_cyl, end_sector; - unsigned int logical_end, physical_end; + int cyl, ext_cyl, end_head, end_cyl, end_sector; + unsigned int logical_end, physical_end, ext_physical_end; if (*(unsigned short *) (bh->b_data+510) == 0xAA55) { @@ -111,6 +111,7 @@ end_cyl = largest->end_cyl + ((largest->end_sector & 0xc0) << 2); end_head = largest->end_head; end_sector = largest->end_sector & 0x3f; + #ifdef DEBUG printk ("scsicam_bios_param : end at h = %d, c = %d, s = %d\n", end_head, end_cyl, end_sector); @@ -122,12 +123,25 @@ /* This is the actual _sector_ number at the end */ logical_end = largest->start_sect + largest->nr_sects; - if (logical_end == physical_end) { + /* This is for >1023 cylinders */ + ext_cyl= (logical_end-(end_head * end_sector + end_sector)) + /(end_head + 1) / end_sector; + ext_physical_end = ext_cyl * (end_head + 1) * end_sector + + end_head * end_sector + end_sector; + +#ifdef DEBUG + printk("scsicam_bios_param : logical_end=%d physical_end=%d ext_physical_end=%d ext_cyl=%d\n" + ,logical_end,physical_end,ext_physical_end,ext_cyl); +#endif + + if ((logical_end == physical_end) || + (end_cyl==1023 && ext_physical_end==logical_end)) { *secs = end_sector; *hds = end_head + 1; *cyls = capacity / ((end_head + 1) * end_sector); return 0; } + #ifdef DEBUG printk ("scsicam_bios_param : logical (%u) != physical (%u)\n", logical_end, physical_end); diff -u --recursive --new-file v1.3.45/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c --- v1.3.45/linux/drivers/scsi/sg.c Tue Nov 21 13:22:11 1995 +++ linux/drivers/scsi/sg.c Thu Nov 30 16:00:33 1995 @@ -215,7 +215,7 @@ if (filp->f_flags & O_NONBLOCK) { restore_flags(flags); - return -EWOULDBLOCK; + return -EAGAIN; } interruptible_sleep_on(&device->read_wait); if (current->signal & ~current->blocked) @@ -323,7 +323,7 @@ while(device->pending) { if (filp->f_flags & O_NONBLOCK) - return -EWOULDBLOCK; + return -EAGAIN; #ifdef DEBUG printk("sg_write: sleeping on pending request\n"); #endif @@ -392,7 +392,7 @@ wake_up(&device->write_wait); sg_free(device->buff,device->buff_len); device->buff = NULL; - return -EWOULDBLOCK; + return -EAGAIN; } #ifdef DEBUG printk("device allocated\n"); diff -u --recursive --new-file v1.3.45/linux/fs/Makefile linux/fs/Makefile --- v1.3.45/linux/fs/Makefile Wed Sep 13 12:45:31 1995 +++ linux/fs/Makefile Mon Dec 11 06:56:35 1995 @@ -13,7 +13,7 @@ O_OBJS = open.o read_write.o inode.o devices.o file_table.o buffer.o \ super.o block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ ioctl.o readdir.o select.o fifo.o locks.o filesystems.o \ - dcache.o $(BINFMTS) + dcache.o dquot.o $(BINFMTS) MOD_LIST_NAME := FS_MODULES ALL_SUB_DIRS = minix ext ext2 msdos proc isofs nfs xiafs umsdos hpfs sysv smbfs diff -u --recursive --new-file v1.3.45/linux/fs/buffer.c linux/fs/buffer.c --- v1.3.45/linux/fs/buffer.c Mon Nov 27 12:48:31 1995 +++ linux/fs/buffer.c Mon Dec 11 07:58:14 1995 @@ -222,6 +222,7 @@ sync_supers(dev); sync_inodes(dev); sync_buffers(dev, 0); + sync_dquots(dev, -1); } int fsync_dev(kdev_t dev) @@ -229,6 +230,7 @@ sync_buffers(dev, 0); sync_supers(dev); sync_inodes(dev); + sync_dquots(dev, -1); return sync_buffers(dev, 1); } diff -u --recursive --new-file v1.3.45/linux/fs/dquot.c linux/fs/dquot.c --- v1.3.45/linux/fs/dquot.c Thu Jan 1 02:00:00 1970 +++ linux/fs/dquot.c Mon Dec 11 07:58:31 1995 @@ -0,0 +1,1060 @@ +/* + * Implementation of the diskquota system for the LINUX operating + * system. QUOTA is implemented using the BSD systemcall interface as + * the means of communication with the user level. Currently only the + * ext2-filesystem has support for diskquotas. Other filesystems may + * be added in future time. This file contains the generic routines + * called by the different filesystems on allocation of an inode or + * block. These routines take care of the administration needed to + * have a consistent diskquota tracking system. The ideas of both + * user and group quotas are based on the Melbourne quota system as + * used on BSD derivated systems. The internal implementation is + * based on the LINUX inode-subsystem with added complexity of the + * diskquota system. This implementation is not based on any BSD + * kernel sourcecode. + * + * Version: $Id: dquot.c,v 5.6 1995/11/15 20:30:27 mvw Exp mvw $ + * + * Author: Marco van Wieringen + * + * (C) Copyright 1994, 1995 Marco van Wieringen + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define __DQUOT_VERSION__ "dquot_5.6.0" + +static char quotamessage[MAX_QUOTA_MESSAGE]; +static char *quotatypes[] = INITQFNAMES; + +static int nr_dquots = 0, nr_free_dquots = 0; +static struct dquot *hash_table[NR_DQHASH]; +static struct dquot *first_dquot; +static struct dqstats dqstats; + +static struct wait_queue *dquot_wait = (struct wait_queue *)NULL; + +extern void add_dquot_ref(kdev_t dev, short type); +extern void reset_dquot_ptrs(kdev_t dev, short type); + +#ifndef min +#define min(a,b) ((a) < (b)) ? (a) : (b) +#endif + +/* + * Functions for management of the hashlist. + */ +static inline int const hashfn(kdev_t dev, unsigned int id, short type) +{ + return((HASHDEV(dev) ^ id) * (MAXQUOTAS - type)) % NR_DQHASH; +} + +static inline struct dquot **const hash(kdev_t dev, unsigned int id, short type) +{ + return(hash_table + hashfn(dev, id, type)); +} + +static inline int has_quota_enabled(kdev_t dev, short type) +{ + struct vfsmount *vfsmnt; + + return((vfsmnt = lookup_vfsmnt(dev)) != (struct vfsmount *)NULL && + (vfsmnt->mnt_quotas[type] != (struct file *)NULL)); +} + +static void insert_dquot_free(struct dquot *dquot) +{ + dquot->dq_next = first_dquot; + dquot->dq_prev = first_dquot->dq_prev; + dquot->dq_next->dq_prev = dquot; + dquot->dq_prev->dq_next = dquot; + first_dquot = dquot; +} + +static void remove_dquot_free(struct dquot *dquot) +{ + if (first_dquot == dquot) + first_dquot = first_dquot->dq_next; + if (dquot->dq_next) + dquot->dq_next->dq_prev = dquot->dq_prev; + if (dquot->dq_prev) + dquot->dq_prev->dq_next = dquot->dq_next; + dquot->dq_next = dquot->dq_prev = NODQUOT; +} + +static void insert_dquot_hash(struct dquot *dquot) +{ + struct dquot **hash_ent; + + hash_ent = hash(dquot->dq_dev, dquot->dq_id, dquot->dq_type); + dquot->dq_hash_next = *hash_ent; + dquot->dq_hash_prev = NODQUOT; + if (dquot->dq_hash_next) + dquot->dq_hash_next->dq_hash_prev = dquot; + *hash_ent = dquot; +} + +static void remove_dquot_hash(struct dquot *dquot) +{ + struct dquot **hash_ent; + + hash_ent = hash(dquot->dq_dev, dquot->dq_id, dquot->dq_type); + if (*hash_ent == dquot) + *hash_ent = dquot->dq_hash_next; + if (dquot->dq_hash_next) + dquot->dq_hash_next->dq_hash_prev = dquot->dq_hash_prev; + if (dquot->dq_hash_prev) + dquot->dq_hash_prev->dq_hash_next = dquot->dq_hash_next; + dquot->dq_hash_prev = dquot->dq_hash_next = NODQUOT; +} + +static void put_last_free(struct dquot *dquot) +{ + remove_dquot_free(dquot); + dquot->dq_prev = first_dquot->dq_prev; + dquot->dq_prev->dq_next = dquot; + dquot->dq_next = first_dquot; + dquot->dq_next->dq_prev = dquot; +} + +static void grow_dquots(void) +{ + struct dquot *dquot; + int cnt; + + if (!(dquot = (struct dquot*) get_free_page(GFP_KERNEL))) + return; + dqstats.pages_allocated++; + cnt = PAGE_SIZE / sizeof(struct dquot); + nr_dquots += cnt; + nr_free_dquots += cnt; + if (!first_dquot) { + dquot->dq_next = dquot->dq_prev = first_dquot = dquot++; + cnt--; + } + for (; cnt; cnt--) + insert_dquot_free(dquot++); +} + +/* + * Functions for locking and waiting on dquots. + */ +static void __wait_on_dquot(struct dquot *dquot) +{ + struct wait_queue wait = {current, NULL}; + + add_wait_queue(&dquot->dq_wait, &wait); +repeat: + current->state = TASK_UNINTERRUPTIBLE; + if (dquot->dq_flags & DQ_LOCKED) { + dquot->dq_flags |= DQ_WANT; + schedule(); + goto repeat; + } + remove_wait_queue(&dquot->dq_wait, &wait); + current->state = TASK_RUNNING; +} + +static inline void wait_on_dquot(struct dquot *dquot) +{ + if (dquot->dq_flags & DQ_LOCKED) + __wait_on_dquot(dquot); +} + +static inline void lock_dquot(struct dquot *dquot) +{ + wait_on_dquot(dquot); + dquot->dq_flags |= DQ_LOCKED; +} + +static inline void unlock_dquot(struct dquot *dquot) +{ + dquot->dq_flags &= ~DQ_LOCKED; + if (dquot->dq_flags & DQ_WANT) { + dquot->dq_flags &= ~DQ_WANT; + wake_up(&dquot->dq_wait); + } +} +/* + * Note that we don't want to disturb any wait-queues when we discard + * an dquot. + * + * FIXME: As soon as we have a nice solution for the inode problem we + * can also fix this one. I.e. the volatile part. + */ +static void clear_dquot(struct dquot * dquot) +{ + struct wait_queue *wait; + + wait_on_dquot(dquot); + remove_dquot_hash(dquot); + remove_dquot_free(dquot); + wait = ((volatile struct dquot *) dquot)->dq_wait; + if (dquot->dq_count) + nr_free_dquots++; + memset(dquot, 0, sizeof(*dquot)); + ((volatile struct dquot *) dquot)->dq_wait = wait; + insert_dquot_free(dquot); +} + +static void write_dquot(struct dquot *dquot) +{ + short type = dquot->dq_type; + struct file *filp = dquot->dq_mnt->mnt_quotas[type]; + unsigned short fs; + + if (!(dquot->dq_flags & DQ_MOD) || (filp == (struct file *)NULL)) + return; + lock_dquot(dquot); + down(&dquot->dq_mnt->mnt_sem); + if (filp->f_op->lseek) { + if (filp->f_op->lseek(filp->f_inode, filp, + dqoff(dquot->dq_id), 0) != dqoff(dquot->dq_id)) { + up(&dquot->dq_mnt->mnt_sem); + unlock_dquot(dquot); + return; + } + } else + filp->f_pos = dqoff(dquot->dq_id); + fs = get_fs(); + set_fs(KERNEL_DS); + if (filp->f_op->write(filp->f_inode, filp, + (char *)&dquot->dq_dqb, sizeof(struct dqblk)) == sizeof(struct dqblk)) + dquot->dq_flags &= ~DQ_MOD; + up(&dquot->dq_mnt->mnt_sem); + set_fs(fs); + unlock_dquot(dquot); + dqstats.writes++; +} + +static void read_dquot(struct dquot *dquot) +{ + short type = dquot->dq_type; + struct file *filp = dquot->dq_mnt->mnt_quotas[type]; + unsigned short fs; + + if (filp == (struct file *)NULL) + return; + lock_dquot(dquot); + down(&dquot->dq_mnt->mnt_sem); + if (filp->f_op->lseek) { + if (filp->f_op->lseek(filp->f_inode, filp, + dqoff(dquot->dq_id), 0) != dqoff(dquot->dq_id)) { + up(&dquot->dq_mnt->mnt_sem); + unlock_dquot(dquot); + return; + } + } else + filp->f_pos = dqoff(dquot->dq_id); + fs = get_fs(); + set_fs(KERNEL_DS); + filp->f_op->read(filp->f_inode, filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk)); + up(&dquot->dq_mnt->mnt_sem); + set_fs(fs); + if (dquot->dq_bhardlimit == 0 && dquot->dq_bsoftlimit == 0 && + dquot->dq_ihardlimit == 0 && dquot->dq_isoftlimit == 0) + dquot->dq_flags |= DQ_FAKE; + unlock_dquot(dquot); + dqstats.reads++; +} + +int sync_dquots(kdev_t dev, short type) +{ + struct dquot *dquot = first_dquot; + int i; + + dqstats.syncs++; + for (i = 0; i < nr_dquots * 2; i++, dquot = dquot->dq_next) { + if (dev == NODEV || dquot->dq_count == 0 || dquot->dq_dev != dev) + continue; + if (type != -1 && dquot->dq_type != type) + continue; + wait_on_dquot(dquot); + if (dquot->dq_flags & DQ_MOD) + write_dquot(dquot); + } + return(0); +} + +/* + * Trash the cache for a certain type on a device. + */ +void invalidate_dquots(kdev_t dev, short type) +{ + struct dquot *dquot, *next; + int cnt; + + next = first_dquot; + for (cnt = nr_dquots ; cnt > 0 ; cnt--) { + dquot = next; + next = dquot->dq_next; + if (dquot->dq_dev != dev || dquot->dq_type != type) + continue; + if (dquot->dq_flags & DQ_LOCKED) { + printk("VFS: dquot busy on removed device %s\n", kdevname(dev)); + continue; + } + if (dquot->dq_flags & DQ_MOD) + write_dquot(dquot); + dqstats.drops++; + clear_dquot(dquot); + } +} + +static inline void dquot_incr_inodes(struct dquot *dquot, unsigned long number) +{ + lock_dquot(dquot); + dquot->dq_curinodes += number; + dquot->dq_flags |= DQ_MOD; + unlock_dquot(dquot); +} + +static inline void dquot_incr_blocks(struct dquot *dquot, unsigned long number) +{ + lock_dquot(dquot); + dquot->dq_curblocks += number; + dquot->dq_flags |= DQ_MOD; + unlock_dquot(dquot); +} + +static inline void dquot_decr_inodes(struct dquot *dquot, unsigned long number) +{ + lock_dquot(dquot); + if (dquot->dq_curinodes > number) + dquot->dq_curinodes -= number; + else + dquot->dq_curinodes = 0; + if (dquot->dq_curinodes < dquot->dq_isoftlimit) + dquot->dq_itime = (time_t) 0; + dquot->dq_flags &= ~DQ_INODES; + dquot->dq_flags |= DQ_MOD; + unlock_dquot(dquot); +} + +static inline void dquot_decr_blocks(struct dquot *dquot, unsigned long number) +{ + lock_dquot(dquot); + if (dquot->dq_curblocks > number) + dquot->dq_curblocks -= number; + else + dquot->dq_curblocks = 0; + if (dquot->dq_curblocks < dquot->dq_bsoftlimit) + dquot->dq_btime = (time_t) 0; + dquot->dq_flags &= ~DQ_BLKS; + dquot->dq_flags |= DQ_MOD; + unlock_dquot(dquot); +} + +static inline int need_print_warning(short type, struct dquot *dquot) +{ + switch (type) { + case USRQUOTA: + return(current->fsuid == dquot->dq_id); + case GRPQUOTA: + return(current->fsgid == dquot->dq_id); + } + return(0); +} + +static int check_idq(struct dquot *dquot, short type, u_long short inodes) +{ + if (inodes <= 0 || dquot->dq_flags & DQ_FAKE) + return(QUOTA_OK); + if (dquot->dq_ihardlimit && + (dquot->dq_curinodes + inodes) > dquot->dq_ihardlimit && !fsuser()) { + if ((dquot->dq_flags & DQ_INODES) == 0 && + need_print_warning(type, dquot)) { + sprintf(quotamessage, "%s: write failed, %s file limit reached\r\n", + dquot->dq_mnt->mnt_dirname, quotatypes[type]); + tty_write_message(current->tty, quotamessage); + dquot->dq_flags |= DQ_INODES; + } + return(NO_QUOTA); + } + if (dquot->dq_isoftlimit && + (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit && + dquot->dq_itime && CURRENT_TIME >= dquot->dq_itime && !fsuser()) { + if (need_print_warning(type, dquot)) { + sprintf(quotamessage, "%s: warning, %s file quota exceeded to long.\r\n", + dquot->dq_mnt->mnt_dirname, quotatypes[type]); + tty_write_message(current->tty, quotamessage); + } + return(NO_QUOTA); + } + if (dquot->dq_isoftlimit && + (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit && + dquot->dq_itime == 0 && !fsuser()) { + if (need_print_warning(type, dquot)) { + sprintf(quotamessage, "%s: warning, %s file quota exceeded\r\n", + dquot->dq_mnt->mnt_dirname, quotatypes[type]); + tty_write_message(current->tty, quotamessage); + } + dquot->dq_itime = CURRENT_TIME + dquot->dq_mnt->mnt_iexp[type]; + } + return(QUOTA_OK); +} + +static int check_bdq(struct dquot *dquot, short type, u_long blocks) +{ + if (blocks <= 0 || dquot->dq_flags & DQ_FAKE) + return(QUOTA_OK); + if (dquot->dq_bhardlimit && + (dquot->dq_curblocks + blocks) > dquot->dq_bhardlimit && !fsuser()) { + if ((dquot->dq_flags & DQ_BLKS) == 0 && + need_print_warning(type, dquot)) { + sprintf(quotamessage, "%s: write failed, %s disk limit reached.\r\n", + dquot->dq_mnt->mnt_dirname, quotatypes[type]); + tty_write_message(current->tty, quotamessage); + dquot->dq_flags |= DQ_BLKS; + } + return(NO_QUOTA); + } + if (dquot->dq_bsoftlimit && + (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit && + dquot->dq_btime && CURRENT_TIME >= dquot->dq_btime && !fsuser()) { + if (need_print_warning(type, dquot)) { + sprintf(quotamessage, "%s: write failed, %s disk quota exceeded to long.\r\n", + dquot->dq_mnt->mnt_dirname, quotatypes[type]); + tty_write_message(current->tty, quotamessage); + } + return(NO_QUOTA); + } + if (dquot->dq_bsoftlimit && + (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit && + dquot->dq_btime == 0 && !fsuser()) { + if (need_print_warning(type, dquot)) { + sprintf(quotamessage, "%s: warning, %s disk quota exceeded\r\n", + dquot->dq_mnt->mnt_dirname, quotatypes[type]); + tty_write_message(current->tty, quotamessage); + } + dquot->dq_btime = CURRENT_TIME + dquot->dq_mnt->mnt_bexp[type]; + } + return(QUOTA_OK); +} + +static void dqput(struct dquot *dquot) +{ + if (!dquot) + return; + /* + * If the dq_mnt pointer isn't initialized this entry needs no + * checking and doesn't need to be written. It just an empty + * dquot that is put back into the freelist. + */ + if (dquot->dq_mnt != (struct vfsmount *)NULL) { + dqstats.drops++; + wait_on_dquot(dquot); + if (!dquot->dq_count) { + printk("VFS: dqput: trying to free free dquot\n"); + printk("VFS: device %s, dquot of %s %d\n", kdevname(dquot->dq_dev), + quotatypes[dquot->dq_type], dquot->dq_id); + return; + } +repeat: + if (dquot->dq_count > 1) { + dquot->dq_count--; + return; + } + wake_up(&dquot_wait); + if (dquot->dq_flags & DQ_MOD) { + write_dquot(dquot); /* we can sleep - so do again */ + wait_on_dquot(dquot); + goto repeat; + } + } + if (dquot->dq_count) { + dquot->dq_count--; + nr_free_dquots++; + } + return; +} + +static struct dquot *get_empty_dquot(void) +{ + struct dquot *dquot, *best; + int cnt; + + if (nr_dquots < NR_DQUOTS && nr_free_dquots < (nr_dquots >> 2)) + grow_dquots(); + +repeat: + dquot = first_dquot; + best = NODQUOT; + for (cnt = 0; cnt < nr_dquots; dquot = dquot->dq_next, cnt++) { + if (!dquot->dq_count) { + if (!best) + best = dquot; + if (!(dquot->dq_flags & DQ_MOD) && !(dquot->dq_flags & DQ_LOCKED)) { + best = dquot; + break; + } + } + } + if (!best || best->dq_flags & DQ_MOD || best->dq_flags & DQ_LOCKED) + if (nr_dquots < NR_DQUOTS) { + grow_dquots(); + goto repeat; + } + dquot = best; + if (!dquot) { + printk("VFS: No free dquots - contact mvw@mcs.ow.org\n"); + sleep_on(&dquot_wait); + goto repeat; + } + if (dquot->dq_flags & DQ_LOCKED) { + wait_on_dquot(dquot); + goto repeat; + } + if (dquot->dq_flags & DQ_MOD) { + write_dquot(dquot); + goto repeat; + } + if (dquot->dq_count) + goto repeat; + clear_dquot(dquot); + dquot->dq_count = 1; + nr_free_dquots--; + if (nr_free_dquots < 0) { + printk ("VFS: get_empty_dquot: bad free dquot count.\n"); + nr_free_dquots = 0; + } + return(dquot); +} + +static struct dquot *dqget(kdev_t dev, unsigned int id, short type) +{ + struct dquot *dquot, *empty; + struct vfsmount *vfsmnt; + + if ((vfsmnt = lookup_vfsmnt(dev)) == (struct vfsmount *)NULL || + (vfsmnt->mnt_quotas[type] == (struct file *)0)) + return(NODQUOT); + dqstats.lookups++; + empty = get_empty_dquot(); +repeat: + dquot = *(hash(dev, id, type)); + while (dquot) { + if (dquot->dq_dev != dev || dquot->dq_id != id) { + dquot = dquot->dq_hash_next; + continue; + } + wait_on_dquot(dquot); + if (dquot->dq_dev != dev || dquot->dq_id != id) + goto repeat; + if (!dquot->dq_count) + nr_free_dquots--; + dquot->dq_count++; + if (empty) + dqput(empty); + dqstats.cache_hits++; + return(dquot); + } + if (!empty) + return(NODQUOT); + dquot = empty; + dquot->dq_id = id; + dquot->dq_type = type; + dquot->dq_dev = dev; + dquot->dq_mnt = vfsmnt; + put_last_free(dquot); + insert_dquot_hash(dquot); + read_dquot(dquot); + return(dquot); +} + +/* + * Initialize a dquot-struct with new quota info. This is used by the + * systemcall interface functions. + */ +static int set_dqblk(kdev_t dev, int id, short type, int flags, struct dqblk *dqblk) +{ + struct dquot *dquot; + struct dqblk dq_dqblk; + int error; + + if (dqblk == (struct dqblk *)NULL) + return(-EFAULT); + + if (flags & QUOTA_SYSCALL) { + if ((error = verify_area(VERIFY_READ, dqblk, sizeof(struct dqblk))) != 0) + return(error); + memcpy_fromfs(&dq_dqblk, dqblk, sizeof(struct dqblk)); + } else { + memcpy(&dq_dqblk, dqblk, sizeof(struct dqblk)); + } + if ((dquot = dqget(dev, id, type)) != NODQUOT) { + lock_dquot(dquot); + if (id > 0 && ((flags & SET_QUOTA) || (flags & SET_QLIMIT))) { + dquot->dq_bhardlimit = dq_dqblk.dqb_bhardlimit; + dquot->dq_bsoftlimit = dq_dqblk.dqb_bsoftlimit; + dquot->dq_ihardlimit = dq_dqblk.dqb_ihardlimit; + dquot->dq_isoftlimit = dq_dqblk.dqb_isoftlimit; + } + if ((flags & SET_QUOTA) || (flags & SET_USE)) { + if (dquot->dq_isoftlimit && + dquot->dq_curinodes < dquot->dq_isoftlimit && + dq_dqblk.dqb_curinodes >= dquot->dq_isoftlimit) + dquot->dq_itime = CURRENT_TIME + dquot->dq_mnt->mnt_iexp[type]; + dquot->dq_curinodes = dq_dqblk.dqb_curinodes; + if (dquot->dq_curinodes < dquot->dq_isoftlimit) + dquot->dq_flags &= ~DQ_INODES; + if (dquot->dq_bsoftlimit && + dquot->dq_curblocks < dquot->dq_bsoftlimit && + dq_dqblk.dqb_curblocks >= dquot->dq_bsoftlimit) + dquot->dq_btime = CURRENT_TIME + dquot->dq_mnt->mnt_bexp[type]; + dquot->dq_curblocks = dq_dqblk.dqb_curblocks; + if (dquot->dq_curblocks < dquot->dq_bsoftlimit) + dquot->dq_flags &= ~DQ_BLKS; + } + if (id == 0) { + /* + * Change in expiretimes, change them in dq_mnt. + */ + dquot->dq_mnt->mnt_bexp[type] = dquot->dq_btime = dq_dqblk.dqb_btime; + dquot->dq_mnt->mnt_iexp[type] = dquot->dq_itime = dq_dqblk.dqb_itime; + } + if (dq_dqblk.dqb_bhardlimit == 0 && dq_dqblk.dqb_bsoftlimit == 0 && + dq_dqblk.dqb_ihardlimit == 0 && dq_dqblk.dqb_isoftlimit == 0) + dquot->dq_flags |= DQ_FAKE; + else + dquot->dq_flags &= ~DQ_FAKE; + dquot->dq_flags |= DQ_MOD; + unlock_dquot(dquot); + dqput(dquot); + } + return(0); +} + +static int get_quota(kdev_t dev, int id, short type, struct dqblk *dqblk) +{ + struct dquot *dquot; + int error; + + if (has_quota_enabled(dev, type)) { + if (dqblk == (struct dqblk *)NULL) + return(-EFAULT); + + if ((error = verify_area(VERIFY_WRITE, dqblk, sizeof(struct dqblk))) != 0) + return(error); + + if ((dquot = dqget(dev, id, type)) != NODQUOT) { + memcpy_tofs(dqblk, (char *)&dquot->dq_dqb, sizeof(struct dqblk)); + dqput(dquot); + return(0); + } + } + return(-ESRCH); +} + +static int get_stats(caddr_t addr) +{ + int error; + + if ((error = verify_area(VERIFY_WRITE, addr, sizeof(struct dqstats))) != 0) + return(error); + + dqstats.allocated_dquots = nr_dquots; + dqstats.free_dquots = nr_free_dquots; + memcpy_tofs(addr, (caddr_t)&dqstats, sizeof(struct dqstats)); + return(0); +} + +/* + * Initialize pointer in a inode to the right dquots. + */ +void dquot_initialize(struct inode *inode, short type) +{ + unsigned int id = 0; + short cnt; + + if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) { + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + if (type != -1 && cnt != type) + continue; + if (!has_quota_enabled(inode->i_dev, cnt)) + continue; + if (inode->i_dquot[cnt] == NODQUOT) { + switch (cnt) { + case USRQUOTA: + id = inode->i_uid; + break; + case GRPQUOTA: + id = inode->i_gid; + break; + } + inode->i_dquot[cnt] = dqget(inode->i_dev, id, cnt); + inode->i_flags |= S_WRITE; + } + } + } +} + +void dquot_drop(struct inode *inode) +{ + short cnt; + + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + if (inode->i_dquot[cnt] == NODQUOT) + continue; + dqput(inode->i_dquot[cnt]); + inode->i_dquot[cnt] = NODQUOT; + } + inode->i_flags &= ~S_WRITE; +} + +/* + * This is a simple algorithm that calculates the size of a file in blocks. + * This is only used on filesystems that do not have a i_blocks count. + */ +static u_long isize_to_blocks(size_t isize, size_t blksize) +{ + u_long blocks; + u_long indirect; + + if (!blksize) + blksize = BLOCK_SIZE; + blocks = (isize / blksize) + ((isize % blksize) ? 1 : 0); + if (blocks > 10) { + indirect = ((blocks - 11) >> 8) + 1; /* single indirect blocks */ + if (blocks > (10 + 256)) { + indirect += ((blocks - 267) >> 16) + 1; /* double indirect blocks */ + if (blocks > (10 + 256 + (256 << 8))) + indirect++; /* triple indirect blocks */ + } + blocks += indirect; + } + return(blocks); +} + +/* + * Externaly referenced funtions trough dq_operations. + */ +int dquot_alloc_block(const struct inode *inode, unsigned long number) +{ + unsigned short cnt; + + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + if (inode->i_dquot[cnt] == NODQUOT) + continue; + if (check_bdq(inode->i_dquot[cnt], cnt, number)) + return(NO_QUOTA); + } + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + if (inode->i_dquot[cnt] == NODQUOT) + continue; + dquot_incr_blocks(inode->i_dquot[cnt], number); + } + return(QUOTA_OK); +} + +int dquot_alloc_inode(const struct inode *inode, unsigned long number) +{ + unsigned short cnt; + + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + if (inode->i_dquot[cnt] == NODQUOT) + continue; + if (check_idq(inode->i_dquot[cnt], cnt, number)) + return(NO_QUOTA); + } + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + if (inode->i_dquot[cnt] == NODQUOT) + continue; + dquot_incr_inodes(inode->i_dquot[cnt], number); + } + return(QUOTA_OK); +} + +void dquot_free_block(const struct inode *inode, unsigned long number) +{ + unsigned short cnt; + + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + if (inode->i_dquot[cnt] == NODQUOT) + continue; + dquot_decr_blocks(inode->i_dquot[cnt], number); + } +} + +void dquot_free_inode(const struct inode *inode, unsigned long number) +{ + unsigned short cnt; + + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + if (inode->i_dquot[cnt] == NODQUOT) + continue; + dquot_decr_inodes(inode->i_dquot[cnt], number); + } +} + +/* + * Transfer the number of inode and blocks from one diskquota to an other. + */ +int dquot_transfer(struct inode *inode, struct iattr *iattr, char direction) +{ + unsigned long blocks; + struct dquot *transfer_from[MAXQUOTAS]; + struct dquot *transfer_to[MAXQUOTAS]; + short cnt, disc; + + /* + * Find out if this filesystems uses i_blocks. + */ + if (inode->i_blksize == 0) + blocks = isize_to_blocks(inode->i_size, BLOCK_SIZE); + else + blocks = (inode->i_blocks / 2); + + /* + * Build the transfer_from and transfer_to lists and check quotas to see + * if operation is permitted. + */ + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + transfer_from[cnt] = NODQUOT; + transfer_to[cnt] = NODQUOT; + + if (!has_quota_enabled(inode->i_dev, cnt)) + continue; + + switch (cnt) { + case USRQUOTA: + if (inode->i_uid == iattr->ia_uid) + continue; + transfer_from[cnt] = dqget(inode->i_dev, (direction) ? iattr->ia_uid : inode->i_uid, cnt); + transfer_to[cnt] = dqget(inode->i_dev, (direction) ? inode->i_uid : iattr->ia_uid, cnt); + break; + case GRPQUOTA: + if (inode->i_gid == iattr->ia_gid) + continue; + transfer_from[cnt] = dqget(inode->i_dev, (direction) ? iattr->ia_gid : inode->i_gid, cnt); + transfer_to[cnt] = dqget(inode->i_dev, (direction) ? inode->i_gid : iattr->ia_gid, cnt); + break; + } + + if (check_idq(transfer_to[cnt], cnt, 1) == NO_QUOTA || + check_bdq(transfer_to[cnt], cnt, blocks) == NO_QUOTA) { + for (disc = 0; disc <= cnt; disc++) { + dqput(transfer_from[disc]); + dqput(transfer_to[disc]); + } + return(NO_QUOTA); + } + } + + /* + * Finaly perform the needed transfer from transfer_from to transfer_to. + * And release any pointer to dquots not needed anymore. + */ + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + /* + * Skip changes for same uid or gid or for non-existing quota-type. + */ + if (transfer_from[cnt] == NODQUOT && transfer_to[cnt] == NODQUOT) + continue; + + if (transfer_from[cnt] != NODQUOT) { + dquot_decr_inodes(transfer_from[cnt], 1); + dquot_decr_blocks(transfer_from[cnt], blocks); + } + if (transfer_to[cnt] != NODQUOT) { + dquot_incr_inodes(transfer_to[cnt], 1); + dquot_incr_blocks(transfer_to[cnt], blocks); + } + if (inode->i_dquot[cnt] != NODQUOT) { + dqput(transfer_from[cnt]); + dqput(inode->i_dquot[cnt]); + inode->i_dquot[cnt] = transfer_to[cnt]; + } else { + dqput(transfer_from[cnt]); + dqput(transfer_to[cnt]); + } + } + return(QUOTA_OK); +} + +void dquot_init(void) +{ + printk("VFS: Diskquotas version %s initialized\r\n", __DQUOT_VERSION__); + memset(hash_table, 0, sizeof(hash_table)); + memset((caddr_t)&dqstats, 0, sizeof(dqstats)); + first_dquot = NODQUOT; +} + +/* + * Definitions of diskquota operations. + */ +struct dquot_operations dquot_operations = { + dquot_initialize, + dquot_drop, + dquot_alloc_block, + dquot_alloc_inode, + dquot_free_block, + dquot_free_inode, + dquot_transfer +}; + +/* + * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount) + */ +int quota_off(kdev_t dev, short type) +{ + struct vfsmount *vfsmnt; + short cnt; + + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + if (type != -1 && cnt != type) + continue; + if ((vfsmnt = lookup_vfsmnt(dev)) == (struct vfsmount *)NULL || + vfsmnt->mnt_quotas[cnt] == (struct file *)NULL) + continue; + vfsmnt->mnt_sb->dq_op = (struct dquot_operations *)NULL; + reset_dquot_ptrs(dev, cnt); + invalidate_dquots(dev, cnt); + close_fp(vfsmnt->mnt_quotas[cnt]); + vfsmnt->mnt_quotas[cnt] = (struct file *)NULL; + vfsmnt->mnt_iexp[cnt] = vfsmnt->mnt_bexp[cnt] = (time_t)NULL; + } + return(0); +} + +int quota_on(kdev_t dev, short type, char *path) +{ + struct file *filp = (struct file *)NULL; + struct vfsmount *vfsmnt; + struct inode *inode; + struct dquot *dquot; + char *tmp; + int error; + + if ((vfsmnt = lookup_vfsmnt(dev)) == (struct vfsmount *)NULL) + return(-ENODEV); + if (vfsmnt->mnt_quotas[type] != (struct file *)NULL) + return(-EBUSY); + if ((error = getname(path, &tmp)) != 0) + return(error); + error = open_namei(tmp, O_RDWR, 0600, &inode, 0); + putname(tmp); + if (error) + return(error); + if (!S_ISREG(inode->i_mode)) { + iput(inode); + return(-EACCES); + } + if ((filp = get_empty_filp()) != (struct file *)NULL) { + filp->f_mode = (O_RDWR + 1) & O_ACCMODE; + filp->f_flags = O_RDWR; + filp->f_inode = inode; + filp->f_pos = 0; + filp->f_reada = 0; + filp->f_op = inode->i_op->default_file_ops; + if (filp->f_op->read || filp->f_op->write) { + if ((error = get_write_access(inode)) == 0) { + if (filp->f_op && filp->f_op->open) + error = filp->f_op->open(inode, filp); + if (error == 0) { + vfsmnt->mnt_quotas[type] = filp; + dquot = dqget(dev, 0, type); + vfsmnt->mnt_iexp[type] = (dquot) ? dquot->dq_itime : MAX_IQ_TIME; + vfsmnt->mnt_bexp[type] = (dquot) ? dquot->dq_btime : MAX_DQ_TIME; + dqput(dquot); + vfsmnt->mnt_sb->dq_op = &dquot_operations; + add_dquot_ref(dev, type); + return(0); + } + put_write_access(inode); + } + } else + error = -EIO; + filp->f_count--; + } else + error = -EMFILE; + iput(inode); + return(error); +} + +/* + * Ok this is the systemcall interface, this communicates with + * the userlevel programs. Currently this only supports diskquota + * calls. Maybe we need to add the process quotas etc in the future. + * But we probably better use rlimits for that. + */ +asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr) +{ + int cmds = 0, type = 0, flags = 0; + struct inode *ino; + kdev_t dev; + + cmds = cmd >> SUBCMDSHIFT; + type = cmd & SUBCMDMASK; + + if ((u_int) type >= MAXQUOTAS) + return(-EINVAL); + switch (cmds) { + case Q_SYNC: + case Q_GETSTATS: + break; + case Q_GETQUOTA: + if (((type == USRQUOTA && current->uid != id) || + (type == GRPQUOTA && current->gid != id)) && !fsuser()) + return(-EPERM); + break; + default: + if (!fsuser()) + return(-EPERM); + } + + if (special == (char *)NULL && (cmds == Q_SYNC || cmds == Q_GETSTATS)) + dev = 0; + else { + if (namei(special, &ino)) + return(-EINVAL); + dev = ino->i_rdev; + if (!S_ISBLK(ino->i_mode)) { + iput(ino); + return(-ENOTBLK); + } + iput(ino); + } + + switch (cmds) { + case Q_QUOTAON: + return(quota_on(dev, type, (char *) addr)); + case Q_QUOTAOFF: + return(quota_off(dev, type)); + case Q_GETQUOTA: + return(get_quota(dev, id, type, (struct dqblk *) addr)); + case Q_SETQUOTA: + flags |= SET_QUOTA; + break; + case Q_SETUSE: + flags |= SET_USE; + break; + case Q_SETQLIM: + flags |= SET_QLIMIT; + break; + case Q_SYNC: + return(sync_dquots(dev, type)); + case Q_GETSTATS: + return(get_stats(addr)); + default: + return(-EINVAL); + } + + flags |= QUOTA_SYSCALL; + if (has_quota_enabled(dev, type)) + return(set_dqblk(dev, id, type, flags, (struct dqblk *) addr)); + return(-ESRCH); +} diff -u --recursive --new-file v1.3.45/linux/fs/exec.c linux/fs/exec.c --- v1.3.45/linux/fs/exec.c Tue Nov 21 13:22:12 1995 +++ linux/fs/exec.c Mon Dec 11 06:56:35 1995 @@ -666,7 +666,7 @@ goto exec_error2; } /* better not execute files which are being written to */ - if (bprm.inode->i_wcount > 0) { + if (bprm.inode->i_writecount > 0) { retval = -ETXTBSY; goto exec_error2; } diff -u --recursive --new-file v1.3.45/linux/fs/ext2/balloc.c linux/fs/ext2/balloc.c --- v1.3.45/linux/fs/ext2/balloc.c Mon Nov 27 12:48:31 1995 +++ linux/fs/ext2/balloc.c Mon Dec 11 06:56:35 1995 @@ -165,7 +165,7 @@ return load__block_bitmap (sb, block_group); } -void ext2_free_blocks (struct super_block * sb, unsigned long block, +void ext2_free_blocks (const struct inode * inode, unsigned long block, unsigned long count) { struct buffer_head * bh; @@ -174,9 +174,11 @@ unsigned long bit; unsigned long i; int bitmap_nr; + struct super_block * sb; struct ext2_group_desc * gdp; struct ext2_super_block * es; + sb = inode->i_sb; if (!sb) { printk ("ext2_free_blocks: nonexistent device"); return; @@ -224,6 +226,8 @@ "bit already cleared for block %lu", block); else { + if (sb->dq_op) + sb->dq_op->free_block(inode, fs_to_dq_blocks(1, inode->i_blksize)); gdp->bg_free_blocks_count++; es->s_free_blocks_count++; } @@ -249,21 +253,23 @@ * each block group the search first looks for an entire free byte in the block * bitmap, and then for any free bit if that fails. */ -int ext2_new_block (struct super_block * sb, unsigned long goal, - u32 * prealloc_count, - u32 * prealloc_block) +int ext2_new_block (const struct inode * inode, unsigned long goal, + u32 * prealloc_count, u32 * prealloc_block, int * err) { struct buffer_head * bh; struct buffer_head * bh2; char * p, * r; int i, j, k, tmp; int bitmap_nr; + struct super_block * sb; struct ext2_group_desc * gdp; struct ext2_super_block * es; + *err = -ENOSPC; #ifdef EXT2FS_DEBUG static int goal_hits = 0, goal_attempts = 0; #endif + sb = inode->i_sb; if (!sb) { printk ("ext2_new_block: nonexistent device"); return 0; @@ -394,6 +400,16 @@ ext2_debug ("using block group %d(%d)\n", i, gdp->bg_free_blocks_count); + /* + * Check quota for allocation of this block. + */ + if (sb->dq_op) + if (sb->dq_op->alloc_block (inode, fs_to_dq_blocks(1, inode->i_blksize))) { + unlock_super (sb); + *err = -EDQUOT; + return 0; + } + tmp = j + i * EXT2_BLOCKS_PER_GROUP(sb) + es->s_first_data_block; if (test_opt (sb, CHECK_STRICT) && @@ -407,6 +423,8 @@ if (set_bit (j, bh->b_data)) { ext2_warning (sb, "ext2_new_block", "bit already set for block %d", j); + if (sb->dq_op) + sb->dq_op->free_block(inode, fs_to_dq_blocks(1, inode->i_blksize)); goto repeat; } @@ -421,8 +439,14 @@ *prealloc_block = tmp + 1; for (k = 1; k < 8 && (j + k) < EXT2_BLOCKS_PER_GROUP(sb); k++) { - if (set_bit (j + k, bh->b_data)) + if (sb->dq_op) + if (sb->dq_op->alloc_block(inode, fs_to_dq_blocks(1, inode->i_blksize))) + break; + if (set_bit (j + k, bh->b_data)) { + if (sb->dq_op) + sb->dq_op->free_block(inode, fs_to_dq_blocks(1, inode->i_blksize)); break; + } (*prealloc_count)++; } gdp->bg_free_blocks_count -= *prealloc_count; @@ -466,6 +490,7 @@ mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); sb->s_dirt = 1; unlock_super (sb); + *err = 0; return j; } diff -u --recursive --new-file v1.3.45/linux/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c --- v1.3.45/linux/fs/ext2/ialloc.c Wed Mar 22 10:33:59 1995 +++ linux/fs/ext2/ialloc.c Mon Dec 11 10:10:07 1995 @@ -252,7 +252,8 @@ ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); } - + if (sb->dq_op) + sb->dq_op->free_inode (inode, 1); sb->s_dirt = 1; clear_inode (inode); unlock_super (sb); @@ -303,7 +304,7 @@ * For other inodes, search forward from the parent directory\'s block * group to find a free inode. */ -struct inode * ext2_new_inode (const struct inode * dir, int mode) +struct inode * ext2_new_inode (const struct inode * dir, int mode, int * err) { struct super_block * sb; struct buffer_head * bh; @@ -325,6 +326,7 @@ repeat: gdp = NULL; i=0; + *err = -ENOSPC; if (S_ISDIR(mode)) { avefreei = es->s_free_inodes_count / sb->u.ext2_sb.s_groups_count; @@ -481,9 +483,21 @@ insert_inode_hash(inode); inc_inode_version (inode, gdp, mode); + unlock_super (sb); + if (sb->dq_op) { + sb->dq_op->initialize (inode, -1); + if (sb->dq_op->alloc_inode (inode, 1)) { + sb->dq_op->drop (inode); + inode->i_nlink = 0; + iput (inode); + *err = -EDQUOT; + return NULL; + } + inode->i_flags |= S_WRITE; + } ext2_debug ("allocating inode %lu\n", inode->i_ino); - unlock_super (sb); + *err = 0; return inode; } diff -u --recursive --new-file v1.3.45/linux/fs/ext2/inode.c linux/fs/ext2/inode.c --- v1.3.45/linux/fs/ext2/inode.c Mon Nov 27 12:48:31 1995 +++ linux/fs/ext2/inode.c Mon Dec 11 06:56:35 1995 @@ -62,17 +62,17 @@ void ext2_discard_prealloc (struct inode * inode) { #ifdef EXT2_PREALLOCATE + unsigned short total; + if (inode->u.ext2_i.i_prealloc_count) { - int i = inode->u.ext2_i.i_prealloc_count; + total = inode->u.ext2_i.i_prealloc_count; inode->u.ext2_i.i_prealloc_count = 0; - ext2_free_blocks (inode->i_sb, - inode->u.ext2_i.i_prealloc_block, - i); + ext2_free_blocks (inode, inode->u.ext2_i.i_prealloc_block, total); } #endif } -static int ext2_alloc_block (struct inode * inode, unsigned long goal) +static int ext2_alloc_block (struct inode * inode, unsigned long goal, int * err) { #ifdef EXT2FS_DEBUG static unsigned long alloc_hits = 0, alloc_attempts = 0; @@ -110,15 +110,14 @@ ext2_debug ("preallocation miss (%lu/%lu).\n", alloc_hits, ++alloc_attempts); if (S_ISREG(inode->i_mode)) - result = ext2_new_block - (inode->i_sb, goal, + result = ext2_new_block (inode, goal, &inode->u.ext2_i.i_prealloc_count, - &inode->u.ext2_i.i_prealloc_block); + &inode->u.ext2_i.i_prealloc_block, err); else - result = ext2_new_block (inode->i_sb, goal, 0, 0); + result = ext2_new_block (inode, goal, 0, 0, err); } #else - result = ext2_new_block (inode->i_sb, goal, 0, 0); + result = ext2_new_block (inode, goal, 0, 0, err); #endif return result; @@ -225,12 +224,12 @@ ext2_debug ("goal = %d.\n", goal); - tmp = ext2_alloc_block (inode, goal); + tmp = ext2_alloc_block (inode, goal, err); if (!tmp) return NULL; result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize); if (*p) { - ext2_free_blocks (inode->i_sb, tmp, 1); + ext2_free_blocks (inode, tmp, 1); brelse (result); goto repeat; } @@ -297,14 +296,14 @@ if (!goal) goal = bh->b_blocknr; } - tmp = ext2_alloc_block (inode, goal); + tmp = ext2_alloc_block (inode, goal, err); if (!tmp) { brelse (bh); return NULL; } result = getblk (bh->b_dev, tmp, blocksize); if (*p) { - ext2_free_blocks (inode->i_sb, tmp, 1); + ext2_free_blocks (inode, tmp, 1); brelse (result); goto repeat; } diff -u --recursive --new-file v1.3.45/linux/fs/ext2/namei.c linux/fs/ext2/namei.c --- v1.3.45/linux/fs/ext2/namei.c Mon Nov 27 12:48:31 1995 +++ linux/fs/ext2/namei.c Mon Dec 11 06:56:35 1995 @@ -375,10 +375,10 @@ *result = NULL; if (!dir) return -ENOENT; - inode = ext2_new_inode (dir, mode); + inode = ext2_new_inode (dir, mode, &err); if (!inode) { iput (dir); - return -ENOSPC; + return err; } inode->i_op = &ext2_file_inode_operations; inode->i_mode = mode; @@ -421,10 +421,10 @@ iput (dir); return -EEXIST; } - inode = ext2_new_inode (dir, mode); + inode = ext2_new_inode (dir, mode, &err); if (!inode) { iput (dir); - return -ENOSPC; + return err; } inode->i_uid = current->fsuid; inode->i_mode = mode; @@ -488,10 +488,10 @@ iput (dir); return -EMLINK; } - inode = ext2_new_inode (dir, S_IFDIR); + inode = ext2_new_inode (dir, S_IFDIR, &err); if (!inode) { iput (dir); - return -ENOSPC; + return err; } inode->i_op = &ext2_dir_inode_operations; inode->i_size = inode->i_sb->s_blocksize; @@ -622,6 +622,8 @@ retval = -EPERM; if (!(inode = iget (dir->i_sb, de->inode))) goto end_rmdir; + if (inode->i_sb->dq_op) + inode->i_sb->dq_op->initialize (inode, -1); if (inode->i_dev != dir->i_dev) goto end_rmdir; if (de->inode != inode->i_ino) { @@ -702,6 +704,8 @@ goto end_unlink; if (!(inode = iget (dir->i_sb, de->inode))) goto end_unlink; + if (inode->i_sb->dq_op) + inode->i_sb->dq_op->initialize (inode, -1); retval = -EPERM; if (S_ISDIR(inode->i_mode)) goto end_unlink; @@ -757,9 +761,9 @@ int l; char c; - if (!(inode = ext2_new_inode (dir, S_IFLNK))) { + if (!(inode = ext2_new_inode (dir, S_IFLNK, &err))) { iput (dir); - return -ENOSPC; + return err; } inode->i_mode = S_IFLNK | S_IRWXUGO; inode->i_op = &ext2_symlink_inode_operations; @@ -795,6 +799,7 @@ } inode->i_size = i; inode->i_dirt = 1; + bh = ext2_find_entry (dir, name, len, &de); if (bh) { inode->i_nlink--; @@ -967,6 +972,9 @@ if (!new_inode) { brelse (new_bh); new_bh = NULL; + } else { + if (new_inode->i_sb->dq_op) + new_inode->i_sb->dq_op->initialize (new_inode, -1); } } if (new_inode == old_inode) { diff -u --recursive --new-file v1.3.45/linux/fs/ext2/super.c linux/fs/ext2/super.c --- v1.3.45/linux/fs/ext2/super.c Mon Nov 13 12:36:46 1995 +++ linux/fs/ext2/super.c Mon Dec 11 06:56:35 1995 @@ -249,6 +249,12 @@ return 0; } } + /* Silently ignore the quota options */ + else if (!strcmp (this_char, "grpquota") + || !strcmp (this_char, "noquota") + || !strcmp (this_char, "quota") + || !strcmp (this_char, "usrquota")) + /* Don't do anything ;-) */ ; else { printk ("EXT2-fs: Unrecognized mount option %s\n", this_char); return 0; diff -u --recursive --new-file v1.3.45/linux/fs/ext2/truncate.c linux/fs/ext2/truncate.c --- v1.3.45/linux/fs/ext2/truncate.c Mon Nov 27 12:48:31 1995 +++ linux/fs/ext2/truncate.c Mon Dec 11 06:56:35 1995 @@ -96,14 +96,14 @@ } else if (free_count > 0 && block_to_free == tmp - free_count) free_count++; else { - ext2_free_blocks (inode->i_sb, block_to_free, free_count); + ext2_free_blocks (inode, block_to_free, free_count); block_to_free = tmp; free_count = 1; } -/* ext2_free_blocks (inode->i_sb, tmp, 1); */ +/* ext2_free_blocks (inode, tmp, 1); */ } if (free_count > 0) - ext2_free_blocks (inode->i_sb, block_to_free, free_count); + ext2_free_blocks (inode, block_to_free, free_count); return retry; } @@ -163,16 +163,16 @@ } else if (free_count > 0 && block_to_free == tmp - free_count) free_count++; else { - ext2_free_blocks (inode->i_sb, block_to_free, free_count); + ext2_free_blocks (inode, block_to_free, free_count); block_to_free = tmp; free_count = 1; } -/* ext2_free_blocks (inode->i_sb, tmp, 1); */ +/* ext2_free_blocks (inode, tmp, 1); */ inode->i_blocks -= blocks; inode->i_dirt = 1; } if (free_count > 0) - ext2_free_blocks (inode->i_sb, block_to_free, free_count); + ext2_free_blocks (inode, block_to_free, free_count); ind = (u32 *) ind_bh->b_data; for (i = 0; i < addr_per_block; i++) if (*(ind++)) @@ -185,7 +185,7 @@ *p = 0; inode->i_blocks -= blocks; inode->i_dirt = 1; - ext2_free_blocks (inode->i_sb, tmp, 1); + ext2_free_blocks (inode, tmp, 1); } if (IS_SYNC(inode) && buffer_dirty(ind_bh)) { ll_rw_block (WRITE, 1, &ind_bh); @@ -245,7 +245,7 @@ *p = 0; inode->i_blocks -= blocks; inode->i_dirt = 1; - ext2_free_blocks (inode->i_sb, tmp, 1); + ext2_free_blocks (inode, tmp, 1); } if (IS_SYNC(inode) && buffer_dirty(dind_bh)) { ll_rw_block (WRITE, 1, &dind_bh); @@ -304,7 +304,7 @@ *p = 0; inode->i_blocks -= blocks; inode->i_dirt = 1; - ext2_free_blocks (inode->i_sb, tmp, 1); + ext2_free_blocks (inode, tmp, 1); } if (IS_SYNC(inode) && buffer_dirty(tind_bh)) { ll_rw_block (WRITE, 1, &tind_bh); diff -u --recursive --new-file v1.3.45/linux/fs/file_table.c linux/fs/file_table.c --- v1.3.45/linux/fs/file_table.c Fri Nov 17 08:42:27 1995 +++ linux/fs/file_table.c Mon Dec 11 07:58:43 1995 @@ -119,3 +119,33 @@ return NULL; } + +void add_dquot_ref(dev_t dev, short type) +{ + struct file *filp; + int cnt; + + for (filp = first_file, cnt = 0; cnt < nr_files; cnt++, filp = filp->f_next) { + if (!filp->f_count || !filp->f_inode || filp->f_inode->i_dev != dev) + continue; + if (filp->f_mode & FMODE_WRITE && filp->f_inode->i_sb->dq_op) { + filp->f_inode->i_sb->dq_op->initialize(filp->f_inode, type); + filp->f_inode->i_flags |= S_WRITE; + } + } +} + +void reset_dquot_ptrs(dev_t dev, short type) +{ + struct file *filp; + int cnt; + + for (filp = first_file, cnt = 0; cnt < nr_files; cnt++, filp = filp->f_next) { + if (!filp->f_count || !filp->f_inode || filp->f_inode->i_dev != dev) + continue; + if (IS_WRITABLE(filp->f_inode)) { + filp->f_inode->i_dquot[type] = NODQUOT; + filp->f_inode->i_flags &= ~S_WRITE; + } + } +} diff -u --recursive --new-file v1.3.45/linux/fs/hpfs/hpfs_fs.c linux/fs/hpfs/hpfs_fs.c --- v1.3.45/linux/fs/hpfs/hpfs_fs.c Thu Nov 9 11:23:51 1995 +++ linux/fs/hpfs/hpfs_fs.c Mon Dec 11 06:56:36 1995 @@ -600,7 +600,7 @@ return 0; } else - return 0; + return 1; } return 1; diff -u --recursive --new-file v1.3.45/linux/fs/inode.c linux/fs/inode.c --- v1.3.45/linux/fs/inode.c Fri Nov 17 08:42:27 1995 +++ linux/fs/inode.c Mon Dec 11 06:56:36 1995 @@ -149,6 +149,10 @@ struct wait_queue * wait; wait_on_inode(inode); + if (IS_WRITABLE(inode)) { + if (inode->i_sb->dq_op) + inode->i_sb->dq_op->drop(inode); + } remove_inode_hash(inode); remove_inode_free(inode); wait = ((volatile struct inode *) inode)->i_wait; @@ -389,28 +393,38 @@ inode->i_count--; return; } + wake_up(&inode_wait); if (inode->i_pipe) { unsigned long page = (unsigned long) PIPE_BASE(*inode); PIPE_BASE(*inode) = NULL; free_page(page); } + if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->put_inode) { inode->i_sb->s_op->put_inode(inode); if (!inode->i_nlink) return; } + if (inode->i_dirt) { write_inode(inode); /* we can sleep - so do again */ wait_on_inode(inode); goto repeat; } + inode->i_count--; + if (IS_WRITABLE(inode)) { + if (inode->i_sb->dq_op) + inode->i_sb->dq_op->drop(inode); + } + if (inode->i_mmap) { printk("iput: inode %lu on device %s still has mappings.\n", inode->i_ino, kdevname(inode->i_dev)); inode->i_mmap = NULL; } + nr_free_inodes++; return; } @@ -499,7 +513,7 @@ return inode; } -struct inode * __iget(struct super_block * sb, int nr, int crossmntp) +struct inode *__iget(struct super_block * sb, int nr, int crossmntp) { static struct wait_queue * update_wait = NULL; struct inode_hash_entry * h; @@ -526,7 +540,6 @@ inode->i_sb = sb; inode->i_dev = sb->s_dev; inode->i_ino = nr; - inode->i_flags = sb->s_flags; put_last_free(inode); insert_inode_hash(inode); read_inode(inode); diff -u --recursive --new-file v1.3.45/linux/fs/isofs/inode.c linux/fs/isofs/inode.c --- v1.3.45/linux/fs/isofs/inode.c Sat Nov 25 19:04:47 1995 +++ linux/fs/isofs/inode.c Mon Dec 11 06:56:36 1995 @@ -142,7 +142,7 @@ break; } } - else return 0; + else return 1; } return 1; } diff -u --recursive --new-file v1.3.45/linux/fs/msdos/inode.c linux/fs/msdos/inode.c --- v1.3.45/linux/fs/msdos/inode.c Mon Nov 13 12:36:46 1995 +++ linux/fs/msdos/inode.c Mon Dec 11 06:56:36 1995 @@ -155,7 +155,7 @@ printk ("MSDOS FS: Invalid blocksize (512 or 1024)\n"); } } - else return 0; + else return 1; } return 1; } diff -u --recursive --new-file v1.3.45/linux/fs/namei.c linux/fs/namei.c --- v1.3.45/linux/fs/namei.c Mon Nov 27 12:48:32 1995 +++ linux/fs/namei.c Mon Dec 11 06:56:36 1995 @@ -136,13 +136,13 @@ return -ETXTBSY; } } - inode->i_wcount++; + inode->i_writecount++; return 0; } void put_write_access(struct inode * inode) { - inode->i_wcount--; + inode->i_writecount--; } /* @@ -151,7 +151,7 @@ * fathers (pseudo-roots, mount-points) */ int lookup(struct inode * dir,const char * name, int len, - struct inode ** result) + struct inode ** result) { struct super_block * sb; int perm; @@ -185,7 +185,7 @@ *result = dir; return 0; } - return dir->i_op->lookup(dir,name,len,result); + return dir->i_op->lookup(dir, name, len, result); } int follow_link(struct inode * dir, struct inode * inode, @@ -211,8 +211,8 @@ * dir_namei() returns the inode of the directory of the * specified name, and the name within that directory. */ -static int dir_namei(const char * pathname, int * namelen, const char ** name, - struct inode * base, struct inode ** res_inode) +static int dir_namei(const char *pathname, int *namelen, const char **name, + struct inode * base, struct inode **res_inode) { char c; const char * thisname; @@ -237,7 +237,7 @@ if (!c) break; base->i_count++; - error = lookup(base,thisname,len,&inode); + error = lookup(base, thisname, len, &inode); if (error) { iput(base); return error; @@ -257,24 +257,24 @@ } static int _namei(const char * pathname, struct inode * base, - int follow_links, struct inode ** res_inode) + int follow_links, struct inode ** res_inode) { - const char * basename; + const char *basename; int namelen,error; struct inode * inode; *res_inode = NULL; - error = dir_namei(pathname,&namelen,&basename,base,&base); + error = dir_namei(pathname, &namelen, &basename, base, &base); if (error) return error; base->i_count++; /* lookup uses up base */ - error = lookup(base,basename,namelen,&inode); + error = lookup(base, basename, namelen, &inode); if (error) { iput(base); return error; } if (follow_links) { - error = follow_link(base,inode,0,0,&inode); + error = follow_link(base, inode, 0, 0, &inode); if (error) return error; } else @@ -283,14 +283,14 @@ return 0; } -int lnamei(const char * pathname, struct inode ** res_inode) +int lnamei(const char *pathname, struct inode **res_inode) { int error; char * tmp; - error = getname(pathname,&tmp); + error = getname(pathname, &tmp); if (!error) { - error = _namei(tmp,NULL,0,res_inode); + error = _namei(tmp, NULL, 0, res_inode); putname(tmp); } return error; @@ -303,14 +303,14 @@ * Open, link etc use their own routines, but this is enough for things * like 'chmod' etc. */ -int namei(const char * pathname, struct inode ** res_inode) +int namei(const char *pathname, struct inode **res_inode) { int error; char * tmp; - error = getname(pathname,&tmp); + error = getname(pathname, &tmp); if (!error) { - error = _namei(tmp,NULL,1,res_inode); + error = _namei(tmp, NULL, 1, res_inode); putname(tmp); } return error; @@ -330,7 +330,7 @@ * for symlinks (where the permissions are checked later). */ int open_namei(const char * pathname, int flag, int mode, - struct inode ** res_inode, struct inode * base) + struct inode ** res_inode, struct inode * base) { const char * basename; int namelen,error; @@ -338,7 +338,7 @@ mode &= S_IALLUGO & ~current->fs->umask; mode |= S_IFREG; - error = dir_namei(pathname,&namelen,&basename,base,&dir); + error = dir_namei(pathname, &namelen, &basename, base, &dir); if (error) return error; if (!namelen) { /* special case: '/usr/' etc */ @@ -357,7 +357,7 @@ dir->i_count++; /* lookup eats the dir */ if (flag & O_CREAT) { down(&dir->i_sem); - error = lookup(dir,basename,namelen,&inode); + error = lookup(dir, basename, namelen, &inode); if (!error) { if (flag & O_EXCL) { iput(inode); @@ -371,14 +371,16 @@ error = -EROFS; else { dir->i_count++; /* create eats the dir */ - error = dir->i_op->create(dir,basename,namelen,mode,res_inode); + if (dir->i_sb->dq_op) + dir->i_sb->dq_op->initialize(dir, -1); + error = dir->i_op->create(dir, basename, namelen, mode, res_inode); up(&dir->i_sem); iput(dir); return error; } up(&dir->i_sem); } else - error = lookup(dir,basename,namelen,&inode); + error = lookup(dir, basename, namelen, &inode); if (error) { iput(dir); return error; @@ -409,7 +411,7 @@ /* * An append-only file must be opened in append mode for writing */ - if (IS_APPEND(inode) && ((flag & 2) && !(flag & O_APPEND))) { + if (IS_APPEND(inode) && ((flag & FMODE_WRITE) && !(flag & O_APPEND))) { iput(inode); return -EPERM; } @@ -420,6 +422,8 @@ iput(inode); return error; } + if (inode->i_sb->dq_op) + inode->i_sb->dq_op->initialize(inode, -1); newattrs.ia_size = 0; newattrs.ia_valid = ATTR_SIZE; if ((error = notify_change(inode, &newattrs))) { @@ -434,7 +438,10 @@ up(&inode->i_sem); inode->i_dirt = 1; put_write_access(inode); - } + } else + if (flag & FMODE_WRITE) + if (inode->i_sb->dq_op) + inode->i_sb->dq_op->initialize(inode, -1); *res_inode = inode; return 0; } @@ -446,7 +453,7 @@ struct inode * dir; mode &= ~current->fs->umask; - error = dir_namei(filename,&namelen,&basename, NULL, &dir); + error = dir_namei(filename, &namelen, &basename, NULL, &dir); if (error) return error; if (!namelen) { @@ -466,6 +473,8 @@ return -EPERM; } dir->i_count++; + if (dir->i_sb->dq_op) + dir->i_sb->dq_op->initialize(dir, -1); down(&dir->i_sem); error = dir->i_op->mknod(dir,basename,namelen,mode,dev); up(&dir->i_sem); @@ -503,7 +512,7 @@ int namelen, error; struct inode * dir; - error = dir_namei(pathname,&namelen,&basename,NULL,&dir); + error = dir_namei(pathname, &namelen, &basename, NULL, &dir); if (error) return error; if (!namelen) { @@ -523,6 +532,8 @@ return -EPERM; } dir->i_count++; + if (dir->i_sb->dq_op) + dir->i_sb->dq_op->initialize(dir, -1); down(&dir->i_sem); error = dir->i_op->mkdir(dir, basename, namelen, mode & 0777 & ~current->fs->umask); up(&dir->i_sem); @@ -549,7 +560,7 @@ int namelen, error; struct inode * dir; - error = dir_namei(name,&namelen,&basename,NULL,&dir); + error = dir_namei(name, &namelen, &basename, NULL, &dir); if (error) return error; if (!namelen) { @@ -575,6 +586,8 @@ iput(dir); return -EPERM; } + if (dir->i_sb->dq_op) + dir->i_sb->dq_op->initialize(dir, -1); return dir->i_op->rmdir(dir,basename,namelen); } @@ -597,7 +610,7 @@ int namelen, error; struct inode * dir; - error = dir_namei(name,&namelen,&basename,NULL,&dir); + error = dir_namei(name, &namelen, &basename, NULL, &dir); if (error) return error; if (!namelen) { @@ -623,6 +636,8 @@ iput(dir); return -EPERM; } + if (dir->i_sb->dq_op) + dir->i_sb->dq_op->initialize(dir, -1); return dir->i_op->unlink(dir,basename,namelen); } @@ -645,7 +660,7 @@ const char * basename; int namelen, error; - error = dir_namei(newname,&namelen,&basename,NULL,&dir); + error = dir_namei(newname, &namelen, &basename, NULL, &dir); if (error) return error; if (!namelen) { @@ -665,6 +680,8 @@ return -EPERM; } dir->i_count++; + if (dir->i_sb->dq_op) + dir->i_sb->dq_op->initialize(dir, -1); down(&dir->i_sem); error = dir->i_op->symlink(dir,basename,namelen,oldname); up(&dir->i_sem); @@ -695,7 +712,7 @@ const char * basename; int namelen, error; - error = dir_namei(newname,&namelen,&basename,NULL,&dir); + error = dir_namei(newname, &namelen, &basename, NULL, &dir); if (error) { iput(oldinode); return error; @@ -734,6 +751,8 @@ return -EPERM; } dir->i_count++; + if (dir->i_sb->dq_op) + dir->i_sb->dq_op->initialize(dir, -1); down(&dir->i_sem); error = dir->i_op->link(oldinode, dir, basename, namelen); up(&dir->i_sem); @@ -766,7 +785,7 @@ const char * old_base, * new_base; int old_len, new_len, error; - error = dir_namei(oldname,&old_len,&old_base,NULL,&old_dir); + error = dir_namei(oldname, &old_len, &old_base, NULL, &old_dir); if (error) return error; if ((error = permission(old_dir,MAY_WRITE | MAY_EXEC)) != 0) { @@ -779,7 +798,7 @@ iput(old_dir); return -EPERM; } - error = dir_namei(newname,&new_len,&new_base,NULL,&new_dir); + error = dir_namei(newname, &new_len, &new_base, NULL, &new_dir); if (error) { iput(old_dir); return error; @@ -820,6 +839,8 @@ return -EPERM; } new_dir->i_count++; + if (new_dir->i_sb->dq_op) + new_dir->i_sb->dq_op->initialize(new_dir, -1); down(&new_dir->i_sem); error = old_dir->i_op->rename(old_dir, old_base, old_len, new_dir, new_base, new_len); diff -u --recursive --new-file v1.3.45/linux/fs/open.c linux/fs/open.c --- v1.3.45/linux/fs/open.c Mon Nov 27 12:48:32 1995 +++ linux/fs/open.c Mon Dec 11 06:56:36 1995 @@ -122,7 +122,7 @@ return -EBADF; if (!(inode = file->f_inode)) return -ENOENT; - if (S_ISDIR(inode->i_mode) || !(file->f_mode & 2)) + if (S_ISDIR(inode->i_mode) || !(file->f_mode & FMODE_WRITE)) return -EACCES; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) return -EPERM; @@ -481,7 +481,7 @@ error = open_namei(filename,flag,mode,&inode,NULL); if (error) goto cleanup_file; - if (f->f_mode & 2) { + if (f->f_mode & FMODE_WRITE) { error = get_write_access(inode); if (error) goto cleanup_inode; @@ -516,7 +516,7 @@ if (f->f_op && f->f_op->release) f->f_op->release(inode,f); cleanup_all: - if (f->f_mode & 2) + if (f->f_mode & FMODE_WRITE) put_write_access(inode); cleanup_inode: iput(inode); @@ -562,7 +562,8 @@ filp->f_op->release(inode,filp); filp->f_count--; filp->f_inode = NULL; - if (filp->f_mode & 2) put_write_access(inode); + if (filp->f_mode & FMODE_WRITE) + put_write_access(inode); iput(inode); return 0; } diff -u --recursive --new-file v1.3.45/linux/fs/proc/array.c linux/fs/proc/array.c --- v1.3.45/linux/fs/proc/array.c Tue Nov 21 13:22:12 1995 +++ linux/fs/proc/array.c Mon Dec 11 09:55:42 1995 @@ -41,6 +41,9 @@ #include #include #include +#ifdef CONFIG_APM +#include +#endif #include #include @@ -457,7 +460,7 @@ if (tsk->state < 0 || tsk->state > 5) state = '.'; else - state = "RSDZTD"[tsk->state]; + state = "RSDZTW"[tsk->state]; vsize = eip = esp = 0; if (tsk->mm) { struct vm_area_struct *vma = tsk->mm->mmap; @@ -820,6 +823,10 @@ case PROC_IOPORTS: return get_ioport_list(page); +#ifdef CONFIG_APM + case PROC_APM: + return apm_proc(page); +#endif } return -EBADF; } diff -u --recursive --new-file v1.3.45/linux/fs/proc/inode.c linux/fs/proc/inode.c --- v1.3.45/linux/fs/proc/inode.c Wed Nov 8 07:11:37 1995 +++ linux/fs/proc/inode.c Mon Dec 11 06:56:36 1995 @@ -66,7 +66,7 @@ if (*value) return 0; } - else return 0; + else return 1; } return 1; } diff -u --recursive --new-file v1.3.45/linux/fs/proc/root.c linux/fs/proc/root.c --- v1.3.45/linux/fs/proc/root.c Mon Sep 25 12:26:23 1995 +++ linux/fs/proc/root.c Mon Dec 11 09:55:42 1995 @@ -13,6 +13,9 @@ #include #include #include +#ifdef CONFIG_APM +#include +#endif /* * Offset of the first process in the /proc root directory.. @@ -293,7 +296,13 @@ PROC_IOPORTS, 7, "ioports", S_IFREG | S_IRUGO, 1, 0, 0, }); - +#ifdef CONFIG_APM + proc_register(&proc_root, &(struct proc_dir_entry) { + PROC_APM, 3, "apm", + S_IFREG | S_IRUGO, 1, 0, 0, + }); +#endif + if (prof_shift) { proc_register(&proc_root, &(struct proc_dir_entry) { PROC_PROFILE, 7, "profile", diff -u --recursive --new-file v1.3.45/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c --- v1.3.45/linux/fs/smbfs/dir.c Sat Nov 11 17:41:34 1995 +++ linux/fs/smbfs/dir.c Mon Dec 11 06:56:36 1995 @@ -874,7 +874,6 @@ if ((error = smb_proc_unlink(SMB_SERVER(dir), path, len)) == 0) smb_invalid_dir_cache(dir->i_ino); } - iput(dir); return error; } diff -u --recursive --new-file v1.3.45/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c --- v1.3.45/linux/fs/smbfs/proc.c Sat Nov 11 17:41:34 1995 +++ linux/fs/smbfs/proc.c Mon Dec 11 08:49:35 1995 @@ -264,7 +264,7 @@ { return (SMB_CMD(packet) == command && SMB_WCT(packet) >= wct && - (bcc == -1 || SMB_BCC(packet) == bcc)) ? 0 : -EIO; + (bcc == -1 || SMB_BCC(packet) >= bcc)) ? 0 : -EIO; } static int @@ -1139,7 +1139,8 @@ smb_proc_readdir_long(struct smb_server *server, struct inode *dir, int fpos, int cache_size, struct smb_dirent *entry) { - int max_matches = 512; + int max_matches = 64; /* this should actually be based on the + maxxmit */ /* NT uses 260, OS/2 uses 2. Both accept 1. */ int info_level = 1; @@ -1600,6 +1601,10 @@ #ifdef LANMAN2 { PROTOCOL_LANMAN2,"LM1.2X002"}, #endif +#ifdef NT1 + { PROTOCOL_NT1,"NT LM 0.12"}, + { PROTOCOL_NT1,"NT LANMAN 1.0"}, +#endif {-1, NULL} }; char dev[] = "A:"; int i, plength; @@ -1712,29 +1717,70 @@ DPRINTK("smb_proc_connect: blkmode = %d\n", WVAL(server->packet, smb_vwv5)); - server->maxxmt = WVAL(server->packet, smb_vwv2); - server->maxmux = WVAL(server->packet, smb_vwv3); - server->maxvcs = WVAL(server->packet, smb_vwv4); - server->blkmode= WVAL(server->packet, smb_vwv5); - server->sesskey= DVAL(server->packet, smb_vwv6); - - smb_setup_header(server, SMBsesssetupX, 10, - 2 + userlen + passlen); - - WSET(server->packet, smb_vwv0, 0x00ff); - WSET(server->packet, smb_vwv1, 0); - WSET(server->packet, smb_vwv2, given_max_xmit); - WSET(server->packet, smb_vwv3, 2); - WSET(server->packet, smb_vwv4, server->pid); - DSET(server->packet, smb_vwv5, server->sesskey); - WSET(server->packet, smb_vwv7, passlen + 1); - WSET(server->packet, smb_vwv8, 0); - WSET(server->packet, smb_vwv9, 0); - - p = SMB_BUF(server->packet); - strcpy(p, server->m.password); - p += passlen + 1; - strcpy(p, server->m.username); + if (server->protocol >= PROTOCOL_NT1) { + server->maxxmt = DVAL(server->packet,smb_vwv3+1); + server->maxmux = WVAL(server->packet, smb_vwv1+1); + server->maxvcs = WVAL(server->packet, smb_vwv2+1); + server->blkmode= DVAL(server->packet, smb_vwv9+1); + server->sesskey= DVAL(server->packet, smb_vwv7+1); + } else { + server->maxxmt = WVAL(server->packet, smb_vwv2); + server->maxmux = WVAL(server->packet, smb_vwv3); + server->maxvcs = WVAL(server->packet, smb_vwv4); + server->blkmode= WVAL(server->packet, smb_vwv5); + server->sesskey= DVAL(server->packet, smb_vwv6); + } + + + if (server->protocol >= PROTOCOL_NT1) { + char *workgroup = "WORKGROUP"; + char *OS_id = "Unix"; + char *client_id = "ksmbfs"; + + smb_setup_header(server, SMBsesssetupX, 13, + 5 + userlen + passlen + + strlen(workgroup) + strlen(OS_id) + + strlen(client_id)); + + WSET(server->packet, smb_vwv0, 0x00ff); + WSET(server->packet, smb_vwv1, 0); + WSET(server->packet, smb_vwv2, given_max_xmit); + WSET(server->packet, smb_vwv3, 2); + WSET(server->packet, smb_vwv4, server->pid); + DSET(server->packet, smb_vwv5, server->sesskey); + WSET(server->packet, smb_vwv7, passlen + 1); + WSET(server->packet, smb_vwv8, 0); + WSET(server->packet, smb_vwv9, 0); + + p = SMB_BUF(server->packet); + strcpy(p, server->m.password); + p += passlen + 1; + strcpy(p, server->m.username); + p += userlen + 1; + strcpy(p, workgroup); + p += strlen(p) + 1; + strcpy(p, OS_id); + p += strlen(p) + 1; + strcpy(p, client_id); + } else { + smb_setup_header(server, SMBsesssetupX, 10, + 2 + userlen + passlen); + + WSET(server->packet, smb_vwv0, 0x00ff); + WSET(server->packet, smb_vwv1, 0); + WSET(server->packet, smb_vwv2, given_max_xmit); + WSET(server->packet, smb_vwv3, 2); + WSET(server->packet, smb_vwv4, server->pid); + DSET(server->packet, smb_vwv5, server->sesskey); + WSET(server->packet, smb_vwv7, passlen + 1); + WSET(server->packet, smb_vwv8, 0); + WSET(server->packet, smb_vwv9, 0); + + p = SMB_BUF(server->packet); + strcpy(p, server->m.password); + p += passlen + 1; + strcpy(p, server->m.username); + } if ((result = smb_request_ok(server,SMBsesssetupX,3,0)) < 0) { DPRINTK("smb_proc_connect: SMBsessetupX failed\n"); diff -u --recursive --new-file v1.3.45/linux/fs/super.c linux/fs/super.c --- v1.3.45/linux/fs/super.c Fri Nov 17 08:42:28 1995 +++ linux/fs/super.c Mon Dec 11 07:46:21 1995 @@ -2,18 +2,22 @@ * linux/fs/super.c * * Copyright (C) 1991, 1992 Linus Torvalds - */ - -/* - * super.c contains code to handle the super-block tables. + * + * super.c contains code to handle: - mount structures + * - super-block tables. + * - mount systemcall + * - umount systemcall * * GK 2/5/95 - Changed to support mounting the root fs via NFS */ + #include #include #include #include +#include +#include #include #include #include @@ -32,8 +36,6 @@ extern int root_mountflags; -struct super_block super_blocks[NR_SUPER]; - static int do_remount_sb(struct super_block *sb, int flags, char * data); #ifdef CONFIG_ROOT_NFS @@ -43,24 +45,118 @@ /* this is initialized in init/main.c */ kdev_t ROOT_DEV; -static struct file_system_type * file_systems = NULL; +struct super_block super_blocks[NR_SUPER]; +static struct file_system_type *file_systems = (struct file_system_type *) NULL; +static struct vfsmount *vfsmntlist = (struct vfsmount *) NULL, + *vfsmnttail = (struct vfsmount *) NULL, + *mru_vfsmnt = (struct vfsmount *) NULL; -int register_filesystem(struct file_system_type * fs) +/* + * This part handles the management of the list of mounted filesystems. + */ +struct vfsmount *lookup_vfsmnt(kdev_t dev) { - struct file_system_type ** tmp; + struct vfsmount *lptr; - if (!fs) - return -EINVAL; - if (fs->next) - return -EBUSY; - tmp = &file_systems; - while (*tmp) { - if (strcmp((*tmp)->name, fs->name) == 0) - return -EBUSY; - tmp = &(*tmp)->next; + if (vfsmntlist == (struct vfsmount *)NULL) + return ((struct vfsmount *)NULL); + + if (mru_vfsmnt != (struct vfsmount *)NULL && + mru_vfsmnt->mnt_dev == dev) + return (mru_vfsmnt); + + for (lptr = vfsmntlist; + lptr != (struct vfsmount *)NULL; + lptr = lptr->mnt_next) + if (lptr->mnt_dev == dev) { + mru_vfsmnt = lptr; + return (lptr); + } + + return ((struct vfsmount *)NULL); + /* NOTREACHED */ +} + +struct vfsmount *add_vfsmnt(kdev_t dev, const char *dev_name, const char *dir_name) +{ + struct vfsmount *lptr; + char *tmp; + + if ((lptr = (struct vfsmount *) + kmalloc(sizeof(struct vfsmount), GFP_KERNEL)) == (struct vfsmount *)NULL) + return ((struct vfsmount *)NULL); + memset(lptr, 0, sizeof(struct vfsmount)); + + lptr->mnt_dev = dev; + lptr->mnt_sem.count = 1; + if (dev_name && !getname(dev_name, &tmp)) { + if ((lptr->mnt_devname = + (char *) kmalloc(strlen(tmp), GFP_KERNEL)) != (char *)NULL) + strcpy(lptr->mnt_devname, tmp); + putname(tmp); } - *tmp = fs; - return 0; + if (dir_name && !getname(dir_name, &tmp)) { + if ((lptr->mnt_dirname = + (char *) kmalloc(strlen(tmp), GFP_KERNEL)) != (char *)NULL) + strcpy(lptr->mnt_dirname, tmp); + putname(tmp); + } + + if (vfsmntlist == (struct vfsmount *)NULL) { + vfsmntlist = vfsmnttail = lptr; + } else { + vfsmnttail->mnt_next = lptr; + vfsmnttail = lptr; + } + return (lptr); +} + +void remove_vfsmnt(kdev_t dev) +{ + struct vfsmount *lptr, *tofree; + + if (vfsmntlist == (struct vfsmount *)NULL) + return; + lptr = vfsmntlist; + if (lptr->mnt_dev == dev) { + tofree = lptr; + vfsmntlist = lptr->mnt_next; + if (vfsmnttail->mnt_dev == dev) + vfsmnttail = vfsmntlist; + } else { + while (lptr->mnt_next != (struct vfsmount *)NULL) { + if (lptr->mnt_next->mnt_dev == dev) + break; + lptr = lptr->mnt_next; + } + tofree = lptr->mnt_next; + if (tofree == (struct vfsmount *)NULL) + return; + lptr->mnt_next = lptr->mnt_next->mnt_next; + if (vfsmnttail->mnt_dev == dev) + vfsmnttail = lptr; + } + kfree(tofree->mnt_devname); + kfree(tofree->mnt_dirname); + kfree_s(tofree, sizeof(struct vfsmount)); +} + +int register_filesystem(struct file_system_type * fs) +{ + struct file_system_type ** tmp; + + if (!fs) + return -EINVAL; + if (fs->next) + return -EBUSY; + tmp = &file_systems; + while (*tmp) { + if (strcmp((*tmp)->name, fs->name) == 0) + return -EBUSY; + tmp = &(*tmp)->next; + } + *tmp = fs; + return 0; } int unregister_filesystem(struct file_system_type * fs) @@ -364,11 +460,20 @@ int retval; if (dev==ROOT_DEV) { - /* Special case for "unmounting" root. We just try to remount - it readonly, and sync() the device. */ + /* + * Special case for "unmounting" root. We just try to remount + * it readonly, and sync() the device. + */ if (!(sb=get_super(dev))) return -ENOENT; if (!(sb->s_flags & MS_RDONLY)) { + /* + * Make sure all quotas are turned off on this device we need to mount + * it readonly so no more writes by the quotasystem. + * If later on the remount fails to bad there are no quotas running + * anymore. Turn them on again by hand. + */ + quota_off(dev, -1); fsync_dev(dev); retval = do_remount_sb(sb, MS_RDONLY, 0); if (retval) @@ -381,6 +486,12 @@ if (!sb->s_covered->i_mount) printk("VFS: umount(%s): mounted inode has i_mount=NULL\n", kdevname(dev)); + /* + * Before checking if the filesystem is still busy make sure the kernel + * doesn't hold any quotafiles open on that device. If the umount fails + * to bad there are no quotas running anymore. Turn them on again by hand. + */ + quota_off(dev, -1); if (!fs_may_umount(dev, sb->s_mounted)) return -EBUSY; sb->s_covered->i_mount = NULL; @@ -391,6 +502,7 @@ if (sb->s_op && sb->s_op->write_super && sb->s_dirt) sb->s_op->write_super(sb); put_super(dev); + remove_vfsmnt(dev); return 0; } @@ -415,9 +527,9 @@ if (!suser()) return -EPERM; - retval = namei(name,&inode); + retval = namei(name, &inode); if (retval) { - retval = lnamei(name,&inode); + retval = lnamei(name, &inode); if (retval) return retval; } @@ -466,13 +578,15 @@ * We also have to flush all inode-data for this device, as the new mount * might need new info. */ -int do_mount(kdev_t dev, const char * dir, const char * type, int flags, void * data) + +int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const char * type, int flags, void * data) { struct inode * dir_i; struct super_block * sb; + struct vfsmount *vfsmnt; int error; - error = namei(dir,&dir_i); + error = namei(dir_name, &dir_i); if (error) return error; if (dir_i->i_count != 1 || dir_i->i_mount) { @@ -496,6 +610,8 @@ iput(dir_i); return -EBUSY; } + vfsmnt = add_vfsmnt(dev, dev_name, dir_name); + vfsmnt->mnt_sb = sb; sb->s_covered = dir_i; dir_i->i_mount = sb->s_mounted; return 0; /* we don't iput(dir_i) - see umount */ @@ -534,7 +650,7 @@ struct inode *dir_i; int retval; - retval = namei(dir,&dir_i); + retval = namei(dir, &dir_i); if (retval) return retval; if (dir_i != dir_i->i_sb->s_mounted) { @@ -619,7 +735,7 @@ t = fstype->name; fops = NULL; if (fstype->requires_dev) { - retval = namei(dev_name,&inode); + retval = namei(dev_name, &inode); if (retval) return retval; if (!S_ISBLK(inode->i_mode)) { @@ -666,7 +782,7 @@ return retval; } } - retval = do_mount(dev,dir_name,t,flags,(void *) page); + retval = do_mount(dev,dev_name,dir_name,t,flags,(void *) page); free_page(page); if (retval && fops && fops->release) fops->release(inode, NULL); @@ -678,10 +794,11 @@ { struct file_system_type * fs_type; struct super_block * sb; + struct vfsmount *vfsmnt; struct inode * inode, d_inode; struct file filp; int retval; - + memset(super_blocks, 0, sizeof(super_blocks)); #ifdef CONFIG_ROOT_NFS if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) { @@ -737,9 +854,9 @@ for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) { if(retval) break; - if (!fs_type->requires_dev) - continue; - sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1); + if (!fs_type->requires_dev) + continue; + sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1); if (sb) { inode = sb->s_mounted; inode->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */ @@ -750,6 +867,8 @@ printk ("VFS: Mounted root (%s filesystem)%s.\n", fs_type->name, (sb->s_flags & MS_RDONLY) ? " readonly" : ""); + vfsmnt = add_vfsmnt(ROOT_DEV, "rootfs", "/"); + vfsmnt->mnt_sb = sb; return; } } diff -u --recursive --new-file v1.3.45/linux/include/asm-alpha/mman.h linux/include/asm-alpha/mman.h --- v1.3.45/linux/include/asm-alpha/mman.h Tue Nov 21 13:22:12 1995 +++ linux/include/asm-alpha/mman.h Mon Dec 11 09:07:22 1995 @@ -30,4 +30,8 @@ #define MCL_CURRENT 8192 /* lock all currently mapped pages */ #define MCL_FUTURE 16384 /* lock all additions to address space */ +/* compatibility flags */ +#define MAP_ANON MAP_ANONYMOUS +#define MAP_FILE 0 + #endif /* __ALPHA_MMAN_H__ */ diff -u --recursive --new-file v1.3.45/linux/include/asm-alpha/page.h linux/include/asm-alpha/page.h --- v1.3.45/linux/include/asm-alpha/page.h Tue Nov 21 13:22:12 1995 +++ linux/include/asm-alpha/page.h Fri Dec 1 07:19:29 1995 @@ -48,24 +48,6 @@ #endif -#define invalidate_all() \ -__asm__ __volatile__( \ - "lda $16,-2($31)\n\t" \ - ".long 51" \ - : : :"$1", "$16", "$17", "$22","$23","$24","$25") - -#define invalidate() \ -__asm__ __volatile__( \ - "lda $16,-1($31)\n\t" \ - ".long 51" \ - : : :"$1", "$16", "$17", "$22","$23","$24","$25") - -/* Certain architectures need to do special things when pte's - * within a page table are directly modified. Thus, the following - * hook is made available. - */ -#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval)) - /* to align the pointer to the (next) page boundary */ #define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) diff -u --recursive --new-file v1.3.45/linux/include/asm-alpha/pgtable.h linux/include/asm-alpha/pgtable.h --- v1.3.45/linux/include/asm-alpha/pgtable.h Mon Sep 25 12:26:23 1995 +++ linux/include/asm-alpha/pgtable.h Fri Dec 1 07:19:29 1995 @@ -9,6 +9,24 @@ * in (currently 8192). */ +#define invalidate_all() \ +__asm__ __volatile__( \ + "lda $16,-2($31)\n\t" \ + ".long 51" \ + : : :"$1", "$16", "$17", "$22","$23","$24","$25") + +#define invalidate() \ +__asm__ __volatile__( \ + "lda $16,-1($31)\n\t" \ + ".long 51" \ + : : :"$1", "$16", "$17", "$22","$23","$24","$25") + +/* Certain architectures need to do special things when pte's + * within a page table are directly modified. Thus, the following + * hook is made available. + */ +#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval)) + /* PMD_SHIFT determines the size of the area a second-level page table can map */ #define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT-3)) #define PMD_SIZE (1UL << PMD_SHIFT) diff -u --recursive --new-file v1.3.45/linux/include/asm-alpha/socket.h linux/include/asm-alpha/socket.h --- v1.3.45/linux/include/asm-alpha/socket.h Tue Jul 11 10:02:59 1995 +++ linux/include/asm-alpha/socket.h Tue Nov 28 08:32:43 1995 @@ -40,5 +40,6 @@ /* linux-specific, might as well be the same as on i386 */ #define SO_NO_CHECK 11 #define SO_PRIORITY 12 +#define SO_BSDCOMPAT 14 #endif /* _ASM_SOCKET_H */ diff -u --recursive --new-file v1.3.45/linux/include/asm-alpha/unistd.h linux/include/asm-alpha/unistd.h --- v1.3.45/linux/include/asm-alpha/unistd.h Sun Oct 29 11:38:49 1995 +++ linux/include/asm-alpha/unistd.h Mon Dec 11 06:56:36 1995 @@ -100,6 +100,7 @@ #define __NR_getrlimit 144 #define __NR_setrlimit 145 #define __NR_setsid 147 +#define __NR_quotactl 148 #define __NR_getsockname 150 #define __NR_sigaction 156 #define __NR_msgctl 200 diff -u --recursive --new-file v1.3.45/linux/include/asm-i386/bitops.h linux/include/asm-i386/bitops.h --- v1.3.45/linux/include/asm-i386/bitops.h Mon Nov 27 12:48:32 1995 +++ linux/include/asm-i386/bitops.h Tue Nov 28 07:41:45 1995 @@ -64,7 +64,7 @@ */ extern __inline__ int test_bit(int nr, const void * addr) { - return 1UL & (((unsigned int *) addr)[nr >> 5] >> (nr & 31)); + return 1UL & (((const unsigned int *) addr)[nr >> 5] >> (nr & 31)); } /* diff -u --recursive --new-file v1.3.45/linux/include/asm-i386/mman.h linux/include/asm-i386/mman.h --- v1.3.45/linux/include/asm-i386/mman.h Tue Nov 21 13:22:13 1995 +++ linux/include/asm-i386/mman.h Mon Dec 11 09:06:30 1995 @@ -24,4 +24,8 @@ #define MCL_CURRENT 1 /* lock all current mappings */ #define MCL_FUTURE 2 /* lock all future mappings */ +/* compatibility flags */ +#define MAP_ANON MAP_ANONYMOUS +#define MAP_FILE 0 + #endif /* __I386_MMAN_H__ */ diff -u --recursive --new-file v1.3.45/linux/include/asm-i386/page.h linux/include/asm-i386/page.h --- v1.3.45/linux/include/asm-i386/page.h Tue Nov 21 13:22:13 1995 +++ linux/include/asm-i386/page.h Thu Nov 30 14:12:41 1995 @@ -50,41 +50,6 @@ #endif -/* - * TLB invalidation: - * - * - invalidate() invalidates the current task TLBs - * - invalidate_all() invalidates all processes TLBs - * - invalidate_task(task) invalidates the specified tasks TLB's - * - invalidate_page(task, vmaddr) invalidates one page - * - * ..but the i386 has somewhat limited invalidation capabilities. - */ - -#ifndef __SMP__ -#define invalidate() \ -__asm__ __volatile__("movl %%cr3,%%eax\n\tmovl %%eax,%%cr3": : :"ax") - -#define invalidate_all() invalidate() -#define invalidate_task(task) \ -do { if ((task)->mm == current->mm) invalidate(); } while (0) -#define invalidate_page(task,addr) \ -do { if ((task)->mm == current->mm) invalidate(); } while (0) - -#else -#include -#define local_invalidate() \ -__asm__ __volatile__("movl %%cr3,%%eax\n\tmovl %%eax,%%cr3": : :"ax") -#define invalidate() \ - smp_invalidate(); -#endif - -/* Certain architectures need to do special things when pte's - * within a page table are directly modified. Thus, the following - * hook is made available. - */ -#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval)) - /* to align the pointer to the (next) page boundary */ #define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) diff -u --recursive --new-file v1.3.45/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h --- v1.3.45/linux/include/asm-i386/pgtable.h Wed Nov 8 07:11:41 1995 +++ linux/include/asm-i386/pgtable.h Thu Nov 30 14:12:41 1995 @@ -17,6 +17,48 @@ * the i386 page table tree. */ +/* + * TLB invalidation: + * + * - invalidate() invalidates the current mm struct TLBs + * - invalidate_all() invalidates all processes TLBs + * - invalidate_mm(mm) invalidates the specified mm context TLB's + * - invalidate_page(mm, vmaddr) invalidates one page + * - invalidate_range(mm, start, end) invalidates a range of pages + * + * ..but the i386 has somewhat limited invalidation capabilities. + */ + +#ifndef __SMP__ +#define invalidate() \ +__asm__ __volatile__("movl %%cr3,%%eax\n\tmovl %%eax,%%cr3": : :"ax") +#else +#include +#define local_invalidate() \ +__asm__ __volatile__("movl %%cr3,%%eax\n\tmovl %%eax,%%cr3": : :"ax") +#define invalidate() \ + smp_invalidate(); +#endif + +/* + * We aren't very clever about this yet. On a 486+ we could actually do + * page-granularity invalidates for better performance in some cases. + * And SMP could certainly avoid some global invalidates.. + */ +#define invalidate_all() invalidate() +#define invalidate_mm(mm_struct) \ +do { if ((mm_struct) == current->mm) invalidate(); } while (0) +#define invalidate_page(mm_struct,addr) \ +do { if ((mm_struct) == current->mm) invalidate(); } while (0) +#define invalidate_range(mm_struct,start,end) \ +do { if ((mm_struct) == current->mm) invalidate(); } while (0) + +/* Certain architectures need to do special things when pte's + * within a page table are directly modified. Thus, the following + * hook is made available. + */ +#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval)) + /* PMD_SHIFT determines the size of the area a second-level page table can map */ #define PMD_SHIFT 22 #define PMD_SIZE (1UL << PMD_SHIFT) diff -u --recursive --new-file v1.3.45/linux/include/linux/apm_bios.h linux/include/linux/apm_bios.h --- v1.3.45/linux/include/linux/apm_bios.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/apm_bios.h Mon Dec 11 09:55:42 1995 @@ -0,0 +1,140 @@ +#ifndef _LINUX_APM_H +#define _LINUX_APM_H + +/* + * Include file for the interface to an APM BIOS + * Copyright 1994, 1995 Stephen Rothwell (Stephen.Rothwell@pd.necisa.oz.au) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * $Id: apm_bios.h,v 0.9 1995/03/09 13:50:05 sfr Exp $ + */ + +typedef unsigned short apm_event_t; + +#ifdef __KERNEL__ + +#include /* for NR_TASKS */ +#include /* for _TSS */ + +#define APM_CS _TSS(NR_TASKS) +#define APM_CS_16 (APM_CS + 8) +#define APM_DS (APM_CS_16 + 8) + +struct apm_bios_info { + unsigned short version; + unsigned short cseg; + unsigned long offset; + unsigned short cseg_16; + unsigned short dseg; + unsigned short flags; + unsigned short cseg_len; + unsigned short dseg_len; +}; + + /* Results of APM Installation Check */ +#define APM_16_BIT_SUPPORT 0x0001 +#define APM_32_BIT_SUPPORT 0x0002 +#define APM_IDLE_SLOWS_CLOCK 0x0004 +#define APM_BIOS_DISABLED 0x0008 +#define APM_BIOS_DISENGAGED 0x0010 + +/* + * Maximum number of events stored + */ +#define APM_MAX_EVENTS 20 + +/* + * The per-file APM data + */ +struct apm_bios_struct { + int magic; + struct apm_bios_struct * next; + int suser; + int suspends_pending; + int standbys_pending; + int event_head; + int event_tail; + apm_event_t events[APM_MAX_EVENTS]; +}; + +/* + * The magic number in apm_bios_struct + */ +#define APM_BIOS_MAGIC 0x4101 + +/* + * in init/main.c + */ +extern struct apm_bios_info apm_bios_info; + +extern void apm_bios_init(void); + +extern int apm_register_callback(int (*callback)(apm_event_t)); +extern void apm_unregister_callback(int (*callback)(apm_event_t)); + +extern int apm_proc(char *); + +extern int apm_display_blank(void); +extern int apm_display_unblank(void); + +#endif /* __KERNEL__ */ + +/* + * Power states + */ +#define APM_STATE_READY 0x0000 +#define APM_STATE_STANDBY 0x0001 +#define APM_STATE_SUSPEND 0x0002 +#define APM_STATE_OFF 0x0003 +#define APM_STATE_BUSY 0x0004 +#define APM_STATE_REJECT 0x0005 + +/* + * Events (results of Get PM Event) + */ +#define APM_SYS_STANDBY 0x0001 +#define APM_SYS_SUSPEND 0x0002 +#define APM_NORMAL_RESUME 0x0003 +#define APM_CRITICAL_RESUME 0x0004 +#define APM_LOW_BATTERY 0x0005 +#define APM_POWER_STATUS_CHANGE 0x0006 +#define APM_UPDATE_TIME 0x0007 +#define APM_CRITICAL_SUSPEND 0x0008 +#define APM_USER_STANDBY 0x0009 +#define APM_USER_SUSPEND 0x000a +#define APM_STANDBY_RESUME 0x000b + +/* + * Error codes + */ +#define APM_SUCCESS 0x00 +#define APM_DISABLED 0x01 +#define APM_CONNECTED 0x02 +#define APM_NOT_CONNECTED 0x03 +#define APM_16_CONNECTED 0x05 +#define APM_16_UNSUPPORTED 0x06 +#define APM_32_CONNECTED 0x07 +#define APM_32_UNSUPPORTED 0x08 +#define APM_BAD_DEVICE 0x09 +#define APM_BAD_PARAM 0x0a +#define APM_NOT_ENGAGED 0x0b +#define APM_BAD_STATE 0x60 +#define APM_NO_EVENTS 0x80 +#define APM_NOT_PRESENT 0x86 + +/* ioctl operations */ +#include + +#define APM_IOC_STANDBY _IO('A', 1) +#define APM_IOC_SUSPEND _IO('A', 2) + +#endif /* LINUX_APM_H */ diff -u --recursive --new-file v1.3.45/linux/include/linux/ax25.h linux/include/linux/ax25.h --- v1.3.45/linux/include/linux/ax25.h Wed Sep 27 16:00:00 1995 +++ linux/include/linux/ax25.h Thu Nov 30 11:15:53 1995 @@ -32,6 +32,12 @@ ax25_address digi_addr[AX25_MAX_DIGIS]; }; +struct ax25_bpqaddr_struct +{ + char dev[16]; + ax25_address addr; +}; + #define AX25_WINDOW 1 #define AX25_T1 2 #define AX25_N2 3 @@ -45,6 +51,7 @@ #define SIOCAX25ADDUID (SIOCPROTOPRIVATE+1) #define SIOCAX25DELUID (SIOCPROTOPRIVATE+2) #define SIOCAX25NOUID (SIOCPROTOPRIVATE+3) +#define SIOCAX25BPQADDR (SIOCPROTOPRIVATE+4) #define SIOCAX25GETPARMS (SIOCPROTOPRIVATE+5) #define SIOCAX25SETPARMS (SIOCPROTOPRIVATE+6) diff -u --recursive --new-file v1.3.45/linux/include/linux/blk.h linux/include/linux/blk.h --- v1.3.45/linux/include/linux/blk.h Mon Nov 27 12:48:36 1995 +++ linux/include/linux/blk.h Mon Dec 11 11:27:54 1995 @@ -336,7 +336,7 @@ #if ! SCSI_MAJOR(MAJOR_NR) -#if defined(_IDE_CD_C) || defined(_TRITON_C) /* shares copy with ide.c */ +#if defined(_IDE_CD_C) || defined(_TRITON_C) || defined(_IDE_TAPE_C) /* shares copy with ide.c */ void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup); #else @@ -375,6 +375,7 @@ } } #ifdef IDE_DRIVER + blk_dev[MAJOR(req->rq_dev)].current_request = req->next; hwgroup->rq = NULL; #else DEVICE_OFF(req->rq_dev); diff -u --recursive --new-file v1.3.45/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h --- v1.3.45/linux/include/linux/ext2_fs.h Sun Aug 13 14:45:35 1995 +++ linux/include/linux/ext2_fs.h Mon Dec 11 06:56:36 1995 @@ -404,9 +404,9 @@ extern int ext2_permission (struct inode *, int); /* balloc.c */ -extern int ext2_new_block (struct super_block *, unsigned long, - __u32 *, __u32 *); -extern void ext2_free_blocks (struct super_block *, unsigned long, +extern int ext2_new_block (const struct inode *, unsigned long, + __u32 *, __u32 *, int *); +extern void ext2_free_blocks (const struct inode *, unsigned long, unsigned long); extern unsigned long ext2_count_free_blocks (struct super_block *); extern void ext2_check_blocks_bitmap (struct super_block *); @@ -427,7 +427,7 @@ extern int ext2_sync_file (struct inode *, struct file *); /* ialloc.c */ -extern struct inode * ext2_new_inode (const struct inode *, int); +extern struct inode * ext2_new_inode (const struct inode *, int, int *); extern void ext2_free_inode (struct inode *); extern unsigned long ext2_count_free_inodes (struct super_block *); extern void ext2_check_inodes_bitmap (struct super_block *); diff -u --recursive --new-file v1.3.45/linux/include/linux/ext_fs.h linux/include/linux/ext_fs.h --- v1.3.45/linux/include/linux/ext_fs.h Mon Jun 12 16:49:41 1995 +++ linux/include/linux/ext_fs.h Mon Dec 11 06:56:36 1995 @@ -63,7 +63,7 @@ extern int ext_open(struct inode * inode, struct file * filp); extern void ext_release(struct inode * inode, struct file * filp); extern int ext_lookup(struct inode * dir,const char * name, int len, - struct inode ** result); + struct inode ** result); extern int ext_create(struct inode * dir,const char * name, int len, int mode, struct inode ** result); extern int ext_mkdir(struct inode * dir, const char * name, int len, int mode); diff -u --recursive --new-file v1.3.45/linux/include/linux/fs.h linux/include/linux/fs.h --- v1.3.45/linux/include/linux/fs.h Mon Nov 27 12:48:36 1995 +++ linux/include/linux/fs.h Mon Dec 11 06:56:37 1995 @@ -39,6 +39,9 @@ #define MAY_WRITE 2 #define MAY_READ 4 +#define FMODE_READ 1 +#define FMODE_WRITE 2 + #define READ 0 #define WRITE 1 #define READA 2 /* read-ahead - don't pause */ @@ -56,15 +59,15 @@ /* * These are the fs-independent mount-flags: up to 16 flags are supported */ -#define MS_RDONLY 1 /* mount read-only */ -#define MS_NOSUID 2 /* ignore suid and sgid bits */ -#define MS_NODEV 4 /* disallow access to device special files */ -#define MS_NOEXEC 8 /* disallow program execution */ -#define MS_SYNCHRONOUS 16 /* writes are synced at once */ -#define MS_REMOUNT 32 /* alter flags of a mounted FS */ - -#define S_APPEND 256 /* append-only file */ -#define S_IMMUTABLE 512 /* immutable file */ +#define MS_RDONLY 1 /* Mount read-only */ +#define MS_NOSUID 2 /* Ignore suid and sgid bits */ +#define MS_NODEV 4 /* Disallow access to device special files */ +#define MS_NOEXEC 8 /* Disallow program execution */ +#define MS_SYNCHRONOUS 16 /* Writes are synced at once */ +#define MS_REMOUNT 32 /* Alter flags of a mounted FS */ +#define S_WRITE 128 /* Write on file/directory/symlink */ +#define S_APPEND 256 /* Append-only file */ +#define S_IMMUTABLE 512 /* Immutable file */ /* * Flags that can be altered by MS_REMOUNT @@ -74,8 +77,8 @@ /* * Magic mount flag number. Has to be or-ed to the flag values. */ -#define MS_MGC_VAL 0xC0ED0000 /* magic flag number to indicate "new" flags */ -#define MS_MGC_MSK 0xffff0000 /* magic flag number mask */ +#define MS_MGC_VAL 0xC0ED0000 /* magic flag number to indicate "new" flags */ +#define MS_MGC_MSK 0xffff0000 /* magic flag number mask */ /* * Note that read-only etc flags are inode-specific: setting some file-system @@ -91,6 +94,7 @@ #define IS_NOEXEC(inode) ((inode)->i_flags & MS_NOEXEC) #define IS_SYNC(inode) ((inode)->i_flags & MS_SYNCHRONOUS) +#define IS_WRITABLE(inode) ((inode)->i_flags & S_WRITE) #define IS_APPEND(inode) ((inode)->i_flags & S_APPEND) #define IS_IMMUTABLE(inode) ((inode)->i_flags & S_IMMUTABLE) @@ -222,6 +226,8 @@ time_t ia_ctime; }; +#include + struct inode { kdev_t i_dev; unsigned long i_ino; @@ -238,17 +244,17 @@ unsigned long i_blocks; unsigned long i_version; struct semaphore i_sem; - struct inode_operations * i_op; - struct super_block * i_sb; - struct wait_queue * i_wait; - struct file_lock * i_flock; - struct vm_area_struct * i_mmap; - struct inode * i_next, * i_prev; - struct inode * i_hash_next, * i_hash_prev; - struct inode * i_bound_to, * i_bound_by; - struct inode * i_mount; + struct inode_operations *i_op; + struct super_block *i_sb; + struct wait_queue *i_wait; + struct file_lock *i_flock; + struct vm_area_struct *i_mmap; + struct dquot *i_dquot[MAXQUOTAS]; + struct inode *i_next, *i_prev; + struct inode *i_hash_next, *i_hash_prev; + struct inode *i_bound_to, *i_bound_by; + struct inode *i_mount; unsigned short i_count; - unsigned short i_wcount; unsigned short i_flags; unsigned char i_lock; unsigned char i_dirt; @@ -256,6 +262,7 @@ unsigned char i_sock; unsigned char i_seek; unsigned char i_update; + unsigned short i_writecount; union { struct pipe_inode_info pipe_i; struct minix_inode_info minix_i; @@ -330,6 +337,7 @@ unsigned char s_dirt; struct file_system_type *s_type; struct super_operations *s_op; + struct dquot_operations *dq_op; unsigned long s_flags; unsigned long s_magic; unsigned long s_time; @@ -404,6 +412,16 @@ int (*remount_fs) (struct super_block *, int *, char *); }; +struct dquot_operations { + void (*initialize) (struct inode *, short); + void (*drop) (struct inode *); + int (*alloc_block) (const struct inode *, unsigned long); + int (*alloc_inode) (const struct inode *, unsigned long); + void (*free_block) (const struct inode *, unsigned long); + void (*free_inode) (const struct inode *, unsigned long); + int (*transfer) (struct inode *, struct iattr *, char); +}; + struct file_system_type { struct super_block *(*read_super) (struct super_block *, void *, int); const char *name; @@ -510,8 +528,8 @@ extern int namei(const char * pathname, struct inode ** res_inode); extern int lnamei(const char * pathname, struct inode ** res_inode); extern int permission(struct inode * inode,int mask); -extern int get_write_access(struct inode * inode); -extern void put_write_access(struct inode * inode); +extern int get_write_access(struct inode *inode); +extern void put_write_access(struct inode *inode); extern int open_namei(const char * pathname, int flag, int mode, struct inode ** res_inode, struct inode * base); extern int do_mknod(const char * filename, int mode, dev_t dev); @@ -575,7 +593,7 @@ extern inline struct inode * iget(struct super_block * sb,int nr) { - return __iget(sb,nr,1); + return __iget(sb, nr, 1); } #endif /* __KERNEL__ */ diff -u --recursive --new-file v1.3.45/linux/include/linux/if.h linux/include/linux/if.h --- v1.3.45/linux/include/linux/if.h Tue Aug 15 20:39:04 1995 +++ linux/include/linux/if.h Thu Nov 30 11:15:53 1995 @@ -97,7 +97,6 @@ union { char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ - char ifrn_hwaddr[IFHWADDRLEN]; /* Obsolete */ } ifr_ifrn; union { @@ -116,7 +115,6 @@ }; #define ifr_name ifr_ifrn.ifrn_name /* interface name */ -#define old_ifr_hwaddr ifr_ifrn.ifrn_hwaddr /* interface hardware */ #define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ #define ifr_addr ifr_ifru.ifru_addr /* address */ #define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */ diff -u --recursive --new-file v1.3.45/linux/include/linux/igmp.h linux/include/linux/igmp.h --- v1.3.45/linux/include/linux/igmp.h Sat Nov 25 19:04:56 1995 +++ linux/include/linux/igmp.h Thu Nov 30 11:15:53 1995 @@ -2,7 +2,7 @@ * Linux NET3: Internet Gateway Management Protocol [IGMP] * * Authors: - * Alan Cox + * Alan Cox * * Extended to talk the BSD extended IGMP protocol of mrouted 3.6 * @@ -65,8 +65,8 @@ /* specifies time in 10th of seconds */ #define IGMP_AGE_THRESHOLD 540 /* If this host don't hear any IGMP V1 */ - /* message in this period of time, revert */ - /* to IGMP v2 router */ + /* message in this period of time, */ + /* revert to IGMP v2 router. */ #define IGMP_ALL_HOSTS htonl(0xE0000001L) #define IGMP_ALL_ROUTER htonl(0xE0000002L) @@ -94,12 +94,13 @@ int users; }; -struct router_info +struct ip_router_info { struct device *dev; - int type; /* type of router which is querier on this interface */ - int time; /* # of slow timeouts since last old query */ - struct router_info *next; + int type; /* type of router which is querier on this interface */ + int time; /* # of slow timeouts since last old query */ + struct timer_list timer; + struct ip_router_info *next; }; extern struct ip_mc_list *ip_mc_head; diff -u --recursive --new-file v1.3.45/linux/include/linux/iso_fs.h linux/include/linux/iso_fs.h --- v1.3.45/linux/include/linux/iso_fs.h Mon Jun 12 16:49:41 1995 +++ linux/include/linux/iso_fs.h Mon Dec 11 06:56:37 1995 @@ -167,7 +167,7 @@ extern int isofs_open(struct inode * inode, struct file * filp); extern void isofs_release(struct inode * inode, struct file * filp); extern int isofs_lookup(struct inode * dir,const char * name, int len, - struct inode ** result); + struct inode ** result); extern unsigned long isofs_count_free_inodes(struct super_block *sb); extern int isofs_new_block(int dev); extern int isofs_free_block(int dev, int block); diff -u --recursive --new-file v1.3.45/linux/include/linux/lp.h linux/include/linux/lp.h --- v1.3.45/linux/include/linux/lp.h Tue Oct 10 18:46:38 1995 +++ linux/include/linux/lp.h Thu Nov 30 14:03:38 1995 @@ -69,6 +69,7 @@ #define LPGETSTATUS 0x060b /* return LP_S(minor) */ #define LPRESET 0x060c /* reset printer */ #define LPGETSTATS 0x060d /* get statistics (struct lp_stats) */ +#define LPGETFLAGS 0x060e /* get status flags */ /* timeout for printk'ing a timeout, in jiffies (100ths of a second). This is also used for re-checking error conditions if LP_ABORT is diff -u --recursive --new-file v1.3.45/linux/include/linux/major.h linux/include/linux/major.h --- v1.3.45/linux/include/linux/major.h Fri Nov 17 08:42:28 1995 +++ linux/include/linux/major.h Mon Dec 11 08:49:53 1995 @@ -99,6 +99,7 @@ #define IDE2_MAJOR 33 #define IDE3_MAJOR 34 #define NETLINK_MAJOR 36 +#define IDETAPE_MAJOR 37 /* * Tests for SCSI devices. diff -u --recursive --new-file v1.3.45/linux/include/linux/minix_fs.h linux/include/linux/minix_fs.h --- v1.3.45/linux/include/linux/minix_fs.h Mon Jun 12 16:49:42 1995 +++ linux/include/linux/minix_fs.h Mon Dec 11 06:56:37 1995 @@ -82,7 +82,7 @@ #ifdef __KERNEL__ extern int minix_lookup(struct inode * dir,const char * name, int len, - struct inode ** result); + struct inode ** result); extern int minix_create(struct inode * dir,const char * name, int len, int mode, struct inode ** result); extern int minix_mkdir(struct inode * dir, const char * name, int len, int mode); diff -u --recursive --new-file v1.3.45/linux/include/linux/mount.h linux/include/linux/mount.h --- v1.3.45/linux/include/linux/mount.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/mount.h Mon Dec 11 06:56:37 1995 @@ -0,0 +1,30 @@ +/* + * + * Definitions for mount interface. This describes the in the kernel build + * linkedlist with mounted filesystems. + * + * Author: Marco van Wieringen + * + * Version: $Id: mount.h,v 1.3 1994/07/20 22:01:00 mvw Exp mvw $ + * + */ +#ifndef _LINUX_MOUNT_H +#define _LINUX_MOUNT_H + +struct vfsmount +{ + dev_t mnt_dev; /* Device this applies to */ + char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */ + char *mnt_dirname; /* Name of directory mounted on */ + unsigned int mnt_flags; /* Flags of this device */ + struct semaphore mnt_sem; /* lock device while I/O in progress */ + struct super_block *mnt_sb; /* pointer to superblock */ + struct file *mnt_quotas[MAXQUOTAS]; /* fp's to quotafiles */ + time_t mnt_iexp[MAXQUOTAS]; /* expiretime for inodes */ + time_t mnt_bexp[MAXQUOTAS]; /* expiretime for blocks */ + struct vfsmount *mnt_next; /* pointer to next in linkedlist */ +}; + +struct vfsmount *lookup_vfsmnt(dev_t dev); + +#endif /* _LINUX_MOUNT_H */ diff -u --recursive --new-file v1.3.45/linux/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h --- v1.3.45/linux/include/linux/msdos_fs.h Sat Nov 11 17:41:34 1995 +++ linux/include/linux/msdos_fs.h Mon Dec 11 06:56:37 1995 @@ -148,7 +148,7 @@ /* namei.c */ extern int msdos_lookup(struct inode *dir,const char *name,int len, - struct inode **result); + struct inode **result); extern int msdos_create(struct inode *dir,const char *name,int len,int mode, struct inode **result); extern int msdos_mkdir(struct inode *dir,const char *name,int len,int mode); diff -u --recursive --new-file v1.3.45/linux/include/linux/pci.h linux/include/linux/pci.h --- v1.3.45/linux/include/linux/pci.h Sat Nov 25 19:04:56 1995 +++ linux/include/linux/pci.h Thu Nov 30 14:04:51 1995 @@ -264,6 +264,7 @@ #define PCI_DEVICE_ID_CIRRUS_5434_8 0x00A8 #define PCI_DEVICE_ID_CIRRUS_6729 0x1100 #define PCI_DEVICE_ID_CIRRUS_7542 0x1200 +#define PCI_DEVICE_ID_CIRRUS_7543 0x1202 #define PCI_VENDOR_ID_IBM 0x1014 @@ -415,8 +416,9 @@ #define PCI_VENDOR_ID_ZEITNET 0x1193 #define PCI_DEVICE_ID_ZEITNET_1221 0x0001 -#define PCI_VENDOR_ID_HAL 0x11cd -#define PCI_DEVICE_ID_HAL_RIO 0x8000 +#define PCI_VENDOR_ID_SPECIALIX 0x11cb +#define PCI_DEVICE_ID_SPECIALIX_XIO 0x4000 +#define PCI_DEVICE_ID_SPECIALIX_RIO 0x8000 #define PCI_VENDOR_ID_CYCLADES 0x120e #define PCI_DEVICE_ID_CYCLADES_Y 0x0100 diff -u --recursive --new-file v1.3.45/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h --- v1.3.45/linux/include/linux/proc_fs.h Fri Nov 17 08:42:28 1995 +++ linux/include/linux/proc_fs.h Mon Dec 11 09:55:42 1995 @@ -34,6 +34,7 @@ PROC_KSYMS, PROC_DMA, PROC_IOPORTS, + PROC_APM, PROC_PROFILE /* whether enabled or not */ }; @@ -87,6 +88,7 @@ PROC_NET_NR, PROC_NET_SOCKSTAT, PROC_NET_RTCACHE, + PROC_NET_AX25_BPQETHER, PROC_NET_LAST }; @@ -111,6 +113,7 @@ PROC_SCSI_ULTRASTOR, PROC_SCSI_7000FASST, PROC_SCSI_EATA2X, + PROC_SCSI_SSC, PROC_SCSI_SCSI_DEBUG, PROC_SCSI_NOT_PRESENT, PROC_SCSI_FILE, /* I'm asuming here that we */ diff -u --recursive --new-file v1.3.45/linux/include/linux/quota.h linux/include/linux/quota.h --- v1.3.45/linux/include/linux/quota.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/quota.h Mon Dec 11 06:56:37 1995 @@ -0,0 +1,219 @@ +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Elz at The University of Melbourne. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Version: $Id: quota.h,v 1.8 1995/03/11 11:43:07 mvw Exp mvw $ + */ + +#ifndef _LINUX_QUOTA_ +#define _LINUX_QUOTA_ + +#include + +/* + * Convert diskblocks to blocks and the other way around. + * currently only to fool the BSD source. :-) + */ +#define dbtob(num) (num << 10) +#define btodb(num) (num >> 10) + +/* + * Convert count of filesystem blocks to diskquota blocks, meant + * for filesystems where i_blksize != BLOCK_SIZE + */ +#define fs_to_dq_blocks(num, blksize) (((num) * (blksize)) / BLOCK_SIZE) + +/* + * Definitions for disk quotas imposed on the average user + * (big brother finally hits Linux). + * + * The following constants define the amount of time given a user + * before the soft limits are treated as hard limits (usually resulting + * in an allocation failure). The timer is started when the user crosses + * their soft limit, it is reset when they go below their soft limit. + */ +#define MAX_IQ_TIME 604800 /* (7*24*60*60) 1 week */ +#define MAX_DQ_TIME 604800 /* (7*24*60*60) 1 week */ + +#define MAXQUOTAS 2 +#define USRQUOTA 0 /* element used for user quotas */ +#define GRPQUOTA 1 /* element used for group quotas */ + +/* + * Definitions for the default names of the quotas files. + */ +#define INITQFNAMES { \ + "user", /* USRQUOTA */ \ + "group", /* GRPQUOTA */ \ + "undefined", \ +}; + +#define QUOTAFILENAME "quota" +#define QUOTAGROUP "staff" + +#define NR_DQHASH 43 /* Just an arbitrary number any suggestions ? */ +#define NR_DQUOTS 256 /* Number of quotas active at one time */ + +/* + * Command definitions for the 'quotactl' system call. + * The commands are broken into a main command defined below + * and a subcommand that is used to convey the type of + * quota that is being manipulated (see above). + */ +#define SUBCMDMASK 0x00ff +#define SUBCMDSHIFT 8 +#define QCMD(cmd, type) (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK)) + +#define Q_QUOTAON 0x0100 /* enable quotas */ +#define Q_QUOTAOFF 0x0200 /* disable quotas */ +#define Q_GETQUOTA 0x0300 /* get limits and usage */ +#define Q_SETQUOTA 0x0400 /* set limits and usage */ +#define Q_SETUSE 0x0500 /* set usage */ +#define Q_SYNC 0x0600 /* sync disk copy of a filesystems quotas */ +#define Q_SETQLIM 0x0700 /* set limits */ +#define Q_GETSTATS 0x0800 /* get collected stats */ + +/* + * The following structure defines the format of the disk quota file + * (as it appears on disk) - the file is an array of these structures + * indexed by user or group number. + */ +struct dqblk { + __u32 dqb_bhardlimit; /* absolute limit on disk blks alloc */ + __u32 dqb_bsoftlimit; /* preferred limit on disk blks */ + __u32 dqb_curblocks; /* current block count */ + __u32 dqb_ihardlimit; /* maximum # allocated inodes */ + __u32 dqb_isoftlimit; /* preferred inode limit */ + __u32 dqb_curinodes; /* current # allocated inodes */ + time_t dqb_btime; /* time limit for excessive disk use */ + time_t dqb_itime; /* time limit for excessive files */ +}; + +/* + * Shorthand notation. + */ +#define dq_bhardlimit dq_dqb.dqb_bhardlimit +#define dq_bsoftlimit dq_dqb.dqb_bsoftlimit +#define dq_curblocks dq_dqb.dqb_curblocks +#define dq_ihardlimit dq_dqb.dqb_ihardlimit +#define dq_isoftlimit dq_dqb.dqb_isoftlimit +#define dq_curinodes dq_dqb.dqb_curinodes +#define dq_btime dq_dqb.dqb_btime +#define dq_itime dq_dqb.dqb_itime + +#define dqoff(UID) ((off_t)((UID) * sizeof (struct dqblk))) + +struct dqstats { + __u32 lookups; + __u32 drops; + __u32 reads; + __u32 writes; + __u32 cache_hits; + __u32 pages_allocated; + __u32 allocated_dquots; + __u32 free_dquots; + __u32 syncs; +}; + +#ifdef __KERNEL__ + +/* + * Maximum lenght of a message generated in the quota system, + * that needs to be kicked onto the tty. + */ +#define MAX_QUOTA_MESSAGE 75 + +#define DQ_LOCKED 0x01 /* locked for update */ +#define DQ_WANT 0x02 /* wanted for update */ +#define DQ_MOD 0x04 /* dquot modified since read */ +#define DQ_BLKS 0x10 /* uid/gid has been warned about blk limit */ +#define DQ_INODES 0x20 /* uid/gid has been warned about inode limit */ +#define DQ_FAKE 0x40 /* no limits only usage */ + +struct dquot { + unsigned int dq_id; /* id this applies to (uid, gid) */ + short dq_type; /* type of quota */ + kdev_t dq_dev; /* Device this applies to */ + short dq_flags; /* see DQ_* */ + short dq_count; /* reference count */ + struct vfsmount *dq_mnt; /* vfsmountpoint this applies to */ + struct dqblk dq_dqb; /* diskquota usage */ + struct wait_queue *dq_wait; /* pointer to waitqueue */ + struct dquot *dq_prev; /* pointer to prev dquot */ + struct dquot *dq_next; /* pointer to next dquot */ + struct dquot *dq_hash_prev; /* pointer to prev dquot */ + struct dquot *dq_hash_next; /* pointer to next dquot */ +}; + +#define NODQUOT (struct dquot *)NULL + +/* + * Flags used for set_dqblk. + */ +#define QUOTA_SYSCALL 0x01 +#define SET_QUOTA 0x02 +#define SET_USE 0x04 +#define SET_QLIMIT 0x08 + +#define QUOTA_OK 0 +#define NO_QUOTA 1 + +/* + * declaration of quota_function calls in kernel. + */ +int quota_off (kdev_t dev, short type); +int sync_dquots (kdev_t dev, short type); + +extern void dquot_initialize(struct inode *inode, short type); +extern void dquot_drop(struct inode *inode); +extern int dquot_alloc_block(const struct inode *inode, unsigned long number); +extern int dquot_alloc_inode(const struct inode *inode, unsigned long number); +extern void dquot_free_block(const struct inode *inode, unsigned long number); +extern void dquot_free_inode(const struct inode *inode, unsigned long number); +extern int dquot_transfer(struct inode *inode, struct iattr *iattr, char direction); + +extern void invalidate_dquots(kdev_t dev, short type); +extern int quota_off(kdev_t dev, short type); +extern int sync_dquots(kdev_t dev, short type); + +#else + +#include + +__BEGIN_DECLS +int quotactl __P ((int, const char *, int, caddr_t)); +__END_DECLS + +#endif /* __KERNEL__ */ +#endif /* _QUOTA_ */ diff -u --recursive --new-file v1.3.45/linux/include/linux/sched.h linux/include/linux/sched.h --- v1.3.45/linux/include/linux/sched.h Tue Nov 21 13:22:13 1995 +++ linux/include/linux/sched.h Mon Dec 11 07:10:15 1995 @@ -133,6 +133,7 @@ struct mm_struct { int count; pgd_t * pgd; + unsigned long context; unsigned long start_code, end_code, start_data, end_data; unsigned long start_brk, brk, start_stack, start_mmap; unsigned long arg_start, arg_end, env_start, env_end; @@ -145,6 +146,7 @@ #define INIT_MM { \ 1, \ swapper_pg_dir, \ + 0, \ 0, 0, 0, 0, \ 0, 0, 0, 0, \ 0, 0, 0, 0, \ diff -u --recursive --new-file v1.3.45/linux/include/linux/smb.h linux/include/linux/smb.h --- v1.3.45/linux/include/linux/smb.h Fri Jul 7 08:54:54 1995 +++ linux/include/linux/smb.h Mon Dec 11 08:49:35 1995 @@ -50,6 +50,7 @@ #define LANMAN1 #define LANMAN2 +#define NT1 enum smb_protocol { PROTOCOL_NONE, diff -u --recursive --new-file v1.3.45/linux/include/linux/sys.h linux/include/linux/sys.h --- v1.3.45/linux/include/linux/sys.h Thu Jun 29 19:02:55 1995 +++ linux/include/linux/sys.h Mon Dec 11 06:56:37 1995 @@ -27,10 +27,4 @@ * These are system calls that haven't been implemented yet * but have an entry in the table for future expansion.. */ -#ifdef __ELF__ -#define sys_quotactl sys_ni_syscall -#else -#define _sys_quotactl _sys_ni_syscall -#endif - #endif diff -u --recursive --new-file v1.3.45/linux/include/linux/sysv_fs.h linux/include/linux/sysv_fs.h --- v1.3.45/linux/include/linux/sysv_fs.h Mon Sep 18 14:54:09 1995 +++ linux/include/linux/sysv_fs.h Mon Dec 11 07:17:03 1995 @@ -362,7 +362,7 @@ */ extern int sysv_lookup(struct inode * dir,const char * name, int len, - struct inode ** result); + struct inode ** result); extern int sysv_create(struct inode * dir,const char * name, int len, int mode, struct inode ** result); extern int sysv_mkdir(struct inode * dir, const char * name, int len, int mode); diff -u --recursive --new-file v1.3.45/linux/include/linux/tty.h linux/include/linux/tty.h --- v1.3.45/linux/include/linux/tty.h Tue Nov 21 13:22:13 1995 +++ linux/include/linux/tty.h Mon Dec 11 07:10:15 1995 @@ -297,6 +297,7 @@ extern int tty_unregister_driver(struct tty_driver *driver); extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp, int buflen); +extern void tty_write_message(struct tty_struct *tty, char *msg); extern int is_orphaned_pgrp(int pgrp); extern int is_ignored(int sig); diff -u --recursive --new-file v1.3.45/linux/include/net/ax25.h linux/include/net/ax25.h --- v1.3.45/linux/include/net/ax25.h Wed Sep 27 16:00:00 1995 +++ linux/include/net/ax25.h Mon Dec 11 11:27:19 1995 @@ -203,6 +203,9 @@ extern void ax25_dev_device_up(struct device *); extern void ax25_dev_device_down(struct device *); extern int ax25_dev_ioctl(unsigned int, void *); +extern int ax25_bpq_get_info(char *, char **, off_t, int, int); +extern ax25_address *ax25_bpq_get_addr(struct device *); +extern int ax25_bpq_ioctl(unsigned int, void *); /* ax25_subr.c */ extern void ax25_clear_queues(ax25_cb *); diff -u --recursive --new-file v1.3.45/linux/include/net/netlink.h linux/include/net/netlink.h --- v1.3.45/linux/include/net/netlink.h Fri Nov 17 08:42:29 1995 +++ linux/include/net/netlink.h Mon Dec 11 11:34:40 1995 @@ -1,9 +1,9 @@ #ifndef __NET_NETLINK_H #define __NET_NETLINK_H -#define NET_MAJOR 18 /* Major 18 is reserved for networking */ -#define MAX_LINKS 3 /* 18,0 for route updates, 18,1 for SKIP */ -#define MAX_QBYTES 32768 /* Maximum bytes in the queue */ +#define NET_MAJOR 36 /* Major 18 is reserved for networking */ +#define MAX_LINKS 4 /* 18,0 for route updates, 18,1 for SKIP, 18,2 debug tap 18,3 PPP reserved */ +#define MAX_QBYTES 32768 /* Maximum bytes in the queue */ #include diff -u --recursive --new-file v1.3.45/linux/init/main.c linux/init/main.c --- v1.3.45/linux/init/main.c Mon Nov 27 12:48:36 1995 +++ linux/init/main.c Mon Dec 11 09:55:42 1995 @@ -29,6 +29,9 @@ #include #include #include +#ifdef CONFIG_APM +#include +#endif #include @@ -127,6 +130,8 @@ char nfs_root_addrs[128] = { "" }; #endif +extern void dquot_init(void); + static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, }; static char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, }; @@ -400,6 +405,7 @@ if (!strncmp(line, "nfsroot=", 8)) { int n; line += 8; + ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255); if (line[0] == '/' || (line[0] >= '0' && line[0] <= '9')) { strncpy(nfs_root_name, line, sizeof(nfs_root_name)); nfs_root_name[sizeof(nfs_root_name)] = '\0'; @@ -580,6 +586,10 @@ #ifdef CONFIG_SYSVIPC ipc_init(); #endif +#ifdef CONFIG_APM + apm_bios_init(); +#endif + dquot_init(); sti(); check_bugs(); diff -u --recursive --new-file v1.3.45/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v1.3.45/linux/kernel/ksyms.c Sat Nov 25 19:04:57 1995 +++ linux/kernel/ksyms.c Thu Nov 30 14:04:51 1995 @@ -336,6 +336,7 @@ #endif X(jiffies), X(xtime), + X(do_gettimeofday), X(loops_per_sec), X(need_resched), X(kill_proc), diff -u --recursive --new-file v1.3.45/linux/kernel/module.c linux/kernel/module.c --- v1.3.45/linux/kernel/module.c Mon Oct 16 18:38:24 1995 +++ linux/kernel/module.c Thu Nov 30 14:04:50 1995 @@ -547,8 +547,10 @@ *p++ = *q++; if (mp->state == MOD_UNINITIALIZED) q = " (uninitialized)"; - else if (mp->state == MOD_RUNNING) - q = ""; + else if (mp->state == MOD_RUNNING) { + sprintf(size,"\t%ld",GET_USE_COUNT(mp)); + q=size; + } else if (mp->state == MOD_DELETED) q = " (deleted)"; else diff -u --recursive --new-file v1.3.45/linux/kernel/printk.c linux/kernel/printk.c --- v1.3.45/linux/kernel/printk.c Sun Oct 29 11:38:49 1995 +++ linux/kernel/printk.c Mon Dec 11 06:56:37 1995 @@ -20,6 +20,8 @@ #include #include #include +#include +#include #define LOG_BUF_LEN 4096 @@ -235,4 +237,17 @@ msg_level = -1; j = 0; } +} + +/* + * Write a message to a certain tty, not just the console. This is used for + * messages that need to be redirected to a specific tty. + * We don't put it into the syslog queue right now maybe in the future if + * really needed. + */ +void tty_write_message(struct tty_struct *tty, char *msg) +{ + if (tty && tty->driver.write) + tty->driver.write(tty, 0, msg, strlen(msg)); + return; } diff -u --recursive --new-file v1.3.45/linux/lib/Makefile linux/lib/Makefile --- v1.3.45/linux/lib/Makefile Tue Aug 15 20:39:05 1995 +++ linux/lib/Makefile Mon Nov 27 15:54:00 1995 @@ -7,7 +7,6 @@ # L_TARGET := lib.a -L_OBJS := ctype.o _exit.o open.o close.o errno.o write.o dup.o \ - setsid.o execve.o wait.o string.o vsprintf.o +L_OBJS := errno.o ctype.o string.o vsprintf.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.45/linux/lib/_exit.c linux/lib/_exit.c --- v1.3.45/linux/lib/_exit.c Wed Jan 4 21:16:06 1995 +++ linux/lib/_exit.c Thu Jan 1 02:00:00 1970 @@ -1,21 +0,0 @@ -/* - * linux/lib/_exit.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -#define __LIBRARY__ -#include - -#define exit __sys_exit -static inline _syscall0(int, exit) -#undef exit - -volatile void _exit(int exit_code) -{ -fake_volatile: - __sys_exit(); - goto fake_volatile; -} - - diff -u --recursive --new-file v1.3.45/linux/lib/close.c linux/lib/close.c --- v1.3.45/linux/lib/close.c Wed Dec 1 14:44:15 1993 +++ linux/lib/close.c Thu Jan 1 02:00:00 1970 @@ -1,11 +0,0 @@ -/* - * linux/lib/close.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -#define __LIBRARY__ -#include - -_syscall1(int,close,int,fd) - diff -u --recursive --new-file v1.3.45/linux/lib/dup.c linux/lib/dup.c --- v1.3.45/linux/lib/dup.c Wed Dec 1 14:44:15 1993 +++ linux/lib/dup.c Thu Jan 1 02:00:00 1970 @@ -1,11 +0,0 @@ -/* - * linux/lib/dup.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -#define __LIBRARY__ -#include - -_syscall1(int,dup,int,fd) - diff -u --recursive --new-file v1.3.45/linux/lib/execve.c linux/lib/execve.c --- v1.3.45/linux/lib/execve.c Wed Dec 1 14:44:15 1993 +++ linux/lib/execve.c Thu Jan 1 02:00:00 1970 @@ -1,11 +0,0 @@ -/* - * linux/lib/execve.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -#define __LIBRARY__ -#include - -_syscall3(int,execve,const char *,file,char **,argv,char **,envp) - diff -u --recursive --new-file v1.3.45/linux/lib/open.c linux/lib/open.c --- v1.3.45/linux/lib/open.c Wed Jan 4 21:16:06 1995 +++ linux/lib/open.c Thu Jan 1 02:00:00 1970 @@ -1,24 +0,0 @@ -/* - * linux/lib/open.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -#define __LIBRARY__ -#include -#include - -#define open __sys_open -static inline _syscall3(int, open, const char *, filename, int, flag, int, mode) -#undef open - -int open(const char * filename, int flag, ...) -{ - int res; - va_list arg; - - va_start(arg,flag); - res = __sys_open(filename, flag, va_arg(arg, int)); - va_end(arg); - return res; -} diff -u --recursive --new-file v1.3.45/linux/lib/setsid.c linux/lib/setsid.c --- v1.3.45/linux/lib/setsid.c Wed Dec 1 14:44:15 1993 +++ linux/lib/setsid.c Thu Jan 1 02:00:00 1970 @@ -1,12 +0,0 @@ -/* - * linux/lib/setsid.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -#define __LIBRARY__ -#include -#include - -_syscall0(pid_t,setsid) - diff -u --recursive --new-file v1.3.45/linux/lib/wait.c linux/lib/wait.c --- v1.3.45/linux/lib/wait.c Wed Dec 1 14:44:15 1993 +++ linux/lib/wait.c Thu Jan 1 02:00:00 1970 @@ -1,17 +0,0 @@ -/* - * linux/lib/wait.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -#define __LIBRARY__ -#include -#include - -_syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) - -pid_t wait(int * wait_stat) -{ - return waitpid(-1,wait_stat,0); -} - diff -u --recursive --new-file v1.3.45/linux/lib/write.c linux/lib/write.c --- v1.3.45/linux/lib/write.c Wed Dec 1 14:44:15 1993 +++ linux/lib/write.c Thu Jan 1 02:00:00 1970 @@ -1,12 +0,0 @@ -/* - * linux/lib/write.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -#define __LIBRARY__ -#include -#include - -_syscall3(int,write,int,fd,const char *,buf,off_t,count) - diff -u --recursive --new-file v1.3.45/linux/mm/mmap.c linux/mm/mmap.c --- v1.3.45/linux/mm/mmap.c Tue Nov 21 13:22:14 1995 +++ linux/mm/mmap.c Mon Dec 11 06:56:37 1995 @@ -95,7 +95,7 @@ return -EINVAL; } if (flags & MAP_DENYWRITE) { - if (file->f_inode->i_wcount > 0) + if (file->f_inode->i_writecount > 0) return -ETXTBSY; } } else if ((flags & MAP_TYPE) != MAP_PRIVATE) diff -u --recursive --new-file v1.3.45/linux/net/Changes linux/net/Changes --- v1.3.45/linux/net/Changes Sat Nov 25 19:04:57 1995 +++ linux/net/Changes Thu Nov 30 11:15:54 1995 @@ -277,8 +277,8 @@ o First parts of the SKIP support [IN, not useful] o TCP ICMP (SOSS should work again) [IN] o IPFW support for TOS changing (Al Longyear) [IN] -o DECNET PPP test code [IN] -o NFS root [IN] +o DECNET PPP test code [Steve] [IN] +o NFS root [Miguel/Gero] [IN] o Path MTU discovery [ANK] [IN] -------->>>>> 1.3.44 <<<<<<-------- @@ -291,6 +291,14 @@ o Fixes to the name set functions (maybe fixes netrom) [Steve] [IN] o Packet protocol labelling (not IPX yet) [IN] +o Faster buffer copy/clone [Linus] [IN] + +-------->>>>> 1.3.46 <<<<<<-------- + +o AX.25/NetROM fixes/changes [John Naylor] [IN] +o Further attempts to fix the IPX memory bug [IN] +o ARP fixes (Assorted) [IN] +o Driver fixes for multicast lists [IN] ---------- Things I thought Linus had for a while and not merged ---------------- diff -u --recursive --new-file v1.3.45/linux/net/Config.in linux/net/Config.in --- v1.3.45/linux/net/Config.in Mon Oct 23 18:02:21 1995 +++ linux/net/Config.in Thu Nov 30 11:15:54 1995 @@ -12,6 +12,7 @@ bool 'Appletalk DDP' CONFIG_ATALK bool 'Amateur Radio AX.25 Level 2' CONFIG_AX25 if [ "$CONFIG_AX25" = "y" ]; then + bool 'AX.25 over Ethernet' CONFIG_BPQETHER bool 'Amateur Radio NET/ROM' CONFIG_NETROM fi bool 'Kernel/User network link driver(ALPHA)' CONFIG_NETLINK diff -u --recursive --new-file v1.3.45/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c --- v1.3.45/linux/net/ax25/af_ax25.c Sat Nov 25 19:04:57 1995 +++ linux/net/ax25/af_ax25.c Thu Nov 30 11:15:54 1995 @@ -651,7 +651,6 @@ struct device *ax25rtr_get_dev(ax25_address *addr) { struct device *dev; - ax25_address dev_addr; for (dev = dev_base; dev != NULL; dev = dev->next) { if (dev->flags & IFF_UP) { @@ -660,11 +659,16 @@ if (ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0) return dev; break; - case ARPHRD_ETHER: - if (arp_query((unsigned char *)&dev_addr, dev->pa_addr, dev)) - if (ax25cmp(addr, &dev_addr) == 0) - return dev; +#ifdef CONFIG_BPQETHER + case ARPHRD_ETHER: { + ax25_address *dev_addr; + + if ((dev_addr = ax25_bpq_get_addr(dev)) != NULL) + if (ax25cmp(addr, dev_addr) == 0) + return dev; + } break; +#endif default: break; } @@ -1659,17 +1663,18 @@ return ax25_rcv(skb, dev, (ax25_address *)dev->dev_addr, ptype); } +#ifdef CONFIG_BPQETHER /* * Receive an AX.25 frame via an Ethernet interface. */ static int bpq_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *ptype) { - ax25_address port_call; + ax25_address *port_call; int len; skb->sk = NULL; /* Initially we don't know who its for */ - if (!arp_query((unsigned char *)&port_call, dev->pa_addr, dev)) { + if ((port_call = ax25_bpq_get_addr(dev)) == NULL) { kfree_skb(skb, FREE_READ); /* We have no port callsign */ return 0; } @@ -1679,8 +1684,9 @@ skb_pull(skb, 2); /* Remove the length bytes */ skb_trim(skb, len); /* Set the length of the data */ - return ax25_rcv(skb, dev, &port_call, ptype); + return ax25_rcv(skb, dev, port_call, ptype); } +#endif static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, int noblock, int flags) { @@ -1970,6 +1976,13 @@ ax25_uid_policy = amount; return 0; +#ifdef CONFIG_BPQETHER + case SIOCAX25BPQADDR: + if (!suser()) + return -EPERM; + return ax25_bpq_ioctl(cmd, (void *)arg); +#endif + case SIOCAX25GETPARMS: case SIOCAX25SETPARMS: return ax25_dev_ioctl(cmd, (void *)arg); @@ -2097,6 +2110,7 @@ NULL, }; +#ifdef CONFIG_BPQETHER static struct packet_type bpq_packet_type = { 0, /* MUTTER ntohs(ETH_P_BPQ),*/ @@ -2105,6 +2119,7 @@ NULL, NULL, }; +#endif static struct notifier_block ax25_dev_notifier = { ax25_device_event, @@ -2116,8 +2131,10 @@ sock_register(ax25_proto_ops.family, &ax25_proto_ops); ax25_packet_type.type = htons(ETH_P_AX25); dev_add_pack(&ax25_packet_type); +#ifdef CONFIG_BPQETHER bpq_packet_type.type = htons(ETH_P_BPQ); dev_add_pack(&bpq_packet_type); +#endif register_netdevice_notifier(&ax25_dev_notifier); proc_net_register(&(struct proc_dir_entry) { @@ -2140,6 +2157,17 @@ }); printk("G4KLX/GW4PTS AX.25 for Linux. Version 0.30 BETA for Linux NET3.032 (Linux 1.3.35)\n"); + +#ifdef CONFIG_BPQETHER + proc_net_register(&(struct proc_dir_entry) { + PROC_NET_AX25_BPQETHER, 13, "ax25_bpqether", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_net_inode_operations, + ax25_bpq_get_info + }); + + printk("G8BPQ Encapsulation of AX.25 frames enabled\n"); +#endif } /* @@ -2149,9 +2177,7 @@ void ax25_queue_xmit(struct sk_buff *skb, struct device *dev, int pri) { - static char bcast_addr[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; unsigned char *ptr; - int size; #ifdef CONFIG_FIREWALL @@ -2163,10 +2189,12 @@ #endif skb->protocol = htons (ETH_P_AX25); - - if (dev->type == ARPHRD_ETHER) +#ifdef CONFIG_BPQETHER + if(dev->type == ARPHRD_ETHER) { - if (skb_headroom(skb) < AX25_BPQ_HEADER_LEN) + static char bcast_addr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; + int size; + if(skb_headroom(skb) < AX25_BPQ_HEADER_LEN) { printk("ax25_queue_xmit: not enough space to add BPQ Ether header\n"); skb->free = 1; @@ -2182,12 +2210,15 @@ *ptr++ = (size + 5) / 256; dev->hard_header(skb, dev, ETH_P_BPQ, bcast_addr, NULL, 0); + + dev_queue_xmit(skb, dev, pri); + + return; } - else - { - ptr = skb_push(skb, 1); - *ptr++ = 0; /* KISS */ - } +#endif + + ptr = skb_push(skb, 1); + *ptr++ = 0; /* KISS */ dev_queue_xmit(skb, dev, pri); } diff -u --recursive --new-file v1.3.45/linux/net/ax25/ax25_route.c linux/net/ax25/ax25_route.c --- v1.3.45/linux/net/ax25/ax25_route.c Wed Sep 27 16:00:01 1995 +++ linux/net/ax25/ax25_route.c Thu Nov 30 11:15:54 1995 @@ -593,4 +593,97 @@ return 0; } +#ifdef CONFIG_BPQETHER +static struct ax25_bpqdev { + struct ax25_bpqdev *next; + struct device *dev; + ax25_address callsign; +} *ax25_bpqdev = NULL; + +int ax25_bpq_get_info(char *buffer, char **start, off_t offset, int length, int dummy) +{ + struct ax25_bpqdev *bpqdev; + int len = 0; + off_t pos = 0; + off_t begin = 0; + + cli(); + + len += sprintf(buffer, "dev callsign\n"); + + for (bpqdev = ax25_bpqdev; bpqdev != NULL; bpqdev = bpqdev->next) { + len += sprintf(buffer + len, "%-4s %-9s\n", + bpqdev->dev ? bpqdev->dev->name : "???", + ax2asc(&bpqdev->callsign)); + + pos = begin + len; + + if (pos < offset) { + len = 0; + begin = pos; + } + + if (pos > offset + length) + break; + } + + sti(); + + *start = buffer + (offset - begin); + len -= (offset - begin); + + if (len > length) len = length; + + return len; +} + +ax25_address *ax25_bpq_get_addr(struct device *dev) +{ + struct ax25_bpqdev *bpqdev; + + for (bpqdev = ax25_bpqdev; bpqdev != NULL; bpqdev = bpqdev->next) + if (bpqdev->dev == dev) + return &bpqdev->callsign; + + return NULL; +} + +int ax25_bpq_ioctl(unsigned int cmd, void *arg) +{ + unsigned long flags; + struct ax25_bpqdev *bpqdev; + struct ax25_bpqaddr_struct bpqaddr; + struct device *dev; + int err; + + switch (cmd) { + case SIOCAX25BPQADDR: + if ((err = verify_area(VERIFY_READ, arg, sizeof(bpqaddr))) != 0) + return err; + memcpy_fromfs(&bpqaddr, arg, sizeof(bpqaddr)); + if ((dev = dev_get(bpqaddr.dev)) == NULL) + return -EINVAL; + for (bpqdev = ax25_bpqdev; bpqdev != NULL; bpqdev = bpqdev->next) { + if (bpqdev->dev == dev) { + bpqdev->callsign = bpqaddr.addr; + return 0; + } + } + if ((bpqdev = (struct ax25_bpqdev *)kmalloc(sizeof(struct ax25_bpqdev), GFP_ATOMIC)) == NULL) + return -ENOMEM; + bpqdev->dev = dev; + bpqdev->callsign = bpqaddr.addr; + save_flags(flags); + cli(); + bpqdev->next = ax25_bpqdev; + ax25_bpqdev = bpqdev; + restore_flags(flags); + break; + } + + return 0; +} + +#endif + #endif diff -u --recursive --new-file v1.3.45/linux/net/core/datagram.c linux/net/core/datagram.c --- v1.3.45/linux/net/core/datagram.c Wed Nov 8 07:11:45 1995 +++ linux/net/core/datagram.c Thu Nov 30 11:15:54 1995 @@ -3,10 +3,10 @@ * * Generic datagram handling routines. These are generic for all protocols. Possibly a generic IP version on top * of these would make sense. Not tonight however 8-). - * This is used because UDP, RAW, PACKET and the to be released IPX layer all have identical select code and mostly - * identical recvfrom() code. So we share it here. The select was shared before but buried in udp.c so I moved it. + * This is used because UDP, RAW, PACKET, DDP, IPX, AX.25 and NetROM layer all have identical select code and mostly + * identical recvmsg() code. So we share it here. The select was shared before but buried in udp.c so I moved it. * - * Authors: Alan Cox . (datagram_select() from old udp.c code) + * Authors: Alan Cox . (datagram_select() from old udp.c code) * * Fixes: * Alan Cox : NULL return from skb_peek_copy() understood @@ -19,9 +19,6 @@ * Linus Torvalds : BSD semantic fixes. * Alan Cox : Datagram iovec handling * - * Note: - * A lot of this will change when the protocol/socket separation - * occurs. Using this will make things reasonably clean. */ #include diff -u --recursive --new-file v1.3.45/linux/net/ipv4/arp.c linux/net/ipv4/arp.c --- v1.3.45/linux/net/ipv4/arp.c Sat Nov 25 19:04:58 1995 +++ linux/net/ipv4/arp.c Thu Nov 30 11:15:54 1995 @@ -1603,6 +1603,7 @@ /* * Test if a hardware address is all zero */ + static inline int empty(unsigned char * addr, int len) { while (len > 0) { @@ -1628,12 +1629,7 @@ u32 ip; /* - * Find out about the hardware type. - * We have to be compatible with BSD UNIX, so we have to - * assume that a "not set" value (i.e. 0) means Ethernet. - * - * ANK: Hey, who wrote it? Do you really mean that BSD considers - * ARPHRD_NETROM as ARPHRD_ETHER, or somthing another? + * Find out about the hardware type. */ si = (struct sockaddr_in *) &r->arp_pa; diff -u --recursive --new-file v1.3.45/linux/net/ipv4/igmp.c linux/net/ipv4/igmp.c --- v1.3.45/linux/net/ipv4/igmp.c Sat Nov 25 19:04:58 1995 +++ linux/net/ipv4/igmp.c Thu Nov 30 11:15:55 1995 @@ -28,9 +28,11 @@ * desired by mrouted, fixed the fact it has been * broken since 1.3.6 and cleaned up a few minor * points. + * * Chih-Jen Chang : Tried to revise IGMP to Version 2 - * Tsu-Sheng Tsao chihjenc@scf.usc.edu and tsusheng@scf.usc.edu - * The enhancements are based on Steve Deering's ipmulti-3.5 code + * Tsu-Sheng Tsao E-mail: chihjenc@scf.usc.edu and tsusheng@scf.usc.edu + * The enhancements are mainly based on Steve Deering's + * ipmulti-3.5 source code. * Chih-Jen Chang : Added the igmp_get_mrouter_info and * Tsu-Sheng Tsao igmp_set_mrouter_info to keep track of * the mrouted version on that device. @@ -38,6 +40,8 @@ * Tsu-Sheng Tsao igmp_heard_query(). Using this parameter * to identify the multicast router verion * and do what the IGMP version 2 specified. + * Chih-Jen Chang : Added a timer to revert to IGMP V2 router + * Tsu-Sheng Tsao if the specified time expired. */ @@ -66,20 +70,33 @@ /* + * If time expired, change the router type to IGMP_NEW_ROUTER. + */ + +static void ip_router_timer_expire(unsigned long data) +{ + struct ip_router_info *i=(struct ip_router_info *)data; + + del_timer(&i->timer); + i->type=IGMP_NEW_ROUTER; /* Revert to new multicast router */ + i->time=0; +} + +/* * Multicast router info manager */ -struct router_info *router_info_head=(struct router_info *)0; +struct ip_router_info *ip_router_info_head=(struct ip_router_info *)0; /* * Get the multicast router info on that device */ -static struct router_info *igmp_get_mrouter_info(struct device *dev) +static struct ip_router_info *igmp_get_mrouter_info(struct device *dev) { - register struct router_info *i; + register struct ip_router_info *i; - for(i=router_info_head;i!=NULL;i=i->next) + for(i=ip_router_info_head;i!=NULL;i=i->next) { if (i->dev == dev) { @@ -90,12 +107,17 @@ /* * Not found. Create a new entry. The default is IGMP V2 router */ - i=(struct router_info *)kmalloc(sizeof(*i), GFP_KERNEL); + i=(struct ip_router_info *)kmalloc(sizeof(*i), GFP_KERNEL); i->dev = dev; i->type = IGMP_NEW_ROUTER; i->time = IGMP_AGE_THRESHOLD; - i->next = router_info_head; - router_info_head = i; + i->next = ip_router_info_head; + ip_router_info_head = i; + + init_timer(&i->timer); + i->timer.data=(unsigned long)i; + i->timer.function=&ip_router_timer_expire; + return i; } @@ -103,16 +125,27 @@ * Set the multicast router info on that device */ -static struct router_info *igmp_set_mrouter_info(struct device *dev,int type,int time) +static struct ip_router_info *igmp_set_mrouter_info(struct device *dev,int type,int time) { - register struct router_info *i; + register struct ip_router_info *i; - for(i=router_info_head;i!=NULL;i=i->next) + for(i=ip_router_info_head;i!=NULL;i=i->next) { if (i->dev == dev) { + if(i->type==IGMP_OLD_ROUTER) + { + del_timer(&i->timer); + } + i->type = type; i->time = time; + + if(i->type==IGMP_OLD_ROUTER) + { + i->timer.expires=jiffies+i->time*HZ; + add_timer(&i->timer); + } return i; } } @@ -120,12 +153,22 @@ /* * Not found. Create a new entry. */ - i=(struct router_info *)kmalloc(sizeof(*i), GFP_KERNEL); + i=(struct ip_router_info *)kmalloc(sizeof(*i), GFP_KERNEL); i->dev = dev; i->type = type; i->time = time; - i->next = router_info_head; - router_info_head = i; + i->next = ip_router_info_head; + ip_router_info_head = i; + + init_timer(&i->timer); + i->timer.data=(unsigned long)i; + i->timer.function=&ip_router_timer_expire; + if(i->type==IGMP_OLD_ROUTER) + { + i->timer.expires=jiffies+i->time*HZ; + add_timer(&i->timer); + } + return i; } @@ -134,7 +177,6 @@ * Timer management */ - static void igmp_stop_timer(struct ip_mc_list *im) { del_timer(&im->timer); @@ -197,7 +239,7 @@ static void igmp_timer_expire(unsigned long data) { struct ip_mc_list *im=(struct ip_mc_list *)data; - struct router_info *r; + struct ip_router_info *r; igmp_stop_timer(im); r=igmp_get_mrouter_info(im->interface); if(r->type==IGMP_NEW_ROUTER) @@ -337,7 +379,7 @@ extern __inline__ void igmp_group_added(struct ip_mc_list *im) { - struct router_info *r; + struct ip_router_info *r; igmp_init_timer(im); ip_mc_filter_add(im->interface, im->multiaddr); r=igmp_get_mrouter_info(im->interface); @@ -462,20 +504,9 @@ void ip_mc_allhost(struct device *dev) { struct ip_mc_list *i; - /* - * Don't add to non multicast units - */ - if(!(dev->flags&IFF_MULTICAST)) - return; - /* - * No duplicates - */ for(i=dev->ip_mc_list;i!=NULL;i=i->next) if(i->multiaddr==IGMP_ALL_HOSTS) return; - /* - * Add it - */ i=(struct ip_mc_list *)kmalloc(sizeof(*i), GFP_KERNEL); if(!i) return; diff -u --recursive --new-file v1.3.45/linux/net/ipv4/raw.c linux/net/ipv4/raw.c --- v1.3.45/linux/net/ipv4/raw.c Sat Nov 25 19:04:58 1995 +++ linux/net/ipv4/raw.c Thu Nov 30 11:15:55 1995 @@ -29,6 +29,7 @@ * Alan Cox : BSD style RAW socket demultiplexing. * Alan Cox : Beginnings of mrouted support. * Alan Cox : Added IP_HDRINCL option. + * Alan Cox : Skip broadcast check if BSDism set. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -228,7 +229,11 @@ if (sin.sin_addr.s_addr == INADDR_ANY) sin.sin_addr.s_addr = ip_my_addr(); - if (sk->broadcast == 0 && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST) + /* + * BSD raw sockets forget to check SO_BROADCAST .... + */ + + if (!sk->bsdism && sk->broadcast == 0 && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST) return -EACCES; if(sk->ip_hdrincl) diff -u --recursive --new-file v1.3.45/linux/net/ipv4/route.c linux/net/ipv4/route.c --- v1.3.45/linux/net/ipv4/route.c Fri Nov 17 08:42:34 1995 +++ linux/net/ipv4/route.c Thu Nov 30 11:15:55 1995 @@ -37,6 +37,8 @@ * Alan Cox : Faster /proc handling * Alexey Kuznetsov : Massive rework to support tree based routing, * routing caches and better behaviour. + * + * Olaf Erb : irtt wasnt being copied right. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -496,6 +498,7 @@ fi->fib_refcnt++; fi->fib_next = fib_info_list; fi->fib_prev = NULL; + fi->fib_irtt = irtt; if (fib_info_list) fib_info_list->fib_prev = fi; fib_info_list = fi; diff -u --recursive --new-file v1.3.45/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c --- v1.3.45/linux/net/ipx/af_ipx.c Sat Nov 25 19:04:58 1995 +++ linux/net/ipx/af_ipx.c Thu Nov 30 11:15:55 1995 @@ -324,12 +324,12 @@ return NOTIFY_DONE; } -static int -ipxitf_def_skb_handler(struct sock *sock, struct sk_buff *skb) +static int ipxitf_def_skb_handler(struct sock *sock, struct sk_buff *skb) { int retval; - if((retval = sock_queue_rcv_skb(sock, skb))<0) { + if((retval = sock_queue_rcv_skb(sock, skb))<0) + { /* * We do a FREE_WRITE here because this indicates how * to treat the socket with which the packet is @@ -343,8 +343,13 @@ return retval; } -static int -ipxitf_demux_socket(ipx_interface *intrfc, struct sk_buff *skb, int copy) +/* + * On input if skb->sk is set the buffer is a socket sending. We need to ensure the + * accounting is kept right in these cases. At the moment the socket write queue is + * charged for the memory. + */ + +static int ipxitf_demux_socket(ipx_interface *intrfc, struct sk_buff *skb, int copy) { ipx_packet *ipx = (ipx_packet *)(skb->h.raw); ipx_socket *sock1 = NULL, *sock2 = NULL; @@ -359,33 +364,42 @@ * The *SPECIAL* socket list contains: 0x452(SAP), 0x453(RIP) and * 0x456(Diagnostic). */ - if (ipx_primary_net && (intrfc != ipx_primary_net)) { - switch (ntohs(ipx->ipx_dest.sock)) { - case 0x452: - case 0x453: - case 0x456: - /* - * The appropriate thing to do here is to - * dup the packet and route to the primary net - * interface via ipxitf_send; however, we'll cheat - * and just demux it here. - */ - sock2 = ipxitf_find_socket(ipx_primary_net, + + if (ipx_primary_net && (intrfc != ipx_primary_net)) + { + switch (ntohs(ipx->ipx_dest.sock)) + { + case 0x452: + case 0x453: + case 0x456: + /* + * The appropriate thing to do here is to + * dup the packet and route to the primary net + * interface via ipxitf_send; however, we'll cheat + * and just demux it here. + */ + sock2 = ipxitf_find_socket(ipx_primary_net, ipx->ipx_dest.sock); - break; - default: - break; + break; + default: + break; } } - /* if there is nothing to do, return */ - if ((sock1 == NULL) && (sock2 == NULL)) { + /* + * if there is nothing to do, return. The kfree will + * cancel any charging. + */ + + if (sock1 == NULL && sock2 == NULL) + { if (!copy) kfree_skb(skb,FREE_WRITE); return 0; } - /* This next segment of code is a little awkward, but it sets it up + /* + * This next segment of code is a little awkward, but it sets it up * so that the appropriate number of copies of the SKB are made and * that skb1 and skb2 point to it (them) so that it (they) can be * demuxed to sock1 and/or sock2. If we are unable to make enough @@ -396,43 +410,48 @@ * this is ok as no socket owns an input buffer. */ - if(skb->sk) + if(skb->sk && !copy) { skb->sk->wmem_alloc -= skb->truesize; /* Adjust */ skb->sk=NULL; /* Disown */ } - if (copy) { + if (copy) + { skb1 = skb_clone(skb, GFP_ATOMIC); - if (skb1 != NULL) { + if (skb1 != NULL) skb1->arp = skb1->free = 1; - } - } else { + } + else + { skb1 = skb; } - if (skb1 == NULL) return -ENOMEM; + if (skb1 == NULL) + return -ENOMEM; - /* Do we need 2 SKBs? */ - if (sock1 && sock2) { + /* + * Do we need 2 SKBs? + */ + + if (sock1 && sock2) + { skb2 = skb_clone(skb1, GFP_ATOMIC); - if (skb2 != NULL) { + if (skb2 != NULL) skb2->arp = skb2->free = 1; - } - } else { - skb2 = skb1; } + else + skb2 = skb1; - if (sock1) { + if (sock1) (void) ipxitf_def_skb_handler(sock1, skb1); - } - if (skb2 == NULL) return -ENOMEM; + if (skb2 == NULL) + return -ENOMEM; - if (sock2) { + if (sock2) (void) ipxitf_def_skb_handler(sock2, skb2); - } return 0; } @@ -443,29 +462,13 @@ struct sk_buff *skb2; int in_offset = skb->h.raw - skb->head; int out_offset = intrfc->if_ipx_offset; -#if 0 - char *oldraw; -#endif int len; /* Hopefully, most cases */ if (in_offset >= out_offset) { -/* skb_push(skb,out_offset);*/ - skb->arp = skb->free = 1; - return skb; - } - -#if 0 - /* Existing SKB will work, just need to move things around a little */ - if (in_offset > out_offset) { - oldraw = skb->h.raw; - skb->h.raw = &(skb->data[out_offset]); - memmove(skb->h.raw, oldraw, skb->len); - skb->len += out_offset; skb->arp = skb->free = 1; return skb; } -#endif /* Need new SKB */ len = skb->len + out_offset; @@ -481,8 +484,7 @@ return skb2; } -static int -ipxitf_send(ipx_interface *intrfc, struct sk_buff *skb, char *node) +static int ipxitf_send(ipx_interface *intrfc, struct sk_buff *skb, char *node) { ipx_packet *ipx = (ipx_packet *)(skb->h.raw); struct device *dev = intrfc->if_dev; @@ -491,29 +493,51 @@ int send_to_wire = 1; int addr_len; - /* We need to know how many skbuffs it will take to send out this - * packet to avoid unnecessary copies. + /* + * We need to know how many skbuffs it will take to send out this + * packet to avoid unnecessary copies. */ + if ((dl == NULL) || (dev == NULL) || (dev->flags & IFF_LOOPBACK)) send_to_wire = 0; - /* See if this should be demuxed to sockets on this interface */ - if (ipx->ipx_dest.net == intrfc->if_netnum) { + /* + * See if this should be demuxed to sockets on this interface + * + * We want to ensure the original was eaten or that we only use + * up clones. + */ + + if (ipx->ipx_dest.net == intrfc->if_netnum) + { + /* + * To our own node, loop and free the original. + */ if (memcmp(intrfc->if_node, node, IPX_NODE_LEN) == 0) return ipxitf_demux_socket(intrfc, skb, 0); - if (memcmp(ipx_broadcast_node, node, IPX_NODE_LEN) == 0) { + /* + * Broadcast, loop and possibly keep to send on. + */ + if (memcmp(ipx_broadcast_node, node, IPX_NODE_LEN) == 0) + { ipxitf_demux_socket(intrfc, skb, send_to_wire); - if (!send_to_wire) return 0; + if (!send_to_wire) + return 0; } } - /* if the originating net is not equal to our net; this is routed */ - if (ipx->ipx_source.net != intrfc->if_netnum) { + /* + * if the originating net is not equal to our net; this is routed + */ + + if (ipx->ipx_source.net != intrfc->if_netnum) + { if (++(ipx->ipx_tctrl) > ipxcfg_max_hops) send_to_wire = 0; } - if (!send_to_wire) { + if (!send_to_wire) + { /* * We do a FREE_WRITE here because this indicates how * to treat the socket with which the packet is @@ -526,45 +550,47 @@ return 0; } - /* determine the appropriate hardware address */ + /* + * Determine the appropriate hardware address + */ + addr_len = dev->addr_len; - if (memcmp(ipx_broadcast_node, node, IPX_NODE_LEN) == 0) { + if (memcmp(ipx_broadcast_node, node, IPX_NODE_LEN) == 0) memcpy(dest_node, dev->broadcast, addr_len); - } else { + else memcpy(dest_node, &(node[IPX_NODE_LEN-addr_len]), addr_len); - } - /* make any compensation for differing physical/data link size */ + /* + * Make any compensation for differing physical/data link size + */ + skb = ipxitf_adjust_skbuff(intrfc, skb); - if (skb == NULL) return 0; + if (skb == NULL) + return 0; /* set up data link and physical headers */ skb->dev = dev; dl->datalink_header(dl, skb, dest_node); -#ifdef ALREADY_DONE_GUV - if (skb->sk != NULL) { - /* This is an outbound packet from this host. We need to - * increment the write count. - */ - skb->sk->wmem_alloc += skb->truesize; - } -#endif #if 0 - /* Now log the packet just before transmission */ + /* + * Now log the packet just before transmission + */ + dump_pkt("IPX snd:", (ipx_packet *)skb->h.raw); dump_data("ETH hdr:", skb->data, skb->h.raw - skb->data); #endif - /* Send it out */ + /* + * Send it out + */ + dev_queue_xmit(skb, dev, SOPRI_NORMAL); return 0; } -static int -ipxrtr_add_route(unsigned long, ipx_interface *, unsigned char *); +static int ipxrtr_add_route(unsigned long, ipx_interface *, unsigned char *); -static int -ipxitf_add_local_route(ipx_interface *intrfc) +static int ipxitf_add_local_route(ipx_interface *intrfc) { return ipxrtr_add_route(intrfc->if_netnum, intrfc, NULL); } @@ -1757,8 +1783,10 @@ if (sk->zapped) return -EIO; /* Socket not bound */ if(flags) return -EINVAL; - if(usipx) { - if(sk->ipx_port == 0) { + if(usipx) + { + if(sk->ipx_port == 0) + { struct sockaddr_ipx uaddr; int ret; @@ -1772,7 +1800,9 @@ return -EINVAL; if(usipx->sipx_family != AF_IPX) return -EINVAL; - } else { + } + else + { if(sk->state!=TCP_ESTABLISHED) return -ENOTCONN; usipx=&local_sipx; diff -u --recursive --new-file v1.3.45/linux/net/netlink.c linux/net/netlink.c --- v1.3.45/linux/net/netlink.c Fri Nov 17 08:42:34 1995 +++ linux/net/netlink.c Thu Nov 30 15:58:24 1995 @@ -90,7 +90,7 @@ if(file->f_flags&O_NONBLOCK) { sti(); - return -EWOULDBLOCK; + return -EAGAIN; } interruptible_sleep_on(&read_space_wait[minor]); if(current->signal & ~current->blocked) @@ -199,7 +199,7 @@ save_flags(flags); cli(); if(rdq_size[unit]+skb->len>MAX_QBYTES) - ret=-EWOULDBLOCK; + ret=-EAGAIN; else { skb_queue_tail(&skb_queue_rd[unit], skb); diff -u --recursive --new-file v1.3.45/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c --- v1.3.45/linux/net/netrom/af_netrom.c Wed Nov 8 07:11:46 1995 +++ linux/net/netrom/af_netrom.c Thu Nov 30 11:15:55 1995 @@ -1368,7 +1368,7 @@ { sock_register(nr_proto_ops.family, &nr_proto_ops); register_netdevice_notifier(&nr_dev_notifier); - printk("G4KLX NET/ROM for Linux. Version 0.3 ALPHA for AX25.030 Linux 1.3.35\n"); + printk("G4KLX NET/ROM for Linux. Version 0.4 ALPHA for AX25.030 Linux 1.3.45\n"); nr_default.quality = NR_DEFAULT_QUAL; nr_default.obs_count = NR_DEFAULT_OBS; diff -u --recursive --new-file v1.3.45/linux/net/netrom/nr_route.c linux/net/netrom/nr_route.c --- v1.3.45/linux/net/netrom/nr_route.c Fri Nov 17 08:42:34 1995 +++ linux/net/netrom/nr_route.c Thu Nov 30 11:15:55 1995 @@ -515,7 +515,6 @@ static struct device *nr_ax25_dev_get(char *devname) { struct device *dev; - ax25_address callsign; if ((dev = dev_get(devname)) == NULL) return NULL; @@ -523,9 +522,11 @@ if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25) return dev; +#ifdef CONFIG_BPQETHER if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ETHER) - if (arp_query((unsigned char *)&callsign, dev->pa_addr, dev)) + if (ax25_bpq_get_addr(dev) != NULL) return dev; +#endif return NULL; }