diff -u -r linux.clean/Documentation/Configure.help linux.new2/Documentation/Configure.help
--- linux.clean/Documentation/Configure.help	Wed Jul 28 18:24:57 1999
+++ linux.new2/Documentation/Configure.help	Sun Sep  5 09:08:18 1999
@@ -3908,6 +3908,25 @@
   Documentation/scsi.txt. The module will be called sg.o. If unsure,
   say N.
 
+Use new queueing code for SCSI
+CONFIG_SCSI_NEW_QUEUES
+  The SCSI code is getting a complete refit of the queueing code with
+  brand new code that should solve a number of outstanding problems.
+  This is optional at the moment mainly because it is new and it might
+  not be working correctly in all cases.   To use the old queueing code
+  turn this off.  At some point in the future, the old code will be removed
+  from the kernel.   Comments/questions/problems to linux-scsi mailing
+  list please.   See http://www.andante.org/scsi_queue.html for more uptodate
+  information.
+
+Debug new queueing code for SCSI
+CONFIG_SCSI_DEBUG_QUEUES
+  This option turns on a lot of additional consistency checking for the new
+  queueing code.   This will adversely affect performance, but it is likely
+  that bugs will be caught sooner if this is turned on.   This will typically
+  cause the kernel to panic if an error is detected, but it would have probably
+  crashed if the panic weren't there.
+
 Probe all LUNs on each SCSI device
 CONFIG_SCSI_MULTI_LUN
   If you have a SCSI device that supports more than one LUN (Logical
diff -u -r linux.clean/drivers/ap1000/ap.c linux.new2/drivers/ap1000/ap.c
--- linux.clean/drivers/ap1000/ap.c	Sat May 15 18:05:35 1999
+++ linux.new2/drivers/ap1000/ap.c	Wed Jul 28 19:06:19 1999
@@ -53,7 +53,7 @@
 	MOD_DEC_USE_COUNT;
 }
 
-static void ap_request(void)
+static void ap_request(request_queue_t * q)
 {
   struct cap_request creq;
   unsigned int minor;
@@ -160,7 +160,7 @@
 #endif
   end_request(1);
   request_count--;
-  ap_request();
+  ap_request(NULL);
 }
 
 
@@ -271,7 +271,7 @@
     return -1;
   }
   printk("ap_init: register dev %d\n", MAJOR_NR);
-  blk_dev[MAJOR_NR].request_fn = &ap_request;
+  blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &ap_request);
 
   for (i=0;i<NUM_APDEVS;i++) {
     ap_blocksizes[i] = AP_BLOCK_SIZE;
@@ -307,7 +307,7 @@
 		invalidate_buffers(MKDEV(MAJOR_NR, i));
 
 	unregister_blkdev( MAJOR_NR, "apblock" );
-	blk_dev[MAJOR_NR].request_fn = 0;
+	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
 }
 
 #endif  /* MODULE */
diff -u -r linux.clean/drivers/ap1000/ddv.c linux.new2/drivers/ap1000/ddv.c
--- linux.clean/drivers/ap1000/ddv.c	Sat May 15 18:05:35 1999
+++ linux.new2/drivers/ap1000/ddv.c	Wed Jul 28 19:06:19 1999
@@ -620,7 +620,7 @@
 }
 
 
-static void ddv_request(void)
+static void ddv_request(request_queue_t * q)
 {
 	cli();
 	ddv_request1();
@@ -932,7 +932,7 @@
 	}
 
 	printk("ddv_init: register dev %d\n", MAJOR_NR);
-	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
 	read_ahead[MAJOR_NR] = DDV_READ_AHEAD;
 	
 	bif_add_debug_key('d',ddv_status,"DDV status");
@@ -1016,7 +1016,7 @@
 	if (*gdp)
 		*gdp = (*gdp)->next;
 	free_irq(APOPT0_IRQ, NULL);
-	blk_dev[MAJOR_NR].request_fn = 0;
+	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
 }
 
 #endif  /* MODULE */
diff -u -r linux.clean/drivers/block/acsi.c linux.new2/drivers/block/acsi.c
--- linux.clean/drivers/block/acsi.c	Sun May 16 02:43:04 1999
+++ linux.new2/drivers/block/acsi.c	Wed Jul 28 19:06:19 1999
@@ -369,7 +369,7 @@
 static void copy_to_acsibuffer( void );
 static void copy_from_acsibuffer( void );
 static void do_end_requests( void );
-static void do_acsi_request( void );
+static void do_acsi_request( request_queue_t * );
 static void redo_acsi_request( void );
 static int acsi_ioctl( struct inode *inode, struct file *file, unsigned int
                        cmd, unsigned long arg );
@@ -947,7 +947,7 @@
  *
  ***********************************************************************/
 
-static void do_acsi_request( void )
+static void do_acsi_request( request_queue_t * q )
 
 {
 	stdma_lock( acsi_interrupt, NULL );
@@ -1817,7 +1817,7 @@
 	phys_acsi_buffer = VTOP( acsi_buffer );
 	STramMask = ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000 : 0xff000000;
 	
-	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
 	read_ahead[MAJOR_NR] = 8;		/* 8 sector (4kB) read-ahead */
 	acsi_gendisk.next = gendisk_head;
 	gendisk_head = &acsi_gendisk;
@@ -1847,7 +1847,7 @@
 	struct gendisk ** gdp;
 
 	del_timer( &acsi_timer );
-	blk_dev[MAJOR_NR].request_fn = 0;
+	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
 	atari_stram_free( acsi_buffer );
 
 	if (unregister_blkdev( MAJOR_NR, "ad" ) != 0)
diff -u -r linux.clean/drivers/block/amiflop.c linux.new2/drivers/block/amiflop.c
--- linux.clean/drivers/block/amiflop.c	Wed Jul 28 18:24:12 1999
+++ linux.new2/drivers/block/amiflop.c	Wed Jul 28 19:06:19 1999
@@ -1473,7 +1473,7 @@
 	goto repeat;
 }
 
-static void do_fd_request(void)
+static void do_fd_request(request_queue_t * q)
 {
 	redo_fd_request();
 }
@@ -1855,7 +1855,7 @@
   post_write_timer.data = 0;
   post_write_timer.function = post_write;
   
-  blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+  blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
   blksize_size[MAJOR_NR] = floppy_blocksizes;
   blk_size[MAJOR_NR] = floppy_sizes;
 
@@ -1897,7 +1897,7 @@
 amiga_chip_free(raw_buf);
 blk_size[MAJOR_NR] = NULL;
 blksize_size[MAJOR_NR] = NULL;
-blk_dev[MAJOR_NR].request_fn = NULL;
+blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
 unregister_blkdev(MAJOR_NR, "fd");
 }
 #endif
diff -u -r linux.clean/drivers/block/ataflop.c linux.new2/drivers/block/ataflop.c
--- linux.clean/drivers/block/ataflop.c	Wed Jul 28 18:24:12 1999
+++ linux.new2/drivers/block/ataflop.c	Wed Jul 28 19:06:19 1999
@@ -1541,7 +1541,7 @@
 }
 
 
-void do_fd_request(void)
+void do_fd_request(request_queue_t * q)
 {
  	unsigned long flags;
 
@@ -2063,7 +2063,7 @@
 
 	blk_size[MAJOR_NR] = floppy_sizes;
 	blksize_size[MAJOR_NR] = floppy_blocksizes;
-	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
 
 	printk(KERN_INFO "Atari floppy driver: max. %cD, %strack buffering\n",
 	       DriveType == 0 ? 'D' : DriveType == 1 ? 'H' : 'E',
@@ -2115,7 +2115,7 @@
 {
 	unregister_blkdev(MAJOR_NR, "fd");
 
-	blk_dev[MAJOR_NR].request_fn = 0;
+	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
 	timer_active &= ~(1 << FLOPPY_TIMER);
 	timer_table[FLOPPY_TIMER].fn = 0;
 	atari_stram_free( DMABuffer );
diff -u -r linux.clean/drivers/block/cpqarray.c linux.new2/drivers/block/cpqarray.c
--- linux.clean/drivers/block/cpqarray.c	Wed Jul 28 18:24:12 1999
+++ linux.new2/drivers/block/cpqarray.c	Wed Jul 28 19:06:19 1999
@@ -138,14 +138,14 @@
  */
 #define DO_IDA_REQUEST(x) { do_ida_request(x); }
 
-static void do_ida_request0(void) DO_IDA_REQUEST(0);
-static void do_ida_request1(void) DO_IDA_REQUEST(1);
-static void do_ida_request2(void) DO_IDA_REQUEST(2);
-static void do_ida_request3(void) DO_IDA_REQUEST(3);
-static void do_ida_request4(void) DO_IDA_REQUEST(4);
-static void do_ida_request5(void) DO_IDA_REQUEST(5);
-static void do_ida_request6(void) DO_IDA_REQUEST(6);
-static void do_ida_request7(void) DO_IDA_REQUEST(7);
+static void do_ida_request0(request_queue_t * q) DO_IDA_REQUEST(0);
+static void do_ida_request1(request_queue_t * q) DO_IDA_REQUEST(1);
+static void do_ida_request2(request_queue_t * q) DO_IDA_REQUEST(2);
+static void do_ida_request3(request_queue_t * q) DO_IDA_REQUEST(3);
+static void do_ida_request4(request_queue_t * q) DO_IDA_REQUEST(4);
+static void do_ida_request5(request_queue_t * q) DO_IDA_REQUEST(5);
+static void do_ida_request6(request_queue_t * q) DO_IDA_REQUEST(6);
+static void do_ida_request7(request_queue_t * q) DO_IDA_REQUEST(7);
 
 static void start_io(ctlr_info_t *h);
 
@@ -372,7 +372,7 @@
  */
 void cpqarray_init(void)
 {
-	void (*request_fns[MAX_CTLR])(void) = {
+	void (*request_fns[MAX_CTLR])(request_queue_t *) = {
 		do_ida_request0, do_ida_request1,
 		do_ida_request2, do_ida_request3,
 		do_ida_request4, do_ida_request5,
@@ -473,7 +473,9 @@
 		ida_gendisk[i].sizes = ida_sizes + (i*256);
 		/* ida_gendisk[i].nr_real is handled by getgeometry */
 	
-		blk_dev[MAJOR_NR+i].request_fn = request_fns[i];
+		blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR + i), request_fns[i]);
+		blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR + i), 0);
+
 		blksize_size[MAJOR_NR+i] = ida_blocksizes + (i*256);
 		hardsect_size[MAJOR_NR+i] = ida_hardsizes + (i*256);
 		read_ahead[MAJOR_NR+i] = READ_AHEAD;
@@ -865,10 +867,13 @@
 	cmdlist_t *c;
 	int seg, sect;
 	char *lastdataend;
+	request_queue_t * q;
 	struct buffer_head *bh;
 	struct request *creq;
 
-	creq = blk_dev[MAJOR_NR+ctlr].current_request;
+	q = &blk_dev[MAJOR_NR+ctlr].request_queue;
+
+	creq = q->current_request;
 	if (creq == NULL || creq->rq_status == RQ_INACTIVE)
 		goto doreq_done;
 
@@ -945,7 +950,7 @@
 	} else {
 DBGPX(		printk("Done with %p, queueing %p\n", creq, creq->next); );
 		creq->rq_status = RQ_INACTIVE;
-		blk_dev[MAJOR_NR+ctlr].current_request = creq->next;
+		q->current_request = creq->next;
 		wake_up(&wait_for_request);
 	}
 
diff -u -r linux.clean/drivers/block/floppy.c linux.new2/drivers/block/floppy.c
--- linux.clean/drivers/block/floppy.c	Wed Jul 28 18:24:12 1999
+++ linux.new2/drivers/block/floppy.c	Wed Jul 28 19:06:19 1999
@@ -2924,7 +2924,7 @@
 	schedule_bh( (void *)(void *) redo_fd_request);
 }
 
-static void do_fd_request(void)
+static void do_fd_request(request_queue_t * q)
 {
 	if(usage_count == 0) {
 		printk("warning: usage count=0, CURRENT=%p exiting\n", CURRENT);
@@ -4121,7 +4121,7 @@
 
 	blk_size[MAJOR_NR] = floppy_sizes;
 	blksize_size[MAJOR_NR] = floppy_blocksizes;
-	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
 	reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
 	config_types();
 
@@ -4150,7 +4150,7 @@
 	fdc = 0; /* reset fdc in case of unexpected interrupt */
 	if (floppy_grab_irq_and_dma()){
 		del_timer(&fd_timeout);
-		blk_dev[MAJOR_NR].request_fn = NULL;
+		blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
 		unregister_blkdev(MAJOR_NR,"fd");
 		del_timer(&fd_timeout);
 		return -EBUSY;
@@ -4216,7 +4216,7 @@
 		schedule();
  		if (usage_count)
  			floppy_release_irq_and_dma();
- 		blk_dev[MAJOR_NR].request_fn = NULL;
+		blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
 		unregister_blkdev(MAJOR_NR,"fd");		
 	}
 	return have_no_fdc;
@@ -4442,7 +4442,7 @@
 		
 	unregister_blkdev(MAJOR_NR, "fd");
 
-	blk_dev[MAJOR_NR].request_fn = 0;
+	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
 	/* eject disk, if any */
 	dummy = fd_eject(0);
 }
diff -u -r linux.clean/drivers/block/hd.c linux.new2/drivers/block/hd.c
--- linux.clean/drivers/block/hd.c	Wed Jul 28 18:24:13 1999
+++ linux.new2/drivers/block/hd.c	Wed Jul 28 19:06:19 1999
@@ -575,7 +575,7 @@
 	panic("unknown hd-command");
 }
 
-static void do_hd_request (void)
+static void do_hd_request (request_queue_t * q)
 {
 	disable_irq(HD_IRQ);
 	hd_request();
@@ -789,7 +789,7 @@
 		printk("hd: unable to get major %d for hard disk\n",MAJOR_NR);
 		return -1;
 	}
-	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
 	read_ahead[MAJOR_NR] = 8;		/* 8 sector (4kB) read-ahead */
 	hd_gendisk.next = gendisk_head;
 	gendisk_head = &hd_gendisk;
diff -u -r linux.clean/drivers/block/ide-probe.c linux.new2/drivers/block/ide-probe.c
--- linux.clean/drivers/block/ide-probe.c	Wed Jul 28 18:24:13 1999
+++ linux.new2/drivers/block/ide-probe.c	Wed Jul 28 19:06:19 1999
@@ -721,7 +721,8 @@
 
 static int hwif_init (ide_hwif_t *hwif)
 {
-	void (*rfn)(void);
+        ide_drive_t *drive;
+	void (*rfn)(request_queue_t *);
 	
 	if (!hwif->present)
 		return 0;
@@ -797,10 +798,23 @@
 	
 	init_gendisk(hwif);
 	blk_dev[hwif->major].data = hwif;
-	blk_dev[hwif->major].request_fn = rfn;
 	blk_dev[hwif->major].queue = ide_get_queue;
 	read_ahead[hwif->major] = 8;	/* (4kB) */
 	hwif->present = 1;	/* success */
+
+	/*
+	 * FIXME(eric) - This needs to be tested.  I *think* that this
+	 * is correct.   Also, I believe that there is no longer any
+	 * reason to have multiple functions (do_ide[0-7]_request)
+	 * functions - the queuedata field could be used to indicate
+	 * the correct hardware group - either this, or we could add
+	 * a new field to request_queue_t to hold this information.
+	 */
+	drive = &hwif->drives[0];
+	blk_init_queue(&drive->queue, rfn);
+
+	drive = &hwif->drives[1];
+	blk_init_queue(&drive->queue, rfn);
 
 #if (DEBUG_SPINLOCK > 0)
 {
diff -u -r linux.clean/drivers/block/ide.c linux.new2/drivers/block/ide.c
--- linux.clean/drivers/block/ide.c	Wed Jul 28 18:24:14 1999
+++ linux.new2/drivers/block/ide.c	Wed Jul 28 19:06:19 1999
@@ -476,8 +476,8 @@
 
 	if (!end_that_request_first(rq, uptodate, hwgroup->drive->name)) {
 		add_blkdev_randomness(MAJOR(rq->rq_dev));
-		hwgroup->drive->queue = rq->next;
-        	blk_dev[MAJOR(rq->rq_dev)].current_request = NULL;
+		hwgroup->drive->queue.current_request = rq->next;
+        	blk_dev[MAJOR(rq->rq_dev)].request_queue.current_request = NULL;
         	hwgroup->rq = NULL;
 		end_that_request_last(rq);
 	}
@@ -727,8 +727,8 @@
 		}
 	}
 	spin_lock_irqsave(&io_request_lock, flags);
-	drive->queue = rq->next;
-	blk_dev[MAJOR(rq->rq_dev)].current_request = NULL;
+	drive->queue.current_request = rq->next;
+	blk_dev[MAJOR(rq->rq_dev)].request_queue.current_request = NULL;
 	HWGROUP(drive)->rq = NULL;
 	rq->rq_status = RQ_INACTIVE;
 	spin_unlock_irqrestore(&io_request_lock, flags);
@@ -1028,7 +1028,7 @@
 static inline void start_request (ide_drive_t *drive)
 {
 	unsigned long block, blockend;
-	struct request *rq = drive->queue;
+	struct request *rq = drive->queue.current_request;
 	unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS;
 	ide_hwif_t *hwif = HWIF(drive);
 
@@ -1111,14 +1111,12 @@
 	best = NULL;
 	drive = hwgroup->drive;
 	do {
-		if (drive->queue && (!drive->sleep || 0 <= (signed long)(jiffies - drive->sleep))) {
+		if (drive->queue.current_request && (!drive->sleep || 0 <= (signed long)(jiffies - drive->sleep))) {
 			if (!best
 			 || (drive->sleep && (!best->sleep || 0 < (signed long)(best->sleep - drive->sleep)))
 			 || (!best->sleep && 0 < (signed long)(WAKEUP(best) - WAKEUP(drive))))
 			{
-				struct blk_dev_struct *bdev = &blk_dev[HWIF(drive)->major];
-				if (bdev->current_request != &bdev->plug)
-					best = drive;
+				best = drive;
 			}
 		}
 	} while ((drive = drive->next) != hwgroup->drive);
@@ -1165,8 +1163,7 @@
 			drive = hwgroup->drive;
 			do {
 				bdev = &blk_dev[HWIF(drive)->major];
-				if (bdev->current_request != &bdev->plug)	/* FIXME: this will do for now */
-					bdev->current_request = NULL;		/* (broken since patch-2.1.15) */
+				bdev->request_queue.current_request = NULL;		/* (broken since patch-2.1.15) */
 				if (drive->sleep && (!sleep || 0 < (signed long)(sleep - drive->sleep)))
 					sleep = drive->sleep;
 			} while ((drive = drive->next) != hwgroup->drive);
@@ -1195,9 +1192,7 @@
 		drive->service_start = jiffies;
 
 		bdev = &blk_dev[hwif->major];
-		if (bdev->current_request == &bdev->plug)	/* FIXME: paranoia */
-			printk("%s: Huh? nuking plugged queue\n", drive->name);
-		bdev->current_request = hwgroup->rq = drive->queue;
+		bdev->request_queue.current_request = hwgroup->rq = drive->queue.current_request;
 		spin_unlock_irqrestore(&io_request_lock, io_flags);
 
 		if (hwif->irq != masked_irq)
@@ -1213,7 +1208,7 @@
 /*
  * ide_get_queue() returns the queue which corresponds to a given device.
  */
-struct request **ide_get_queue (kdev_t dev)
+request_queue_t *ide_get_queue (kdev_t dev)
 {
 	ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[MAJOR(dev)].data;
 
@@ -1254,55 +1249,55 @@
 	spin_lock_irq(&io_request_lock);
 }
 
-void do_ide0_request (void)
+void do_ide0_request (request_queue_t * q)
 {
 	unlock_do_hwgroup_request (ide_hwifs[0].hwgroup);
 }
 
 #if MAX_HWIFS > 1
-void do_ide1_request (void)
+void do_ide1_request (request_queue_t * q)
 {
 	unlock_do_hwgroup_request (ide_hwifs[1].hwgroup);
 }
 #endif /* MAX_HWIFS > 1 */
 
 #if MAX_HWIFS > 2
-void do_ide2_request (void)
+void do_ide2_request (request_queue_t * q)
 {
 	unlock_do_hwgroup_request (ide_hwifs[2].hwgroup);
 }
 #endif /* MAX_HWIFS > 2 */
 
 #if MAX_HWIFS > 3
-void do_ide3_request (void)
+void do_ide3_request (request_queue_t * q)
 {
 	unlock_do_hwgroup_request (ide_hwifs[3].hwgroup);
 }
 #endif /* MAX_HWIFS > 3 */
 
 #if MAX_HWIFS > 4
-void do_ide4_request (void)
+void do_ide4_request (request_queue_t * q)
 {
 	unlock_do_hwgroup_request (ide_hwifs[4].hwgroup);
 }
 #endif /* MAX_HWIFS > 4 */
 
 #if MAX_HWIFS > 5
-void do_ide5_request (void)
+void do_ide5_request (request_queue_t * q)
 {
 	unlock_do_hwgroup_request (ide_hwifs[5].hwgroup);
 }
 #endif /* MAX_HWIFS > 5 */
 
 #if MAX_HWIFS > 6
-void do_ide6_request (void)
+void do_ide6_request (request_queue_t * q)
 {
 	unlock_do_hwgroup_request (ide_hwifs[6].hwgroup);
 }
 #endif /* MAX_HWIFS > 6 */
 
 #if MAX_HWIFS > 7
-void do_ide7_request (void)
+void do_ide7_request (request_queue_t * q)
 {
 	unlock_do_hwgroup_request (ide_hwifs[7].hwgroup);
 }
@@ -1562,10 +1557,10 @@
 		rq->sem = &sem;
 
 	spin_lock_irqsave(&io_request_lock, flags);
-	cur_rq = drive->queue;
+	cur_rq = drive->queue.current_request;
 	if (cur_rq == NULL || action == ide_preempt) {
 		rq->next = cur_rq;
-		drive->queue = rq;
+		drive->queue.current_request = rq;
 		if (action == ide_preempt)
 			hwgroup->rq = NULL;
 	} else {
@@ -1872,7 +1867,7 @@
 	kfree(blksize_size[hwif->major]);
 	kfree(max_sectors[hwif->major]);
 	kfree(max_readahead[hwif->major]);
-	blk_dev[hwif->major].request_fn = NULL;
+	blk_cleanup_queue(BLK_DEFAULT_QUEUE(hwif->major));
 	blk_dev[hwif->major].data = NULL;
 	blk_dev[hwif->major].queue = NULL;
 	blksize_size[hwif->major] = NULL;
diff -u -r linux.clean/drivers/block/ll_rw_blk.c linux.new2/drivers/block/ll_rw_blk.c
--- linux.clean/drivers/block/ll_rw_blk.c	Wed Jul 28 18:24:14 1999
+++ linux.new2/drivers/block/ll_rw_blk.c	Sun Sep  5 15:40:49 1999
@@ -121,14 +121,49 @@
  * NOTE: the device-specific queue() functions
  * have to be atomic!
  */
-static inline struct request **get_queue(kdev_t dev)
+static inline request_queue_t *get_queue(kdev_t dev)
 {
 	int major = MAJOR(dev);
 	struct blk_dev_struct *bdev = blk_dev + major;
 
 	if (bdev->queue)
 		return bdev->queue(dev);
-	return &blk_dev[major].current_request;
+	return &blk_dev[major].request_queue;
+}
+
+void blk_cleanup_queue(request_queue_t * q)
+{
+	memset(q, 0, sizeof(*q));
+}
+
+void blk_queue_headactive(request_queue_t * q, int active)
+{
+	q->head_active     = active;
+}
+
+void blk_queue_pluggable(request_queue_t * q, int use_plug)
+{
+	q->use_plug        = use_plug;
+}
+
+void blk_init_queue(request_queue_t * q, request_fn_proc * rfn)
+{
+	q->request_fn      = rfn;
+	q->current_request = NULL;
+	q->merge_fn        = NULL;
+	q->merge_requests_fn = NULL;
+	q->plug_tq.sync    = 0;
+	q->plug_tq.routine = &unplug_device;
+	q->plug_tq.data    = q;
+	q->plugged         = 0;
+	/*
+	 * These booleans describe the queue properties.  We set the
+	 * default (and most common) values here.  Other drivers can
+	 * use the appropriate functions to alter the queue properties.
+	 * as appropriate.
+	 */
+	q->use_plug        = 1;
+	q->head_active     = 1;
 }
 
 /*
@@ -136,22 +171,18 @@
  */
 void unplug_device(void * data)
 {
-	struct blk_dev_struct * dev = (struct blk_dev_struct *) data;
-	int queue_new_request=0;
+	request_queue_t * q = (request_queue_t *) data;
 	unsigned long flags;
 
 	spin_lock_irqsave(&io_request_lock,flags);
-	if (dev->current_request == &dev->plug) {
-		struct request * next = dev->plug.next;
-		dev->current_request = next;
-		if (next || dev->queue) {
-			dev->plug.next = NULL;
-			queue_new_request = 1;
+	if( q->plugged )
+	{
+	        q->plugged = 0;
+		if( q->current_request != NULL )
+		{
+			(q->request_fn)(q);
 		}
 	}
-	if (queue_new_request)
-		(dev->request_fn)();
-
 	spin_unlock_irqrestore(&io_request_lock,flags);
 }
 
@@ -163,12 +194,13 @@
  * This is called with interrupts off and no requests on the queue.
  * (and with the request spinlock aquired)
  */
-static inline void plug_device(struct blk_dev_struct * dev)
+static inline void plug_device(request_queue_t * q)
 {
-	if (dev->current_request)
+	if (q->current_request)
 		return;
-	dev->current_request = &dev->plug;
-	queue_task(&dev->plug_tq, &tq_disk);
+
+	q->plugged = 1;
+	queue_task(&q->plug_tq, &tq_disk);
 }
 
 /*
@@ -200,6 +232,7 @@
 	prev_found = req;
 	req->rq_status = RQ_ACTIVE;
 	req->rq_dev = dev;
+	req->special = NULL;
 	return req;
 }
 
@@ -290,12 +323,11 @@
  * which is important for drive_stat_acct() above.
  */
 
-void add_request(struct blk_dev_struct * dev, struct request * req)
+static void add_request(request_queue_t * q, struct request * req)
 {
-	struct request * tmp, **current_request;
+	struct request * tmp;
 	short		 disk_index;
 	unsigned long flags;
-	int queue_new_request = 0;
 
 	switch (MAJOR(req->rq_dev)) {
 		case SCSI_DISK0_MAJOR:
@@ -321,12 +353,9 @@
 	 * We use the goto to reduce locking complexity
 	 */
 	spin_lock_irqsave(&io_request_lock,flags);
-	current_request = get_queue(req->rq_dev);
 
-	if (!(tmp = *current_request)) {
-		*current_request = req;
-		if (dev->current_request != &dev->plug)
-			queue_new_request = 1;
+	if (!(tmp = q->current_request)) {
+		q->current_request = req;
 		goto out;
 	}
 	for ( ; tmp->next ; tmp = tmp->next) {
@@ -344,22 +373,29 @@
 	req->next = tmp->next;
 	tmp->next = req;
 
-/* for SCSI devices, call request_fn unconditionally */
-	if (scsi_blk_major(MAJOR(req->rq_dev)))
-		queue_new_request = 1;
+	/*
+	 * FIXME(eric) I don't understand why there is a need for this
+	 * special case code.  It clearly doesn't fit any more with
+	 * the new queueing architecture, and it got added in 2.3.10.  
+	 * I am leaving this in here until I hear back from the COMPAQ
+	 * people.
+	 */
 	if (MAJOR(req->rq_dev) >= COMPAQ_SMART2_MAJOR+0 &&
 	    MAJOR(req->rq_dev) <= COMPAQ_SMART2_MAJOR+7)
-		queue_new_request = 1;
+	{
+		(q->request_fn)(q);
+	}
+
 out:
-	if (queue_new_request)
-		(dev->request_fn)();
 	spin_unlock_irqrestore(&io_request_lock,flags);
 }
 
 /*
  * Has to be called with the request spinlock aquired
  */
-static inline void attempt_merge (struct request *req, int max_sectors)
+static inline void attempt_merge (request_queue_t * q,
+				  struct request *req, 
+				  int max_sectors)
 {
 	struct request *next = req->next;
 
@@ -369,6 +405,13 @@
 		return;
 	if (next->sem || req->cmd != next->cmd || req->rq_dev != next->rq_dev || req->nr_sectors + next->nr_sectors > max_sectors)
 		return;
+
+	if( q->merge_requests_fn != NULL
+	    && !(q->merge_requests_fn)(q, req, next) )
+	{
+	    return;
+	}
+
 	req->bhtail->b_reqnext = next->bh;
 	req->bhtail = next->bhtail;
 	req->nr_sectors += next->nr_sectors;
@@ -377,7 +420,10 @@
 	wake_up (&wait_for_request);
 }
 
-void make_request(int major,int rw, struct buffer_head * bh)
+static void __make_request(request_queue_t * q,
+			   int major,
+			   int rw, 
+			   struct buffer_head * bh)
 {
 	unsigned int sector, count;
 	struct request * req;
@@ -466,13 +512,20 @@
 	 * not to schedule or do something nonatomic
 	 */
 	spin_lock_irqsave(&io_request_lock,flags);
-	req = *get_queue(bh->b_rdev);
+	req = q->current_request;
 	if (!req) {
 		/* MD and loop can't handle plugging without deadlocking */
 		if (major != MD_MAJOR && major != LOOP_MAJOR && 
-		    major != DDV_MAJOR && major != NBD_MAJOR)
-			plug_device(blk_dev + major); /* is atomic */
+		    major != DDV_MAJOR && major != NBD_MAJOR
+		    && q->use_plug)
+			plug_device(q); /* is atomic */
 	} else switch (major) {
+	     /*
+	      * FIXME(eric) - this entire switch statement is going away
+	      * soon, and we will instead key off of q->head_active to decide
+	      * whether the top request in the queue is active on the device
+	      * or not.
+	      */
 	     case IDE0_MAJOR:	/* same as HD_MAJOR */
 	     case IDE1_MAJOR:
 	     case FLOPPY_MAJOR:
@@ -493,7 +546,7 @@
 		 * All other drivers need to jump over the first entry, as that
 		 * entry may be busy being processed and we thus can't change it.
 		 */
-		if (req == blk_dev[major].current_request)
+		if (req == q->current_request)
 	        	req = req->next;
 		if (!req)
 			break;
@@ -529,13 +582,33 @@
 				continue;
 			/* Can we add it to the end of this request? */
 			if (req->sector + req->nr_sectors == sector) {
+				/*
+				 * See if this queue has rules that
+				 * may suggest that we shouldn't merge
+				 * this 
+				 */
+				if( q->merge_fn != NULL
+				    && !(q->merge_fn)(q, req, bh) )
+				{
+					continue;
+				}
 				req->bhtail->b_reqnext = bh;
 				req->bhtail = bh;
 			    	req->nr_sectors += count;
 				/* Can we now merge this req with the next? */
-				attempt_merge(req, max_sectors);
+				attempt_merge(q, req, max_sectors);
 			/* or to the beginning? */
 			} else if (req->sector - count == sector) {
+				/*
+				 * See if this queue has rules that
+				 * may suggest that we shouldn't merge
+				 * this 
+				 */
+				if( q->merge_fn != NULL
+				    && !(q->merge_fn)(q, req, bh) )
+				{
+					continue;
+				}
 			    	bh->b_reqnext = req->bh;
 			    	req->bh = bh;
 			    	req->buffer = bh->b_data;
@@ -569,18 +642,36 @@
 	req->sector = sector;
 	req->nr_sectors = count;
 	req->current_nr_sectors = count;
+	req->nr_sg_segments = 1; /* Always 1 for a new request. */
 	req->buffer = bh->b_data;
 	req->sem = NULL;
 	req->bh = bh;
 	req->bhtail = bh;
 	req->next = NULL;
-	add_request(major+blk_dev,req);
+	add_request(q, req);
 	return;
 
 end_io:
 	bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state));
 }
 
+void make_request(int major,int rw,  struct buffer_head * bh)
+{
+  request_queue_t * q;
+  unsigned long flags;
+	
+  q = get_queue(bh->b_dev);
+
+  __make_request(q, major, rw, bh);
+
+  spin_lock_irqsave(&io_request_lock,flags);
+  if( !q->plugged )
+  {
+	(q->request_fn)(q);
+  }
+  spin_unlock_irqrestore(&io_request_lock,flags);
+}
+
 /* This function can be used to request a number of buffers from a block
    device. Currently the only restriction is that all buffers must belong to
    the same device */
@@ -589,9 +680,11 @@
 {
 	unsigned int major;
 	int correct_size;
-	struct blk_dev_struct * dev;
+	request_queue_t		* q;
+	unsigned long flags;
 	int i;
 
+
 	/* Make sure that the first block contains something reasonable */
 	while (!*bh) {
 		bh++;
@@ -599,10 +692,8 @@
 			return;
 	}
 
-	dev = NULL;
-	if ((major = MAJOR(bh[0]->b_dev)) < MAX_BLKDEV)
-		dev = blk_dev + major;
-	if (!dev || !dev->request_fn) {
+	major = MAJOR(bh[0]->b_dev);
+	if (!(q = get_queue(bh[0]->b_dev))) {
 		printk(KERN_ERR
 	"ll_rw_block: Trying to read nonexistent block-device %s (%ld)\n",
 		kdevname(bh[0]->b_dev), bh[0]->b_blocknr);
@@ -656,9 +747,16 @@
 				continue;
 			}
 #endif
-			make_request(MAJOR(bh[i]->b_rdev), rw, bh[i]);
+			__make_request(q, MAJOR(bh[i]->b_rdev), rw, bh[i]);
 		}
 	}
+
+	spin_lock_irqsave(&io_request_lock,flags);
+	if( !q->plugged )
+	{
+		(q->request_fn)(q);
+	}
+	spin_unlock_irqrestore(&io_request_lock,flags);
 	return;
 
       sorry:
@@ -734,15 +832,8 @@
 	struct blk_dev_struct *dev;
 
 	for (dev = blk_dev + MAX_BLKDEV; dev-- != blk_dev;) {
-		dev->request_fn      = NULL;
 		dev->queue           = NULL;
-		dev->current_request = NULL;
-		dev->plug.rq_status  = RQ_INACTIVE;
-		dev->plug.cmd        = -1;
-		dev->plug.next       = NULL;
-		dev->plug_tq.sync    = 0;
-		dev->plug_tq.routine = &unplug_device;
-		dev->plug_tq.data    = dev;
+		blk_init_queue(&dev->request_queue, NULL);
 	}
 
 	req = all_requests + NR_REQUEST;
@@ -854,3 +945,6 @@
 EXPORT_SYMBOL(io_request_lock);
 EXPORT_SYMBOL(end_that_request_first);
 EXPORT_SYMBOL(end_that_request_last);
+EXPORT_SYMBOL(blk_init_queue);
+EXPORT_SYMBOL(blk_cleanup_queue);
+EXPORT_SYMBOL(blk_queue_headactive);
diff -u -r linux.clean/drivers/block/loop.c linux.new2/drivers/block/loop.c
--- linux.clean/drivers/block/loop.c	Wed Jul 28 18:25:01 1999
+++ linux.new2/drivers/block/loop.c	Wed Jul 28 19:06:20 1999
@@ -156,7 +156,7 @@
 	loop_sizes[lo->lo_number] = size;
 }
 
-static void do_lo_request(void)
+static void do_lo_request(request_queue_t * q)
 {
 	int	real_block, block, offset, len, blksize, size;
 	char	*dest_addr;
@@ -718,7 +718,7 @@
 	printk(KERN_INFO "loop: registered device at major %d\n", MAJOR_NR);
 #endif
 
-	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
 	for (i=0; i < MAX_LOOP; i++) {
 		memset(&loop_dev[i], 0, sizeof(struct loop_device));
 		loop_dev[i].lo_number = i;
diff -u -r linux.clean/drivers/block/md.c linux.new2/drivers/block/md.c
--- linux.clean/drivers/block/md.c	Sun May 16 02:43:04 1999
+++ linux.new2/drivers/block/md.c	Wed Jul 28 19:06:20 1999
@@ -759,7 +759,7 @@
 	}
 }
 
-static void do_md_request (void)
+static void do_md_request (request_queue_t * q)
 {
   printk ("Got md request, not good...");
   return;
@@ -1277,8 +1277,7 @@
     return (-1);
   }
 
-  blk_dev[MD_MAJOR].request_fn=DEVICE_REQUEST;
-  blk_dev[MD_MAJOR].current_request=NULL;
+  blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
   read_ahead[MD_MAJOR]=INT_MAX;
   memset(md_dev, 0, MAX_MD_DEV * sizeof (struct md_dev));
   md_gendisk.next=gendisk_head;
diff -u -r linux.clean/drivers/block/nbd.c linux.new2/drivers/block/nbd.c
--- linux.clean/drivers/block/nbd.c	Wed Jul 28 18:24:14 1999
+++ linux.new2/drivers/block/nbd.c	Wed Jul 28 19:06:20 1999
@@ -288,7 +288,7 @@
 #undef FAIL
 #define FAIL( s ) { printk( KERN_ERR "NBD, minor %d: " s "\n", dev ); goto error_out; }
 
-static void do_nbd_request(void)
+static void do_nbd_request(request_queue_t * q)
 {
 	struct request *req;
 	int dev;
@@ -486,7 +486,7 @@
 #endif
 	blksize_size[MAJOR_NR] = nbd_blksizes;
 	blk_size[MAJOR_NR] = nbd_sizes;
-	blk_dev[MAJOR_NR].request_fn = do_nbd_request;
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_nbd_request);
 	for (i = 0; i < MAX_NBD; i++) {
 		nbd_dev[i].refcnt = 0;
 		nbd_dev[i].file = NULL;
diff -u -r linux.clean/drivers/block/paride/pcd.c linux.new2/drivers/block/paride/pcd.c
--- linux.clean/drivers/block/paride/pcd.c	Wed Nov  4 13:03:01 1998
+++ linux.new2/drivers/block/paride/pcd.c	Wed Jul 28 19:06:20 1999
@@ -217,7 +217,7 @@
 
 static int 	pcd_detect(void);
 static void     do_pcd_read_drq(void);
-static void 	do_pcd_request(void);
+static void 	do_pcd_request(request_queue_t * q);
 static void 	do_pcd_read(void);
 
 static int pcd_blocksizes[PCD_UNITS];
@@ -333,7 +333,7 @@
 	for (unit=0;unit<PCD_UNITS;unit++)
 		if (PCD.present) register_cdrom(&PCD.info);
 
-	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
 	read_ahead[MAJOR_NR] = 8;	/* 8 sector (4kB) read ahead */
 
 	for (i=0;i<PCD_UNITS;i++) pcd_blocksizes[i] = 1024;
@@ -704,7 +704,7 @@
 
 /* I/O request processing */
 
-static void do_pcd_request (void)
+static void do_pcd_request (request_queue_t * q)
 
 {       int unit;
 
@@ -768,7 +768,7 @@
 		spin_lock_irqsave(&io_request_lock,saved_flags);
 		pcd_busy = 0;
 		end_request(0);
-		do_pcd_request();
+		do_pcd_request(NULL);
 		spin_unlock_irqrestore(&io_request_lock,saved_flags);
 		return;
 	}
@@ -792,7 +792,7 @@
 		spin_lock_irqsave(&io_request_lock,saved_flags);
 		end_request(1);
 		pcd_busy = 0;
-		do_pcd_request();
+		do_pcd_request(NULL);
 		spin_unlock_irqrestore(&io_request_lock,saved_flags);
 		return;
 	}
@@ -816,14 +816,14 @@
 		pcd_busy = 0;
 		pcd_bufblk = -1;
 		end_request(0);
-		do_pcd_request();
+		do_pcd_request(NULL);
 		spin_unlock_irqrestore(&io_request_lock,saved_flags);
 		return;
 	}
 
 	do_pcd_read();
 	spin_lock_irqsave(&io_request_lock,saved_flags);
-	do_pcd_request();
+	do_pcd_request(NULL);
 	spin_unlock_irqrestore(&io_request_lock,saved_flags); 
 }
 
diff -u -r linux.clean/drivers/block/paride/pd.c linux.new2/drivers/block/paride/pd.c
--- linux.clean/drivers/block/paride/pd.c	Sun May 16 02:43:04 1999
+++ linux.new2/drivers/block/paride/pd.c	Wed Jul 28 19:06:20 1999
@@ -265,7 +265,7 @@
 #endif
 static void pd_geninit(struct gendisk *ignored);
 static int pd_open(struct inode *inode, struct file *file);
-static void do_pd_request(void);
+static void do_pd_request(request_queue_t * q);
 static int pd_ioctl(struct inode *inode,struct file *file,
                     unsigned int cmd, unsigned long arg);
 static int pd_release (struct inode *inode, struct file *file);
@@ -404,7 +404,7 @@
                         name,major);
                 return -1;
         }
-        blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
         read_ahead[MAJOR_NR] = 8;       /* 8 sector (4kB) read ahead */
         
 	pd_gendisk.major = major;
@@ -894,7 +894,7 @@
 	return (!(RR(1,6) & STAT_BUSY)) ;
 }
 
-static void do_pd_request (void)
+static void do_pd_request (request_queue_t * q)
 
 {       struct buffer_head * bh;
 	struct request * req;
@@ -992,7 +992,7 @@
 		spin_lock_irqsave(&io_request_lock,saved_flags);
                 end_request(0);
                 pd_busy = 0;
-                do_pd_request();
+                do_pd_request(NULL);
 		spin_unlock_irqrestore(&io_request_lock,saved_flags);
                 return;
         }
@@ -1016,7 +1016,7 @@
 		spin_lock_irqsave(&io_request_lock,saved_flags);
                 end_request(0);
                 pd_busy = 0;
-                do_pd_request();
+                do_pd_request(NULL);
 		spin_unlock_irqrestore(&io_request_lock,saved_flags);
                 return;
             }
@@ -1031,7 +1031,7 @@
 	spin_lock_irqsave(&io_request_lock,saved_flags);
         end_request(1);
         pd_busy = 0;
-        do_pd_request();
+        do_pd_request(NULL);
 	spin_unlock_irqrestore(&io_request_lock,saved_flags);
 }
 
@@ -1058,7 +1058,7 @@
 		spin_lock_irqsave(&io_request_lock,saved_flags);
                 end_request(0);
                 pd_busy = 0;
-                do_pd_request();
+                do_pd_request(NULL);
 		spin_unlock_irqrestore(&io_request_lock,saved_flags);
                 return;
         }
@@ -1074,7 +1074,7 @@
 		spin_lock_irqsave(&io_request_lock,saved_flags);
                 end_request(0);
                 pd_busy = 0;
-                do_pd_request();
+                do_pd_request(NULL);
                 spin_unlock_irqrestore(&io_request_lock,saved_flags);
 		return;
             }
@@ -1103,7 +1103,7 @@
 		spin_lock_irqsave(&io_request_lock,saved_flags);
                 end_request(0);
                 pd_busy = 0;
-                do_pd_request();
+                do_pd_request(NULL);
 		spin_unlock_irqrestore(&io_request_lock,saved_flags);
                 return;
         }
@@ -1111,7 +1111,7 @@
 	spin_lock_irqsave(&io_request_lock,saved_flags);
         end_request(1);
         pd_busy = 0;
-        do_pd_request();
+        do_pd_request(NULL);
 	spin_unlock_irqrestore(&io_request_lock,saved_flags);
 }
 
diff -u -r linux.clean/drivers/block/paride/pf.c linux.new2/drivers/block/paride/pf.c
--- linux.clean/drivers/block/paride/pf.c	Sun May 16 02:43:04 1999
+++ linux.new2/drivers/block/paride/pf.c	Wed Jul 28 19:06:20 1999
@@ -246,7 +246,7 @@
 void cleanup_module( void );
 #endif
 static int pf_open(struct inode *inode, struct file *file);
-static void do_pf_request(void);
+static void do_pf_request(request_queue_t * q);
 static int pf_ioctl(struct inode *inode,struct file *file,
                     unsigned int cmd, unsigned long arg);
 
@@ -365,7 +365,7 @@
                         major);
                 return -1;
         }
-        blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
         read_ahead[MAJOR_NR] = 8;       /* 8 sector (4kB) read ahead */
         
 	for (i=0;i<PF_UNITS;i++) pf_blocksizes[i] = 1024;
@@ -863,7 +863,7 @@
 	return (((RR(1,6)&(STAT_BUSY|pf_mask)) == pf_mask));
 }
 
-static void do_pf_request (void)
+static void do_pf_request (request_queue_t * q)
 
 {       struct buffer_head * bh;
 	struct request * req;
@@ -958,7 +958,7 @@
 		spin_lock_irqsave(&io_request_lock,saved_flags);
                 end_request(0);
                 pf_busy = 0;
-                do_pf_request();
+                do_pf_request(NULL);
 		spin_unlock_irqrestore(&io_request_lock,saved_flags);
                 return;
         }
@@ -984,7 +984,7 @@
 		spin_lock_irqsave(&io_request_lock,saved_flags);
                 end_request(0);
                 pf_busy = 0;
-                do_pf_request();
+                do_pf_request(NULL);
 		spin_unlock_irqrestore(&io_request_lock,saved_flags);
                 return;
             }
@@ -999,7 +999,7 @@
 	spin_lock_irqsave(&io_request_lock,saved_flags); 
         end_request(1);
         pf_busy = 0;
-        do_pf_request();
+        do_pf_request(NULL);
 	spin_unlock_irqrestore(&io_request_lock,saved_flags);
 }
 
@@ -1025,7 +1025,7 @@
 		spin_lock_irqsave(&io_request_lock,saved_flags);
                 end_request(0);
                 pf_busy = 0;
-                do_pf_request();
+                do_pf_request(NULL);
 		spin_unlock_irqrestore(&io_request_lock,saved_flags);
                 return;
         }
@@ -1042,7 +1042,7 @@
 		spin_lock_irqsave(&io_request_lock,saved_flags);
                 end_request(0);
                 pf_busy = 0;
-                do_pf_request();
+                do_pf_request(NULL);
 		spin_unlock_irqrestore(&io_request_lock,saved_flags);
                 return;
             }
@@ -1072,7 +1072,7 @@
 		spin_lock_irqsave(&io_request_lock,saved_flags);
                 end_request(0);
                 pf_busy = 0;
-                do_pf_request();
+                do_pf_request(NULL);
 		spin_unlock_irqrestore(&io_request_lock,saved_flags);
                 return;
         }
@@ -1080,7 +1080,7 @@
 	spin_lock_irqsave(&io_request_lock,saved_flags);
         end_request(1);
         pf_busy = 0;
-        do_pf_request();
+        do_pf_request(NULL);
 	spin_unlock_irqrestore(&io_request_lock,saved_flags);
 }
 
diff -u -r linux.clean/drivers/block/ps2esdi.c linux.new2/drivers/block/ps2esdi.c
--- linux.clean/drivers/block/ps2esdi.c	Sun May 16 02:43:04 1999
+++ linux.new2/drivers/block/ps2esdi.c	Wed Jul 28 19:06:20 1999
@@ -70,7 +70,7 @@
 
 static void ps2esdi_geninit(struct gendisk *ignored);
 
-static void do_ps2esdi_request(void);
+static void do_ps2esdi_request(request_queue_t * q);
 
 static void ps2esdi_readwrite(int cmd, u_char drive, u_int block, u_int count);
 
@@ -188,7 +188,7 @@
 		return -1;
 	}
 	/* set up some global information - indicating device specific info */
-	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
 	read_ahead[MAJOR_NR] = 8;	/* 8 sector (4kB) read ahead */
 
 	/* some minor housekeeping - setup the global gendisk structure */
@@ -463,7 +463,7 @@
 }
 
 /* strategy routine that handles most of the IO requests */
-static void do_ps2esdi_request(void)
+static void do_ps2esdi_request(request_queue_t * q)
 {
 	u_int block, count;
 	/* since, this routine is called with interrupts cleared - they 
@@ -486,7 +486,7 @@
 		printk("%s: DMA above 16MB not supported\n", DEVICE_NAME);
 		end_request(FAIL);
 		if (CURRENT)
-			do_ps2esdi_request();
+			do_ps2esdi_request(q);
 		return;
 	}			/* check for above 16Mb dmas */
 	if ((CURRENT_DEV < ps2esdi_drives) &&
@@ -520,7 +520,7 @@
 			printk("%s: Unknown command\n", DEVICE_NAME);
 			end_request(FAIL);
 			if (CURRENT)
-				do_ps2esdi_request();
+				do_ps2esdi_request(q);
 			break;
 		}		/* handle different commands */
 	}
@@ -530,7 +530,7 @@
 		       CURRENT->sector, ps2esdi[MINOR(CURRENT->rq_dev)].nr_sects);
 		end_request(FAIL);
 		if (CURRENT)
-			do_ps2esdi_request();
+			do_ps2esdi_request(q);
 	}
 
 }				/* main strategy routine */
@@ -597,11 +597,11 @@
 	if (ps2esdi_out_cmd_blk(cmd_blk)) {
 		printk("%s: Controller failed\n", DEVICE_NAME);
 		if ((++CURRENT->errors) < MAX_RETRIES)
-			return do_ps2esdi_request();
+			return do_ps2esdi_request(NULL);
 		else {
 			end_request(FAIL);
 			if (CURRENT)
-				do_ps2esdi_request();
+				do_ps2esdi_request(NULL);
 		}
 	}
 	/* check for failure to put out the command block */ 
@@ -899,11 +899,11 @@
 			outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 			outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
 			if ((++CURRENT->errors) < MAX_RETRIES)
-				do_ps2esdi_request();
+				do_ps2esdi_request(NULL);
 			else {
 				end_request(FAIL);
 				if (CURRENT)
-					do_ps2esdi_request();
+					do_ps2esdi_request(NULL);
 			}
 			break;
 		}
@@ -945,11 +945,11 @@
 		outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 		outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
 		if ((++CURRENT->errors) < MAX_RETRIES)
-			do_ps2esdi_request();
+			do_ps2esdi_request(NULL);
 		else {
 			end_request(FAIL);
 			if (CURRENT)
-				do_ps2esdi_request();
+				do_ps2esdi_request(NULL);
 		}
 		break;
 
@@ -959,7 +959,7 @@
 		outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
 		end_request(FAIL);
 		if (CURRENT)
-			do_ps2esdi_request();
+			do_ps2esdi_request(NULL);
 		break;
 
 	case INT_CMD_FORMAT:
@@ -991,11 +991,11 @@
 	if (CURRENT->nr_sectors -= CURRENT->current_nr_sectors) {
 		CURRENT->buffer += CURRENT->current_nr_sectors * SECT_SIZE;
 		CURRENT->sector += CURRENT->current_nr_sectors;
-		do_ps2esdi_request();
+		do_ps2esdi_request(NULL);
 	} else {
 		end_request(SUCCES);
 		if (CURRENT)
-			do_ps2esdi_request();
+			do_ps2esdi_request(NULL);
 	}
 }
 
diff -u -r linux.clean/drivers/block/rd.c linux.new2/drivers/block/rd.c
--- linux.clean/drivers/block/rd.c	Wed Jul 28 18:23:15 1999
+++ linux.new2/drivers/block/rd.c	Wed Jul 28 19:06:20 1999
@@ -132,7 +132,7 @@
  *  allocated size, we must get rid of it...
  *
  */
-static void rd_request(void)
+static void rd_request(request_queue_t * q)
 {
 	unsigned int minor;
 	unsigned long offset, len;
@@ -306,7 +306,7 @@
 		return -EIO;
 	}
 
-	blk_dev[MAJOR_NR].request_fn = &rd_request;
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &rd_request);
 
 	for (i = 0; i < NUM_RAMDISKS; i++) {
 		/* rd_size is given in kB */
@@ -350,7 +350,7 @@
 		invalidate_buffers(MKDEV(MAJOR_NR, i));
 
 	unregister_blkdev( MAJOR_NR, "ramdisk" );
-	blk_dev[MAJOR_NR].request_fn = 0;
+	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
 }
 
 #endif  /* MODULE */
diff -u -r linux.clean/drivers/block/swim3.c linux.new2/drivers/block/swim3.c
--- linux.clean/drivers/block/swim3.c	Wed May 12 02:36:27 1999
+++ linux.new2/drivers/block/swim3.c	Wed Jul 28 19:06:20 1999
@@ -219,7 +219,7 @@
 static void swim3_select(struct floppy_state *fs, int sel);
 static void swim3_action(struct floppy_state *fs, int action);
 static int swim3_readbit(struct floppy_state *fs, int bit);
-static void do_fd_request(void);
+static void do_fd_request(request_queue_t * q);
 static void start_request(struct floppy_state *fs);
 static void set_timeout(struct floppy_state *fs, int nticks,
 			void (*proc)(unsigned long));
@@ -290,7 +290,7 @@
 	return (stat & DATA) == 0;
 }
 
-static void do_fd_request(void)
+static void do_fd_request(request_queue_t * q)
 {
 	int i;
 	for(i=0;i<floppy_count;i++)
@@ -1089,7 +1089,7 @@
 			       MAJOR_NR);
 			return -EBUSY;
 		}
-		blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+		blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
 		blksize_size[MAJOR_NR] = floppy_blocksizes;
 		blk_size[MAJOR_NR] = floppy_sizes;
 	}
diff -u -r linux.clean/drivers/block/xd.c linux.new2/drivers/block/xd.c
--- linux.clean/drivers/block/xd.c	Sun May 16 02:43:04 1999
+++ linux.new2/drivers/block/xd.c	Wed Jul 28 19:06:20 1999
@@ -185,7 +185,7 @@
 		printk("xd: Unable to get major number %d\n",MAJOR_NR);
 		return -1;
 	}
-	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
 	read_ahead[MAJOR_NR] = 8;	/* 8 sector (4kB) read ahead */
 	xd_gendisk.next = gendisk_head;
 	gendisk_head = &xd_gendisk;
@@ -284,7 +284,7 @@
 }
 
 /* do_xd_request: handle an incoming request */
-static void do_xd_request (void)
+static void do_xd_request (request_queue_t * q)
 {
 	u_int block,count,retry;
 	int code;
@@ -1143,7 +1143,7 @@
 	struct gendisk ** gdp;
 	
 	blksize_size[MAJOR_NR] = NULL;
-	blk_dev[MAJOR_NR].request_fn = NULL;
+	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
 	blk_size[MAJOR_NR] = NULL;
 	hardsect_size[MAJOR_NR] = NULL;
 	read_ahead[MAJOR_NR] = 0;
diff -u -r linux.clean/drivers/block/xd.h linux.new2/drivers/block/xd.h
--- linux.clean/drivers/block/xd.h	Sun Jan  4 13:40:15 1998
+++ linux.new2/drivers/block/xd.h	Wed Jul 28 19:06:20 1999
@@ -112,7 +112,7 @@
 static void xd_geninit (struct gendisk *);
 
 static int xd_open (struct inode *inode,struct file *file);
-static void do_xd_request (void);
+static void do_xd_request (request_queue_t * q);
 static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg);
 static int xd_release (struct inode *inode,struct file *file);
 static int xd_reread_partitions (kdev_t dev);
diff -u -r linux.clean/drivers/block/z2ram.c linux.new2/drivers/block/z2ram.c
--- linux.clean/drivers/block/z2ram.c	Fri Dec 18 12:36:05 1998
+++ linux.new2/drivers/block/z2ram.c	Wed Jul 28 19:06:20 1999
@@ -74,7 +74,7 @@
 static int current_device   = -1;
 
 static void
-do_z2_request( void )
+do_z2_request( request_queue_t * q )
 {
     u_long start, len, addr, size;
 
@@ -380,7 +380,7 @@
 	    }
     }    
    
-    blk_dev[ MAJOR_NR ].request_fn = DEVICE_REQUEST;
+    blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
     blksize_size[ MAJOR_NR ] = z2_blocksizes;
     blk_size[ MAJOR_NR ] = z2_sizes;
 
diff -u -r linux.clean/drivers/cdrom/aztcd.c linux.new2/drivers/cdrom/aztcd.c
--- linux.clean/drivers/cdrom/aztcd.c	Wed Jul 28 18:24:14 1999
+++ linux.new2/drivers/cdrom/aztcd.c	Wed Jul 28 19:06:20 1999
@@ -355,7 +355,7 @@
 static int  check_aztcd_media_change(kdev_t full_dev);
 static int  aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
 static void azt_transfer(void);
-static void do_aztcd_request(void);
+static void do_aztcd_request(request_queue_t *);
 static void azt_invalidate_buffers(void);
 int         aztcd_open(struct inode *ip, struct file *fp);
 
@@ -1478,7 +1478,7 @@
   }
 }
 
-static void do_aztcd_request(void)
+static void do_aztcd_request(request_queue_t * q)
 {
 #ifdef AZT_TEST
   printk(" do_aztcd_request(%ld+%ld) Time:%li\n", CURRENT -> sector, CURRENT -> nr_sectors,jiffies);
@@ -1798,7 +1798,7 @@
 		       MAJOR_NR);
                 return -EIO;
 	}
-	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
 #ifndef AZT_KERNEL_PRIOR_2_1
 	blksize_size[MAJOR_NR] = aztcd_blocksizes;
 #endif
diff -u -r linux.clean/drivers/cdrom/cdu31a.c linux.new2/drivers/cdrom/cdu31a.c
--- linux.clean/drivers/cdrom/cdu31a.c	Wed Jul 28 18:24:14 1999
+++ linux.new2/drivers/cdrom/cdu31a.c	Wed Jul 28 19:06:20 1999
@@ -1641,7 +1641,7 @@
  * data access on a CD is done sequentially, this saves a lot of operations.
  */
 static void
-do_cdu31a_request(void)
+do_cdu31a_request(request_queue_t * q)
 {
    int block;
    int nblock;
@@ -3497,7 +3497,7 @@
 
       is_a_cdu31a = strcmp("CD-ROM CDU31A", drive_config.product_id) == 0;
 
-      blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+      blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
       read_ahead[MAJOR_NR] = CDU31A_READAHEAD;
       cdu31a_block_size = 1024; /* 1kB default block size */
       /* use 'mount -o block=2048' */
diff -u -r linux.clean/drivers/cdrom/cm206.c linux.new2/drivers/cdrom/cm206.c
--- linux.clean/drivers/cdrom/cm206.c	Wed Jul 28 18:24:14 1999
+++ linux.new2/drivers/cdrom/cm206.c	Wed Jul 28 19:06:20 1999
@@ -801,7 +801,7 @@
 /* This is not a very smart implementation. We could optimize for 
    consecutive block numbers. I'm not convinced this would really
    bring down the processor load. */
-static void do_cm206_request(void)
+static void do_cm206_request(request_queue_t * q)
 {
   long int i, cd_sec_no;
   int quarter, error; 
@@ -1394,7 +1394,7 @@
     cleanup(3);
     return -EIO;
   }    
-  blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+  blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
   blksize_size[MAJOR_NR] = cm206_blocksizes;
   read_ahead[MAJOR_NR] = 16;	/* reads ahead what? */
   init_bh(CM206_BH, cm206_bh);
diff -u -r linux.clean/drivers/cdrom/gscd.c linux.new2/drivers/cdrom/gscd.c
--- linux.clean/drivers/cdrom/gscd.c	Wed Jul 28 18:24:14 1999
+++ linux.new2/drivers/cdrom/gscd.c	Wed Jul 28 19:06:20 1999
@@ -86,7 +86,8 @@
 
 /* Schnittstellen zum Kern/FS */
 
-static void do_gscd_request       (void);
+static void do_gscd_request       (request_queue_t *);
+static void __do_gscd_request     (void);
 static int  gscd_ioctl            (struct inode *, struct file *, unsigned int, unsigned long);
 static int  gscd_open             (struct inode *, struct file *);
 static int  gscd_release          (struct inode *, struct file *);
@@ -260,7 +261,12 @@
  * I/O request routine called from Linux kernel.
  */
 
-static void do_gscd_request (void)
+static void do_gscd_request (request_queue_t * q)
+{
+  __do_gscd_request();
+}
+
+static void __do_gscd_request (void)
 {
 unsigned int block,dev;
 unsigned int nsect;
@@ -355,7 +361,7 @@
               end_request(1);
 	   }
 	}
-	SET_TIMER(do_gscd_request, 1);
+	SET_TIMER(__do_gscd_request, 1);
 }
 
 
@@ -1060,7 +1066,7 @@
 		return -EIO;
 	}
 
-	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
 	blksize_size[MAJOR_NR] = gscd_blocksizes;
 	read_ahead[MAJOR_NR] = 4;
         
diff -u -r linux.clean/drivers/cdrom/mcd.c linux.new2/drivers/cdrom/mcd.c
--- linux.clean/drivers/cdrom/mcd.c	Wed Jul 28 18:24:15 1999
+++ linux.new2/drivers/cdrom/mcd.c	Wed Jul 28 19:06:20 1999
@@ -648,7 +648,7 @@
 
 
 static void
-do_mcd_request(void)
+do_mcd_request(request_queue_t * q)
 {
 #ifdef TEST2
   printk(" do_mcd_request(%ld+%ld)\n", CURRENT -> sector, CURRENT -> nr_sectors);
@@ -1179,7 +1179,7 @@
 	}
 
 	blksize_size[MAJOR_NR] = mcd_blocksizes;
-	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
 	read_ahead[MAJOR_NR] = 4;
 
 	/* check for card */
diff -u -r linux.clean/drivers/cdrom/mcdx.c linux.new2/drivers/cdrom/mcdx.c
--- linux.clean/drivers/cdrom/mcdx.c	Wed Jul 28 18:24:15 1999
+++ linux.new2/drivers/cdrom/mcdx.c	Wed Jul 28 19:06:21 1999
@@ -208,7 +208,7 @@
 
 /* declared in blk.h */
 int mcdx_init(void);
-void do_mcdx_request(void);
+void do_mcdx_request(request_queue_t * q);
 
 /* already declared in init/main */
 void mcdx_setup(char *, int *);
@@ -521,7 +521,7 @@
 	}
 }
 
-void do_mcdx_request()
+void do_mcdx_request(request_queue_t * q)
 {
     int dev;
     struct s_drive_stuff *stuffp;
@@ -1116,7 +1116,7 @@
 		return 1;
 	}
 
-	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
 	read_ahead[MAJOR_NR] = READ_AHEAD;
 	blksize_size[MAJOR_NR] = mcdx_blocksizes;
 
diff -u -r linux.clean/drivers/cdrom/optcd.c linux.new2/drivers/cdrom/optcd.c
--- linux.clean/drivers/cdrom/optcd.c	Wed Jul 28 18:24:15 1999
+++ linux.new2/drivers/cdrom/optcd.c	Wed Jul 28 19:06:21 1999
@@ -1360,7 +1360,7 @@
 }
 
 
-static void do_optcd_request(void)
+static void do_optcd_request(request_queue_t * q)
 {
 	DEBUG((DEBUG_REQUEST, "do_optcd_request(%ld+%ld)",
 	       CURRENT -> sector, CURRENT -> nr_sectors));
@@ -2067,7 +2067,7 @@
 
 	hardsect_size[MAJOR_NR] = &hsecsize;
 	blksize_size[MAJOR_NR] = &blksize;
-	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
 	read_ahead[MAJOR_NR] = 4;
 	request_region(optcd_port, 4, "optcd");
 
diff -u -r linux.clean/drivers/cdrom/sbpcd.c linux.new2/drivers/cdrom/sbpcd.c
--- linux.clean/drivers/cdrom/sbpcd.c	Wed Jul 28 18:24:15 1999
+++ linux.new2/drivers/cdrom/sbpcd.c	Wed Jul 28 19:06:21 1999
@@ -4794,7 +4794,7 @@
 /*
  *  I/O request routine, called from Linux kernel.
  */
-static void DO_SBPCD_REQUEST(void)
+static void DO_SBPCD_REQUEST(request_queue_t * q)
 {
 	u_int block;
 	u_int nsect;
@@ -5725,7 +5725,7 @@
 		goto init_done;
 #endif MODULE
 	}
-	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
 	read_ahead[MAJOR_NR] = buffers * (CD_FRAMESIZE / 512);
 	
 	request_region(CDo_command,4,major_name);
diff -u -r linux.clean/drivers/cdrom/sjcd.c linux.new2/drivers/cdrom/sjcd.c
--- linux.clean/drivers/cdrom/sjcd.c	Wed Jul 28 18:24:15 1999
+++ linux.new2/drivers/cdrom/sjcd.c	Wed Jul 28 19:06:21 1999
@@ -1272,7 +1272,7 @@
   SJCD_SET_TIMER( sjcd_poll, 1 );
 }
 
-static void do_sjcd_request( void ){
+static void do_sjcd_request( request_queue_t * q ){
 #if defined( SJCD_TRACE )
   printk( "SJCD: do_sjcd_request(%ld+%ld)\n",
 	 CURRENT->sector, CURRENT->nr_sectors );
@@ -1475,7 +1475,7 @@
     return( -EIO );
   }
   
-  blk_dev[ MAJOR_NR ].request_fn = DEVICE_REQUEST;
+  blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
   read_ahead[ MAJOR_NR ] = 4;
   
   if( check_region( sjcd_base, 4 ) ){
diff -u -r linux.clean/drivers/cdrom/sonycd535.c linux.new2/drivers/cdrom/sonycd535.c
--- linux.clean/drivers/cdrom/sonycd535.c	Wed Jul 28 18:24:15 1999
+++ linux.new2/drivers/cdrom/sonycd535.c	Wed Jul 28 19:06:21 1999
@@ -781,7 +781,7 @@
  * data access on a CD is done sequentially, this saves a lot of operations.
  */
 static void
-do_cdu535_request(void)
+do_cdu535_request(request_queue_t * q)
 {
 	unsigned int dev;
 	unsigned int read_size;
@@ -1599,7 +1599,7 @@
 							MAJOR_NR, CDU535_MESSAGE_NAME);
 					return -EIO;
 				}
-				blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+				blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
 				blksize_size[MAJOR_NR] = &sonycd535_block_size;
 				read_ahead[MAJOR_NR] = 8;	/* 8 sector (4kB) read-ahead */
 
diff -u -r linux.clean/drivers/i2o/i2o_block.c linux.new2/drivers/i2o/i2o_block.c
--- linux.clean/drivers/i2o/i2o_block.c	Wed Jul 28 18:24:19 1999
+++ linux.new2/drivers/i2o/i2o_block.c	Wed Jul 28 19:06:21 1999
@@ -96,7 +96,7 @@
 
 static int i2ob_install_device(struct i2o_controller *, struct i2o_device *, int);
 static void i2ob_end_request(struct request *);
-static void do_i2ob_request(void);
+static void do_i2ob_request(request_queue_t * q);
 
 /*
  *	Get a message
@@ -314,7 +314,7 @@
 	 */
 	 
 	atomic_dec(&queue_depth);
-	do_i2ob_request();
+	do_i2ob_request(NULL);
 	spin_unlock(&i2ob_lock);
 	spin_unlock(&io_request_lock);
 }
@@ -359,7 +359,7 @@
  *	we use it.
  */
 
-static void do_i2ob_request(void)
+static void do_i2ob_request(request_queue_t * q)
 {
 	struct request *req;
 	int unit;
@@ -415,7 +415,7 @@
 {
 	unsigned long flags;
 	spin_lock_irqsave(&i2ob_lock, flags);
-	do_i2ob_request();
+	do_i2ob_request(NULL);
 	spin_unlock_irqrestore(&i2ob_lock, flags);
 }	
 
@@ -995,7 +995,9 @@
 	blk_size[MAJOR_NR] = i2ob_sizes;
 	max_sectors[MAJOR_NR] = i2ob_max_sectors;
 	
-	blk_dev[MAJOR_NR].request_fn = i2ob_request;
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), i2ob_request);
+        blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0);
+
 	for (i = 0; i < MAX_I2OB << 4; i++) {
 		i2ob_dev[i].refcnt = 0;
 		i2ob_dev[i].flags = 0;
diff -u -r linux.clean/drivers/scsi/Config.in linux.new2/drivers/scsi/Config.in
--- linux.clean/drivers/scsi/Config.in	Wed Jun  9 19:59:15 1999
+++ linux.new2/drivers/scsi/Config.in	Wed Jul 28 19:22:39 1999
@@ -10,6 +10,11 @@
 
 comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
 
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  bool 'Use new SCSI queueing code' CONFIG_SCSI_NEW_QUEUES
+  bool 'Enable extra checks in new queueing code' CONFIG_SCSI_DEBUG_QUEUES
+fi
+
 bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN
 
 bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS
diff -u -r linux.clean/drivers/scsi/Makefile linux.new2/drivers/scsi/Makefile
--- linux.clean/drivers/scsi/Makefile	Thu Apr 29 14:53:41 1999
+++ linux.new2/drivers/scsi/Makefile	Wed Jul 28 19:22:39 1999
@@ -40,8 +40,8 @@
     OX_OBJS  := scsi_syms.o
   endif
   L_OBJS += scsi_n_syms.o hosts.o scsi_ioctl.o constants.o scsicam.o
-  L_OBJS += scsi_error.o scsi_obsolete.o scsi_queue.o
-  L_OBJS += scsi_proc.o
+  L_OBJS += scsi_error.o scsi_obsolete.o scsi_queue.o scsi_lib.o 
+  L_OBJS += scsi_merge.o scsi_proc.o
 else
   ifeq ($(CONFIG_SCSI),m)
     MIX_OBJS += scsi_syms.o
@@ -659,10 +659,11 @@
 	$(CC) $(CFLAGS) -c megaraid.c
 
 scsi_mod.o: $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o \
-		scsicam.o scsi_proc.o scsi_error.o scsi_obsolete.o scsi_queue.o
+		scsicam.o scsi_proc.o scsi_error.o scsi_obsolete.o \
+		scsi_queue.o scsi_lib.o scsi_merge.o
 	$(LD) $(LD_RFLAG) -r -o $@ $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o \
-		constants.o scsicam.o scsi_proc.o               \
-		scsi_error.o scsi_obsolete.o scsi_queue.o \
+		constants.o scsicam.o scsi_proc.o scsi_merge.o     \
+		scsi_error.o scsi_obsolete.o scsi_queue.o scsi_lib.o
 
 sr_mod.o: sr.o sr_ioctl.o sr_vendor.o
 	$(LD) $(LD_RFLAG) -r -o $@ sr.o sr_ioctl.o sr_vendor.o
diff -u -r linux.clean/drivers/scsi/aha1542.c linux.new2/drivers/scsi/aha1542.c
--- linux.clean/drivers/scsi/aha1542.c	Wed Oct  7 18:52:55 1998
+++ linux.new2/drivers/scsi/aha1542.c	Wed Jul 28 19:22:39 1999
@@ -1255,7 +1255,13 @@
      * check for timeout, and if we are doing something like this
      * we are pretty desperate anyways.
      */
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    spin_unlock_irq(&io_request_lock);
+#endif
     scsi_sleep(4*HZ);
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    spin_lock_irq(&io_request_lock);
+#endif
 
     WAIT(STATUS(SCpnt->host->io_port), 
 	 STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
@@ -1322,7 +1328,13 @@
      * check for timeout, and if we are doing something like this
      * we are pretty desperate anyways.
      */
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    spin_unlock_irq(&io_request_lock);
+#endif
     scsi_sleep(4*HZ);
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    spin_lock_irq(&io_request_lock);
+#endif
 
     WAIT(STATUS(SCpnt->host->io_port), 
 	 STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
diff -u -r linux.clean/drivers/scsi/gdth_proc.c linux.new2/drivers/scsi/gdth_proc.c
--- linux.clean/drivers/scsi/gdth_proc.c	Wed May 12 16:27:37 1999
+++ linux.new2/drivers/scsi/gdth_proc.c	Wed Jul 28 19:22:39 1999
@@ -938,10 +938,14 @@
     scp->request.rq_status = RQ_SCSI_BUSY;
     scp->request.sem = &sem;
     scp->SCp.this_residual = IOCTL_PRI;
+#ifndef CONFIG_SCSI_NEW_QUEUES
     GDTH_LOCK_SCSI_DOCMD();
+#endif
     scsi_do_cmd(scp, cmnd, gdtcmd, sizeof(gdth_cmd_str), 
                 gdth_scsi_done, timeout*HZ, 1);
+#ifndef CONFIG_SCSI_NEW_QUEUES
     GDTH_UNLOCK_SCSI_DOCMD();
+#endif
     down(&sem);
 }
 
diff -u -r linux.clean/drivers/scsi/hosts.c linux.new2/drivers/scsi/hosts.c
--- linux.clean/drivers/scsi/hosts.c	Tue May 11 17:37:40 1999
+++ linux.new2/drivers/scsi/hosts.c	Sun Sep  5 09:07:37 1999
@@ -657,8 +657,10 @@
     atomic_set(&retval->host_active,0);
     retval->host_busy = 0;
     retval->host_failed = 0;
+#ifndef CONFIG_SCSI_NEW_QUEUES
     retval->block = NULL;
     retval->wish_block = 0;
+#endif
     if(j > 0xffff) panic("Too many extra bytes requested\n");
     retval->extra_bytes = j;
     retval->loaded_as_module = scsi_loadable_module_flag;
@@ -684,11 +686,18 @@
     retval->ehandler = NULL;    /* Initial value until the thing starts up. */
     retval->eh_notify   = NULL;    /* Who we notify when we exit. */
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
     /*
      * Initialize the fields used for mid-level queueing.
      */
     retval->pending_commands = NULL;
+#endif
+
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    retval->host_blocked = FALSE;
+#else
     retval->host_busy = FALSE;
+#endif
 
 #ifdef DEBUG
     printk("Register %x %x: %d\n", (int)retval, (int)retval->hostt, j);
@@ -744,6 +753,7 @@
 
             kernel_thread((int (*)(void *))scsi_error_handler, 
                           (void *) shpnt, 0);
+
             /*
              * Now wait for the kernel error thread to initialize itself
              * as it might be needed when we scan the bus.
@@ -834,7 +844,9 @@
     printk ("scsi : %d host%s.\n", next_scsi_host,
 	    (next_scsi_host == 1) ? "" : "s");
     
+#ifndef CONFIG_SCSI_NEW_QUEUES
     scsi_make_blocked_list();
+#endif
     
     /* Now attach the high level drivers */
 #ifdef CONFIG_BLK_DEV_SD
diff -u -r linux.clean/drivers/scsi/hosts.h linux.new2/drivers/scsi/hosts.h
--- linux.clean/drivers/scsi/hosts.h	Mon Sep  6 04:50:28 1999
+++ linux.new2/drivers/scsi/hosts.h	Sun Sep  5 15:25:00 1999
@@ -1,6 +1,6 @@
 /*
  *  hosts.h Copyright (C) 1992 Drew Eckhardt
- *          Copyright (C) 1993, 1994, 1995 Eric Youngdale
+ *          Copyright (C) 1993, 1994, 1995, 1998, 1999 Eric Youngdale
  *
  *  mid to low-level SCSI driver interface header
  *      Initial versions: Drew Eckhardt
@@ -8,7 +8,7 @@
  *
  *  <drew@colorado.edu>
  *
- *	 Modified by Eric Youngdale eric@aib.com to
+ *	 Modified by Eric Youngdale eric@andante.org to
  *	 add scatter-gather, multiple outstanding request, and other
  *	 enhancements.
  *
@@ -297,6 +297,8 @@
      */
     struct Scsi_Host      * next;
     Scsi_Device           * host_queue;
+
+#ifndef CONFIG_SCSI_NEW_QUEUES
     /*
      * List of commands that have been rejected because either the host
      * or the device was busy.  These need to be retried relatively quickly,
@@ -304,6 +306,7 @@
      * is available.
      */
     Scsi_Cmnd             * pending_commands;
+#endif
 
     struct task_struct    * ehandler;  /* Error recovery thread. */
     struct semaphore      * eh_wait;   /* The error recovery thread waits on
@@ -336,6 +339,7 @@
     unsigned int max_lun;
     unsigned int max_channel;
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
     /*
      * Pointer to a circularly linked list - this indicates the hosts
      * that should be locked out of performing I/O while we have an active
@@ -343,6 +347,7 @@
      */
     struct Scsi_Host * block;
     unsigned wish_block:1;
+#endif
 
     /* These parameters should be set by the detect routine */
     unsigned char *base;
@@ -387,9 +392,16 @@
      * Host uses correct SCSI ordering not PC ordering. The bit is
      * set for the minority of drivers whose authors actually read the spec ;)
      */
-
     unsigned reverse_ordering:1;
-    
+
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    /*
+     * Indicates that one or more devices on this host were starved, and
+     * when the device becomes less busy that we need to feed them.
+     */
+    unsigned some_device_starved:1;
+#endif
+   
     void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *);
 
     /*
@@ -408,7 +420,6 @@
 
 extern void build_proc_dir_entries(Scsi_Host_Template  *);
 
-
 /*
  *  scsi_init initializes the scsi hosts.
  */
@@ -452,6 +463,9 @@
     void (*finish)(void);	  /* Perform initialization after attachment */
     int (*attach)(Scsi_Device *); /* Attach devices to arrays */
     void (*detach)(Scsi_Device *);
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    int (*init_command)(Scsi_Cmnd *);     /* Used by new queueing code. */
+#endif
 };
 
 extern struct Scsi_Device_Template sd_template;
diff -u -r linux.clean/drivers/scsi/scsi.c linux.new2/drivers/scsi/scsi.c
--- linux.clean/drivers/scsi/scsi.c	Tue Jun  8 13:41:03 1999
+++ linux.new2/drivers/scsi/scsi.c	Sun Sep  5 09:07:40 1999
@@ -313,6 +313,7 @@
     return 0;
 }
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
 /*
  * Function:    scsi_make_blocked_list
  *
@@ -392,6 +393,7 @@
     }
 
 }
+#endif
 
 static void scan_scsis_done (Scsi_Cmnd * SCpnt)
 {
@@ -457,6 +459,18 @@
   SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);
   memset (SDpnt, 0, sizeof (Scsi_Device));
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+  /*
+   * Register the queue for the device.  All I/O requests will come
+   * in through here.  We also need to register a pointer to
+   * ourselves, since the queue handler won't know what device
+   * the queue actually represents.   We could look it up, but it
+   * is pointless work.
+   */
+  blk_init_queue(&SDpnt->request_queue, scsi_request_fn);
+  blk_queue_headactive(&SDpnt->request_queue, 0);
+  SDpnt->request_queue.queuedata = (void *) SDpnt;
+#endif
 
   /* Make sure we have something that is valid for DMA purposes */
   scsi_result = ( ( !shpnt->unchecked_isa_dma )
@@ -476,6 +490,10 @@
   SDpnt->host = shpnt;
   SDpnt->online = TRUE;
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+  initialize_merge_fn(SDpnt);
+#endif
+
   init_waitqueue_head(&SDpnt->device_wait);
 
   /*
@@ -520,7 +538,9 @@
     for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
         if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
             oldSDpnt->scsi_request_fn = NULL;
+#endif
             for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
                 if(sdtpnt->attach) {
 		  (*sdtpnt->attach)(oldSDpnt);
@@ -651,9 +671,12 @@
    * Assume that the device will have handshaking problems, and then fix this
    * field later if it turns out it doesn't
    */
-  SDpnt->borken = 1;
-  SDpnt->was_reset = 0;
+  SDpnt->borken          = 1;
+  SDpnt->was_reset       = 0;
   SDpnt->expecting_cc_ua = 0;
+#ifdef CONFIG_SCSI_NEW_QUEUES
+  SDpnt->starved         = 0;
+#endif
 
   scsi_cmd[0] = TEST_UNIT_READY;
   scsi_cmd[1] = lun << 5;
@@ -668,11 +691,15 @@
     DECLARE_MUTEX_LOCKED(sem);
     SCpnt->request.sem = &sem;
     SCpnt->request.rq_status = RQ_SCSI_BUSY;
+#ifndef CONFIG_SCSI_NEW_QUEUES
     spin_lock_irq(&io_request_lock);
+#endif
     scsi_do_cmd (SCpnt, (void *) scsi_cmd,
                  (void *) NULL,
                  0, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5);
+#ifndef CONFIG_SCSI_NEW_QUEUES
     spin_unlock_irq(&io_request_lock);
+#endif
     down (&sem);
     SCpnt->request.sem = NULL;
   }
@@ -711,11 +738,15 @@
     DECLARE_MUTEX_LOCKED(sem);
     SCpnt->request.sem = &sem;
     SCpnt->request.rq_status = RQ_SCSI_BUSY;
+#ifndef CONFIG_SCSI_NEW_QUEUES
     spin_lock_irq(&io_request_lock);
+#endif
     scsi_do_cmd (SCpnt, (void *) scsi_cmd,
                  (void *) scsi_result,
                  256, scan_scsis_done, SCSI_TIMEOUT, 3);
+#ifndef CONFIG_SCSI_NEW_QUEUES
     spin_unlock_irq(&io_request_lock);
+#endif
     down (&sem);
     SCpnt->request.sem = NULL;
   }
@@ -857,11 +888,15 @@
       DECLARE_MUTEX_LOCKED(sem);
       SCpnt->request.rq_status = RQ_SCSI_BUSY;
       SCpnt->request.sem = &sem;
+#ifndef CONFIG_SCSI_NEW_QUEUES
       spin_lock_irq(&io_request_lock);
+#endif
       scsi_do_cmd (SCpnt, (void *) scsi_cmd,
                    (void *) scsi_result, 0x2a,
                    scan_scsis_done, SCSI_TIMEOUT, 3);
+#ifndef CONFIG_SCSI_NEW_QUEUES
       spin_unlock_irq(&io_request_lock);
+#endif
       down (&sem);
       SCpnt->request.sem = NULL;
     }
@@ -888,6 +923,21 @@
 
   memset (SDpnt, 0, sizeof (Scsi_Device));
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+  /*
+   * Register the queue for the device.  All I/O requests will come
+   * in through here.  We also need to register a pointer to
+   * ourselves, since the queue handler won't know what device
+   * the queue actually represents.   We could look it up, but it
+   * is pointless work.
+   */
+  blk_init_queue(&SDpnt->request_queue, scsi_request_fn);
+  blk_queue_headactive(&SDpnt->request_queue, 0);
+  SDpnt->request_queue.queuedata = (void *) SDpnt;
+  SDpnt->host = shpnt;
+  initialize_merge_fn(SDpnt);
+#endif
+
   /*
    * And hook up our command block to the new device we will be testing
    * for.
@@ -977,7 +1027,7 @@
  * turned off when entering the routine.  It is the responsibility
  * of the calling code to ensure that this is the case.
  */
-
+#ifndef CONFIG_SCSI_NEW_QUEUES
 Scsi_Cmnd * scsi_request_queueable (struct request * req, Scsi_Device * device)
 {
     Scsi_Cmnd * SCpnt = NULL;
@@ -1091,6 +1141,7 @@
 
     return SCpnt;
 }
+#endif
 
 /* This function returns a structure pointer that will be valid for
  * the device.  The wait parameter tells us whether we should wait for
@@ -1101,7 +1152,134 @@
  * scsi_request_queueable function also knows the internal allocation scheme
  * of the packets for each device
  */
+#ifdef CONFIG_SCSI_NEW_QUEUES
+/*
+ * This lock protects the freelist for all devices on the system.
+ * We could make this finer grained by having a single lock per
+ * device if it is ever found that there is excessive contention
+ * on this lock.
+ */
+static spinlock_t device_request_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Used for access to internal allocator used for DMA safe buffers.
+ */
+static spinlock_t allocator_request_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Used to protect insertion into and removal from the queue of
+ * commands to be processed by the bottom half handler.
+ */
+static spinlock_t scsi_bhqueue_lock      = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Function:    scsi_allocate_device
+ *
+ * Purpose:     Allocate a command descriptor.
+ *
+ * Arguments:   device    - device for which we want a command descriptor
+ *		wait      - 1 if we should wait in the event that none
+ *                          are available.
+ *
+ * Lock status: No locks assumed to be held.  This function is SMP-safe.
+ *
+ * Returns:     Pointer to command descriptor.
+ *
+ * Notes:	Prior to the new queue code, this function was not SMP-safe.
+ */
+Scsi_Cmnd * scsi_allocate_device (Scsi_Device * device, int wait)
+{
+    struct Scsi_Host * host;
+    Scsi_Cmnd * SCpnt = NULL;
+    unsigned long flags;
+
+    if (!device)
+	panic ("No device passed to scsi_allocate_device().\n");
+
+    host = device->host;
+
+    spin_lock_irqsave(&device_request_lock, flags);
+
+    while(1==1)
+    {
+        SCpnt = NULL;
+        if( !device->device_blocked )
+        {
+            if (!device->single_lun) 
+            {
+                for(SCpnt = device->device_queue; SCpnt; SCpnt = SCpnt->next)
+                {
+                    if(SCpnt->request.rq_status == RQ_INACTIVE) break;
+                }
+            }
+            else
+            {
+                /*
+                 * FIXME(eric) - the single_lun code is broken.  Each
+                 * device has it's own list of commands, and seaching this
+                 * device won't find commands active on another lun
+                 */
+                panic("single_lun not supported");
+            }
+        }
 
+        /*
+         * If we couldn't find a free command block, and we have been
+         * asked to wait, then do so.
+         */
+        if (SCpnt)
+        {
+            break;
+        }
+         
+        /*
+         * If we have been asked to wait for a free block, then
+         * wait here.
+         */
+        spin_unlock_irqrestore(&device_request_lock, flags);
+        if( wait )
+        {
+            /*
+             * This should block until a device command block
+             * becomes available.
+             */
+            sleep_on(&device->device_wait);
+            spin_lock_irqsave(&device_request_lock, flags);
+        }
+        else
+        {
+            return NULL;
+        }
+    }
+        
+    SCpnt->request.rq_status = RQ_SCSI_BUSY;
+    SCpnt->request.sem = NULL;   /* And no one is waiting for this
+                                  * to complete */
+    atomic_inc(&SCpnt->host->host_active); 
+    
+    SCpnt->use_sg = 0;            /* Reset the scatter-gather flag */
+    SCpnt->old_use_sg  = 0;
+    SCpnt->transfersize = 0;      /* No default transfer size */
+    SCpnt->cmd_len = 0;
+    
+    SCpnt->underflow = 0;         /* Do not flag underflow conditions */
+    SCpnt->state = SCSI_STATE_INITIALIZING;
+    SCpnt->owner = SCSI_OWNER_HIGHLEVEL;
+
+    spin_unlock_irq(&device_request_lock);
+
+    SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n", 
+                               SCpnt->target,
+                               atomic_read(&SCpnt->host->host_active)));
+
+    return SCpnt;
+}
+#else
+/*
+ * This is the old version of scsi_allocate_device that was used prior to
+ * the new queue code.   It is essentially unchanged, and it is *NOT*
+ * SMP-safe.
+ */
 Scsi_Cmnd * scsi_allocate_device (struct request ** reqp, Scsi_Device * device,
 			     int wait)
 {
@@ -1253,6 +1431,7 @@
 
     return SCpnt;
 }
+#endif
 
 /*
  * Function:    scsi_release_command
@@ -1268,6 +1447,11 @@
 void
 scsi_release_command(Scsi_Cmnd * SCpnt)
 {
+#ifdef CONFIG_SCSI_NEW_QUEUES
+  unsigned long flags;
+  spin_lock_irqsave(&device_request_lock, flags);
+#endif
+
   SCpnt->request.rq_status = RQ_INACTIVE;
   SCpnt->state = SCSI_STATE_UNUSED;
   SCpnt->owner = SCSI_OWNER_NOBODY;
@@ -1296,12 +1480,134 @@
                                  atomic_read(&SCpnt->host->eh_wait->count)));
       up(SCpnt->host->eh_wait);
   }
+
+#ifdef CONFIG_SCSI_NEW_QUEUES
+  spin_unlock_irqrestore(&device_request_lock, flags);
+#endif
 }
 
 /*
  * This is inline because we have stack problemes if we recurse to deeply.
  */
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+int scsi_dispatch_cmd (Scsi_Cmnd * SCpnt)
+{
+#ifdef DEBUG_DELAY
+    unsigned long clock;
+#endif
+    struct Scsi_Host   * host;
+    int                  rtn = 0;
+    unsigned long        timeout;
+
+    ASSERT_LOCK(&io_request_lock, 0);
+
+#if DEBUG
+    unsigned long *ret = 0;
+#ifdef __mips__
+    __asm__ __volatile__ ("move\t%0,$31":"=r"(ret));
+#else
+   ret =  __builtin_return_address(0);
+#endif
+#endif
+
+    host = SCpnt->host;
+
+    /* Assign a unique nonzero serial_number. */
+    if (++serial_number == 0) serial_number = 1;
+    SCpnt->serial_number = serial_number;
+
+    /*
+     * We will wait MIN_RESET_DELAY clock ticks after the last reset so
+     * we can avoid the drive not being ready.
+     */
+    timeout = host->last_reset + MIN_RESET_DELAY;
+
+    if (host->resetting && time_before(jiffies, timeout)) {
+	int ticks_remaining = timeout - jiffies;
+	/*
+	 * NOTE: This may be executed from within an interrupt
+	 * handler!  This is bad, but for now, it'll do.  The irq
+	 * level of the interrupt handler has been masked out by the
+	 * platform dependent interrupt handling code already, so the
+	 * sti() here will not cause another call to the SCSI host's
+	 * interrupt handler (assuming there is one irq-level per
+	 * host).
+	 */
+	while (--ticks_remaining >= 0) mdelay(1+999/HZ);
+	host->resetting = 0;
+    }
+
+    if( host->hostt->use_new_eh_code )
+      {
+        scsi_add_timer(SCpnt, SCpnt->timeout_per_command, scsi_times_out);
+      }
+    else
+      {
+        scsi_add_timer(SCpnt, SCpnt->timeout_per_command, 
+                            scsi_old_times_out);
+      }
+
+    /*
+     * We will use a queued command if possible, otherwise we will emulate the
+     * queuing and calling of completion function ourselves.
+     */
+    SCSI_LOG_MLQUEUE(3,printk("scsi_dispatch_cmnd (host = %d, channel = %d, target = %d, "
+	   "command = %p, buffer = %p, \nbufflen = %d, done = %p)\n",
+	   SCpnt->host->host_no, SCpnt->channel, SCpnt->target, SCpnt->cmnd,
+	   SCpnt->buffer, SCpnt->bufflen, SCpnt->done));
+
+    SCpnt->state = SCSI_STATE_QUEUED;
+    SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+    if (host->can_queue)
+    {
+	SCSI_LOG_MLQUEUE(3,printk("queuecommand : routine at %p\n",
+                                  host->hostt->queuecommand));
+        /*
+         * Use the old error handling code if we haven't converted the driver
+         * to use the new one yet.  Note - only the new queuecommand variant
+         * passes a meaningful return value.
+         */
+        if( host->hostt->use_new_eh_code )
+          {
+            rtn = host->hostt->queuecommand (SCpnt, scsi_done);
+            if( rtn != 0 )
+            {
+                scsi_delete_timer(SCpnt);
+                scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_HOST_BUSY);
+            }
+          }
+        else
+          {
+            host->hostt->queuecommand (SCpnt, scsi_old_done);
+          }
+    }
+    else
+    {
+	int temp;
+
+	SCSI_LOG_MLQUEUE(3,printk("command() :  routine at %p\n", host->hostt->command));
+	temp = host->hostt->command (SCpnt);
+	SCpnt->result = temp;
+#ifdef DEBUG_DELAY
+	clock = jiffies + 4 * HZ;
+	while (time_before(jiffies, clock)) barrier();
+	printk("done(host = %d, result = %04x) : routine at %p\n",
+	       host->host_no, temp, host->hostt->command);
+#endif
+        if( host->hostt->use_new_eh_code )
+          {
+            scsi_done(SCpnt);
+          }
+        else
+          {
+            scsi_old_done(SCpnt);
+          }
+    }
+    SCSI_LOG_MLQUEUE(3,printk("leaving scsi_dispatch_cmnd()\n"));
+    return rtn;
+}
+#else
 inline int internal_cmnd (Scsi_Cmnd * SCpnt)
 {
 #ifdef DEBUG_DELAY
@@ -1419,6 +1725,7 @@
     SCSI_LOG_MLQUEUE(3,printk("leaving internal_cmnd()\n"));
     return rtn;
 }
+#endif
 
 /*
  * scsi_do_cmd sends all the commands out to the low-level driver.  It
@@ -1427,6 +1734,32 @@
  * drivers go for the same host at the same time.
  */
 
+/*
+ * Function:    scsi_do_cmd
+ *
+ * Purpose:     Queue a SCSI command
+ *
+ * Arguments:   SCpnt     - command descriptor.
+ *		cmnd      - actual SCSI command to be performed.
+ *              buffer    - data buffer.
+ *              bufflen   - size of data buffer.
+ *              done      - completion function to be run.
+ *              timeout   - how long to let it run before timeout.
+ *              retries   - number of retries we allow.
+ *
+ * Lock status: With the new queueing code, this is SMP-safe, and no locks
+ *              need be held upon entry.   The old queueing code the lock was
+ *              assumed to be held upon entry.
+ *
+ * Returns:     Pointer to command descriptor.
+ *
+ * Notes:	Prior to the new queue code, this function was not SMP-safe.
+ *              Also, this function is now only used for queueing requests
+ *              for things like ioctls and character device requests - this
+ *              is because we essentially just inject a request into the
+ *              queue for the device. Normal block device handling manipulates
+ *              the queue directly.
+ */
 void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
 		  void *buffer, unsigned bufflen, void (*done)(Scsi_Cmnd *),
 		  int timeout, int retries)
@@ -1434,6 +1767,8 @@
     struct Scsi_Host * host = SCpnt->host;
     Scsi_Device      * device = SCpnt->device;
 
+    ASSERT_LOCK(&io_request_lock, 0);
+
     SCpnt->owner = SCSI_OWNER_MIDLEVEL;
 
 SCSI_LOG_MLQUEUE(4,
@@ -1464,6 +1799,7 @@
      * ourselves.
      */
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
     SCpnt->pid = scsi_pid++;
 
     while (SCSI_BLOCK((Scsi_Device *) NULL, host)) {
@@ -1473,6 +1809,7 @@
     }
 
     if (host->block) host_active = host;
+#endif
 
     host->host_busy++;
     device->device_busy++;
@@ -1513,39 +1850,73 @@
     SCpnt->internal_timeout = NORMAL_TIMEOUT;
     SCpnt->abort_reason = 0;
     SCpnt->result = 0;
+
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    /*
+     * At this point, we merely set up the command, stick it in the normal
+     * request queue, and return.  Eventually that request will come to the
+     * top of the list, and will be dispatched.
+     */
+    scsi_insert_special_cmd (SCpnt, 0);  
+#else
     internal_cmnd (SCpnt);
+#endif
 
     SCSI_LOG_MLQUEUE(3,printk ("Leaving scsi_do_cmd()\n"));
 }
 
-/* This function is the mid-level interrupt routine, which decides how
+/* 
+ * This function is the mid-level interrupt routine, which decides how
  *  to handle error conditions.  Each invocation of this function must
  *  do one and *only* one of the following:
  *
  *      1) Insert command in BH queue.
  *      2) Activate error handler for host.
  *
- * FIXME(eric) - I am concerned about stack overflow (still).  An interrupt could
- * come while we are processing the bottom queue, which would cause another command
- * to be stuffed onto the bottom queue, and it would in turn be processed as that
- * interrupt handler is returning.  Given a sufficiently steady rate of returning
- * commands, this could cause the stack to overflow.  I am not sure what is the most
- * appropriate solution here - we should probably keep a depth count, and not process
- * any commands while we still have a bottom handler active higher in the stack.
- *
- * There is currently code in the bottom half handler to monitor recursion in the bottom
- * handler and report if it ever happens.  If this becomes a problem, it won't be hard to
- * engineer something to deal with it so that only the outer layer ever does any real
- * processing.
+ * FIXME(eric) - I am concerned about stack overflow (still).  An
+ * interrupt could come while we are processing the bottom queue,
+ * which would cause another command to be stuffed onto the bottom
+ * queue, and it would in turn be processed as that interrupt handler
+ * is returning.  Given a sufficiently steady rate of returning
+ * commands, this could cause the stack to overflow.  I am not sure
+ * what is the most appropriate solution here - we should probably
+ * keep a depth count, and not process any commands while we still
+ * have a bottom handler active higher in the stack.
+ *
+ * There is currently code in the bottom half handler to monitor
+ * recursion in the bottom handler and report if it ever happens.  If
+ * this becomes a problem, it won't be hard to engineer something to
+ * deal with it so that only the outer layer ever does any real
+ * processing.  
  */
 void
 scsi_done (Scsi_Cmnd * SCpnt)
 {
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    unsigned long flags;
+    int           tstatus;
+#endif
 
   /*
    * We don't have to worry about this one timing out any more.
    */
+#ifdef CONFIG_SCSI_NEW_QUEUES
+  tstatus = scsi_delete_timer(SCpnt);
+
+  /*
+   * If we are unable to remove the timer, it means that the command
+   * has already timed out.  In this case, we have no choice but to
+   * let the timeout function run, as we have no idea where in fact
+   * that function could really be.  It might be on another processor,
+   * etc, etc.
+   */
+  if( !tstatus )
+  {
+      return;
+  }
+#else
   scsi_delete_timer(SCpnt);
+#endif
 
   /* Set the serial numbers back to zero */
   SCpnt->serial_number = 0;
@@ -1564,6 +1935,10 @@
       return;
     }
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+  spin_lock_irqsave(&scsi_bhqueue_lock, flags);
+#endif
+
   SCpnt->serial_number_at_timeout = 0;
   SCpnt->state = SCSI_STATE_BHQUEUE;
   SCpnt->owner = SCSI_OWNER_BH_HANDLER;
@@ -1579,6 +1954,10 @@
    * We already have the io_request_lock here, since we are called from the
    * interrupt handler or the error handler. (DB)
    *
+   * This may be true at the moment, but I would like to wean all of the low
+   * level drivers away from using io_request_lock.   Technically they should
+   * all use their own locking.  I am adding a small spinlock to protect
+   * this datastructure to make it safe for that day.  (ERY)
    */
   if (!scsi_bh_queue_head) {
   	scsi_bh_queue_head = SCpnt;
@@ -1587,6 +1966,9 @@
   	scsi_bh_queue_tail->bh_next = SCpnt;
   	scsi_bh_queue_tail = SCpnt;
   }
+#ifdef CONFIG_SCSI_NEW_QUEUES
+  spin_unlock_irqrestore(&scsi_bhqueue_lock, flags);
+#endif
 
   /*
    * Mark the bottom half handler to be run.
@@ -1609,6 +1991,13 @@
  * race condition when scsi_done is called after a command has already
  * timed out but before the time out is processed by the error handler.
  * (DB)
+ *
+ * I believe I have corrected this.  We simply monitor the return status of
+ * del_timer() - if this comes back as 0, it means that the timer has fired
+ * and that a timeout is in progress.   I have modified scsi_done() such
+ * that in this instance the command is never inserted in the bottom
+ * half queue.  Thus the only time we hold the lock here is when
+ * we wish to atomically remove the contents of the queue.
  */
 void scsi_bottom_half_handler(void)
 {
@@ -1616,15 +2005,25 @@
   Scsi_Cmnd        * SCnext;
   unsigned long      flags;
   
+#ifndef CONFIG_SCSI_NEW_QUEUES
   spin_lock_irqsave(&io_request_lock, flags);
+#endif
 
   while(1==1)
   {
+#ifdef CONFIG_SCSI_NEW_QUEUES
+      spin_lock_irqsave(&scsi_bhqueue_lock, flags);
+#endif
       SCpnt = scsi_bh_queue_head;
       scsi_bh_queue_head = NULL;
+#ifdef CONFIG_SCSI_NEW_QUEUES
+      spin_unlock_irqrestore(&scsi_bhqueue_lock, flags);
+#endif
       
       if( SCpnt == NULL ) {
+#ifndef CONFIG_SCSI_NEW_QUEUES
           spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
           return;
           }
       
@@ -1717,9 +2116,9 @@
       } /* for(; SCpnt...) */
 
   } /* while(1==1) */
-
+#ifndef CONFIG_SCSI_NEW_QUEUES
   spin_unlock_irqrestore(&io_request_lock, flags);
-
+#endif
 }
 
 /*
@@ -1741,9 +2140,13 @@
   SCpnt->request_bufflen = SCpnt->bufflen;
   SCpnt->use_sg = SCpnt->old_use_sg;
   SCpnt->cmd_len = SCpnt->old_cmd_len;
+#ifdef CONFIG_SCSI_NEW_QUEUES
+  return scsi_dispatch_cmd (SCpnt);
+#else
   SCpnt->result = 0;
   memset ((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer);
   return internal_cmnd (SCpnt);
+#endif
 }
 
 /*
@@ -1759,12 +2162,15 @@
     struct Scsi_Host * host;
     Scsi_Device * device;
 
+    ASSERT_LOCK(&io_request_lock, 0);
+
     host = SCpnt->host;
     device = SCpnt->device;
 
     host->host_busy--; /* Indicate that we are free */
     device->device_busy--; /* Decrement device usage counter. */
   
+#ifndef CONFIG_SCSI_NEW_QUEUES
     if (host->block && host->host_busy == 0) 
     {
         host_active = NULL;
@@ -1790,6 +2196,7 @@
     }
 
     wake_up(&host->host_wait);
+#endif
     
     /*
      * If we have valid sense information, then some kind of recovery
@@ -1817,16 +2224,47 @@
 static void scsi_unregister_host(Scsi_Host_Template *);
 #endif
 
+/*
+ * Function:    scsi_malloc
+ *
+ * Purpose:     Allocate memory from the DMA-safe pool.
+ *
+ * Arguments:   len       - amount of memory we need.
+ *
+ * Lock status: No locks assumed to be held.  This function is SMP-safe.
+ *
+ * Returns:     Pointer to memory block.
+ *
+ * Notes:	Prior to the new queue code, this function was not SMP-safe.
+ *              This function can only allocate in units of sectors
+ *              (i.e. 512 bytes).
+ *
+ *              We cannot use the normal system allocator becuase we need
+ *              to be able to guarantee that we can process a complete disk
+ *              I/O request without touching the system allocator.  Think
+ *              about it - if the system were heavily swapping, and tried to
+ *              write out a block of memory to disk, and the SCSI code needed
+ *              to allocate more memory in order to be able to write the
+ *              data to disk, you would wedge the system.
+ */
 void *scsi_malloc(unsigned int len)
 {
     unsigned int nbits, mask;
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    unsigned long flags;
+#endif
     int i, j;
+
     if(len % SECTOR_SIZE != 0 || len > PAGE_SIZE)
 	return NULL;
 
     nbits = len >> 9;
     mask = (1 << nbits) - 1;
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    spin_lock_irqsave(&allocator_request_lock, flags);
+#endif
+
     for(i=0;i < dma_sectors / SECTORS_PER_PAGE; i++)
 	for(j=0; j<=SECTORS_PER_PAGE - nbits; j++){
 	    if ((dma_malloc_freelist[i] & (mask << j)) == 0){
@@ -1836,15 +2274,43 @@
                 SCSI_LOG_MLQUEUE(3,printk("SMalloc: %d %p [From:%p]\n",len, dma_malloc_pages[i] + (j << 9)));
 		printk("SMalloc: %d %p [From:%p]\n",len, dma_malloc_pages[i] + (j << 9));
 #endif
+#ifdef CONFIG_SCSI_NEW_QUEUES
+                spin_unlock_irqrestore(&allocator_request_lock, flags);
+#endif
 		return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9));
 	    }
 	}
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    spin_unlock_irqrestore(&allocator_request_lock, flags);
+#endif
     return NULL;  /* Nope.  No more */
 }
 
+/*
+ * Function:    scsi_free
+ *
+ * Purpose:     Free memory into the DMA-safe pool.
+ *
+ * Arguments:   ptr       - data block we are freeing.
+ *              len       - size of block we are freeing.
+ *
+ * Lock status: No locks assumed to be held.  This function is SMP-safe.
+ *
+ * Returns:     Nothing
+ *
+ * Notes:	This function *must* only be used to free memory
+ *              allocated from scsi_malloc().
+ *
+ *              Prior to the new queue code, this function was not SMP-safe.
+ *              This function can only allocate in units of sectors
+ *              (i.e. 512 bytes).
+ */
 int scsi_free(void *obj, unsigned int len)
 {
     unsigned int page, sector, nbits, mask;
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    unsigned long flags;
+#endif
 
 #ifdef DEBUG
     unsigned long ret = 0;
@@ -1858,6 +2324,10 @@
     SCSI_LOG_MLQUEUE(3,printk("SFree: %p %d\n",obj, len));
 #endif
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    spin_lock_irqsave(&allocator_request_lock, flags);
+#endif
+
     for (page = 0; page < dma_sectors / SECTORS_PER_PAGE; page++) {
         unsigned long page_addr = (unsigned long) dma_malloc_pages[page];
         if ((unsigned long) obj >= page_addr &&
@@ -1881,6 +2351,9 @@
             }
             scsi_dma_free_sectors += nbits;
             dma_malloc_freelist[page] &= ~(mask << sector);
+#ifdef CONFIG_SCSI_NEW_QUEUES
+            spin_unlock_irqrestore(&allocator_request_lock, flags);
+#endif
             return 0;
 	}
     }
@@ -1933,10 +2406,17 @@
 
 void scsi_build_commandblocks(Scsi_Device * SDpnt)
 {
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    unsigned long flags;
+#endif
     struct Scsi_Host *host = SDpnt->host;
     int j;
     Scsi_Cmnd * SCpnt;
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    spin_lock_irqsave(&device_request_lock, flags);
+#endif
+
     if (SDpnt->queue_depth == 0)
         SDpnt->queue_depth = host->cmd_per_lun;
     SDpnt->device_queue = NULL;
@@ -1977,6 +2457,9 @@
 	/* Still problem if 0==j , continue anyway ... */
     }
     SDpnt->has_cmdblocks = 1;
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    spin_unlock_irqrestore(&device_request_lock, flags);
+#endif
 }
 
 #ifndef MODULE /* { */
@@ -2417,6 +2900,9 @@
                 HBA_ptr->host_queue = scd->next;
             }
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+            blk_cleanup_queue(&scd->request_queue);
+#endif
             scsi_init_free((char *) scd, sizeof(Scsi_Device));
         } else {
             return(-EBUSY);
@@ -2428,13 +2914,29 @@
 #endif
 
 /*
- * Go through the device list and recompute the most appropriate size
- * for the dma pool.  Then grab more memory (as required).
+ * Function:    resize_dma_pool
+ *
+ * Purpose:     Ensure that the DMA pool is sufficiently large to be
+ *              able to guarantee that we can always process I/O requests
+ *              without calling the system allocator.
+ *
+ * Arguments:   None.
+ *
+ * Lock status: No locks assumed to be held.  This function is SMP-safe.
+ *
+ * Returns:     Nothing
+ *
+ * Notes:	Prior to the new queue code, this function was not SMP-safe.
+ *              Go through the device list and recompute the most appropriate
+ *              size for the dma pool.  Then grab more memory (as required).
  */
 static void resize_dma_pool(void)
 {
     int i;
     unsigned long size;
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    unsigned long flags;
+#endif
     struct Scsi_Host * shpnt;
     struct Scsi_Host * host = NULL;
     Scsi_Device * SDpnt;
@@ -2443,6 +2945,10 @@
     unsigned int new_need_isa_buffer = 0;
     unsigned char ** new_dma_malloc_pages = NULL;
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    spin_lock_irqsave(&allocator_request_lock, flags);
+#endif
+
     if( !scsi_hostlist )
     {
 	/*
@@ -2463,6 +2969,9 @@
 	dma_malloc_freelist = NULL;
 	dma_sectors = 0;
 	scsi_dma_free_sectors = 0;
+#ifdef CONFIG_SCSI_NEW_QUEUES
+        spin_unlock_irqrestore(&allocator_request_lock, flags);
+#endif
 	return;
     }
     /* Next, check to see if we need to extend the DMA buffer pool */
@@ -2579,6 +3088,10 @@
     dma_sectors = new_dma_sectors;
     scsi_need_isa_buffer = new_need_isa_buffer;
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    spin_unlock_irqrestore(&allocator_request_lock, flags);
+#endif
+
 #ifdef DEBUG_INIT
     printk("resize_dma_pool: dma free sectors   = %d\n", scsi_dma_free_sectors);
     printk("resize_dma_pool: dma sectors        = %d\n", dma_sectors);
@@ -2659,8 +3172,8 @@
                 
                 shpnt->eh_notify = &sem;
                 kernel_thread((int (*)(void *))scsi_error_handler, 
-                              (void *) shpnt, 0);
-                
+                              (void *) shpnt, 0);                
+
                 /*
                  * Now wait for the kernel error thread to initialize itself
                  * as it might be needed when we scan the bus.
@@ -2690,7 +3203,9 @@
 	printk ("scsi : %d host%s.\n", next_scsi_host,
 		(next_scsi_host == 1) ? "" : "s");
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
 	scsi_make_blocked_list();
+#endif
 
 	/* The next step is to call scan_scsis here.  This generates the
 	 * Scsi_Devices entries
@@ -2921,6 +3436,9 @@
             }
             SDpnt->has_cmdblocks = 0;
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+            blk_cleanup_queue(&SDpnt->request_queue);
+#endif
             /* Next free up the Scsi_Device structures for this host */
             shpnt->host_queue = SDpnt->next;
 	    scsi_init_free((char *) SDpnt, sizeof (Scsi_Device));
@@ -2978,7 +3496,9 @@
 	    (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
 #endif
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
     scsi_make_blocked_list();
+#endif
 
     /* There were some hosts that were loaded at boot time, so we cannot
        do any more than this */
@@ -3211,12 +3731,11 @@
     i = 0;
     for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
     {
-        printk(" %d %d %d : %d %p\n",
+        printk(" %d %d %d : %d\n",
                shpnt->host_failed,
                shpnt->host_busy,
                atomic_read(&shpnt->host_active),
-               shpnt->host_blocked,
-               shpnt->pending_commands);
+               shpnt->host_blocked);
 
     }
 
@@ -3268,11 +3787,11 @@
             printk("Dump of pending block device requests\n");
             for(i=0; i<MAX_BLKDEV; i++)
             {
-                if(blk_dev[i].current_request)
+                if(blk_dev[i].request_queue.current_request)
                 {
                     struct request * req;
                     printk("%d: ", i);
-                    req = blk_dev[i].current_request;
+                    req = blk_dev[i].request_queue.current_request;
                     while(req) 
                     {
                         printk("(%s %d %ld %ld %ld) ",
@@ -3288,7 +3807,7 @@
             }
         }
     }
-    printk("wait_for_request = %p\n", wait_for_request);
+    printk("wait_for_request = %p\n", &wait_for_request);
 #endif /* CONFIG_SCSI_LOGGING */ /* } */
 #endif /* CONFIG_PROC_FS */
 }
diff -u -r linux.clean/drivers/scsi/scsi.h linux.new2/drivers/scsi/scsi.h
--- linux.clean/drivers/scsi/scsi.h	Mon Sep  6 09:03:51 1999
+++ linux.new2/drivers/scsi/scsi.h	Mon Sep  6 09:03:14 1999
@@ -1,13 +1,13 @@
 /*
  *  scsi.h Copyright (C) 1992 Drew Eckhardt 
- *         Copyright (C) 1993, 1994, 1995 Eric Youngdale
+ *         Copyright (C) 1993, 1994, 1995, 1998, 1999 Eric Youngdale
  *  generic SCSI package header file by
  *      Initial versions: Drew Eckhardt
  *      Subsequent revisions: Eric Youngdale
  *
  *  <drew@colorado.edu>
  *
- *       Modified by Eric Youngdale eric@aib.com to
+ *       Modified by Eric Youngdale eric@andante.org to
  *       add scatter-gather, multiple outstanding request, and other
  *       enhancements.
  */
@@ -49,6 +49,21 @@
 #endif
 
 /*
+ * Used for debugging the new queueing code.  We want to make sure
+ * that the lock state is consistent with design.  Only do this in
+ * the user space simulator.
+ */
+#define ASSERT_LOCK(_LOCK, _COUNT)
+
+#if defined(CONFIG_SCSI_NEW_QUEUES) && defined(__SMP__) && defined(CONFIG_USER_DEBUG)
+#undef ASSERT_LOCK
+#define ASSERT_LOCK(_LOCK,_COUNT)       \
+        { if( (_LOCK)->lock != _COUNT )   \
+                panic("Lock count inconsistent %s %d\n", __FILE__, __LINE__); \
+                                                                                       }
+#endif
+
+/*
  *  Use these to separate status msg and our bytes
  *
  *  These are set by:
@@ -378,19 +393,38 @@
 extern int  scsi_block_when_processing_errors(Scsi_Device *);
 extern void scsi_sleep(int);
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+/*
+ * Prototypes for functions in scsi_lib.c
+ */
+extern void initialize_merge_fn(Scsi_Device * SDpnt);
+extern void scsi_request_fn(request_queue_t * q);
+#endif
+
 /*
  *  scsi_abort aborts the current command that is executing on host host.
  *  The error code, if non zero is returned in the host byte, otherwise 
  *  DID_ABORT is returned in the hostbyte.
  */
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+extern int scsi_insert_special_cmd (Scsi_Cmnd * SCpnt, int);
+extern int scsi_dispatch_cmd (Scsi_Cmnd * SCpnt);
+#endif
+
 extern void scsi_do_cmd (Scsi_Cmnd *, const void *cmnd ,
 			 void *buffer, unsigned bufflen, 
 			 void (*done)(struct scsi_cmnd *),
 			 int timeout, int retries);
 
 
+extern void scsi_request_fn(request_queue_t * q);
+
+#ifdef CONFIG_SCSI_NEW_QUEUES
+extern Scsi_Cmnd * scsi_allocate_device(Scsi_Device *, int);
+#else
 extern Scsi_Cmnd * scsi_allocate_device(struct request **, Scsi_Device *, int);
+#endif
 
 extern Scsi_Cmnd * scsi_request_queueable(struct request *, Scsi_Device *);
 
@@ -421,9 +455,17 @@
     wait_queue_head_t device_wait;/* Used to wait if
                                                       device is busy */
     struct Scsi_Host   * host;
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    request_queue_t         request_queue;
+#endif
     volatile unsigned short device_busy;   /* commands actually active on low-level */
-    void              (* scsi_request_fn)(void);  /* Used to jumpstart things after an 
+#ifndef CONFIG_SCSI_NEW_QUEUES
+    void              (* scsi_request_fn)(request_queue_t *);  /* Used to jumpstart things after an 
                                      * ioctl */
+#else
+    int               (* scsi_init_io_fn)(Scsi_Cmnd *); /* Used to initialize
+                                                           new request */
+#endif
     Scsi_Cmnd          * device_queue;    /* queue of SCSI Command structures */
 
 /* public: */
@@ -431,6 +473,11 @@
 
     unsigned int manufacturer;      /* Manufacturer of device, for using 
 				     * vendor-specific cmd's */
+
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    unsigned sector_size;	    /* size in bytes */
+#endif
+
     int attached;                   /* # of high level drivers attached to 
 				     * this */
     int access_count;               /* Count of open channels/mounts */
@@ -468,6 +515,12 @@
     unsigned expecting_cc_ua:1;     /* Expecting a CHECK_CONDITION/UNIT_ATTN
                                      * because we did a bus reset. */
     unsigned device_blocked:1;      /* Device returned QUEUE_FULL. */
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    unsigned ten:1;		    /* support ten byte read / write */
+    unsigned remap:1;		    /* support remapping  */
+    unsigned starved:1;             /* unable to process commands because
+                                       host busy */
+#endif
 };
 
 
@@ -619,6 +672,16 @@
     unsigned long      pid;	   /* Process ID, starts at 0 */
 };
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+/*
+ *  Flag bits for the internal_timeout array
+ */
+#define NORMAL_TIMEOUT 0
+#define IN_ABORT  1
+#define IN_RESET  2
+#define IN_RESET2 4
+#define IN_RESET3 8
+#endif
 
 /*
  * Definitions and prototypes used for scsi mid-level queue.
@@ -630,9 +693,18 @@
 extern int scsi_mlqueue_finish(struct Scsi_Host * host, Scsi_Device * device);
 
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+extern Scsi_Cmnd * scsi_end_request(Scsi_Cmnd * SCpnt, int uptodate,
+                                    int sectors);
+
+extern void scsi_io_completion (Scsi_Cmnd *SCpnt, int good_sectors,
+			 int block_sectors);
+#endif
+
 #if defined(MAJOR_NR) && (MAJOR_NR != SCSI_TAPE_MAJOR)
 #include "hosts.h"
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
 static Scsi_Cmnd * end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors)
 {
     struct request * req;
@@ -685,7 +757,7 @@
     scsi_release_command(SCpnt);
     return NULL;
 }
-
+#endif
 
 /* This is just like INIT_REQUEST, but we need to be aware of the fact
  * that an interrupt may start another request, so we run this with interrupts
diff -u -r linux.clean/drivers/scsi/scsi_debug.c linux.new2/drivers/scsi/scsi_debug.c
--- linux.clean/drivers/scsi/scsi_debug.c	Mon Sep  6 11:02:50 1999
+++ linux.new2/drivers/scsi/scsi_debug.c	Mon Sep  6 11:03:06 1999
@@ -42,12 +42,14 @@
 #define NR_FAKE_DISKS   3
 #define N_HEAD          32
 #define N_SECTOR        64
-#define DISK_READONLY(TGT)      (1)
+#define DISK_READONLY(TGT)      (0)
 #define DISK_REMOVEABLE(TGT)    (1)
+#define DEVICE_TYPE(TGT) (TGT == 2 ? TYPE_TAPE : TYPE_DISK);
+
 
 /* Do not attempt to use a timer to simulate a real disk with latency */
 /* Only use this in the actual kernel, not in the simulator. */
-/* #define IMMEDIATE */
+#define IMMEDIATE
 
 /* Skip some consistency checking.  Good for benchmarking */
 #define SPEEDY
@@ -66,6 +68,7 @@
 /* Number of jiffies to wait before completing a command */
 #define DISK_SPEED     10
 #define CAPACITY (0x80000)
+#define SIZE(TGT) (TGT == 2 ? 2248 : 512)
 
 static int starts[] = {N_HEAD, N_HEAD * N_SECTOR, 50000, CAPACITY, 0};
 static int npart = 0;
@@ -244,6 +247,10 @@
 	SCpnt->result = 0;
 	done(SCpnt); 
 	return 0;
+    case START_STOP:
+	SCSI_LOG_LLQUEUE(3,printk("START_STOP\n"));
+	scsi_debug_errsts = 0;
+	break;
     case ALLOW_MEDIUM_REMOVAL:
 	if(cmd[4]) 
         {
@@ -258,7 +265,7 @@
     case INQUIRY:
 	SCSI_LOG_LLQUEUE(3,printk("Inquiry...(%p %d)\n", buff, bufflen));
 	memset(buff, 0, bufflen);
-	buff[0] = TYPE_DISK;
+	buff[0] = DEVICE_TYPE(target);
 	buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0;  /* Removable disk */
 	buff[2] = 1;
 	buff[4] = 33 - 5;
@@ -281,7 +288,10 @@
 	buff[1] = (CAPACITY >> 16) & 0xff;
 	buff[2] = (CAPACITY >> 8) & 0xff;
 	buff[3] = CAPACITY & 0xff;
-	buff[6] = 2; /* 512 byte sectors */
+        buff[4] = 0;
+        buff[5] = 0;
+	buff[6] = (SIZE(target) >> 8) & 0xff; /* 512 byte sectors */
+        buff[7] = SIZE(target) & 0xff;
 	scsi_debug_errsts = 0;
 	break;
     case READ_10:
@@ -465,6 +475,8 @@
     if( !scsi_debug_lockup )
     {
         SCpnt->result = scsi_debug_errsts;
+        SCint[i]   = SCpnt;
+        do_done[i] = done;
         scsi_debug_intr_handle(i);  /* No timer - do this one right away */
     }
     restore_flags(flags);
@@ -691,7 +703,22 @@
 	len = length;
     
     return(len);
+
 }
+#ifdef CONFIG_USER_DEBUG
+/*
+ * This is a hack for the user space emulator.  It allows us to
+ * "insert" arbitrary numbers of additional drivers.
+ */
+void * scsi_debug_get_handle(void)
+{
+     static Scsi_Host_Template driver_copy = SCSI_DEBUG;
+     void * rtn;
+     rtn = kmalloc(sizeof(driver_copy), GFP_ATOMIC);
+     memcpy(rtn, (void *) &driver_copy, sizeof(driver_copy));
+     return rtn;
+}
+#endif
 
 #ifdef MODULE
 /* Eventually this will go into an include file, but this will be later */
diff -u -r linux.clean/drivers/scsi/scsi_debug.h linux.new2/drivers/scsi/scsi_debug.h
--- linux.clean/drivers/scsi/scsi_debug.h	Mon Dec 28 01:19:23 1998
+++ linux.new2/drivers/scsi/scsi_debug.h	Wed Jul 28 19:22:39 1999
@@ -34,9 +34,9 @@
 		    bios_param:        scsi_debug_biosparam,	\
 		    can_queue:         SCSI_DEBUG_CANQUEUE,	\
 		    this_id:           7,			\
-		    sg_tablesize:      SG_ALL,			\
+		    sg_tablesize:      16,			\
 		    cmd_per_lun:       3,			\
-		    unchecked_isa_dma: 1,			\
+		    unchecked_isa_dma: 0,			\
 		    use_clustering:    ENABLE_CLUSTERING,	\
 		    use_new_eh_code:   1,			\
 }
diff -u -r linux.clean/drivers/scsi/scsi_error.c linux.new2/drivers/scsi/scsi_error.c
--- linux.clean/drivers/scsi/scsi_error.c	Wed Jun 16 22:26:27 1999
+++ linux.new2/drivers/scsi/scsi_error.c	Sun Sep  5 09:05:03 1999
@@ -127,7 +127,9 @@
  *
  * Arguments:   SCset   - command that we are canceling timer for.
  *
- * Returns:     Amount of time remaining before command would have timed out.
+ * Returns:     1 if we were able to detach the timer.  0 if we
+ *              blew it, and the timer function has already started
+ *              to run.
  *
  * Notes:	This should be turned into an inline function.
  */
@@ -136,8 +138,12 @@
 {
   int rtn;
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
   rtn = jiffies - SCset->eh_timeout.expires;
   del_timer(&SCset->eh_timeout);
+#else
+  rtn = del_timer(&SCset->eh_timeout);
+#endif
 
   SCSI_LOG_ERROR_RECOVERY(5,printk("Clearing timer for command %p\n", SCset));
 
@@ -572,9 +578,13 @@
     
     add_timer(&timer);
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
     spin_unlock_irq(&io_request_lock);
+#endif
     down(&sem);
+#ifndef CONFIG_SCSI_NEW_QUEUES
     spin_lock_irq(&io_request_lock);
+#endif
     
     del_timer(&timer);
 }
@@ -844,7 +854,14 @@
    * If we had a successful bus reset, mark the command blocks to expect
    * a condition code of unit attention.
    */
+
+#ifdef CONFIG_SCSI_NEW_QUEUES
+  spin_unlock_irq(&io_request_lock);
+#endif
   scsi_sleep(BUS_RESET_SETTLE_TIME);
+#ifdef CONFIG_SCSI_NEW_QUEUES
+  spin_lock_irq(&io_request_lock);
+#endif
   if( SCpnt->eh_state == SUCCESS )
     {
       Scsi_Device * SDloop;
@@ -893,7 +910,13 @@
      * If we had a successful host reset, mark the command blocks to expect
      * a condition code of unit attention.
      */
+#ifdef CONFIG_SCSI_NEW_QUEUES
+  spin_unlock_irq(&io_request_lock);
+#endif
     scsi_sleep(HOST_RESET_SETTLE_TIME);
+#ifdef CONFIG_SCSI_NEW_QUEUES
+  spin_lock_irq(&io_request_lock);
+#endif
     if( SCpnt->eh_state == SUCCESS )
     {
         Scsi_Device * SDloop;
@@ -1244,6 +1267,9 @@
 scsi_restart_operations(struct Scsi_Host * host)
 {
   Scsi_Device * SDpnt;
+#ifdef CONFIG_SCSI_NEW_QUEUES
+  unsigned long flags;
+#endif
 
   /*
    * Next free up anything directly waiting upon the host.  This will be
@@ -1254,6 +1280,28 @@
 
    wake_up(&host->host_wait);
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+   /*
+    * Finally we need to re-initiate requests that may be pending.  We will
+    * have had everything blocked while error handling is taking place, and
+    * now that error recovery is done, we will need to ensure that these
+    * requests are started.
+    */
+   spin_lock_irqsave(&io_request_lock, flags);
+   for( SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next )
+   {
+       request_queue_t  * q;
+       if(    (host->can_queue > 0 && (host->host_busy >= host->can_queue))
+	    || (host->host_blocked) 
+	    || (SDpnt->device_blocked) )
+       {
+           break;
+       }
+       q = &SDpnt->request_queue;
+       q->request_fn(q);
+   }
+   spin_unlock_irqrestore(&io_request_lock, flags);
+#else
    /*
     * Finally, block devices need an extra kick in the pants.  This is because
     * the request queueing mechanism may have queued lots of pending requests
@@ -1266,8 +1314,9 @@
        SCSI_LOG_ERROR_RECOVERY(5,printk("Calling request function to restart things...\n"));
 
        if( SDpnt->scsi_request_fn != NULL )
-	 (*SDpnt->scsi_request_fn)();
+	 (*SDpnt->scsi_request_fn)(NULL);
      }
+#endif
 }
 
 /*
@@ -1652,7 +1701,13 @@
                        * Due to the spinlock, we will never get out of this
                        * loop without a proper wait (DB)
                        */
+#ifdef CONFIG_SCSI_NEW_QUEUES
+                    spin_unlock_irq(&io_request_lock);
+#endif
                       scsi_sleep(1 * HZ);
+#ifdef CONFIG_SCSI_NEW_QUEUES
+                      spin_lock_irq(&io_request_lock);
+#endif
 
                       goto next_device;
                   }
@@ -1761,7 +1816,13 @@
                 * Due to the spinlock, we will never get out of this
                 * loop without a proper wait. (DB)
                 */
+#ifdef CONFIG_SCSI_NEW_QUEUES
+              spin_unlock_irq(&io_request_lock);
+#endif
                scsi_sleep(1 * HZ);
+#ifdef CONFIG_SCSI_NEW_QUEUES
+               spin_lock_irq(&io_request_lock);
+#endif
 
               goto next_device2;
           }
diff -u -r linux.clean/drivers/scsi/scsi_ioctl.c linux.new2/drivers/scsi/scsi_ioctl.c
--- linux.clean/drivers/scsi/scsi_ioctl.c	Tue May 11 17:37:40 1999
+++ linux.new2/drivers/scsi/scsi_ioctl.c	Wed Jul 28 19:22:39 1999
@@ -19,7 +19,7 @@
 #include <scsi/scsi_ioctl.h>
 
 #define NORMAL_RETRIES 5   
-#define NORMAL_TIMEOUT (10 * HZ)
+#define IOCTL_NORMAL_TIMEOUT (10 * HZ)
 #define FORMAT_UNIT_TIMEOUT (2 * 60 * 60 * HZ)
 #define START_STOP_TIMEOUT (60 * HZ)
 #define MOVE_MEDIUM_TIMEOUT (5 * 60 * HZ)
@@ -67,7 +67,7 @@
 /*
  * 
  * The SCSI_IOCTL_SEND_COMMAND ioctl sends a command out to the SCSI host.
- * The NORMAL_TIMEOUT and NORMAL_RETRIES  variables are used.  
+ * The IOCTL_NORMAL_TIMEOUT and NORMAL_RETRIES  variables are used.  
  * 
  * dev is the SCSI device struct ptr, *(int *) arg is the length of the
  * input data, if any, not including the command string & counts, 
@@ -103,22 +103,34 @@
 static int ioctl_internal_command(Scsi_Device *dev, char * cmd,
 				  int timeout, int retries)
 {
+#ifndef CONFIG_SCSI_NEW_QUEUES
     unsigned long flags;
+#endif
     int result;
     Scsi_Cmnd * SCpnt;
     Scsi_Device * SDpnt;
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
     spin_lock_irqsave(&io_request_lock, flags);
+#endif
 
     SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", cmd[0]));
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    SCpnt = scsi_allocate_device(dev, 1);
+#else
     SCpnt = scsi_allocate_device(NULL, dev, 1);
+#endif
     {
 	DECLARE_MUTEX_LOCKED(sem);
 	SCpnt->request.sem = &sem;
 	scsi_do_cmd(SCpnt,  cmd, NULL,  0, scsi_ioctl_done,  timeout, retries);
+#ifndef CONFIG_SCSI_NEW_QUEUES
 	spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	down(&sem);
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_lock_irqsave(&io_request_lock, flags);
+#endif
         SCpnt->request.sem = NULL;
     }
     
@@ -163,11 +175,15 @@
     scsi_release_command(SCpnt);
     SCpnt = NULL;
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
     if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
-	(*SDpnt->scsi_request_fn)();
+	(*SDpnt->scsi_request_fn)(NULL);
+#endif
 
     wake_up(&SDpnt->device_wait);
+#ifndef CONFIG_SCSI_NEW_QUEUES
     spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
     return result;
 }
 
@@ -178,7 +194,9 @@
  */
 int scsi_ioctl_send_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic)
 {
+#ifndef CONFIG_SCSI_NEW_QUEUES
     unsigned long flags;
+#endif
     char * buf;
     unsigned char cmd[12]; 
     char * cmd_in;
@@ -227,9 +245,13 @@
     if(buf_needed){
 	buf_needed = (buf_needed + 511) & ~511;
 	if (buf_needed > MAX_BUF) buf_needed = MAX_BUF;
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	buf = (char *) scsi_malloc(buf_needed);
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	if (!buf) return -ENOMEM;
 	memset(buf, 0, buf_needed);
     } else
@@ -277,23 +299,30 @@
  	retries = NORMAL_RETRIES;
 	break;
       default:
- 	timeout = NORMAL_TIMEOUT;
+ 	timeout = IOCTL_NORMAL_TIMEOUT;
  	retries = NORMAL_RETRIES;
 	break;
       }
 
 #ifndef DEBUG_NO_CMD
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
     spin_lock_irqsave(&io_request_lock, flags);
+#endif
     
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    SCpnt = scsi_allocate_device(dev, 1);
+#else
     SCpnt = scsi_allocate_device(NULL, dev, 1);
-
+#endif
     {
 	DECLARE_MUTEX_LOCKED(sem);
 	SCpnt->request.sem = &sem;
 	scsi_do_cmd(SCpnt,  cmd,  buf, needed,  scsi_ioctl_done,
 		    timeout, retries);
+#ifndef CONFIG_SCSI_NEW_QUEUES
 	spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	down(&sem);
         SCpnt->request.sem = NULL;
     }
@@ -316,7 +345,9 @@
     }
     result = SCpnt->result;
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
     spin_lock_irqsave(&io_request_lock, flags);
+#endif
 
     wake_up(&SCpnt->device->device_wait);
     SDpnt = SCpnt->device;
@@ -325,10 +356,14 @@
 
     if (buf) scsi_free(buf, buf_needed);
     
+#ifndef CONFIG_SCSI_NEW_QUEUES
     if(SDpnt->scsi_request_fn)
-	(*SDpnt->scsi_request_fn)();
+	(*SDpnt->scsi_request_fn)(NULL);
+#endif
     
+#ifndef CONFIG_SCSI_NEW_QUEUES
     spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
     return result;
 #else
     {
@@ -414,7 +449,7 @@
 	scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
 	scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
 	return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
-				      NORMAL_TIMEOUT, NORMAL_RETRIES);
+				      IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES);
 	break;
     case SCSI_IOCTL_DOORUNLOCK:
 	if (!dev->removable || !dev->lockable) return 0;
@@ -423,14 +458,14 @@
 	scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
 	scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
 	return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
-				      NORMAL_TIMEOUT, NORMAL_RETRIES);
+				      IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES);
     case SCSI_IOCTL_TEST_UNIT_READY:
 	scsi_cmd[0] = TEST_UNIT_READY;
 	scsi_cmd[1] = dev->lun << 5;
 	scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
 	scsi_cmd[4] = 0;
 	return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
-				      NORMAL_TIMEOUT, NORMAL_RETRIES);
+				      IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES);
 	break;
     case SCSI_IOCTL_START_UNIT:
 	scsi_cmd[0] = START_STOP;
diff -u -r linux.clean/drivers/scsi/scsi_lib.c linux.new2/drivers/scsi/scsi_lib.c
--- linux.clean/drivers/scsi/scsi_lib.c	Mon Sep  6 17:19:16 1999
+++ linux.new2/drivers/scsi/scsi_lib.c	Sun Sep  5 08:18:35 1999
@@ -0,0 +1,814 @@
+/*
+ *  scsi_lib.c Copyright (C) 1999 Eric Youngdale
+ *
+ *  SCSI queueing library.
+ *      Initial versions: Eric Youngdale (eric@andante.org).
+ *			  Based upon conversations with large numbers
+ *			  of people at Linux Expo.
+ */
+
+/*
+ * The fundamental purpose of this file is to contain a library of utility
+ * routines that can be used by low-level drivers.   Ultimately the idea
+ * is that there should be a sufficiently rich number of functions that it
+ * would be possible for a driver author to fashion a queueing function for
+ * a low-level driver if they wished.   Note however that this file also
+ * contains the "default" versions of these functions, as we don't want to
+ * go through and retrofit queueing functions into all 30 some-odd drivers.
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/blk.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/smp_lock.h>
+
+
+#define __KERNEL_SYSCALLS__
+
+#include <linux/unistd.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "constants.h"
+#include <scsi/scsi_ioctl.h>
+
+/*
+ * This entire source file deals with the new queueing code.
+ */
+#ifdef CONFIG_SCSI_NEW_QUEUES
+
+/*
+ * Function:    scsi_insert_special_cmd()
+ *
+ * Purpose:     Insert pre-formed command into request queue.
+ *
+ * Arguments:   SCpnt   - command that is ready to be queued.
+ *		at_head - boolean.  True if we should insert at head
+ *			  of queue, false if we should insert at tail.
+ *
+ * Returns:     Nothing
+ *
+ * Notes:	This function is called from character device and from
+ *		ioctl types of functions where the caller knows exactly
+ *		what SCSI command needs to be issued.   The idea is that
+ *		we merely inject the command into the queue (at the head
+ *		for now), and then call the queue request function to actually
+ *		process it.
+ */
+int scsi_insert_special_cmd( Scsi_Cmnd * SCpnt, int at_head )
+{
+    unsigned long      flags;
+    request_queue_t  * q;
+
+    ASSERT_LOCK(&io_request_lock, 0);
+
+    /*
+     * The SCpnt already contains a request structure - we will doctor the
+     * thing up with the appropriate values and use that in the actual
+     * request queue.
+     */
+    q = &SCpnt->device->request_queue;
+    SCpnt->request.cmd = SPECIAL;
+    SCpnt->request.special = (void *) SCpnt;
+
+    /*
+     * For the moment, we insert at the head of the queue.   This may turn
+     * out to be a bad idea, but we will see about that when we get there.
+     */
+    spin_lock_irqsave(&io_request_lock, flags);
+
+    if( at_head )
+    {
+	SCpnt->request.next = q->current_request;
+	q->current_request = &SCpnt->request;
+    }
+    else
+    {
+	/*
+	 * FIXME(eric) - we always insert at the tail of the list.  Otherwise
+	 * ioctl commands would always take precedence over normal I/O.
+	 */
+	SCpnt->request.next = NULL;
+	if( q->current_request == NULL )
+	{
+	    q->current_request = &SCpnt->request;
+	}
+	else
+	{
+	    struct request   * req;
+	    
+	    for(req = q->current_request; req; req = req->next )
+	    {
+		if( req->next == NULL )
+		{
+		    req->next = &SCpnt->request;
+		}
+	    }
+	}
+    }
+
+    /*
+     * Now hit the requeue function for the queue.   If the host is already
+     * busy, so be it - we have nothing special to do.   If the host can queue
+     * it, then send it off.
+     */
+    q->request_fn(q);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+    return 0;
+}
+
+/*
+ * Function:    scsi_init_cmd_errh()
+ *
+ * Purpose:     Initialize SCpnt fields related to error handling.
+ *
+ * Arguments:   SCpnt   - command that is ready to be queued.
+ *
+ * Returns:     Nothing
+ *
+ * Notes:	This function has the job of initializing a number of
+ *		fields related to error handling.   Typically this will
+ *		be called once for each command, as required.
+ */
+int scsi_init_cmd_errh(Scsi_Cmnd * SCpnt)
+{
+    ASSERT_LOCK(&io_request_lock, 0);
+
+    SCpnt->owner = SCSI_OWNER_MIDLEVEL;
+    SCpnt->reset_chain = NULL;
+    SCpnt->serial_number = 0;
+    SCpnt->serial_number_at_timeout = 0;
+    SCpnt->flags = 0;
+    SCpnt->retries = 0;
+
+    SCpnt->abort_reason = 0;
+
+    memset ((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer);
+
+    if (SCpnt->cmd_len == 0)
+	SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+
+    /*
+     * We need saved copies of a number of fields - this is because
+     * error handling may need to overwrite these with different values
+     * to run different commands, and once error handling is complete,
+     * we will need to restore these values prior to running the actual
+     * command.
+     */
+    SCpnt->old_use_sg = SCpnt->use_sg;
+    SCpnt->old_cmd_len = SCpnt->cmd_len;
+    memcpy ((void *) SCpnt->data_cmnd , 
+	    (const void *) SCpnt->cmnd, sizeof(SCpnt->cmnd));
+    SCpnt->buffer = SCpnt->request_buffer;
+    SCpnt->bufflen = SCpnt->request_bufflen;
+
+    SCpnt->reset_chain = NULL;
+
+    SCpnt->internal_timeout = NORMAL_TIMEOUT;
+    SCpnt->abort_reason = 0;
+
+    return 1;
+}
+
+/*
+ * Function:    scsi_queue_next_request()
+ *
+ * Purpose:     Handle post-processing of completed commands.
+ *
+ * Arguments:   SCpnt   - command that may need to be requeued.
+ *
+ * Returns:     Nothing
+ *
+ * Notes:	After command completion, there may be blocks left
+ *		over which weren't finished by the previous command
+ *		this can be for a number of reasons - the main one is
+ *		that a medium error occurred, and the sectors after
+ *		the bad block need to be re-read.
+ *
+ *		If SCpnt is NULL, it means that the previous command
+ *		was completely finished, and we should simply start
+ *		a new command, if possible.
+ */
+void scsi_queue_next_request(request_queue_t * q, Scsi_Cmnd * SCpnt)
+{
+    int                all_clear;
+    unsigned long      flags;
+    Scsi_Device      * SDpnt;
+    struct Scsi_Host * SHpnt;
+
+    ASSERT_LOCK(&io_request_lock, 0);
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    if( SCpnt != NULL )
+    {
+
+	/*
+	 * For some reason, we are not done with this request.
+	 * This happens for I/O errors in the middle of the request,
+	 * in which case we need to request the blocks that come after
+	 * the bad sector.
+	 */
+	SCpnt->request.next = q->current_request;
+	q->current_request = &SCpnt->request;
+	SCpnt->request.special = (void *) SCpnt;	
+    }
+
+    /*
+     * Just hit the requeue function for the queue.
+     * FIXME - if this queue is empty, check to see if we might need to
+     * start requests for other devices attached to the same host.
+     */
+    q->request_fn(q);
+
+    /*
+     * Now see whether there are other devices on the bus which
+     * might be starved.  If so, hit the request function.  If we
+     * don't find any, then it is safe to reset the flag.  If we
+     * find any device that it is starved, it isn't safe to reset the
+     * flag as the queue function releases the lock and thus some
+     * other device might have become starved along the way.
+     */
+    SDpnt = ( Scsi_Device *) q->queuedata;
+    SHpnt = SDpnt->host;
+    all_clear = 1;
+    if( SHpnt->some_device_starved )
+    {
+	for( SDpnt = SHpnt->host_queue; SDpnt; SDpnt = SDpnt->next )
+	{
+	    request_queue_t  * q;
+	    if(    (SHpnt->can_queue > 0 && (SHpnt->host_busy >= SHpnt->can_queue))
+	        || (SHpnt->host_blocked) )
+	    {
+		break;
+	    }
+	    
+	    if( SDpnt->device_blocked || !SDpnt->starved )
+	    {
+		continue;
+	    }
+	    
+	    q = &SDpnt->request_queue;
+	    q->request_fn(q);
+	    all_clear = 0;
+	}
+	if( SDpnt == NULL && all_clear )
+	{
+	    SHpnt->some_device_starved = 0;
+	}
+    }
+   
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+/*
+ * Function:    scsi_end_request()
+ *
+ * Purpose:     Post-processing of completed commands called from interrupt
+ *		handler.
+ *
+ * Arguments:   SCpnt    - command that is complete.
+ *		uptodate - 1 if I/O indicates success, 0 for I/O error.
+ *		sectors  - number of sectors we want to mark.
+ *
+ * Lock status: Unknown at this time.  FIXME
+ *
+ * Returns:     Nothing
+ *
+ * Notes:	This is called for block device requests in order to
+ *		mark some number of sectors as complete.
+ */
+Scsi_Cmnd * scsi_end_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors)
+{
+    struct request * req;
+    struct buffer_head * bh;
+    
+    ASSERT_LOCK(&io_request_lock, 0);
+
+    req = &SCpnt->request;
+    req->errors = 0;
+    if (!uptodate) 
+    {
+	printk(" I/O error: dev %s, sector %lu\n",
+	       kdevname(req->rq_dev), req->sector);
+    }
+    
+    do 
+    {
+	if ((bh = req->bh) != NULL) 
+        {
+	    req->bh = bh->b_reqnext;
+	    req->nr_sectors -= bh->b_size >> 9;
+	    req->sector += bh->b_size >> 9;
+	    bh->b_reqnext = NULL;
+	    bh->b_end_io(bh, uptodate);
+	    sectors -= bh->b_size >> 9;
+	    if ((bh = req->bh) != NULL) {
+		req->current_nr_sectors = bh->b_size >> 9;
+		if (req->nr_sectors < req->current_nr_sectors) 
+                {
+		    req->nr_sectors = req->current_nr_sectors;
+		    printk("scsi_end_request: buffer-list destroyed\n");
+		}
+	    }
+	}
+    } while(sectors && bh);
+
+    /*
+     * If there are blocks left over at the end, set up the command
+     * to queue the remainder of them.
+     */
+    if( req->bh )
+    {
+	req->buffer = bh->b_data;
+	return SCpnt;
+    }
+
+    /*
+     * This request is done.  If there is someone blocked waiting for this
+     * request, wake them up.  Typically used to wake up processes trying
+     * to swap a page into memory.
+     */
+    if (req->sem != NULL) 
+    {
+	up(req->sem);
+    }
+
+    add_blkdev_randomness(MAJOR(req->rq_dev));
+    scsi_release_command(SCpnt);
+    return NULL;
+}
+
+/*
+ * Function:    scsi_io_completion()
+ *
+ * Purpose:     Completion processing for block device I/O requests.
+ *
+ * Arguments:   SCpnt   - command that is finished.
+ *
+ * Lock status: Unknown at this time.  FIXME.
+ *
+ * Returns:     Nothing
+ *
+ * Notes:	This function is matched in terms of capabilities to
+ *		the function that created the scatter-gather list.
+ *		In other words, if there are no bounce buffers
+ *		(the normal case for most drivers), we don't need
+ *		the logic to deal with cleaning up afterwards.
+ */
+void scsi_io_completion (Scsi_Cmnd *SCpnt, int good_sectors,
+			 int block_sectors)
+{
+    int result = SCpnt->result;
+    int this_count = SCpnt->bufflen >> 9;
+    request_queue_t * q = &SCpnt->device->request_queue;
+
+    ASSERT_LOCK(&io_request_lock, 0);
+
+    /*
+     * Free up any indirection buffers we allocated for DMA purposes. 
+     */
+    if (SCpnt->use_sg) 
+    {
+	struct scatterlist * sgpnt;
+	sgpnt = (struct scatterlist *) SCpnt->buffer;
+	scsi_free(SCpnt->buffer, SCpnt->sglist_len);
+    }
+
+    /*
+     * Next deal with any sectors which we were able to correctly
+     * handle.
+     */
+    if (good_sectors > 0) 
+    {
+	SCSI_LOG_HLCOMPLETE(1,printk("%ld sectors remain.\n", 
+				     SCpnt->request.nr_sectors));
+	SCSI_LOG_HLCOMPLETE(1,printk("use_sg is %d\n ",SCpnt->use_sg));
+
+	SCpnt->request.errors = 0;
+	/*
+	 * If multiple sectors are requested in one buffer, then
+	 * they will have been finished off by the first command.
+	 * If not, then we have a multi-buffer command.
+	 */
+	SCpnt = scsi_end_request(SCpnt, 1, good_sectors);
+
+	/*
+	 * If the command completed without error, then either finish off the
+	 * rest of the command, or start a new one.
+	 */
+	if (result == 0)
+	{
+	    scsi_queue_next_request(q, SCpnt);
+	    return;
+	}
+    }
+
+    /*
+     * Now, if we were good little boys and girls, Santa left us a request
+     * sense buffer.  We can extract information from this, so we
+     * can choose a block to remap, etc.
+     */
+    if (driver_byte(result) != 0) 
+    {
+	if (suggestion(result) == SUGGEST_REMAP) 
+	{
+#ifdef REMAP
+	    /*
+	     * Not yet implemented.  A read will fail after being remapped,
+	     * a write will call the strategy routine again.
+	     */
+	    if( SCpnt->device->remap )
+	    {
+		    result = 0;
+	    }
+#endif
+	}
+	
+	if (   (SCpnt->sense_buffer[0] & 0x7f) == 0x70
+	    && (SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION )
+	{
+	    if(SCpnt->device->removable) 
+	    {
+		/* detected disc change.  set a bit and quietly refuse
+		 * further access.
+		 */
+		SCpnt->device->changed = 1;
+		SCpnt = scsi_end_request(SCpnt, 0, this_count);
+		scsi_queue_next_request(q, SCpnt);
+		return;
+	    }
+	    else
+	    {
+		/*
+		 * Must have been a power glitch, or a bus reset.
+		 * Could not have been a media change, so we just retry
+		 * the request and see what happens.
+		 */
+		scsi_queue_next_request(q, SCpnt);
+		return;
+	    }
+	}
+	
+	
+	/* If we had an ILLEGAL REQUEST returned, then we may have
+	 * performed an unsupported command.  The only thing this should be
+	 * would be a ten byte read where only a six byte read was supported.
+	 * Also, on a system where READ CAPACITY failed, we have have read
+	 * past the end of the disk.
+	 */
+	
+	switch(SCpnt->sense_buffer[2])
+	{
+	case ILLEGAL_REQUEST:
+	    if (SCpnt->device->ten) 
+	    {
+		SCpnt->device->ten = 0;
+		scsi_queue_next_request(q, SCpnt);
+		result = 0;
+	    } 
+	    else 
+	    {
+		SCpnt = scsi_end_request(SCpnt, 0, this_count);
+		scsi_queue_next_request(q, SCpnt);
+		return;
+	    }
+	    break;
+	case NOT_READY:
+	    printk(KERN_INFO "Device %x not ready.\n",
+		   SCpnt->request.rq_dev);
+	    SCpnt = scsi_end_request(SCpnt, 0, this_count);
+	    scsi_queue_next_request(q, SCpnt);
+	    return;
+	    break;
+	case MEDIUM_ERROR:
+	case VOLUME_OVERFLOW:
+	    printk("scsi%d: ERROR on channel %d, id %d, lun %d, CDB: ",
+		   SCpnt->host->host_no, (int) SCpnt->channel,
+		   (int) SCpnt->target, (int) SCpnt->lun);
+	    print_command(SCpnt->cmnd);
+	    print_sense("sd", SCpnt);
+	    SCpnt = scsi_end_request(SCpnt, 0, block_sectors);
+	    scsi_queue_next_request(q, SCpnt);
+	    return;
+	default:
+	    break;
+	}
+    }  /* driver byte != 0 */
+    if (result) 
+    {
+	printk("SCSI disk error : host %d channel %d id %d lun %d return code = %x\n",
+	       SCpnt->device->host->host_no,
+	       SCpnt->device->channel,
+	       SCpnt->device->id,
+	       SCpnt->device->lun, result);
+	
+	if (driver_byte(result) & DRIVER_SENSE)
+	    print_sense("sd", SCpnt);
+	SCpnt = scsi_end_request(SCpnt, 0, SCpnt->request.current_nr_sectors);
+	scsi_queue_next_request(q, SCpnt);
+	return;
+    }
+}
+
+/*
+ * Function:    scsi_get_request_dev()
+ *
+ * Purpose:     Find the upper-level driver that is responsible for this
+ *		request
+ *
+ * Arguments:   request   - I/O request we are preparing to queue.
+ *
+ * Lock status: No locks assumed to be held, but as it happens the
+ *		io_request_lock is held when this is called.
+ *
+ * Returns:     Nothing
+ *
+ * Notes:	The requests in the request queue may have originated
+ *		from any block device driver.  We need to find out which
+ *		one so that we can later form the appropriate command.
+ */
+struct Scsi_Device_Template * scsi_get_request_dev(struct request * req)
+{
+    struct Scsi_Device_Template * spnt;
+    kdev_t dev = req->rq_dev;
+    int major = MAJOR(dev);
+
+    ASSERT_LOCK(&io_request_lock, 1);
+
+    for(spnt = scsi_devicelist; spnt; spnt = spnt->next)
+    {
+	/*
+	 * Search for a block device driver that supports this
+	 * major.
+	 */
+	if( spnt->blk && spnt->major == major )
+	{
+	    return spnt;
+	}
+    }
+    return NULL;
+}
+
+/*
+ * Function:    scsi_request_fn()
+ *
+ * Purpose:     Generic version of request function for SCSI hosts.
+ *
+ * Arguments:   q       - Pointer to actual queue.
+ *
+ * Returns:     Nothing
+ *
+ * Lock status: IO request lock assumed to be held when called.
+ *
+ * Notes:	The theory is that this function is something which individual
+ *		drivers could also supply if they wished to.   The problem
+ *		is that we have 30 some odd low-level drivers in the kernel
+ *		tree already, and it would be most difficult to retrofit
+ *		this crap into all of them.   Thus this function has the job
+ *		of acting as a generic queue manager for all of those existing
+ *		drivers.
+ */
+void scsi_request_fn(request_queue_t * q)
+{
+    struct request   * req;
+    Scsi_Cmnd        * SCpnt;
+    Scsi_Device      * SDpnt;
+    struct Scsi_Host * SHpnt;
+    struct Scsi_Device_Template * STpnt;
+   
+    ASSERT_LOCK(&io_request_lock, 1);
+
+    SDpnt = ( Scsi_Device *) q->queuedata;
+    if( !SDpnt )
+    {
+	panic("Missing device");
+    }
+
+    SHpnt = SDpnt->host;
+
+    /*
+     * If the host for this device is in error recovery mode, don't
+     * do anything at all here.  When the host leaves error recovery
+     * mode, it will automatically restart things and start queueing
+     * commands again.  Same goes if the queue is actually plugged,
+     * if the device itself is blocked, or if the host is fully
+     * occupied.
+     */
+    if(    SHpnt->in_recovery 
+	|| q->plugged )
+    {
+	return;
+    }
+
+    /*
+     * To start with, we keep looping until the queue is empty, or until
+     * the host is no longer able to accept any more requests.
+     */
+    while(1==1)
+    {
+	/*
+	 * If the host cannot accept another request, then quit.
+	 */
+	if( SDpnt->device_blocked )
+	{
+	    break;
+	}
+
+	if(    (SHpnt->can_queue > 0 && (SHpnt->host_busy >= SHpnt->can_queue))
+	    || (SHpnt->host_blocked) )
+	{
+	    /*
+	     * If we are unable to process any commands at all for this
+	     * device, then we consider it to be starved.  What this means
+	     * is that there are no outstanding commands for this device
+	     * and hence we need a little help getting it started again
+	     * once the host isn't quite so busy.
+	     */
+	    if( SDpnt->device_busy == 0 )
+	    {
+		SDpnt->starved             = 1;
+		SHpnt->some_device_starved = 1;
+	    }
+	    break;
+	}
+	else
+	{
+	    SDpnt->starved = 0;
+	}
+	/*
+	 * Loop through all of the requests in this queue, and find
+	 * one that is queueable.
+	 */
+	req = q->current_request; 
+
+	/*
+	 * If we couldn't find a request that could be queued, then we
+	 * can also quit.
+	 */
+	if( !req )
+	{
+	    break;
+	}
+
+	/*
+	 * Find the actual device driver associated with this command.
+	 * The SPECIAL requests are things like character device or
+	 * ioctls, which did not originate from ll_rw_blk.
+	 */
+	if( req->special != NULL )
+	{
+	    STpnt = NULL;
+	    SCpnt = (Scsi_Cmnd *) req->special;
+	}
+	else
+	{
+	    STpnt = scsi_get_request_dev(req);
+	    if( !STpnt )
+	    {
+		panic("Unable to find device associated with request");
+	    }
+	    
+	    /*
+	     * Now try and find a command block that we can use.
+	     */
+	    SCpnt = scsi_allocate_device(SDpnt, FALSE);
+	    /*
+	     * If so, we are ready to do something.  Bump the count
+	     * while the queue is locked and then break out of the loop.
+	     * Otherwise loop around and try another request.
+	     */
+	    if( !SCpnt )
+	    {
+		break;
+	    }
+	    SHpnt->host_busy++;
+	    SDpnt->device_busy++;
+	}
+
+	/*
+	 * FIXME(eric)
+	 * I am not sure where the best place to do this is.  We need
+	 * to hook in a place where we are likely to come if in user
+	 * space.   Technically the error handling thread should be
+	 * doing this crap, but the error handler isn't used by
+	 * most hosts.
+	 */
+	if( SDpnt->was_reset )
+	{
+	    /*
+	     * We need to relock the door, but we might
+	     * be in an interrupt handler.  Only do this
+	     * from user space, since we do not want to
+	     * sleep from an interrupt.
+	     */
+	    if( SDpnt->removable && !in_interrupt() )
+	    {
+		spin_unlock_irq(&io_request_lock);
+		scsi_ioctl(SDpnt, SCSI_IOCTL_DOORLOCK, 0);
+		SDpnt->was_reset = 0;
+		spin_lock_irq(&io_request_lock);
+		continue;
+	    }
+	    SDpnt->was_reset = 0;
+	}
+
+	/*
+	 * Finally, before we release the lock, we copy the
+	 * request to the command block, and remove the
+	 * request from the request list.   Note that we always
+	 * operate on the queue head - there is absolutely no
+	 * reason to search the list, because all of the commands
+	 * in this queue are for the same device.
+	 */
+	q->current_request = req->next;
+
+	if( req->special == NULL )
+	{
+	    memcpy(&SCpnt->request, req, sizeof(struct request));
+
+	    /*
+	     * We have copied the data out of the request block - it is now in
+	     * a field in SCpnt.  Release the request block.
+	     */
+	    req->next      = NULL;
+	    req->rq_status = RQ_INACTIVE;
+	    wake_up(&wait_for_request);
+	}
+
+	/*
+	 * Now it is finally safe to release the lock.  We are not going
+	 * to noodle the request list until this request has been queued
+	 * and we loop back to queue another.
+	 */
+	spin_unlock_irq(&io_request_lock);
+
+	if( req->special == NULL )
+	{
+	    /*
+	     * This will do a couple of things:
+	     *  1) Fill in the actual SCSI command.
+	     *  2) Fill in any other upper-level specific fields (timeout).
+	     *
+	     * If this returns 0, it means that the request failed (reading
+	     * past end of disk, reading offline device, etc).   This won't
+	     * actually talk to the device, but some kinds of consistency
+	     * checking may cause the request to be rejected immediately.
+	     */
+	    if( STpnt == NULL )
+	    {
+		STpnt = scsi_get_request_dev(req);
+	    }
+
+	    /* 
+	     * This sets up the scatter-gather table (allocating if
+	     * required).  Hosts that need bounce buffers will also
+	     * get those allocated here.  
+	     */
+	    if( !SDpnt->scsi_init_io_fn(SCpnt) )
+	    {
+		continue;
+	    }
+
+	    /*
+	     * Initialize the actual SCSI command for this request.
+	     */
+	    if( !STpnt->init_command(SCpnt) )
+	    {
+		continue;
+	    }
+	    
+	}
+	    
+	/*
+	 * Finally, initialize any error handling parameters, and set up
+	 * the timers for timeouts.
+	 */
+	scsi_init_cmd_errh(SCpnt);
+	
+	/*
+	 * Dispatch the command to the low-level driver.
+	 */
+	scsi_dispatch_cmd(SCpnt);
+
+	/*
+	 * Now we need to grab the lock again.  We are about to mess with
+	 * the request queue and try to find another command.
+	 */
+	spin_lock_irq(&io_request_lock);
+    }
+}
+#endif
diff -u -r linux.clean/drivers/scsi/scsi_merge.c linux.new2/drivers/scsi/scsi_merge.c
--- linux.clean/drivers/scsi/scsi_merge.c	Mon Sep  6 17:19:14 1999
+++ linux.new2/drivers/scsi/scsi_merge.c	Sun Sep  5 08:18:54 1999
@@ -0,0 +1,815 @@
+/*
+ *  scsi_merge.c Copyright (C) 1999 Eric Youngdale
+ *
+ *  SCSI queueing library.
+ *      Initial versions: Eric Youngdale (eric@andante.org).
+ *			  Based upon conversations with large numbers
+ *			  of people at Linux Expo.
+ */
+
+/*
+ * This file contains queue management functions that are used by SCSI.
+ * Typically this is used for several purposes.   First, we need to ensure
+ * that commands do not grow so large that they cannot be handled all at
+ * once by a host adapter.   The various flavors of merge functions included
+ * here serve this purpose.
+ *
+ * Note that it would be quite trivial to allow the low-level driver the
+ * flexibility to define it's own queue handling functions.  For the time
+ * being, the hooks are not present.   Right now we are just using the
+ * data in the host template as an indicator of how we should be handling
+ * queues, and we select routines that are optimized for that purpose.
+ *
+ * Some hosts do not impose any restrictions on the size of a request.
+ * In such cases none of the merge functions in this file are called,
+ * and we allow ll_rw_blk to merge requests in the default manner.
+ * This isn't guaranteed to be optimal, but it should be pretty darned
+ * good.   If someone comes up with ideas of better ways of managing queues
+ * to improve on the default behavior, then certainly fit it into this
+ * scheme in whatever manner makes the most sense.   Please note that
+ * since each device has it's own queue, we have considerable flexibility
+ * in queue management.
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/blk.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/smp_lock.h>
+
+
+#define __KERNEL_SYSCALLS__
+
+#include <linux/unistd.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "constants.h"
+#include <scsi/scsi_ioctl.h>
+
+/*
+ * Enable a bunch of additional consistency checking.   Turn this off
+ * if you are benchmarking.
+ */
+
+#ifdef CONFIG_SCSI_DEBUG_QUEUES
+/*
+ * Simple sanity check that we will use for the first go around
+ * in order to ensure that we are doing the counting correctly.
+ * This can be removed for optimization.
+ */
+#define SANITY_CHECK(req, _CLUSTER, _DMA)				\
+    if( req->nr_sg_segments != __count_segments(req, _CLUSTER, _DMA) )	\
+    {									\
+	panic("Incorrect segment count");				\
+    }
+#else
+#define SANITY_CHECK(req, _CLUSTER, _DMA)
+#endif
+
+/*
+ * FIXME(eric) - the original disk code disabled clustering for MOD
+ * devices.  I have no idea why we thought this was a good idea - my
+ * guess is that it was an attempt to limit the size of requests to MOD
+ * devices.
+ */
+#define CLUSTERABLE_DEVICE(SH,SD) (SH->use_clustering && \
+				   SD->type != TYPE_MOD)
+
+/*
+ * This entire source file deals with the new queueing code.
+ */
+#ifdef CONFIG_SCSI_NEW_QUEUES
+
+/*
+ * Function:    __scsi_merge_fn()
+ *
+ * Purpose:     Prototype for queue merge function.
+ *
+ * Arguments:   q	- Queue for which we are merging request.
+ *		req	- request into which we wish to merge.
+ *		use_clustering - 1 if this host wishes to use clustering
+ *		dma_host - 1 if this host has ISA DMA issues (bus doesn't
+ *			expose all of the address lines, so that DMA cannot
+ *			be done from an arbitrary address).
+ *
+ * Returns:     Count of the number of SG segments for the request.
+ *
+ * Lock status: 
+ *
+ * Notes:	This is only used for diagnostic purposes.
+ */
+__inline static int __count_segments(struct request * req,
+				     int use_clustering,
+				     int dma_host)
+{
+    int	ret = 1;
+    struct buffer_head * bh;
+
+    for(bh = req->bh; bh->b_reqnext != NULL; bh = bh->b_reqnext)
+    {
+	if( use_clustering )
+	{
+	    /* 
+	     * See if we can do this without creating another
+	     * scatter-gather segment.  In the event that this is a
+	     * DMA capable host, make sure that a segment doesn't span
+	     * the DMA threshold boundary.  
+	     */
+	    if( dma_host &&
+		virt_to_phys(bh->b_data-1) == ISA_DMA_THRESHOLD)
+	    {
+		ret++;
+	    }
+	    else if( CONTIGUOUS_BUFFERS(bh, bh->b_reqnext) )
+	    {
+		/*
+		 * This one is OK.  Let it go.
+		 */
+		continue;
+	    }
+	    ret++;
+	}
+	else
+	{
+	    ret++;
+	}
+    }
+    return ret;
+}
+
+/*
+ * Function:    __scsi_merge_fn()
+ *
+ * Purpose:     Prototype for queue merge function.
+ *
+ * Arguments:   q	- Queue for which we are merging request.
+ *		req	- request into which we wish to merge.
+ *		bh	- Block which we may wish to merge into request
+ *		use_clustering - 1 if this host wishes to use clustering
+ *		dma_host - 1 if this host has ISA DMA issues (bus doesn't
+ *			expose all of the address lines, so that DMA cannot
+ *			be done from an arbitrary address).
+ *
+ * Returns:     1 if it is OK to merge the block into the request.  0
+ *		if it is not OK.
+ *
+ * Lock status: io_request_lock is assumed to be held here.
+ *
+ * Notes:	Some drivers have limited scatter-gather table sizes, and
+ *		thus they cannot queue an infinitely large command.  This
+ *		function is called from ll_rw_blk before it attempts to merge
+ *		a new block into a request to make sure that the request will
+ *		not become too large.
+ *
+ *		This function is not designed to be directly called.  Instead
+ *		it should be referenced from other functions where the
+ *		use_clustering and dma_host parameters should be integer
+ *		constants.  The compiler should thus be able to properly
+ *		optimize the code, eliminating stuff that is irrelevant.
+ *		It is more maintainable to do this way with a single function
+ *		than to have 4 separate functions all doing roughly the
+ *		same thing.
+ */
+__inline static int __scsi_merge_fn(request_queue_t * q,
+			 struct request * req,
+			 struct buffer_head * bh,
+			 int use_clustering,
+			 int dma_host)
+{
+    unsigned int sector, count;
+    Scsi_Device      * SDpnt;
+    struct Scsi_Host * SHpnt;
+
+    SDpnt = ( Scsi_Device *) q->queuedata;
+    SHpnt = SDpnt->host;
+
+    count = bh->b_size >> 9;
+    sector = bh->b_rsector;
+
+    /*
+     * We come in here in one of two cases.   The first is that we
+     * are checking to see if we can add the buffer to the end of the
+     * request, the other is to see if we should add the request to the
+     * start.
+     */
+    if (req->sector + req->nr_sectors == sector) 
+    {
+	if( use_clustering )
+	{
+	    /* 
+	     * See if we can do this without creating another
+	     * scatter-gather segment.  In the event that this is a
+	     * DMA capable host, make sure that a segment doesn't span
+	     * the DMA threshold boundary.  
+	     */
+	    if( dma_host &&
+		virt_to_phys(req->bhtail->b_data-1) == ISA_DMA_THRESHOLD)
+	    {
+		goto new_segment;
+	    }
+
+	    if( CONTIGUOUS_BUFFERS(req->bhtail, bh) )
+	    {
+		/*
+		 * This one is OK.  Let it go.
+		 */
+		return 1;
+	    }
+	}
+	goto new_segment;
+    } 
+    else if (req->sector - count == sector) 
+    {
+	if( use_clustering )
+	{
+	    /* 
+	     * See if we can do this without creating another
+	     * scatter-gather segment.  In the event that this is a
+	     * DMA capable host, make sure that a segment doesn't span
+	     * the DMA threshold boundary. 
+	     */
+	    if( dma_host &&
+		virt_to_phys(bh->b_data-1) == ISA_DMA_THRESHOLD)
+	    {
+		goto new_segment;
+	    }
+	    if( CONTIGUOUS_BUFFERS(bh, req->bh) )
+	    {
+		/*
+		 * This one is OK.  Let it go.
+		 */
+		return 1;
+	    }
+	}
+	goto new_segment;
+    }
+    else
+    {
+	panic("Attempt to merge sector that doesn't belong");
+    }
+ new_segment:
+    if( req->nr_sg_segments < SHpnt->sg_tablesize )
+    {
+	/*
+	 * This will form the start of a new segment.  Bump the 
+	 * counter.
+	 */
+	req->nr_sg_segments++;
+	return 1;
+   }
+    else
+    {
+	return 0;
+    }
+}
+
+/*
+ * Function:    scsi_merge_fn_()
+ *
+ * Purpose:     queue merge function.
+ *
+ * Arguments:   q	- Queue for which we are merging request.
+ *		req	- request into which we wish to merge.
+ *		bh	- Block which we may wish to merge into request
+ *
+ * Returns:     1 if it is OK to merge the block into the request.  0
+ *		if it is not OK.
+ *
+ * Lock status: io_request_lock is assumed to be held here.
+ *
+ * Notes:	Optimized for different cases depending upon whether
+ *		ISA DMA is in use and whether clustering should be used.
+ */
+#define MERGEFCT(_FUNCTION, _CLUSTER, _DMA)		\
+static int _FUNCTION(request_queue_t * q,		\
+	       struct request * req,			\
+	       struct buffer_head * bh)			\
+{							\
+    int ret;						\
+    SANITY_CHECK(req, _CLUSTER, _DMA);			\
+    ret =  __scsi_merge_fn(q, req, bh, _CLUSTER, _DMA); \
+    return ret;						\
+}
+
+MERGEFCT(scsi_merge_fn_,   0, 0)
+MERGEFCT(scsi_merge_fn_d,  0, 1)
+MERGEFCT(scsi_merge_fn_c,  1, 0)
+MERGEFCT(scsi_merge_fn_dc, 1, 1)
+
+/*
+ * Function:    __scsi_merge_requests_fn()
+ *
+ * Purpose:     Prototype for queue merge function.
+ *
+ * Arguments:   q	- Queue for which we are merging request.
+ *		req	- request into which we wish to merge.
+ *		next	- 2nd request that we might want to combine with req
+ *		use_clustering - 1 if this host wishes to use clustering
+ *		dma_host - 1 if this host has ISA DMA issues (bus doesn't
+ *			expose all of the address lines, so that DMA cannot
+ *			be done from an arbitrary address).
+ *
+ * Returns:     1 if it is OK to merge the two requests.  0
+ *		if it is not OK.
+ *
+ * Lock status: io_request_lock is assumed to be held here.
+ *
+ * Notes:	Some drivers have limited scatter-gather table sizes, and
+ *		thus they cannot queue an infinitely large command.  This
+ *		function is called from ll_rw_blk before it attempts to merge
+ *		a new block into a request to make sure that the request will
+ *		not become too large.
+ *
+ *		This function is not designed to be directly called.  Instead
+ *		it should be referenced from other functions where the
+ *		use_clustering and dma_host parameters should be integer
+ *		constants.  The compiler should thus be able to properly
+ *		optimize the code, eliminating stuff that is irrelevant.
+ *		It is more maintainable to do this way with a single function
+ *		than to have 4 separate functions all doing roughly the
+ *		same thing.
+ */
+__inline static int __scsi_merge_requests_fn(request_queue_t * q,
+					     struct request * req,
+					     struct request * next,
+					     int use_clustering,
+					     int dma_host)
+{
+    Scsi_Device      * SDpnt;
+    struct Scsi_Host * SHpnt;
+
+    SDpnt = ( Scsi_Device *) q->queuedata;
+    SHpnt = SDpnt->host;
+
+    /*
+     * If the two requests together are too large (even assuming that we
+     * can merge the boundary requests into one segment, then don't
+     * allow the merge.
+     */
+    if( req->nr_sg_segments + next->nr_sg_segments - 1 > SHpnt->sg_tablesize )
+    {
+	return 0;
+    }
+
+    /*
+     * The main question is whether the two segments at the boundaries
+     * would be considered one or two.
+     */
+    if( use_clustering )
+    {
+	/* 
+	 * See if we can do this without creating another
+	 * scatter-gather segment.  In the event that this is a
+	 * DMA capable host, make sure that a segment doesn't span
+	 * the DMA threshold boundary.  
+	 */
+	if( dma_host &&
+	    virt_to_phys(req->bhtail->b_data-1) == ISA_DMA_THRESHOLD)
+	{
+	    goto dont_combine;
+	}
+	
+	if( CONTIGUOUS_BUFFERS(req->bhtail, next->bh) )
+	{
+	    /*
+	     * This one is OK.  Let it go.
+	     */
+	    req->nr_sg_segments += next->nr_sg_segments - 1;
+	    return 1;
+	}
+    }
+
+ dont_combine:
+    /*
+     * We know that the two requests at the boundary should not be combined.
+     * Make sure we can fix something that is the sum of the two.
+     * A slightly stricter test than we had above.
+     */
+    if( req->nr_sg_segments + next->nr_sg_segments > SHpnt->sg_tablesize )
+    {
+	return 0;
+    }
+    else
+    {
+	/*
+	 * This will form the start of a new segment.  Bump the 
+	 * counter.
+	 */
+	req->nr_sg_segments += next->nr_sg_segments;
+	return 1;
+    }
+}
+
+/*
+ * Function:    scsi_merge_requests_fn_()
+ *
+ * Purpose:     queue merge function.
+ *
+ * Arguments:   q	- Queue for which we are merging request.
+ *		req	- request into which we wish to merge.
+ *		bh	- Block which we may wish to merge into request
+ *
+ * Returns:     1 if it is OK to merge the block into the request.  0
+ *		if it is not OK.
+ *
+ * Lock status: io_request_lock is assumed to be held here.
+ *
+ * Notes:	Optimized for different cases depending upon whether
+ *		ISA DMA is in use and whether clustering should be used.
+ */
+#define MERGEREQFCT(_FUNCTION, _CLUSTER, _DMA)		\
+static int _FUNCTION(request_queue_t * q,		\
+		     struct request * req,		\
+		     struct request * next)		\
+{							\
+    int ret;						\
+    SANITY_CHECK(req, _CLUSTER, _DMA);			\
+    ret =  __scsi_merge_requests_fn(q, req, next, _CLUSTER, _DMA); \
+    return ret;						\
+}
+
+MERGEREQFCT(scsi_merge_requests_fn_,   0, 0)
+MERGEREQFCT(scsi_merge_requests_fn_d,  0, 1)
+MERGEREQFCT(scsi_merge_requests_fn_c,  1, 0)
+MERGEREQFCT(scsi_merge_requests_fn_dc, 1, 1)
+
+/*
+ * Function:    __init_io()
+ *
+ * Purpose:     Prototype for io initialize function.
+ *
+ * Arguments:   SCpnt	- Command descriptor we wish to initialize
+ *		sg_count_valid	- 1 if the sg count in the req is valid.
+ *		use_clustering - 1 if this host wishes to use clustering
+ *		dma_host - 1 if this host has ISA DMA issues (bus doesn't
+ *			expose all of the address lines, so that DMA cannot
+ *			be done from an arbitrary address).
+ *
+ * Returns:     1 on success.
+ *
+ * Lock status: 
+ *
+ * Notes:	Only the SCpnt argument should be a non-constant variable.
+ *		This function is designed in such a way that it will be
+ *		invoked from a series of small stubs, each of which would
+ *		be optimized for specific circumstances.
+ *
+ *		The advantage of this is that hosts that don't do DMA
+ *		get versions of the function that essentially don't have
+ *		any of the DMA code.  Same goes for clustering - in the
+ *		case of hosts with no need for clustering, there is no point
+ *		in a whole bunch of overhead.
+ *
+ *		Finally, in the event that a host has set can_queue to SG_ALL
+ *		implying that there is no limit to the length of a scatter
+ *		gather list, the sg count in the request won't be valid
+ *		(mainly because we don't need queue management functions
+ *		which keep the tally uptodate.
+ */
+__inline static int __init_io(Scsi_Cmnd * SCpnt,
+			      int sg_count_valid,
+			      int use_clustering,
+			      int dma_host)
+{
+    struct buffer_head   * bh;
+    struct buffer_head   * bhprev;
+    char		 * buff;
+    int                    count;
+    int			   i;
+    struct request       * req;
+    struct scatterlist   * sgpnt;
+    int			   this_count;
+
+    /*
+     * FIXME(eric) - don't inline this - it doesn't depend on the
+     * integer flags.   Come to think of it, I don't think this is even
+     * needed any more.  Need to play with it and see if we hit the
+     * panic.  If not, then don't bother.
+     */
+    if (!SCpnt->request.bh ) 
+    {
+	/* 
+	 * Case of page request (i.e. raw device), or unlinked buffer 
+	 * Typically used for swapping, but this isn't how we do
+	 * swapping any more.
+	 */
+	panic("I believe this is dead code.  If we hit this, I was wrong");
+#if 0
+	SCpnt->request_bufflen = SCpnt->request.nr_sectors << 9;
+	SCpnt->request_buffer = SCpnt->request.buffer;
+	SCpnt->use_sg = 0;
+	/*
+	 * FIXME(eric) - need to handle DMA here.
+	 */
+#endif
+	return 1;
+    }
+
+    req = &SCpnt->request;
+    /*
+     * First we need to know how many scatter gather segments are needed.
+     */
+    if( !sg_count_valid )
+    {
+	count = __count_segments(req, use_clustering, dma_host);
+    }
+    else
+    {
+	count = req->nr_sg_segments;
+    }
+
+    /*
+     * If the dma pool is nearly empty, then queue a minimal request
+     * with a single segment.  Typically this will satisfy a single
+     * buffer.
+     */
+    if( dma_host && scsi_dma_free_sectors <= 10 )
+    {
+	this_count = SCpnt->request.current_nr_sectors;
+	goto single_segment;
+    }
+
+    /*
+     * Don't bother with scatter-gather if there is only one segment.
+     */
+    if( count == 1 )
+    {
+	this_count = SCpnt->request.nr_sectors;
+	goto single_segment;
+    }
+
+    SCpnt->use_sg = count;
+    
+    /* 
+     * Allocate the actual scatter-gather table itself.
+     * scsi_malloc can only allocate in chunks of 512 bytes 
+     */
+    SCpnt->sglist_len  = (SCpnt->use_sg 
+			  * sizeof(struct scatterlist) + 511) & ~511;
+    
+    sgpnt = (struct scatterlist * ) scsi_malloc(SCpnt->sglist_len);
+    
+    /*
+     * Now fill the scatter-gather table.
+     */
+    if (!sgpnt) 
+    {
+	/*
+	 * If we cannot allocate the scatter-gather table, then
+	 * simply write the first buffer all by itself.
+	 */
+	printk("Warning - running *really* short on DMA buffers\n");
+	this_count = SCpnt->request.current_nr_sectors;
+	goto single_segment;
+    }
+
+    /* 
+     * Next, walk the list, and fill in the addresses and sizes of
+     * each segment.
+     */
+    memset(sgpnt, 0, SCpnt->sglist_len);  
+    SCpnt->request_buffer = (char *) sgpnt;
+    SCpnt->request_bufflen     = 0;
+    bhprev = NULL;
+    
+    for(count = 0, bh = SCpnt->request.bh;
+	bh; bh = bh->b_reqnext) 
+    {
+	if( use_clustering && bhprev != NULL)
+	{
+	    if( dma_host &&
+		virt_to_phys(bhprev->b_data-1) == ISA_DMA_THRESHOLD)
+	    {
+		/* Nothing - fall through */
+	    }
+	    else if( CONTIGUOUS_BUFFERS(bhprev, bh) )
+	    {
+		/*
+		 * This one is OK.  Let it go.
+		 */
+		sgpnt[count - 1].length    += bh->b_size;
+		if( !dma_host )
+		{
+		    SCpnt->request_bufflen     += bh->b_size;
+		}
+		bhprev                      = bh;
+		continue;
+	    }
+	}
+	count++;
+	sgpnt[count - 1].address    = bh->b_data;
+	sgpnt[count - 1].length    += bh->b_size;
+	if( !dma_host )
+	{
+	    SCpnt->request_bufflen     += bh->b_size;
+	}
+	bhprev                      = bh;
+    }
+    
+    /*
+     * Verify that the count is correct.
+     */
+    if( count != SCpnt->use_sg )
+    {
+	panic("Incorrect sg segment count");
+    }
+
+    if( !dma_host )
+    {
+	return 1;
+    }
+
+    /*
+     * Now allocate bounce buffers, if needed.
+     */
+    SCpnt->request_bufflen     = 0;
+    for(i=0; i < count; i++)
+    {
+	SCpnt->request_bufflen     += sgpnt[i].length;
+	if (virt_to_phys(sgpnt[i].address) + sgpnt[i].length - 1 >
+	    ISA_DMA_THRESHOLD && !sgpnt[count].alt_address) 
+	{
+	    sgpnt[i].alt_address = sgpnt[i].address;
+	    sgpnt[i].address =
+		(char *) scsi_malloc(sgpnt[i].length);
+	    /*
+	     * If we cannot allocate memory for this DMA bounce
+	     * buffer, then queue just what we have done so far.
+	     */
+	    if( sgpnt[i].address == NULL )
+	    {
+		printk("Warning - running low on DMA memory\n");
+		SCpnt->request_bufflen     -= sgpnt[i].length;		
+		SCpnt->use_sg = i;
+		if( i == 0 )
+		{
+		    panic("DMA pool exhausted");
+		}
+		break;
+	    }
+	    if (SCpnt->request.cmd == WRITE)
+	    {
+		memcpy(sgpnt[i].address, sgpnt[i].alt_address,
+		       sgpnt[i].length);
+	    }
+	}
+    }
+    return 1;
+
+ single_segment:
+    /*
+     * Come here if for any reason we choose to do this as a single
+     * segment.  Possibly the entire request, or possibly a small
+     * chunk of the entire request.
+     */
+    bh = SCpnt->request.bh;
+    buff = SCpnt->request.buffer;
+
+    if( dma_host )
+    {
+	/*
+	 * Allocate a DMA bounce buffer.  If the allocation fails, fall
+	 * back and allocate a really small one - enough to satisfy
+	 * the first buffer.
+	 */
+	if( virt_to_phys(SCpnt->request.bh->b_data)
+	    + (this_count << 9) - 1 > ISA_DMA_THRESHOLD)
+	{
+	    buff = (char *) scsi_malloc(this_count << 9);
+	    if( !buff )
+	    {
+		printk("Warning - running low on DMA memory\n");
+		this_count = SCpnt->request.current_nr_sectors;
+		buff = (char *) scsi_malloc(this_count << 9);
+		if( !buff )
+		{
+		    panic("Unable to allocate DMA buffer\n");
+		}
+	    }
+	    if (SCpnt->request.cmd == WRITE)
+		memcpy(buff, (char *)SCpnt->request.buffer, this_count << 9);
+	}
+    }
+
+    SCpnt->request_bufflen = this_count << 9;
+    SCpnt->request_buffer  = buff;
+    SCpnt->use_sg = 0;
+    return 1;
+}
+
+#define INITIO(_FUNCTION, _VALID, _CLUSTER, _DMA)	\
+static int _FUNCTION(Scsi_Cmnd * SCpnt)			\
+{							\
+    return __init_io(SCpnt, _VALID, _CLUSTER, _DMA);	\
+}
+
+INITIO(scsi_init_io_,   0, 0, 0)
+INITIO(scsi_init_io_d,  0, 0, 1)
+INITIO(scsi_init_io_c,  0, 1, 0)
+INITIO(scsi_init_io_dc, 0, 1, 1)
+
+INITIO(scsi_init_io_v,   1, 0, 0)
+INITIO(scsi_init_io_vd,  1, 0, 1)
+INITIO(scsi_init_io_vc,  1, 1, 0)
+INITIO(scsi_init_io_vdc, 1, 1, 1)
+
+/*
+ * Function:    initialize_merge_fn()
+ *
+ * Purpose:     Initialize merge function for a host
+ *
+ * Arguments:   SHpnt	- Host descriptor.
+ *
+ * Returns:     Nothing.
+ *
+ * Lock status: 
+ *
+ * Notes:
+ */
+void
+initialize_merge_fn(Scsi_Device * SDpnt)
+{
+    request_queue_t * q;
+    struct Scsi_Host * SHpnt;
+    SHpnt = SDpnt->host;
+
+    q = &SDpnt->request_queue;
+
+    /*
+     * If the host has already selected a merge manager, then don't
+     * pick a new one.
+     */
+    if( q->merge_fn != NULL )
+    {
+	return;
+    }
+
+    /*
+     * If this host has an unlimited tablesize, then don't bother with a
+     * merge manager.  The whole point of the operation is to make sure
+     * that requests don't grow too large, and this host isn't picky.
+     */
+    if( SHpnt->sg_tablesize == SG_ALL )
+    {
+	if( !CLUSTERABLE_DEVICE(SHpnt, SDpnt) && SHpnt->unchecked_isa_dma == 0 )
+	{
+	    SDpnt->scsi_init_io_fn = scsi_init_io_;
+	}
+	else if( !CLUSTERABLE_DEVICE(SHpnt, SDpnt) && SHpnt->unchecked_isa_dma != 0 )
+	{
+	    SDpnt->scsi_init_io_fn = scsi_init_io_d;
+	}
+	else if( CLUSTERABLE_DEVICE(SHpnt, SDpnt) && SHpnt->unchecked_isa_dma == 0 )
+	{
+	    SDpnt->scsi_init_io_fn = scsi_init_io_c;
+	}
+	else if( CLUSTERABLE_DEVICE(SHpnt, SDpnt) && SHpnt->unchecked_isa_dma != 0 )
+	{
+	    SDpnt->scsi_init_io_fn = scsi_init_io_dc;
+	}
+	return;
+    }
+
+    /*
+     * Now pick out the correct function.
+     */
+    if( !CLUSTERABLE_DEVICE(SHpnt, SDpnt) && SHpnt->unchecked_isa_dma == 0 )
+    {
+	q->merge_fn            = scsi_merge_fn_;
+	q->merge_requests_fn   = scsi_merge_requests_fn_;
+	SDpnt->scsi_init_io_fn = scsi_init_io_v;
+    }
+    else if( !CLUSTERABLE_DEVICE(SHpnt, SDpnt) && SHpnt->unchecked_isa_dma != 0 )
+    {
+	q->merge_fn          = scsi_merge_fn_d;
+	q->merge_requests_fn = scsi_merge_requests_fn_d;
+	SDpnt->scsi_init_io_fn = scsi_init_io_vd;
+    }
+    else if( CLUSTERABLE_DEVICE(SHpnt, SDpnt) && SHpnt->unchecked_isa_dma == 0 )
+    {
+	q->merge_fn          = scsi_merge_fn_c;
+	q->merge_requests_fn = scsi_merge_requests_fn_c;
+	SDpnt->scsi_init_io_fn = scsi_init_io_vc;
+    }
+    else if( CLUSTERABLE_DEVICE(SHpnt, SDpnt) && SHpnt->unchecked_isa_dma != 0 )
+    {
+	q->merge_fn          = scsi_merge_fn_dc;
+	q->merge_requests_fn = scsi_merge_requests_fn_dc;
+	SDpnt->scsi_init_io_fn = scsi_init_io_vdc;
+    }
+}
+#endif
diff -u -r linux.clean/drivers/scsi/scsi_obsolete.c linux.new2/drivers/scsi/scsi_obsolete.c
--- linux.clean/drivers/scsi/scsi_obsolete.c	Sun Jan 17 21:29:54 1999
+++ linux.new2/drivers/scsi/scsi_obsolete.c	Wed Jul 28 19:22:39 1999
@@ -13,7 +13,7 @@
  *      Tommy Thorn <tthorn>
  *      Thomas Wuensche <tw@fgb1.fgb.mw.tu-muenchen.de>
  *
- *  Modified by Eric Youngdale eric@aib.com to
+ *  Modified by Eric Youngdale eric@andante.org to
  *  add scatter-gather, multiple outstanding request, and other
  *  enhancements.
  *
@@ -84,7 +84,12 @@
 extern void scsi_old_done (Scsi_Cmnd *SCpnt);
 int update_timeout (Scsi_Cmnd *, int);
 extern void scsi_old_times_out (Scsi_Cmnd * SCpnt);
+
+#ifdef CONFIG_SCSI_NEW_QUEUES
+extern int scsi_dispatch_cmd (Scsi_Cmnd * SCpnt);
+#else
 extern void internal_cmnd (Scsi_Cmnd * SCpnt);
+#endif
 
 extern volatile struct Scsi_Host * host_active;
 #define SCSI_BLOCK(HOST) ((HOST->block && host_active && HOST != host_active) \
@@ -233,7 +238,11 @@
     SCpnt->use_sg = 0;
     SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
     SCpnt->result = 0;
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    scsi_dispatch_cmd (SCpnt);
+#else
     internal_cmnd (SCpnt);
+#endif
 }
 
 
@@ -654,7 +663,11 @@
 	    SCpnt->use_sg = SCpnt->old_use_sg;
 	    SCpnt->cmd_len = SCpnt->old_cmd_len;
             SCpnt->result = 0;
-	    internal_cmnd (SCpnt);
+#ifdef CONFIG_SCSI_NEW_QUEUES
+            scsi_dispatch_cmd (SCpnt);
+#else
+            internal_cmnd (SCpnt);
+#endif
 	}
 	break;
     default:
@@ -667,6 +680,7 @@
 #endif
 	host->host_busy--; /* Indicate that we are free */
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
 	if (host->block && host->host_busy == 0) {
 	    host_active = NULL;
 
@@ -681,6 +695,7 @@
 	}
 
 	wake_up(&host->host_wait);
+#endif
 	SCpnt->result = result | ((exit & 0xff) << 24);
 	SCpnt->use_sg = SCpnt->old_use_sg;
 	SCpnt->cmd_len = SCpnt->old_cmd_len;
@@ -971,7 +986,11 @@
 	    }
 	    else
 	    {
+#ifdef CONFIG_SCSI_NEW_QUEUES
+		host->host_busy++;
+#else
 		if (!host->block) host->host_busy++;
+#endif
 		host->last_reset = jiffies;
 		host->resetting = 1;
 		SCpnt->flags |= (WAS_RESET | IS_RESETTING);
@@ -984,7 +1003,11 @@
 		if (time_before(host->last_reset, jiffies) ||
 		    (time_after(host->last_reset, jiffies + 20 * HZ)))
 		  host->last_reset = jiffies;
+#ifdef CONFIG_SCSI_NEW_QUEUES
+		host->host_busy--;
+#else
 		if (!host->block) host->host_busy--;
+#endif
 	    }
 	    if (reset_flags & SCSI_RESET_SYNCHRONOUS)
 	      SCpnt->flags &= ~SYNC_RESET;
diff -u -r linux.clean/drivers/scsi/scsi_queue.c linux.new2/drivers/scsi/scsi_queue.c
--- linux.clean/drivers/scsi/scsi_queue.c	Mon Jul 27 21:22:12 1998
+++ linux.new2/drivers/scsi/scsi_queue.c	Wed Jul 28 19:22:39 1999
@@ -56,13 +56,16 @@
 
 static const char RCSid[] = "$Header: /mnt/ide/home/eric/CVSROOT/linux/drivers/scsi/scsi_queue.c,v 1.1 1997/10/21 11:16:38 eric Exp $";
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
 /*
  * Lock used to prevent more than one process from frobbing the list at the
  * same time.  FIXME(eric) - there should be separate spinlocks for each host.
- * This will reduce contention.
+ * This will reduce contention.  Then again, this shouldn't be held all
+ * that long in the first place.
  */
 spinlock_t	scsi_mlqueue_lock        = SPIN_LOCK_UNLOCKED;
 spinlock_t	scsi_mlqueue_remove_lock = SPIN_LOCK_UNLOCKED;
+#endif
 
 /*
  * Function:    scsi_mlqueue_insert()
@@ -84,8 +87,10 @@
 int
 scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason)
 {
+#ifndef CONFIG_SCSI_NEW_QUEUES
     Scsi_Cmnd        * cpnt;
     unsigned long      flags;
+#endif
     struct Scsi_Host * host;
 
     SCSI_LOG_MLQUEUE(1,printk("Inserting command %p into mlqueue\n", cmd));
@@ -132,7 +137,7 @@
 	 * If a host is inactive and cannot queue any commands, I don't see
 	 * how things could possibly work anyways.
 	 */
-	if( cmd->device->device_busy == 0 )
+	if( cmd->device->device_blocked == 0 )
 	{
 	    if( scsi_retry_command(cmd) == 0 )
 	    {
@@ -140,7 +145,11 @@
 	    }
 	}
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+	cmd->device->device_blocked = TRUE;
+#else
 	cmd->device->device_busy = TRUE;
+#endif
 	cmd->device_wait         = TRUE;
     }
 
@@ -151,6 +160,13 @@
     cmd->owner = SCSI_OWNER_MIDLEVEL;
     cmd->bh_next = NULL;
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    /*
+     * Insert this command at the head of the queue for it's device.
+     * It will go before all other commands that are already in the queue.
+     */
+    scsi_insert_special_cmd(cmd, 1);
+#else
     /*
      * As a performance enhancement, look to see whether the list is
      * empty.  If it is, then we can just atomicly insert the command
@@ -190,9 +206,11 @@
     }
 
     spin_unlock_irqrestore(&scsi_mlqueue_lock, flags);
+#endif
     return 0;
 }
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
 /*
  * Function:    scsi_mlqueue_finish()
  *
@@ -228,10 +246,18 @@
 	host->host_blocked = FALSE;
     }
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    if( device->device_blocked )
+#else
     if( device->device_busy )
+#endif
     {
 	reason = SCSI_MLQUEUE_DEVICE_BUSY;
+#ifdef CONFIG_SCSI_NEW_QUEUES
+	device->device_blocked = FALSE;
+#else
 	device->device_busy = FALSE;
+#endif
     }
 
     /*
@@ -255,8 +281,13 @@
 	     * the device, then we should keep waiting.  Similarily, if
 	     * the device is now busy, we should also keep waiting.
 	     */
+#ifdef CONFIG_SCSI_NEW_QUEUES
+	    if(    (cpnt->host_wait == FALSE)
+		|| (device->device_blocked == TRUE) )
+#else
 	    if(    (cpnt->host_wait == FALSE)
 		|| (device->device_busy == TRUE) )
+#endif
 	    {
 		prev = cpnt;
 		continue;
@@ -314,3 +345,4 @@
     SCSI_LOG_MLQUEUE(2,printk("scsi_mlqueue_finish returning\n"));
     return 0;
 }
+#endif
diff -u -r linux.clean/drivers/scsi/scsi_syms.c linux.new2/drivers/scsi/scsi_syms.c
--- linux.clean/drivers/scsi/scsi_syms.c	Wed Jun  9 19:59:16 1999
+++ linux.new2/drivers/scsi/scsi_syms.c	Sun Sep  5 16:30:40 1999
@@ -59,7 +59,9 @@
 EXPORT_SYMBOL(scsi_dma_free_sectors);
 EXPORT_SYMBOL(kernel_scsi_ioctl);
 EXPORT_SYMBOL(scsi_need_isa_buffer);
+#ifndef CONFIG_SCSI_NEW_QUEUES
 EXPORT_SYMBOL(scsi_request_queueable);
+#endif
 EXPORT_SYMBOL(scsi_release_command);
 EXPORT_SYMBOL(print_Scsi_Cmnd);
 EXPORT_SYMBOL(scsi_block_when_processing_errors);
@@ -72,6 +74,12 @@
 EXPORT_SYMBOL(scsi_sleep);
 
 EXPORT_SYMBOL(proc_print_scsidevice);
+
+#ifdef CONFIG_SCSI_NEW_QUEUES
+EXPORT_SYMBOL(scsi_io_completion);
+EXPORT_SYMBOL(scsi_end_request);
+#endif
+
 /*
  * These are here only while I debug the rest of the scsi stuff.
  */
@@ -79,6 +87,5 @@
 EXPORT_SYMBOL(scsi_hosts);
 EXPORT_SYMBOL(scsi_devicelist);
 EXPORT_SYMBOL(scsi_device_types);
-
 
 #endif /* CONFIG_MODULES */
diff -u -r linux.clean/drivers/scsi/sd.c linux.new2/drivers/scsi/sd.c
--- linux.clean/drivers/scsi/sd.c	Wed Jul 28 18:24:34 1999
+++ linux.new2/drivers/scsi/sd.c	Wed Jul 28 19:45:36 1999
@@ -1,6 +1,6 @@
 /*
  *      sd.c Copyright (C) 1992 Drew Eckhardt
- *           Copyright (C) 1993, 1994, 1995 Eric Youngdale
+ *           Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale
  *
  *      Linux scsi disk driver
  *              Initial versions: Drew Eckhardt
@@ -8,11 +8,11 @@
  *
  *      <drew@colorado.edu>
  *
- *       Modified by Eric Youngdale ericy@cais.com to
+ *       Modified by Eric Youngdale ericy@andante.org to
  *       add scatter-gather, multiple outstanding request, and other
  *       enhancements.
  *
- *       Modified by Eric Youngdale eric@aib.com to support loadable
+ *       Modified by Eric Youngdale eric@andante.org to support loadable
  *       low-level scsi drivers.
  *
  *       Modified by Jirka Hanika geo@ff.cuni.cz to support more
@@ -94,13 +94,20 @@
 
 static int sd_init_onedisk(int);
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
 static void requeue_sd_request (Scsi_Cmnd * SCpnt);
+#endif
 
 static int sd_init(void);
 static void sd_finish(void);
 static int sd_attach(Scsi_Device *);
 static int sd_detect(Scsi_Device *);
 static void sd_detach(Scsi_Device *);
+static void rw_intr (Scsi_Cmnd *SCpnt);
+
+#ifdef CONFIG_SCSI_NEW_QUEUES
+static int sd_init_command(Scsi_Cmnd *);
+#endif
 
 static void sd_devname(unsigned int disknum, char * buffer)
 {
@@ -120,12 +127,193 @@
 }
 
 struct Scsi_Device_Template sd_template =
-{ NULL, "disk", "sd", NULL, TYPE_DISK,
-      SCSI_DISK0_MAJOR, 0, 0, 0, 1,
-      sd_detect, sd_init,
-      sd_finish, sd_attach, sd_detach
+{
+    name:         "disk",
+    tag:          "sd", 
+    scsi_type:    TYPE_DISK,
+    major:        SCSI_DISK0_MAJOR, 
+    blk:          1,
+    detect:       sd_detect, 
+    init:         sd_init,
+    finish:       sd_finish, 
+    attach:       sd_attach, 
+    detach:       sd_detach,
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    init_command: sd_init_command,
+#endif
 };
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+static request_queue_t * sd_find_queue(kdev_t dev)
+{
+     Scsi_Disk       * dpnt;
+    int target;
+    target =  DEVICE_NR(dev);
+
+    dpnt = &rscsi_disks[target];
+    if(!dpnt)
+	return NULL;   /* No such device */
+    return &dpnt->device->request_queue;
+}
+
+static int sd_init_command(Scsi_Cmnd * SCpnt)
+{
+    int dev, devm, block, this_count;
+    Scsi_Disk           * dpnt;
+    char nbuff[6];
+
+    devm =  MINOR(SCpnt->request.rq_dev);
+    dev = DEVICE_NR(SCpnt->request.rq_dev);
+
+    block = SCpnt->request.sector;
+    this_count = SCpnt->request_bufflen >> 9;
+
+    SCSI_LOG_HLQUEUE(1,printk("Doing sd request, dev = %d, block = %d\n", devm, block));
+
+    dpnt = &rscsi_disks[dev];
+    if (devm >= (sd_template.dev_max << 4) ||
+        !dpnt || 
+	!dpnt->device->online ||
+	block + SCpnt->request.nr_sectors > sd[devm].nr_sects)
+    {
+        SCSI_LOG_HLQUEUE(2,printk("Finishing %ld sectors\n", SCpnt->request.nr_sectors));
+	SCpnt = scsi_end_request(SCpnt, 0, SCpnt->request.nr_sectors);
+        SCSI_LOG_HLQUEUE(2,printk("Retry with 0x%p\n", SCpnt));
+        return 0;
+    }
+
+    block += sd[devm].start_sect;
+    if (dpnt->device->changed)
+    {
+	/*
+	 * quietly refuse to do anything to a changed disc until the changed
+	 * bit has been reset
+	 */
+	/* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
+	SCpnt = scsi_end_request(SCpnt, 0, SCpnt->request.nr_sectors);
+        return 0;
+    }
+
+    SCSI_LOG_HLQUEUE(2,sd_devname(devm, nbuff));
+    SCSI_LOG_HLQUEUE(2,printk("%s : real dev = /dev/%d, block = %d\n",
+	   nbuff, dev, block));
+
+    /*
+     * If we have a 1K hardware sectorsize, prevent access to single
+     * 512 byte sectors.  In theory we could handle this - in fact
+     * the scsi cdrom driver must be able to handle this because
+     * we typically use 1K blocksizes, and cdroms typically have
+     * 2K hardware sectorsizes.  Of course, things are simpler
+     * with the cdrom, since it is read-only.  For performance
+     * reasons, the filesystems should be able to handle this
+     * and not force the scsi disk driver to use bounce buffers
+     * for this.
+     */
+    if (dpnt->device->sector_size == 1024)
+    {
+	if((block & 1) || (SCpnt->request.nr_sectors & 1)) 
+        {
+	    printk("sd.c:Bad block number requested");
+	    SCpnt = scsi_end_request(SCpnt, 0, SCpnt->request.nr_sectors);
+	    return 0;
+	}
+        else
+        {
+            block = block >> 1;
+            this_count = this_count >> 1;
+        }
+    }
+
+     if (dpnt->device->sector_size == 2048)
+     {
+         if((block & 3) || (SCpnt->request.nr_sectors & 3)) 
+         {
+             printk("sd.c:Bad block number requested");
+             SCpnt = scsi_end_request(SCpnt, 0, SCpnt->request.nr_sectors);
+             return 0;
+         }
+         else
+         {
+             block = block >> 2;
+             this_count = this_count >> 2;
+         }
+     }
+    switch (SCpnt->request.cmd)
+    {
+    case WRITE :
+	if (!dpnt->device->writeable)
+	{
+	    SCpnt = scsi_end_request(SCpnt, 0, SCpnt->request.nr_sectors);
+            return 0;
+	}
+	SCpnt->cmnd[0] = WRITE_6;
+	break;
+    case READ :
+	SCpnt->cmnd[0] = READ_6;
+	break;
+    default :
+	panic ("Unknown sd command %d\n", SCpnt->request.cmd);
+    }
+
+    SCSI_LOG_HLQUEUE(2,printk("%s : %s %d/%ld 512 byte blocks.\n",
+                              nbuff,
+                              (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
+                              this_count, SCpnt->request.nr_sectors));
+
+    SCpnt->cmnd[1] = (SCpnt->lun << 5) & 0xe0;
+     
+    if (((this_count > 0xff) ||  (block > 0x1fffff)) && SCpnt->device->ten)
+    {
+	if (this_count > 0xffff)
+	    this_count = 0xffff;
+
+	SCpnt->cmnd[0] += READ_10 - READ_6 ;
+	SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff;
+	SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff;
+	SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff;
+	SCpnt->cmnd[5] = (unsigned char) block & 0xff;
+	SCpnt->cmnd[6] = SCpnt->cmnd[9] = 0;
+	SCpnt->cmnd[7] = (unsigned char) (this_count >> 8) & 0xff;
+	SCpnt->cmnd[8] = (unsigned char) this_count & 0xff;
+    }
+    else
+    {
+	if (this_count > 0xff)
+	    this_count = 0xff;
+
+	SCpnt->cmnd[1] |= (unsigned char) ((block >> 16) & 0x1f);
+	SCpnt->cmnd[2] = (unsigned char) ((block >> 8) & 0xff);
+	SCpnt->cmnd[3] = (unsigned char) block & 0xff;
+	SCpnt->cmnd[4] = (unsigned char) this_count;
+	SCpnt->cmnd[5] = 0;
+    }
+
+    /*
+     * We shouldn't disconnect in the middle of a sector, so with a dumb
+     * host adapter, it's safe to assume that we can at least transfer
+     * this many bytes between each connect / disconnect.
+     */
+    SCpnt->transfersize = dpnt->device->sector_size;
+    SCpnt->underflow = this_count << 9;
+    
+    SCpnt->allowed = MAX_RETRIES;
+    SCpnt->timeout_per_command = (SCpnt->device->type == TYPE_DISK ?
+		  SD_TIMEOUT : SD_MOD_TIMEOUT);
+
+    /*
+     * This is the completion routine we use.  This is matched in terms
+     * of capability to this function.
+     */
+    SCpnt->done = rw_intr;
+
+    /*
+     * This indicates that the command is ready from our end to be
+     * queued.
+     */
+    return 1;
+}
+#endif
+
 static int sd_open(struct inode * inode, struct file * filp)
 {
     int target;
@@ -287,7 +475,7 @@
     int good_sectors = (result == 0 ? this_count : 0);
     int block_sectors = 1;
 
-    sd_devname(DEVICE_NR(SCpnt->request.rq_dev), nbuff);
+    SCSI_LOG_HLCOMPLETE(1,sd_devname(DEVICE_NR(SCpnt->request.rq_dev), nbuff));
 
     SCSI_LOG_HLCOMPLETE(1,printk("%s : rw_intr(%d, %x [%x %x])\n", nbuff,
 	   SCpnt->host->host_no, 
@@ -300,6 +488,47 @@
       relatively rare error condition, no care is taken to avoid unnecessary
       additional work such as memcpy's that could be avoided.
     */
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    if (driver_byte(result) != 0 &&		    /* An error occurred */
+	SCpnt->sense_buffer[0] == 0xF0 &&	    /* Sense data is valid */
+	SCpnt->sense_buffer[2] == MEDIUM_ERROR)
+    {
+	long error_sector = (SCpnt->sense_buffer[3] << 24) |
+			    (SCpnt->sense_buffer[4] << 16) |
+			    (SCpnt->sense_buffer[5] << 8) |
+			    SCpnt->sense_buffer[6];
+	if (SCpnt->request.bh != NULL)
+            block_sectors = SCpnt->request.bh->b_size >> 9;
+        switch(SCpnt->device->sector_size)
+        {
+        case 1024:
+	    error_sector <<= 1;
+	    if (block_sectors < 2) block_sectors = 2;
+            break;
+        case 2048:
+	    error_sector <<= 2;
+	    if (block_sectors < 4) block_sectors = 4;
+            break;
+        case 256:
+            error_sector >>= 1;
+            break;
+        default:
+            break;
+        }
+	error_sector -= sd[MINOR(SCpnt->request.rq_dev)].start_sect;
+	error_sector &= ~ (block_sectors - 1);
+	good_sectors = error_sector - SCpnt->request.sector;
+	if (good_sectors < 0 || good_sectors >= this_count)
+	  good_sectors = 0;
+    }
+
+    /*
+     * This calls the generic completion function, now that we know
+     * how many actual sectors finished, and how many sectors we need
+     * to say have failed.
+     */
+    scsi_io_completion(SCpnt, good_sectors, block_sectors);
+#else
 
     if (driver_byte(result) != 0 &&		    /* An error occurred */
 	SCpnt->sense_buffer[0] == 0xF0 &&	    /* Sense data is valid */
@@ -519,6 +748,7 @@
 	requeue_sd_request(SCpnt);
 	return;
     }
+#endif
 }
 
 /*
@@ -527,7 +757,8 @@
  * them to SCSI commands.
  */
 
-static void do_sd_request (void)
+#ifndef CONFIG_SCSI_NEW_QUEUES
+static void do_sd_request (request_queue_t * q)
 {
     Scsi_Cmnd * SCpnt = NULL;
     Scsi_Device * SDev;
@@ -535,7 +766,7 @@
     int flag = 0;
 
     while (1==1){
-	if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) {
+	if (CURRENT != NULL && q->plugged) {
 	    return;
 	}
 
@@ -627,6 +858,9 @@
 		req1 = req;
 		req = req->next;
 	    }
+            /*
+             * WTF???   Why are we interested in requests that are inactive?
+             */
 	    if (SCpnt && req->rq_status == RQ_INACTIVE) {
 		if (req == CURRENT)
 		    CURRENT = CURRENT->next;
@@ -655,7 +889,7 @@
  repeat:
 
     if(!SCpnt || SCpnt->request.rq_status == RQ_INACTIVE) {
-	do_sd_request();
+	do_sd_request(NULL);
 	return;
     }
 
@@ -1058,6 +1292,7 @@
 		  SD_TIMEOUT : SD_MOD_TIMEOUT),
 		 MAX_RETRIES);
 }
+#endif
 
 static int check_scsidisk_media_change(kdev_t full_dev){
     int retval;
@@ -1141,6 +1376,7 @@
     char          nbuff[6];
     unsigned char *buffer;
     unsigned long spintime;
+    int sector_size;
     int the_result, retries;
     Scsi_Cmnd * SCpnt;
 
@@ -1158,14 +1394,21 @@
         return i;
     }
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
     spin_lock_irq(&io_request_lock);
+#endif
 
     /* We need to retry the READ_CAPACITY because a UNIT_ATTENTION is
      * considered a fatal error, and many devices report such an error
      * just after a scsi bus reset.
      */
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    SCpnt = scsi_allocate_device(rscsi_disks[i].device, 1);
+#else
     SCpnt = scsi_allocate_device(NULL, rscsi_disks[i].device, 1);
+#endif
+
     buffer = (unsigned char *) scsi_malloc(512);
 
     spintime = 0;
@@ -1192,9 +1435,13 @@
 				 (void *) cmd, (void *) buffer,
 				 512, sd_init_done,  SD_TIMEOUT,
 				 MAX_RETRIES);
+#ifndef CONFIG_SCSI_NEW_QUEUES
 		    spin_unlock_irq(&io_request_lock);
+#endif
 		    down(&sem);
+#ifndef CONFIG_SCSI_NEW_QUEUES
 		    spin_lock_irq(&io_request_lock);
+#endif
                     SCpnt->request.sem = NULL;
 		}
 
@@ -1230,9 +1477,13 @@
 				     (void *) cmd, (void *) buffer,
 				     512, sd_init_done,  SD_TIMEOUT,
 				     MAX_RETRIES);
+#ifndef CONFIG_SCSI_NEW_QUEUES
 			spin_unlock_irq(&io_request_lock);
+#endif
 			down(&sem);
+#ifndef CONFIG_SCSI_NEW_QUEUES
 			spin_lock_irq(&io_request_lock);
+#endif
                         SCpnt->request.sem = NULL;
 		    }
 
@@ -1240,10 +1491,14 @@
 		}
 
 		time1 = jiffies + HZ;
+#ifndef CONFIG_SCSI_NEW_QUEUES
 		spin_unlock_irq(&io_request_lock);
+#endif
 		while(jiffies < time1); /* Wait 1 second for next try */
 		printk( "." );
+#ifndef CONFIG_SCSI_NEW_QUEUES
 		spin_lock_irq(&io_request_lock);
+#endif
 	    }
 	} while(the_result && spintime && spintime+100*HZ > jiffies);
 	if (spintime) {
@@ -1272,9 +1527,13 @@
 			 (void *) cmd, (void *) buffer,
 			 8, sd_init_done,  SD_TIMEOUT,
 			 MAX_RETRIES);
+#ifndef CONFIG_SCSI_NEW_QUEUES
 	    spin_unlock_irq(&io_request_lock);
+#endif
 	    down(&sem);	/* sleep until it is ready */
+#ifndef CONFIG_SCSI_NEW_QUEUES
 	    spin_lock_irq(&io_request_lock);
+#endif
             SCpnt->request.sem = NULL;
 	}
 
@@ -1316,7 +1575,7 @@
 	printk("%s : block size assumed to be 512 bytes, disk size 1GB.  \n",
 	       nbuff);
 	rscsi_disks[i].capacity = 0x1fffff;
-	rscsi_disks[i].sector_size = 512;
+	sector_size = 512;
 
 	/* Set dirty bit for removable devices if not ready - sometimes drives
 	 * will not report this properly. */
@@ -1337,23 +1596,32 @@
 				       (buffer[2] << 8) |
 				       buffer[3]);
 
-	rscsi_disks[i].sector_size = (buffer[4] << 24) |
+	sector_size = (buffer[4] << 24) |
 	    (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
 
-	if (rscsi_disks[i].sector_size == 0) {
-	  rscsi_disks[i].sector_size = 512;
+	if (sector_size == 0) {
+	  sector_size = 512;
 	  printk("%s : sector size 0 reported, assuming 512.\n", nbuff);
 	}
 
 
-	if (rscsi_disks[i].sector_size != 512 &&
-	    rscsi_disks[i].sector_size != 1024 &&
-	    rscsi_disks[i].sector_size != 2048 &&
-	    rscsi_disks[i].sector_size != 4096 &&
-	    rscsi_disks[i].sector_size != 256)
+	if (sector_size != 512 &&
+	    sector_size != 1024 &&
+	    sector_size != 2048 &&
+	    sector_size != 4096 &&
+	    sector_size != 256)
 	{
 	    printk ("%s : unsupported sector size %d.\n",
-		    nbuff, rscsi_disks[i].sector_size);
+		    nbuff, sector_size);
+#ifdef CONFIG_SCSI_NEW_QUEUES
+            /*
+             * The user might want to re-format the drive with
+             * a supported sectorsize.  Once this happens, it
+             * would be relatively trivial to set the thing up.
+             * For this reason, we leave the thing in the table.
+             */
+            rscsi_disks[i].capacity = 0;
+#else
 	    if(rscsi_disks[i].device->removable){
 		rscsi_disks[i].capacity = 0;
 	    } else {
@@ -1369,9 +1637,10 @@
                 
 		return i;
 	    }
+#endif
 	}
 
-        if( rscsi_disks[i].sector_size == 2048 )
+        if( sector_size == 2048 )
           {
             int m;
 
@@ -1394,7 +1663,7 @@
 	 */
 	int m, mb;
         int sz_quot, sz_rem;
-	int hard_sector = rscsi_disks[i].sector_size;
+	int hard_sector = sector_size;
 	/* There are 16 minors allocated for each major device */
 	for (m=i<<4; m<((i+1)<<4); m++){
 	    sd_hardsizes[m] = hard_sector;
@@ -1409,13 +1678,13 @@
 		nbuff, hard_sector, rscsi_disks[i].capacity,
                 mb, sz_quot, sz_rem);
     }
-	if(rscsi_disks[i].sector_size == 4096)
+	if(sector_size == 4096)
 	    rscsi_disks[i].capacity <<= 3;
-	if(rscsi_disks[i].sector_size == 2048)
+	if(sector_size == 2048)
 	    rscsi_disks[i].capacity <<= 2;  /* Change into 512 byte sectors */
-	if(rscsi_disks[i].sector_size == 1024)
+	if(sector_size == 1024)
 	    rscsi_disks[i].capacity <<= 1;  /* Change into 512 byte sectors */
-	if(rscsi_disks[i].sector_size == 256)
+	if(sector_size == 256)
 	    rscsi_disks[i].capacity >>= 1;  /* Change into 512 byte sectors */
     }
 
@@ -1452,9 +1721,13 @@
 			 (void *) cmd, (void *) buffer,
 			 512, sd_init_done,  SD_TIMEOUT,
 			 MAX_RETRIES);
+#ifndef CONFIG_SCSI_NEW_QUEUES
 	    spin_unlock_irq(&io_request_lock);
+#endif
 	    down(&sem);
+#ifndef CONFIG_SCSI_NEW_QUEUES
 	    spin_lock_irq(&io_request_lock);
+#endif
             SCpnt->request.sem = NULL;
 	}
 
@@ -1471,15 +1744,25 @@
 
     }	/* check for write protect */
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    SCpnt->device->ten   = 1;
+    SCpnt->device->remap = 1;
+    SCpnt->device->sector_size = sector_size;
+#else
+    rscsi_disks[i].ten = 1;
+    rscsi_disks[i].remap = 1;
+    rscsi_disks[i].sector_size = sector_size;
+#endif
+
     /* Wake up a process waiting for device */
     wake_up(&SCpnt->device->device_wait);
     scsi_release_command(SCpnt);
     SCpnt = NULL;
 
-    rscsi_disks[i].ten = 1;
-    rscsi_disks[i].remap = 1;
     scsi_free(buffer, 512);
+#ifndef CONFIG_SCSI_NEW_QUEUES
     spin_unlock_irq(&io_request_lock);
+#endif
     return i;
 }
 
@@ -1563,23 +1846,30 @@
     return 0;
 }
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
 /*
  * sd_get_queue() returns the queue which corresponds to a given device.
  */
-static struct request **sd_get_queue (kdev_t dev)
+static request_queue_t *sd_get_queue (kdev_t dev)
 {
-	return &blk_dev[MAJOR_NR].current_request;
+	return &blk_dev[MAJOR_NR].request_queue;
 }
+#endif
 
 static void sd_finish()
 {
     struct gendisk *gendisk;
     int i;
 
-    for (i=0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) {
-        /* FIXME: After 2.2 we should implement multiple sd queues */
-        blk_dev[SD_MAJOR(i)].request_fn = DEVICE_REQUEST;
+    for (i=0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) 
+    {
+#ifdef CONFIG_SCSI_NEW_QUEUES
+        blk_dev[SD_MAJOR(i)].queue = sd_find_queue;
+#else
+        blk_init_queue(BLK_DEFAULT_QUEUE(SD_MAJOR(i)), DEVICE_REQUEST);
+        blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0);
         if (i) blk_dev[SD_MAJOR(i)].queue = sd_get_queue;
+#endif
     }
 
     for (gendisk = gendisk_head; gendisk != NULL; gendisk = gendisk->next)
@@ -1651,7 +1941,9 @@
 
     if(i >= sd_template.dev_max) panic ("scsi_devices corrupt (sd)");
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
     SDp->scsi_request_fn = do_sd_request;
+#endif
     rscsi_disks[i].device = SDp;
     rscsi_disks[i].has_part_table = 0;
     sd_template.nr_dev++;
@@ -1704,7 +1996,11 @@
          * to make sure that everything remains consistent.
          */
         sd_blocksizes[index] = 1024;
+#ifdef CONFIG_SCSI_NEW_QUEUES
+        if( rscsi_disks[target].device->sector_size == 2048 )
+#else
         if( rscsi_disks[target].sector_size == 2048 )
+#endif
           sd_blocksizes[index] = 2048;
         else
           sd_blocksizes[index] = 1024;
@@ -1816,7 +2112,7 @@
     }
 
     for (i=0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) {
-        blk_dev[SD_MAJOR(i)].request_fn = NULL;
+        blk_cleanup_queue(BLK_DEFAULT_QUEUE(SD_MAJOR(i)));
         blk_size[SD_MAJOR(i)] = NULL;
         hardsect_size[SD_MAJOR(i)] = NULL;
         read_ahead[SD_MAJOR(i)] = 0;
diff -u -r linux.clean/drivers/scsi/sd.h linux.new2/drivers/scsi/sd.h
--- linux.clean/drivers/scsi/sd.h	Mon Sep  6 09:03:52 1999
+++ linux.new2/drivers/scsi/sd.h	Mon Sep  6 09:03:14 1999
@@ -5,7 +5,7 @@
  *
  *	<drew@colorado.edu>
  *
- *	 Modified by Eric Youngdale eric@aib.com to
+ *	 Modified by Eric Youngdale eric@andante.org to
  *	 add scatter-gather, multiple outstanding request, and other
  *	 enhancements.
  */
@@ -27,14 +27,18 @@
 
 typedef struct scsi_disk {
     unsigned capacity;		    /* size in blocks */
+#ifndef CONFIG_SCSI_NEW_QUEUES
     unsigned sector_size;	    /* size in bytes */
+#endif
     Scsi_Device	 *device;	    
     unsigned char ready;	    /* flag ready for FLOPTICAL */
     unsigned char write_prot;	    /* flag write_protect for rmvable dev */
     unsigned char sector_bit_size;  /* sector_size = 2 to the  bit size power */
     unsigned char sector_bit_shift; /* power of 2 sectors per FS block */
+#ifndef CONFIG_SCSI_NEW_QUEUES
     unsigned ten:1;		    /* support ten byte read / write */
     unsigned remap:1;		    /* support remapping  */
+#endif
     unsigned has_part_table:1;	    /* has partition table */
 } Scsi_Disk;
 
diff -u -r linux.clean/drivers/scsi/sg.c linux.new2/drivers/scsi/sg.c
--- linux.clean/drivers/scsi/sg.c	Mon Jun  7 19:26:25 1999
+++ linux.new2/drivers/scsi/sg.c	Wed Jul 28 19:22:40 1999
@@ -366,7 +366,9 @@
 static ssize_t sg_write(struct file * filp, const char * buf, 
                         size_t count, loff_t *ppos)
 {
+#ifndef CONFIG_SCSI_NEW_QUEUES
     unsigned long         flags;
+#endif
     int                   mxsize, cmd_size, k;
     unsigned char         cmnd[MAX_COMMAND_SIZE];
     int                   input_size;
@@ -432,8 +434,14 @@
         return k;    /* probably out of space --> ENOMEM */
     }
 /*  SCSI_LOG_TIMEOUT(7, printk("sg_write: allocating device\n")); */
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    if (! (SCpnt = scsi_allocate_device(sdp->device, 
+                                        !(filp->f_flags & O_NONBLOCK)))) 
+#else
     if (! (SCpnt = scsi_allocate_device(NULL, sdp->device, 
-                                        !(filp->f_flags & O_NONBLOCK)))) {
+                                        !(filp->f_flags & O_NONBLOCK)))) 
+#endif
+    {
         sg_finish_rem_req(srp, NULL, 0);
         return -EAGAIN;   /* No available command blocks at the moment */
     }
@@ -448,7 +456,9 @@
     cmnd[1]= (cmnd[1] & 0x1f) | (sdp->device->lun << 5);
 
 /*  SCSI_LOG_TIMEOUT(7, printk("sg_write: do cmd\n")); */
+#ifndef CONFIG_SCSI_NEW_QUEUES
     spin_lock_irqsave(&io_request_lock, flags);
+#endif
     SCpnt->use_sg = srp->data.use_sg;
     SCpnt->sglist_len = srp->data.sglist_len;
     SCpnt->bufflen = srp->data.bufflen;
@@ -467,7 +477,9 @@
                 (void *)SCpnt->buffer, mxsize,
                 sg_command_done, sfp->timeout, SG_DEFAULT_RETRIES);
     /* 'mxsize' overwrites SCpnt->bufflen, hence need for b_malloc_len */
+#ifndef CONFIG_SCSI_NEW_QUEUES
     spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 /*  SCSI_LOG_TIMEOUT(6, printk("sg_write: sent scsi cmd to mid-level\n")); */
     return count;
 }
@@ -1099,7 +1111,13 @@
         scsi_add_timer(scpnt, scpnt->timeout_per_command,
                        scsi_old_times_out);
 #else
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    spin_unlock_irq(&io_request_lock);
+#endif
     scsi_sleep(HZ); /* just sleep 1 second and hope ... */
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    spin_lock_irq(&io_request_lock);
+#endif
 #endif
 }
 
diff -u -r linux.clean/drivers/scsi/sr.c linux.new2/drivers/scsi/sr.c
--- linux.clean/drivers/scsi/sr.c	Tue May 11 17:37:40 1999
+++ linux.new2/drivers/scsi/sr.c	Wed Jul 28 19:47:14 1999
@@ -1,17 +1,17 @@
 /*
  *  sr.c Copyright (C) 1992 David Giller
- *	     Copyright (C) 1993, 1994, 1995 Eric Youngdale
+ *	     Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale
  *
  *  adapted from:
  *	sd.c Copyright (C) 1992 Drew Eckhardt
  *	Linux scsi disk driver by
  *		Drew Eckhardt <drew@colorado.edu>
  *
- *      Modified by Eric Youngdale ericy@cais.com to
+ *      Modified by Eric Youngdale ericy@andante.org to
  *      add scatter-gather, multiple outstanding request, and other
  *      enhancements.
  *
- *	    Modified by Eric Youngdale eric@aib.com to support loadable
+ *	    Modified by Eric Youngdale eric@andante.org to support loadable
  *	    low-level scsi drivers.
  *
  *	 Modified by Thomas Quinot thomas@melchior.cuivre.fdn.fr to
@@ -54,10 +54,26 @@
 static int sr_detect(Scsi_Device *);
 static void sr_detach(Scsi_Device *);
 
-struct Scsi_Device_Template sr_template = {NULL, "cdrom", "sr", NULL, TYPE_ROM,
-                                           SCSI_CDROM_MAJOR, 0, 0, 0, 1,
-                                           sr_detect, sr_init,
-                                           sr_finish, sr_attach, sr_detach};
+#ifdef CONFIG_SCSI_NEW_QUEUES
+static int sr_init_command(Scsi_Cmnd *);
+#endif
+
+struct Scsi_Device_Template sr_template = 
+{
+    name:       "cdrom", 
+    tag:        "sr", 
+    scsi_type:  TYPE_ROM,
+    major:      SCSI_CDROM_MAJOR, 
+    blk:        1,
+    detect:     sr_detect, 
+    init:       sr_init,
+    finish:     sr_finish, 
+    attach:     sr_attach, 
+    detach:     sr_detach,
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    init_command: sr_init_command
+#endif
+};
 
 Scsi_CD * scsi_CDs = NULL;
 static int * sr_sizes = NULL;
@@ -73,8 +89,13 @@
 
 static void sr_release(struct cdrom_device_info *cdi)
 {
+#ifdef CONFIG_SCSI_NEW_QUEUES
+	if (scsi_CDs[MINOR(cdi->dev)].device->sector_size > 2048)
+		sr_set_blocklength(MINOR(cdi->dev),2048);
+#else
 	if (scsi_CDs[MINOR(cdi->dev)].sector_size > 2048)
 		sr_set_blocklength(MINOR(cdi->dev),2048);
+#endif
 	sync_dev(cdi->dev);
 	scsi_CDs[MINOR(cdi->dev)].device->access_count--;
 	if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module)
@@ -153,7 +174,11 @@
                   */
                 scsi_CDs[MINOR(cdi->dev)].needs_sector_size = 1;
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+                scsi_CDs[MINOR(cdi->dev)].device->sector_size = 2048;
+#else
                 scsi_CDs[MINOR(cdi->dev)].sector_size = 2048;
+#endif
         }
 	return retval;
 }
@@ -178,6 +203,46 @@
       Since this is a relatively rare error condition, no care is taken to
       avoid unnecessary additional work such as memcpy's that could be avoided.
     */
+#ifdef CONFIG_SCSI_NEW_QUEUES
+
+    if (driver_byte(result) != 0 &&		    /* An error occurred */
+        SCpnt->sense_buffer[0] == 0xF0 &&	    /* Sense data is valid */
+        (SCpnt->sense_buffer[2] == MEDIUM_ERROR ||
+         SCpnt->sense_buffer[2] == VOLUME_OVERFLOW ||
+         SCpnt->sense_buffer[2] == ILLEGAL_REQUEST))
+    {
+        long error_sector = (SCpnt->sense_buffer[3] << 24) |
+            (SCpnt->sense_buffer[4] << 16) |
+            (SCpnt->sense_buffer[5] << 8) |
+            SCpnt->sense_buffer[6];
+        int device_nr = DEVICE_NR(SCpnt->request.rq_dev);
+        if (SCpnt->request.bh != NULL)
+            block_sectors = SCpnt->request.bh->b_size >> 9;
+        if (block_sectors < 4) block_sectors = 4;
+        if (scsi_CDs[device_nr].device->sector_size == 2048)
+            error_sector <<= 2;
+        error_sector &= ~ (block_sectors - 1);
+        good_sectors = error_sector - SCpnt->request.sector;
+        if (good_sectors < 0 || good_sectors >= this_count)
+            good_sectors = 0;
+        /*
+         * The SCSI specification allows for the value returned by READ
+         * CAPACITY to be up to 75 2K sectors past the last readable
+         * block.  Therefore, if we hit a medium error within the last
+         * 75 2K sectors, we decrease the saved size value.
+         */
+        if ((error_sector >> 1) < sr_sizes[device_nr] &&
+            scsi_CDs[device_nr].capacity - error_sector < 4*75)
+            sr_sizes[device_nr] = error_sector >> 1;
+    }
+
+    /*
+     * This calls the generic completion function, now that we know
+     * how many actual sectors finished, and how many sectors we need
+     * to say have failed.
+     */
+    scsi_io_completion(SCpnt, good_sectors, block_sectors);
+#else
 
 	if (driver_byte(result) != 0 &&		    /* An error occurred */
 	    SCpnt->sense_buffer[0] == 0xF0 &&	    /* Sense data is valid */
@@ -376,7 +441,183 @@
 	SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors);
 	requeue_sr_request(SCpnt);
     }
+#endif
+}
+
+#ifdef CONFIG_SCSI_NEW_QUEUES
+
+static request_queue_t * sr_find_queue(kdev_t dev)
+{
+    if(   MINOR(dev) >= sr_template.dev_max 
+       || !scsi_CDs[MINOR(dev)].device)
+	return NULL;   /* No such device */
+    return &scsi_CDs[MINOR(dev)].device->request_queue;
+}
+
+static int sr_init_command(Scsi_Cmnd * SCpnt)
+{
+    int dev, devm, block, this_count;
+    char nbuff[6];
+
+    devm =  MINOR(SCpnt->request.rq_dev);
+    dev = DEVICE_NR(SCpnt->request.rq_dev);
+
+    block = SCpnt->request.sector;
+    this_count = SCpnt->request_bufflen >> 9;
+
+    if( !SCpnt->request.bh )
+    {
+        /*
+         * Umm, yeah, right.   Swapping to a cdrom.  Nice try.
+         */
+	SCpnt = scsi_end_request(SCpnt, 0, SCpnt->request.nr_sectors);
+        return 0;
+    }
+
+    SCSI_LOG_HLQUEUE(1,printk("Doing sd request, dev = %d, block = %d\n", devm, block));
+
+    if ( dev >= sr_template.nr_dev || 
+	!scsi_CDs[dev].device ||
+	!scsi_CDs[dev].device->online)
+    {
+        SCSI_LOG_HLQUEUE(2,printk("Finishing %ld sectors\n", SCpnt->request.nr_sectors));
+	SCpnt = scsi_end_request(SCpnt, 0, SCpnt->request.nr_sectors);
+        SCSI_LOG_HLQUEUE(2,printk("Retry with 0x%p\n", SCpnt));
+        return 0;
+    }
+
+    if (scsi_CDs[dev].device->changed) 
+    {
+	/*
+	 * quietly refuse to do anything to a changed disc until the changed
+	 * bit has been reset
+	 */
+	/* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
+	SCpnt = scsi_end_request(SCpnt, 0, SCpnt->request.nr_sectors);
+        return 0;
+    }
+
+    /*
+     * we do lazy blocksize switching (when reading XA sectors,
+     * see CDROMREADMODE2 ioctl) 
+     */
+    if( scsi_CDs[dev].device->sector_size > 2048 ) 
+    {
+        if (!in_interrupt())
+            sr_set_blocklength(DEVICE_NR(CURRENT->rq_dev),2048);
+        else
+            printk("sr: can't switch blocksize: in interrupt\n");
+    }
+
+    if( SCpnt->request.cmd == WRITE )
+    {
+	SCpnt = scsi_end_request(SCpnt, 0, SCpnt->request.nr_sectors);
+        return 0;
+    }
+
+    if (scsi_CDs[dev].device->sector_size == 1024)
+    {
+	if((block & 1) || (SCpnt->request.nr_sectors & 1)) 
+        {
+	    printk("sd.c:Bad block number requested");
+	    SCpnt = scsi_end_request(SCpnt, 0, SCpnt->request.nr_sectors);
+	    return 0;
+	}
+        else
+        {
+            block = block >> 1;
+            this_count = this_count >> 1;
+        }
+    }
+
+     if (scsi_CDs[dev].device->sector_size == 2048)
+     {
+         if((block & 3) || (SCpnt->request.nr_sectors & 3)) 
+         {
+             printk("sd.c:Bad block number requested");
+             SCpnt = scsi_end_request(SCpnt, 0, SCpnt->request.nr_sectors);
+             return 0;
+         }
+         else
+         {
+             block = block >> 2;
+             this_count = this_count >> 2;
+         }
+     }
+    switch (SCpnt->request.cmd)
+    {
+    case WRITE :
+	if (!scsi_CDs[dev].device->writeable)
+	{
+	    SCpnt = scsi_end_request(SCpnt, 0, SCpnt->request.nr_sectors);
+            return 0;
+	}
+	SCpnt->cmnd[0] = WRITE_6;
+	break;
+    case READ :
+	SCpnt->cmnd[0] = READ_6;
+	break;
+    default :
+	panic ("Unknown sd command %d\n", SCpnt->request.cmd);
+    }
+
+    SCSI_LOG_HLQUEUE(2,printk("%s : %s %d/%ld 512 byte blocks.\n",
+                              nbuff,
+                              (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
+                              this_count, SCpnt->request.nr_sectors));
+
+    SCpnt->cmnd[1] = (SCpnt->lun << 5) & 0xe0;  
+   
+    if (((this_count > 0xff) ||  (block > 0x1fffff)) && SCpnt->device->ten)
+    {
+	if (this_count > 0xffff)
+	    this_count = 0xffff;
+
+	SCpnt->cmnd[0] += READ_10 - READ_6 ;
+	SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff;
+	SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff;
+	SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff;
+	SCpnt->cmnd[5] = (unsigned char) block & 0xff;
+	SCpnt->cmnd[6] = SCpnt->cmnd[9] = 0;
+	SCpnt->cmnd[7] = (unsigned char) (this_count >> 8) & 0xff;
+	SCpnt->cmnd[8] = (unsigned char) this_count & 0xff;
+    }
+    else
+    {
+	if (this_count > 0xff)
+	    this_count = 0xff;
+
+	SCpnt->cmnd[1] |= (unsigned char) ((block >> 16) & 0x1f);
+	SCpnt->cmnd[2] = (unsigned char) ((block >> 8) & 0xff);
+	SCpnt->cmnd[3] = (unsigned char) block & 0xff;
+	SCpnt->cmnd[4] = (unsigned char) this_count;
+	SCpnt->cmnd[5] = 0;
+    }
+
+    /*
+     * We shouldn't disconnect in the middle of a sector, so with a dumb
+     * host adapter, it's safe to assume that we can at least transfer
+     * this many bytes between each connect / disconnect.
+     */
+    SCpnt->transfersize = scsi_CDs[dev].device->sector_size;
+    SCpnt->underflow = this_count << 9;
+    
+    SCpnt->allowed = MAX_RETRIES;
+    SCpnt->timeout_per_command = SR_TIMEOUT;
+
+    /*
+     * This is the completion routine we use.  This is matched in terms
+     * of capability to this function.
+     */
+    SCpnt->done = rw_intr;
+
+    /*
+     * This indicates that the command is ready from our end to be
+     * queued.
+     */
+    return 1;
 }
+#endif
 
 static int sr_open(struct cdrom_device_info *cdi, int purpose)
 {
@@ -419,8 +660,8 @@
  * Its function in life is to take block device requests, and
  * translate them to SCSI commands.
  */
-
-static void do_sr_request (void)
+#ifndef CONFIG_SCSI_NEW_QUEUES
+static void do_sr_request (request_queue_t * q)
 {
     Scsi_Cmnd * SCpnt = NULL;
     struct request * req = NULL;
@@ -428,7 +669,7 @@
     int flag = 0;
 
     while (1==1){
-	if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) {
+	if (CURRENT != NULL && q->plugged) {
 	    return;
 	};
 
@@ -506,6 +747,9 @@
 		req1 = req;
 		req = req->next;
 	    }
+            /*
+             * WTF???   Why are we interested in requests that are inactive?
+             */
 	    if (SCpnt && req->rq_status == RQ_INACTIVE) {
 		if (req == CURRENT)
 		    CURRENT = CURRENT->next;
@@ -534,7 +778,7 @@
 
  repeat:
 	if(!SCpnt || SCpnt->request.rq_status == RQ_INACTIVE) {
-		do_sr_request();
+		do_sr_request(NULL);
 		return;
 	}
 
@@ -822,6 +1066,7 @@
 		 realcount * scsi_CDs[dev].sector_size,
 		 rw_intr, SR_TIMEOUT, MAX_RETRIES);
 }
+#endif
 
 static int sr_detect(Scsi_Device * SDp){
 
@@ -851,7 +1096,10 @@
 
     if(i >= sr_template.dev_max) panic ("scsi_devices corrupt (sr)");
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
     SDp->scsi_request_fn = do_sr_request;
+#endif
+
     scsi_CDs[i].device = SDp;
 
     sr_template.nr_dev++;
@@ -873,15 +1121,24 @@
     }
 }
 
-void get_sectorsize(int i){
+void get_sectorsize(int i)
+{
     unsigned char cmd[10];
     unsigned char *buffer;
     int the_result, retries;
+    int sector_size;
     Scsi_Cmnd * SCpnt;
+#ifndef CONFIG_SCSI_NEW_QUEUES
     unsigned long flags;
+#endif
 
     buffer = (unsigned char *) scsi_malloc(512);
+
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    SCpnt = scsi_allocate_device(scsi_CDs[i].device, 1);
+#else
     SCpnt = scsi_allocate_device(NULL, scsi_CDs[i].device, 1);
+#endif
 
     retries = 3;
     do {
@@ -897,12 +1154,16 @@
 	{
 	    DECLARE_MUTEX_LOCKED(sem);
 	    SCpnt->request.sem = &sem;
+#ifndef CONFIG_SCSI_NEW_QUEUES
 	    spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	    scsi_do_cmd (SCpnt,
 			 (void *) cmd, (void *) buffer,
 			 512, sr_init_done,  SR_TIMEOUT,
 			 MAX_RETRIES);
+#ifndef CONFIG_SCSI_NEW_QUEUES
 	    spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	    down(&sem);
 	}
 
@@ -918,16 +1179,16 @@
 
     if (the_result) {
 	scsi_CDs[i].capacity = 0x1fffff;
-	scsi_CDs[i].sector_size = 2048;  /* A guess, just in case */
+	sector_size = 2048;  /* A guess, just in case */
 	scsi_CDs[i].needs_sector_size = 1;
     } else {
 	scsi_CDs[i].capacity = 1 + ((buffer[0] << 24) |
 				    (buffer[1] << 16) |
 				    (buffer[2] << 8) |
 				    buffer[3]);
-	scsi_CDs[i].sector_size = (buffer[4] << 24) |
+	sector_size = (buffer[4] << 24) |
 	    (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
-	switch (scsi_CDs[i].sector_size) {
+	switch (sector_size) {
 		/*
 		 * HP 4020i CD-Recorder reports 2340 byte sectors
 		 * Philips CD-Writers report 2352 byte sectors
@@ -935,7 +1196,7 @@
 		 * Use 2k sectors for them..
 		 */
 		case 0: case 2340: case 2352:
-			scsi_CDs[i].sector_size = 2048;
+			sector_size = 2048;
 			/* fall through */
 		case 2048:
 			scsi_CDs[i].capacity *= 4;
@@ -944,11 +1205,17 @@
 			break;
 		default:
 			printk ("sr%d: unsupported sector size %d.\n",
-				i, scsi_CDs[i].sector_size);
+				i, sector_size);
 			scsi_CDs[i].capacity = 0;
 			scsi_CDs[i].needs_sector_size = 1;
 	}
 
+#ifdef CONFIG_SCSI_NEW_QUEUES
+        scsi_CDs[i].device->sector_size = sector_size;
+#else
+        scsi_CDs[i].sector_size = sector_size;
+#endif
+
         /*
          * Add this so that we have the ability to correctly gauge
          * what the device is capable of.
@@ -1051,7 +1318,13 @@
     int i;
     char name[6];
 
-    blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    blk_dev[MAJOR_NR].queue = sr_find_queue;
+#else
+    blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
+    blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0);
+#endif
+
     blk_size[MAJOR_NR] = sr_sizes;
 
     for (i = 0; i < sr_template.nr_dev; ++i)
@@ -1060,7 +1333,11 @@
 	 * with loadable modules. */
 	if (scsi_CDs[i].capacity) continue;
 	scsi_CDs[i].capacity = 0x1fffff;
+#ifdef CONFIG_SCSI_NEW_QUEUES
+	scsi_CDs[i].device->sector_size = 2048;  /* A guess, just in case */
+#else
 	scsi_CDs[i].sector_size = 2048;  /* A guess, just in case */
+#endif
 	scsi_CDs[i].needs_sector_size = 1;
 	scsi_CDs[i].device->changed = 1; /* force recheck CD type */
 #if 0
@@ -1069,8 +1346,14 @@
 	printk("Scd sectorsize = %d bytes.\n", scsi_CDs[i].sector_size);
 #endif
 	scsi_CDs[i].use = 1;
+
+#ifdef CONFIG_SCSI_NEW_QUEUES
+	scsi_CDs[i].device->ten = 1;
+	scsi_CDs[i].device->remap = 1;
+#else
 	scsi_CDs[i].ten = 1;
 	scsi_CDs[i].remap = 1;
+#endif
       	scsi_CDs[i].readcd_known = 0;
       	scsi_CDs[i].readcd_cdda  = 0;
 	sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9);
@@ -1159,7 +1442,7 @@
     }
 
     blksize_size[MAJOR_NR] = NULL;
-    blk_dev[MAJOR_NR].request_fn = NULL;
+    blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
     blk_size[MAJOR_NR] = NULL;
     read_ahead[MAJOR_NR] = 0;
 
diff -u -r linux.clean/drivers/scsi/sr.h linux.new2/drivers/scsi/sr.h
--- linux.clean/drivers/scsi/sr.h	Mon Sep  6 09:15:13 1999
+++ linux.new2/drivers/scsi/sr.h	Mon Sep  6 09:14:33 1999
@@ -9,7 +9,7 @@
  *
  *	<drew@colorado.edu>
  *
- *       Modified by Eric Youngdale eric@aib.com to
+ *       Modified by Eric Youngdale eric@andante.org to
  *       add scatter-gather, multiple outstanding request, and other
  *       enhancements.
  */
@@ -22,15 +22,20 @@
 typedef struct
 	{
 	unsigned 	capacity;		/* size in blocks 			*/
+#ifndef CONFIG_SCSI_NEW_QUEUES
 	unsigned 	sector_size;		/* size in bytes 			*/
+#endif
+
 	Scsi_Device  	*device;
         unsigned int    vendor;                 /* vendor code, see sr_vendor.c         */
 	unsigned long   ms_offset;              /* for reading multisession-CD's        */
 	unsigned char	sector_bit_size;	/* sector size = 2^sector_bit_size	*/
 	unsigned char	sector_bit_shift;	/* sectors/FS block = 2^sector_bit_shift*/
 	unsigned 	needs_sector_size:1;   	/* needs to get sector size */
+#ifndef CONFIG_SCSI_NEW_QUEUES
 	unsigned 	ten:1;			/* support ten byte commands		*/
 	unsigned 	remap:1;		/* support remapping			*/
+#endif
 	unsigned 	use:1;			/* is this device still supportable	*/
         unsigned	xa_flag:1;              /* CD has XA sectors ? */
 	unsigned 	readcd_known:1;		/* drive supports READ_CD (0xbe) */
diff -u -r linux.clean/drivers/scsi/sr_ioctl.c linux.new2/drivers/scsi/sr_ioctl.c
--- linux.clean/drivers/scsi/sr_ioctl.c	Sun May 16 02:43:04 1999
+++ linux.new2/drivers/scsi/sr_ioctl.c	Wed Jul 28 19:22:40 1999
@@ -56,10 +56,18 @@
     int result, err = 0, retries = 0;
     unsigned long flags;
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
     spin_lock_irqsave(&io_request_lock, flags);
+#endif
     SDev  = scsi_CDs[target].device;
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    SCpnt = scsi_allocate_device(scsi_CDs[target].device, 1);
+#else
     SCpnt = scsi_allocate_device(NULL, scsi_CDs[target].device, 1);
+#endif
+#ifndef CONFIG_SCSI_NEW_QUEUES
     spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 
 retry:
     if( !scsi_block_when_processing_errors(SDev) )
@@ -67,11 +75,15 @@
     {
 	DECLARE_MUTEX_LOCKED(sem);
 	SCpnt->request.sem = &sem;
+#ifndef CONFIG_SCSI_NEW_QUEUES
 	spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	scsi_do_cmd(SCpnt,
 		    (void *) sr_cmd, buffer, buflength, sr_ioctl_done, 
 		    IOCTL_TIMEOUT, IOCTL_RETRIES);
+#ifndef CONFIG_SCSI_NEW_QUEUES
 	spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	down(&sem);
         SCpnt->request.sem = NULL;
     }
@@ -97,14 +109,18 @@
                     printk(KERN_INFO "sr%d: CDROM not ready yet.\n", target);
 		if (retries++ < 10) {
 		    /* sleep 2 sec and try again */
+#ifndef CONFIG_SCSI_NEW_QUEUES
 		    /*
 		     * The spinlock is silly - we should really lock more of this
 		     * function, but the minimal locking required to not lock up
 		     * is around this - scsi_sleep() assumes we hold the spinlock.
 		     */
 		    spin_lock_irqsave(&io_request_lock, flags);
+#endif
 		    scsi_sleep(2*HZ);
+#ifndef CONFIG_SCSI_NEW_QUEUES
 		    spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
                     goto retry;
 		} else {
 		    /* 20 secs are enough? */
@@ -242,7 +258,9 @@
         u_char  sr_cmd[10];
 	char * buffer;
         int result;
+#ifndef CONFIG_SCSI_NEW_QUEUES
         unsigned long flags;
+#endif
         	
 	sr_cmd[0] = SCMD_READ_SUBCHANNEL;
 	sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5);
@@ -254,9 +272,13 @@
 	sr_cmd[8] = 24;
 	sr_cmd[9] = 0;
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	buffer = (unsigned char*) scsi_malloc(512);
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	if(!buffer) return -ENOMEM;
 	
 	result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24, 0);
@@ -264,9 +286,13 @@
 	memcpy (mcn->medium_catalog_number, buffer + 9, 13);
         mcn->medium_catalog_number[13] = 0;
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	scsi_free(buffer, 512);
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	
 	return result;
 }
@@ -396,7 +422,9 @@
     {
 	struct cdrom_tochdr* tochdr = (struct cdrom_tochdr*)arg;
 	char * buffer;
+#ifndef CONFIG_SCSI_NEW_QUEUES
         unsigned long flags;
+#endif
 	
 	sr_cmd[0] = SCMD_READ_TOC;
 	sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5);
@@ -406,9 +434,13 @@
 	sr_cmd[8] = 12;             /* LSB of length */
 	sr_cmd[9] = 0;
 	
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	buffer = (unsigned char *) scsi_malloc(512);
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	if(!buffer) return -ENOMEM;
 	
 	result = sr_do_ioctl(target, sr_cmd, buffer, 12, 1);
@@ -416,9 +448,13 @@
 	tochdr->cdth_trk0 = buffer[2];
 	tochdr->cdth_trk1 = buffer[3];
 	
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	scsi_free(buffer, 512);
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
         break;
     }
 	
@@ -426,7 +462,9 @@
     {
 	struct cdrom_tocentry* tocentry = (struct cdrom_tocentry*)arg;
 	unsigned char * buffer;
+#ifndef CONFIG_SCSI_NEW_QUEUES
         unsigned long flags;
+#endif
 	
 	sr_cmd[0] = SCMD_READ_TOC;
 	sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) |
@@ -437,9 +475,13 @@
 	sr_cmd[8] = 12;            /* LSB of length */
 	sr_cmd[9] = 0;
 	
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	buffer = (unsigned char *) scsi_malloc(512);
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	if(!buffer) return -ENOMEM;
 	
 	result = sr_do_ioctl (target, sr_cmd, buffer, 12, 0);
@@ -455,9 +497,13 @@
 	    tocentry->cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8)
                                        + buffer[10]) << 8) + buffer[11];
 	
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	scsi_free(buffer, 512);
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
         break;
     }
 	
@@ -483,7 +529,9 @@
     {
 	char * buffer, * mask;
 	struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg;
+#ifndef CONFIG_SCSI_NEW_QUEUES
         unsigned long flags;
+#endif
 	
 	/* First we get the current params so we can just twiddle the volume */
 	
@@ -494,16 +542,24 @@
 	sr_cmd[4] = 28;
 	sr_cmd[5] = 0;
 	
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	buffer = (unsigned char *) scsi_malloc(512);
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	if(!buffer) return -ENOMEM;
 	
 	if ((result = sr_do_ioctl (target, sr_cmd, buffer, 28, 0))) {
 	    printk ("Hosed while obtaining audio mode page\n");
+#ifndef CONFIG_SCSI_NEW_QUEUES
             spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	    scsi_free(buffer, 512);
+#ifndef CONFIG_SCSI_NEW_QUEUES
             spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
             break;
 	}
 	
@@ -514,23 +570,35 @@
 	sr_cmd[4] = 28;
 	sr_cmd[5] = 0;
 	
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	mask = (unsigned char *) scsi_malloc(512);
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	if(!mask) {
+#ifndef CONFIG_SCSI_NEW_QUEUES
             spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	    scsi_free(buffer, 512);
+#ifndef CONFIG_SCSI_NEW_QUEUES
             spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	    result = -ENOMEM;
             break;
 	};
 
 	if ((result = sr_do_ioctl (target, sr_cmd, mask, 28, 0))) {
 	    printk ("Hosed while obtaining mask for audio mode page\n");
+#ifndef CONFIG_SCSI_NEW_QUEUES
             spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	    scsi_free(buffer, 512);
 	    scsi_free(mask, 512);
+#ifndef CONFIG_SCSI_NEW_QUEUES
             spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	    break;
 	}
 	
@@ -549,10 +617,14 @@
 	sr_cmd[5] = 0;
 	
 	result = sr_do_ioctl (target, sr_cmd, buffer, 28, 0);
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	scsi_free(buffer, 512);
 	scsi_free(mask, 512);
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
         break;
     }
 	
@@ -560,7 +632,9 @@
     {
 	char * buffer;
 	struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg;
+#ifndef CONFIG_SCSI_NEW_QUEUES
         unsigned long flags;
+#endif
 	
 	/* Get the current params */
 	
@@ -571,16 +645,24 @@
 	sr_cmd[4] = 28;
 	sr_cmd[5] = 0;
 	
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	buffer = (unsigned char *) scsi_malloc(512);
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	if(!buffer) return -ENOMEM;
 	
 	if ((result = sr_do_ioctl (target, sr_cmd, buffer, 28, 0))) {
 	    printk ("(CDROMVOLREAD) Hosed while obtaining audio mode page\n");
+#ifndef CONFIG_SCSI_NEW_QUEUES
             spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	    scsi_free(buffer, 512);
+#ifndef CONFIG_SCSI_NEW_QUEUES
             spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
             break;
 	}
 
@@ -589,9 +671,13 @@
 	volctrl->channel2 = buffer[25];
 	volctrl->channel3 = buffer[27];
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	scsi_free(buffer, 512);
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
         break;
     }
 	
@@ -599,7 +685,9 @@
     {
 	struct cdrom_subchnl* subchnl = (struct cdrom_subchnl*)arg;
 	char * buffer;
+#ifndef CONFIG_SCSI_NEW_QUEUES
         unsigned long flags;
+#endif
 	
 	sr_cmd[0] = SCMD_READ_SUBCHANNEL;
 	sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02;    /* MSF format */
@@ -611,9 +699,13 @@
 	sr_cmd[8] = 16;
 	sr_cmd[9] = 0;
 	
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	buffer = (unsigned char *) scsi_malloc(512);
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	if(!buffer) return -ENOMEM;
 	
 	result = sr_do_ioctl(target, sr_cmd, buffer, 16, 0);
@@ -631,9 +723,13 @@
 	subchnl->cdsc_absaddr.msf.second = buffer[10];
 	subchnl->cdsc_absaddr.msf.frame = buffer[11];
 	
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	scsi_free(buffer, 512);
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
         break;
     }
     default:
@@ -710,9 +806,15 @@
     }
 
     /* ... if this fails, we switch the blocksize using MODE SELECT */
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    if (blksize != scsi_CDs[minor].device->sector_size)
+#else
     if (blksize != scsi_CDs[minor].sector_size)
+#endif
+    {
         if (0 != (rc = sr_set_blocklength(minor, blksize)))
             return rc;
+    }
 
 #ifdef DEBUG
     printk("sr%d: sr_read_sector lba=%d blksize=%d\n",minor,lba,blksize);
@@ -741,14 +843,20 @@
 {
     unsigned char *raw_sector;
     int is_xa;
+#ifndef CONFIG_SCSI_NEW_QUEUES
     unsigned long flags;
+#endif
     
     if (!xa_test)
         return 0;
    
+#ifndef CONFIG_SCSI_NEW_QUEUES
     spin_lock_irqsave(&io_request_lock, flags);
+#endif
     raw_sector = (unsigned char *) scsi_malloc(2048+512);
+#ifndef CONFIG_SCSI_NEW_QUEUES
     spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
     if (!raw_sector) return -ENOMEM;
     if (0 == sr_read_sector(minor,scsi_CDs[minor].ms_offset+16,
                             CD_FRAMESIZE_RAW1,raw_sector)) {
@@ -757,9 +865,13 @@
         /* read a raw sector failed for some reason. */
         is_xa = -1;
     }
+#ifndef CONFIG_SCSI_NEW_QUEUES
     spin_lock_irqsave(&io_request_lock, flags);
+#endif
     scsi_free(raw_sector, 2048+512);
+#ifndef CONFIG_SCSI_NEW_QUEUES
     spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 #ifdef DEBUG
     printk("sr%d: sr_is_xa: %d\n",minor,is_xa);
 #endif
@@ -782,7 +894,9 @@
         struct cdrom_msf   msf;
         int                lba, rc;
 	int                blocksize = 2048;
+#ifndef CONFIG_SCSI_NEW_QUEUES
         unsigned long flags;
+#endif
 
         switch (cmd) {
         case CDROMREADMODE2: blocksize = CD_FRAMESIZE_RAW0; break; /* 2336 */
@@ -791,9 +905,13 @@
 
 	if (copy_from_user(&msf,(void*)arg,sizeof(msf)))
 		return -EFAULT;
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_lock_irqsave(&io_request_lock, flags);
+#endif
         raw = scsi_malloc(2048+512);
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	if (!(raw))
                 return -ENOMEM;
 
@@ -807,9 +925,13 @@
 		if (copy_to_user((void*)arg, raw, blocksize))
 			rc = -EFAULT;
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	scsi_free(raw,2048+512);
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	return rc;
     }
     case CDROMREADAUDIO:
@@ -817,7 +939,9 @@
 	unsigned char      *raw;
         int                lba, rc=0;
         struct cdrom_read_audio ra;
+#ifndef CONFIG_SCSI_NEW_QUEUES
         unsigned long flags;
+#endif
 
         if (!scsi_CDs[target].readcd_known || !scsi_CDs[target].readcd_cdda)
             return -EINVAL;  /* -EDRIVE_DOES_NOT_SUPPORT_THIS ? */
@@ -833,9 +957,13 @@
 
         if (lba < 0 || lba >= scsi_CDs[target].capacity)
             return -EINVAL;
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_lock_irqsave(&io_request_lock, flags);
+#endif
         raw = scsi_malloc(2048+512);
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	if (!(raw))
             return -ENOMEM;
 
@@ -851,9 +979,13 @@
             ra.nframes -= 1;
             lba++;
         }
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	scsi_free(raw,2048+512);
+#ifndef CONFIG_SCSI_NEW_QUEUES
         spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
         return rc;
     }
 
diff -u -r linux.clean/drivers/scsi/sr_vendor.c linux.new2/drivers/scsi/sr_vendor.c
--- linux.clean/drivers/scsi/sr_vendor.c	Mon May 10 16:01:21 1999
+++ linux.new2/drivers/scsi/sr_vendor.c	Wed Jul 28 19:22:40 1999
@@ -134,7 +134,13 @@
 	modesel->block_length_med  = (blocklength >> 8 ) & 0xff;
 	modesel->block_length_lo   =  blocklength        & 0xff;
 	if (0 == (rc = sr_do_ioctl(minor, cmd, buffer, sizeof(*modesel), 0)))
+	{
+#ifdef CONFIG_SCSI_NEW_QUEUES
+		scsi_CDs[minor].device->sector_size = blocklength;
+#else
 		scsi_CDs[minor].sector_size = blocklength;
+#endif
+	}
 #ifdef DEBUG
 	else
 		printk("sr%d: switching blocklength to %d bytes failed\n",
@@ -287,8 +293,14 @@
 	if (CDS_AUDIO != sr_disk_status(cdi) && 1 == sr_is_xa(minor))
 		scsi_CDs[minor].xa_flag = 1;
 	
+#ifdef CONFIG_SCSI_NEW_QUEUES
+	if (2048 != scsi_CDs[minor].device->sector_size)
+#else
 	if (2048 != scsi_CDs[minor].sector_size)
+#endif
+	{
 		sr_set_blocklength(minor,2048);
+	}
 	if (no_multi)
 		cdi->mask |= CDC_MULTI_SESSION;
 
diff -u -r linux.clean/drivers/scsi/st.c linux.new2/drivers/scsi/st.c
--- linux.clean/drivers/scsi/st.c	Wed Jul 28 18:24:34 1999
+++ linux.new2/drivers/scsi/st.c	Wed Jul 28 19:22:40 1999
@@ -265,14 +265,25 @@
 st_do_scsi(Scsi_Cmnd *SCpnt, Scsi_Tape *STp, unsigned char *cmd, int bytes,
 	   int timeout, int retries, int do_wait)
 {
+#ifndef CONFIG_SCSI_NEW_QUEUES
   unsigned long flags;
+#endif
   unsigned char *bp;
 
+#ifndef CONFIG_SCSI_NEW_QUEUES
   spin_lock_irqsave(&io_request_lock, flags);
+#endif
   if (SCpnt == NULL)
-    if ((SCpnt = scsi_allocate_device(NULL, STp->device, 1)) == NULL) {
+#ifdef CONFIG_SCSI_NEW_QUEUES
+    if ((SCpnt = scsi_allocate_device(STp->device, 1)) == NULL) 
+#else
+    if ((SCpnt = scsi_allocate_device(NULL, STp->device, 1)) == NULL) 
+#endif
+    {
       printk(KERN_ERR "st%d: Can't get SCSI request.\n", TAPE_NR(STp->devt));
+#ifndef CONFIG_SCSI_NEW_QUEUES
       spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
       return NULL;
     }
 
@@ -294,7 +305,9 @@
 
   scsi_do_cmd(SCpnt, (void *)cmd, bp, bytes,
 	      st_sleep_done, timeout, retries);
+#ifndef CONFIG_SCSI_NEW_QUEUES
   spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 
   if (do_wait) {
       down(SCpnt->request.sem);
diff -u -r linux.clean/include/linux/blk.h linux.new2/include/linux/blk.h
--- linux.clean/include/linux/blk.h	Mon Sep  6 04:42:10 1999
+++ linux.new2/include/linux/blk.h	Sun Sep  5 15:07:04 1999
@@ -144,9 +144,11 @@
 #elif (SCSI_DISK_MAJOR(MAJOR_NR))
 
 #define DEVICE_NAME "scsidisk"
+#ifndef CONFIG_SCSI_NEW_QUEUES
 #define DEVICE_INTR do_sd  
-#define TIMEOUT_VALUE (2*HZ)
 #define DEVICE_REQUEST do_sd_request
+#endif
+#define TIMEOUT_VALUE (2*HZ)
 #define DEVICE_NR(device) (((MAJOR(device) & SD_MAJOR_MASK) << (8 - 4)) + (MINOR(device) >> 4))
 #define DEVICE_ON(device)
 #define DEVICE_OFF(device)
@@ -171,8 +173,10 @@
 #elif (MAJOR_NR == SCSI_CDROM_MAJOR)
 
 #define DEVICE_NAME "CD-ROM"
+#ifndef CONFIG_SCSI_NEW_QUEUES
 #define DEVICE_INTR do_sr
 #define DEVICE_REQUEST do_sr_request
+#endif
 #define DEVICE_NR(device) (MINOR(device))
 #define DEVICE_ON(device)
 #define DEVICE_OFF(device)
@@ -383,7 +387,7 @@
 #if !defined(IDE_DRIVER)
 
 #ifndef CURRENT
-#define CURRENT (blk_dev[MAJOR_NR].current_request)
+#define CURRENT (blk_dev[MAJOR_NR].request_queue.current_request)
 #endif
 
 #ifndef DEVICE_NAME
@@ -417,7 +421,9 @@
 
 #endif /* DEVICE_TIMEOUT */
 
-static void (DEVICE_REQUEST)(void);
+#ifdef DEVICE_REQUEST
+static void (DEVICE_REQUEST)(request_queue_t *);
+#endif 
   
 #ifdef DEVICE_INTR
 #define CLEAR_INTR SET_INTR(NULL)
diff -u -r linux.clean/include/linux/blkdev.h linux.new2/include/linux/blkdev.h
--- linux.clean/include/linux/blkdev.h	Mon Sep  6 04:39:43 1999
+++ linux.new2/include/linux/blkdev.h	Sun Sep  5 15:06:56 1999
@@ -26,6 +26,8 @@
 	unsigned long sector;
 	unsigned long nr_sectors;
 	unsigned long current_nr_sectors;
+	unsigned long nr_sg_segments; /* # scatter-gather segments */
+        void * special;
 	char * buffer;
 	struct semaphore * sem;
 	struct buffer_head * bh;
@@ -33,19 +35,57 @@
 	struct request * next;
 };
 
-typedef void (request_fn_proc) (void);
-typedef struct request ** (queue_proc) (kdev_t dev);
+typedef struct request_queue request_queue_t;
+typedef int (merge_request_fn) (request_queue_t *, 
+				struct request  * req,
+				struct buffer_head *);
+typedef int (merge_requests_fn) (request_queue_t *, 
+				 struct request  * req,
+				 struct request  * req2);
+typedef void (request_fn_proc) (request_queue_t *);
+typedef request_queue_t * (queue_proc) (kdev_t dev);
+
+struct request_queue
+{
+	struct request		* current_request;
+	request_fn_proc		* request_fn;
+	merge_request_fn	* merge_fn;
+	merge_requests_fn	* merge_requests_fn;
+	/*
+	 * The queue owner gets to use this for whatever they like.
+	 * ll_rw_blk doesn't touch it.
+	 */
+	void                    * queuedata;
+
+	/*
+	 * This is used to remove the plug when tq_disk runs.
+	 */
+	struct tq_struct          plug_tq;
+	/*
+	 * Boolean that indicates whether this queue is plugged or not.
+	 */
+	char			  plugged;
+
+	/*
+	 * Boolean that indicates whether current_request is active or
+	 * not.
+	 */
+	char			  head_active;
+
+	/*
+	 * Boolean that indicates whether we should use plugging on
+	 * this queue or not.
+	 */
+	char			  use_plug; 
+};
 
 struct blk_dev_struct {
-	request_fn_proc		*request_fn;
 	/*
 	 * queue_proc has to be atomic
 	 */
+	request_queue_t		request_queue;
 	queue_proc		*queue;
 	void			*data;
-	struct request		*current_request;
-	struct request   plug;
-	struct tq_struct plug_tq;
 };
 
 struct sec_size {
@@ -53,12 +93,28 @@
 	unsigned block_size_bits;
 };
 
+/*
+ * Used to indicate the default queue for drivers that don't bother
+ * to implement multiple queues.  We have this access macro here
+ * so as to eliminate the need for each and every block device
+ * driver to know about the internal structure of blk_dev[].
+ */
+#define BLK_DEFAULT_QUEUE(_MAJOR)  &blk_dev[_MAJOR].request_queue
+
 extern struct sec_size * blk_sec[MAX_BLKDEV];
 extern struct blk_dev_struct blk_dev[MAX_BLKDEV];
 extern wait_queue_head_t wait_for_request;
 extern void resetup_one_dev(struct gendisk *dev, int drive);
 extern void unplug_device(void * data);
 extern void make_request(int major,int rw, struct buffer_head * bh);
+
+/*
+ * Access functions for manipulating queue properties
+ */
+extern void blk_init_queue(request_queue_t *, request_fn_proc *);
+extern void blk_cleanup_queue(request_queue_t *);
+extern void blk_queue_headactive(request_queue_t *, int);
+extern void blk_queue_pluggable(request_queue_t *, int);
 
 /* md needs this function to remap requests */
 extern int md_map (int minor, kdev_t *rdev, unsigned long *rsector, unsigned long size);
diff -u -r linux.clean/include/linux/fs.h linux.new2/include/linux/fs.h
--- linux.clean/include/linux/fs.h	Mon Sep  6 04:39:32 1999
+++ linux.new2/include/linux/fs.h	Sun Sep  5 14:25:33 1999
@@ -62,6 +62,7 @@
 #define WRITE 1
 #define READA 2		/* read-ahead  - don't block if no resources */
 #define WRITEA 3	/* write-ahead - don't block if no resources */
+#define SPECIAL 4	/* For non-blockdevice requests in request queue */
 
 #ifndef NULL
 #define NULL ((void *) 0)
diff -u -r linux.clean/include/linux/ide.h linux.new2/include/linux/ide.h
--- linux.clean/include/linux/ide.h	Mon Sep  6 04:42:26 1999
+++ linux.new2/include/linux/ide.h	Sun Sep  5 15:07:48 1999
@@ -234,7 +234,7 @@
 	} special_t;
 
 typedef struct ide_drive_s {
-	struct request		*queue;	/* request queue */
+	request_queue_t		 queue;	/* request queue */
 	struct ide_drive_s 	*next;	/* circular list of hwgroup drives */
 	unsigned long sleep;		/* sleep until this time */
 	unsigned long service_start;	/* time we started last request */
@@ -723,7 +723,7 @@
 /*
  * ide_get_queue() returns the queue which corresponds to a given device.
  */
-struct request **ide_get_queue (kdev_t dev);
+request_queue_t *ide_get_queue (kdev_t dev);
 
 /*
  * CompactFlash cards and their brethern pretend to be removable hard disks,
@@ -736,27 +736,27 @@
 void ide_timer_expiry (unsigned long data);
 void ide_intr (int irq, void *dev_id, struct pt_regs *regs);
 void ide_geninit (struct gendisk *gd);
-void do_ide0_request (void);
+void do_ide0_request (request_queue_t * q);
 #if MAX_HWIFS > 1
-void do_ide1_request (void);
+void do_ide1_request (request_queue_t * q);
 #endif
 #if MAX_HWIFS > 2
-void do_ide2_request (void);
+void do_ide2_request (request_queue_t * q);
 #endif
 #if MAX_HWIFS > 3
-void do_ide3_request (void);
+void do_ide3_request (request_queue_t * q);
 #endif
 #if MAX_HWIFS > 4
-void do_ide4_request (void);
+void do_ide4_request (request_queue_t * q);
 #endif
 #if MAX_HWIFS > 5
-void do_ide5_request (void);
+void do_ide5_request (request_queue_t * q);
 #endif
 #if MAX_HWIFS > 6
-void do_ide6_request (void);
+void do_ide6_request (request_queue_t * q);
 #endif
 #if MAX_HWIFS > 7
-void do_ide7_request (void);
+void do_ide7_request (request_queue_t * q);
 #endif
 void ide_init_subdrivers (void);
 
