]> git.neil.brown.name Git - history.git/commitdiff
Import 1.1.81 1.1.81
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:50 +0000 (15:09 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:50 +0000 (15:09 -0500)
36 files changed:
CREDITS
Makefile
arch/i386/config.in
drivers/block/README.ide
drivers/block/README.sbpcd
drivers/block/ide-cd.c
drivers/block/ide.c
drivers/block/sbpcd.c
drivers/block/sbpcd2.c [new file with mode: 0644]
drivers/block/sbpcd3.c [new file with mode: 0644]
drivers/block/sbpcd4.c [new file with mode: 0644]
drivers/net/arcnet.c
drivers/scsi/ChangeLog
drivers/scsi/Makefile
drivers/scsi/README.st
drivers/scsi/eata_dma.c [new file with mode: 0644]
drivers/scsi/eata_dma.h [new file with mode: 0644]
drivers/scsi/hosts.c
drivers/scsi/hosts.h
drivers/scsi/scsi.c
drivers/scsi/scsi_module.c
drivers/scsi/sd.c
drivers/scsi/sg.c
drivers/scsi/sr.c
drivers/scsi/st.c
drivers/scsi/st.h
include/linux/fs.h
include/linux/mtio.h
include/linux/net.h
include/linux/pci.h
include/linux/sbpcd.h
init/main.c
kernel/ksyms.c
kernel/resource.c
net/socket.c
net/unix/proc.c

diff --git a/CREDITS b/CREDITS
index f9500cf9c8d0e3981df16edacc095a159a76e4ae..a22555331e81350d4140cbc211393f9149f22bd6 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -7,6 +7,10 @@
                        Linus
 ----------
 
+M: Matti Aarnio
+E: mea@utu.fi
+D: Dynamicized network socket allocations, LILO for AHA1542
+
 N: Werner Almesberger
 E: almesber@bernina.ethz.ch
 D: dosfs, LILO, some fd features, various other hacks here and there
index 79412c1fa7f85711312fb73930c516d8e995c960..e3d54757771a810029830d13194890117587c954 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 80
+SUBLEVEL = 81
 
 ARCH = i386
 
index 41a6e0ba892261d24afd39b7bec7d91ab3f2b9d2..e366c404f85eb7dee7e953eb9412ef25169a0069 100644 (file)
@@ -73,6 +73,7 @@ bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 y
 bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 n
 bool 'Adaptec AHA274X/284X support' CONFIG_SCSI_AHA274X n
 bool 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC n
+bool 'EATA-DMA (DPT,NEC&ATT for ISA,EISA,PCI) support' CONFIG_SCSI_EATA_DMA n
 bool 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F n
 bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN n
 bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 n
@@ -86,7 +87,7 @@ bool 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE
 bool 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 n
 bool 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR n
 bool '7000FASST SCSI support' CONFIG_SCSI_7000FASST n
-bool 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA n
+#bool 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA n
 #bool 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG n
 fi
 
index 651244f4ad8f87004124c59191f2a3fb1edd448b..82bee1100070d4716ac7528a397994966a2d9ab1 100644 (file)
@@ -81,13 +81,13 @@ interface (/dev/hda) and an IDE cdrom drive on the secondary interface
 
        ln -sf /dev/hdc /dev/cdrom
        mkdir /cd
-       mount /dev/cdrom /cd -t iso9660 -o ro,block=2048
+       mount /dev/cdrom /cd -t iso9660 -o ro
 
 Please pass on any feedback on the cdrom stuff to the author & maintainer,
 Scott Snyder (snyder@fnald0.fnal.gov).
 
-Note that present, the kernel is unable to execute demand-paged binaries
-directly off of the cdrom (due to the different block size).
+The kernel is now be able to execute binaries directly off of the cdrom,
+provided it is mounted with the default block size of 1024.
 
 The hdparm.c program for controlling various IDE features is now packaged
 separately.  Look for it on popular linux FTP sites.
index 433270bde94ad66b41ba824a3f79b7e8d0c42a28..e83a7f84b13bb0ce4bdbc58ebe24c4856330d723 100644 (file)
@@ -1,4 +1,4 @@
-This README belongs to release 3.0 or newer of the SoundBlaster Pro
+This README belongs to release 3.1 or newer of the SoundBlaster Pro
 (Matsushita, Kotobuki, Panasonic, CreativeLabs, Longshine and soon TEAC, too)
 CD-ROM driver for Linux.
 
@@ -28,11 +28,11 @@ Regarding CD200 and CD-55A support:
             (if you are: mail!; I do not have such drives).
     Please, don't drop simple questions about the new drives in the
             newsgroups. Full support needs more or less time.
-If you are able to set the appropriate DBG-xxx switches, you can mail me
-the "SBPCD:..." messages, regarding the new drives. But I mostly will
-not answer (just use) it.
+If you like to help, you can mail me the "SBPCD:..." messages, regarding the
+new drives. But I mostly will not answer (just use) it.
 
-This driver is NOT for Mitsumi or Sony or Aztech or Philips or XXX drives.
+This driver is NOT for Mitsumi or Sony or Aztech or Philips or XXX drives,
+and this driver is in no way useable for any new IDE ATAPI drive.
 For Aztech CDA-268 drives (and for some Wearnes, Okano and Orchid drives),
 Werner Zimmermann has done a driver which currently resides at ftp.gwdg.de
 under /pub/linux/cdrom/drivers/aztech/.
@@ -50,15 +50,15 @@ work.
 The interface type has to get configured in /usr/include/linux/sbpcd.h, 
 because the behavior of some sound card interfaces is different.
 
-The driver respects different drive firmware releases - my old drive is a 2.11,
+The driver respects all known drive firmware releases - my old drive is a 2.11,
 but it should work with "old" drives <2.01 ... >3.00 and with "new" drives
 (which count the releases around 0.75 or 1.00).
 
 Up to 4 drives per interface card, and up to 4 interface cards are supported.
-CR-52x ("old"), CR-56x ("new") and LCS drives can be mixed, but the CR-521
-ones are hard-wired to drive ID 0. The drives have to use different drive IDs,
-and each drive has to get a unique minor number (0...3), corresponding to it's
-drive ID.
+All supported drive families can be mixed, but the CR-521 drives are 
+hard-wired to drive ID 0. The drives have to use different drive IDs, and each
+drive has to get a unique minor number (0...3), corresponding indirectly to 
+it's drive ID.
 The drive IDs may be selected freely from 0 to 3 - they do not have to be in
 consecutive order.
 
@@ -79,24 +79,22 @@ to change old drives to any ID, too. He writes in this sense:
    did not work with other values. If the values are not good,
    ID 3 behaves like ID 0."
 
-To use more than 4 drives (now that the single-speed CR-521's are as cheap as
-50$), you need a second interface card and you have to "duplicate" the driver.
-Just copy sbpcd.c into sbpcd2.c and so forth and change SBPCD_ISSUE (at top
-of sbpcd2.c) accordingly.
+To use more than 4 drives, you simply need a second controller card at a 
+different address and a second cable.
 
 The driver supports reading of data from the CD and playing of audio tracks.
 The audio part should run with WorkMan, xcdplayer, with the "non-X11" products
 CDplayer and WorkBone - tell me if it is not compatible with other software.
 
-With the "new" drive family CR-562 and CR-563, the reading of audio frames is
-possible. This is currently implemented by an IOCTL function which reads only
-up to 4 frames of 2352 bytes at once. Reading more than 1 frame at once misses
-some chunks at each frame boundary. Reading the same frame a second time gives
-different data; the frame data start at a different position. But all read
-bytes are valid, and we always read 98 consecutive chunks (of 24 Bytes) as a
-frame. This lack has to get corrected by higher level software which reads the
-same frame again and tries to find and eliminate overlapping chunks
-(24-byte-pieces).
+With the CR-562 and CR-563 drives, the reading of audio frames is possible.
+This is implemented by an IOCTL function which per default reads only up to
+4 frames of 2352 bytes at once (configurable with the "READ_AUDIO" define).
+Reading the same frame a second time gives different data; the frame data 
+start at a different position, but all read bytes are valid, and we always
+read 98 consecutive chunks (of 24 Bytes) as a frame. Reading more than 1 frame
+at once misses some chunks at each frame boundary.This lack has to get 
+corrected by external, "higher level" software which reads the same frame 
+again and tries to find and eliminate overlapping chunks (24-byte-pieces).
 
 The transfer rate with reading audio (1-frame-pieces) is as slow as 32 kB/sec.
 This could be better reading bigger chunks, but the "missing" chunks occur at
@@ -104,12 +102,11 @@ the beginning of each single frame.
 The software interface possibly may change a bit the day the SCSI driver
 supports it too.
 
-With the CR-562 and CR-563 drives, MultiSession is supported, "ManySession"
-(not recommended, see below) alternatively.
-Photo CDs work, too (the "old" drives like CR-521 can access only the first
+With the CR-562 and CR-563 drives, MultiSession is supported.
+Photo CDs work (the "old" drives like CR-521 can access only the first
 session of a photoCD).
-At ftp.gwdg.de:/pub/linux/hpcdtoppm/ is Hadmut Danisch's package to convert
-photo CD image files.
+At ftp.gwdg.de:/pub/linux/hpcdtoppm/ you will find Hadmut Danisch's package to
+convert photo CD image files and Gerd Knorr's viewing utility.
 
 The transfer rate will reach 150 kB/sec with "old" drives and 300 kB/sec with
 double-speed drives. XA (PhotoCD) disks with "old" drives give only 50 kB/sec.
@@ -133,6 +130,7 @@ To install:
           Most "compatible" sound cards (for example "Highscreen", "SoundFX"
           and "Galaxy") need "SBPRO 0".
           The "no-sound" board from OmniCd needs the "SBPRO 1" setup.
+          All other "no-sound" boards need the "SBPRO 0" setup.
           The Spea Media FX sound card needs "SBPRO 2".
           sbpcd.c holds some examples in it's auto-probe list.
           If you configure "SBPRO" wrong, the playing of audio CDs will work,
@@ -149,27 +147,30 @@ To install:
       This is especially useful if you install a fresh distribution.
 2. "cd /usr/src/linux" and do a "make config" and select "y" for Matsushita
    CD-ROM support and for ISO9660 FileSystem support. If you do not have a
-   second, third, or fourth controller and/or did not prepare sbpcd2 etc.,
-   do not say "y" to the secondary Matsushita CD-ROM questions.
+   second, third, or fourth controller installed, do not say "y" to the 
+   secondary Matsushita CD-ROM questions.
    SCSI and/or SCSI CD-ROM support is not needed.
 
 3. Then do a "make dep", then make the kernel image ("make zlilo" or else).
 
 4. Make the device file(s). The driver uses definitely and exclusive the
    MAJOR 25, so do
-        mknod /dev/sbpcd b 25 0       (if you have only drive #0)
+        mknod /dev/sbpcd  b 25 0       (if you have only one drive)
    and/or
         mknod /dev/sbpcd0 b 25 0
         mknod /dev/sbpcd1 b 25 1
         mknod /dev/sbpcd2 b 25 2
         mknod /dev/sbpcd3 b 25 3
    to make the node(s).
-   Take care that you create a node with the same MINOR as your drive ID is.
-   So, if the DOS driver tells you have drive id #3, you have to
-        mknod /dev/<any_name> b 25 3
+
+   The driver no longer uses the "AT bus style" device numbering; the SCSI
+   scheme is used now; that means, the "first found" drive gets MINOR 0
+   (regardless to it's jumpered ID), the "next found" (at the same cable)
+   gets MINOR 1, ...
    
    For a second interface board, you have to make nodes like
         mknod /dev/sbpcd4 b 26 0
+        mknod /dev/sbpcd5 b 26 1
    and so on. Use the MAJORs 26, 27, 28.
 
    If you further make a link like
@@ -198,19 +199,9 @@ I/O port 0x0230 first. If this is not appropriate, sbpcd.h should get changed
 No DMA and no IRQ is used, so the IRQ line stays free for the SB Pro sound
 drivers.
 
-To reduce or increase the amount of kernel messages, edit sbpcd.c and change
-the initialization of the variable "sbpcd_debug". This is the way to get rid
-of the initial warning message block, too.
-
-With "#define MANY_SESSION 1" (sbpcd.c), the driver can use "many-session" CDs.
-This will work only with "new" drives like CR-562 or CR-563. That is NOT
-multisession - it is a CD with multiple independent sessions, each containing
-block addresses as if it were the only session. With this feature enabled, the
-driver will read the LAST session. Without it, the FIRST session gets read.
-If you would like the support of reading "in-between" sessions, drop me a mail
-and some food for the soul. :-)
-Those "many-session" CDs can get made by CDROM writers like Philips CDD 521.
-If you enable this feature, it is impossible to read true multisession CDs.
+To reduce or increase the amount of kernel messages, edit sbpcd.c and play
+with the "DBG_xxx" switches (initialization of the variable "sbpcd_debug").
+This is the way to get rid of the initial warning message block, too.
 
 The driver uses the "variable BLOCK_SIZE" feature. To use it, you have to
 specify "block=2048" as a mount option. Doing this will disable the direct
@@ -272,6 +263,8 @@ main(int argc, char *argv[])
 }
 /*===================== end program ========================================*/
 
+Jeff Tranter's "eject" utility can do this, too (and more) for you.
+
 There is a new ioctl CDROMMULTISESSION to obtain with a user program if
 the CD is an XA disk and - if it is - where the last session starts. The
 following example illustrates how to call it:
@@ -341,12 +334,15 @@ main(int argc, char *argv[])
 Auto-probing at boot time:
 --------------------------
 
-The driver does auto-probing at many well-known interface card addresses. The
-idea to do that came from Adam J. Richter (YGGDRASIL). Some well-known
-addresses are excluded from auto-probing because they can cause a hang if an
-ethernet card gets touched.
+The driver does auto-probing at many well-known interface card addresses,
+but not all:
+Some probings can cause a hang if an NE2000 ethernet card gets touched, because
+SBPCD's auto-probing happens before the initialization of the net drivers.
+Those "hazardous" addresses are excluded from auto-probing; the "kernel 
+command line" feature has to be used during installation if you have your 
+drive at those addresses.
 
-This auto-probing looks first at the configured address resp. the address
+The auto-probing looks first at the configured address resp. the address
 submitted by the kernel command line. With this, it is possible to use this
 driver within installation boot floppies, and for any non-standard address,
 too.
@@ -357,9 +353,6 @@ o.k., but you will get I/O errors during mount). In that case, use the "kernel
 command line" feature and specify address & type at boot time to find out the
 right setup.
 
-SBPCD's auto-probing happens before the initialization of the net drivers. That
-makes a hang possible if an ethernet card gets touched.
-
 For every-day use, address and type should get configured within sbpcd.h. That
 will stop the auto-probing due to success with the first try.
 
@@ -367,10 +360,9 @@ will stop the auto-probing due to success with the first try.
 Setting up address and interface type:
 --------------------------------------
 
-If your I/O port address is not 0x0230 or if you use a "no-sound" interface
-other than OmniCD, you have to look for the #defines near the beginning of
-sbpcd.h and configure them: set SBPRO to 0 or 1 or 2, and change CDROM_PORT to
-the address of your CDROM I/O port.
+If your I/O port address is not 0x340, you have to look for the #defines near
+the beginning of sbpcd.h and configure them: set SBPRO to 0 or 1 or 2, and
+change CDROM_PORT to the address of your CDROM I/O port.
 
 Most of the "SoundBlaster compatible" cards behave like the no-sound
 interfaces! 
@@ -384,19 +376,19 @@ you can set SOUND_BASE (in sbpcd.h) to get it done with your card, too...
 Using audio CDs:
 ----------------
 
-Workman, WorkBone, xcdplayer and cdplayer should work good now, even with the
-double-speed drives.
+Workman, WorkBone, xcdplayer, cdplayer and the nice little tool "cdplay" (see
+README.aztcd from the Aztech driver package) should work.
 
 The program CDplayer likes to talk to "/dev/mcd" only, xcdplayer wants
-"/dev/rsr0", workman loves "/dev/sr0" - so, do the appropriate links for using
-them without the need of supplying parameters.
+"/dev/rsr0", workman loves "/dev/sr0" or "/dev/cdrom" - so, do the appropriate
+links for using them without the need of supplying parameters.
 
 
 Copying audio tracks:
 ---------------------
 
-The following little program will copy track 2 of an audio CD into the file
-"track02":
+The following program will copy track 1 (or a piece of it) from an audio CD
+into the file "track01":
 
 /*=================== begin program ========================================*/
 /*
@@ -419,13 +411,14 @@ The following little program will copy track 2 of an audio CD into the file
  * This is only an example of the low-level access routine. The read data are
  * pure 16-bit CDDA values; they have to get converted to make sound out of
  * them.
+ * It is no fun to listen to it without prior overlap/underlap correction!
  */
 #include <stdio.h>
 #include <sys/ioctl.h>
 #include <linux/cdrom.h>
 
 static struct cdrom_tochdr hdr;
-static struct cdrom_tocentry entry[100];
+static struct cdrom_tocentry entry[101];
 static struct cdrom_read_audio arg;
 static u_char buffer[CD_FRAMESIZE_RAW];
 static int datafile, drive;
@@ -484,10 +477,9 @@ main(int argc, char *argv[])
 /*
  * ask for track number (not implemented here)
  */
-track=2;
-#if 0 /* just read a little piece */
-entry[track].cdte_addr.lba=170;
-entry[track+1].cdte_addr.lba=190;
+track=1;
+#if 0 /* just read a little piece (4 seconds) */
+entry[track+1].cdte_addr.lba=entry[track].cdte_addr.lba+300;
 #endif
 /*
  * read track into file
@@ -504,20 +496,19 @@ entry[track+1].cdte_addr.lba=190;
   arg.nframes=1;
   arg.buf=&buffer[0];
   limit=entry[track+1].cdte_addr.lba;
-  for (i=arg.addr.lba;i<limit;i++)
+  for (;arg.addr.lba<limit;arg.addr.lba++)
     {
       err=ioctl(drive, CDROMREADAUDIO, &arg);
       if (err!=0)
        {
-         fprintf(stderr, "can't read frame #%d (error %d).\n", 
-                i-entry[track].cdte_addr.lba+1, err);
-         exit (-1);
+         fprintf(stderr, "can't read abs. frame #%d (error %d).\n", 
+                arg.addr.lba, err);
        }
       j=write(datafile, &buffer[0], CD_FRAMESIZE_RAW);
       if (j!=CD_FRAMESIZE_RAW)
        {
-         fprintf(stderr,"I/O error (datafile) at frame %d\n",
-                i-entry[track].cdte_addr.lba+1);
+         fprintf(stderr,"I/O error (datafile) at rel. frame %d\n",
+                        arg.addr.lba-entry[track].cdte_addr.lba);
        }
       arg.addr.lba++;
     }
index 9284d3ffa63ae2abdb94c5d54dbaa18021266701..21bd50cb4b9d1241a198c0ce4819326318e9fd0c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/block/ide-cd.c  (ALPHA)
+ * linux/drivers/block/ide-cd.c  (BETA)
  *
  * 1.00  Oct 31, 1994 -- Initial version.
  * 1.01  Nov  2, 1994 -- Fixed problem with starting request in
  *                       Try to use LBA instead of track or MSF addressing
  *                       when possible.
  *                       Don't wait for READY_STAT.
+ * 2.03  Jan 10, 1995 -- Rewrite block read routines to handle block sizes
+ *                       other than 2k and to move multiple sectors in a
+ *                       single transaction.
  *
  * ATAPI cd-rom driver.  To be used with ide.c.
  *
- * Copyright (C) 1994  scott snyder  <snyder@fnald0.fnal.gov>
+ * Copyright (C) 1994, 1995  scott snyder  <snyder@fnald0.fnal.gov>
  */
 
 #include <linux/cdrom.h>
 
-#define BLOCKS_PER_FRAME (CD_FRAMESIZE / 512)
+#define SECTOR_SIZE 512
+#define SECTOR_BITS 9
+#define SECTORS_PER_FRAME (CD_FRAMESIZE / SECTOR_SIZE)
+
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
 
 #define OUT_WORDS(b,n)  outsw (IDE_PORT (HD_DATA, dev->hwif), (b), (n))
 #define IN_WORDS(b,n)   insw  (IDE_PORT (HD_DATA, dev->hwif), (b), (n))
@@ -107,11 +114,34 @@ struct atapi_toc_entry {
 
 struct atapi_toc {
   struct atapi_toc_header hdr;
-  struct atapi_toc_entry  ent[MAX_TRACKS+1];
+  struct atapi_toc_entry  ent[MAX_TRACKS+1];  /* One extra for the leadout. */
+};
+
+
+#define SECTOR_BUFFER_SIZE CD_FRAMESIZE
+
+/* Extra per-device info for cdrom drives. */
+struct cdrom_info {
+
+  /* Buffer for table of contents.  NULL if we haven't allocated
+     a TOC buffer for this device yet. */
+
+  struct atapi_toc *toc;
+
+  /* Sector buffer.  If a read request wants only the first part of a cdrom
+     block, we cache the rest of the block here, in the expectation that that
+     data is going to be wanted soon.  SECTOR_BUFFERED is the number of the
+     first buffered sector, and NSECTORS_BUFFERED is the number of sectors
+     in the buffer.  Before the buffer is allocated, we should have
+     SECTOR_BUFFER == NULL and NSECTORS_BUFFERED == 0. */
+
+  unsigned long sector_buffered;
+  unsigned long nsectors_buffered;
+  char *sector_buffer;
 };
 
 
-static struct atapi_toc *cdrom_toc[2][MAX_DRIVES];
+static struct cdrom_info cdrom_info[2][MAX_DRIVES];
 
 
 \f
@@ -119,6 +149,34 @@ static struct atapi_toc *cdrom_toc[2][MAX_DRIVES];
  * Generic packet command support routines.
  */
 
+
+static void cdrom_end_request (int uptodate, ide_dev_t *dev)
+{
+  struct request *rq = ide_cur_rq[dev->hwif];
+
+  /* The code in blk.h can screw us up on error recovery if the block
+     size is larger than 1k.  Fix that up here. */
+  if (!uptodate && rq->bh != 0)
+    {
+      int adj = rq->current_nr_sectors - 1;
+      rq->current_nr_sectors -= adj;
+      rq->sector += adj;
+    }
+
+  end_request (uptodate, dev->hwif);
+}
+
+
+/* Mark that we've seen a media change, and invalidate our internal
+   buffers. */
+static void cdrom_saw_media_change (ide_dev_t *dev)
+{
+  CDROM_FLAGS (dev)->media_changed = 1;
+  CDROM_FLAGS (dev)->toc_valid = 0;
+  cdrom_info[dev->hwif][dev->select.b.drive].nsectors_buffered = 0;
+}
+
+
 /* Returns 0 if the request should be continued.
    Returns 1 if the request was ended. */
 static int cdrom_decode_status (ide_dev_t *dev, int good_stat, int *stat_ret)
@@ -140,14 +198,13 @@ static int cdrom_decode_status (ide_dev_t *dev, int good_stat, int *stat_ret)
   if ((err & 0xf0) == 0x20)
     {
       struct packet_command *pc;
-      CDROM_FLAGS (dev)->media_changed = 1;
-      CDROM_FLAGS (dev)->toc_valid = 0;
+      cdrom_saw_media_change (dev);
 
       /* Fail the request if this is a read command. */
       if (rq->cmd == READ)
         {
           printk ("%s : tray open\n", dev->name);
-          end_request (0, dev->hwif);
+          cdrom_end_request (0, dev);
         }
 
       else
@@ -164,22 +221,21 @@ static int cdrom_decode_status (ide_dev_t *dev, int good_stat, int *stat_ret)
 
           /* Set the error flag and complete the request. */
           pc->stat = 1;
-          end_request (1, dev->hwif);
+          cdrom_end_request (1, dev);
         }
     }
 
   /* Check for media change. */
   else if ((err & 0xf0) == 0x60)
     {
-      CDROM_FLAGS (dev)->media_changed = 1;
-      CDROM_FLAGS (dev)->toc_valid = 0;
+      cdrom_saw_media_change (dev);
       printk ("%s: media changed\n", dev->name);
 
       /* We're going to retry this command.
          But be sure to give up if we've retried too many times. */
       if ((++rq->errors > ERROR_MAX))
         {
-          end_request (0, dev->hwif);
+          cdrom_end_request (0, dev);
         }
     }
 
@@ -189,19 +245,19 @@ static int cdrom_decode_status (ide_dev_t *dev, int good_stat, int *stat_ret)
       struct packet_command *pc = (struct packet_command *)rq->buffer;
       dump_status (dev->hwif, "packet command error", stat);
       pc->stat = 1;  /* signal error */
-      end_request (1, dev->hwif);
+      cdrom_end_request (1, dev);
     }
 
   /* If there were other errors, go to the default handler. */
   else if ((err & ~ABRT_ERR) != 0)
     {
-      ide_error (dev, "cdrom_read_intr", stat);
+      ide_error (dev, "cdrom_decode_status", stat);
     }
 
   /* Else, abort if we've racked up too many retries. */
   else if ((++rq->errors > ERROR_MAX))
     {
-      end_request (0, dev->hwif);
+      cdrom_end_request (0, dev);
     }
 
   /* Retry, or handle the next request. */
@@ -266,36 +322,95 @@ static int cdrom_transfer_packet_command (ide_dev_t *dev,
  * Block read functions.
  */
 
-static int cdrom_start_read (ide_dev_t *dev, unsigned int block);
-
-
 /*
- * Interrupt routine to read the final status from a transfer.
+ * Buffer up to SECTORS_TO_TRANSFER sectors from the drive in our sector
+ * buffer.  SECTOR is the number of the first sector to be buffered.
  */
-static void cdrom_read_intr_2 (ide_dev_t *dev)
+static void cdrom_buffer_sectors (ide_dev_t *dev, unsigned long sector,
+                                  int sectors_to_transfer)
 {
-  int stat;
-  struct request *rq = ide_cur_rq[dev->hwif];
+  struct cdrom_info *info = &cdrom_info[dev->hwif][dev->select.b.drive];
 
-  stat = GET_STAT (dev->hwif);
+  /* Number of sectors to read into the buffer. */
+  int sectors_to_buffer = MIN (sectors_to_transfer,
+                               (SECTOR_BUFFER_SIZE >> SECTOR_BITS));
 
-  if (OK_STAT (stat, 0, BAD_STAT))
+  char *dest;
+
+  /* If we don't yet have a sector buffer, try to allocate one.
+     If we can't get one atomically, it's not fatal -- we'll just throw
+     the data away rather than caching it. */
+  if (info->sector_buffer == NULL)
     {
-      if (rq->current_nr_sectors <= 0)
-        {
-          end_request (1, dev->hwif);
-        }
+      info->sector_buffer = (char *) kmalloc (SECTOR_BUFFER_SIZE, GFP_ATOMIC);
 
-      if (rq->current_nr_sectors > 0)
+      /* If we couldn't get a buffer, don't try to buffer anything... */
+      if (info->sector_buffer == NULL)
+        sectors_to_buffer = 0;
+    }
+
+  /* Remember the sector number and the number of sectors we're storing. */
+  info->sector_buffered = sector;
+  info->nsectors_buffered = sectors_to_buffer;
+
+  /* Read the data into the buffer. */
+  dest = info->sector_buffer;
+  while (sectors_to_buffer > 0)
+    {
+      IN_WORDS (dest, SECTOR_SIZE / 2);
+      --sectors_to_buffer;
+      --sectors_to_transfer;
+      dest += SECTOR_SIZE;
+    }
+
+  /* Throw away any remaining data. */
+  while (sectors_to_transfer > 0)
+    {
+      char dum[SECTOR_SIZE];
+      IN_WORDS (dest, sizeof (dum) / 2);
+      --sectors_to_transfer;
+    }
+}
+
+
+/*
+ * Check the contents of the interrupt reason register from the cdrom
+ * and attempt to recover if there are problems.  Returns  0 if everything's
+ * ok; nonzero if the request has been terminated.
+ */
+static inline
+int cdrom_read_check_ireason (ide_dev_t *dev, int len, int ireason)
+{
+  ireason &= 3;
+  if (ireason == 2) return 0;
+
+  if (ireason == 0)
+    {
+      /* Whoops... The drive is expecting to receive data from us! */
+      printk ("%s: cdrom_read_intr: "
+              "Drive wants to transfer data the wrong way!\n",
+              dev->name);
+
+      /* Throw some data at the drive so it doesn't hang
+         and quit this request. */
+      while (len > 0)
         {
-          cdrom_start_read (dev, rq->sector);
-          return;
+          short dum = 0;
+          OUT_WORDS (&dum, 1);
+          len -= 2;
         }
     }
+
   else
-    ide_error (dev, "cdrom_read_intr_2", stat);
+    {
+      /* Drive wants a command packet, or invalid ireason... */
+      printk ("%s: cdrom_read_intr: bad interrupt reason %d\n",
+              dev->name, ireason);
+    }
 
+  cdrom_end_request (0, dev);
   DO_REQUEST;
+  return -1;
 }
 
 
@@ -304,34 +419,175 @@ static void cdrom_read_intr_2 (ide_dev_t *dev)
  */
 static void cdrom_read_intr (ide_dev_t *dev)
 {
-  int stat_dum, len;
+  int stat;
+  int ireason, len, sectors_to_transfer, nskip;
+
   struct request *rq = ide_cur_rq[dev->hwif];
 
   /* Check for errors. */
-  if (cdrom_decode_status (dev, DRQ_STAT, &stat_dum)) return;
+  if (cdrom_decode_status (dev, 0, &stat)) return;
 
-  /* Error bit not set.
-     Read the device registers to see how much data is waiting. */
+  /* Read the interrupt reason and the transfer length. */
+  ireason = IN_BYTE (HD_NSECTOR, dev->hwif);
   len = IN_BYTE (HD_LCYL, dev->hwif) + 256 * IN_BYTE (HD_HCYL, dev->hwif);
 
-  if (len != CD_FRAMESIZE)
+  /* If DRQ is clear, the command has completed. */
+  if ((stat & DRQ_STAT) == 0)
+    {
+      /* If we're not done filling the current buffer, complain.
+         Otherwise, complete the command normally. */
+      if (rq->current_nr_sectors > 0)
+        {
+          printk ("%s: cdrom_read_intr: data underrun (%ld blocks)\n",
+                  dev->name, rq->current_nr_sectors);
+          cdrom_end_request (0, dev);
+        }
+      else
+        cdrom_end_request (1, dev);
+
+      DO_REQUEST;
+      return;
+    }
+
+  /* Check that the drive is expecting to do the same thing that we are. */
+  if (cdrom_read_check_ireason (dev, len, ireason)) return;
+
+  /* Assume that the drive will always provide data in multiples of at least
+     SECTOR_SIZE, as it gets hairy to keep track of the transfers otherwise. */
+  if ((len % SECTOR_SIZE) != 0)
+    {
+      printk ("%s: cdrom_read_intr: Bad transfer size %d\n",
+              dev->name, len);
+      printk ("  This drive is not supported by this version of the driver\n");
+      cdrom_end_request (0, dev);
+      DO_REQUEST;
+      return;
+    }
+
+  /* The number of sectors we need to read from the drive. */
+  sectors_to_transfer = len / SECTOR_SIZE;
+
+  /* First, figure out if we need to bit-bucket any of the leading sectors. */
+  nskip = MIN ((int)(rq->current_nr_sectors - (rq->bh->b_size >> SECTOR_BITS)),
+               sectors_to_transfer);
+
+  while (nskip > 0)
     {
-      printk ("cdrom_read_intr: funny value for read length %d\n", len);
-      if (len > CD_FRAMESIZE) len = CD_FRAMESIZE;
+      /* We need to throw away a sector. */
+      char dum[SECTOR_SIZE];
+      IN_WORDS (dum, sizeof (dum) / 2);
+
+      --rq->current_nr_sectors;
+      --nskip;
+      --sectors_to_transfer;
     }
 
-  IN_WORDS (rq->buffer, len/2);
+  /* Now loop while we still have data to read from the drive. */
+  while (sectors_to_transfer > 0)
+    {
+      int this_transfer;
 
-  rq->current_nr_sectors -= BLOCKS_PER_FRAME;
-  rq->nr_sectors -= BLOCKS_PER_FRAME;
-  rq->sector += BLOCKS_PER_FRAME;
-  rq->buffer += CD_FRAMESIZE;
+      /* If we've filled the present buffer but there's another chained
+         buffer after it, move on. */
+      if (rq->current_nr_sectors == 0 &&
+          rq->nr_sectors > 0)
+        cdrom_end_request (1, dev);
 
-  /* Wait for another interrupt with the final status. */
-  ide_handler[dev->hwif] = cdrom_read_intr_2;
+      /* If the buffers are full, cache the rest of the data in our
+         internal buffer. */
+      if (rq->current_nr_sectors == 0)
+        {
+          cdrom_buffer_sectors (dev, rq->sector, sectors_to_transfer);
+          sectors_to_transfer = 0;
+        }
+      else
+        {
+          /* Transfer data to the buffers.
+             Figure out how many sectors we can transfer
+             to the current buffer. */
+          this_transfer = MIN (sectors_to_transfer,
+                               rq->current_nr_sectors);
+
+          /* Read this_transfer sectors into the current buffer. */
+          while (this_transfer > 0)
+            {
+              IN_WORDS (rq->buffer, SECTOR_SIZE / 2);
+              rq->buffer += SECTOR_SIZE;
+              --rq->nr_sectors;
+              --rq->current_nr_sectors;
+              ++rq->sector;
+              --this_transfer;
+              --sectors_to_transfer;
+            }
+        }
+    }
+
+  /* Done moving data!
+     Wait for another interrupt. */
+  ide_handler[dev->hwif] = cdrom_read_intr;
 }
 
 
+/*
+ * Try to satisfy some of the current read request from our cached data.
+ * Returns nonzero if the request has been completed, zero otherwise.
+ */
+static int cdrom_read_from_buffer (ide_dev_t *dev)
+{
+  struct cdrom_info *info = &cdrom_info[dev->hwif][dev->select.b.drive];
+  struct request *rq = ide_cur_rq[dev->hwif];
+
+  /* Can't do anything if there's no buffer. */
+  if (info->sector_buffer == NULL) return 0;
+
+  /* Loop while this request needs data and the next block is present
+     in our cache. */
+  while (rq->nr_sectors > 0 &&
+         rq->sector >= info->sector_buffered &&
+         rq->sector < info->sector_buffered + info->nsectors_buffered)
+    {
+      if (rq->current_nr_sectors == 0)
+        cdrom_end_request (1, dev);
+
+      memcpy (rq->buffer,
+              info->sector_buffer +
+                (rq->sector - info->sector_buffered) * SECTOR_SIZE,
+              SECTOR_SIZE);
+      rq->buffer += SECTOR_SIZE;
+      --rq->current_nr_sectors;
+      --rq->nr_sectors;
+      ++rq->sector;
+    }
+
+  /* If we've statisfied the current request, terminate it successfully. */
+  if (rq->nr_sectors == 0)
+    {
+      cdrom_end_request (1, dev);
+      return -1;
+    }
+
+  /* Move on to the next buffer if needed. */
+  if (rq->current_nr_sectors == 0)
+    cdrom_end_request (1, dev);
+
+  /* If this condition does not hold, then the kluge i use to
+     represent the number of sectors to skip at the start of a transfer
+     will fail.  I think that this will never happen, but let's be
+     paranoid and check. */
+  if (rq->current_nr_sectors < (rq->bh->b_size >> SECTOR_BITS) &&
+      (rq->sector % SECTORS_PER_FRAME) != 0)
+    {
+      printk ("%s: cdrom_read_from_buffer: buffer botch (%ld)\n",
+              dev->name, rq->sector);
+      cdrom_end_request (0, dev);
+      return -1;
+    }
+
+  return 0;
+}
+
+
+
 /*
  * Routine to send a read packet command to the drive.
  * This is usually called directly from cdrom_start_read.
@@ -343,10 +599,51 @@ static int cdrom_start_read_continuation (ide_dev_t *dev)
   struct packet_command pc;
   struct request *rq = ide_cur_rq[dev->hwif];
 
+  int nsect, sector, nframes, frame, nskip;
+
+  /* Number of sectors to transfer. */
+  nsect = rq->nr_sectors;
+
+  /* Starting sector. */
+  sector = rq->sector;
+
+  /* If the requested sector doesn't start on a cdrom block boundary,
+     we must adjust the start of the transfer so that it does,
+     and remember to skip the first few sectors.  If the CURRENT_NR_SECTORS
+     field is larger than the size of the buffer, it will mean that
+     we're to skip a number of sectors equal to the amount by which
+     CURRENT_NR_SECTORS is larger than the buffer size. */
+  nskip = (sector % SECTORS_PER_FRAME);
+  if (nskip > 0)
+    {
+      /* Sanity check... */
+      if (rq->current_nr_sectors != (rq->bh->b_size >> SECTOR_BITS))
+        {
+          printk ("%s: cdrom_start_read_continuation: buffer botch (%ld)\n",
+                  dev->name, rq->current_nr_sectors);
+          cdrom_end_request (0, dev);
+          DO_REQUEST;
+          return 1;
+        }
+
+      sector -= nskip;
+      nsect += nskip;
+      rq->current_nr_sectors += nskip;
+    }
+
+  /* Convert from sectors to cdrom blocks, rounding up the transfer
+     length if needed. */
+  nframes = (nsect + SECTORS_PER_FRAME-1) / SECTORS_PER_FRAME;
+  frame = sector / SECTORS_PER_FRAME;
+
+  /* Largest number of frames was can transfer at once is 64k-1. */
+  nframes = MIN (nframes, 65535);
+
   /* Set up the command */
   memset (&pc.c, 0, sizeof (pc.c));
   pc.c[0] = READ_10;
-  pc.c[8] = 1;  /* lsb of transfer length */
+  pc.c[7] = (nframes >> 8);
+  pc.c[8] = (nframes & 0xff);
 
   /* Write the sector address into the command image. */
   {
@@ -354,7 +651,7 @@ static int cdrom_start_read_continuation (ide_dev_t *dev)
       struct {unsigned char b0, b1, b2, b3;} b;
       struct {unsigned long l0;} l;
     } conv;
-    conv.l.l0 = rq->sector / BLOCKS_PER_FRAME;
+    conv.l.l0 = frame;
     pc.c[2] = conv.b.b3;
     pc.c[3] = conv.b.b2;
     pc.c[4] = conv.b.b1;
@@ -381,17 +678,25 @@ static int cdrom_start_read (ide_dev_t *dev, unsigned int block)
 {
   struct request *rq = ide_cur_rq[dev->hwif];
 
-  if (rq->cmd == READ &&
-      (rq->current_nr_sectors != BLOCKS_PER_FRAME ||
-       (rq->sector & (BLOCKS_PER_FRAME-1)) != 0))
-        {
-          printk ("cdrom_start_read: funny request 0x%lx 0x%lx\n",
-                  rq->current_nr_sectors, rq->sector);
-          end_request (0, dev->hwif);
-          return 1;
-        }
+  /* We may be retrying this request after an error.
+     Fix up any weirdness which might be present in the request packet. */
+  if (rq->buffer != rq->bh->b_data)
+    {
+      int n = (rq->buffer - rq->bh->b_data) / SECTOR_SIZE;
+      rq->buffer = rq->bh->b_data;
+      rq->nr_sectors += n;
+      rq->current_nr_sectors += n;
+      rq->sector -= n;
+    }
+
+  if (rq->current_nr_sectors > (rq->bh->b_size >> SECTOR_BITS))
+    rq->current_nr_sectors = rq->bh->b_size;
 
-  if (cdrom_start_packet_command (dev, CD_FRAMESIZE))
+  /* Satisfy whatever we can of this request from our cached sector. */
+  if (cdrom_read_from_buffer (dev))
+    return 1;
+
+  if (cdrom_start_packet_command (dev, 32768))
     return 1;
 
   if (CDROM_FLAGS (dev)->drq_interrupt)
@@ -406,6 +711,7 @@ static int cdrom_start_read (ide_dev_t *dev, unsigned int block)
 }
 
 
+
 \f
 /****************************************************************************
  * Execute all other packet commands.
@@ -429,13 +735,13 @@ static void cdrom_pc_intr (ide_dev_t *dev)
   if ((stat & DRQ_STAT) == 0)
     {
       if (pc->buflen == 0)
-        end_request (1, dev->hwif);
+        cdrom_end_request (1, dev);
       else
         {
           printk ("%s: cdrom_pc_intr: data underrun %d\n",
                   dev->name, pc->buflen);
           pc->stat = 1;
-          end_request (1, dev->hwif);
+          cdrom_end_request (1, dev);
         }
       DO_REQUEST;
       return;
@@ -616,23 +922,10 @@ static int do_rw_cdrom (ide_dev_t *dev, unsigned long block)
   if (rq -> cmd != READ)
     {
       printk ("ide-cd: bad cmd %d\n", rq -> cmd);
-      end_request (0, dev->hwif);
+      cdrom_end_request (0, dev);
       return 1;
     }
 
-  if (rq->cmd == READ)
-    {
-      /* This can happen if there was an I/O error on the previous
-         buffer in this request. */
-      if ((rq->nr_sectors & (BLOCKS_PER_FRAME-1)) == BLOCKS_PER_FRAME-1 &&
-          (rq->sector & (BLOCKS_PER_FRAME-1)) == 1 &&
-          (rq->current_nr_sectors & (BLOCKS_PER_FRAME-1)) == 0)
-        {
-          rq->nr_sectors &= (BLOCKS_PER_FRAME-1);
-          rq->sector = (rq->sector+BLOCKS_PER_FRAME) & (BLOCKS_PER_FRAME-1);
-        }
-    }
-
   return cdrom_start_read (dev, block);
 }
 
@@ -802,14 +1095,14 @@ static int
 cdrom_read_toc (ide_dev_t *dev)
 {
   int stat, ntracks, i;
-  struct atapi_toc *toc = cdrom_toc[dev->hwif][dev->select.b.drive];
+  struct atapi_toc *toc = cdrom_info[dev->hwif][dev->select.b.drive].toc;
 
   if (toc == NULL)
     {
       /* Try to allocate space. */
       toc = (struct atapi_toc *) kmalloc (sizeof (struct atapi_toc),
                                           GFP_KERNEL);
-      cdrom_toc[dev->hwif][dev->select.b.drive] = toc;
+      cdrom_info[dev->hwif][dev->select.b.drive].toc = toc;
     }
 
   if (toc == NULL)
@@ -1002,7 +1295,7 @@ int cdrom_get_toc_entry (ide_dev_t *dev, int track,
   stat = cdrom_read_toc (dev);
   if (stat) return stat;
 
-  toc = cdrom_toc[dev->hwif][dev->select.b.drive];
+  toc = cdrom_info[dev->hwif][dev->select.b.drive].toc;
 
   /* Check validity of requested track number. */
   ntracks = toc->hdr.last_track - toc->hdr.first_track + 1;
@@ -1098,7 +1391,7 @@ static int ide_cdrom_ioctl (ide_dev_t *dev, struct inode *inode,
         stat = cdrom_read_toc (dev);
         if (stat) return stat;
 
-        toc = cdrom_toc[dev->hwif][dev->select.b.drive];
+        toc = cdrom_info[dev->hwif][dev->select.b.drive].toc;
         tochdr.cdth_trk0 = toc->hdr.first_track;
         tochdr.cdth_trk1 = toc->hdr.last_track;
 
@@ -1327,18 +1620,22 @@ static void cdrom_setup (ide_dev_t *dev)
   CDROM_FLAGS (dev)->no_playaudio12 = 0;
   CDROM_FLAGS (dev)->drq_interrupt = ((dev->id->config & 0x0060) == 0x20);
 
-  cdrom_toc[dev->hwif][dev->select.b.drive] = NULL;
+  cdrom_info[dev->hwif][dev->select.b.drive].toc               = NULL;
+  cdrom_info[dev->hwif][dev->select.b.drive].sector_buffer     = NULL;
+  cdrom_info[dev->hwif][dev->select.b.drive].sector_buffered   = 0;
+  cdrom_info[dev->hwif][dev->select.b.drive].nsectors_buffered = 0;
 }
 
 
+#undef MIN
+#undef SECTOR_SIZE
+#undef SECTOR_BITS
 
 
 /*
  * TODO:
  *  Retrieve and interpret extended ATAPI error codes.
- *  Transfer multiple sectors at once.
  *  Read actual disk capacity.
- *  Support demand-paged executables (1k block sizes?).
  *  Multisession support.
  *  Direct reading of audio data.
  *  Eject-on-dismount.
index 3af7a5d6ce33510a8462932010c0e7058f947e80..8dcb840db4b70233f8d6ee92b8de43c088d1365a 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *  linux/drivers/block/ide.c  Version 3.6  January 5, 1994
+ *  linux/drivers/block/ide.c  Version 3.8  January 12, 1995
  *
- *  Copyright (C) 1994  Linus Torvalds & authors (see below)
+ *  Copyright (C) 1994, 1995  Linus Torvalds & authors (see below)
  */
 
 /*
  *                     increase DRQ_WAIT to eliminate nuisance messages
  *                     wait for DRQ_STAT instead of DATA_READY during probing
  *                       (courtesy of Gary Thomas gary@efland.UU.NET)
+ *  Version 3.8                fixed byte-swapping for confused Mitsumi cdrom drives
+ *                     update of ide-cd.c from Scott, allows blocksize=1024
+ *                     cdrom probe fixes, inspired by jprang@uni-duisburg.de
+ *
  *  To do:
  *     - special 32-bit controller-type detection & support
  *     - figure out why two WD drives on one i/f sometimes don't identify
@@ -460,7 +464,7 @@ static void do_ide_reset (ide_dev_t *dev)
        printk("%s: do_ide_reset: ", ide_name[DEV_HWIF]);
        /* ATAPI devices usually do *not* assert READY after a reset */
        if (!OK_STAT(tmp=GET_STAT(DEV_HWIF), 0, BUSY_STAT)) {
-               printk("timed out, status=0x%02x\n", tmp);
+               printk("timed-out, status=0x%02x\n", tmp);
        } else  {
                if ((tmp = GET_ERR(DEV_HWIF)) == 1)
                        printk("success\n");
@@ -1596,19 +1600,23 @@ static void do_identify (ide_dev_t *dev)
        sti();
 
        /*
-        * Everything except ATAPI seems to use big-endian string ordering,
-        * whereas the NEC and Vertos ATAPI drives both use little-endian.
-        * Latest reports indicate that some Mitsumi ATAPI use big-endian.
+        * Non-ATAPI drives seem to always use big-endian string ordering.
+        * Most ATAPI cdrom drives, such as the NEC, Vertos, and some Mitsumi
+        * models, use little-endian.  But otherMitsumi models appear to use
+        * big-endian, confusing the issue.  We try to take all of this into 
+        * consideration, "knowing" that Mitsumi drive names begin with "FX".
         */
-       bswap = (id->config & 0x8000) ? 0 : 1;
-       if (bswap && id->model[0] == 'F' && id->model[1] == 'X')
-               bswap = 0; 
-       fixstring (id->serial_no, sizeof(id->serial_no), bswap);
-       fixstring (id->fw_rev,    sizeof(id->fw_rev),    bswap);
+       bswap = 1;
+       if (id->model[0] != 'X' || id->model[1] != 'F') {
+               if ((id->model[0] == 'F' && id->model[1] == 'X') || (id->config & 0x8000))
+                       bswap = 0;
+       }
        fixstring (id->model,     sizeof(id->model),     bswap);
+       fixstring (id->fw_rev,    sizeof(id->fw_rev),    bswap);
+       fixstring (id->serial_no, sizeof(id->serial_no), bswap);
 
        /*
-        * Check for ATAPI device (such as an NEC-260 IDE cdrom drive)
+        * Check for an ATAPI device
         */
        if (id->config & 0x8000) {
 #ifdef CONFIG_BLK_DEV_IDECD
@@ -1715,9 +1723,14 @@ static void delay_10ms (void)
 
 
 static int try_to_identify (ide_dev_t *dev, byte cmd)
+/*
+ * Returns:    0  device was identified
+ *             1  device timed-out (no response to identify request)
+ *             2  device aborted the command (refused to identify itself)
+ */
 {
        int rc;
-       unsigned long timer, timeout;
+       unsigned long timeout;
 #if PROBE_FOR_IRQS
        int irqs = 0;
        static byte irq_probed[2] = {0,0};
@@ -1733,58 +1746,61 @@ static int try_to_identify (ide_dev_t *dev, byte cmd)
        delay_10ms();                           /* take a deep breath */
        OUT_BYTE(cmd,HD_COMMAND);               /* ask drive for ID */
        delay_10ms();                           /* wait for BUSY_STAT */
-       timeout = (cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY;
-       for (timer = jiffies + (timeout / 2); timer > jiffies;) {
-               if ((IN_BYTE(HD_ALTSTATUS,DEV_HWIF) & BUSY_STAT) == 0) {
-                       delay_10ms();           /* wait for IRQ & DATA_READY */
-                       if (OK_STAT(GET_STAT(DEV_HWIF),DRQ_STAT,BAD_RW_STAT)){
-                               cli();                  /* some sys need this */
-                               do_identify(dev);       /* drive returned ID */
-                               rc = 0;
-                       } else
-                               rc = 1;                 /* drive refused ID */
+       timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
+       for (timeout += jiffies; IN_BYTE(HD_ALTSTATUS,DEV_HWIF) & BUSY_STAT;) {
+               if (timeout < jiffies) {
 #if PROBE_FOR_IRQS
-                       if (!irq_probed[DEV_HWIF]) {
-                               irqs = probe_irq_off(irqs);  /* end probe */
-                               if (irqs > 0) {
-                                       irq_probed[DEV_HWIF] = 1;
-                                       ide_irq[DEV_HWIF] = irqs;
-                               } else
-                                       printk("%s: IRQ probe failed (%d)\n", dev->name, irqs);
-                       }
+                       if (!irq_probed[DEV_HWIF])
+                               (void) probe_irq_off(irqs);
 #endif /* PROBE_FOR_IRQS */
-                       goto done_try;
+                       return 1;       /* drive timed-out */
                }
        }
-       rc = 2;                                 /* it ain't responding */
+       delay_10ms();           /* wait for IRQ and DRQ_STAT */
+       if (OK_STAT(GET_STAT(DEV_HWIF),DRQ_STAT,BAD_RW_STAT)) {
+               cli();                  /* some systems need this */
+               do_identify(dev);       /* drive returned ID */
+               rc = 0;                 /* success */
+       } else
+               rc = 2;                 /* drive refused ID */
 #if PROBE_FOR_IRQS
-       if (!irq_probed[DEV_HWIF])
-               (void) probe_irq_off(irqs);     /* end probing */
+       if (!irq_probed[DEV_HWIF]) {
+               irqs = probe_irq_off(irqs);     /* get irq number */
+               if (irqs > 0) {
+                       irq_probed[DEV_HWIF] = 1;
+                       ide_irq[DEV_HWIF] = irqs;
+               } else                          /* Mmmm.. multiple IRQs */
+                       printk("%s: IRQ probe failed (%d)\n", dev->name, irqs);
+       }
 #endif /* PROBE_FOR_IRQS */
-done_try:
-       OUT_BYTE(dev->ctl|2,HD_CMD);            /* disable device irq */
        return rc;
 }
 
 /*
  * This routine has the difficult job of finding a drive if it exists,
- * without getting hung up if it doesn't exist, and without leaving any IRQs
- * dangling to haunt us later.  The last point actually occurred in v2.3, and
- * is the reason for the slightly complex exit sequence.  If a drive is "known"
- * to exist (from CMOS or kernel parameters), but does not respond right away,
- * the probe will "hang in there" for the maximum wait time (about 30 seconds).
- * Otherwise, it will exit much more quickly.
+ * without getting hung up if it doesn't exist, without trampling on
+ * ethernet cards, and without leaving any IRQs dangling to haunt us later.
  *
- * Returns 1 if device present but not identified.  Returns 0 otherwise.
+ * If a drive is "known" to exist (from CMOS or kernel parameters),
+ * but does not respond right away, the probe will "hang in there"
+ * for the maximum wait time (about 30 seconds), otherwise it will
+ * exit much more quickly.
  */
 static int do_probe (ide_dev_t *dev, byte cmd)
+/*
+ * Returns:    0  device was identified
+ *             1  device timed-out (no response to identify request)
+ *             2  device aborted the command (refused to identify itself)
+ *             3  bad status from device (possible for ATAPI drives)
+ *             4  probe was not attempted
+ */
 {
        int rc;
 
 #ifdef CONFIG_BLK_DEV_IDECD
        if (dev->present) {     /* avoid waiting for inappropriate probes */
                if ((dev->type == disk) ^ (cmd == WIN_IDENTIFY))
-                       return 1;
+                       return 4;
        }
 #endif /* CONFIG_BLK_DEV_IDECD */
 #if DEBUG
@@ -1794,21 +1810,23 @@ static int do_probe (ide_dev_t *dev, byte cmd)
 #endif
        OUT_BYTE(dev->select.all,HD_CURRENT);   /* select target drive */
        delay_10ms();                           /* wait for BUSY_STAT */
-       if (IN_BYTE(HD_CURRENT,DEV_HWIF) != dev->select.all && !dev->present)
-               return 0;     /* no i/f present: avoid killing ethernet cards */
+       if (IN_BYTE(HD_CURRENT,DEV_HWIF) != dev->select.all && !dev->present) {
+               OUT_BYTE(0xa0,HD_CURRENT);      /* exit with drive0 selected */
+               return 3;    /* no i/f present: avoid killing ethernet cards */
+       }
 
        if (OK_STAT(GET_STAT(DEV_HWIF),READY_STAT,BUSY_STAT)
         || dev->present || cmd == WIN_PIDENTIFY)
        {
-               if ((rc = try_to_identify(dev, cmd)))   /* send cmd and wait */
-                       rc = try_to_identify(dev, cmd);         /* try again */
-               if (rc)
-                       printk("%s: identification %s\n", dev->name,
-                               (rc == 1) ? "refused" : "timed-out");
+               if ((rc = try_to_identify(dev, cmd)))  /* send cmd and wait */
+                       rc = try_to_identify(dev, cmd); /* failed: try again */
+               if (rc == 1)
+                       printk("%s: no response\n", dev->name);
+               OUT_BYTE(dev->ctl|2,HD_CMD);    /* disable device irq */
                delay_10ms();
                (void) GET_STAT(DEV_HWIF);      /* ensure drive irq is clear */
        } else {
-               rc = 2;                         /* drive not present */
+               rc = 3;                         /* not present or maybe ATAPI */
        }
        if (dev->select.b.drive == 1) {
                OUT_BYTE(0xa0,HD_CURRENT);      /* exit with drive0 selected */
@@ -1821,16 +1839,20 @@ static int do_probe (ide_dev_t *dev, byte cmd)
 }
 
 static byte probe_for_drive (ide_dev_t *dev)
+/*
+ * Returns:    0  no device was found
+ *             1  device was found (note: dev->present might still be 0)
+ */
 {
        if (dev->dont_probe)                    /* skip probing? */
                return dev->present;
-       if (do_probe(dev, WIN_IDENTIFY) == 1) { /* 1 = drive aborted the cmd */
+       if (do_probe(dev, WIN_IDENTIFY) >= 2) { /* if !(success || timed-out) */
 #ifdef CONFIG_BLK_DEV_IDECD
-               (void) do_probe(dev, WIN_PIDENTIFY);
+               (void) do_probe(dev, WIN_PIDENTIFY); /* look for ATAPI device */
 #endif /* CONFIG_BLK_DEV_IDECD */
        }
        if (!dev->present)
-               return 0;                       /* drive not present */
+               return 0;                       /* drive not found */
        if (dev->id == NULL) {                  /* identification failed? */
                if (dev->type == disk) {
                        printk ("%s: non-IDE device, CHS=%d/%d/%d\n",
@@ -1843,7 +1865,7 @@ static byte probe_for_drive (ide_dev_t *dev)
 #endif /* CONFIG_BLK_DEV_IDECD */
                else {
                        dev->present = 0;       /* nuke it */
-                       return 0;               /* drive not present */
+                       return 1;               /* drive was found */
                }
        }
 #ifdef CONFIG_BLK_DEV_IDECD
@@ -1857,7 +1879,7 @@ static byte probe_for_drive (ide_dev_t *dev)
                        dev->present = 0;
                }
        }
-       return 1;       /* drive present */
+       return 1;       /* drive was found */
 }
 
 static void probe_for_drives (byte hwif)
@@ -1877,15 +1899,15 @@ static void probe_for_drives (byte hwif)
                save_flags(flags);
                sti();  /* needed for jiffies and irq probing */
 
-               /* second drive can only exist if first drive was present */
+               /* second drive should only exist if first drive was found */
                if (probe_for_drive(&devs[0]) || devs[1].present)
                        (void) probe_for_drive(&devs[1]);
 #if PROBE_FOR_IRQS
                (void) probe_irq_off(probe_irq_on()); /* clear dangling irqs */
 #endif /* PROBE_FOR_IRQS */
                if (devs[0].present || devs[1].present) {
-                       request_region(IDE_PORT(HD_DATA,HWIF),8,"ide");
-                       request_region(IDE_PORT(HD_CMD,HWIF),1,"ide");
+                       request_region(IDE_PORT(HD_DATA,HWIF),8,ide_name[HWIF]);
+                       request_region(IDE_PORT(HD_CMD,HWIF),1,ide_name[HWIF]);
                }
                restore_flags(flags);
        }
index 91791bf92f385ff15fd47361f405b3a37f7cfa25..1fec0fa8ecbff1fd8873d9c4bc15fdf9806a0e70 100644 (file)
@@ -9,7 +9,7 @@
  *            Not for the TEAC CD-55A drive (yet).
  *            Not for the CreativeLabs CD200 drive (yet).
  *
- *  NOTE:     This is release 3.0.
+ *  NOTE:     This is release 3.1.
  *            It works with my SbPro & drive CR-521 V2.11 from 2/92
  *            and with the new CR-562-B V0.75 on a "naked" Panasonic
  *            CI-101P interface. And vice versa. 
  *       Started CD200 support. Drive detection should work, but nothing
  *       more.
  *
+ *  3.1  Working to support the CD200 and the Teac CD-55A drives.
+ *       AT-BUS style device numbering no longer used: use SCSI style now.
+ *       So, the first "found" device has MINOR 0, regardless of the
+ *       jumpered drive ID. This implies modifications to the /dev/sbpcd*
+ *       entries for some people, but will help the DAU (german TLA, english:
+ *       "newbie", maybe ;-) to install his "first" system from a CD.
+ *     
  *  TODO
  *
  *     disk change detection
  *
  */
 
-#define SBPCD_ISSUE 1 /* change to 2, 3, 4 for multiple interface boards */
+#ifndef SBPCD_ISSUE
+#define SBPCD_ISSUE 1
+#endif SBPCD_ISSUE
 
 #include <linux/config.h>
 #include <linux/errno.h>
 
 #include "blk.h"
 
-#define VERSION "3.0 Eberhard Moenkeberg <emoenke@gwdg.de>"
+#define VERSION "3.1 Eberhard Moenkeberg <emoenke@gwdg.de>"
 
 /*
  * still testing around...
  */
-#define MULTISESSION_BY_DRIVER 1 /* if set to 0 here, we need a counterpart in
-                                  * linux/fs/isofs/inode.c
+#define MULTISESSION_BY_DRIVER 0 /* if set to 0 here, we need the counterpart
+                                  * in linux/fs/isofs/inode.c
                                   */
 #define READ_AUDIO 4 /* max. number of audio frames to read with one */
                      /* request (allocates n* 2352 bytes kernel memory!) */
 #define PRINTK_BUG 0
 #define TEST_STI 0
 
+#define DISTRIBUTION 1
+
 #if 0
 #define INLINE
 #else
  * send mail to emoenke@gwdg.de if your interface card is not FULLY
  * represented here.
  */
-static int autoprobe[] = 
+#if !(SBPCD_ISSUE-1)
+static int sbpcd_probe[] = 
 {
   CDROM_PORT, SBPRO, /* probe with user's setup first */
   0x230, 1, /* Soundblaster Pro and 16 (default) */
@@ -348,23 +360,29 @@ static int autoprobe[] =
   0x330, 2, /* SPEA Media FX (default) */
   0x320, 2, /* SPEA Media FX */
   0x340, 2, /* SPEA Media FX */
-  0x350, 2, /* SPEA Media FX */
+  0x634, 0, /* some newer sound cards */
+  0x638, 0, /* some newer sound cards */
 /* due to incomplete address decoding of the SbPro card, these must be last */
   0x630, 0, /* "sound card #9" (default) */
   0x650, 0, /* "sound card #9" */
-#if 0
-/* some "hazardous" locations
+/*
+ * some "hazardous" locations
  * (will stop the bus if a NE2000 ethernet card resides at offset -0x10)
  */
+#if 0
   0x330, 0, /* Lasermate, CI-101P, WDH-7001C */
   0x350, 0, /* Lasermate, CI-101P */
+  0x350, 2, /* SPEA Media FX */
   0x370, 0, /* Lasermate, CI-101P */
   0x290, 1, /* Soundblaster 16 */
   0x310, 0, /* Lasermate, CI-101P, WDH-7001C */
 #endif
 };
+#else
+static int sbpcd_probe[] = {CDROM_PORT, SBPRO}; /* probe with user's setup only */
+#endif
 
-#define NUM_AUTOPROBE  (sizeof(autoprobe) / sizeof(int))
+#define NUM_PROBE  (sizeof(sbpcd_probe) / sizeof(int))
 
 
 /*==========================================================================*/
@@ -392,7 +410,7 @@ static void sbp_read_cmd(void);
 static int sbp_data(void);
 static int cmd_out(void);
 static int DiskInfo(void);
-static int check_media_change(dev_t);
+static int sbpcd_chk_disk_change(dev_t);
 
 /*==========================================================================*/
 
@@ -430,7 +448,7 @@ static int check_media_change(dev_t);
  * (1<<DBG_CD2)  MKE CD200 debugging trace
  * (1<<DBG_000)  unnecessary information
  */
-#if 1
+#if DISTRIBUTION
 static int sbpcd_debug =  (1<<DBG_INF) |
                           (1<<DBG_WRN) |
                           (1<<DBG_MUL);
@@ -444,9 +462,9 @@ static int sbpcd_debug =  (1<<DBG_INF) |
                           (1<<DBG_ID)  |
                           (1<<DBG_UPC);
 #endif
-static unsigned char setup_done = 0;
 static int sbpcd_ioaddr = CDROM_PORT;  /* default I/O base address */
 static int sbpro_type = SBPRO;
+static unsigned char setup_done = 0;
 static int CDo_command, CDo_reset;
 static int CDo_sel_i_d, CDo_enable;
 static int CDi_info, CDi_status, CDi_data;
@@ -515,7 +533,11 @@ static u_int maxtim_data= 9000;
 #else
 static u_int maxtim_data= 3000;
 #endif LONG_TIMING
-
+#if DISTRIBUTION
+static int n_retries=3;
+#else
+static int n_retries=1;
+#endif
 /*==========================================================================*/
 
 static int ndrives=0;
@@ -529,7 +551,8 @@ static int sbpcd_blocksizes[NR_SBPCD] = {0, };
 static int d=0; /* DriveStruct index: drive number */
 
 static struct {
-  char drv_minor; /* minor number or -1 */
+  char drv_id; /* "jumpered" drive ID or -1 */
+  char drv_sel; /* drive select lines bits */
 
   char drive_model[9];
   char firmware_version[4];
@@ -665,9 +688,11 @@ static int sbpcd_dbg_ioctl(unsigned long arg, int level)
  */
 static INLINE void sbp_sleep(u_int jifs)
 {
-   current->state = TASK_INTERRUPTIBLE;
-   current->timeout = jiffies + jifs;
-   schedule();
+  sti();
+  current->state = TASK_INTERRUPTIBLE;
+  current->timeout = jiffies + jifs;
+  schedule();
+  sti();
 }
 
 /*==========================================================================*/
@@ -2266,6 +2291,18 @@ static int yy_ReadError(int fam)
 
 #endif CD200
 /*==========================================================================*/
+static void ask_mail(void)
+{
+  int i;
+
+  printk("SBPCD: please mail the following lines to emoenke@gwdg.de:\n");
+  printk("SBPCD: infobuf = \"");
+  for (i=0;i<12;i++) printk("%02X ",infobuf[i]);
+  printk("\"\nSBPCD: infobuf = \"");
+  for (i=0;i<12;i++) printk("%c",infobuf[i]);
+  printk("\"\n");
+}
+/*==========================================================================*/
 static int check_version(void)
 {
   int i, j;
@@ -2287,7 +2324,7 @@ static int check_version(void)
 #if 0
   OUT(CDo_reset,0);
   sbp_sleep(600);
-  OUT(CDo_enable,d);
+  OUT(CDo_enable,DriveStruct[d].drv_sel);
 #endif
   drvcmd[0]=CMD2_READ_VER;
   response_count=12;
@@ -2304,47 +2341,42 @@ static int check_version(void)
          for (i=0;i<12;i++) DPRINTF((DBG_ID,"%c",infobuf[i]));
          DPRINTF((DBG_ID,"\"\n"));
        }
-    }
-
-  for (i=0;i<5;i++) if (infobuf[i]!=family2[i]) break;
-  if (i==5)
-    {
-      DriveStruct[d].drive_model[0]='C';
-      DriveStruct[d].drive_model[1]='D';
-      DriveStruct[d].drive_model[2]='2';
-      DriveStruct[d].drive_model[3]='0';
-      DriveStruct[d].drive_model[4]='0';
-      DriveStruct[d].drive_model[5]=infobuf[i++];
-      DriveStruct[d].drive_model[6]=infobuf[i++];
-      DriveStruct[d].drive_model[7]=0;
-      DriveStruct[d].drv_type=drv_fam2;
-    }
-  else
-    {
-      for (i=0;i<5;i++) if (infobuf[i]!=familyT[i]) break;
-      if (i==5)
+      else
        {
-         DriveStruct[d].drive_model[0]='C';
-         DriveStruct[d].drive_model[1]='D';
-         DriveStruct[d].drive_model[2]='-';
-         DriveStruct[d].drive_model[3]='5';
-         DriveStruct[d].drive_model[4]='5';
-         DriveStruct[d].drive_model[5]='A';
-         DriveStruct[d].drive_model[6]=infobuf[i++];
-         DriveStruct[d].drive_model[7]=infobuf[i++];
-         DriveStruct[d].drive_model[8]=0;
-         DriveStruct[d].drv_type=drv_famT;
+         for (i=0;i<5;i++) if (infobuf[i]!=family2[i]) break;
+         if (i==5)
+           {
+             DriveStruct[d].drive_model[0]='C';
+             DriveStruct[d].drive_model[1]='D';
+             DriveStruct[d].drive_model[2]='2';
+             DriveStruct[d].drive_model[3]='0';
+             DriveStruct[d].drive_model[4]='0';
+             DriveStruct[d].drive_model[5]=infobuf[i++];
+             DriveStruct[d].drive_model[6]=infobuf[i++];
+             DriveStruct[d].drive_model[7]=0;
+             DriveStruct[d].drv_type=drv_fam2;
+           }
+         else
+           {
+             printk("\n\nSBPCD: possibly CD-55A present.\n");
+             for (i=0;i<5;i++) if (infobuf[i]!=familyT[i]) break;
+             if (i==5)
+               {
+                 DriveStruct[d].drive_model[0]='C';
+                 DriveStruct[d].drive_model[1]='D';
+                 DriveStruct[d].drive_model[2]='-';
+                 DriveStruct[d].drive_model[3]='5';
+                 DriveStruct[d].drive_model[4]='5';
+                 DriveStruct[d].drive_model[5]='A';
+                 DriveStruct[d].drive_model[6]=infobuf[i++];
+                 DriveStruct[d].drive_model[7]=infobuf[i++];
+                 DriveStruct[d].drive_model[8]=0;
+               }
+             DriveStruct[d].drv_type=drv_famT;
+           }
        }
     }
-#if 1
-  if (DriveStruct[d].drv_type)
-    {
-      printk("\n\nSBPCD: new drive CD200 or CD-55A successfully detected.\n");
-      printk("SBPCD: support is not fulfilled yet - drive gets ignored.\n");
-      printk("SBPCD: just wait some days - don't mail, please.\n\n");
-      DriveStruct[d].drv_type=0;
-    }
-#endif
+
   if (!DriveStruct[d].drv_type)
     {
       /* check for CR-52x, CR-56x and LCS-7260 */
@@ -2425,7 +2457,15 @@ static int check_version(void)
          (DriveStruct[d].firmware_version[1]!='4') ||
          (DriveStruct[d].firmware_version[2]!='F') ||
          (DriveStruct[d].firmware_version[3]!='4'))
-       printk("SBPCD: please mail me your LCS-7260 DOS driver.\n");
+       ask_mail();
+    }
+  else if (famT_drive)
+    {
+      printk("\n\nSBPCD: possibly TEAC CD-55A present.\n");
+      printk("SBPCD: support is not fulfilled yet - drive gets ignored.\n");
+      ask_mail();
+      DriveStruct[d].drv_type=0;
+      return (-1);
     }
   else
     {
@@ -2446,8 +2486,16 @@ static int check_version(void)
          if (j<100) DriveStruct[d].drv_type=drv_099;
          else DriveStruct[d].drv_type=drv_100;
        }
-      else /* CD200, CD-55A */
+      else if (fam2_drive)
        {
+         printk("\n\nSBPCD: new drive CD200 (%s)detected.\n", DriveStruct[d].firmware_version);
+         printk("SBPCD: support is not fulfilled yet - drive gets ignored.\n");
+         if (j!=101) /* only 1.01 known at time */
+           ask_mail();
+         else
+           printk("SBPCD: just wait some days...\n\n");
+         DriveStruct[d].drv_type=0;
+         return (-1);
        }
     }
   DPRINTF((DBG_LCS,"SBPCD: drive type %02X\n",DriveStruct[d].drv_type));
@@ -2455,17 +2503,16 @@ static int check_version(void)
   return (0);
 }
 /*==========================================================================*/
-static int switch_drive(int num)
+static int switch_drive(int i)
 {
-  int i;
-
-  d=num;
-
-  i=num;
-  if (sbpro_type==1) i=(i&0x01)<<1|(i&0x02)>>1;
-  OUT(CDo_enable,i);
-  DPRINTF((DBG_DID,"SBPCD: switch_drive: drive %d activated.\n",DriveStruct[d].drv_minor));
-  return (0);
+  d=i;
+  if (DriveStruct[d].drv_id!=-1)
+    {
+      OUT(CDo_enable,DriveStruct[d].drv_sel);
+      DPRINTF((DBG_DID,"SBPCD: drive %d (ID=%d) activated.\n", i, DriveStruct[d].drv_id));
+      return (0);
+    }
+  else return (-1);
 }
 /*==========================================================================*/
 /*
@@ -2481,26 +2528,27 @@ static int check_drives(void)
   ndrives=0;
   for (j=0;j<NR_SBPCD;j++)
     {
-      DriveStruct[j].drv_minor=j;
-      switch_drive(j);
-      DPRINTF((DBG_ID,"SBPCD: check_drives: drive %d activated.\n",j));
+      DriveStruct[ndrives].drv_id=j;
+      if (sbpro_type==1) DriveStruct[ndrives].drv_sel=(j&0x01)<<1|(j&0x02)>>1;
+      else DriveStruct[ndrives].drv_sel=j;
+      switch_drive(ndrives);
+      DPRINTF((DBG_INI,"SBPCD: check_drives: drive %d (ID=%d) activated.\n",ndrives,j));
       i=check_version();
-      DPRINTF((DBG_ID,"SBPCD: check_version returns %d.\n",i));
-      if (i>=0)
+      if (i<0) DPRINTF((DBG_INI,"SBPCD: check_version returns %d.\n",i));
+      else
        {
-         ndrives++;
          DriveStruct[d].drv_options=drv_pattern[j];
-         if (fam0L_drive)
-           DriveStruct[d].drv_options&=~(speed_auto|speed_300|speed_150);
-
-         printk("%sDrive %d: %.9s (%.4s)\n", printk_header,
-                DriveStruct[d].drv_minor,
+         if (fam0L_drive) DriveStruct[d].drv_options&=~(speed_auto|speed_300|speed_150);
+         printk("%sDrive %d (ID=%d): %.9s (%.4s)\n", printk_header, d,
+                DriveStruct[d].drv_id,
                 DriveStruct[d].drive_model,
                 DriveStruct[d].firmware_version);
          printk_header="       - ";
+         ndrives++;
        }
-      else DriveStruct[d].drv_minor=-1;
+
     }
+  for (j=ndrives;j<NR_SBPCD;j++) DriveStruct[j].drv_id=-1;
   if (ndrives==0) return (-1);
   return (0);
 }
@@ -2933,16 +2981,15 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
                       u_long arg)
 {
   int i, st;
-  unsigned int *p_lba;
 
   DPRINTF((DBG_IO2,"SBPCD: ioctl(%d, 0x%08lX, 0x%08lX)\n",
                                MINOR(inode->i_rdev), cmd, arg));
   if (!inode) return (-EINVAL);
   i=MINOR(inode->i_rdev);
-  if ( (i<0) || (i>=NR_SBPCD) )
+  if ((i<0) || (i>=NR_SBPCD) || (DriveStruct[i].drv_id==-1))
     {
-      printk("SBPCD: ioctl: bad device: %d\n", i);
-      return (-ENODEV);             /* no such drive */
+      printk("SBPCD: ioctl: bad device: %04X\n", inode->i_rdev);
+      return (-ENXIO);             /* no such drive */
     }
   switch_drive(i);
 
@@ -3339,6 +3386,8 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
                DPRINTF((DBG_AUD,"SBPCD: read_audio: read aborted by drive\n"));
 #if 0000
                i=DriveReset();                /* ugly fix to prevent a hang */
+#else
+               i=xx_ReadError();
 #endif 0000
                continue;
              }
@@ -3424,13 +3473,12 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
     case CDROMMULTISESSION_SYS: /* tell start-of-last-session to kernel */
       DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMMULTISESSION_SYS entered.\n"));
       if(!suser()) return -EACCES;
-      p_lba=(unsigned int *) arg;
       if (DriveStruct[d].f_multisession)
-       *p_lba=DriveStruct[d].lba_multi;
+       *((unsigned int *) arg)=DriveStruct[d].lba_multi;
       else
-       *p_lba=0;
+       *((unsigned int *) arg)=0;
       DPRINTF((DBG_MUL,"SBPCD: ioctl: CDROMMULTISESSION_SYS done (%d).\n",
-              p_lba[0]));
+              ((unsigned int *) arg)[0]));
       return (0);
 
     case BLKRASET:
@@ -3471,7 +3519,6 @@ static void sbp_transfer(void)
 static void DO_SBPCD_REQUEST(void)
 {
   u_int block;
-  int dev;
   u_int nsect;
   int i, status_tries, data_tries;
   
@@ -3482,13 +3529,13 @@ request_loop:
   if ((CURRENT==NULL)||(CURRENT->dev<0)) goto done;
   if (CURRENT -> sector == -1) goto done;
 
-  dev = MINOR(CURRENT->dev);
-  if ( (dev<0) || (dev>=NR_SBPCD) )
+  i = MINOR(CURRENT->dev);
+  if ( (i<0) || (i>=NR_SBPCD) || (DriveStruct[i].drv_id==-1))
     {
-      printk("SBPCD: do_request: bad device: %d\n", dev);
+      printk("SBPCD: do_request: bad device: %04X\n", CURRENT->dev);
       goto done;
     }
-  switch_drive(dev);
+  switch_drive(i);
 
   INIT_REQUEST;
   block = CURRENT->sector; /* always numbered as 512-byte-pieces */
@@ -3530,13 +3577,14 @@ request_loop:
       }
 #endif XA_TEST1
 
-  for (data_tries=3; data_tries > 0; data_tries--)
+  for (data_tries=n_retries; data_tries > 0; data_tries--)
     {
       for (status_tries=3; status_tries > 0; status_tries--)
        {
          flags_cmd_out |= f_respo3;
          xx_ReadStatus();
          if (sbp_status() != 0) break;
+         if (st_check) xx_ReadError();
          sbp_sleep(1);    /* wait a bit, try again */
        }
       if (status_tries == 0)
@@ -3761,7 +3809,11 @@ static int sbp_data(void)
   if (error_flag)    /* must have been spurious D_RDY or (ATTN&&!D_RDY) */
     {
       DPRINTF((DBG_INF,"SBPCD: read aborted by drive\n"));
+#if 0
       i=DriveReset();                /* ugly fix to prevent a hang */
+#else
+      i=xx_ReadError();
+#endif
       return (0);
     }
 
@@ -3824,17 +3876,15 @@ static int sbpcd_open(struct inode *ip, struct file *fp)
 {
   int i;
 
-  if (ndrives==0) return (-ENXIO);             /* no hardware */
-
-  if (fp->f_mode & 2)
-         return -EROFS;
-
   i = MINOR(ip->i_rdev);
-  if ( (i<0) || (i>=NR_SBPCD) )
+  if ((i<0) || (i>=NR_SBPCD) || (DriveStruct[i].drv_id==-1))
     {
-      printk("SBPCD: open: bad device: %d\n", i);
-      return (-ENODEV);             /* no such drive */
+      printk("SBPCD: open: bad device: %04X\n", ip->i_rdev);
+      return (-ENXIO);             /* no such drive */
     }
+  if (fp->f_mode & 2)
+         return -EROFS;
+  
   switch_drive(i);
 
   flags_cmd_out |= f_respo2;
@@ -3898,9 +3948,9 @@ static void sbpcd_release(struct inode * ip, struct file * file)
   int i;
 
   i = MINOR(ip->i_rdev);
-  if ( (i<0) || (i>=NR_SBPCD) ) 
+  if ((i<0) || (i>=NR_SBPCD) || (DriveStruct[i].drv_id==-1))
     {
-      printk("SBPCD: release: bad device: %d\n", i);
+      printk("SBPCD: release: bad device: %04X\n", ip->i_rdev);
       return;
     }
   switch_drive(i);
@@ -3908,7 +3958,6 @@ static void sbpcd_release(struct inode * ip, struct file * file)
   DriveStruct[d].sbp_first_frame=DriveStruct[d].sbp_last_frame=-1;
   sync_dev(ip->i_rdev);                   /* nonsense if read only device? */
   invalidate_buffers(ip->i_rdev);
-  DriveStruct[d].diskstate_flags &= ~cd_size_bit;
 
 /*
  * try to keep an "open" counter here and unlock the door if 1->0.
@@ -3923,6 +3972,7 @@ static void sbpcd_release(struct inode * ip, struct file * file)
            i=yy_LockDoor(0);
          while (i!=0);
          if (DriveStruct[d].f_eject) yy_SpinDown();
+         DriveStruct[d].diskstate_flags &= ~cd_size_bit;
        }
     }
 }
@@ -3943,7 +3993,7 @@ static struct file_operations sbpcd_fops =
   sbpcd_release,          /* release */
   NULL,                   /* fsync */
   NULL,                   /* fasync */
-  check_media_change,     /* media_change */
+  sbpcd_chk_disk_change,     /* media_change */
   NULL                    /* revalidate */
 };
 /*==========================================================================*/
@@ -4080,24 +4130,24 @@ unsigned long SBPCD_INIT(u_long mem_start, u_long mem_end)
       DPRINTF((DBG_WRN,"SBPCD: = = = = = = = = = = END of WARNING = = = = = = = = = =\n"));
       DPRINTF((DBG_WRN,"SBPCD: \n"));
     }
-  autoprobe[0]=sbpcd_ioaddr; /* possibly changed by kernel command line */
-  autoprobe[1]=sbpro_type; /* possibly changed by kernel command line */
+  sbpcd_probe[0]=sbpcd_ioaddr; /* possibly changed by kernel command line */
+  sbpcd_probe[1]=sbpro_type; /* possibly changed by kernel command line */
 
-  for (port_index=0;port_index<NUM_AUTOPROBE;port_index+=2)
+  for (port_index=0;port_index<NUM_PROBE;port_index+=2)
     {
-      addr[1]=autoprobe[port_index];
+      addr[1]=sbpcd_probe[port_index];
       if (check_region(addr[1],4))
        {
          DPRINTF((DBG_INI,"SBPCD: check_region: %03X is not free.\n",addr[1]));
          continue;
        }
-      if (autoprobe[port_index+1]==0) type=str_lm;
-      else if (autoprobe[port_index+1]==1) type=str_sb;
+      if (sbpcd_probe[port_index+1]==0) type=str_lm;
+      else if (sbpcd_probe[port_index+1]==1) type=str_sb;
       else type=str_sp;
       sbpcd_setup(type, addr);
       DPRINTF((DBG_INF,"SBPCD: Trying to detect a %s CD-ROM drive at 0x%X.\n", type, CDo_command));
       DPRINTF((DBG_INF,"SBPCD: - "));
-      if (autoprobe[port_index+1]==2)
+      if (sbpcd_probe[port_index+1]==2)
        {
          i=config_spea();
          if (i<0)
@@ -4153,7 +4203,7 @@ unsigned long SBPCD_INIT(u_long mem_start, u_long mem_end)
 
   for (j=0;j<NR_SBPCD;j++)
     {
-      if (DriveStruct[j].drv_minor==-1) continue;
+      if (DriveStruct[j].drv_id==-1) continue;
       switch_drive(j);
       if (!famL_drive) xy_DriveReset();
       if (!st_spinning) xx_SpinUp();
@@ -4228,17 +4278,18 @@ unsigned long SBPCD_INIT(u_long mem_start, u_long mem_end)
   blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
   read_ahead[MAJOR_NR] = SBP_BUFFER_FRAMES * (CD_FRAMESIZE / 512);
   
-  request_region(CDo_command,4,"sbpcd");
+  request_region(CDo_command,4,major_name);
 
   for (j=0;j<NR_SBPCD;j++)
     {
-      if (DriveStruct[j].drv_minor==-1) continue;
+      if (DriveStruct[j].drv_id==-1) continue;
+      switch_drive(j);
 /*
  * allocate memory for the frame buffers
  */ 
       DriveStruct[j].sbp_buf=(u_char *)mem_start;
       mem_start += SBP_BUFFER_FRAMES*CD_FRAMESIZE;
-      if (fam1_drive)
+      if ((fam1_drive) && (SBP_BUFFER_AUDIO_FRAMES>0))
        {
          DriveStruct[j].aud_buf=(u_char *)mem_start;
          mem_start += SBP_BUFFER_AUDIO_FRAMES*CD_FRAMESIZE_RAW;
@@ -4274,20 +4325,21 @@ init_done:
  * used externally (isofs/inode.c, fs/buffer.c)
  * Currently disabled (has to get "synchronized").
  */
-static int check_media_change(dev_t full_dev)
+static int sbpcd_chk_disk_change(dev_t full_dev)
 {
-  int st;
+  int i, st;
 
   DPRINTF((DBG_CHK,"SBPCD: media_check (%d) called\n", MINOR(full_dev)));
   return (0); /* "busy" test necessary before we really can check */
 
-  if ((MAJOR(full_dev)!=MAJOR_NR)||(MINOR(full_dev)>=NR_SBPCD))
+  i=MINOR(full_dev);
+  if ( (i<0) || (i>=NR_SBPCD) || (DriveStruct[i].drv_id==-1) )
     {
       printk("SBPCD: media_check: invalid device %04X.\n", full_dev);
       return (-1);
     }
 
-  switch_drive(MINOR(full_dev));
+  switch_drive(i);
   
   xx_ReadStatus();                         /* command: give 1-byte status */
   st=ResponseStatus();
diff --git a/drivers/block/sbpcd2.c b/drivers/block/sbpcd2.c
new file mode 100644 (file)
index 0000000..82e2c68
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * duplication of sbpcd.c for multiple interfaces
+ */
+#define SBPCD_ISSUE 2
+#include "sbpcd.c"
diff --git a/drivers/block/sbpcd3.c b/drivers/block/sbpcd3.c
new file mode 100644 (file)
index 0000000..0e79c41
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * duplication of sbpcd.c for multiple interfaces
+ */
+#define SBPCD_ISSUE 3
+#include "sbpcd.c"
diff --git a/drivers/block/sbpcd4.c b/drivers/block/sbpcd4.c
new file mode 100644 (file)
index 0000000..f4b34cc
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * duplication of sbpcd.c for multiple interfaces
+ */
+#define SBPCD_ISSUE 4
+#include "sbpcd.c"
index 4720accd4d6d644862350d418a671ab403a25a5a..c24adac1470e3c6e35e0fc32fa27a4c54b922bc0 100644 (file)
@@ -99,11 +99,12 @@ static char *version =
 #include <linux/malloc.h>
 #include <linux/string.h>
 #include <linux/timer.h>
+#include <linux/errno.h>
+
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
-#include <errno.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
index ff64849c0c05bb128be2d108ececf3787eafff3b..33c140abbc35a48f1d41d004c69a0d4de92ee92d 100644 (file)
@@ -1,3 +1,150 @@
+Tue Jan 10 10:09:58 1995  Eric Youngdale  (eric@andante)
+
+       * Linux 1.1.79 released.
+
+       Patch from some undetermined individual who needs to get a life :-).
+
+       * sr.c: Attacked by spelling bee...
+
+       Patches from Gerd Knorr:
+
+       * sr.c: make printk messages for photoCD a little more informative.
+
+       * sr_ioctl.c: Fix CDROMMULTISESSION_SYS ioctl.
+
+Mon Jan  9 10:01:37 1995  Eric Youngdale  (eric@andante)
+
+       * Linux 1.1.78 released.
+
+       * Makefile: Add empty modules: target.
+
+       * Wheee.  Now change register_iomem to request_region.
+
+       * in2000.c: Bugfix - apparently this is the fix that we have
+       all been waiting for.  It fixes a problem whereby the driver
+       is not stable under heavy load.  Race condition and all that.
+       Patch from Peter Lu.
+
+Wed Jan  4 21:17:40 1995  Eric Youngdale  (eric@andante)
+
+       * Linux 1.1.77 released.
+
+       * 53c7,8xx.c: Fix from Linus - emulate splx.
+
+       Throughout:
+
+               Change "snarf_region" with "register_iomem".
+
+       * scsi_module.c: New file.  Contains support for low-level loadable
+         scsi drivers. [ERY].
+
+       * sd.c: More s/int/long/ changes.
+
+       * seagate.c: Explicitly include linux/config.h
+
+       * sg.c: Increment/decrement module usage count on open/close.
+
+       * sg.c: Be a bit more careful about the user not supplying enough
+         information for a valid command.  Pass correct size down to
+         scsi_do_cmd.
+
+       * sr.c:  More changes for Photo-CD.  This apparently breaks NEC drives.
+
+       * sr_ioctl.c:  Support CDROMMULTISESSION ioctl.
+
+
+Sun Jan  1 19:55:21 1995  Eric Youngdale  (eric@andante)
+
+       * Linux 1.1.76 released.
+
+       * constants.c: Add type cast in switch statement.
+
+       * scsi.c (scsi_free): Change datatype of "offset" to long.
+         (scsi_malloc): Change a few more variables to long.  Who
+         did this and why was it important?  64 bit machines?
+
+
+       Lots of changes to use save_state/restore_state instead of cli/sti.
+       Files changed include:
+
+       * aha1542.c:
+       * aha1740.c:
+       * buslogic.c:
+       * in2000.c:
+       * scsi.c:
+       * scsi_debug.c:
+       * sd.c:
+       * sr.c:
+       * st.c:
+
+Wed Dec 28 16:38:29 1994  Eric Youngdale  (eric@andante)
+
+       * Linux 1.1.75 released.
+
+       * buslogic.c: Spelling fix.
+
+       * scsi.c: Add HP C1790A and C2500A scanjet to blacklist.
+
+       * scsi.c: Spelling fixup.
+
+       * sd.c: Add support for sd_hardsizes (hard sector sizes).
+
+       * ultrastor.c: Use save_flags/restore_flags instead of cli/sti.
+
+Fri Dec 23 13:36:25 1994  Eric Youngdale  (eric@andante)
+
+       * Linux 1.1.74 released.
+
+       * README.st: Update from Kai Makisara.
+
+       * eata.c: New version from Dario - version 1.11.
+         use scsicam bios_param routine.  Add support for 2011
+         and 2021 boards.
+
+       * hosts.c: Add support for blocking.  Linked list automatically
+         generated when shpnt->block is set.
+
+       * scsi.c: Add sankyo & HP scanjet to blacklist.  Add support for
+         kicking things loose when we deadlock.
+
+       * scsi.c: Recognize scanners and processors in scan_scsis.
+
+       * scsi_ioctl.h: Increase timeout to 9 seconds.
+
+       * st.c: New version from Kai - add better support for backspace.
+
+       * u14-34f.c: New version from Dario.  Supports blocking. 
+
+Wed Dec 14 14:46:30 1994  Eric Youngdale  (eric@andante)
+
+       * Linux 1.1.73 released.
+
+       * buslogic.c: Update from Dave Gentzel.  Version 1.14.
+         Add module related stuff.   More fault tolerant if out of
+         DMA memory.
+
+       * fdomain.c: New version from Rik Faith - version 5.22.  Add support
+         for ISA-200S SCSI adapter.
+
+       * hosts.c: Spelling.
+
+       * qlogic.c: Update to version 0.38a.  Add more support for PCMIA.
+
+       * scsi.c: Mask device type with 0x1f during scan_scsis.
+         Add support for deadlocking, err, make that getting out of
+         deadlock situations that are created when we allow the user
+         to limit requests to one host adapter at a time.
+
+       * scsi.c: Bugfix - pass pid, not SCpnt as second arg to
+         scsi_times_out.
+
+       * scsi.c: Restore interrupt state to previous value instead of using
+         cli/sti pairs.
+
+       * scsi.c: Add a bunch of module stuff (all commented out for now).
+
+       * scsi.c: Clean up scsi_dump_status.
+
 Tue Dec  6 12:34:20 1994  Eric Youngdale  (eric@andante)
 
        * Linux 1.1.72 released.
index 45787f5aa57e3d708d1d5c3c52ba415acf1ead4f..1aa26b84e481fc1479277ce7b0122ffd24257252 100644 (file)
@@ -25,6 +25,7 @@ endif
 
 SCSI_OBJS =
 SCSI_SRCS =
+SCSI_MODULE_OBJS =
 
 ifdef CONFIG_SCSI
 
@@ -61,9 +62,11 @@ SCSI_OBJS := $(SCSI_OBJS) aha152x.o
 SCSI_SRCS := $(SCSI_SRCS) aha152x.c
 endif
 
+SCSI_SRCS := $(SCSI_SRCS) aha1542.c
 ifdef CONFIG_SCSI_AHA1542
 SCSI_OBJS := $(SCSI_OBJS) aha1542.o
-SCSI_SRCS := $(SCSI_SRCS) aha1542.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) aha1542.o
 endif
 
 ifdef CONFIG_SCSI_AHA1740
@@ -81,14 +84,21 @@ SCSI_OBJS := $(SCSI_OBJS) buslogic.o
 SCSI_SRCS := $(SCSI_SRCS) buslogic.c
 endif
 
+ifdef CONFIG_SCSI_EATA_DMA
+SCSI_OBJS := $(SCSI_OBJS) eata_dma.o
+SCSI_SRCS := $(SCSI_SRCS) eata_dma.c
+endif
+
 ifdef CONFIG_SCSI_U14_34F
 SCSI_OBJS := $(SCSI_OBJS) u14-34f.o
 SCSI_SRCS := $(SCSI_SRCS) u14-34f.c
 endif
 
+SCSI_SRCS := $(SCSI_SRCS) scsi_debug.c
 ifdef CONFIG_SCSI_DEBUG
 SCSI_OBJS := $(SCSI_OBJS) scsi_debug.o
-SCSI_SRCS := $(SCSI_SRCS) scsi_debug.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) scsi_debug.o
 endif
 
 ifdef CONFIG_SCSI_FUTURE_DOMAIN
@@ -96,9 +106,11 @@ SCSI_OBJS := $(SCSI_OBJS) fdomain.o
 SCSI_SRCS := $(SCSI_SRCS) fdomain.c
 endif
 
+SCSI_SRCS := $(SCSI_SRCS) in2000.c
 ifdef CONFIG_SCSI_IN2000
 SCSI_OBJS := $(SCSI_OBJS) in2000.o
-SCSI_SRCS := $(SCSI_SRCS) in2000.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) in2000.o
 endif
 
 ifdef CONFIG_SCSI_GENERIC_NCR5380
@@ -175,6 +187,10 @@ seagate.o: seagate.c
        mv scriptu.h 53c8xx_u.h
        rm fake.c
 
+modules: $(SCSI_MODULE_OBJS)
+       echo $(SCSI_MODULE_OBJS) > ../../modules/SCSI_MODULES
+       (cd ../../modules;for i in $(SCSI_MODULE_OBJS); do ln -sf ../drivers/scsi/$$i .; done)
+
 dep:
        $(CPP) -M $(AHA152X) $(SCSI_SRCS) > .depend
 
@@ -189,8 +205,6 @@ dep:
 
 endif
 
-modules:
-
 #
 # include a dependency file if one exists
 #
index 1412ca33baba772b729a6d44a1332f15824fe978..029fbe529b33386ac7ffd2ceffd1e04f38142faf 100644 (file)
@@ -1,5 +1,5 @@
 This file contains brief information about the SCSI tape driver.
-Last modified: Sat Dec 17 13:38:43 1994 by root@kai.home
+Last modified: Tue Jan 10 21:32:35 1995 by root@kai.home
 
 BASICS
 
@@ -107,7 +107,8 @@ MTSETDRVBUFFER
            Sets the buffering options. The bits are the new states
            (enabled/disabled) of the write buffering (MT_ST_BUFFER_WRITES),
            asynchronous writes (MT_ST_ASYNC_WRITES), read ahead
-           (MT_ST_READ_AHEAD), writing of two filemark (ST_TWO_FM), and
+           (MT_ST_READ_AHEAD), writing of two filemark (ST_TWO_FM),
+          using the SCSI spacing to EOD (MT_ST_FAST_EOM), and
           debugging (MT_ST_DEBUGGING ; debugging must be compiled into the
           driver).
         MT_ST_WRITE_THRESHOLD
@@ -142,6 +143,12 @@ is defined.
 Immediate return from tape positioning SCSI commands can be enabled by
 defining ST_NOWAIT.
 
+The MTEOM command is by default implemented as spacing over 32767
+filemarks. With this method the file number in the status is
+correct. The user can request using direct spacing to EOD by setting
+ST_FAST_EOM 1 (or using the MTSTOPTIONS ioctl). In this case the file
+number will be invalid.
+
 When using read ahead or buffered writes the position within the file
 may not be correct after the file is closed (correct position may
 require backspacing over more than one record). The correct position
diff --git a/drivers/scsi/eata_dma.c b/drivers/scsi/eata_dma.c
new file mode 100644 (file)
index 0000000..75c06c8
--- /dev/null
@@ -0,0 +1,981 @@
+/************************************************************
+ *                                                          *
+ *                  Linux EATA SCSI driver                  *
+ *                                                          *
+ *  based on the CAM document CAM/89-004 rev. 2.0c,         *
+ *  DPT's driver kit, some internal documents and source,   *
+ *  and several other Linux scsi drivers and kernel docs.   *
+ *                                                          *
+ *  The driver currently:                                   *
+ *      -supports all ISA based EATA-DMA boards             *
+ *      -supports all EISA based EATA-DMA boards            *
+ *      -supports all PCI based EATA-DMA boards             *
+ *      -supports multiple HBAs with & without IRQ sharing  *
+ *      -supports all SCSI channels on multi channel boards *
+ *                                                          *
+ *  (c)1993,94,95 Michael Neuffer                           *
+ *                neuffer@goofy.zdv.uni-mainz.de            *
+ *                                                          *
+ *  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 of the License, or         *
+ *  (at your option) any later version.                     *
+ *                                                          *
+ *  This program is distributed in the hope that it will be *
+ *  useful, but WITHOUT ANY WARRANTY; without even the      *
+ *  implied warranty of MERCHANTABILITY or FITNESS FOR A    *
+ *  PARTICULAR PURPOSE.  See the GNU General Public License *
+ *  for more details.                                       *
+ *                                                          *
+ *  You should have received a copy of the GNU General      *
+ *  Public License along with this kernel; if not, write to *
+ *  the Free Software Foundation, Inc., 675 Mass Ave,       *
+ *  Cambridge, MA 02139, USA.                               *
+ *                                                          *
+ * I have to thank DPT for their excellent support. I took  *
+ * me almost a year and a stopover at their HQ, on my first *
+ * trip to the USA, to get it, but since then they've been  *
+ * very helpful and tried to give me all the infos and      *
+ * support I need.                                          *
+ *                                                          *
+ *  Thanks also to Greg Hosler who did a lot of testing and *
+ *  found quite a number of bugs during the devellopment.   *
+ ************************************************************
+ *  last change: 95/01/08                                   *
+ ************************************************************/
+
+/* Look in eata_dma.h for configuration information */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/in.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include "eata_dma.h"
+#include "scsi.h"
+#include "sd.h"
+
+static uint ISAbases[] =
+{0x1F0, 0x170, 0x330, 0x230};
+static unchar EISAbases[] =
+{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
+static uint registered_HBAs = 0;
+static struct Scsi_Host *last_HBA = NULL;
+static unchar reg_IRQ[] =
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+static unchar reg_IRQL[] =
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+static struct eata_sp status[MAXIRQ];  /* Statuspacket array   */
+
+static struct geom_emul geometry;      /* Drive 1 & 2 geometry */
+
+#if DEBUG
+static ulong int_counter = 0;
+static ulong queue_counter = 0;
+#endif
+
+const char *eata_info(struct Scsi_Host *host)
+{
+    static char *information = "EATA SCSI HBA Driver\n";
+    return information;
+}
+
+void eata_int_handler(int irq)
+{
+    uint i, result;
+    uint hba_stat, scsi_stat, eata_stat;
+    Scsi_Cmnd *cmd;
+    struct eata_ccb *cp;
+    struct eata_sp *sp;
+    uint base;
+    ulong flags;
+    uint x;
+    struct Scsi_Host *sh;
+
+    save_flags(flags);
+    cli();
+
+    for (x = 1, sh = last_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) {
+        if (sh->irq != irq)
+           continue;
+        if (!(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ))
+           continue;
+
+       DBG(DEBUG, int_counter++);
+
+       sp=&SD(sh)->sp;
+
+       cp = sp->ccb;
+       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 0x%04x, pid %lx, target: %x, "
+                            "lun: %x, ea_s: 0x%02x, hba_s: 0x%02x \n", 
+                            irq, base, cmd->pid, cmd->target, cmd->lun, 
+                            eata_stat, hba_stat));
+
+       switch (hba_stat) {
+       case 0x00:              /* status OK */
+           if (scsi_stat == INTERMEDIATE_GOOD && cmd->device->type != TYPE_TAPE)
+               result = DID_ERROR << 16;
+
+           /* If there was a bus reset, redo operation on each target */
+           else if (scsi_stat == CONDITION_GOOD
+                    && cmd->device->type == TYPE_DISK
+                    && (HD(cmd)->t_state[cmd->target] == RESET))
+               result = DID_BUS_BUSY << 16;        
+           else
+               result = DID_OK << 16;
+           if (scsi_stat == 0)
+               HD(cmd)->t_state[cmd->target] = FALSE;
+           HD(cmd)->t_timeout[cmd->target] = 0;
+           break;
+       case 0x01:              /* Selection Timeout */
+           result = DID_BAD_TARGET << 16;                  /* These two lines are new */
+           break;
+       case 0x02:              /* Command Timeout   */
+           if (HD(cmd)->t_timeout[cmd->target] > 1)
+               result = DID_ERROR << 16;
+           else {
+               result = DID_TIME_OUT << 16;
+               HD(cmd)->t_timeout[cmd->target]++;
+           }
+           break;
+       case 0x03:              /* SCSI Bus Reset Received */
+           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[i] = RESET;
+
+           break;
+       case 0x07:              /* Bus Parity Error */
+       case 0x0c:              /* Controller Ram Parity */
+       case 0x04:              /* Initial Controller Power-up */
+       case 0x05:              /* Unexpected Bus Phase */
+       case 0x06:              /* Unexpected Bus Free */
+       case 0x08:              /* SCSI Hung */
+       case 0x09:              /* Unexpected Message Reject */
+       case 0x0a:              /* SCSI Bus Reset Stuck */
+       case 0x0b:              /* Auto Request-Sense Failed */
+       default:
+           result = DID_ERROR << 16;
+           break;
+       }
+       cmd->result = result | scsi_stat;
+
+       if (scsi_stat == CHECK_CONDITION) { 
+           cmd->result |= (DRIVER_SENSE << 24);
+       }
+
+       DBG(DBG_INTR,printk("scsi_stat: 0x%02x, result: 0x%08x\n",  
+                           scsi_stat, result)); 
+       DBG(DBG_INTR&&DBG_DELAY,DEL2(800));
+
+       cp->status = FREE;   /* now we can release the slot  */
+       restore_flags(flags);
+   
+       DBG(DBG_INTR,printk("Calling scsi_done(%lx)\n",(long)cmd));
+       cmd->scsi_done(cmd);
+       DBG(DBG_INTR,printk("returned from scsi_done(%lx)\n",(long)cmd));
+       save_flags(flags);
+       cli();
+    }
+    restore_flags(flags);
+
+    return;
+}
+
+inline uint eata_send_command(ulong addr, uint base, unchar command)
+{
+    uint loop = R_LIMIT;
+
+    while (inb(base + HA_RAUXSTAT) & HA_ABUSY)
+        if (--loop == 0)
+            return(TRUE);
+
+    outb(addr & 0x000000ff, base + HA_WDMAADDR);
+    outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 1);
+    outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 2);
+    outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR + 3);
+    outb(command, base + HA_WCOMMAND);
+    return(FALSE);
+}
+
+int eata_queue(Scsi_Cmnd * cmd, void *(done) (Scsi_Cmnd *))
+{
+    uint i, x, y;
+    long flags;
+
+    hostdata *hd;
+    struct Scsi_Host *sh;
+    struct eata_ccb *cp;
+    struct scatterlist *sl;
+
+    save_flags(flags);
+    cli();
+
+    DBG(DEBUG,queue_counter++);
+
+    hd = HD(cmd);
+    sh = cmd->host;
+    /* check for free slot */
+     for (y = hd->last_ccb + 1, x = 0; x < sh->can_queue; x++, y++) { 
+       if (y >= sh->can_queue)
+           y = 0;
+       if (hd->ccb[y].status == FREE)
+           break;
+    }
+
+    hd->last_ccb = y;
+
+    if (x == sh->can_queue) { 
+
+        DBG(DBG_QUEUE, printk("can_queue %d, x %d, y %d\n",sh->can_queue,x,y));
+#if DEBUG
+        panic("eata_dma: run out of queue slots cmdno:%ld intrno: %ld\n", 
+             queue_counter, int_counter);
+#else
+        panic("eata_dma: run out of queue slots....\n");
+#endif
+    }
+
+    cp = &hd->ccb[y];
+
+    memset(cp, 0, sizeof(struct eata_ccb));
+
+    cp->status = USED;         /* claim free slot */
+    
+    DBG(DBG_QUEUE, printk("eata_queue pid %lx, target: %x, lun: %x, y %d\n",
+                         cmd->pid, cmd->target, cmd->lun, y));
+    DBG(DBG_QUEUE && DBG_DELAY, DEL2(250));
+    cmd->scsi_done = (void *)done;
+
+    if (cmd->cmnd[0] == WRITE_6 || cmd->cmnd[0] == WRITE_10)
+       cp->DataOut = TRUE;     /* Output mode */
+    else
+       cp->DataIn = TRUE;      /* Input mode  */
+
+    if (cmd->use_sg) {
+       cp->scatter = TRUE;     /* SG mode     */
+       cp->cp_dataDMA = htonl((long)&cp->sg_list);
+        cp->cp_datalen = htonl(cmd->use_sg*8);
+       sl=(struct scatterlist *)cmd->request_buffer;
+       for(i = 0; i < cmd->use_sg; i++, sl++){
+           cp->sg_list[i].data = htonl((ulong) sl->address);
+           cp->sg_list[i].len = htonl((ulong) sl->length);
+       }
+    } else {
+        cp->scatter = FALSE;
+       cp->cp_datalen = htonl(cmd->request_bufflen);
+       cp->cp_dataDMA = htonl((int)cmd->request_buffer);
+    }
+
+    cp->Auto_Req_Sen = TRUE;
+    cp->cp_reqDMA = htonl((ulong) cmd->sense_buffer);
+    cp->reqlen = sizeof(cmd->sense_buffer);
+
+    cp->cp_id = cmd->target;
+    cp->cp_lun = cmd->lun;
+    cp->cp_dispri = TRUE;
+    cp->cp_identify = TRUE;
+    memcpy(cp->cp_cdb, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd));
+
+    cp->cp_statDMA = htonl((ulong) &(hd->sp));
+
+    cp->cp_viraddr = cp;
+    cp->cmd = cmd;
+    cmd->host_scribble = (char *)&hd->ccb[y];  
+
+    if(eata_send_command((ulong) cp, (uint) sh->base, EATA_CMD_DMA_SEND_CP)) {
+      cmd->result = DID_ERROR << 16;
+      printk("eata_queue target %d, pid %ld, HBA busy, returning DID_ERROR, done.\n",
+              cmd->target, cmd->pid);
+      restore_flags(flags);
+      done(cmd);
+      return (0);
+    }
+    DBG(DBG_QUEUE,printk("Queued base 0x%04lx pid: %lx target: %x lun: %x slot %d irq %d\n",
+                         (long)sh->base, cmd->pid, cmd->target, cmd->lun, y, sh->irq));
+    DBG(DBG_QUEUE && DBG_DELAY, DEL2(200));
+    restore_flags(flags);
+    return (0);
+}
+
+static volatile int internal_done_flag = 0;
+static volatile int internal_done_errcode = 0;
+
+static void internal_done(Scsi_Cmnd * cmd)
+{
+    internal_done_errcode = cmd->result;
+    ++internal_done_flag;
+}
+
+int eata_command(Scsi_Cmnd * cmd)
+{
+
+    DBG(DBG_COM, printk("eata_command: calling eata_queue\n"));
+
+    eata_queue(cmd, (void *)internal_done);
+
+    while (!internal_done_flag);
+    internal_done_flag = 0;
+    return (internal_done_errcode);
+}
+
+int eata_abort(Scsi_Cmnd * cmd)
+{
+    ulong flags;
+    uint loop = R_LIMIT;
+
+    save_flags(flags);
+    cli();
+
+    DBG(DBG_ABNORM, printk("eata_abort called pid: %lx target: %x lun: %x reason %x\n",
+                          cmd->pid, cmd->target, cmd->lun, cmd->abort_reason));
+    DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+
+    while (inb((uint)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY)
+        if (--loop == 0) {
+           printk("eata_dma: abort, timeout error.\n");
+           restore_flags(flags);
+           DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+           return (SCSI_ABORT_ERROR);
+       }
+    if (CD(cmd)->status == FREE) {
+        DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_NOT_RUNNING\n")); 
+       restore_flags(flags);
+       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 == RESET) {
+       restore_flags(flags);
+        printk("eata_dma: abort, command reset error.\n");
+       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       return (SCSI_ABORT_ERROR);
+    }
+    if (CD(cmd)->status == LOCKED) {
+       restore_flags(flags);
+        DBG(DBG_ABNORM, printk("eata_dma: abort, queue slot locked.\n"));
+        DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       return (SCSI_ABORT_NOT_RUNNING);
+    } else
+       panic("eata_dma: abort: invalid slot status\n");
+}
+
+int eata_reset(Scsi_Cmnd * cmd)
+{
+    uint x, z, time, limit = 0;
+    uint loop = R_LIMIT;
+    ulong flags;
+    unchar success = FALSE;
+    Scsi_Cmnd *sp; 
+
+    save_flags(flags);
+    cli();
+
+    DBG(DBG_ABNORM, printk("eata_reset called pid:%lx target: %x lun: %x reason %x\n",
+                          cmd->pid, cmd->target, cmd->lun, cmd->abort_reason));
+
+
+    if (HD(cmd)->state == RESET) {
+       printk("eata_dma: reset, exit, already in reset.\n");
+       restore_flags(flags);
+        DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       return (SCSI_RESET_ERROR);
+    }
+
+    while (inb((uint)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY)
+        if (--loop == 0) {
+           printk("eata_dma: reset, exit, timeout error.\n");
+           restore_flags(flags);
+           DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+           return (SCSI_RESET_ERROR);
+       }
+    for (z = 0; z < MAXTARGET; z++)
+       HD(cmd)->t_state[z] = RESET;
+
+    for (x = 0; x < cmd->host->can_queue; x++) {
+
+       if (HD(cmd)->ccb[x].status == FREE)
+           continue;
+
+       if (HD(cmd)->ccb[x].status == LOCKED) {
+           HD(cmd)->ccb[x].status = FREE;
+           printk("eata_dma: reset, locked slot %d forced free.\n", x);
+           DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+           continue;
+       }
+       sp = HD(cmd)->ccb[x].cmd;
+       HD(cmd)->ccb[x].status = RESET;
+       printk("eata_dma: reset, slot %d in reset, pid %ld.\n", x, sp->pid);
+        DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       if (sp == NULL)
+           panic("eata_dma: reset, slot %d, sp==NULL.\n", x);
+            DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       if (sp == cmd)
+           success = TRUE;
+    }
+
+    /* hard reset the HBA  */
+    inb((uint) (cmd->host->base) + HA_RSTATUS);   /* This might cause trouble */
+    eata_send_command(0, (uint) cmd->host->base, EATA_CMD_RESET);
+
+    DBG(DBG_ABNORM, printk("eata_dma: reset, board reset done, enabling interrupts.\n"));
+    HD(cmd)->state = RESET;
+
+    restore_flags(flags);
+
+    time = jiffies;
+    while (jiffies < (time + 300) && limit++ < 10000000);
+
+    save_flags(flags);
+    cli();
+
+    DBG(DBG_ABNORM, printk("eata_dma: reset, interrupts disabled, loops %d.\n",
+                          limit));
+    DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+    for (x = 0; x < cmd->host->can_queue; x++) {
+
+       /* Skip slots already set free by interrupt */
+       if (HD(cmd)->ccb[x].status != RESET)
+           continue;
+
+       sp = HD(cmd)->ccb[x].cmd;
+       sp->result = DID_RESET << 16;
+
+       /* This mailbox is still waiting for its interrupt */
+       HD(cmd)->ccb[x].status = LOCKED;
+
+       printk("eata_dma, reset, slot %d locked, DID_RESET, pid %ld done.\n",
+           x, sp->pid);
+        DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       restore_flags(flags);
+       sp->scsi_done(sp);
+       cli();
+    }
+
+    HD(cmd)->state = FALSE;
+    restore_flags(flags);
+
+    if (success) {
+       DBG(DBG_ABNORM, printk("eata_dma: reset, exit, success.\n"));
+        DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       return (SCSI_RESET_SUCCESS);
+    } else {
+       DBG(DBG_ABNORM, printk("eata_dma: reset, exit, wakeup.\n"));
+        DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       return (SCSI_RESET_PUNT);
+    }
+}
+
+int check_blink_state(long base)
+{
+    uint ret = 0;
+    uint loops = 10;
+    ulong blinkindicator = 0x42445054;
+    ulong state = 0x12345678;
+    ulong oldstate = 0;
+
+    while ((loops--) && (state != oldstate)) {
+       oldstate = state;
+       state = inl((uint) base + 1);
+    }
+
+    if ((state == oldstate) && (state == blinkindicator))
+       ret = 1;
+    DBG(DBG_BLINK, printk("Did Blink check. Status: %d\n", ret));
+    return (ret);
+}
+
+int get_conf_PIO(struct eata_register *base, struct get_conf *buf)
+{
+    ulong loop = R_LIMIT;
+    ushort *p;
+
+    if(check_region((uint)base, 9)) 
+        return (FALSE);
+    memset(buf, 0, sizeof(struct get_conf));
+
+    while (inb((uint) base + HA_RSTATUS) & HA_SBUSY)
+       if (--loop == 0) 
+           return (FALSE);
+       
+    DBG(DBG_PIO && DBG_PROBE, printk("Issuing PIO READ CONFIG to HBA at %lx\n", 
+                                  (long)base));
+    eata_send_command(0, (uint) base, EATA_CMD_PIO_READ_CONFIG);
+    loop = R_LIMIT;
+    for (p = (ushort *) buf; 
+         (long)p <= ((long)buf + (sizeof(struct get_conf)/ 2)); p++) {
+        while (!(inb((uint) base + HA_RSTATUS) & HA_SDRQ))
+           if (--loop == 0)
+               return (FALSE);
+       loop = R_LIMIT;
+       *p = inw((uint) base + HA_RDATA);
+    }
+    if (!(inb((uint) base + HA_RSTATUS) & HA_SERROR)) {                /* Error ? */
+        DBG(DBG_PIO&&DBG_PROBE, printk("\nSignature: %c%c%c%c\n", 
+                             (char)buf->sig[0], (char)buf->sig[1], 
+                             (char)buf->sig[2], (char)buf->sig[3]));
+
+       if ((buf->sig[0] == 'E') && (buf->sig[1] == 'A')
+           && (buf->sig[2] == 'T') && (buf->sig[3] == 'A')) {
+           DBG(DBG_PIO&&DBG_PROBE, printk("EATA Controller found at %x "
+                     "EATA Level: %x\n", (uint) base, (uint) (buf->version)));
+       
+           while (inb((uint) base + HA_RSTATUS) & HA_SDRQ) 
+               inw((uint) base + HA_RDATA);
+           return (TRUE);
+       } 
+    } else {
+        printk("eata_dma: get_conf_PIO, error during transfer for HBA at %lx",
+              (long)base);
+    }
+    return (FALSE);
+}
+
+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",
+       (uint) ntohl(gc->len), gc->version,
+       gc->OCS_enabled, gc->TAR_support, gc->TRNXFR, gc->MORE_support,
+       gc->DMA_support);
+    printk("DMAV:%d HAAV:%d SCSIID0:%d ID1:%d ID2:%d QUEUE:%d SG:%d SEC:%d\n",
+       gc->DMA_valid, gc->HAA_valid, gc->scsi_id[3], gc->scsi_id[2],
+       gc->scsi_id[1], ntohs(gc->queuesiz), ntohs(gc->SGsiz), gc->SECOND);
+    printk("IRQ:%d IRQT:%d DMAC:%d FORCADR:%d MCH:%d RIDQ:%d PCI:%d EISA:%d\n",
+       gc->IRQ, gc->IRQ_TR, (8 - gc->DMA_channel) & 7, gc->FORCADR, 
+       gc->MAX_CHAN, gc->ID_qest, gc->is_PCI, gc->is_EISA);
+    DBG(DPT_DEBUG, DELAY(1400));
+}
+
+int register_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt)
+{
+    ulong size = 0;
+    unchar dma_channel = 0;
+    uint i;
+    struct Scsi_Host *sh;
+    hostdata *hd;
+    
+    printk("EATA compliant HBA detected. EATA Level %x\n",
+       (uint) (gc->version));
+
+    DBG(DBG_REGISTER, print_config(gc));
+
+    if (!gc->DMA_support) {
+       printk("HBA at 0x%08lx doesn't support DMA. Sorry\n",base);
+       return (FALSE);
+    }
+
+    /* if gc->DMA_valid it must be a PM2011 and we have to register it */
+    dma_channel = (8 - gc->DMA_channel) & 7;
+    if (gc->DMA_valid) {
+       if (request_dma(dma_channel, "DPT_PM2011")) {
+           printk("Unable to allocate DMA channel %d for HBA PM2011.\n",
+               dma_channel);
+           return (FALSE);
+       }
+    }
+
+    if (!reg_IRQ[gc->IRQ]) {   /* Interrupt already registered ? */
+       if (!request_irq(gc->IRQ, eata_int_handler, SA_INTERRUPT, "EATA-DMA")){
+           reg_IRQ[gc->IRQ]++;
+           if (!gc->IRQ_TR)
+               reg_IRQL[gc->IRQ] = 1;  /* IRQ is edge triggered */
+
+           /* We free it again so we can do a get_conf_dma and 
+            * allocate the interrupt again later */
+           free_irq(gc->IRQ);  
+       } else {
+           printk("Couldn't allocate IRQ %d, Sorry.", gc->IRQ);
+           return (0);
+       }
+    } else {                   /* More than one HBA on this IRQ */
+       if (reg_IRQL[gc->IRQ]) {
+           printk("Can't support more than one HBA on this IRQ,\n"
+                  "  if the IRQ is edge triggered. Sorry.\n");
+           return (0);
+       } else
+           reg_IRQ[gc->IRQ]++;
+    }
+
+
+    request_region(base, 9, "eata_dma");
+
+    if(gc->HAA_valid == FALSE) gc->MAX_CHAN = 0;
+
+    size = sizeof(hostdata) + ((sizeof(struct eata_ccb) * ntohs(gc->queuesiz))/
+                              (gc->MAX_CHAN + 1));
+    if(ntohs(gc->queuesiz) == 0) {
+        gc->queuesiz = ntohs(64);
+           printk("Warning: Queue size had to be corrected.\n"
+                  "This might be a PM2012 with a defective Firmware\n");
+    }
+    if (gc->MAX_CHAN) {
+       printk("This is a multichannel HBA. Linux doesn't support them,\n");
+       printk("so we'll try to register every channel as a virtual HBA.\n");
+    }
+    
+    for (i = 0; i <= gc->MAX_CHAN; i++) {
+
+       sh = scsi_register(tpnt, size);
+       hd = SD(sh);                   
+
+       memset(hd->ccb, 0, (sizeof(struct eata_ccb) * ntohs(gc->queuesiz)) / 
+              (gc->MAX_CHAN + 1));
+
+       sh->base = (char *) base;
+       sh->irq = gc->IRQ;
+       sh->dma_channel = dma_channel;
+
+       sh->this_id = gc->scsi_id[3 - i];
+
+       sh->can_queue = ntohs(gc->queuesiz) / (gc->MAX_CHAN + 1);
+
+       if (gc->OCS_enabled == TRUE) {
+           sh->cmd_per_lun = sh->can_queue/C_P_L_DIV; 
+       } else {
+           sh->cmd_per_lun = 1;
+       }
+       sh->sg_tablesize = ntohs(gc->SGsiz);
+       if (sh->sg_tablesize > SG_SIZE || sh->sg_tablesize == 0) {
+           sh->sg_tablesize = SG_SIZE;
+           if (ntohs(gc->SGsiz) == 0)
+               printk("Warning: SG size had to be corrected.\n"
+                      "This might be a PM2012 with a defective Firmware\n");
+       }
+       sh->loaded_as_module = 0;       /* Not yet supported */
+
+       hd->channel = i;
+
+       if (gc->is_PCI)
+           hd->bustype = 'P';
+       else if (gc->is_EISA)
+           hd->bustype = 'E';
+       else
+           hd->bustype = 'I';
+
+       if (gc->SECOND)
+           hd->primary = FALSE;
+       else
+           hd->primary = TRUE;
+
+       if (hd->bustype != 'I')
+           sh->unchecked_isa_dma = FALSE;
+       else
+           sh->unchecked_isa_dma = TRUE;   /* We're doing ISA DMA */
+
+       if((hd->primary == TRUE) && (i == 0) && HARDCODED){                  
+         geometry.drv[0].heads = HEADS0;          
+         geometry.drv[0].sectors = SECTORS0;      
+         geometry.drv[0].cylinder = CYLINDER0;
+         geometry.drv[0].id = ID0;
+         geometry.drv[0].trans = TRUE;
+         geometry.drv[1].heads = HEADS1;
+         geometry.drv[1].sectors = SECTORS1;
+         geometry.drv[1].cylinder = CYLINDER1;
+         geometry.drv[1].id = ID1;
+         geometry.drv[1].trans = TRUE;
+       } else {
+         geometry.drv[0].id=-1;
+         geometry.drv[1].id=-1;
+       }
+
+       hd->next = NULL;        /* build a linked list of all HBAs */
+       hd->prev = last_HBA;
+       hd->prev->next = sh;
+       last_HBA = sh;
+
+       registered_HBAs++;
+    }
+    return (1);
+}
+
+/* flag: -1 scan for primary   HBA
+ *        0 scan for secondary HBA
+ * buf :  pointer to data structure for read config command
+ */
+
+long find_EISA(struct get_conf *buf)
+{
+    struct eata_register *base;
+    int i;
+
+#if CHECKPAL
+    unsigned char pal1, pal2, pal3, *p;
+#endif
+
+    for (i = 0; i < MAXEISA; i++) {
+       if (EISAbases[i] == TRUE) {     /* Still a possibility ?          */
+
+           base = (void *)0x1c88 + (i * 0x1000);
+#if CHECKPAL
+           p = (char *)base;
+           pal1 = *(p - 8);
+           pal2 = *(p - 7);
+           pal3 = *(p - 6);
+
+           if (((pal1 == 0x12) && (pal2 == 0x14)) ||
+               ((pal1 == 0x38) && (pal2 == 0xa3) && (pal3 == 0x82)) ||
+               ((pal1 == 0x06) && (pal2 == 0x94) && (pal3 == 0x24))) {
+               DBG(DBG_PROBE, printk("EISA EATA id tags found: %x %x %x \n",
+                       (int)pal1, (int)pal2, (int)pal3));
+#endif
+               if (get_conf_PIO(base, buf)) {
+                   DBG(DBG_PROBE&&DBG_EISA,print_config(buf));
+                   if ((buf->SECOND == FALSE) && (buf->IRQ)) {
+                       /* We just found a primary EISA, so there is no primary
+                        * ISA HBA and we can take it from the EISA list. 
+                        */
+                       ISAbases[0] = 0;
+                       EISAbases[i] = 0;
+                       return ((long)base);
+                   } else if ((buf->SECOND == TRUE) && (buf->IRQ)) {
+                       /* We've found a secondary EISA, so there is no 
+                        * secondary ISA HBA  */
+                       ISAbases[1] = 0;
+                       /* and we can take it from the list and return it */
+                       EISAbases[i] = 0;
+                       return ((long)base);
+                   } else {
+                       EISAbases[i] = 0;
+                       printk("No vaild IRQ. HBA removed from list\n");
+                   }
+                } else
+                   /* Nothing found here so we take it from the list */
+                   EISAbases[i] = 0;  
+#if CHECKPAL
+           }
+#endif
+        }
+    }
+    return (0l);               /* Nothing found  :-(             */
+}
+
+long find_ISA(struct get_conf *buf)
+{
+    int i, l;
+    long ret;
+
+    ret = (long)NULL;
+
+    for (l = 0; l < MAXISA; l++) {     
+        if (ISAbases[l]) {     
+           i = get_conf_PIO((struct eata_register *)ISAbases[l], buf);
+           if (i == TRUE) {
+               ret = ISAbases[l];
+               ISAbases[l] = 0;
+               return (ret);
+           } else
+               ISAbases[l] = 0;
+        }
+    }
+    return ((long)NULL);
+}
+
+void find_PCI(struct get_conf *buf, Scsi_Host_Template * tpnt)
+{
+
+#ifndef CONFIG_PCI
+    printk("Kernel PCI support not enabled. Skipping.\n");
+#else
+
+    unchar pci_bus, pci_device_fn;
+    static short pci_index = 0;        /* Device index to PCI BIOS calls */
+    ulong base = 0;
+    ushort com_adr;
+    ushort rev_device;
+    uint error, i, x;
+
+    if (pcibios_present()) {
+       for (i = 0; i <= MAXPCI; ++i, ++pci_index) {
+
+           if (pcibios_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, 
+                                   pci_index, &pci_bus, &pci_device_fn))
+               break;
+           DBG(DBG_PROBE && DBG_PCI, printk("eata_dma: HBA at bus %d, device %d,"
+                               " function %d, index %d\n", (int)pci_bus, 
+                               (int)((pci_device_fn & 0xf8) >> 3),
+                               (int)(pci_device_fn & 7), pci_index));
+
+           if (!(error = pcibios_read_config_word(pci_bus, pci_device_fn, 
+                                                PCI_CLASS_DEVICE, &rev_device))) {
+               if (rev_device == PCI_CLASS_STORAGE_SCSI) {
+                   if (!(error = pcibios_read_config_word(pci_bus, 
+                                                          pci_device_fn, PCI_COMMAND, 
+                                                          (ushort *) & com_adr))) {
+                       if (!((com_adr & PCI_COMMAND_IO) && 
+                             (com_adr & PCI_COMMAND_MASTER))) {
+                           printk("HBA has IO or BUSMASTER mode disabled\n");
+                           continue;
+                       }
+                   } else
+                       printk("error %x while reading PCI_COMMAND\n", error);
+               } else
+                 printk("DEVICECLASSID %x didn't match\n", rev_device);
+           } else {
+             printk("error %x while reading PCI_CLASS_BASE\n", error);
+             continue;
+           }
+
+           if (!(error = pcibios_read_config_dword(pci_bus, pci_device_fn,
+                                                 PCI_BASE_ADDRESS_0, &base))) {
+
+               /* Check if the address is vaild */
+               if (base & 0x01) {
+                   base &= 0xfffffffe;
+                                       /* EISA tag there ? */
+                   if ((inb(base) == 0x12) && (inb(base + 1) == 0x14))
+                       continue;       /* Jep, it's forced, so move on  */
+                   base += 0x10;       /* Now, THIS is the real address */
+                   if (base != 0x1f8) {
+                       /* We didn't find it in the primary search */
+                       if (get_conf_PIO((struct eata_register *)base, buf)) {
+                           if (buf->FORCADR)   /* If the address is forced */
+                               continue;       /* we'll find it later      */
+
+                           /* OK. We made it till here, so we can go now  
+                            * and register it. We  only have to check and 
+                            * eventually remove it from the EISA and ISA list 
+                            */
+
+                           register_HBA(base, buf, tpnt);
+
+                           if (base < 0x1000) {
+                               for (x = 0; x < MAXISA; ++x) {
+                                   if (ISAbases[x] == base) {
+                                       ISAbases[x] = 0;
+                                       break;
+                                   }
+                               }
+                           } else if ((base & 0x0fff) == 0x0c88) {
+                               x = (base >> 12) & 0x0f;
+                               EISAbases[x] = 0;
+                           }
+                           continue;  /*break;*/
+                       } else if (check_blink_state(base)) {
+                           printk("HBA is in BLINK state. Consult your HBAs "
+                                  " Manual to correct this.\n");
+                       }
+                   }
+               }
+           } else
+             printk("error %x while reading PCI_BASE_ADDRESS_0\n", error);
+       }
+    } else
+    printk("No BIOS32 extensions present. This release still depends on it."
+            " Sorry.\n");
+#endif /* #ifndef CONFIG_PCI */
+    return;
+}
+
+int eata_detect(Scsi_Host_Template * tpnt)
+{
+    struct Scsi_Host *HBA_ptr;
+    struct get_conf gc;
+    ulong base = 0;
+    int i;
+    geometry.drv[0].trans = geometry.drv[1].trans = 0;
+
+    printk("EATA (Extended Attachment) driver version: %d.%d%s\n"
+          "developed in co-operation with DPT\n"             
+          "(c) 1993-95 Michael Neuffer  neuffer@goofy.zdv.uni-mainz.de\n",
+          VER_MAJOR, VER_MINOR, VER_SUB);
+    DBG((DBG_PROBE && DBG_DELAY)|| DPT_DEBUG,
+       printk("Using lots of delays to let you read the debugging output\n"));
+
+    printk("Now scanning for PCI HBAs\n");
+
+    find_PCI(&gc, tpnt);
+
+    printk("Now scanning for EISA HBAs\n");
+
+    for (i = 0; i <= MAXEISA; i++) {
+       base = find_EISA(&gc);
+       if (base)
+           register_HBA(base, &gc, tpnt);
+    }
+
+    printk("Now scanning for ISA HBAs\n");
+
+    for (i = 0; i <= MAXISA; i++) {
+       base = find_ISA(&gc);
+       if (base)
+           register_HBA(base, &gc, tpnt);
+    }
+
+    for (i = 0; i <= MAXIRQ; i++)
+       if (reg_IRQ[i])
+           request_irq(i, eata_int_handler, SA_INTERRUPT, "EATA-DMA");
+
+    HBA_ptr = last_HBA;
+    for (i = 1; i < registered_HBAs; i++)
+        HBA_ptr = SD(HBA_ptr)->prev;
+
+    printk("\nRegistered HBAs:\n");
+    printk(" # Type: BaseIO: IRQ: Chan: ID: Prim: QS: SG: CPL:\n");
+    for (i = 1; i <= registered_HBAs; i++) {
+        printk("%2d   %c   0x%04x   %2d     %d   %d     %d  %2d  %2d   %2d\n", 
+              i, SD(HBA_ptr)->bustype, (uint) HBA_ptr->base, HBA_ptr->irq, 
+              SD(HBA_ptr)->channel, HBA_ptr->this_id, SD(HBA_ptr)->primary, 
+              HBA_ptr->can_queue, HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun);
+        HBA_ptr = SD(HBA_ptr)->next;
+      }
+    DBG(DPT_DEBUG,DELAY(1200));
+
+    return (registered_HBAs);
+}
+
+
+
diff --git a/drivers/scsi/eata_dma.h b/drivers/scsi/eata_dma.h
new file mode 100644 (file)
index 0000000..b71332d
--- /dev/null
@@ -0,0 +1,367 @@
+/********************************************************
+* Header file for eata_dma.c Linux EATA-DMA SCSI driver *
+* (c) 1993,94,95 Michael Neuffer                        *
+*********************************************************
+* last change: 94/01/08                                 *
+********************************************************/
+
+
+#ifndef _EATA_DMA_H
+#define _EATA_DMA_H
+
+#include "../block/blk.h"
+#include "scsi.h"
+#include "hosts.h"
+#include <linux/scsicam.h>
+
+#define VER_MAJOR 2
+#define VER_MINOR 1
+#define VER_SUB   "0f"
+
+/************************************************************************
+ * Here you can configure your drives that are using a non-standard     *
+ * geometry.                                                            *
+ * To enable this set HARDCODED to 1                                    *
+ * If you have only one drive that need reconfiguration, set ID1 to -1  *
+ ************************************************************************/
+#define HARDCODED     0          /* Here are drives running in emu. mode   */
+
+#define ID0           0          /* SCSI ID of "IDE" drive mapped to C:    
+                                  * If you're not sure check your config
+                                 * utility that came with your controller
+                                 */
+#define HEADS0       13          /* Number of emulated heads of this drive */  
+#define SECTORS0     38          /* Number of emulated sectors             */ 
+#define CYLINDER0   719          /* Number of emulated cylinders           */
+   
+#define ID1           1          /* SCSI ID of "IDE" drive mapped to D:    */
+#define HEADS1       16          /* Number of emulated heads of this drive */ 
+#define SECTORS1     62          /* Number of emulated sectors             */
+#define CYLINDER1  1024          /* Number of emulated cylinders           */
+
+/************************************************************************
+ * Here you can switch parts of the code on and of                      *
+ ************************************************************************/
+
+#define CHECKPAL        0        /* EISA pal checking on/off            */
+
+/************************************************************************
+ * Debug options.                                                       * 
+ * Enable DEBUG and whichever options you require.                      *
+ ************************************************************************/
+#define DEBUG          1       /* Enable debug code.                   */
+#define DPT_DEBUG       0       /* Bobs special                         */
+#define DBG_DELAY       0      /* Build in delays so debug messages can be
+                                * be read before they vanish of the top of
+                                * the screen!
+                                */
+#define DBG_PROBE      0       /* Debug probe routines.                */
+#define DBG_PCI         0       /* Trace PCI routines                   */
+#define DBG_EISA        0       /* Trace EISA routines                  */
+#define DBG_ISA         0       /* Trace ISA routines                   */ 
+#define DBG_BLINK       0       /* Trace Blink check                    */
+#define DBG_PIO         0       /* Trace get_config_PIO                 */
+#define DBG_COM        0       /* Trace command call                   */
+#define DBG_QUEUE      0       /* Trace command queueing.              */
+#define DBG_INTR       0       /* Trace interrupt service routine.     */
+#define DBG_REGISTER    0       /* */
+#define DBG_ABNORM     1       /* Debug abnormal actions (reset, abort)*/
+
+#if DEBUG 
+#define DBG(x, y)      if ((x)) {y;} 
+#else
+#define DBG(x, y)
+#endif
+
+
+#define EATA_DMA {                   \
+       NULL, NULL,                  \
+        "EATA (Extended Attachment) driver\n", \
+        eata_detect,                 \
+        NULL,                        \
+        eata_info,                   \
+        eata_command,                \
+        eata_queue,                  \
+        eata_abort,                  \
+        eata_reset,                  \
+        NULL, /* Slave attach */     \
+       scsicam_bios_param,          \
+        0,      /* Canqueue     */   \
+        0,      /* this_id      */   \
+        0,      /* sg_tablesize */   \
+        0,      /* cmd_per_lun  */   \
+        0,      /* present      */   \
+        0,      /* True if ISA  */   \
+       ENABLE_CLUSTERING }
+
+int eata_detect(Scsi_Host_Template *);
+const char *eata_info(struct Scsi_Host *);
+int eata_command(Scsi_Cmnd *);
+int eata_queue(Scsi_Cmnd *, void *(done)(Scsi_Cmnd *));
+int eata_abort(Scsi_Cmnd *);
+int eata_reset(Scsi_Cmnd *);
+
+
+/*********************************************
+ * Misc. definitions                         *
+ *********************************************/
+
+#ifndef TRUE
+# define TRUE 1
+#endif
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+#define R_LIMIT 0x20000
+
+#define MAXISA     4
+#define MAXEISA   16  
+#define MAXPCI    16
+#define MAXIRQ    16 
+#define MAXTARGET  8
+
+/* PCI Bus And Device Limitations */
+
+#define MAX_PCI_DEVICES          32       /* Maximum # Of Devices Per Bus   */
+#define MAX_METHOD_2             16       /* Max Devices For Method 2       */
+#define MAX_PCI_BUS              16       /* Maximum # Of Busses Allowed    */
+
+
+#define SG_SIZE   64
+#define C_P_L_DIV 32     
+
+#define FREE      0
+#define USED      1
+#define TIMEOUT   2
+#define RESET     4
+#define LOCKED    8
+
+#define HD(cmd)  ((hostdata *)&(cmd->host->hostdata))
+#define CD(cmd)  ((struct eata_ccb *)(cmd->host_scribble))
+#define SD(host) ((hostdata *)&(host->hostdata))
+
+#define DELAY(x) { int i; i = jiffies + x; while (jiffies < i); }
+#define DEL2(x)  { ulong i; for (i = 0; i < 0xffff*x; i++); }
+
+/***********************************************
+ *    EATA Command & Register definitions      *
+ ***********************************************/
+#define PCI_REG_DPTconfig        0x40    
+#define PCI_REG_PumpModeAddress  0x44    
+#define PCI_REG_PumpModeData     0x48    
+#define PCI_REG_ConfigParam1     0x50    
+#define PCI_REG_ConfigParam2     0x54    
+
+
+#define EATA_CMD_PIO_READ_CONFIG 0xf0
+#define EATA_CMD_PIO_SET_CONFIG  0xf1
+#define EATA_CMD_PIO_SEND_CP     0xf2
+#define EATA_CMD_PIO_RECEIVE_SP  0xf3
+#define EATA_CMD_PIO_TRUNC       0xf4
+
+#define EATA_CMD_RESET           0xf9
+
+#define EATA_CMD_DMA_READ_CONFIG 0xfd
+#define EATA_CMD_DMA_SET_CONFIG  0xfe
+#define EATA_CMD_DMA_SEND_CP     0xff
+
+#define ECS_EMULATE_SENSE        0xd4
+
+#define HA_WCOMMAND 0x07        /* command register offset   */
+#define HA_WDMAADDR 0x02        /* DMA address LSB offset    */  
+#define HA_RAUXSTAT 0x08        /* aux status register offset*/
+#define HA_RSTATUS  0x07        /* status register offset    */
+#define HA_RDATA    0x00        /* data register (16bit)     */
+
+#define HA_ABUSY    0x01        /* aux busy bit              */
+#define HA_AIRQ     0x02        /* aux IRQ pending bit       */
+#define HA_SERROR   0x01        /* pr. command ended in error*/
+#define HA_SMORE    0x02        /* more data soon to come    */
+#define HA_SCORR    0x04        /* data corrected            */
+#define HA_SDRQ     0x08        /* data request active       */
+#define HA_SSC      0x10        /* seek complete             */
+#define HA_SFAULT   0x20        /* write fault               */
+#define HA_SREADY   0x40        /* drive ready               */
+#define HA_SBUSY    0x80        /* drive busy                */
+#define HA_SDRDY    HA_SSC+HA_SREADY+HA_SDRQ 
+
+/**********************************************
+ * Message definitions                        *
+ **********************************************/
+
+struct reg_bit {        /* reading this one will clear the interrupt   */
+  unchar error:1;     /* previous command ended in an error           */
+  unchar more:1;      /* more DATA comming soon, poll BSY & DRQ (PIO) */
+  unchar corr:1;      /* data read was successfully corrected with ECC*/
+  unchar drq:1;       /* data request aktive  */     
+  unchar sc:1;        /* seek complete        */
+  unchar fault:1;     /* write fault          */
+  unchar ready:1;     /* drive ready          */
+  unchar busy:1;      /* controller busy      */
+};
+
+struct reg_abit {       /* reading this won't clear the interrupt */
+  unchar abusy:1;     /* auxiliary busy                         */
+  unchar irq:1;       /* set when drive interrupt is asserted   */
+  unchar dummy:6;
+};
+
+struct eata_register {             /* EATA register set */
+  unchar data_reg[2];          /* R, couldn't figure this one out          */
+  unchar cp_addr[4];           /* W, CP address register                   */
+  union { 
+    unchar command;                    /* W, command code: [read|set] conf, send CP*/
+    struct reg_bit status;     /* R, see register_bit1                     */
+    unchar statusunchar;
+  } ovr;   
+  struct reg_abit aux_stat;    /* R, see register_bit2                     */
+};
+
+/**********************************************
+ *  Other  definitions                        *
+ **********************************************/
+
+struct eata_sg_list
+{
+  ulong data;
+  ulong len;
+};
+
+struct get_conf {          /* Read Configuration Array  */
+  ulong  len;                 /* Should return 0x22                    */
+  unchar sig[4];              /* Signature MUST be "EATA"              */
+  unchar    version2:4,
+             version:4;       /* EATA Version level                    */
+  unchar OCS_enabled:1,              /* Overlap Command Support enabled        */
+         TAR_support:1,              /* SCSI Target Mode supported             */
+              TRNXFR:1,              /* Truncate Transfer Cmd not necessary    */
+                              /* Only used in PIO Mode                         */
+        MORE_support:1,              /* MORE supported (only PIO Mode)         */
+         DMA_support:1,              /* DMA supported Driver uses only         */
+                              /* this mode                             */
+           DMA_valid:1,       /* DRQ value in Byte 30 is valid         */
+                 ATA:1,       /* ATA device connected (not supported)  */
+           HAA_valid:1;       /* Hostadapter Address is valid          */
+
+  ushort cppadlen;           /* Number of pad unchars send after CD data */
+                              /* set to zero for DMA commands          */
+  unchar scsi_id[4];          /* SCSI ID of controller 2-0 Byte 0 res.  */
+                              /* if not, zero is returned              */
+  ulong  cplen;                      /* CP length: number of valid cp unchars  */
+  ulong  splen;                      /* Number of unchars returned after       */ 
+                              /* Receive SP command                    */
+  ushort queuesiz;           /* max number of queueable CPs            */
+  ushort dummy;
+  ushort SGsiz;                      /* max number of SG table entries         */
+  unchar    IRQ:4,            /* IRQ used this HA                      */
+         IRQ_TR:1,            /* IRQ Trigger: 0=edge, 1=level          */
+         SECOND:1,            /* This is a secondary controller                */  
+    DMA_channel:2;            /* DRQ index, DRQ is 2comp of DRQX       */
+  unchar sync;                /* device at ID 7 tru 0 is running in    */
+                              /* synchronous mode, this will disappear  */
+  unchar   DSBLE:1,           /* ISA i/o addressing is disabled         */
+         FORCADR:1,           /* i/o address has been forced            */
+                :6;
+  unchar  MAX_ID:5,           /* Max number of SCSI target IDs          */
+        MAX_CHAN:3;           /* Number of SCSI busses on HBA           */
+  unchar MAX_LUN;             /* Max number of LUNs                     */
+  unchar        :5,          
+         ID_qest:1,           /* Raidnum ID is questionable             */
+          is_PCI:1,           /* HBA is PCI                             */
+         is_EISA:1;           /* HBA is EISA                            */
+  unchar unused[478]; 
+};
+
+struct eata_ccb {             /* Send Command Packet structure      */
+  unchar SCSI_Reset:1,        /* Cause a SCSI Bus reset on the cmd  */
+           HBA_Init:1,        /* Cause Controller to reinitialize   */
+       Auto_Req_Sen:1,        /* Do Auto Request Sense on errors    */
+            scatter:1,        /* Data Ptr points to a SG Packet     */
+             Resrvd:1,        /* RFU                                */
+          Interpret:1,        /* Interpret the SCSI cdb of own use  */
+            DataOut:1,        /* Data Out phase with command        */
+             DataIn:1;        /* Data In phase with command         */
+  unchar reqlen;             /* Request Sense Length               */ 
+                              /* Valid if Auto_Req_Sen=1            */
+  unchar unused[3];
+  unchar  FWNEST:1,           /* send cmd to phys RAID component*/
+         unused2:7;
+  unchar Phsunit:1,           /* physical unit on mirrored pair        */
+            I_AT:1,           /* inhibit address translation    */
+         I_HBA_C:1,           /* HBA Inhibit caching            */
+         unused3:5;
+
+  unchar cp_id;               /* SCSI Device ID of target       */ 
+  unchar    cp_lun:3,
+                  :2,
+         cp_luntar:1,         /* CP is for target ROUTINE       */
+         cp_dispri:1,         /* Grant disconnect privilege     */
+       cp_identify:1;         /* Always TRUE                    */         
+  unchar cp_msg1;             /* Message bytes 0-3              */
+  unchar cp_msg2;
+  unchar cp_msg3;
+  unchar cp_cdb[12];                 /* Command Descriptor Block       */
+  ulong  cp_datalen;         /* Data Transfer Length           */
+                              /* If scatter=1 len of sg package */
+  void *cp_viraddr;           /* address of this ccb            */
+  ulong cp_dataDMA;          /* Data Address, if scatter=1     */
+                              /* address of scatter packet      */  
+  ulong cp_statDMA;           /* address for Status Packet      */ 
+  ulong cp_reqDMA;            /* Request Sense Address, used if */
+                              /* CP command ends with error     */
+  ulong timeout;
+  unchar retries;
+  unchar status;              /* status of this queueslot       */
+  struct eata_sg_list sg_list[SG_SIZE];
+  Scsi_Cmnd *cmd;             /* address of cmd                 */
+};
+
+
+struct eata_sp
+{
+  unchar hba_stat:7,          /* HBA status                     */
+              EOC:1;          /* True if command finished       */
+  unchar scsi_stat;           /* Target SCSI status             */       
+  unchar reserved[2];
+  ulong  residue_len;         /* Number of unchars not transferred */
+  struct eata_ccb *ccb;       /* Address set in COMMAND PACKET  */
+  unchar msg[12];
+};
+
+typedef struct hstd{
+  unchar bustype;              /* bustype of HBA             */
+  unchar channel;              /* no. of scsi channel        */
+  unchar state;                /* state of HBA               */
+  unchar t_state[MAXTARGET];   /* state of Target (RESET,..) */
+  uint   t_timeout[MAXTARGET]; /* timeouts on target         */
+  unchar primary;              /* true if primary            */
+  uint   last_ccb;             /* Last used ccb              */
+  struct Scsi_Host *next;         
+  struct Scsi_Host *prev;
+  struct eata_sp sp;           /* status packet              */ 
+  struct eata_ccb ccb[0];      /* ccb array begins here      */
+}hostdata;
+
+
+
+/* structure for max. 2 emulated drives */
+struct drive_geom_emul {
+  unchar trans;                 /* translation flag 1=transl */
+  unchar channel;               /* SCSI channel number       */
+  unchar HBA;                   /* HBA number (prim/sec)     */
+  unchar id;                    /* drive id                  */
+  unchar lun;                   /* drive lun                 */
+  uint   heads;                 /* number of heads           */
+  uint   sectors;               /* number of sectors         */
+  uint   cylinder;              /* number of cylinders       */
+};
+
+struct geom_emul {
+  int bios_drives;               /* number of emulated drives */
+  struct drive_geom_emul drv[2]; /* drive structures          */
+};
+
+#endif /* _EATA_H */
index 6e42031583a5ae441f9f9f54b8a6c4493e155ad5..19499d3404157050c3ee67775017244e64f4f3d2 100644 (file)
 #include "buslogic.h"
 #endif
 
+#ifdef CONFIG_SCSI_EATA_DMA
+#include "eata_dma.h"
+#endif
+
 #ifdef CONFIG_SCSI_U14_34F
 #include "u14-34f.h"
 #endif
@@ -178,6 +182,9 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
 #ifdef CONFIG_SCSI_NCR53C7xx
        NCR53c7xx,
 #endif
+#ifdef CONFIG_SCSI_EATA_DMA
+       EATA_DMA,
+#endif
 #ifdef CONFIG_SCSI_7000FASST
        WD7000,
 #endif
@@ -199,7 +206,7 @@ struct Scsi_Host * scsi_hostlist = NULL;
 struct Scsi_Device_Template * scsi_devicelist;
 
 int max_scsi_hosts = 0;
-static int next_host = 0;
+int next_scsi_host = 0;
 
 void
 scsi_unregister(struct Scsi_Host * sh){
@@ -215,7 +222,7 @@ scsi_unregister(struct Scsi_Host * sh){
                while(shpnt->next != sh) shpnt = shpnt->next;
                shpnt->next = shpnt->next->next;
        };
-       next_host--;
+       next_scsi_host--;
        scsi_init_free((char *) sh, sizeof(struct Scsi_Host) + j);
 }
 
@@ -225,13 +232,14 @@ scsi_unregister(struct Scsi_Host * sh){
 
 struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
        struct Scsi_Host * retval, *shpnt;
-       retval = (struct Scsi_Host *)scsi_init_malloc(sizeof(struct Scsi_Host) + j);
+       retval = (struct Scsi_Host *)scsi_init_malloc(sizeof(struct Scsi_Host) + j,
+                                                     (tpnt->unchecked_isa_dma && j ? GFP_DMA : 0) | GFP_ATOMIC);
        retval->host_busy = 0;
        retval->block = NULL;
        if(j > 0xffff) panic("Too many extra bytes requested\n");
        retval->extra_bytes = j;
        retval->loaded_as_module = scsi_loadable_module_flag;
-       retval->host_no = next_host++;
+       retval->host_no = next_scsi_host++;
        retval->host_queue = NULL;
        retval->host_wait = NULL;
        retval->last_reset = 0;
@@ -241,7 +249,7 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
        retval->hostt = tpnt;
        retval->next = NULL;
 #ifdef DEBUG
-       printk("Register %x %x: %d\n", retval, retval->hostt, j);
+       printk("Register %x %x: %d\n", (int)retval, (int)retval->hostt, j);
 #endif
 
        /* The next four are the default values which can be overridden
@@ -276,9 +284,10 @@ scsi_register_device(struct Scsi_Device_Template * sdpnt)
 unsigned int scsi_init()
 {
        static int called = 0;
-       int i, j, count, pcount;
+       int i, pcount;
        Scsi_Host_Template * tpnt;
-       count = 0;
+       struct Scsi_Host * shpnt;
+       const char * name;
 
        if(called) return 0;
 
@@ -290,28 +299,37 @@ unsigned int scsi_init()
                 * "inactive" - where as 0 will indicate a time out condition.
                 */
 
-               pcount = next_host;
+               pcount = next_scsi_host;
                if ((tpnt->detect) &&
                    (tpnt->present =
                     tpnt->detect(tpnt)))
                {
                        /* The only time this should come up is when people use
                           some kind of patched driver of some kind or another. */
-                       if(pcount == next_host) {
+                       if(pcount == next_scsi_host) {
                                if(tpnt->present > 1)
                                        panic("Failure to register low-level scsi driver");
                                /* The low-level driver failed to register a driver.  We
-                                  can do this now. */
+                                  can do this now. */
                                scsi_register(tpnt,0);
                        };
                        tpnt->next = scsi_hosts;
                        scsi_hosts = tpnt;
-                       for(j = 0; j < tpnt->present; j++)
-                               printk ("scsi%d : %s\n",
-                                       count++, tpnt->name);
                }
        }
-       printk ("scsi : %d hosts.\n", count);
+
+
+       for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
+           {
+             if(shpnt->hostt->info)
+               name = shpnt->hostt->info(shpnt);
+             else
+               name = shpnt->hostt->name;
+             printk ("scsi%d : %s\n", /* And print a little message */
+                     shpnt->host_no, name);
+           }
+
+       printk ("scsi : %d hosts.\n", next_scsi_host);
 
       {
       int block_count = 0, index;
@@ -351,7 +369,7 @@ unsigned int scsi_init()
        scsi_register_device(&sg_template);
 #endif
 
-       max_scsi_hosts = count;
+       max_scsi_hosts = next_scsi_host;
        return 0;
 }
 
index 4fb7625ba89d6543987dd122ca0840f7b3573a60..de93c5fac4e085979d3ce55503a751e8e5e184e2 100644 (file)
@@ -292,9 +292,12 @@ extern Scsi_Host_Template * scsi_hosts;
    looks normal.  Also, it makes it possible to use the same code for a
    loadable module. */
 
-extern void * scsi_init_malloc(unsigned int size);
+extern void * scsi_init_malloc(unsigned int size, int priority);
 extern void scsi_init_free(char * ptr, unsigned int size);
 
+void scan_scsis (struct Scsi_Host * shpnt);
+
+extern int next_scsi_host;
 
 extern int scsi_loadable_module_flag;
 unsigned int scsi_init(void);
@@ -317,7 +320,7 @@ struct Scsi_Device_Template
   int (*detect)(Scsi_Device *); /* Returns 1 if we can attach this device */
   void (*init)(void);  /* Sizes arrays based upon number of devices detected */
   void (*finish)(void);  /* Perform initialization after attachment */
-  void (*attach)(Scsi_Device *); /* Attach devices to arrays */
+  int (*attach)(Scsi_Device *); /* Attach devices to arrays */
   void (*detach)(Scsi_Device *);
 };
 
@@ -328,4 +331,26 @@ extern struct Scsi_Device_Template sg_template;
 
 int scsi_register_device(struct Scsi_Device_Template * sdpnt);
 
+/* These are used by loadable modules */
+extern int scsi_register_module(int, void *);
+extern void scsi_unregister_module(int, void *);
+
+/* The different types of modules that we can load and unload */
+#define MODULE_SCSI_HA 1
+#define MODULE_SCSI_CONST 2
+#define MODULE_SCSI_IOCTL 3
+#define MODULE_SCSI_DEV 4
+
+
+/*
+ * This is an ugly hack.  If we expect to be able to load devices at run time, we need
+ * to leave extra room in some of the data structures.  Doing a realloc to enlarge
+ * the structures would be riddled with race conditions, so until a better solution 
+ * is discovered, we use this crude approach
+ */
+#define SD_EXTRA_DEVS 2
+#define ST_EXTRA_DEVS 2
+#define SR_EXTRA_DEVS 2
+#define SG_EXTRA_DEVS (SD_EXTRA_DEVS + SR_EXTRA_DEVS + ST_EXTRA_DEVS)
+
 #endif
index b6df266d6dd77249d78a67a3f51efb02123bc2ed..14899b1f6798c03e74dcc6ea6486f1dfbea1a9c3 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/string.h>
 #include <linux/malloc.h>
 #include <asm/irq.h>
+#include <asm/dma.h>
+#include <linux/ioport.h>
 
 #include "../block/blk.h"
 #include "scsi.h"
@@ -219,6 +221,9 @@ static void scan_scsis_done (Scsi_Cmnd * SCpnt)
        printk ("scan_scsis_done(%d, %06x)\n", SCpnt->host, SCpnt->result);
 #endif 
        SCpnt->request.dev = 0xfffe;
+
+       if (SCpnt->request.sem != NULL)
+         up(SCpnt->request.sem);
        }
 
 #ifdef NO_MULTI_LUN
@@ -242,11 +247,12 @@ void scsi_luns_setup(char *str, int *ints) {
  *     devices to the disk driver.
  */
 
-static void scan_scsis (struct Scsi_Host * shpnt)
+void scan_scsis (struct Scsi_Host * shpnt)
 {
   int dev, lun, type;
   unsigned char scsi_cmd [12];
-  unsigned char scsi_result [256];
+  unsigned char scsi_result0 [256];
+  unsigned char * scsi_result;
   Scsi_Device * SDpnt, *SDtail;
   struct Scsi_Device_Template * sdtpnt;
   Scsi_Cmnd  SCmd;
@@ -256,12 +262,17 @@ static void scan_scsis (struct Scsi_Host * shpnt)
   type = -1;
   SCmd.next = NULL;
   SCmd.prev = NULL;
-  SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device));
+  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 = ((current == task[0]  || !shpnt->unchecked_isa_dma) 
+                ?  &scsi_result0[0] : scsi_malloc(512));
+           
+
   shpnt->host_queue = &SCmd;  /* We need this so that
                                         commands can time out */
   for (dev = 0; dev < 8; ++dev)
@@ -306,7 +317,21 @@ static void scan_scsis (struct Scsi_Host * shpnt)
                       scsi_result, 256,  scan_scsis_done, 
                       SCSI_TIMEOUT + 400, 5);
          
-         while (SCmd.request.dev != 0xfffe);
+         /* Wait for command to finish.  Use simple wait if we are booting, else
+            do it right and use a mutex */
+
+         if (current == task[0]){
+           while (SCmd.request.dev != 0xfffe);
+         } else {
+           if (SCmd.request.dev != 0xfffe){
+             struct semaphore sem = MUTEX_LOCKED;
+             SCmd.request.sem = &sem;
+             down(&sem);
+             /* Hmm.. Have to ask about this one */
+             while (SCmd.request.dev != 0xfffe) schedule();
+           }
+         }
+
 #if defined(DEBUG) || defined(DEBUG_INIT)
          printk("scsi: scan SCSIS id %d lun %d\n", dev, lun);
          printk("scsi: return code %08x\n", SCmd.result);
@@ -349,8 +374,18 @@ static void scan_scsis (struct Scsi_Host * shpnt)
                       scsi_result, 256,  scan_scsis_done, 
                       SCSI_TIMEOUT, 3);
          
-         while (SCmd.request.dev != 0xfffe);
-         
+         if (current == task[0]){
+           while (SCmd.request.dev != 0xfffe);
+         } else {
+           if (SCmd.request.dev != 0xfffe){
+             struct semaphore sem = MUTEX_LOCKED;
+             SCmd.request.sem = &sem;
+             down(&sem);
+             /* Hmm.. Have to ask about this one */
+             while (SCmd.request.dev != 0xfffe) schedule();
+           }
+         }
+
          the_result = SCmd.result;
          
 #if defined(DEBUG) || defined(DEBUG_INIT)
@@ -498,8 +533,18 @@ static void scan_scsis (struct Scsi_Host * shpnt)
                                 scsi_result, 0x2a,  scan_scsis_done, 
                                 SCSI_TIMEOUT, 3);
                    
-                   while (SCmd.request.dev != 0xfffe);
-                 };
+                   if (current == task[0]){
+                     while (SCmd.request.dev != 0xfffe);
+                   } else {
+                     if (SCmd.request.dev != 0xfffe){
+                       struct semaphore sem = MUTEX_LOCKED;
+                       SCmd.request.sem = &sem;
+                       down(&sem);
+                       /* Hmm.. Have to ask about this one */
+                       while (SCmd.request.dev != 0xfffe) schedule();
+                     }
+                   }
+                 }
                  /* Add this device to the linked list at the end */
                  if(SDtail)
                    SDtail->next = SDpnt;
@@ -507,7 +552,7 @@ static void scan_scsis (struct Scsi_Host * shpnt)
                    scsi_devices = SDpnt;
                  SDtail = SDpnt;
 
-                 SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device));
+                 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(blacklisted(scsi_result)) break;
@@ -534,6 +579,10 @@ static void scan_scsis (struct Scsi_Host * shpnt)
   /* Last device block does not exist.  Free memory. */
   scsi_init_free((char *) SDpnt, sizeof(Scsi_Device));
   
+
+  /* If we allocated a buffer so we could do DMA, free it now */
+  if (scsi_result != &scsi_result0[0]) scsi_free(scsi_result, 512);
+
   in_scan_scsis = 0;
 }       /* scan_scsis  ends */
 
@@ -1805,18 +1854,23 @@ static int update_timeout(Scsi_Cmnd * SCset, int timeout)
        }               
 
 
-static unsigned short * dma_malloc_freelist = NULL;
+static unsigned char * dma_malloc_freelist = NULL;
+static int scsi_need_isa_bounce_buffers;
 static unsigned int dma_sectors = 0;
 unsigned int dma_free_sectors = 0;
 unsigned int need_isa_buffer = 0;
-static unsigned char * dma_malloc_buffer = NULL;
+static unsigned char ** dma_malloc_pages = NULL;
+#define MALLOC_PAGEBITS 12
+
+static int scsi_register_host(Scsi_Host_Template *);
+static void scsi_unregister_host(Scsi_Host_Template *);
 
 void *scsi_malloc(unsigned int len)
 {
   unsigned int nbits, mask;
   unsigned long flags;
   int i, j;
-  if((len & 0x1ff) || len > 8192)
+  if((len & 0x1ff) || len > (1<<MALLOC_PAGEBITS))
     return NULL;
   
   save_flags(flags);
@@ -1824,16 +1878,16 @@ void *scsi_malloc(unsigned int len)
   nbits = len >> 9;
   mask = (1 << nbits) - 1;
   
-  for(i=0;i < (dma_sectors >> 4); i++)
-    for(j=0; j<17-nbits; j++){
+  for(i=0;i < (dma_sectors >> (MALLOC_PAGEBITS - 9)); i++)
+    for(j=0; j<=(sizeof(*dma_malloc_freelist) * 8) - nbits; j++){
       if ((dma_malloc_freelist[i] & (mask << j)) == 0){
        dma_malloc_freelist[i] |= (mask << j);
        restore_flags(flags);
        dma_free_sectors -= nbits;
 #ifdef DEBUG
-       printk("SMalloc: %d %x ",len, dma_malloc_buffer + (i << 13) + (j << 9));
+       printk("SMalloc: %d %x ",len, dma_malloc_pages[i] + (j << 9));
 #endif
-       return (void *) ((unsigned long) dma_malloc_buffer + (i << 13) + (j << 9));
+       return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9));
       };
     };
   restore_flags(flags);
@@ -1850,14 +1904,20 @@ int scsi_free(void *obj, unsigned int len)
   printk("Sfree %x %d\n",obj, len);
 #endif
 
-  offset = ((unsigned long) obj) - ((unsigned long) dma_malloc_buffer);
-
-  if (offset < 0) panic("Bad offset");
-  page = offset >> 13;
+   offset = -1;
+  for (page = 0; page < (dma_sectors >> 3); page++)
+       if ((unsigned long) obj >= (unsigned long) dma_malloc_pages[page] &&
+               (unsigned long) obj < (unsigned long) dma_malloc_pages[page] + (1 << MALLOC_PAGEBITS))
+               {
+                       offset = ((unsigned long) obj) - ((unsigned long)dma_malloc_pages[page]);
+                       break;
+               }
+                
+  if (page == (dma_sectors >> 3)) panic("Bad offset");
   sector = offset >> 9;
   if(sector >= dma_sectors) panic ("Bad page");
 
-  sector = (offset >> 9) & 15;
+  sector = (offset >> 9) & (sizeof(*dma_malloc_freelist) * 8 - 1);
   nbits = len >> 9;
   mask = (1 << nbits) - 1;
 
@@ -1882,11 +1942,11 @@ int scsi_free(void *obj, unsigned int len)
 static unsigned long scsi_init_memory_start = 0;
 int scsi_loadable_module_flag; /* Set after we scan builtin drivers */
 
-void * scsi_init_malloc(unsigned int size)
+void * scsi_init_malloc(unsigned int size, int priority)
 {
   unsigned long retval;
   if(scsi_loadable_module_flag) {
-    retval = (unsigned long) kmalloc(size, GFP_ATOMIC);
+    retval = (unsigned long) kmalloc(size, priority);
   } else {
     retval = scsi_init_memory_start;
     scsi_init_memory_start += size;
@@ -1898,7 +1958,7 @@ void * scsi_init_malloc(unsigned int size)
 void scsi_init_free(char * ptr, unsigned int size)
 { /* FIXME - not right.  We need to compare addresses to see whether this was
      kmalloc'd or not */
-  if((unsigned long) ptr < scsi_loadable_module_flag) {
+  if((unsigned long) ptr > scsi_init_memory_start) {
     kfree(ptr);
   } else {
     if(((unsigned long) ptr) + size == scsi_init_memory_start)
@@ -1919,6 +1979,7 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
        struct Scsi_Host * shpnt;
        struct Scsi_Device_Template * sdtpnt;
        Scsi_Cmnd * SCpnt;
+       int i;
 #ifdef FOO_ON_YOU
        return;
 #endif 
@@ -1945,10 +2006,11 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
          int j;
          SDpnt->scsi_request_fn = NULL;
          for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-           if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
-         if(SDpnt->type != -1){
+             if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
+
+         if(SDpnt->attached){
            for(j=0;j<SDpnt->host->cmd_per_lun;j++){
-             SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd));
+             SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd), GFP_ATOMIC);
              SCpnt->host = SDpnt->host;
              SCpnt->device = SDpnt;
              SCpnt->target = SDpnt->id;
@@ -1974,6 +2036,11 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
        if (scsi_devicelist)
          dma_sectors = 16;  /* Base value we use */
 
+       if (memory_end-1 > ISA_DMA_THRESHOLD)
+         scsi_need_isa_bounce_buffers = 1;
+       else
+         scsi_need_isa_bounce_buffers = 0;
+
        for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
          host = SDpnt->host;
          
@@ -1995,16 +2062,22 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
        dma_free_sectors = dma_sectors;  /* This must be a multiple of 16 */
 
        scsi_init_memory_start = (scsi_init_memory_start + 3) & 0xfffffffc;
-       dma_malloc_freelist = (unsigned short *) 
-         scsi_init_malloc(dma_sectors >> 3);
+       dma_malloc_freelist = (unsigned char *) 
+         scsi_init_malloc(dma_sectors >> 3, GFP_ATOMIC);
        memset(dma_malloc_freelist, 0, dma_sectors >> 3);
 
+       dma_malloc_pages = (unsigned char **) 
+         scsi_init_malloc(dma_sectors >> 1, GFP_ATOMIC);
+       memset(dma_malloc_pages, 0, dma_sectors >> 1);
        /* Some host adapters require buffers to be word aligned */
        if(scsi_init_memory_start & 1) scsi_init_memory_start++;
-
-       dma_malloc_buffer = (unsigned char *) 
-         scsi_init_malloc(dma_sectors << 9);
        
+       for(i=0; i< dma_sectors >> 3; i++)
+         dma_malloc_pages[i] = (unsigned char *) 
+           scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
+
+
        /* OK, now we finish the initialization by doing spin-up, read
           capacity, etc, etc */
        for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
@@ -2059,7 +2132,6 @@ static void print_inquiry(unsigned char *data)
          printk("\n");
 }
 
-#ifdef NOT_YET
 /*
  * This entry point should be called by a loadable module if it is trying
  * add a low level scsi driver to the system.
@@ -2368,7 +2440,6 @@ void scsi_unregister_module(int module_type, void * ptr)
   }
   return;
 }
-#endif
 
 #ifdef DEBUG_TIMEOUT
 static void 
@@ -2424,5 +2495,3 @@ scsi_dump_status(void)
       }
 }
 #endif
-
-
index c013f17b9a8c37a5513d5a34328e9568f8e2cc87..e6d7a607d512df9f9e6b80d34005ae1d5a37fdef 100644 (file)
@@ -30,7 +30,7 @@
  */
 
 #include <linux/module.h>
-#include "../../tools/version.h"
+#include <linux/version.h>
 
 char kernel_version[] = UTS_RELEASE;
 
index c997084ed5bfae5c7bf2fdbb315ec577212723ad..157d7e49c5a18cb29f6a33af3f6b42368cfa22ed 100644 (file)
@@ -45,8 +45,9 @@ static const char RCSid[] = "$Header:";
                            SC->device->type != TYPE_MOD)
 
 struct hd_struct * sd;
+int revalidate_scsidisk(int dev, int maxusage);
 
-Scsi_Disk * rscsi_disks;
+Scsi_Disk * rscsi_disks = NULL;
 static int * sd_sizes;
 static int * sd_blocksizes;
 static int * sd_hardsizes;             /* Hardware sector size */
@@ -62,13 +63,14 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt);
 
 static void sd_init(void);
 static void sd_finish(void);
-static void sd_attach(Scsi_Device *);
+static int sd_attach(Scsi_Device *);
 static int sd_detect(Scsi_Device *);
+static void sd_detach(Scsi_Device *);
 
 struct Scsi_Device_Template sd_template = {NULL, "disk", "sd", TYPE_DISK, 
                                             SCSI_DISK_MAJOR, 0, 0, 0, 1,
                                             sd_detect, sd_init,
-                                            sd_finish, sd_attach, NULL};
+                                            sd_finish, sd_attach, sd_detach};
 
 static int sd_open(struct inode * inode, struct file * filp)
 {
@@ -90,6 +92,8 @@ static int sd_open(struct inode * inode, struct file * filp)
            sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
        };
        rscsi_disks[target].device->access_count++;
+       if (rscsi_disks[target].device->host->hostt->usage_count)
+         (*rscsi_disks[target].device->host->hostt->usage_count)++;
        return 0;
 }
 
@@ -101,6 +105,8 @@ static void sd_release(struct inode * inode, struct file * file)
        target =  DEVICE_NR(MINOR(inode->i_rdev));
 
        rscsi_disks[target].device->access_count--;
+       if (rscsi_disks[target].device->host->hostt->usage_count)
+         (*rscsi_disks[target].device->host->hostt->usage_count)--;
 
        if(rscsi_disks[target].device->removable) {
          if(!rscsi_disks[target].device->access_count)
@@ -147,7 +153,10 @@ static void sd_geninit (void)
        for (i = 0; i < sd_template.dev_max; ++i)
          if(rscsi_disks[i].device) 
            sd[i << 4].nr_sects = rscsi_disks[i].capacity;
+#if 0
+       /* No longer needed - we keep track of this as we attach/detach */
        sd_gendisk.nr_real = sd_template.dev_max;
+#endif
 }
 
 /*
@@ -1048,22 +1057,24 @@ static void sd_init()
        }
 
        /* We do not support attaching loadable devices yet. */
-       if(scsi_loadable_module_flag) return;
+       if(rscsi_disks) return;
 
-       sd_template.dev_max = sd_template.dev_noticed;
+       sd_template.dev_max = sd_template.dev_noticed + SD_EXTRA_DEVS;
 
        rscsi_disks = (Scsi_Disk *) 
-         scsi_init_malloc(sd_template.dev_max * sizeof(Scsi_Disk));
+         scsi_init_malloc(sd_template.dev_max * sizeof(Scsi_Disk), GFP_ATOMIC);
        memset(rscsi_disks, 0, sd_template.dev_max * sizeof(Scsi_Disk));
 
        sd_sizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * 
-                                           sizeof(int));
+                                           sizeof(int), GFP_ATOMIC);
        memset(sd_sizes, 0, (sd_template.dev_max << 4) * sizeof(int));
 
        sd_blocksizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * 
-                                                sizeof(int));
+                                                sizeof(int), GFP_ATOMIC);
+
        sd_hardsizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * 
-                                                sizeof(int));
+                                                  sizeof(struct hd_struct), GFP_ATOMIC);
+
        for(i=0;i<(sd_template.dev_max << 4);i++){
                sd_blocksizes[i] = 1024;
                sd_hardsizes[i] = 512;
@@ -1071,7 +1082,8 @@ static void sd_init()
        blksize_size[MAJOR_NR] = sd_blocksizes;
        hardsect_size[MAJOR_NR] = sd_hardsizes;
        sd = (struct hd_struct *) scsi_init_malloc((sd_template.dev_max << 4) *
-                                                  sizeof(struct hd_struct));
+                                                  sizeof(struct hd_struct),
+                                                  GFP_ATOMIC);
 
 
        sd_gendisk.max_nr = sd_template.dev_max;
@@ -1085,28 +1097,37 @@ static void sd_finish()
 {
         int i;
 
-       for (i = 0; i < sd_template.dev_max; ++i)
-         if (rscsi_disks[i].device) i = sd_init_onedisk(i);
-
        blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 
+       sd_gendisk.next = gendisk_head;
+       gendisk_head = &sd_gendisk;
+
+       for (i = 0; i < sd_template.dev_max; ++i)
+           if (!rscsi_disks[i].capacity && 
+                 rscsi_disks[i].device)
+             {
+               i = sd_init_onedisk(i);
+               if (scsi_loadable_module_flag 
+                   && !rscsi_disks[i].has_part_table) {
+                 sd_sizes[i << 4] = rscsi_disks[i].capacity;
+                 revalidate_scsidisk(i << 4, 0);
+               }
+               rscsi_disks[i].has_part_table = 1;
+             }
+
        /* If our host adapter is capable of scatter-gather, then we increase
           the read-ahead to 16 blocks (32 sectors).  If not, we use
           a two block (4 sector) read ahead. */
-       if(rscsi_disks[0].device->host->sg_tablesize)
+       if(rscsi_disks[0].device && rscsi_disks[0].device->host->sg_tablesize)
          read_ahead[MAJOR_NR] = 120;
        /* 64 sector read-ahead */
        else
          read_ahead[MAJOR_NR] = 4;  /* 4 sector read-ahead */
        
-       sd_gendisk.next = gendisk_head;
-       gendisk_head = &sd_gendisk;
        return;
 }
 
 static int sd_detect(Scsi_Device * SDp){
-  /* We do not support attaching loadable devices yet. */
-  if(scsi_loadable_module_flag) return 0;
   if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0;
 
   printk("Detected scsi disk sd%c at scsi%d, id %d, lun %d\n", 
@@ -1117,17 +1138,17 @@ static int sd_detect(Scsi_Device * SDp){
 
 }
 
-static void sd_attach(Scsi_Device * SDp){
+static int sd_attach(Scsi_Device * SDp){
    Scsi_Disk * dpnt;
    int i;
 
-   /* We do not support attaching loadable devices yet. */
-   if(scsi_loadable_module_flag) return;
-   if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return;
-
-   if(sd_template.nr_dev >= sd_template.dev_max) 
-     panic ("scsi_devices corrupt (sd)");
+   if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0;
 
+   if(sd_template.nr_dev >= sd_template.dev_max) {
+       SDp->attached--;
+       return 1;
+   }
+   
    for(dpnt = rscsi_disks, i=0; i<sd_template.dev_max; i++, dpnt++) 
      if(!dpnt->device) break;
 
@@ -1135,8 +1156,11 @@ static void sd_attach(Scsi_Device * SDp){
 
    SDp->scsi_request_fn = do_sd_request;
    rscsi_disks[i].device = SDp;
+   rscsi_disks[i].has_part_table = 0;
    sd_template.nr_dev++;
-};
+   sd_gendisk.nr_real++;
+   return 0;
+}
 
 #define DEVICE_BUSY rscsi_disks[target].device->busy
 #define USAGE rscsi_disks[target].device->access_count
@@ -1199,3 +1223,40 @@ static int fop_revalidate_scsidisk(dev_t dev){
   return revalidate_scsidisk(dev, 0);
 }
 
+
+static void sd_detach(Scsi_Device * SDp)
+{
+  Scsi_Disk * dpnt;
+  int i;
+  int max_p;
+  int major;
+  int start;
+  
+  for(dpnt = rscsi_disks, i=0; i<sd_template.dev_max; i++, dpnt++) 
+    if(dpnt->device == SDp) {
+
+      /* If we are disconnecting a disk driver, sync and invalidate everything */
+      max_p = sd_gendisk.max_p;
+      start = i << sd_gendisk.minor_shift;
+      major = MAJOR_NR << 8;
+
+      for (i=max_p - 1; i >=0 ; i--) {
+       sync_dev(major | start | i);
+       invalidate_inodes(major | start | i);
+       invalidate_buffers(major | start | i);
+       sd_gendisk.part[start+i].start_sect = 0;
+       sd_gendisk.part[start+i].nr_sects = 0;
+       sd_sizes[start+i] = 0;
+      };
+      
+      dpnt->has_part_table = 0;
+      dpnt->device = NULL;
+      dpnt->capacity = 0;
+      SDp->attached--;
+      sd_template.dev_noticed--;
+      sd_template.nr_dev--;
+      sd_gendisk.nr_real--;
+      return;
+    }
+  return;
+}
index 851d83c309361b164b69db034a7b6604468b6a26..5cdb2e410d9f3b5f7f249583c8ce4125562f6979 100644 (file)
 #include "sg.h"
 
 static void sg_init(void);
-static void sg_attach(Scsi_Device *);
+static int sg_attach(Scsi_Device *);
 static int sg_detect(Scsi_Device *);
+static void sg_detach(Scsi_Device *);
 
 
 struct Scsi_Device_Template sg_template = {NULL, NULL, "sg", 0xff, 
                                             SCSI_GENERIC_MAJOR, 0, 0, 0, 0,
                                             sg_detect, sg_init,
-                                            NULL, sg_attach, NULL};
+                                            NULL, sg_attach, sg_detach};
 
 #ifdef SG_BIG_BUFF
 static char *big_buff;
@@ -334,9 +335,6 @@ static struct file_operations sg_fops = {
 
 
 static int sg_detect(Scsi_Device * SDp){
-  /* We do not support attaching loadable devices yet. */
-  if(scsi_loadable_module_flag) return 0;
-
   ++sg_template.dev_noticed;
   return 1;
 }
@@ -358,33 +356,36 @@ static void sg_init()
      sg_registered++;
    }
 
-   /* We do not support attaching loadable devices yet. */
-   if(scsi_loadable_module_flag) return;
+   /* If we have already been through here, return */
+   if(scsi_generics) return;
+
 #ifdef DEBUG
   printk("sg: Init generic device.\n");
 #endif
 
 #ifdef SG_BIG_BUFF
-  big_buff= (char *) scsi_init_malloc(SG_BIG_BUFF);
+  big_buff= (char *) scsi_init_malloc(SG_BIG_BUFF, GFP_ATOMIC | GFP_DMA);
 #endif
 
    scsi_generics = (struct scsi_generic *) 
-     scsi_init_malloc(sg_template.dev_noticed * sizeof(struct scsi_generic));
-   memset(scsi_generics, 0, sg_template.dev_noticed * sizeof(struct scsi_generic));
+     scsi_init_malloc((sg_template.dev_noticed + SG_EXTRA_DEVS) 
+                     * sizeof(struct scsi_generic), GFP_ATOMIC);
+   memset(scsi_generics, 0, (sg_template.dev_noticed + SG_EXTRA_DEVS)
+         * sizeof(struct scsi_generic));
 
    sg_template.dev_max = sg_template.dev_noticed;
  }
 
-static void sg_attach(Scsi_Device * SDp)
+static int sg_attach(Scsi_Device * SDp)
  {
    struct scsi_generic * gpnt;
    int i;
 
-   /* We do not support attaching loadable devices yet. */
-   if(scsi_loadable_module_flag) return;
-
    if(sg_template.nr_dev >= sg_template.dev_max) 
-     panic ("scsi_devices corrupt (sg)");
+     {
+       SDp->attached--;
+       return 1;
+     }
 
    for(gpnt = scsi_generics, i=0; i<sg_template.dev_max; i++, gpnt++) 
      if(!gpnt->device) break;
@@ -401,4 +402,22 @@ static void sg_attach(Scsi_Device * SDp)
    scsi_generics[i].pending=0;
    scsi_generics[i].timeout=SG_DEFAULT_TIMEOUT;
    sg_template.nr_dev++;
+   return 0;
  };
+
+
+
+static void sg_detach(Scsi_Device * SDp)
+{
+  struct scsi_generic * gpnt;
+  int i;
+  
+  for(gpnt = scsi_generics, i=0; i<sg_template.dev_max; i++, gpnt++) 
+    if(gpnt->device == SDp) {
+      gpnt->device = NULL;
+      SDp->attached--;
+      sg_template.nr_dev--;
+      return;
+    }
+  return;
+}
index 10bf4cd8bcadf2ff2e4c3de7f4e5e609227e21cd..8dcb3b06280bed812c10523c485d4d44f3863866 100644 (file)
 
 static void sr_init(void);
 static void sr_finish(void);
-static void sr_attach(Scsi_Device *);
+static int sr_attach(Scsi_Device *);
 static int sr_detect(Scsi_Device *);
+static void sr_detach(Scsi_Device *);
 
 struct Scsi_Device_Template sr_template = {NULL, "cdrom", "sr", TYPE_ROM, 
                                             SCSI_CDROM_MAJOR, 0, 0, 0, 1,
                                             sr_detect, sr_init,
-                                            sr_finish, sr_attach, NULL};
+                                            sr_finish, sr_attach, sr_detach};
 
 Scsi_CD * scsi_CDs;
 static int * sr_sizes;
@@ -61,6 +62,8 @@ static void sr_release(struct inode * inode, struct file * file)
        sync_dev(inode->i_rdev);
        if(! --scsi_CDs[MINOR(inode->i_rdev)].device->access_count)
          sr_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
+       if (scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)
+         (*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)--;
 }
 
 static struct file_operations sr_fops = 
@@ -413,6 +416,8 @@ static int sr_open(struct inode * inode, struct file * filp)
 
        if(!scsi_CDs[MINOR(inode->i_rdev)].device->access_count++)
          sr_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
+       if (scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)
+         (*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)++;
 
        /* If this device did not have media in the drive at boot time, then
           we would have been unable to get the sector size.  Check to see if
@@ -795,8 +800,6 @@ are any multiple of 512 bytes long.  */
 
 static int sr_detect(Scsi_Device * SDp){
   
-  /* We do not support attaching loadable devices yet. */
-  if(scsi_loadable_module_flag) return 0;
   if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 0;
 
   printk("Detected scsi CD-ROM sr%d at scsi%d, id %d, lun %d\n", 
@@ -806,17 +809,17 @@ static int sr_detect(Scsi_Device * SDp){
         return 1;
 }
 
-static void sr_attach(Scsi_Device * SDp){
+static int sr_attach(Scsi_Device * SDp){
   Scsi_CD * cpnt;
   int i;
   
-  /* We do not support attaching loadable devices yet. */
-  
-  if(scsi_loadable_module_flag) return;
-  if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return;
+  if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 1;
   
   if (sr_template.nr_dev >= sr_template.dev_max)
-    panic ("scsi_devices corrupt (sr)");
+    {
+       SDp->attached--;
+       return 1;
+    }
   
   for(cpnt = scsi_CDs, i=0; i<sr_template.dev_max; i++, cpnt++) 
     if(!cpnt->device) break;
@@ -828,6 +831,7 @@ static void sr_attach(Scsi_Device * SDp){
   sr_template.nr_dev++;
   if(sr_template.nr_dev > sr_template.dev_max)
     panic ("scsi_devices corrupt (sr)");
+  return 0;
 }
      
 
@@ -923,20 +927,20 @@ static void sr_init()
            printk("Unable to get major %d for SCSI-CD\n",MAJOR_NR);
            return;
          }
+         sr_registered++;
        }
 
-       /* We do not support attaching loadable devices yet. */
-       if(scsi_loadable_module_flag) return;
-
-       sr_template.dev_max = sr_template.dev_noticed;
-       scsi_CDs = (Scsi_CD *) scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD));
+       
+       if (scsi_CDs) return;
+       sr_template.dev_max = sr_template.dev_noticed + SR_EXTRA_DEVS;
+       scsi_CDs = (Scsi_CD *) scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD), GFP_ATOMIC);
        memset(scsi_CDs, 0, sr_template.dev_max * sizeof(Scsi_CD));
 
-       sr_sizes = (int *) scsi_init_malloc(sr_template.dev_max * sizeof(int));
+       sr_sizes = (int *) scsi_init_malloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC);
        memset(sr_sizes, 0, sr_template.dev_max * sizeof(int));
 
        sr_blocksizes = (int *) scsi_init_malloc(sr_template.dev_max * 
-                                                sizeof(int));
+                                                sizeof(int), GFP_ATOMIC);
        for(i=0;i<sr_template.dev_max;i++) sr_blocksizes[i] = 2048;
        blksize_size[MAJOR_NR] = sr_blocksizes;
 
@@ -946,26 +950,61 @@ void sr_finish()
 {
   int i;
 
+       blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+       blk_size[MAJOR_NR] = sr_sizes;  
+
        for (i = 0; i < sr_template.nr_dev; ++i)
                {
+                 /* If we have already seen this, then skip it.  Comes up
+                    with loadable modules. */
+                 if (scsi_CDs[i].capacity) continue;
                  get_sectorsize(i);
-                 printk("Scd sectorsize = %d bytes\n", scsi_CDs[i].sector_size);
+                 printk("Scd sectorsize = %d bytes.\n", scsi_CDs[i].sector_size);
                  scsi_CDs[i].use = 1;
                  scsi_CDs[i].ten = 1;
                  scsi_CDs[i].remap = 1;
                  sr_sizes[i] = scsi_CDs[i].capacity;
                }
 
-       blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
-       blk_size[MAJOR_NR] = sr_sizes;  
 
        /* If our host adapter is capable of scatter-gather, then we increase
           the read-ahead to 16 blocks (32 sectors).  If not, we use
           a two block (4 sector) read ahead. */
-       if(scsi_CDs[0].device->host->sg_tablesize)
+       if(scsi_CDs[0].device && scsi_CDs[0].device->host->sg_tablesize)
          read_ahead[MAJOR_NR] = 32;  /* 32 sector read-ahead.  Always removable. */
        else
          read_ahead[MAJOR_NR] = 4;  /* 4 sector read-ahead */
 
        return;
 }      
+
+static void sr_detach(Scsi_Device * SDp)
+{
+  Scsi_CD * cpnt;
+  int i, major;
+  
+  major = MAJOR_NR << 8;
+
+  for(cpnt = scsi_CDs, i=0; i<sg_template.dev_max; i++, cpnt++) 
+    if(cpnt->device == SDp) {
+      /*
+       * Since the cdrom is read-only, no need to sync the device.
+       * We should be kind to our buffer cache, however.
+       */
+      invalidate_inodes(major | i);
+      invalidate_buffers(major | i);
+
+      /*
+       * Reset things back to a sane state so that one can re-load a new
+       * driver (perhaps the same one).
+       */
+      cpnt->device = NULL;
+      cpnt->capacity = 0;
+      SDp->attached--;
+      sr_template.nr_dev--;
+      sr_template.dev_noticed--;
+      sr_sizes[i] = 0;
+      return;
+    }
+  return;
+}
index fc6db910a18827b0875f0cab8a152c261adf695f..6061559b8bbd542f1bbc87f1a12bf58767510268 100644 (file)
@@ -5,13 +5,13 @@
   History:
   Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.
   Contribution and ideas from several people including (in alphabetical
-  order) Klaus Ehrenfried, Wolfgang Denk, Andreas Koppenh"ofer, J"org Weule,
-  and Eric Youngdale.
+  order) Klaus Ehrenfried, Steve Hirsch, Wolfgang Denk, Andreas Koppenh"ofer,
+  J"org Weule, and Eric Youngdale.
 
-  Copyright 1992, 1993, 1994 Kai Makisara
-                email makisara@vtinsx.ins.vtt.fi or Kai.Makisara@vtt.fi
+  Copyright 1992, 1993, 1994, 1995 Kai Makisara
+                email Kai.Makisara@metla.fi
 
-  Last modified: Sun Dec 18 10:15:33 1994 by root@kai.home
+  Last modified: Wed Jan 11 22:02:20 1995 by root@kai.home
 */
 
 #include <linux/fs.h>
@@ -43,6 +43,8 @@
 
 #define ST_TWO_FM 0
 
+#define ST_FAST_MTEOM 0
+
 #define ST_BUFFER_WRITES 1
 
 #define ST_ASYNC_WRITES 1
@@ -86,13 +88,14 @@ static int st_max_buffers = ST_MAX_BUFFERS;
 static Scsi_Tape * scsi_tapes;
 
 static void st_init(void);
-static void st_attach(Scsi_Device *);
+static int st_attach(Scsi_Device *);
 static int st_detect(Scsi_Device *);
+static void st_detach(Scsi_Device *);
 
 struct Scsi_Device_Template st_template = {NULL, "tape", "st", TYPE_TAPE, 
                                             SCSI_TAPE_MAJOR, 0, 0, 0, 0,
                                             st_detect, st_init,
-                                            NULL, st_attach, NULL};
+                                            NULL, st_attach, st_detach};
 
 static int st_int_ioctl(struct inode * inode,struct file * file,
             unsigned int cmd_in, unsigned long arg);
@@ -366,7 +369,6 @@ flush_buffer(struct inode * inode, struct file * filp, int seek_next)
        STp->block_size;
   (STp->buffer)->buffer_bytes = 0;
   (STp->buffer)->read_pointer = 0;
-  STp->drv_block -= backspace;
   result = 0;
   if (!seek_next) {
     if ((STp->eof == ST_FM) && !STp->eof_hit) {
@@ -592,6 +594,9 @@ scsi_tape_open(struct inode * inode, struct file * filp)
 #endif
     }
 
+    if (scsi_tapes[dev].device->host->hostt->usage_count)
+      (*scsi_tapes[dev].device->host->hostt->usage_count)++;
+
     return 0;
 }
 
@@ -671,6 +676,9 @@ scsi_tape_close(struct inode * inode, struct file * filp)
       (STp->buffer)->in_use = 0;
     STp->in_use = 0;
 
+    if (scsi_tapes[dev].device->host->hostt->usage_count)
+      (*scsi_tapes[dev].device->host->hostt->usage_count)--;
+
     return;
 }
 
@@ -1164,14 +1172,15 @@ st_set_options(struct inode * inode, long options)
     STp->do_async_writes  = (options & MT_ST_ASYNC_WRITES) != 0;
     STp->do_read_ahead    = (options & MT_ST_READ_AHEAD) != 0;
     STp->two_fm                  = (options & MT_ST_TWO_FM) != 0;
+    STp->fast_mteom      = (options & MT_ST_FAST_MTEOM) != 0;
 #ifdef DEBUG
     debugging = (options & MT_ST_DEBUGGING) != 0;
     printk(
 "st%d: options: buffer writes: %d, async writes: %d, read ahead: %d\n",
           dev, STp->do_buffer_writes, STp->do_async_writes,
           STp->do_read_ahead);
-    printk("              two FMs: %d, debugging: %d\n", STp->two_fm,
-          debugging);
+    printk("              two FMs: %d, fast mteom: %d debugging: %d\n",
+          STp->two_fm, STp->fast_mteom, debugging);
 #endif
   }
   else if ((options & MT_ST_OPTIONS) == MT_ST_WRITE_THRESHOLD) {
@@ -1398,15 +1407,19 @@ st_int_ioctl(struct inode * inode,struct file * file,
        fileno = blkno = at_sm = 0;
        break; 
      case MTEOM:
-       /* space to the end of tape */
-       ioctl_result = st_int_ioctl(inode, file, MTFSF, 0x3fff);
-       fileno = (STp->mt_status)->mt_fileno ;
-       if (STp->eof == ST_EOD || STp->eof == ST_EOM_OK)
-        return 0;
-       /* The next lines would hide the number of spaced FileMarks
-          That's why I inserted the previous lines. I had no luck
-         with detecting EOM with FSF, so we go now to EOM.
-          Joerg Weule */
+       if (!STp->fast_mteom) {
+        /* space to the end of tape */
+        ioctl_result = st_int_ioctl(inode, file, MTFSF, 0x3fff);
+        fileno = (STp->mt_status)->mt_fileno ;
+        if (STp->eof == ST_EOD || STp->eof == ST_EOM_OK)
+          return 0;
+        /* The next lines would hide the number of spaced FileMarks
+           That's why I inserted the previous lines. I had no luck
+           with detecting EOM with FSF, so we go now to EOM.
+           Joerg Weule */
+       }
+       else
+        fileno = (-1);
        cmd[0] = SPACE;
        cmd[1] = 3;
 #ifdef DEBUG
@@ -1566,7 +1579,7 @@ st_int_ioctl(struct inode * inode,struct file * file,
      else if (cmd_in == MTSETDENSITY)
        STp->density = arg;
      else if (cmd_in == MTEOM) {
-       STp->eof = ST_EOM_OK;
+       STp->eof = ST_EOD;
        STp->eof_hit = 0;
      }
      else if (cmd_in != MTSETBLK && cmd_in != MTNOP) {
@@ -1607,6 +1620,10 @@ st_int_ioctl(struct inode * inode,struct file * file,
        else
         STp->drv_block = (-1);
      }
+     else if (cmd_in == MTEOM) {
+       (STp->mt_status)->mt_fileno = (-1);
+       STp->drv_block = (-1);
+     }
      if (STp->eof == ST_NOEOF &&
         (SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK)
        STp->eof = ST_EOD;
@@ -1699,7 +1716,7 @@ st_ioctl(struct inode * inode,struct file * file,
      }
      if (STp->eof == ST_EOM_OK || STp->eof == ST_EOM_ERROR)
        (STp->mt_status)->mt_gstat |= GMT_EOT(0xffffffff);
-     else if (STp->eof == ST_EOD || STp->eof == ST_EOM_OK)
+     else if (STp->eof == ST_EOD)
        (STp->mt_status)->mt_gstat |= GMT_EOD(0xffffffff);
      if (STp->density == 1)
        (STp->mt_status)->mt_gstat |= GMT_D_800(0xffffffff);
@@ -1823,16 +1840,17 @@ static struct file_operations st_fops = {
    NULL                    /* fsync */
 };
 
-static void st_attach(Scsi_Device * SDp){
+static int st_attach(Scsi_Device * SDp){
    Scsi_Tape * tpnt;
    int i;
 
-   /* We do not support attaching loadable devices yet. */
-   if(scsi_loadable_module_flag) return;
-   if(SDp->type != TYPE_TAPE) return;
+   if(SDp->type != TYPE_TAPE) return 1;
 
    if(st_template.nr_dev >= st_template.dev_max) 
-     panic ("scsi_devices corrupt (st)");
+     {
+       SDp->attached--;
+       return 1;
+     }
 
    for(tpnt = scsi_tapes, i=0; i<st_template.dev_max; i++, tpnt++) 
      if(!tpnt->device) break;
@@ -1840,13 +1858,17 @@ static void st_attach(Scsi_Device * SDp){
    if(i >= st_template.dev_max) panic ("scsi_devices corrupt (st)");
 
    scsi_tapes[i].device = SDp;
+   if (SDp->scsi_level <= 2)
+     scsi_tapes[i].mt_status->mt_type = MT_ISSCSI1;
+   else
+     scsi_tapes[i].mt_status->mt_type = MT_ISSCSI2;
+
    st_template.nr_dev++;
+   return 0;
 };
 
-static int st_detect(Scsi_Device * SDp){
-  
-  /* We do not support attaching loadable devices yet. */
-  if(scsi_loadable_module_flag) return 0;
+static int st_detect(Scsi_Device * SDp)
+{
   if(SDp->type != TYPE_TAPE) return 0;
 
   printk("Detected scsi tape st%d at scsi%d, id %d, lun %d\n", 
@@ -1874,19 +1896,18 @@ static void st_init()
     st_registered++;
   }
 
-  /* We do not support attaching loadable devices yet. */
-  if(scsi_loadable_module_flag) return;
-
-  scsi_tapes = (Scsi_Tape *) scsi_init_malloc(st_template.dev_noticed * 
-                                             sizeof(Scsi_Tape));
-  st_template.dev_max = st_template.dev_noticed;
+  if (scsi_tapes) return;
+  scsi_tapes = (Scsi_Tape *) scsi_init_malloc(
+               (st_template.dev_noticed + ST_EXTRA_DEVS) * 
+                                             sizeof(Scsi_Tape), GFP_ATOMIC);
+  st_template.dev_max = st_template.dev_noticed + ST_EXTRA_DEVS;
 
 #ifdef DEBUG
   printk("st: Buffer size %d bytes, write threshold %d bytes.\n",
         st_buffer_size, st_write_threshold);
 #endif
 
-  for (i=0, SDp = scsi_devices; i < st_template.dev_noticed; ++i) {
+  for (i=0; i < st_template.dev_max; ++i) {
     STp = &(scsi_tapes[i]);
     STp->device = NULL;
     STp->capacity = 0xfffff;
@@ -1901,25 +1922,14 @@ static void st_init()
     STp->do_async_writes = ST_ASYNC_WRITES;
     STp->do_read_ahead = ST_READ_AHEAD;
     STp->two_fm = ST_TWO_FM;
+    STp->fast_mteom = ST_FAST_MTEOM;
     STp->write_threshold = st_write_threshold;
     STp->drv_block = 0;
     STp->moves_after_eof = 1;
     STp->at_sm = 0;
-    STp->mt_status = (struct mtget *) scsi_init_malloc(sizeof(struct mtget));
+    STp->mt_status = (struct mtget *) scsi_init_malloc(sizeof(struct mtget), GFP_ATOMIC);
     /* Initialize status */
     memset((void *) scsi_tapes[i].mt_status, 0, sizeof(struct mtget));
-    for (; SDp; SDp = SDp->next)
-      if (SDp->type == TYPE_TAPE)
-       break;
-    if (!SDp)
-      printk("st%d: ERROR: Not found in scsi chain.\n", i);
-    else {
-      if (SDp->scsi_level <= 2)
-       STp->mt_status->mt_type = MT_ISSCSI1;
-      else
-       STp->mt_status->mt_type = MT_ISSCSI2;
-    }
-    SDp = SDp->next;
   }
 
   /* Allocate the buffers */
@@ -1927,10 +1937,15 @@ static void st_init()
   if (st_nbr_buffers > st_max_buffers)
     st_nbr_buffers = st_max_buffers;
   st_buffers = (ST_buffer **) scsi_init_malloc(st_nbr_buffers * 
-                                              sizeof(ST_buffer *));
+                                              sizeof(ST_buffer *), GFP_ATOMIC);
+  /* FIXME - if we are hitting this because we are loading a tape module
+  as a loadable driver, we should not use kmalloc - it will allocate
+  a 64Kb region in order to buffer about 32Kb.  Try using 31 blocks
+  instead. */
+  
   for (i=0; i < st_nbr_buffers; i++) {
     st_buffers[i] = (ST_buffer *) scsi_init_malloc(sizeof(ST_buffer) - 
-                                                  1 + st_buffer_size);
+                                                  1 + st_buffer_size, GFP_ATOMIC | GFP_DMA);
 #ifdef DEBUG
 /*    printk("st: Buffer address: %p\n", st_buffers[i]); */
 #endif
@@ -1939,3 +1954,19 @@ static void st_init()
   }
   return;
 }
+
+static void st_detach(Scsi_Device * SDp)
+{
+  Scsi_Tape * tpnt;
+  int i;
+  
+  for(tpnt = scsi_tapes, i=0; i<st_template.dev_max; i++, tpnt++) 
+    if(tpnt->device == SDp) {
+      tpnt->device = NULL;
+      SDp->attached--;
+      st_template.nr_dev--;
+      st_template.dev_noticed--;
+      return;
+    }
+  return;
+}
index fcfb3241a24d4fdc0a25786b9ff8640d5746c6f1..e6632159e3b3fb4438bc87802e7964d89a45fb2c 100644 (file)
@@ -38,6 +38,7 @@ typedef struct {
   unsigned char do_async_writes;
   unsigned char do_read_ahead;
   unsigned char two_fm;
+  unsigned char fast_mteom;
   unsigned char density;
   ST_buffer * buffer;
   int block_size;
index 48bbc7adfb0ccda93f1c8ad638c3de8ad20586d0..da4830d90c8248eaf58ad81ee9970d493a0fdc61 100644 (file)
@@ -225,13 +225,13 @@ struct inode {
        struct inode * i_hash_next, * i_hash_prev;
        struct inode * i_bound_to, * i_bound_by;
        struct inode * i_mount;
-       struct socket * i_socket;
        unsigned short i_count;
        unsigned short i_wcount;
        unsigned short i_flags;
        unsigned char i_lock;
        unsigned char i_dirt;
        unsigned char i_pipe;
+       unsigned char i_sock;
        unsigned char i_seek;
        unsigned char i_update;
        union {
@@ -246,6 +246,7 @@ struct inode {
                struct nfs_inode_info nfs_i;
                struct xiafs_inode_info xiafs_i;
                struct sysv_inode_info sysv_i;
+               struct socket socket_i;
                void * generic_ip;
        } u;
 };
index cee9ac02644833751384093c1e667381f4307ffb..f995bd2f9d9ac5e0a6ca62ada58d0c33f471f206 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mtio.h,v 1.13 1994/07/19 19:35:52 root Exp $
+/* $Id: /usr/src/linux-1.1.64/include/linux/mtio.h at Tue Jan 10 21:02:51 1995 by root@kai.home$
  *
  * linux/mtio.h header file for Linux. Written by H. Bergman
  */
@@ -220,5 +220,6 @@ struct      mtpos {
 #define MT_ST_READ_AHEAD       0x4
 #define MT_ST_DEBUGGING                0x8
 #define MT_ST_TWO_FM           0x10
+#define MT_ST_FAST_MTEOM       0x20
 
 #endif /* _LINUX_MTIO_H */
index 9d9b8816883d48afa2d6dd8152cd4f9e67e0c5ff..70710d5427752e4e1207eab1a7b5d9ee818a1033 100644 (file)
@@ -81,8 +81,6 @@ struct socket {
   struct wait_queue    **wait;         /* ptr to place to wait on      */
   struct inode         *inode;
   struct fasync_struct  *fasync_list;  /* Asynchronous wake up list    */
-  struct socket                *nextsock;      /* next on the allocated socks  */
-  struct socket                *prevsock;      /* precious on the allocated socks */
 };
 
 #define SOCK_INODE(S)  ((S)->inode)
index cc6885fd474559d6cfd8d949aea78598b5c366df..3cdfe1e1cc1993d3411a25f4e9b700f3633ff75c 100644 (file)
 
 #define PCI_CLASS_REVISION     0x08    /* High 24 bits are class, low 8
                                           revision */
+#define PCI_REVISION_ID         0x08    /* Revision ID */
+#define PCI_CLASS_PROG          0x09    /* Reg. Level Programming Interface */
+#define PCI_CLASS_DEVICE        0x0a    /* Device class */
+
 #define PCI_CACHE_LINE_SIZE    0x0c    /* 8 bits */
 #define PCI_LATENCY_TIMER      0x0d    /* 8 bits */
 #define PCI_HEADER_TYPE                0x0e    /* 8 bits */
@@ -197,6 +201,9 @@ struct pci_class_type {
 #define PCI_VENDOR_ID_ADAPTEC          0x9004
 #define PCI_DEVICE_ID_ADAPTEC_2940     0x7178
 
+#define PCI_VENDOR_ID_DPT               0x1044   
+#define PCI_DEVICE_ID_DPT               0xa400  
+
 #define PCI_VENDOR_ID_S3               0x5333
 #define PCI_DEVICE_ID_S3_864_1         0x88c0
 #define PCI_DEVICE_ID_S3_864_2         0x88c1
@@ -261,10 +268,11 @@ struct pci_vendor_type {
 };
 
 
-#define PCI_VENDOR_NUM 17
+#define PCI_VENDOR_NUM 18
 #define PCI_VENDOR_TYPE { \
        {PCI_VENDOR_ID_NCR,             "NCR"}, \
        {PCI_VENDOR_ID_ADAPTEC,         "Adaptec"}, \
+       {PCI_VENDOR_ID_DPT,             "DPT"}, \
        {PCI_VENDOR_ID_S3,              "S3 Inc."}, \
        {PCI_VENDOR_ID_OPTI,            "OPTI"}, \
        {PCI_VENDOR_ID_UMC,             "UMC"}, \
@@ -289,13 +297,14 @@ struct pci_device_type {
        char *device_name;
 };
 
-#define PCI_DEVICE_NUM 33
+#define PCI_DEVICE_NUM 34
 #define PCI_DEVICE_TYPE { \
        {PCI_VENDOR_ID_NCR,     PCI_DEVICE_ID_NCR_53C810,       "53c810"}, \
        {PCI_VENDOR_ID_NCR,     PCI_DEVICE_ID_NCR_53C815,       "53c815"}, \
        {PCI_VENDOR_ID_NCR,     PCI_DEVICE_ID_NCR_53C820,       "53c820"}, \
        {PCI_VENDOR_ID_NCR,     PCI_DEVICE_ID_NCR_53C825,       "53c825"}, \
        {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_2940,     "2940"}, \
+       {PCI_VENDOR_ID_DPT,     PCI_DEVICE_ID_DPT,              "SmartCache/Raid"}, \
        {PCI_VENDOR_ID_S3,      PCI_DEVICE_ID_S3_864_1,         "Vision 864-P"}, \
        {PCI_VENDOR_ID_S3,      PCI_DEVICE_ID_S3_864_2,         "Vision 864-P"}, \
        {PCI_VENDOR_ID_S3,      PCI_DEVICE_ID_S3_928,           "Vision 928-P"}, \
@@ -327,6 +336,7 @@ struct pci_device_type {
        {0,0,"UNKNOWN DEVICE.PLEASE FIND OUT AND MAIL POTTER@CAO-VLSI.IBP.FR"} \
 }
 
+
 /* PCI BIOS */
 
 extern int pcibios_present (void);
index fad5d7ff4a43604b43e1e53b330e854407606fa5..e05f1834a17886971a1600798047c8bb69b68b7d 100644 (file)
 /* ignore the rest if you have only one interface board & driver */
 
 #if !(SBPCD_ISSUE-2) /* second interface board: */
-#define CDROM_PORT 0x0370
+#define CDROM_PORT 0x0320
 #define SBPRO     0
 #endif
 #if !(SBPCD_ISSUE-3) /* third interface board: */
-#define CDROM_PORT 0x0330
-#define SBPRO     0
+#define CDROM_PORT 0x0630
+#define SBPRO     1
 #endif
 #if !(SBPCD_ISSUE-4) /* fourth interface board: */
-#define CDROM_PORT 0x0230
-#define SBPRO     1
+#define CDROM_PORT 0x0634
+#define SBPRO     0
 #endif
 
 /*==========================================================================*/
@@ -545,8 +545,7 @@ Read XA Parameter:
 #define CMD1_x08       0x08
 #define CMD2_x08       0x08
 #define CMDT_x08       0x08
-#define CMD2_xD4       0xd4
-#define CMD2_xDA       0xda
+#define CMD2_SETSPEED  0xda
 
 #define CMD0_PATH_CHECK        0x00
 #define CMD1_PATH_CHECK        0x00
@@ -563,6 +562,7 @@ Read XA Parameter:
 #define CMDL_READ      0x02
 #define CMDT_READ      0x28
 #define CMD0_READ_XA   0x03
+#define CMD2_READ_XA   0xd4
 #define CMDL_READ_XA   0x03 /* really ?? */
 #define CMD0_READ_HEAD 0x04
 #define CMD0_SPINUP    0x05
index 06e46a0ca3335293b5a5c1ef76e1e94ad2288b89..452e67c4c0b7fdb1ff28836ee21c6051efce84b4 100644 (file)
@@ -98,7 +98,6 @@ extern void aha274x_setup(char *str, int *ints);
 extern void buslogic_setup(char *str, int *ints);
 extern void scsi_luns_setup(char *str, int *ints);
 extern void sound_setup(char *str, int *ints);
-extern void sock_setup(char *str, int *ints);
 #ifdef CONFIG_SBPCD
 extern void sbpcd_setup(char *str, int *ints);
 #endif CONFIG_SBPCD
index ec00ac6c033acb8fb17905a2564f637168a92814..347081df9efc2b25bc50274e31d16c6a73543fd5 100644 (file)
@@ -57,6 +57,11 @@ extern char * ftape_big_buffer;
 extern void (*do_floppy)(void);
 #endif
 
+#ifdef CONFIG_SCSI
+#include "../drivers/scsi/scsi.h"
+#include "../drivers/scsi/hosts.h"
+#endif
+
 extern int sys_tz;
 extern int request_dma(unsigned int dmanr, char * deviceID);
 extern void free_dma(unsigned int dmanr);
@@ -267,6 +272,15 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
        X(dev_ioctl),
        X(dev_queue_xmit),
        X(dev_base),
+#endif
+#ifdef CONFIG_SCSI
+       /* Supports loadable scsi drivers */
+       X(scsi_register_module),
+       X(scsi_unregister_module),
+       X(scsi_free),
+       X(scsi_malloc),
+       X(scsi_register),
+       X(scsi_unregister),
 #endif
        /* Added to make file system as module */
        X(set_writetime),
index e630ca6a5c0783259e654b7d5716b9ba7479e55c..2e01f21fa0475ddbb5d52ee523d4acc3437d60c3 100644 (file)
@@ -94,7 +94,7 @@ void request_region(unsigned int from, unsigned int num, const char *name)
 
 /*
  * This is for compatibility with older drivers.
- * It can be removed when all driver call the new function.
+ * It can be removed when all drivers call the new function.
  */
 void snarf_region(unsigned int from, unsigned int num)
 {
index e05c691f5cbedfaeb010d79880552e74651944f3..0ebf815f247793d90258e58230dfc9f1eee08c26 100644 (file)
@@ -27,6 +27,8 @@
  *                                     to be allocated when needed, and mr.
  *                                     Uphoff's max is used as max to be
  *                                     allowed to allocate.
+ *             Linus           :       Argh. removed all the socket allocation
+ *                                     altogether: it's in the inode now.
  *
  *
  *             This program is free software; you can redistribute it and/or
@@ -94,45 +96,14 @@ static struct file_operations socket_file_ops = {
        sock_fasync
 };
 
-/*
- *     The lists of sockets
- */
-
-static struct socket *freesockets = NULL;      /* List of free sockets,
-                                                  pick the first */
-static struct socket *usedsockets = NULL;      /* Doubly-linked list of the
-                                                  active sockets */
-
-/*
- *     Used to wait for a socket.
- */
-static struct wait_queue *socket_wait_free = NULL;
 /*
  *     The protocol list. Each protocol is registered in here.
  */
 static struct proto_ops *pops[NPROTO];
-/*      
- *     Maximum number of sockets -- override-able on command-line.
- */
-static int maxnsockets = NSOCKETS;
-/*
- *     Number of sockets allocated
- */
-static int nsockets = 0;
 /*
- *     Statistics counters of the free/used lists
+ *     Statistics counters of the socket lists
  */
 static int sockets_in_use  = 0;
-static int sockets_in_free = 0;
-
-/*      
- *     Overrides default max number of sockets if supplied on command-line.
- */
-void sock_setup(char *str, int *ints)
-{
-       maxnsockets = ints[0] ? ints[1] : NSOCKETS;
-}
-
 
 /*
  *     Support routines. Move socket addresses back and forth across the kernel/user
@@ -219,25 +190,13 @@ static int get_fd(struct inode *inode)
 
 /*
  *     Go from an inode to its socket slot.
+ *
+ * The original socket implementation wasn't very clever, which is
+ * why this exists at all..
  */
-
-struct socket *socki_lookup(struct inode *inode)
+inline struct socket *socki_lookup(struct inode *inode)
 {
-       struct socket *sock;
-
-       if ((sock = inode->i_socket) != NULL) 
-       {
-               if (sock->state != SS_FREE && SOCK_INODE(sock) == inode)
-                       return sock;
-               printk("socket.c: uhhuh. stale inode->i_socket pointer\n");
-       }
-       for (sock = usedsockets; sock != NULL; sock = sock->nextsock)
-               if (sock->state != SS_FREE && SOCK_INODE(sock) == inode) 
-               {
-                       printk("socket.c: uhhuh. Found socket despite no inode->i_socket pointer\n");
-                       return(sock);
-               }
-               return(NULL);
+       return &inode->u.socket_i;
 }
 
 /*
@@ -247,149 +206,51 @@ struct socket *socki_lookup(struct inode *inode)
 static inline struct socket *sockfd_lookup(int fd, struct file **pfile)
 {
        struct file *file;
+       struct inode *inode;
 
        if (fd < 0 || fd >= NR_OPEN || !(file = current->files->fd[fd])) 
-               return(NULL);
+               return NULL;
+
+       inode = file->f_inode;
+       if (!inode || !inode->i_sock)
+               return NULL;
 
        if (pfile) 
                *pfile = file;
 
-       return(socki_lookup(file->f_inode));
+       return socki_lookup(inode);
 }
 
 /*
- *     Allocate a socket. Wait if we are out of sockets.
+ *     Allocate a socket.
  */
-
-static struct socket *sock_alloc(int wait)
+static struct socket *sock_alloc(void)
 {
-       struct socket *sock;
-       int i;
-
-       while (1) 
-       {
-               if (freesockets == NULL)
-               {
-                       /* Lets see if we can allocate some more */
-                       cli();
-                       /* Alloc them from same memory page, if possible.
-                          Nothing SHOULD prevent us from allocing one at
-                          the time.. */
-                       for (i = 0; i < 16 && nsockets < maxnsockets; ++i)
-                       {
-                               sock = (struct socket*)kmalloc(sizeof(struct socket),GFP_KERNEL);
-                               if (sock == NULL) break; /* Ah well.. */
-                               sock->state = SS_FREE;
-                               sock->nextsock = freesockets;
-                               sock->prevsock = NULL;
-                               freesockets = sock;
-                               ++sockets_in_free;
-                               ++nsockets;
-                       }
-                       sti();
-               }
-
-
-               cli();
-               sock = freesockets;
-               if (sock != NULL) /* Freelist, we pick
-                                    the first -- or only */
-               {
-               /*
-                * Move it to the `usedsockets' linked-list
-                * at its FRONT (thus  ->prevsock = NULL)
-                */
-                       freesockets = sock->nextsock;
-                       sock->nextsock = usedsockets;
-                       sock->prevsock = NULL;
-                       /* Is there something in there already ? */
-                       if (usedsockets != NULL)
-                         /* Yes, attach the `previous' pointer */
-                         usedsockets->prevsock = sock;
-                       usedsockets = sock;
-
-                       --sockets_in_free;
-                       ++sockets_in_use;
-                       sti();
-               /*
-                *      Got one..
-                */
-                       sock->state = SS_UNCONNECTED;
-                       sock->flags = 0;
-                       sock->ops = NULL;
-                       sock->data = NULL;
-                       sock->conn = NULL;
-                       sock->iconn = NULL;
-                       sock->fasync_list = NULL;
-               /*
-                * This really shouldn't be necessary, but everything
-                * else depends on inodes, so we grab it.
-                * Sleeps are also done on the i_wait member of this
-                * inode.  The close system call will iput this inode
-                * for us.
-                */
-                       if (!(SOCK_INODE(sock) = get_empty_inode())) 
-                       {
-                               printk("NET: sock_alloc: no more inodes\n");
-                       /*
-                        * Roll-back the linkage
-                        */
-                               cli();
-                               /* Not the last ? */
-                               if (sock->nextsock != NULL)
-                                 sock->nextsock->prevsock = sock->prevsock;
-                               /* Not the first ? */
-                               if (sock->prevsock != NULL)
-                                 sock->prevsock->nextsock = sock->nextsock;
-                               else
-                                 /* It is the first, update the head-handle */
-                                 usedsockets = sock->nextsock;
-                               /* Link it back to the free-list */
-                               sock->nextsock = freesockets;
-                               sock->prevsock = NULL; /* Not used, but .. */
-                               freesockets = sock;
-                               ++sockets_in_free;
-                               --sockets_in_use;
-                               sti();
-                               sock->state = SS_FREE;
-                               return(NULL);
-                       }
-                       SOCK_INODE(sock)->i_mode = S_IFSOCK;
-                       SOCK_INODE(sock)->i_uid = current->euid;
-                       SOCK_INODE(sock)->i_gid = current->egid;
-                       SOCK_INODE(sock)->i_socket = sock;
-
-                       sock->wait = &SOCK_INODE(sock)->i_wait;
-
-                       return(sock);
-               }
-               sti();
-
-               /*
-                * The rest of these are in fact vestigial from the previous
-                * version, which didn't have growing list of sockets.
-                * These may become necessary if there are 2000 (or whatever
-                * the hard limit is set to) sockets already in system,
-                * but then the system itself is quite catatonic.. IMO [mea]
-                */
-
-               /*
-                *      If its a 'now or never request' then return.
-                */
-               if (!wait) 
-                       return(NULL);
-               /*
-                *      Sleep on the socket free'ing queue.
-                */
-               interruptible_sleep_on(&socket_wait_free);
-               /*
-                *      If we have been interrupted then return.
-                */
-               if (current->signal & ~current->blocked) 
-               {
-                       return(NULL);
-               }
-       }
+       struct inode * inode;
+       struct socket * sock;
+
+       inode = get_empty_inode();
+       if (!inode)
+               return NULL;
+
+       inode->i_mode = S_IFSOCK;
+       inode->i_sock = 1;
+       inode->i_uid = current->uid;
+       inode->i_gid = current->gid;
+
+       sock = &inode->u.socket_i;
+       sock->state = SS_UNCONNECTED;
+       sock->flags = 0;
+       sock->ops = NULL;
+       sock->data = NULL;
+       sock->conn = NULL;
+       sock->iconn = NULL;
+       sock->next = NULL;
+       sock->wait = &inode->i_wait;
+       sock->inode = inode;            /* "backlink": we could use pointer arithmetic instead */
+       sock->fasync_list = NULL;
+       sockets_in_use++;
+       return sock;
 }
 
 /*
@@ -407,9 +268,7 @@ static inline void sock_release_peer(struct socket *peer)
 static void sock_release(struct socket *sock)
 {
        int oldstate;
-       struct inode *inode;
        struct socket *peersock, *nextsock;
-       unsigned long flags;
 
        if ((oldstate = sock->state) != SS_UNCONNECTED)
                sock->state = SS_DISCONNECTING;
@@ -434,40 +293,8 @@ static void sock_release(struct socket *sock)
                sock->ops->release(sock, peersock);
        if (peersock)
                sock_release_peer(peersock);
-       inode = SOCK_INODE(sock);
-       /*
-        * Remove this `sock' from the doubly-linked chain.
-        */
-       save_flags(flags);
-       cli();
-       sock->state = SS_FREE;          /* this really releases us */
-       /* Not the last ? */
-       if (sock->nextsock != NULL)
-         sock->nextsock->prevsock = sock->prevsock;
-       /* Not the first ? */
-       if (sock->prevsock != NULL)
-         sock->prevsock->nextsock = sock->nextsock;
-       else
-         /* It is the first, update the head-handle */
-         usedsockets = sock->nextsock;
-       /* Link it back to the free-list */
-       sock->nextsock = freesockets;
-       sock->prevsock = NULL; /* Not really used, but.. */
-       freesockets = sock;
        --sockets_in_use;       /* Bookkeeping.. */
-       ++sockets_in_free;
-       restore_flags(flags);
-       
-       /*
-        *      This will wake anyone waiting for a free socket.
-        */
-       wake_up_interruptible(&socket_wait_free);
-
-       /*
-        *      We need to do this. If sock alloc was called we already have an inode. 
-        */
-        
-       iput(inode);
+       iput(SOCK_INODE(sock));
 }
 
 /*
@@ -802,7 +629,7 @@ static int sock_socket(int family, int type, int protocol)
  *     default.
  */
 
-       if (!(sock = sock_alloc(1))) 
+       if (!(sock = sock_alloc())) 
        {
                printk("NET: sock_socket: no more sockets\n");
                return(-ENOSR); /* Was: EAGAIN, but we are out of
@@ -975,7 +802,7 @@ static int sock_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrl
                return(-EINVAL);
        }
 
-       if (!(newsock = sock_alloc(0))) 
+       if (!(newsock = sock_alloc())) 
        {
                printk("NET: sock_accept: no more sockets\n");
                return(-ENOSR); /* Was: EAGAIN, but we are out of system
@@ -1547,10 +1374,7 @@ void sock_init(void)
 
 int socket_get_info(char *buffer, char **start, off_t offset, int length)
 {
-       int len = sprintf(buffer,
-                         "sockets: used %d free %d alloced %d highlimit %d\n",
-                         sockets_in_use, sockets_in_free,
-                         nsockets, maxnsockets);
+       int len = sprintf(buffer, "sockets: used %d\n", sockets_in_use);
        if (offset >= len)
        {
                *start = buffer;
index 36cd8b1c6c10244a525fc5938d687f56d0eac7a1..fed2372c6c2be4225e99dfb55026601a569bc86c 100644 (file)
@@ -49,7 +49,7 @@ int unix_get_info(char *buffer, char **start, off_t offset, int length)
        
        len += sprintf(buffer, "Num RefCount Protocol Flags    Type St Path\n");
 
-       for(i = 0; i < NSOCKETS; i++) 
+       for(i = 0; i < NSOCKETS_UNIX; i++) 
        {
                save_flags(flags);
                cli();