diff -u --recursive --new-file v1.1.80/linux/CREDITS linux/CREDITS
--- v1.1.80/linux/CREDITS	Fri Jan 13 10:12:21 1995
+++ linux/CREDITS	Thu Jan 12 18:34:15 1995
@@ -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
diff -u --recursive --new-file v1.1.80/linux/Makefile linux/Makefile
--- v1.1.80/linux/Makefile	Fri Jan 13 10:12:21 1995
+++ linux/Makefile	Fri Jan 13 12:54:46 1995
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 80
+SUBLEVEL = 81
 
 ARCH = i386
 
diff -u --recursive --new-file v1.1.80/linux/arch/i386/config.in linux/arch/i386/config.in
--- v1.1.80/linux/arch/i386/config.in	Fri Jan 13 10:12:22 1995
+++ linux/arch/i386/config.in	Fri Jan 13 07:52:15 1995
@@ -73,6 +73,7 @@
 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 '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
 
diff -u --recursive --new-file v1.1.80/linux/drivers/block/README.ide linux/drivers/block/README.ide
--- v1.1.80/linux/drivers/block/README.ide	Mon Jan  9 07:22:00 1995
+++ linux/drivers/block/README.ide	Fri Jan 13 09:24:17 1995
@@ -81,13 +81,13 @@
 
 	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.
diff -u --recursive --new-file v1.1.80/linux/drivers/block/README.sbpcd linux/drivers/block/README.sbpcd
--- v1.1.80/linux/drivers/block/README.sbpcd	Mon Jan  9 07:22:00 1995
+++ linux/drivers/block/README.sbpcd	Fri Jan 13 09:02:32 1995
@@ -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 @@
             (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 @@
 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 @@
    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 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 @@
           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 @@
       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 @@
 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 @@
 }
 /*===================== 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
  * 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 @@
 /*
  * 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 @@
   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++;
     }
diff -u --recursive --new-file v1.1.80/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
--- v1.1.80/linux/drivers/block/ide-cd.c	Mon Jan  9 07:22:01 1995
+++ linux/drivers/block/ide-cd.c	Fri Jan 13 09:24:17 1995
@@ -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
@@ -17,15 +17,22 @@
  *                       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 {
   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];
 
 
 
@@ -119,6 +149,34 @@
  * 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 @@
   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 @@
 
           /* 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 @@
       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 @@
  * Block read functions.
  */
 
-static int cdrom_start_read (ide_dev_t *dev, unsigned int block);
+/*
+ * 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_buffer_sectors (ide_dev_t *dev, unsigned long sector,
+                                  int sectors_to_transfer)
+{
+  struct cdrom_info *info = &cdrom_info[dev->hwif][dev->select.b.drive];
+
+  /* Number of sectors to read into the buffer. */
+  int sectors_to_buffer = MIN (sectors_to_transfer,
+                               (SECTOR_BUFFER_SIZE >> SECTOR_BITS));
+
+  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)
+    {
+      info->sector_buffer = (char *) kmalloc (SECTOR_BUFFER_SIZE, GFP_ATOMIC);
+
+      /* 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;
+    }
+}
 
 
 /*
- * Interrupt routine to read the final status from a 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 void cdrom_read_intr_2 (ide_dev_t *dev)
+static inline
+int cdrom_read_check_ireason (ide_dev_t *dev, int len, int ireason)
 {
-  int stat;
-  struct request *rq = ide_cur_rq[dev->hwif];
-
-  stat = GET_STAT (dev->hwif);
+  ireason &= 3;
+  if (ireason == 2) return 0;
 
-  if (OK_STAT (stat, 0, BAD_STAT))
+  if (ireason == 0)
     {
-      if (rq->current_nr_sectors <= 0)
-        {
-          end_request (1, dev->hwif);
-        }
+      /* 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);
 
-      if (rq->current_nr_sectors > 0)
+      /* 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,35 +419,176 @@
  */
 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;
+
+      /* 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);
 
-  rq->current_nr_sectors -= BLOCKS_PER_FRAME;
-  rq->nr_sectors -= BLOCKS_PER_FRAME;
-  rq->sector += BLOCKS_PER_FRAME;
-  rq->buffer += CD_FRAMESIZE;
+      /* 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;
+            }
+        }
+    }
 
-  /* Wait for another interrupt with the final status. */
-  ide_handler[dev->hwif] = cdrom_read_intr_2;
+  /* 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.
  * However, for drq_interrupt devices, it is called from an interrupt
@@ -343,10 +599,51 @@
   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 @@
       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 @@
 {
   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 (cdrom_start_packet_command (dev, CD_FRAMESIZE))
+  if (rq->current_nr_sectors > (rq->bh->b_size >> SECTOR_BITS))
+    rq->current_nr_sectors = rq->bh->b_size;
+
+  /* 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 @@
 }
 
 
+
 
 /****************************************************************************
  * Execute all other packet commands.
@@ -429,13 +735,13 @@
   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 @@
   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 @@
 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 @@
   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 @@
         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 @@
   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.
diff -u --recursive --new-file v1.1.80/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v1.1.80/linux/drivers/block/ide.c	Wed Jan 11 21:14:26 1995
+++ linux/drivers/block/ide.c	Fri Jan 13 09:24:17 1995
@@ -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)
  */
 
 /*
@@ -92,6 +92,10 @@
  *			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 @@
 	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 @@
 	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 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 @@
 	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 @@
 #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 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 @@
 #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 @@
 			dev->present = 0;
 		}
 	}
-	return 1;	/* drive present */
+	return 1;	/* drive was found */
 }
 
 static void probe_for_drives (byte hwif)
@@ -1877,15 +1899,15 @@
 		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);
 	}
diff -u --recursive --new-file v1.1.80/linux/drivers/block/sbpcd.c linux/drivers/block/sbpcd.c
--- v1.1.80/linux/drivers/block/sbpcd.c	Wed Jan 11 21:14:26 1995
+++ linux/drivers/block/sbpcd.c	Fri Jan 13 09:02:32 1995
@@ -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. 
@@ -169,6 +169,13 @@
  *       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
@@ -209,7 +216,9 @@
  *
  */
 
-#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>
@@ -244,13 +253,13 @@
 
 #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!) */
@@ -272,6 +281,8 @@
 #define PRINTK_BUG 0
 #define TEST_STI 0
 
+#define DISTRIBUTION 1
+
 #if 0
 #define INLINE
 #else
@@ -329,7 +340,8 @@
  * 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 @@
   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 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 @@
  * (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 @@
                           (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 @@
 #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 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 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 @@
 
 #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 @@
 #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 @@
 	  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 @@
 	  (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 @@
 	  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 @@
   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 @@
   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 @@
 		       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 @@
 		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 @@
     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 DO_SBPCD_REQUEST(void)
 {
   u_int block;
-  int dev;
   u_int nsect;
   int i, status_tries, data_tries;
   
@@ -3482,13 +3529,13 @@
   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 @@
       }
 #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 @@
   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 @@
 {
   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 @@
   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 @@
   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 @@
 	    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 @@
   sbpcd_release,          /* release */
   NULL,                   /* fsync */
   NULL,                   /* fasync */
-  check_media_change,     /* media_change */
+  sbpcd_chk_disk_change,     /* media_change */
   NULL                    /* revalidate */
 };
 /*==========================================================================*/
@@ -4080,24 +4130,24 @@
       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 @@
 
   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 @@
   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 @@
  * 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 -u --recursive --new-file v1.1.80/linux/drivers/block/sbpcd2.c linux/drivers/block/sbpcd2.c
--- v1.1.80/linux/drivers/block/sbpcd2.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/block/sbpcd2.c	Fri Jan 13 09:02:32 1995
@@ -0,0 +1,5 @@
+/*
+ * duplication of sbpcd.c for multiple interfaces
+ */
+#define SBPCD_ISSUE 2
+#include "sbpcd.c"
diff -u --recursive --new-file v1.1.80/linux/drivers/block/sbpcd3.c linux/drivers/block/sbpcd3.c
--- v1.1.80/linux/drivers/block/sbpcd3.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/block/sbpcd3.c	Fri Jan 13 09:02:32 1995
@@ -0,0 +1,5 @@
+/*
+ * duplication of sbpcd.c for multiple interfaces
+ */
+#define SBPCD_ISSUE 3
+#include "sbpcd.c"
diff -u --recursive --new-file v1.1.80/linux/drivers/block/sbpcd4.c linux/drivers/block/sbpcd4.c
--- v1.1.80/linux/drivers/block/sbpcd4.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/block/sbpcd4.c	Fri Jan 13 09:02:32 1995
@@ -0,0 +1,5 @@
+/*
+ * duplication of sbpcd.c for multiple interfaces
+ */
+#define SBPCD_ISSUE 4
+#include "sbpcd.c"
diff -u --recursive --new-file v1.1.80/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c
--- v1.1.80/linux/drivers/net/arcnet.c	Fri Jan 13 10:12:23 1995
+++ linux/drivers/net/arcnet.c	Fri Jan 13 10:15:28 1995
@@ -99,11 +99,12 @@
 #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>
diff -u --recursive --new-file v1.1.80/linux/drivers/scsi/ChangeLog linux/drivers/scsi/ChangeLog
--- v1.1.80/linux/drivers/scsi/ChangeLog	Mon Dec 12 20:35:51 1994
+++ linux/drivers/scsi/ChangeLog	Fri Jan 13 07:56:34 1995
@@ -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.
diff -u --recursive --new-file v1.1.80/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v1.1.80/linux/drivers/scsi/Makefile	Wed Jan 11 21:14:27 1995
+++ linux/drivers/scsi/Makefile	Fri Jan 13 08:03:53 1995
@@ -25,6 +25,7 @@
 
 SCSI_OBJS =
 SCSI_SRCS =
+SCSI_MODULE_OBJS =
 
 ifdef CONFIG_SCSI
 
@@ -61,9 +62,11 @@
 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_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_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 @@
 	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
 
@@ -188,8 +204,6 @@
 dep:
 
 endif
-
-modules:
 
 #
 # include a dependency file if one exists
diff -u --recursive --new-file v1.1.80/linux/drivers/scsi/README.st linux/drivers/scsi/README.st
--- v1.1.80/linux/drivers/scsi/README.st	Mon Dec 19 17:33:44 1994
+++ linux/drivers/scsi/README.st	Fri Jan 13 09:08:37 1995
@@ -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 @@
            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
@@ -141,6 +142,12 @@
 
 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
diff -u --recursive --new-file v1.1.80/linux/drivers/scsi/eata_dma.c linux/drivers/scsi/eata_dma.c
--- v1.1.80/linux/drivers/scsi/eata_dma.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/eata_dma.c	Fri Jan 13 07:52:52 1995
@@ -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 -u --recursive --new-file v1.1.80/linux/drivers/scsi/eata_dma.h linux/drivers/scsi/eata_dma.h
--- v1.1.80/linux/drivers/scsi/eata_dma.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/eata_dma.h	Fri Jan 13 07:52:52 1995
@@ -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 */
diff -u --recursive --new-file v1.1.80/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v1.1.80/linux/drivers/scsi/hosts.c	Tue Dec 20 10:23:14 1994
+++ linux/drivers/scsi/hosts.c	Fri Jan 13 07:56:34 1995
@@ -47,6 +47,10 @@
 #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 @@
 #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_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 @@
 		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 @@
 
 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 @@
 	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 @@
 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 @@
 		 * "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 @@
 	scsi_register_device(&sg_template);
 #endif
 
-	max_scsi_hosts = count;
+	max_scsi_hosts = next_scsi_host;
 	return 0;
 }
 
diff -u --recursive --new-file v1.1.80/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h
--- v1.1.80/linux/drivers/scsi/hosts.h	Tue Dec 20 10:23:14 1994
+++ linux/drivers/scsi/hosts.h	Fri Jan 13 07:56:34 1995
@@ -292,9 +292,12 @@
    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 @@
   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 *);
 };
 
@@ -327,5 +330,27 @@
 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
diff -u --recursive --new-file v1.1.80/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v1.1.80/linux/drivers/scsi/scsi.c	Sun Jan  1 15:44:03 1995
+++ linux/drivers/scsi/scsi.c	Fri Jan 13 07:56:34 1995
@@ -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 @@
 	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 @@
  *	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 @@
   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 @@
 		       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 @@
 		       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 @@
 				 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 @@
 		    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 @@
   /* 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 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 @@
   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 @@
   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 @@
 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_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 @@
 	struct Scsi_Host * shpnt;
 	struct Scsi_Device_Template * sdtpnt;
 	Scsi_Cmnd * SCpnt;
+	int i;
 #ifdef FOO_ON_YOU
 	return;
 #endif	
@@ -1945,10 +2006,11 @@
 	  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 @@
 	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 @@
 	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 @@
 	  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 @@
   }
   return;
 }
-#endif
 
 #ifdef DEBUG_TIMEOUT
 static void 
@@ -2424,5 +2495,3 @@
       }
 }
 #endif
-
-
diff -u --recursive --new-file v1.1.80/linux/drivers/scsi/scsi_module.c linux/drivers/scsi/scsi_module.c
--- v1.1.80/linux/drivers/scsi/scsi_module.c	Mon Jan  9 07:22:07 1995
+++ linux/drivers/scsi/scsi_module.c	Fri Jan 13 07:56:34 1995
@@ -30,7 +30,7 @@
  */
 
 #include <linux/module.h>
-#include "../../tools/version.h"
+#include <linux/version.h>
 
 char kernel_version[] = UTS_RELEASE;
 
diff -u --recursive --new-file v1.1.80/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v1.1.80/linux/drivers/scsi/sd.c	Mon Jan  9 07:22:07 1995
+++ linux/drivers/scsi/sd.c	Fri Jan 13 07:56:34 1995
@@ -45,8 +45,9 @@
 			    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 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 @@
 	    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 @@
 	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 @@
 	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 @@
 	}
 
 	/* 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 @@
 	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 @@
 {
         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 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 @@
 
    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 @@
   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;
+}
diff -u --recursive --new-file v1.1.80/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- v1.1.80/linux/drivers/scsi/sg.c	Mon Jan  9 07:22:07 1995
+++ linux/drivers/scsi/sg.c	Fri Jan 13 07:56:34 1995
@@ -26,14 +26,15 @@
 #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 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 @@
      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 @@
    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;
+}
diff -u --recursive --new-file v1.1.80/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v1.1.80/linux/drivers/scsi/sr.c	Wed Jan 11 21:14:27 1995
+++ linux/drivers/scsi/sr.c	Fri Jan 13 07:56:34 1995
@@ -35,13 +35,14 @@
 
 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 @@
 	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 @@
 
 	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 @@
 
 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 @@
 	 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 @@
   sr_template.nr_dev++;
   if(sr_template.nr_dev > sr_template.dev_max)
     panic ("scsi_devices corrupt (sr)");
+  return 0;
 }
      
 
@@ -923,20 +927,20 @@
 	    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 @@
 {
   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;
+}
diff -u --recursive --new-file v1.1.80/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v1.1.80/linux/drivers/scsi/st.c	Sun Jan  1 15:44:03 1995
+++ linux/drivers/scsi/st.c	Fri Jan 13 09:08:37 1995
@@ -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 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 @@
 	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 @@
 #endif
     }
 
+    if (scsi_tapes[dev].device->host->hostt->usage_count)
+      (*scsi_tapes[dev].device->host->hostt->usage_count)++;
+
     return 0;
 }
 
@@ -671,6 +676,9 @@
       (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 @@
     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 @@
        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 @@
      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 @@
        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 @@
      }
      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 @@
    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 @@
    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 @@
     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 @@
     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,15 +1937,36 @@
   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
     st_buffers[i]->in_use = 0;
     st_buffers[i]->writing = 0;
   }
+  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;
 }
diff -u --recursive --new-file v1.1.80/linux/drivers/scsi/st.h linux/drivers/scsi/st.h
--- v1.1.80/linux/drivers/scsi/st.h	Wed Nov 30 22:01:07 1994
+++ linux/drivers/scsi/st.h	Fri Jan 13 09:08:37 1995
@@ -38,6 +38,7 @@
   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;
diff -u --recursive --new-file v1.1.80/linux/include/linux/fs.h linux/include/linux/fs.h
--- v1.1.80/linux/include/linux/fs.h	Thu Dec 22 06:57:29 1994
+++ linux/include/linux/fs.h	Fri Jan 13 13:35:12 1995
@@ -225,13 +225,13 @@
 	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 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;
 };
diff -u --recursive --new-file v1.1.80/linux/include/linux/mtio.h linux/include/linux/mtio.h
--- v1.1.80/linux/include/linux/mtio.h	Thu Nov  3 16:44:04 1994
+++ linux/include/linux/mtio.h	Fri Jan 13 09:08:37 1995
@@ -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 @@
 #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 */
diff -u --recursive --new-file v1.1.80/linux/include/linux/net.h linux/include/linux/net.h
--- v1.1.80/linux/include/linux/net.h	Fri Jan 13 10:12:23 1995
+++ linux/include/linux/net.h	Fri Jan 13 12:54:25 1995
@@ -81,8 +81,6 @@
   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)
diff -u --recursive --new-file v1.1.80/linux/include/linux/pci.h linux/include/linux/pci.h
--- v1.1.80/linux/include/linux/pci.h	Mon Jan  9 11:24:24 1995
+++ linux/include/linux/pci.h	Fri Jan 13 07:51:25 1995
@@ -72,6 +72,10 @@
 
 #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 @@
 #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 @@
 };
 
 
-#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 @@
 	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"}, \
@@ -326,6 +335,7 @@
 	{PCI_VENDOR_ID_CMD,	PCI_DEVICE_ID_CMD_640,		"640A"}, \
 	{0,0,"UNKNOWN DEVICE.PLEASE FIND OUT AND MAIL POTTER@CAO-VLSI.IBP.FR"} \
 }
+
 
 /* PCI BIOS */
 
diff -u --recursive --new-file v1.1.80/linux/include/linux/sbpcd.h linux/include/linux/sbpcd.h
--- v1.1.80/linux/include/linux/sbpcd.h	Mon Jan  9 07:22:11 1995
+++ linux/include/linux/sbpcd.h	Fri Jan 13 09:02:32 1995
@@ -59,16 +59,16 @@
 /* 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 @@
 #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 @@
 #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
diff -u --recursive --new-file v1.1.80/linux/init/main.c linux/init/main.c
--- v1.1.80/linux/init/main.c	Fri Jan 13 10:12:23 1995
+++ linux/init/main.c	Fri Jan 13 12:54:26 1995
@@ -98,7 +98,6 @@
 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
diff -u --recursive --new-file v1.1.80/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v1.1.80/linux/kernel/ksyms.c	Fri Jan 13 10:12:24 1995
+++ linux/kernel/ksyms.c	Fri Jan 13 12:54:26 1995
@@ -57,6 +57,11 @@
 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 @@
 	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),
diff -u --recursive --new-file v1.1.80/linux/kernel/resource.c linux/kernel/resource.c
--- v1.1.80/linux/kernel/resource.c	Fri Jan 13 10:12:24 1995
+++ linux/kernel/resource.c	Fri Jan 13 09:20:31 1995
@@ -94,7 +94,7 @@
 
 /*
  * 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)
 {
diff -u --recursive --new-file v1.1.80/linux/net/socket.c linux/net/socket.c
--- v1.1.80/linux/net/socket.c	Fri Jan 13 10:12:24 1995
+++ linux/net/socket.c	Fri Jan 13 13:34:05 1995
@@ -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
@@ -95,44 +97,13 @@
 };
 
 /*
- *	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 @@
 
 /*
  *	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 @@
 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 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 @@
 		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 @@
  *	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 @@
 		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 @@
 
 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;
diff -u --recursive --new-file v1.1.80/linux/net/unix/proc.c linux/net/unix/proc.c
--- v1.1.80/linux/net/unix/proc.c	Mon May 23 08:17:54 1994
+++ linux/net/unix/proc.c	Thu Jan 12 18:30:51 1995
@@ -49,7 +49,7 @@
 	
   	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();
