diff -u -r linux.clean/Documentation/Configure.help linux.new2/Documentation/Configure.help
--- linux.clean/Documentation/Configure.help	Sun Nov  7 16:35:15 1999
+++ linux.new2/Documentation/Configure.help	Sun Nov 14 08:27:47 1999
@@ -4058,6 +4058,16 @@
   Documentation/scsi.txt. The module will be called sg.o. If unsure,
   say N.
 
+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.   Comments/questions/problems to
+  linux-scsi mailing list please.  See http://www.andante.org/scsi_queue.html
+  for more uptodate information.
+
 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/DAC960.c linux.new2/drivers/block/DAC960.c
--- linux.clean/drivers/block/DAC960.c	Sun Nov  7 16:34:53 1999
+++ linux.new2/drivers/block/DAC960.c	Sun Nov  7 16:43:19 1999
@@ -1026,7 +1026,7 @@
 
 static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
 {
-  static void (*RequestFunctions[DAC960_MaxControllers])(void) =
+  static void (*RequestFunctions[DAC960_MaxControllers])(request_queue_t *) =
     { DAC960_RequestFunction0, DAC960_RequestFunction1,
       DAC960_RequestFunction2, DAC960_RequestFunction3,
       DAC960_RequestFunction4, DAC960_RequestFunction5,
@@ -1046,8 +1046,8 @@
   /*
     Initialize the I/O Request Function.
   */
-  blk_dev[MajorNumber].request_fn =
-    RequestFunctions[Controller->ControllerNumber];
+  blk_init_queue(BLK_DEFAULT_QUEUE(MajorNumber), 
+		 RequestFunctions[Controller->ControllerNumber]);
   /*
     Initialize the Disk Partitions array, Partition Sizes array, Block Sizes
     array, Max Sectors per Request array, and Max Segments per Request array.
@@ -1113,7 +1113,7 @@
   /*
     Remove the I/O Request Function.
   */
-  blk_dev[MajorNumber].request_fn = NULL;
+  blk_cleanup_queue(BLK_DEFAULT_QUEUE(MajorNumber));
   /*
     Remove the Disk Partitions array, Partition Sizes array, Block Sizes
     array, Max Sectors per Request array, and Max Segments per Request array.
@@ -1375,7 +1375,7 @@
   DAC960_RequestFunction0 is the I/O Request Function for DAC960 Controller 0.
 */
 
-static void DAC960_RequestFunction0(void)
+static void DAC960_RequestFunction0(request_queue_t * q)
 {
   DAC960_Controller_T *Controller = DAC960_Controllers[0];
   ProcessorFlags_T ProcessorFlags;
@@ -1398,7 +1398,7 @@
   DAC960_RequestFunction1 is the I/O Request Function for DAC960 Controller 1.
 */
 
-static void DAC960_RequestFunction1(void)
+static void DAC960_RequestFunction1(request_queue_t * q)
 {
   DAC960_Controller_T *Controller = DAC960_Controllers[1];
   ProcessorFlags_T ProcessorFlags;
@@ -1421,7 +1421,7 @@
   DAC960_RequestFunction2 is the I/O Request Function for DAC960 Controller 2.
 */
 
-static void DAC960_RequestFunction2(void)
+static void DAC960_RequestFunction2(request_queue_t * q)
 {
   DAC960_Controller_T *Controller = DAC960_Controllers[2];
   ProcessorFlags_T ProcessorFlags;
@@ -1444,7 +1444,7 @@
   DAC960_RequestFunction3 is the I/O Request Function for DAC960 Controller 3.
 */
 
-static void DAC960_RequestFunction3(void)
+static void DAC960_RequestFunction3(request_queue_t * q)
 {
   DAC960_Controller_T *Controller = DAC960_Controllers[3];
   ProcessorFlags_T ProcessorFlags;
@@ -1467,7 +1467,7 @@
   DAC960_RequestFunction4 is the I/O Request Function for DAC960 Controller 4.
 */
 
-static void DAC960_RequestFunction4(void)
+static void DAC960_RequestFunction4(request_queue_t * q)
 {
   DAC960_Controller_T *Controller = DAC960_Controllers[4];
   ProcessorFlags_T ProcessorFlags;
@@ -1490,7 +1490,7 @@
   DAC960_RequestFunction5 is the I/O Request Function for DAC960 Controller 5.
 */
 
-static void DAC960_RequestFunction5(void)
+static void DAC960_RequestFunction5(request_queue_t * q)
 {
   DAC960_Controller_T *Controller = DAC960_Controllers[5];
   ProcessorFlags_T ProcessorFlags;
@@ -1513,7 +1513,7 @@
   DAC960_RequestFunction6 is the I/O Request Function for DAC960 Controller 6.
 */
 
-static void DAC960_RequestFunction6(void)
+static void DAC960_RequestFunction6(request_queue_t * q)
 {
   DAC960_Controller_T *Controller = DAC960_Controllers[6];
   ProcessorFlags_T ProcessorFlags;
@@ -1536,7 +1536,7 @@
   DAC960_RequestFunction7 is the I/O Request Function for DAC960 Controller 7.
 */
 
-static void DAC960_RequestFunction7(void)
+static void DAC960_RequestFunction7(request_queue_t * q)
 {
   DAC960_Controller_T *Controller = DAC960_Controllers[7];
   ProcessorFlags_T ProcessorFlags;
diff -u -r linux.clean/drivers/block/acsi.c linux.new2/drivers/block/acsi.c
--- linux.clean/drivers/block/acsi.c	Tue Sep  7 18:55:55 1999
+++ linux.new2/drivers/block/acsi.c	Tue Sep  7 18:57:06 1999
@@ -360,7 +360,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 );
@@ -938,7 +938,7 @@
  *
  ***********************************************************************/
 
-static void do_acsi_request( void )
+static void do_acsi_request( request_queue_t * q )
 
 {
 	stdma_lock( acsi_interrupt, NULL );
@@ -1808,7 +1808,7 @@
 	phys_acsi_buffer = virt_to_phys( 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;
@@ -1838,7 +1838,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	Sun Sep 12 15:25:56 1999
+++ linux.new2/drivers/block/amiflop.c	Sun Sep 12 15:32:06 1999
@@ -1484,7 +1484,7 @@
 	goto repeat;
 }
 
-static void do_fd_request(void)
+static void do_fd_request(request_queue_t * q)
 {
 	redo_fd_request();
 }
@@ -1869,7 +1869,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;
 
@@ -1911,7 +1911,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	Tue Sep  7 18:55:55 1999
+++ linux.new2/drivers/block/ataflop.c	Tue Sep  7 18:57:07 1999
@@ -1529,7 +1529,7 @@
 }
 
 
-void do_fd_request(void)
+void do_fd_request(request_queue_t * q)
 {
  	unsigned long flags;
 
@@ -2051,7 +2051,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',
@@ -2103,7 +2103,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	Sun Nov  7 16:34:53 1999
+++ linux.new2/drivers/block/cpqarray.c	Sun Nov  7 16:43:19 1999
@@ -139,14 +139,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);
 
@@ -378,7 +378,7 @@
  */
 void __init 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,
@@ -479,7 +479,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;
@@ -893,10 +895,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;
 
@@ -973,7 +978,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	Sun Sep 12 15:25:56 1999
+++ linux.new2/drivers/block/floppy.c	Sun Sep 12 15:26:43 1999
@@ -2930,7 +2930,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);
@@ -4130,7 +4130,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();
 
@@ -4159,7 +4159,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;
@@ -4225,7 +4225,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;
@@ -4447,7 +4447,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	Sun Oct 17 12:32:50 1999
+++ linux.new2/drivers/block/hd.c	Sun Oct 17 12:33:25 1999
@@ -585,7 +585,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();
@@ -813,7 +813,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	Sun Nov  7 16:33:46 1999
+++ linux.new2/drivers/block/ide-probe.c	Sun Nov  7 16:38:59 1999
@@ -707,7 +707,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;
@@ -789,10 +790,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	Sun Nov  7 16:35:19 1999
+++ linux.new2/drivers/block/ide.c	Sun Nov  7 16:48:08 1999
@@ -489,8 +489,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);
 	}
@@ -751,8 +751,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);
@@ -1056,7 +1056,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);
 
@@ -1142,14 +1142,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);
@@ -1196,8 +1194,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);
@@ -1228,9 +1225,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 0
@@ -1270,7 +1265,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;
 
@@ -1311,69 +1306,69 @@
 	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);
 }
 #endif /* MAX_HWIFS > 7 */
 
 #if MAX_HWIFS > 8
-void do_ide8_request (void)
+void do_ide8_request (request_queue_t * q)
 {
 	unlock_do_hwgroup_request (ide_hwifs[8].hwgroup);
 }
 #endif /* MAX_HWIFS > 8 */
 
 #if MAX_HWIFS > 9
-void do_ide9_request (void)
+void do_ide9_request (request_queue_t * q)
 {
 	unlock_do_hwgroup_request (ide_hwifs[9].hwgroup);
 }
@@ -1650,10 +1645,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 {
@@ -1959,7 +1954,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	Sun Nov  7 16:34:53 1999
+++ linux.new2/drivers/block/ll_rw_blk.c	Sun Nov  7 19:44:15 1999
@@ -141,14 +141,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;
 }
 
 /*
@@ -156,22 +191,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);
 }
 
@@ -183,12 +214,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);
 }
 
 /*
@@ -220,6 +252,7 @@
 	prev_found = req;
 	req->rq_status = RQ_ACTIVE;
 	req->rq_dev = dev;
+	req->special = NULL;
 	return req;
 }
 
@@ -334,12 +367,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)
 {
 	int major = MAJOR(req->rq_dev);
-	struct request * tmp, **current_request;
+	struct request * tmp;
 	unsigned long flags;
-	int queue_new_request = 0;
 
 	drive_stat_acct(req, req->nr_sectors, 1);
 	req->next = NULL;
@@ -348,12 +380,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) {
@@ -371,26 +400,34 @@
 	req->next = tmp->next;
 	tmp->next = req;
 
-/* for SCSI devices, call request_fn unconditionally */
-	if (scsi_blk_major(major))
-		queue_new_request = 1;
-	if (major >= COMPAQ_SMART2_MAJOR+0 &&
-	    major <= COMPAQ_SMART2_MAJOR+7)
-		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 >= COMPAQ_SMART2_MAJOR+0 && major <= COMPAQ_SMART2_MAJOR+7)
+	{
+		(q->request_fn)(q);
+	}
+
 	if (major >= DAC960_MAJOR+0 && major <= DAC960_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,
-				int max_segments)
+static inline void attempt_merge (request_queue_t * q,
+				  struct request *req, 
+				  int max_sectors,
+				  int max_segments)
 {
 	struct request *next = req->next;
 	int total_segments;
@@ -406,6 +443,13 @@
 		total_segments--;
 	if (total_segments > max_segments)
 		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;
@@ -415,7 +459,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;
@@ -509,13 +556,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:
@@ -538,7 +592,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;
@@ -582,25 +636,71 @@
 				continue;
 			/* Can we add it to the end of this request? */
 			if (req->sector + req->nr_sectors == sector) {
-				if (req->bhtail->b_data + req->bhtail->b_size
-				    != bh->b_data) {
-					if (req->nr_segments < max_segments)
-						req->nr_segments++;
-					else continue;
+				/*
+				 * The merge_fn is a more advanced way
+				 * of accomplishing the same task.  Instead
+				 * of applying a fixed limit of some sort
+				 * we instead define a function which can
+				 * determine whether or not it is safe to
+				 * merge the request or not.
+				 */
+				if( q->merge_fn == NULL )
+				{
+					if (req->bhtail->b_data + req->bhtail->b_size
+					    != bh->b_data) {
+						if (req->nr_segments < max_segments)
+							req->nr_segments++;
+						else continue;
+					}
+				}
+				else
+				{
+					/*
+					 * See if this queue has rules that
+					 * may suggest that we shouldn't merge
+					 * this 
+					 */
+					if( !(q->merge_fn)(q, req, bh) )
+					{
+						continue;
+					}
 				}
 				req->bhtail->b_reqnext = bh;
 				req->bhtail = bh;
 			    	req->nr_sectors += count;
 				drive_stat_acct(req, count, 0);
 				/* Can we now merge this req with the next? */
-				attempt_merge(req, max_sectors, max_segments);
+				attempt_merge(q, req, max_sectors, max_segments);
 			/* or to the beginning? */
 			} else if (req->sector - count == sector) {
-				if (bh->b_data + bh->b_size
-				    != req->bh->b_data) {
-					if (req->nr_segments < max_segments)
-						req->nr_segments++;
-					else continue;
+				/*
+				 * The merge_fn is a more advanced way
+				 * of accomplishing the same task.  Instead
+				 * of applying a fixed limit of some sort
+				 * we instead define a function which can
+				 * determine whether or not it is safe to
+				 * merge the request or not.
+				 */
+				if( q->merge_fn == NULL )
+				{
+					if (bh->b_data + bh->b_size
+					    != req->bh->b_data) {
+						if (req->nr_segments < max_segments)
+							req->nr_segments++;
+						else continue;
+					}
+				}
+				else
+				{
+					/*
+					 * See if this queue has rules that
+					 * may suggest that we shouldn't merge
+					 * this 
+					 */
+					if( !(q->merge_fn)(q, req, bh) )
+					{
+						continue;
+					}
 				}
 			    	bh->b_reqnext = req->bh;
 			    	req->bh = bh;
@@ -637,18 +737,36 @@
 	req->nr_sectors = count;
 	req->nr_segments = 1;
 	req->current_nr_sectors = count;
+	req->nr_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 */
@@ -657,13 +775,13 @@
 {
 	unsigned int major;
 	int correct_size;
-	struct blk_dev_struct * dev;
+	request_queue_t		* q;
+	unsigned long flags;
 	int i;
 
-	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);
@@ -716,8 +834,15 @@
 			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:
@@ -791,15 +916,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;
@@ -914,3 +1032,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	Sun Nov  7 16:35:19 1999
+++ linux.new2/drivers/block/loop.c	Sun Nov  7 16:48:08 1999
@@ -164,7 +164,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;
@@ -754,7 +754,7 @@
 		return -ENOMEM;
 	}		
 
-	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 Nov  7 16:34:53 1999
+++ linux.new2/drivers/block/md.c	Sun Nov  7 16:43:19 1999
@@ -761,7 +761,7 @@
 	}
 }
 
-static void do_md_request (void)
+static void do_md_request (request_queue_t * q)
 {
   printk ("Got md request, not good...");
   return;
@@ -1287,8 +1287,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	Sun Nov  7 16:33:46 1999
+++ linux.new2/drivers/block/paride/pcd.c	Sun Nov  7 16:38:59 1999
@@ -220,7 +220,7 @@
 static int 	pcd_detect(void);
 static void 	pcd_probe_capabilities(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];
@@ -343,7 +343,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;
@@ -750,7 +750,7 @@
 
 /* I/O request processing */
 
-static void do_pcd_request (void)
+static void do_pcd_request (request_queue_t * q)
 
 {       int unit;
 
@@ -814,7 +814,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;
 	}
@@ -838,7 +838,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;
 	}
@@ -862,14 +862,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 Oct 17 12:26:52 1999
+++ linux.new2/drivers/block/paride/pd.c	Sun Oct 17 12:27:55 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 Oct 17 15:45:14 1999
+++ linux.new2/drivers/block/paride/pf.c	Sun Oct 17 15:45:34 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 Oct 17 12:32:51 1999
+++ linux.new2/drivers/block/ps2esdi.c	Sun Oct 17 12:33:26 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 */
@@ -464,7 +464,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 
@@ -487,7 +487,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) &&
@@ -521,7 +521,7 @@
 			printk("%s: Unknown command\n", DEVICE_NAME);
 			end_request(FAIL);
 			if (CURRENT)
-				do_ps2esdi_request();
+				do_ps2esdi_request(q);
 			break;
 		}		/* handle different commands */
 	}
@@ -531,7 +531,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 */
@@ -598,11 +598,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 */ 
@@ -901,11 +901,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;
 		}
@@ -947,11 +947,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;
 
@@ -961,7 +961,7 @@
 		outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
 		end_request(FAIL);
 		if (CURRENT)
-			do_ps2esdi_request();
+			do_ps2esdi_request(NULL);
 		break;
 
 	case INT_CMD_FORMAT:
@@ -993,11 +993,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	Sun Nov  7 16:34:12 1999
+++ linux.new2/drivers/block/rd.c	Sun Nov  7 16:41:25 1999
@@ -181,7 +181,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;
@@ -357,7 +357,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 */
@@ -404,7 +404,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/swim_iop.c linux.new2/drivers/block/swim_iop.c
--- linux.clean/drivers/block/swim_iop.c	Sun Sep 12 15:25:57 1999
+++ linux.new2/drivers/block/swim_iop.c	Mon Sep 13 18:45:28 1999
@@ -121,7 +121,7 @@
 static void set_timeout(struct floppy_state *fs, int nticks,
 			void (*proc)(unsigned long));
 static void fd_request_timeout(unsigned long);
-static void do_fd_request(void);
+static void do_fd_request(request_queue_t * q);
 static void start_request(struct floppy_state *fs);
 
 static struct file_operations floppy_fops = {
@@ -163,7 +163,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;
 
@@ -566,7 +566,7 @@
 	restore_flags(flags);
 }
 
-static void do_fd_request(void)
+static void do_fd_request(request_queue_t * q)
 {
 	int i;
 
diff -u -r linux.clean/drivers/block/xd.c linux.new2/drivers/block/xd.c
--- linux.clean/drivers/block/xd.c	Sun Oct 17 12:32:51 1999
+++ linux.new2/drivers/block/xd.c	Sun Oct 17 12:33:26 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	Thu Sep  9 13:17:20 1999
+++ linux.new2/drivers/block/z2ram.c	Thu Sep  9 13:18:16 1999
@@ -68,7 +68,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;
 
@@ -373,7 +373,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	Sat Sep 11 08:08:57 1999
+++ linux.new2/drivers/cdrom/sonycd535.c	Sat Sep 11 08:10:38 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;
@@ -1601,7 +1601,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	Sun Nov  7 16:35:20 1999
+++ linux.new2/drivers/i2o/i2o_block.c	Sun Nov  7 16:48:09 1999
@@ -118,7 +118,7 @@
 
 static int i2ob_install_device(struct i2o_controller *, struct i2o_device *, int);
 static void i2ob_end_request(struct request *);
-static void i2ob_request(void);
+static void i2ob_request(request_queue_t * q);
 
 /*
  * Dump messages.
@@ -135,7 +135,6 @@
         printk(KERN_INFO "\n");
 }
 
-
 /*
  *	Get a message
  */
@@ -399,7 +398,7 @@
 	 */
 	 
 	atomic_dec(&queue_depth);
-	i2ob_request();
+	i2ob_request(NULL);
 	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
@@ -453,7 +452,7 @@
  *	we use it.
  */
 
-static void i2ob_request(void)
+static void i2ob_request(request_queue_t * q)
 {
 	struct request *req;
 	struct i2ob_request *ireq;
@@ -527,7 +526,6 @@
 	}
 }
 
-
 /*
  *	SCSI-CAM for ioctl geometry mapping
  *	Duplicated with SCSI - this should be moved into somewhere common
@@ -1086,7 +1084,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	Sun Oct 17 15:45:17 1999
+++ linux.new2/drivers/scsi/Config.in	Sun Nov 14 08:26:49 1999
@@ -10,8 +10,12 @@
 
 comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
 
-bool '  Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  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
 bool '  SCSI logging facility' CONFIG_SCSI_LOGGING
 
diff -u -r linux.clean/drivers/scsi/Makefile linux.new2/drivers/scsi/Makefile
--- linux.clean/drivers/scsi/Makefile	Sun Oct 17 15:38:26 1999
+++ linux.new2/drivers/scsi/Makefile	Sun Oct 17 15:39:14 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
@@ -713,10 +713,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	Sun Oct 17 12:32:56 1999
+++ linux.new2/drivers/scsi/aha1542.c	Sun Nov 14 08:57:51 1999
@@ -1297,7 +1297,9 @@
      * check for timeout, and if we are doing something like this
      * we are pretty desperate anyways.
      */
+    spin_unlock_irq(&io_request_lock);
     scsi_sleep(4*HZ);
+    spin_lock_irq(&io_request_lock);
 
     WAIT(STATUS(SCpnt->host->io_port), 
 	 STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
@@ -1364,7 +1366,9 @@
      * check for timeout, and if we are doing something like this
      * we are pretty desperate anyways.
      */
+    spin_unlock_irq(&io_request_lock);
     scsi_sleep(4*HZ);
+    spin_lock_irq(&io_request_lock);
 
     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	Sun Nov 14 08:58:07 1999
@@ -938,10 +938,8 @@
     scp->request.rq_status = RQ_SCSI_BUSY;
     scp->request.sem = &sem;
     scp->SCp.this_residual = IOCTL_PRI;
-    GDTH_LOCK_SCSI_DOCMD();
     scsi_do_cmd(scp, cmnd, gdtcmd, sizeof(gdth_cmd_str), 
                 gdth_scsi_done, timeout*HZ, 1);
-    GDTH_UNLOCK_SCSI_DOCMD();
     down(&sem);
 }
 
diff -u -r linux.clean/drivers/scsi/hosts.c linux.new2/drivers/scsi/hosts.c
--- linux.clean/drivers/scsi/hosts.c	Sun Oct 17 15:38:27 1999
+++ linux.new2/drivers/scsi/hosts.c	Sun Nov 14 09:07:36 1999
@@ -692,8 +692,6 @@
     atomic_set(&retval->host_active,0);
     retval->host_busy = 0;
     retval->host_failed = 0;
-    retval->block = NULL;
-    retval->wish_block = 0;
     if(j > 0xffff) panic("Too many extra bytes requested\n");
     retval->extra_bytes = j;
     retval->loaded_as_module = scsi_loadable_module_flag;
@@ -719,11 +717,8 @@
     retval->ehandler = NULL;    /* Initial value until the thing starts up. */
     retval->eh_notify   = NULL;    /* Who we notify when we exit. */
 
-    /*
-     * Initialize the fields used for mid-level queueing.
-     */
-    retval->pending_commands = NULL;
-    retval->host_busy = FALSE;
+
+    retval->host_blocked = FALSE;
 
 #ifdef DEBUG
     printk("Register %x %x: %d\n", (int)retval, (int)retval->hostt, j);
@@ -779,6 +774,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.
@@ -869,7 +865,6 @@
     printk ("scsi : %d host%s.\n", next_scsi_host,
 	    (next_scsi_host == 1) ? "" : "s");
     
-    scsi_make_blocked_list();
     
     /* 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	Wed Oct 20 16:36:45 1999
+++ linux.new2/drivers/scsi/hosts.h	Sun Nov 14 09:07:39 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,13 +297,7 @@
      */
     struct Scsi_Host      * next;
     Scsi_Device           * host_queue;
-    /*
-     * List of commands that have been rejected because either the host
-     * or the device was busy.  These need to be retried relatively quickly,
-     * but we need to hold onto it for a short period until the host/device
-     * is available.
-     */
-    Scsi_Cmnd             * pending_commands;
+
 
     struct task_struct    * ehandler;  /* Error recovery thread. */
     struct semaphore      * eh_wait;   /* The error recovery thread waits on
@@ -336,13 +330,6 @@
     unsigned int max_lun;
     unsigned int max_channel;
 
-    /*
-     * Pointer to a circularly linked list - this indicates the hosts
-     * that should be locked out of performing I/O while we have an active
-     * command on this host.
-     */
-    struct Scsi_Host * block;
-    unsigned wish_block:1;
 
     /* These parameters should be set by the detect routine */
     unsigned char *base;
@@ -387,9 +374,14 @@
      * 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;
-    
+
+    /*
+     * 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;
+   
     void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *);
 
     /*
@@ -408,7 +400,6 @@
 
 extern void build_proc_dir_entries(Scsi_Host_Template  *);
 
-
 /*
  *  scsi_init initializes the scsi hosts.
  */
@@ -452,6 +443,7 @@
     void (*finish)(void);	  /* Perform initialization after attachment */
     int (*attach)(Scsi_Device *); /* Attach devices to arrays */
     void (*detach)(Scsi_Device *);
+    int (*init_command)(Scsi_Cmnd *);     /* Used by new queueing code. */
 };
 
 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	Sun Nov  7 16:35:21 1999
+++ linux.new2/drivers/scsi/scsi.c	Sun Nov 14 08:55:35 1999
@@ -119,7 +119,8 @@
 unsigned long scsi_pid = 0;
 Scsi_Cmnd *last_cmnd = NULL;
 /* Command groups 3 and 4 are reserved and should never be used.  */
-const unsigned char scsi_command_size[8] = {
+const unsigned char scsi_command_size[8] =
+{
 	6, 10, 10, 12,
 	12, 12, 10, 10
 };
@@ -227,50 +228,50 @@
 	{"Aashima", "IMAGERY 2400SP", "1.03", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
 	{"CHINON", "CD-ROM CDS-431", "H42", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
 	{"CHINON", "CD-ROM CDS-535", "Q14", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
-	{"DENON", "DRD-25X", "V", BLIST_NOLUN},			/* Locks up if probed for lun != 0 */
-	{"HITACHI", "DK312C", "CM81", BLIST_NOLUN},		/* Responds to all lun - dtg */
-	{"HITACHI", "DK314C", "CR21", BLIST_NOLUN},		/* responds to all lun */
-	{"IMS", "CDD521/10", "2.06", BLIST_NOLUN},		/* Locks-up when LUN>0 polled. */
-	{"MAXTOR", "XT-3280", "PR02", BLIST_NOLUN},		/* Locks-up when LUN>0 polled. */
-	{"MAXTOR", "XT-4380S", "B3C", BLIST_NOLUN},		/* Locks-up when LUN>0 polled. */
-	{"MAXTOR", "MXT-1240S", "I1.2", BLIST_NOLUN},		/* Locks up when LUN>0 polled */
-	{"MAXTOR", "XT-4170S", "B5A", BLIST_NOLUN},		/* Locks-up sometimes when LUN>0 polled. */
-	{"MAXTOR", "XT-8760S", "B7B", BLIST_NOLUN},		/* guess what? */
+	{"DENON", "DRD-25X", "V", BLIST_NOLUN},		/* Locks up if probed for lun != 0 */
+	{"HITACHI", "DK312C", "CM81", BLIST_NOLUN},	/* Responds to all lun - dtg */
+	{"HITACHI", "DK314C", "CR21", BLIST_NOLUN},	/* responds to all lun */
+	{"IMS", "CDD521/10", "2.06", BLIST_NOLUN},	/* Locks-up when LUN>0 polled. */
+	{"MAXTOR", "XT-3280", "PR02", BLIST_NOLUN},	/* Locks-up when LUN>0 polled. */
+	{"MAXTOR", "XT-4380S", "B3C", BLIST_NOLUN},	/* Locks-up when LUN>0 polled. */
+	{"MAXTOR", "MXT-1240S", "I1.2", BLIST_NOLUN},	/* Locks up when LUN>0 polled */
+	{"MAXTOR", "XT-4170S", "B5A", BLIST_NOLUN},	/* Locks-up sometimes when LUN>0 polled. */
+	{"MAXTOR", "XT-8760S", "B7B", BLIST_NOLUN},	/* guess what? */
 	{"MEDIAVIS", "RENO CD-ROMX2A", "2.03", BLIST_NOLUN},	/*Responds to all lun */
-	{"MICROP", "4110", "*", BLIST_NOTQ},			/* Buggy Tagged Queuing */
+	{"MICROP", "4110", "*", BLIST_NOTQ},	/* Buggy Tagged Queuing */
 	{"NEC", "CD-ROM DRIVE:841", "1.0", BLIST_NOLUN},	/* Locks-up when LUN>0 polled. */
-	{"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN},		/* Responds to all lun */
-	{"RODIME", "RO3000S", "2.33", BLIST_NOLUN},		/* Locks up if polled for lun != 0 */
-	{"SANYO", "CRD-250S", "1.20", BLIST_NOLUN},		/* causes failed REQUEST SENSE on lun 1
-								 * for aha152x controller, which causes
-								 * SCSI code to reset bus.*/
-	{"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN},		/* causes failed REQUEST SENSE on lun 1
-								 * for aha152x controller, which causes
-								 * SCSI code to reset bus.*/
-	{"SEAGATE", "ST296", "921", BLIST_NOLUN},		/* Responds to all lun */
-	{"SEAGATE", "ST1581", "6538", BLIST_NOLUN},		/* Responds to all lun */
-	{"SONY", "CD-ROM CDU-541", "4.3d", BLIST_NOLUN},	
+	{"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN},	/* Responds to all lun */
+	{"RODIME", "RO3000S", "2.33", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
+	{"SANYO", "CRD-250S", "1.20", BLIST_NOLUN},	/* causes failed REQUEST SENSE on lun 1
+							 * for aha152x controller, which causes
+							 * SCSI code to reset bus.*/
+	{"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN},	/* causes failed REQUEST SENSE on lun 1
+							 * for aha152x controller, which causes
+							 * SCSI code to reset bus.*/
+	{"SEAGATE", "ST296", "921", BLIST_NOLUN},	/* Responds to all lun */
+	{"SEAGATE", "ST1581", "6538", BLIST_NOLUN},	/* Responds to all lun */
+	{"SONY", "CD-ROM CDU-541", "4.3d", BLIST_NOLUN},
 	{"SONY", "CD-ROM CDU-55S", "1.0i", BLIST_NOLUN},
 	{"SONY", "CD-ROM CDU-561", "1.7x", BLIST_NOLUN},
 	{"SONY", "CD-ROM CDU-8012", "*", BLIST_NOLUN},
-	{"TANDBERG", "TDC 3600", "U07", BLIST_NOLUN},		/* Locks up if polled for lun != 0 */
-	{"TEAC", "CD-R55S", "1.0H", BLIST_NOLUN},		/* Locks up if polled for lun != 0 */
-	{"TEAC", "CD-ROM", "1.06", BLIST_NOLUN},		/* causes failed REQUEST SENSE on lun 1
-								 * for seagate controller, which causes
-								 * SCSI code to reset bus.*/
-	{"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN},		/* causes failed REQUEST SENSE on lun 1
-								 * for seagate controller, which causes
-								 * SCSI code to reset bus.*/
-	{"QUANTUM", "LPS525S", "3110", BLIST_NOLUN},		/* Locks sometimes if polled for lun != 0 */
-	{"QUANTUM", "PD1225S", "3110", BLIST_NOLUN},		/* Locks sometimes if polled for lun != 0 */
+	{"TANDBERG", "TDC 3600", "U07", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
+	{"TEAC", "CD-R55S", "1.0H", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
+	{"TEAC", "CD-ROM", "1.06", BLIST_NOLUN},	/* causes failed REQUEST SENSE on lun 1
+							 * for seagate controller, which causes
+							 * SCSI code to reset bus.*/
+	{"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN},	/* causes failed REQUEST SENSE on lun 1
+							 * for seagate controller, which causes
+							 * SCSI code to reset bus.*/
+	{"QUANTUM", "LPS525S", "3110", BLIST_NOLUN},	/* Locks sometimes if polled for lun != 0 */
+	{"QUANTUM", "PD1225S", "3110", BLIST_NOLUN},	/* Locks sometimes if polled for lun != 0 */
 	{"QUANTUM", "FIREBALL ST4.3S", "0F0C", BLIST_NOLUN},	/* Locks up when polled for lun != 0 */
 	{"MEDIAVIS", "CDR-H93MV", "1.31", BLIST_NOLUN},		/* Locks up if polled for lun != 0 */
-	{"SANKYO", "CP525", "6.64", BLIST_NOLUN},		/* causes failed REQ SENSE, extra reset */
-	{"HP", "C1750A", "3226", BLIST_NOLUN},			/* scanjet iic */
-	{"HP", "C1790A", "", BLIST_NOLUN},			/* scanjet iip */
-	{"HP", "C2500A", "", BLIST_NOLUN},			/* scanjet iicx */
-	{"YAMAHA", "CDR102", "1.00", BLIST_NOLUN},		/* extra reset */
-	{"RELISYS", "Scorpio", "*", BLIST_NOLUN},		/* responds to all LUN */
+	{"SANKYO", "CP525", "6.64", BLIST_NOLUN},	/* causes failed REQ SENSE, extra reset */
+	{"HP", "C1750A", "3226", BLIST_NOLUN},	/* scanjet iic */
+	{"HP", "C1790A", "", BLIST_NOLUN},	/* scanjet iip */
+	{"HP", "C2500A", "", BLIST_NOLUN},	/* scanjet iicx */
+	{"YAMAHA", "CDR102", "1.00", BLIST_NOLUN},	/* extra reset */
+	{"RELISYS", "Scorpio", "*", BLIST_NOLUN},	/* responds to all LUN */
 
 /*
  * Other types of devices that have special flags.
@@ -285,9 +286,9 @@
 	{"REGAL", "CDC-4X", "*", BLIST_MAX5LUN | BLIST_SINGLELUN},
 	{"NAKAMICH", "MJ-4.8S", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
 	{"NAKAMICH", "MJ-5.16S", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"PIONEER", "CD-ROM DRM-600", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"PIONEER", "CD-ROM DRM-602X", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"PIONEER", "CD-ROM DRM-604X", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
+    {"PIONEER", "CD-ROM DRM-600", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
+   {"PIONEER", "CD-ROM DRM-602X", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
+   {"PIONEER", "CD-ROM DRM-604X", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
 	{"EMULEX", "MD21/S2     ESDI", "*", BLIST_SINGLELUN},
 	{"CANON", "IPUBJD", "*", BLIST_SPARSELUN},
 	{"nCipher", "Fastness Crypto", "*", BLIST_FORCELUN},
@@ -327,87 +328,6 @@
 	return 0;
 }
 
-/*
- * Function:    scsi_make_blocked_list
- *
- * Purpose:     Build linked list of hosts that require blocking.
- *
- * Arguments:   None.
- *
- * Returns:     Nothing
- *
- * Notes:       Blocking is sort of a hack that is used to prevent more than one
- *              host adapter from being active at one time.  This is used in cases
- *              where the ISA bus becomes unreliable if you have more than one
- *              host adapter really pumping data through.
- *
- *              We spent a lot of time examining the problem, and I *believe* that
- *              the problem is bus related as opposed to being a driver bug.
- *
- *              The blocked list is used as part of the synchronization object
- *              that we use to ensure that only one host is active at one time.
- *              I (ERY) would like to make this go away someday, but this would
- *              require that we have a recursive mutex object.
- */
-
-void scsi_make_blocked_list(void)
-{
-	int block_count = 0, index;
-	struct Scsi_Host *sh[128], *shpnt;
-
-	/*
-	 * Create a circular linked list from the scsi hosts which have
-	 * the "wish_block" field in the Scsi_Host structure set.
-	 * The blocked list should include all the scsi hosts using ISA DMA.
-	 * In some systems, using two dma channels simultaneously causes
-	 * unpredictable results.
-	 * Among the scsi hosts in the blocked list, only one host at a time
-	 * is allowed to have active commands queued. The transition from
-	 * one active host to the next one is allowed only when host_busy == 0
-	 * for the active host (which implies host_busy == 0 for all the hosts
-	 * in the list). Moreover for block devices the transition to a new
-	 * active host is allowed only when a request is completed, since a
-	 * block device request can be divided into multiple scsi commands
-	 * (when there are few sg lists or clustering is disabled).
-	 *
-	 * (DB, 4 Feb 1995)
-	 */
-
-
-	host_active = NULL;
-
-	for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
-
-#if 0
-		/*
-		 * Is this is a candidate for the blocked list?
-		 * Useful to put into the blocked list all the hosts whose driver
-		 * does not know about the host->block feature.
-		 */
-		if (shpnt->unchecked_isa_dma)
-			shpnt->wish_block = 1;
-#endif
-
-		if (shpnt->wish_block)
-			sh[block_count++] = shpnt;
-	}
-
-	if (block_count == 1)
-		sh[0]->block = NULL;
-
-	else if (block_count > 1) {
-
-		for (index = 0; index < block_count - 1; index++) {
-			sh[index]->block = sh[index + 1];
-			printk("scsi%d : added to blocked host list.\n",
-			       sh[index]->host_no);
-		}
-
-		sh[block_count - 1]->block = sh[0];
-		printk("scsi%d : added to blocked host list.\n",
-		       sh[index]->host_no);
-	}
-}
 
 static void scan_scsis_done(Scsi_Cmnd * SCpnt)
 {
@@ -472,23 +392,20 @@
 #endif
 
 /*
- *	Issue a command and wait for it to complete
+ *    Issue a command and wait for it to complete
  */
- 
-void scsi_wait_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
-		  void *buffer, unsigned bufflen, void (*done)(Scsi_Cmnd *),
-		  int timeout, int retries)
+
+void scsi_wait_cmd(Scsi_Cmnd * SCpnt, const void *cmnd,
+	      void *buffer, unsigned bufflen, void (*done) (Scsi_Cmnd *),
+		   int timeout, int retries)
 {
-	unsigned long flags;
 	DECLARE_MUTEX_LOCKED(sem);
-	
+
 	SCpnt->request.sem = &sem;
 	SCpnt->request.rq_status = RQ_SCSI_BUSY;
-	spin_lock_irqsave(&io_request_lock, flags);
-	scsi_do_cmd (SCpnt, (void *) cmnd,
-        	buffer, bufflen, done, timeout, retries);
-	spin_unlock_irqrestore(&io_request_lock, flags);
-	down (&sem);
+	scsi_do_cmd(SCpnt, (void *) cmnd,
+		    buffer, bufflen, done, timeout, retries);
+	down(&sem);
 	SCpnt->request.sem = NULL;
 }
 
@@ -524,6 +441,16 @@
 		SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof(Scsi_Device),
 							 GFP_ATOMIC);
 		if (SDpnt) {
+			/*
+			 * 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;
 			/* Make sure we have something that is valid for DMA purposes */
 			scsi_result = ((!shpnt->unchecked_isa_dma)
 				       ? &scsi_result0[0] : scsi_init_malloc(512, GFP_DMA));
@@ -541,6 +468,8 @@
 	SDpnt->host = shpnt;
 	SDpnt->online = TRUE;
 
+	initialize_merge_fn(SDpnt);
+
 	init_waitqueue_head(&SDpnt->device_wait);
 
 	/*
@@ -586,7 +515,6 @@
 				if (sdtpnt->init && sdtpnt->dev_noticed)
 					(*sdtpnt->init) ();
 
-			oldSDpnt->scsi_request_fn = NULL;
 			for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) {
 				if (sdtpnt->attach) {
 					(*sdtpnt->attach) (oldSDpnt);
@@ -722,6 +650,7 @@
 	SDpnt->borken = 1;
 	SDpnt->was_reset = 0;
 	SDpnt->expecting_cc_ua = 0;
+	SDpnt->starved = 0;
 
 	scsi_cmd[0] = TEST_UNIT_READY;
 	scsi_cmd[1] = lun << 5;
@@ -733,9 +662,9 @@
 	SCpnt->lun = SDpnt->lun;
 	SCpnt->channel = SDpnt->channel;
 
-	scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
-                  (void *) NULL,
-                  0, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5);
+	scsi_wait_cmd(SCpnt, (void *) scsi_cmd,
+		      (void *) NULL,
+		      0, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5);
 
 	SCSI_LOG_SCAN_BUS(3, printk("scsi: scan_scsis_single id %d lun %d. Return code 0x%08x\n",
 				    dev, lun, SCpnt->result));
@@ -766,9 +695,9 @@
 	scsi_cmd[5] = 0;
 	SCpnt->cmd_len = 0;
 
-	scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
-                  (void *) scsi_result,
-                  256, scan_scsis_done, SCSI_TIMEOUT, 3);
+	scsi_wait_cmd(SCpnt, (void *) scsi_cmd,
+		      (void *) scsi_result,
+		      256, scan_scsis_done, SCSI_TIMEOUT, 3);
 
 	SCSI_LOG_SCAN_BUS(3, printk("scsi: INQUIRY %s with code 0x%x\n",
 		SCpnt->result ? "failed" : "successful", SCpnt->result));
@@ -899,9 +828,9 @@
 		scsi_cmd[4] = 0x2a;
 		scsi_cmd[5] = 0;
 		SCpnt->cmd_len = 0;
-		scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
-                	(void *) scsi_result, 0x2a,
-                	scan_scsis_done, SCSI_TIMEOUT, 3);
+		scsi_wait_cmd(SCpnt, (void *) scsi_cmd,
+			      (void *) scsi_result, 0x2a,
+			      scan_scsis_done, SCSI_TIMEOUT, 3);
 	}
 	/*
 	 * Detach the command from the device. It was just a temporary to be used while
@@ -921,6 +850,19 @@
 		return 0;
 	}
 	/*
+	 * 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);
+
+	/*
 	 * And hook up our command block to the new device we will be testing
 	 * for.
 	 */
@@ -1006,127 +948,6 @@
  * of the calling code to ensure that this is the case.
  */
 
-Scsi_Cmnd *scsi_request_queueable(struct request * req, Scsi_Device * device)
-{
-	Scsi_Cmnd *SCpnt = NULL;
-	int tablesize;
-	Scsi_Cmnd *found = NULL;
-	struct buffer_head *bh, *bhp;
-
-	if (!device)
-		panic("No device passed to scsi_request_queueable().\n");
-
-	if (req && req->rq_status == RQ_INACTIVE)
-		panic("Inactive in scsi_request_queueable");
-
-	/*
-	 * Look for a free command block.  If we have been instructed not to queue
-	 * multiple commands to multi-lun devices, then check to see what else is
-	 * going for this device first.
-	 */
-
-	if (!device->single_lun) {
-		SCpnt = device->device_queue;
-		while (SCpnt) {
-			if (SCpnt->request.rq_status == RQ_INACTIVE)
-				break;
-			SCpnt = SCpnt->next;
-		}
-	} else {
-		SCpnt = device->device_queue;
-		while (SCpnt) {
-			if (SCpnt->channel == device->channel
-			    && SCpnt->target == device->id) {
-				if (SCpnt->lun == device->lun) {
-					if (found == NULL
-					    && SCpnt->request.rq_status == RQ_INACTIVE) {
-						found = SCpnt;
-					}
-				}
-				if (SCpnt->request.rq_status != RQ_INACTIVE) {
-					/*
-					 * I think that we should really limit things to one
-					 * outstanding command per device - this is what tends
-					 * to trip up buggy firmware.
-					 */
-					return NULL;
-				}
-			}
-			SCpnt = SCpnt->next;
-		}
-		SCpnt = found;
-	}
-
-	if (!SCpnt)
-		return NULL;
-
-	if (SCSI_BLOCK(device, device->host))
-		return NULL;
-
-	if (req) {
-		memcpy(&SCpnt->request, req, sizeof(struct request));
-		tablesize = device->host->sg_tablesize;
-		bhp = bh = req->bh;
-		if (!tablesize)
-			bh = NULL;
-		/* Take a quick look through the table to see how big it is.
-		 * We already have our copy of req, so we can mess with that
-		 * if we want to.
-		 */
-		while (req->nr_sectors && bh) {
-			bhp = bhp->b_reqnext;
-			if (!bhp || !CONTIGUOUS_BUFFERS(bh, bhp))
-				tablesize--;
-			req->nr_sectors -= bh->b_size >> 9;
-			req->sector += bh->b_size >> 9;
-			if (!tablesize)
-				break;
-			bh = bhp;
-		}
-		if (req->nr_sectors && bh && bh->b_reqnext) {	/* Any leftovers? */
-			SCpnt->request.bhtail = bh;
-			req->bh = bh->b_reqnext;	/* Divide request */
-			bh->b_reqnext = NULL;
-			bh = req->bh;
-
-			/* Now reset things so that req looks OK */
-			SCpnt->request.nr_sectors -= req->nr_sectors;
-			req->current_nr_sectors = bh->b_size >> 9;
-			req->buffer = bh->b_data;
-			SCpnt->request.sem = NULL;	/* Wait until whole thing done */
-		} else {
-			req->rq_status = RQ_INACTIVE;
-			wake_up(&wait_for_request);
-		}
-	} else {
-		SCpnt->request.rq_status = RQ_SCSI_BUSY;	/* Busy, but no request */
-		SCpnt->request.sem = NULL;	/* And no one is waiting for the device
-						 * either */
-	}
-
-	atomic_inc(&SCpnt->host->host_active);
-	SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n", SCpnt->target,
-				atomic_read(&SCpnt->host->host_active)));
-	SCpnt->use_sg = 0;	/* Reset the scatter-gather flag */
-	SCpnt->old_use_sg = 0;
-	SCpnt->transfersize = 0;
-	SCpnt->resid = 0;
-	SCpnt->underflow = 0;
-	SCpnt->cmd_len = 0;
-
-	/*
-	 *	Since not everyone seems to set the device info correctly
-	 *	before Scsi_Cmnd gets send out to scsi_do_command, we do it here.
-	 */
-	
-	SCpnt->channel = device->channel;
-	SCpnt->lun = device->lun;
-	SCpnt->target = device->id;
-	SCpnt->state = SCSI_STATE_INITIALIZING;
-	SCpnt->owner = SCSI_OWNER_HIGHLEVEL;
-
-	return SCpnt;
-}
 
 /* This function returns a structure pointer that will be valid for
  * the device.  The wait parameter tells us whether we should wait for
@@ -1138,163 +959,157 @@
  * of the packets for each device
  */
 
-Scsi_Cmnd *scsi_allocate_device(struct request ** reqp, Scsi_Device * device,
-				int wait)
+/*
+ * 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)
 {
-	kdev_t dev;
-	struct request *req = NULL;
-	int tablesize;
-	struct buffer_head *bh, *bhp;
 	struct Scsi_Host *host;
 	Scsi_Cmnd *SCpnt = NULL;
-	Scsi_Cmnd *SCwait = NULL;
-	Scsi_Cmnd *found = NULL;
+	Scsi_Device *SDpnt;
+	unsigned long flags;
 
 	if (!device)
 		panic("No device passed to scsi_allocate_device().\n");
 
-	if (reqp)
-		req = *reqp;
-
-	/*
-	 * See if this request has already been queued by an 
-	 * interrupt routine 
-	 */
-	 
-	if (req) {
-		if (req->rq_status == RQ_INACTIVE)
-			return NULL;
-		dev = req->rq_dev;
-	} else
-		dev = 0;	/* unused */
-
 	host = device->host;
 
-	if (in_interrupt() && SCSI_BLOCK(device, host))
-		return NULL;
+	spin_lock_irqsave(&device_request_lock, flags);
 
 	while (1 == 1) {
-		if (!device->single_lun) {
-			SCpnt = device->device_queue;
-			while (SCpnt) {
-				SCwait = SCpnt;
-				if (SCpnt->request.rq_status == RQ_INACTIVE)
-					break;
-				SCpnt = SCpnt->next;
-			}
-		} else {
-			SCpnt = device->device_queue;
-			while (SCpnt) {
-				if (SCpnt->channel == device->channel
-				    && SCpnt->target == device->id) {
-					if (SCpnt->lun == device->lun) {
-						SCwait = SCpnt;
-						if (found == NULL
-						    && SCpnt->request.rq_status == RQ_INACTIVE) {
-							found = SCpnt;
+		SCpnt = NULL;
+		if (!device->device_blocked) {
+			if (device->single_lun) {
+				/*
+				 * FIXME(eric) - this is not at all optimal.  Given that
+				 * single lun devices are rare and usually slow
+				 * (i.e. CD changers), this is good enough for now, but
+				 * we may want to come back and optimize this later.
+				 *
+				 * Scan through all of the devices attached to this
+				 * host, and see if any are active or not.  If so,
+				 * we need to defer this command.
+				 *
+				 * We really need a busy counter per device.  This would
+				 * allow us to more easily figure out whether we should
+				 * do anything here or not.
+				 */
+				for (SDpnt = host->host_queue;
+				     SDpnt;
+				     SDpnt = SDpnt->next) {
+					/*
+					 * Only look for other devices on the same bus
+					 * with the same target ID.
+					 */
+					if (SDpnt->channel != device->channel
+					    || SDpnt->id != device->id
+					    || SDpnt == device) {
+						continue;
+					}
+					for (SCpnt = SDpnt->device_queue;
+					     SCpnt;
+					     SCpnt = SCpnt->next) {
+						if (SCpnt->request.rq_status == RQ_INACTIVE) {
+							break;
 						}
 					}
-					if (SCpnt->request.rq_status != RQ_INACTIVE) {
-						/*
-						 * I think that we should really limit things to one
-						 * outstanding command per device - this is what tends
-						 * to trip up buggy firmware.
-						 */
-						found = NULL;
+					if (SCpnt) {
 						break;
 					}
 				}
-				SCpnt = SCpnt->next;
+				if (SDpnt) {
+					/*
+					 * Some other device in this cluster is busy.
+					 * If asked to wait, we need to wait, otherwise
+					 * return NULL.
+					 */
+					SCpnt = NULL;
+					break;
+				}
+			}
+			/*
+			 * Now we can check for a free command block for this device.
+			 */
+			for (SCpnt = device->device_queue; SCpnt; SCpnt = SCpnt->next) {
+				if (SCpnt->request.rq_status == RQ_INACTIVE)
+					break;
 			}
-			SCpnt = found;
 		}
-
-		/* See if this request has already been queued by an interrupt routine
+		/*
+		 * If we couldn't find a free command block, and we have been
+		 * asked to wait, then do so.
 		 */
-		if (req && (req->rq_status == RQ_INACTIVE || req->rq_dev != dev)) {
-			return NULL;
+		if (SCpnt) {
+			break;
 		}
-		if (!SCpnt || SCpnt->request.rq_status != RQ_INACTIVE) {	/* Might have changed */
-			if (wait && SCwait && SCwait->request.rq_status != RQ_INACTIVE) {
-				spin_unlock(&io_request_lock);	/* FIXME!!!! */
-				sleep_on(&device->device_wait);
-				spin_lock_irq(&io_request_lock);	/* FIXME!!!! */
-			} else {
-				if (!wait)
-					return NULL;
-				if (!SCwait) {
-					printk("Attempt to allocate device channel %d,"
-					       " target %d, lun %d\n", device->channel,
-					       device->id, device->lun);
-					panic("No device found in scsi_allocate_device\n");
-				}
-			}
+		/*
+		 * 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 {
-			if (req) {
-				memcpy(&SCpnt->request, req, sizeof(struct request));
-				tablesize = device->host->sg_tablesize;
-				bhp = bh = req->bh;
-				if (!tablesize)
-					bh = NULL;
-				/* Take a quick look through the table to see how big it is.
-				 * We already have our copy of req, so we can mess with that
-				 * if we want to.
-				 */
-				while (req->nr_sectors && bh) {
-					bhp = bhp->b_reqnext;
-					if (!bhp || !CONTIGUOUS_BUFFERS(bh, bhp))
-						tablesize--;
-					req->nr_sectors -= bh->b_size >> 9;
-					req->sector += bh->b_size >> 9;
-					if (!tablesize)
-						break;
-					bh = bhp;
-				}
-				if (req->nr_sectors && bh && bh->b_reqnext) {	/* Any leftovers? */
-					SCpnt->request.bhtail = bh;
-					req->bh = bh->b_reqnext;	/* Divide request */
-					bh->b_reqnext = NULL;
-					bh = req->bh;
-					/* Now reset things so that req looks OK */
-					SCpnt->request.nr_sectors -= req->nr_sectors;
-					req->current_nr_sectors = bh->b_size >> 9;
-					req->buffer = bh->b_data;
-					SCpnt->request.sem = NULL;	/* Wait until whole thing done */
-				} else {
-					req->rq_status = RQ_INACTIVE;
-					*reqp = req->next;
-					wake_up(&wait_for_request);
-				}
-			} else {
-				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);
-			SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n",
-						   SCpnt->target,
-				atomic_read(&SCpnt->host->host_active)));
-			break;
+			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->resid = 0;
-	SCpnt->underflow = 0;	/* Do not flag underflow conditions */
 
-	/* Since not everyone seems to set the device info correctly
-	 * before Scsi_Cmnd gets send out to scsi_do_command, we do it here.
-	 * FIXME(eric) This doesn't make any sense.
-	 */
-	SCpnt->channel = device->channel;
-	SCpnt->lun = device->lun;
-	SCpnt->target = device->id;
+	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;
 }
 
@@ -1311,6 +1126,9 @@
  */
 void scsi_release_command(Scsi_Cmnd * SCpnt)
 {
+	unsigned long flags;
+	spin_lock_irqsave(&device_request_lock, flags);
+
 	SCpnt->request.rq_status = RQ_INACTIVE;
 	SCpnt->state = SCSI_STATE_UNUSED;
 	SCpnt->owner = SCSI_OWNER_NOBODY;
@@ -1336,13 +1154,14 @@
 			     atomic_read(&SCpnt->host->eh_wait->count)));
 		up(SCpnt->host->eh_wait);
 	}
+	spin_unlock_irqrestore(&device_request_lock, flags);
 }
 
 /*
  * This is inline because we have stack problemes if we recurse to deeply.
  */
 
-inline int internal_cmnd(Scsi_Cmnd * SCpnt)
+int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt)
 {
 #ifdef DEBUG_DELAY
 	unsigned long clock;
@@ -1351,6 +1170,8 @@
 	int rtn = 0;
 	unsigned long timeout;
 
+	ASSERT_LOCK(&io_request_lock, 0);
+
 #if DEBUG
 	unsigned long *ret = 0;
 #ifdef __mips__
@@ -1384,11 +1205,9 @@
 		 * interrupt handler (assuming there is one irq-level per
 		 * host).
 		 */
-		spin_unlock_irq(&io_request_lock);
 		while (--ticks_remaining >= 0)
 			mdelay(1 + 999 / HZ);
 		host->resetting = 0;
-		spin_lock_irq(&io_request_lock);
 	}
 	if (host->hostt->use_new_eh_code) {
 		scsi_add_timer(SCpnt, SCpnt->timeout_per_command, scsi_times_out);
@@ -1401,7 +1220,7 @@
 	 * 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("internal_cmnd (host = %d, channel = %d, target = %d, "
+	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));
@@ -1419,6 +1238,7 @@
 		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 {
@@ -1432,10 +1252,8 @@
 		SCpnt->result = temp;
 #ifdef DEBUG_DELAY
 		clock = jiffies + 4 * HZ;
-		spin_unlock_irq(&io_request_lock);
 		while (time_before(jiffies, clock))
 			barrier();
-		spin_lock_irq(&io_request_lock);
 		printk("done(host = %d, result = %04x) : routine at %p\n",
 		       host->host_no, temp, host->hostt->command);
 #endif
@@ -1445,7 +1263,7 @@
 			scsi_old_done(SCpnt);
 		}
 	}
-	SCSI_LOG_MLQUEUE(3, printk("leaving internal_cmnd()\n"));
+	SCSI_LOG_MLQUEUE(3, printk("leaving scsi_dispatch_cmnd()\n"));
 	return rtn;
 }
 
@@ -1456,6 +1274,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)
@@ -1463,6 +1307,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,
@@ -1490,16 +1336,6 @@
 	 * ourselves.
 	 */
 
-	SCpnt->pid = scsi_pid++;
-
-	while (SCSI_BLOCK((Scsi_Device *) NULL, host)) {
-		spin_unlock(&io_request_lock);	/* FIXME!!! */
-		SCSI_SLEEP(&host->host_wait, SCSI_BLOCK((Scsi_Device *) NULL, host));
-		spin_lock_irq(&io_request_lock);	/* FIXME!!! */
-	}
-
-	if (host->block)
-		host_active = host;
 
 	host->host_busy++;
 	device->device_busy++;
@@ -1540,39 +1376,61 @@
 	SCpnt->internal_timeout = NORMAL_TIMEOUT;
 	SCpnt->abort_reason = 0;
 	SCpnt->result = 0;
-	internal_cmnd(SCpnt);
+
+	/*
+	 * 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);
 
 	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)
 {
+	unsigned long flags;
+	int tstatus;
 
 	/*
 	 * We don't have to worry about this one timing out any more.
 	 */
-	scsi_delete_timer(SCpnt);
+	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;
+	}
 	/* Set the serial numbers back to zero */
 	SCpnt->serial_number = 0;
 
@@ -1588,6 +1446,8 @@
 		SCSI_LOG_MLCOMPLETE(1, printk("Ignoring completion of %p due to timeout status", SCpnt));
 		return;
 	}
+	spin_lock_irqsave(&scsi_bhqueue_lock, flags);
+
 	SCpnt->serial_number_at_timeout = 0;
 	SCpnt->state = SCSI_STATE_BHQUEUE;
 	SCpnt->owner = SCSI_OWNER_BH_HANDLER;
@@ -1603,6 +1463,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;
@@ -1612,6 +1476,7 @@
 		scsi_bh_queue_tail = SCpnt;
 	}
 
+	spin_unlock_irqrestore(&scsi_bhqueue_lock, flags);
 	/*
 	 * Mark the bottom half handler to be run.
 	 */
@@ -1633,6 +1498,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)
 {
@@ -1640,14 +1512,14 @@
 	Scsi_Cmnd *SCnext;
 	unsigned long flags;
 
-	spin_lock_irqsave(&io_request_lock, flags);
 
 	while (1 == 1) {
+		spin_lock_irqsave(&scsi_bhqueue_lock, flags);
 		SCpnt = scsi_bh_queue_head;
 		scsi_bh_queue_head = NULL;
+		spin_unlock_irqrestore(&scsi_bhqueue_lock, flags);
 
 		if (SCpnt == NULL) {
-			spin_unlock_irqrestore(&io_request_lock, flags);
 			return;
 		}
 		SCnext = SCpnt->bh_next;
@@ -1731,8 +1603,6 @@
 
 	}			/* while(1==1) */
 
-	spin_unlock_irqrestore(&io_request_lock, flags);
-
 }
 
 /*
@@ -1753,9 +1623,7 @@
 	SCpnt->request_bufflen = SCpnt->bufflen;
 	SCpnt->use_sg = SCpnt->old_use_sg;
 	SCpnt->cmd_len = SCpnt->old_cmd_len;
-	SCpnt->result = 0;
-	memset((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer);
-	return internal_cmnd(SCpnt);
+	return scsi_dispatch_cmd(SCpnt);
 }
 
 /*
@@ -1770,32 +1638,14 @@
 	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. */
 
-	if (host->block && host->host_busy == 0) {
-		host_active = NULL;
-
-		/* For block devices "wake_up" is done in end_scsi_request */
-		if (!SCSI_BLK_MAJOR(MAJOR(SCpnt->request.rq_dev))) {
-			struct Scsi_Host *next;
-
-			for (next = host->block; next != host; next = next->block)
-				wake_up(&next->host_wait);
-		}
-	}
-	/*
-	 * Now try and drain the mid-level queue if any commands have been
-	 * inserted.  Check to see whether the queue even has anything in
-	 * it first, as otherwise this is useless overhead.
-	 */
-	if (SCpnt->host->pending_commands != NULL) {
-		scsi_mlqueue_finish(SCpnt->host, SCpnt->device);
-	}
-	wake_up(&host->host_wait);
 
 	/*
 	 * If we have valid sense information, then some kind of recovery
@@ -1821,9 +1671,34 @@
 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;
+	unsigned long flags;
+
 	int i, j;
 	if (len % SECTOR_SIZE != 0 || len > PAGE_SIZE)
 		return NULL;
@@ -1831,6 +1706,8 @@
 	nbits = len >> 9;
 	mask = (1 << nbits) - 1;
 
+	spin_lock_irqsave(&allocator_request_lock, flags);
+
 	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) {
@@ -1840,15 +1717,37 @@
 				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
+				spin_unlock_irqrestore(&allocator_request_lock, flags);
 				return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9));
 			}
 		}
+	spin_unlock_irqrestore(&allocator_request_lock, flags);
 	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;
+	unsigned long flags;
 
 #ifdef DEBUG
 	unsigned long ret = 0;
@@ -1862,6 +1761,8 @@
 	SCSI_LOG_MLQUEUE(3, printk("SFree: %p %d\n", obj, len));
 #endif
 
+	spin_lock_irqsave(&allocator_request_lock, flags);
+
 	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 &&
@@ -1884,6 +1785,7 @@
 			}
 			scsi_dma_free_sectors += nbits;
 			dma_malloc_freelist[page] &= ~(mask << sector);
+			spin_unlock_irqrestore(&allocator_request_lock, flags);
 			return 0;
 		}
 	}
@@ -1934,10 +1836,13 @@
 
 void scsi_build_commandblocks(Scsi_Device * SDpnt)
 {
+	unsigned long flags;
 	struct Scsi_Host *host = SDpnt->host;
 	int j;
 	Scsi_Cmnd *SCpnt;
 
+	spin_lock_irqsave(&device_request_lock, flags);
+
 	if (SDpnt->queue_depth == 0)
 		SDpnt->queue_depth = host->cmd_per_lun;
 	SDpnt->device_queue = NULL;
@@ -1977,8 +1882,10 @@
 		       SDpnt->queue_depth, j);
 		SDpnt->queue_depth = j;
 		SDpnt->has_cmdblocks = (0 != j);
-	} else
+	} else {
 		SDpnt->has_cmdblocks = 1;
+	}
+	spin_unlock_irqrestore(&device_request_lock, flags);
 }
 
 #ifndef MODULE			/* { */
@@ -2160,7 +2067,7 @@
 			}
 		}
 
-	stop_output:
+	      stop_output:
 		*start = buffer + (offset - begin);	/* Start of wanted data */
 		len -= (offset - begin);	/* Start slop */
 		if (len > length)
@@ -2374,6 +2281,7 @@
 			if (HBA_ptr->host_queue == scd) {
 				HBA_ptr->host_queue = scd->next;
 			}
+			blk_cleanup_queue(&scd->request_queue);
 			scsi_init_free((char *) scd, sizeof(Scsi_Device));
 		} else {
 			return (-EBUSY);
@@ -2385,13 +2293,27 @@
 #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, k;
 	unsigned long size;
+	unsigned long flags;
 	struct Scsi_Host *shpnt;
 	struct Scsi_Host *host = NULL;
 	Scsi_Device *SDpnt;
@@ -2401,6 +2323,8 @@
 	unsigned char **new_dma_malloc_pages = NULL;
 	int out_of_space = 0;
 
+	spin_lock_irqsave(&allocator_request_lock, flags);
+
 	if (!scsi_hostlist) {
 		/*
 		 * Free up the DMA pool.
@@ -2420,6 +2344,7 @@
 		dma_malloc_freelist = NULL;
 		dma_sectors = 0;
 		scsi_dma_free_sectors = 0;
+		spin_unlock_irqrestore(&allocator_request_lock, flags);
 		return;
 	}
 	/* Next, check to see if we need to extend the DMA buffer pool */
@@ -2566,6 +2491,8 @@
 	dma_sectors = new_dma_sectors;
 	scsi_need_isa_buffer = new_need_isa_buffer;
 
+	spin_unlock_irqrestore(&allocator_request_lock, flags);
+
 #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);
@@ -2668,8 +2595,6 @@
 		printk("scsi : %d host%s.\n", next_scsi_host,
 		       (next_scsi_host == 1) ? "" : "s");
 
-		scsi_make_blocked_list();
-
 		/* The next step is to call scan_scsis here.  This generates the
 		 * Scsi_Devices entries
 		 */
@@ -2881,6 +2806,7 @@
 			}
 			SDpnt->has_cmdblocks = 0;
 
+			blk_cleanup_queue(&SDpnt->request_queue);
 			/* Next free up the Scsi_Device structures for this host */
 			shpnt->host_queue = SDpnt->next;
 			scsi_init_free((char *) SDpnt, sizeof(Scsi_Device));
@@ -2940,7 +2866,6 @@
 	       (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
 #endif
 
-	scsi_make_blocked_list();
 
 	/* There were some hosts that were loaded at boot time, so we cannot
 	   do any more than this */
@@ -3175,12 +3100,11 @@
 	printk("Dump of scsi host parameters:\n");
 	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);
 
 	}
 
@@ -3226,10 +3150,10 @@
 			/* Now dump the request lists for each block device */
 			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) ",
 						   kdevname(req->rq_dev),
@@ -3244,7 +3168,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	Wed Oct 20 16:36:45 1999
+++ linux.new2/drivers/scsi/scsi.h	Sun Nov 14 09:25:47 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(__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:
@@ -379,23 +394,33 @@
 extern void scsi_sleep(int);
 
 /*
+ * Prototypes for functions in scsi_lib.c
+ */
+extern void initialize_merge_fn(Scsi_Device * SDpnt);
+extern void scsi_request_fn(request_queue_t * q);
+
+extern int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int);
+extern int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt);
+
+/*
  *  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.
  */
 
 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_wait_cmd (Scsi_Cmnd *, const void *cmnd ,
 			void *buffer, unsigned bufflen,
 			void (*done) (struct scsi_cmnd *),
 			int timeout, int retries);
 
+extern void scsi_wait_cmd(Scsi_Cmnd *, const void *cmnd,
+			  void *buffer, unsigned bufflen,
+			  void (*done) (struct scsi_cmnd *),
+			  int timeout, int retries);
 
-extern Scsi_Cmnd *scsi_allocate_device(struct request **, Scsi_Device *, int);
+extern void scsi_request_fn(request_queue_t * q);
+
+extern Scsi_Cmnd *scsi_allocate_device(Scsi_Device *, int);
 
 extern Scsi_Cmnd *scsi_request_queueable(struct request *, Scsi_Device *);
 
@@ -426,9 +451,10 @@
 	wait_queue_head_t device_wait;	/* Used to wait if
 					   device is busy */
 	struct Scsi_Host *host;
+	request_queue_t request_queue;
 	volatile unsigned short device_busy;	/* commands actually active on low-level */
-	void (*scsi_request_fn) (void);		/* Used to jumpstart things after an 
-						   * ioctl */
+	int (*scsi_init_io_fn) (Scsi_Cmnd *);	/* Used to initialize
+						   new request */
 	Scsi_Cmnd *device_queue;	/* queue of SCSI Command structures */
 
 /* public: */
@@ -436,6 +462,8 @@
 
 	unsigned int manufacturer;	/* Manufacturer of device, for using 
 					 * vendor-specific cmd's */
+	unsigned sector_size;	/* size in bytes */
+
 	int attached;		/* # of high level drivers attached to 
 				 * this */
 	int access_count;	/* Count of open channels/mounts */
@@ -473,6 +501,10 @@
 	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. */
+	unsigned ten:1;		/* support ten byte read / write */
+	unsigned remap:1;	/* support remapping  */
+	unsigned starved:1;	/* unable to process commands because
+				   host busy */
 };
 
 
@@ -575,16 +607,16 @@
 				   reconnects.   Probably == sector
 				   size */
 
-	int	resid;		/* Number of bytes requested to be
+	int resid;		/* Number of bytes requested to be
 				   transferred less actual number
 				   transferred (0 if not supported) */
 
 	struct request request;	/* A copy of the command we are
 				   working on */
 
-	unsigned char sense_buffer[64];  /* obtained by REQUEST SENSE when
-					    CHECK CONDITION is received on
-					    original command (auto-sense) */
+	unsigned char sense_buffer[64];		/* obtained by REQUEST SENSE when
+						   CHECK CONDITION is received on
+						   original command (auto-sense) */
 
 	unsigned flags;
 
@@ -628,6 +660,14 @@
 	unsigned long pid;	/* Process ID, starts at 0 */
 };
 
+/*
+ *  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
 
 /*
  * Definitions and prototypes used for scsi mid-level queue.
@@ -638,60 +678,15 @@
 extern int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason);
 extern int scsi_mlqueue_finish(struct Scsi_Host *host, Scsi_Device * device);
 
+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);
+
 
 #if defined(MAJOR_NR) && (MAJOR_NR != SCSI_TAPE_MAJOR)
 #include "hosts.h"
-
-static Scsi_Cmnd *end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors)
-{
-	struct request *req;
-	struct buffer_head *bh;
-
-	req = &SCpnt->request;
-	req->errors = 0;
-	if (!uptodate) {
-		printk(DEVICE_NAME " 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("end_scsi_request: buffer-list destroyed\n");
-				}
-			}
-		}
-	} while (sectors && bh);
-	if (req->bh) {
-		req->buffer = bh->b_data;
-		return SCpnt;
-	}
-	DEVICE_OFF(req->rq_dev);
-	if (req->sem != NULL) {
-		up(req->sem);
-	}
-	add_blkdev_randomness(MAJOR(req->rq_dev));
-
-	if (SCpnt->host->block) {
-		struct Scsi_Host *next;
-
-		for (next = SCpnt->host->block; next != SCpnt->host;
-		     next = next->block)
-			wake_up(&next->host_wait);
-	}
-	wake_up(&wait_for_request);
-	wake_up(&SCpnt->device->device_wait);
-	scsi_release_command(SCpnt);
-	return NULL;
-}
 
 
 /* This is just like INIT_REQUEST, but we need to be aware of the fact
diff -u -r linux.clean/drivers/scsi/scsi_debug.c linux.new2/drivers/scsi/scsi_debug.c
--- linux.clean/drivers/scsi/scsi_debug.c	Sun Oct 17 12:32:57 1999
+++ linux.new2/drivers/scsi/scsi_debug.c	Sun Nov 14 09:35:30 1999
@@ -41,14 +41,17 @@
 
 #define NR_HOSTS_PRESENT 1
 #define NR_FAKE_DISKS   3
-#define N_HEAD          32
-#define N_SECTOR        64
-#define DISK_READONLY(TGT)      (1)
+#define N_HEAD          255
+#define N_SECTOR        63
+#define N_CYLINDER      524
+#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
@@ -65,11 +68,15 @@
 #define START_PARTITION 4
 
 /* Time to wait before completing a command */
-#define DISK_SPEED     (HZ/10)   /* 100ms */
-#define CAPACITY (0x80000)
+#define DISK_SPEED     (HZ/10)	/* 100ms */
+#define CAPACITY (N_HEAD * N_SECTOR * N_CYLINDER)
+#define SIZE(TGT) (TGT == 2 ? 2248 : 512)
 
 static int starts[] =
-{N_HEAD, N_HEAD * N_SECTOR, 50000, CAPACITY, 0};
+{N_SECTOR,
+ N_HEAD * N_SECTOR,		/* Single cylinder */
+ N_HEAD * N_SECTOR * 4,
+ CAPACITY, 0};
 static int npart = 0;
 
 #include "scsi_debug.h"
@@ -119,21 +126,25 @@
 
 typedef void (*done_fct_t) (Scsi_Cmnd *);
 
-static volatile done_fct_t do_done[SCSI_DEBUG_MAILBOXES] = {NULL,};
+static volatile done_fct_t do_done[SCSI_DEBUG_MAILBOXES] =
+{NULL,};
 
 static void scsi_debug_intr_handle(unsigned long);
 
 static struct timer_list timeout[SCSI_DEBUG_MAILBOXES];
 
-Scsi_Cmnd *SCint[SCSI_DEBUG_MAILBOXES]  = {NULL,};
-static char SCrst[SCSI_DEBUG_MAILBOXES] = {0,};
+Scsi_Cmnd *SCint[SCSI_DEBUG_MAILBOXES] =
+{NULL,};
+static char SCrst[SCSI_DEBUG_MAILBOXES] =
+{0,};
 
 /*
  * Semaphore used to simulate bus lockups.
  */
 static int scsi_debug_lockup = 0;
 
-static char sense_buffer[128] = {0,};
+static char sense_buffer[128] =
+{0,};
 
 static void scsi_dump(Scsi_Cmnd * SCpnt, int flag)
 {
@@ -249,6 +260,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]) {
 			SCSI_LOG_LLQUEUE(2, printk("Medium removal inhibited..."));
@@ -260,7 +275,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;
@@ -284,7 +299,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:
@@ -334,15 +352,23 @@
 				p = (struct partition *) (buff + 0x1be);
 				i = 0;
 				while (starts[i + 1]) {
+					int start_cyl, end_cyl;
+
+					start_cyl = starts[i] / N_HEAD / N_SECTOR;
+					end_cyl = (starts[i + 1] - 1) / N_HEAD / N_SECTOR;
+					p->boot_ind = 0;
+
+					p->head = (i == 0 ? 1 : 0);
+					p->sector = 1 | ((start_cyl >> 8) << 6);
+					p->cyl = (start_cyl & 0xff);
+
+					p->end_head = N_HEAD - 1;
+					p->end_sector = N_SECTOR | ((end_cyl >> 8) << 6);
+					p->end_cyl = (end_cyl & 0xff);
+
 					p->start_sect = starts[i];
 					p->nr_sects = starts[i + 1] - starts[i];
 					p->sys_ind = 0x81;	/* Linux partition */
-					p->head = (i == 0 ? 1 : 0);
-					p->sector = 1;
-					p->cyl = starts[i] / N_HEAD / N_SECTOR;
-					p->end_head = N_HEAD - 1;
-					p->end_sector = N_SECTOR;
-					p->end_cyl = starts[i + 1] / N_HEAD / N_SECTOR;
 					p++;
 					i++;
 				};
@@ -472,6 +498,8 @@
 #ifdef IMMEDIATE
 	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);
@@ -596,7 +624,7 @@
 	int size = disk->capacity;
 	info[0] = N_HEAD;
 	info[1] = N_SECTOR;
-	info[2] = (size + 2047) >> 11;
+	info[2] = N_CYLINDER;
 	if (info[2] >= 1024)
 		info[2] = 1024;
 	return 0;
@@ -690,6 +718,21 @@
 
 	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	Sun Sep 12 15:26:06 1999
+++ linux.new2/drivers/scsi/scsi_debug.h	Sun Nov 14 08:55:35 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	Sun Oct 17 15:45:17 1999
+++ linux.new2/drivers/scsi/scsi_error.c	Sun Nov 14 08:55:35 1999
@@ -35,11 +35,13 @@
 #include "hosts.h"
 #include "constants.h"
 
-#ifdef MODULE
+/*
+ * We must always allow SHUTDOWN_SIGS.  Even if we are not a module,
+ * the host drivers that we are using may be loaded as modules, and
+ * when we unload these,  we need to ensure that the error handler thread
+ * can be shut down.
+ */
 #define SHUTDOWN_SIGS	(sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM))
-#else
-#define SHUTDOWN_SIGS	(0UL)
-#endif
 
 #ifdef DEBUG
 #define SENSE_TIMEOUT SCSI_TIMEOUT
@@ -128,7 +130,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 +140,7 @@
 {
 	int rtn;
 
-	rtn = jiffies - SCset->eh_timeout.expires;
-	del_timer(&SCset->eh_timeout);
+	rtn = del_timer(&SCset->eh_timeout);
 
 	SCSI_LOG_ERROR_RECOVERY(5, printk("Clearing timer for command %p\n", SCset));
 
@@ -563,10 +566,7 @@
 
 	add_timer(&timer);
 
-	spin_unlock_irq(&io_request_lock);
 	down(&sem);
-	spin_lock_irq(&io_request_lock);
-
 	del_timer(&timer);
 }
 
@@ -811,7 +811,9 @@
 	 * If we had a successful bus reset, mark the command blocks to expect
 	 * a condition code of unit attention.
 	 */
+	spin_unlock_irq(&io_request_lock);
 	scsi_sleep(BUS_RESET_SETTLE_TIME);
+	spin_lock_irq(&io_request_lock);
 	if (SCpnt->eh_state == SUCCESS) {
 		Scsi_Device *SDloop;
 		for (SDloop = SCpnt->host->host_queue; SDloop; SDloop = SDloop->next) {
@@ -854,7 +856,9 @@
 	 * If we had a successful host reset, mark the command blocks to expect
 	 * a condition code of unit attention.
 	 */
+	spin_unlock_irq(&io_request_lock);
 	scsi_sleep(HOST_RESET_SETTLE_TIME);
+	spin_lock_irq(&io_request_lock);
 	if (SCpnt->eh_state == SUCCESS) {
 		Scsi_Device *SDloop;
 		for (SDloop = SCpnt->host->host_queue; SDloop; SDloop = SDloop->next) {
@@ -1172,6 +1176,7 @@
 STATIC void scsi_restart_operations(struct Scsi_Host *host)
 {
 	Scsi_Device *SDpnt;
+	unsigned long flags;
 
 	/*
 	 * Next free up anything directly waiting upon the host.  This will be
@@ -1183,18 +1188,23 @@
 	wake_up(&host->host_wait);
 
 	/*
-	 * Finally, block devices need an extra kick in the pants.  This is because
-	 * the request queueing mechanism may have queued lots of pending requests
-	 * and there won't be a process waiting in a place where we can simply wake
-	 * it up.  Thus we simply go through and call the request function to goose
-	 * the various top level drivers and get things moving again.
+	 * 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) {
-		SCSI_LOG_ERROR_RECOVERY(5, printk("Calling request function to restart things...\n"));
-
-		if (SDpnt->scsi_request_fn != NULL)
-			(*SDpnt->scsi_request_fn) ();
+		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);
 }
 
 /*
@@ -1524,7 +1534,9 @@
 						 * Due to the spinlock, we will never get out of this
 						 * loop without a proper wait (DB)
 						 */
+						spin_unlock_irq(&io_request_lock);
 						scsi_sleep(1 * HZ);
+						spin_lock_irq(&io_request_lock);
 
 						goto next_device;
 					}
@@ -1617,7 +1629,9 @@
 				 * Due to the spinlock, we will never get out of this
 				 * loop without a proper wait. (DB)
 				 */
+				spin_unlock_irq(&io_request_lock);
 				scsi_sleep(1 * HZ);
+				spin_lock_irq(&io_request_lock);
 
 				goto next_device2;
 			}
@@ -1768,11 +1782,11 @@
 	lock_kernel();
 
 	/*
-	 *	Flush resources
+	 *    Flush resources
 	 */
-	 
+
 	daemonize();
-	
+
 	/*
 	 * Set the name of this process.
 	 */
diff -u -r linux.clean/drivers/scsi/scsi_ioctl.c linux.new2/drivers/scsi/scsi_ioctl.c
--- linux.clean/drivers/scsi/scsi_ioctl.c	Sun Oct 17 15:38:27 1999
+++ linux.new2/drivers/scsi/scsi_ioctl.c	Sun Nov 14 08:55:35 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)
@@ -69,7 +69,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, 
@@ -105,22 +105,18 @@
 static int ioctl_internal_command(Scsi_Device * dev, char *cmd,
 				  int timeout, int retries)
 {
-	unsigned long flags;
 	int result;
 	Scsi_Cmnd *SCpnt;
 	Scsi_Device *SDpnt;
 
-	spin_lock_irqsave(&io_request_lock, flags);
 
 	SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", cmd[0]));
-	SCpnt = scsi_allocate_device(NULL, dev, 1);
+	SCpnt = scsi_allocate_device(dev, 1);
 	{
 		DECLARE_MUTEX_LOCKED(sem);
 		SCpnt->request.sem = &sem;
 		scsi_do_cmd(SCpnt, cmd, NULL, 0, scsi_ioctl_done, timeout, retries);
-		spin_unlock_irqrestore(&io_request_lock, flags);
 		down(&sem);
-		spin_lock_irqsave(&io_request_lock, flags);
 		SCpnt->request.sem = NULL;
 	}
 
@@ -167,11 +163,8 @@
 	scsi_release_command(SCpnt);
 	SCpnt = NULL;
 
-	if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
-		(*SDpnt->scsi_request_fn) ();
 
 	wake_up(&SDpnt->device_wait);
-	spin_unlock_irqrestore(&io_request_lock, flags);
 	return result;
 }
 
@@ -183,34 +176,33 @@
  * The structure that we are passed should look like:
  *
  * struct sdata {
- *  unsigned int inlen;	     [i] Length of data to be written to device 
+ *  unsigned int inlen;      [i] Length of data to be written to device 
  *  unsigned int outlen;     [i] Length of data to be read from device 
  *  unsigned char cmd[x];    [i] SCSI command (6 <= x <= 12).
- *			     [o] Data read from device starts here.
- *			     [o] On error, sense buffer starts here.
+ *                           [o] Data read from device starts here.
+ *                           [o] On error, sense buffer starts here.
  *  unsigned char wdata[y];  [i] Data written to device starts here.
  * };
  * Notes:
- *   -	The SCSI command length is determined by examining the 1st byte
- *	of the given command. There is no way to override this.
- *   -	Data transfers are limited to PAGE_SIZE (4K on i386, 8K on alpha).
- *   -	The length (x + y) must be at least OMAX_SB_LEN bytes long to
- *	accomodate the sense buffer when an error occurs.
- *	The sense buffer is truncated to OMAX_SB_LEN (16) bytes so that
- *	old code will not be surprised.
- *   -	If a Unix error occurs (e.g. ENOMEM) then the user will receive
- *	a negative return and the Unix error code in 'errno'. 
- *	If the SCSI command succeeds then 0 is returned.
- *	Positive numbers returned are the compacted SCSI error codes (4 
- *	bytes in one int) where the lowest byte is the SCSI status.
- *	See the drivers/scsi/scsi.h file for more information on this.
+ *   -  The SCSI command length is determined by examining the 1st byte
+ *      of the given command. There is no way to override this.
+ *   -  Data transfers are limited to PAGE_SIZE (4K on i386, 8K on alpha).
+ *   -  The length (x + y) must be at least OMAX_SB_LEN bytes long to
+ *      accomodate the sense buffer when an error occurs.
+ *      The sense buffer is truncated to OMAX_SB_LEN (16) bytes so that
+ *      old code will not be surprised.
+ *   -  If a Unix error occurs (e.g. ENOMEM) then the user will receive
+ *      a negative return and the Unix error code in 'errno'. 
+ *      If the SCSI command succeeds then 0 is returned.
+ *      Positive numbers returned are the compacted SCSI error codes (4 
+ *      bytes in one int) where the lowest byte is the SCSI status.
+ *      See the drivers/scsi/scsi.h file for more information on this.
  *
  */
-#define OMAX_SB_LEN 16   /* Old sense buffer length */
+#define OMAX_SB_LEN 16		/* Old sense buffer length */
 
 int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
 {
-	unsigned long flags;
 	char *buf;
 	unsigned char cmd[12];
 	char *cmd_in;
@@ -251,9 +243,7 @@
 		buf_needed = (buf_needed + 511) & ~511;
 		if (buf_needed > MAX_BUF)
 			buf_needed = MAX_BUF;
-		spin_lock_irqsave(&io_request_lock, flags);
 		buf = (char *) scsi_malloc(buf_needed);
-		spin_unlock_irqrestore(&io_request_lock, flags);
 		if (!buf)
 			return -ENOMEM;
 		memset(buf, 0, buf_needed);
@@ -299,23 +289,21 @@
 		retries = NORMAL_RETRIES;
 		break;
 	default:
-		timeout = NORMAL_TIMEOUT;
+		timeout = IOCTL_NORMAL_TIMEOUT;
 		retries = NORMAL_RETRIES;
 		break;
 	}
 
 #ifndef DEBUG_NO_CMD
 
-	spin_lock_irqsave(&io_request_lock, flags);
 
-	SCpnt = scsi_allocate_device(NULL, dev, 1);
+	SCpnt = scsi_allocate_device(dev, 1);
 
 	{
 		DECLARE_MUTEX_LOCKED(sem);
 		SCpnt->request.sem = &sem;
 		scsi_do_cmd(SCpnt, cmd, buf, needed, scsi_ioctl_done,
 			    timeout, retries);
-		spin_unlock_irqrestore(&io_request_lock, flags);
 		down(&sem);
 		SCpnt->request.sem = NULL;
 	}
@@ -339,7 +327,6 @@
 	}
 	result = SCpnt->result;
 
-	spin_lock_irqsave(&io_request_lock, flags);
 
 	wake_up(&SCpnt->device->device_wait);
 	SDpnt = SCpnt->device;
@@ -349,10 +336,7 @@
 	if (buf)
 		scsi_free(buf, buf_needed);
 
-	if (SDpnt->scsi_request_fn)
-		(*SDpnt->scsi_request_fn) ();
 
-	spin_unlock_irqrestore(&io_request_lock, flags);
 	return result;
 #else
 	{
@@ -445,7 +429,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)
@@ -455,14 +439,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	Sun Nov  7 19:33:48 1999
+++ linux.new2/drivers/scsi/scsi_lib.c	Sun Nov 14 08:55:35 1999
@@ -0,0 +1,755 @@
+/*
+ *  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.
+ */
+
+/*
+ * 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);
+	}
+
+	/*
+	 * If this is a single-lun device, and we are currently finished
+	 * with this device, then see if we need to get another device
+	 * started.
+	 */
+	if (SDpnt->single_lun
+	    && q->current_request == NULL
+	    && SDpnt->device_busy == 0) {
+		request_queue_t *q;
+
+		for (SDpnt = SHpnt->host_queue;
+		     SDpnt;
+		     SDpnt = SDpnt->next) {
+			if (((SHpnt->can_queue > 0)
+			     && (SHpnt->host_busy >= SHpnt->can_queue))
+			    || (SHpnt->host_blocked)
+			    || (SDpnt->device_blocked)) {
+				break;
+			}
+			q = &SDpnt->request_queue;
+			q->request_fn(q);
+		}
+	}
+}
diff -u -r linux.clean/drivers/scsi/scsi_merge.c linux.new2/drivers/scsi/scsi_merge.c
--- linux.clean/drivers/scsi/scsi_merge.c	Sun Nov  7 19:33:52 1999
+++ linux.new2/drivers/scsi/scsi_merge.c	Sun Nov 14 08:55:35 1999
@@ -0,0 +1,740 @@
+/*
+ *  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_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.
+ */
+
+/*
+ * Function:    __count_segments()
+ *
+ * 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_segments < SHpnt->sg_tablesize) {
+		/*
+		 * This will form the start of a new segment.  Bump the 
+		 * counter.
+		 */
+		req->nr_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_segments + next->nr_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_segments += next->nr_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_segments + next->nr_segments > SHpnt->sg_tablesize) {
+		return 0;
+	} else {
+		/*
+		 * This will form the start of a new segment.  Bump the 
+		 * counter.
+		 */
+		req->nr_segments += next->nr_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_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);	\
+}
+
+/*
+ * ll_rw_blk.c now keeps track of the number of segments in
+ * a request.  Thus we don't have to do it any more here.
+ * We always force "_VALID" to 1.  Eventually clean this up
+ * and get rid of the extra argument.
+ */
+#if 0
+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)
+#else
+INITIO(scsi_init_io_, 1, 0, 0)
+INITIO(scsi_init_io_d, 1, 0, 1)
+INITIO(scsi_init_io_c, 1, 1, 0)
+INITIO(scsi_init_io_dc, 1, 1, 1)
+#endif
+
+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;
+	}
+}
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 Sep 12 15:26:06 1999
+++ linux.new2/drivers/scsi/scsi_obsolete.c	Sun Nov 14 08:55:36 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,13 +84,15 @@
 extern void scsi_old_done(Scsi_Cmnd * SCpnt);
 int update_timeout(Scsi_Cmnd *, int);
 extern void scsi_old_times_out(Scsi_Cmnd * SCpnt);
-extern void internal_cmnd(Scsi_Cmnd * SCpnt);
+
+extern int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt);
 
 extern volatile struct Scsi_Host *host_active;
 #define SCSI_BLOCK(HOST) ((HOST->block && host_active && HOST != host_active) \
 			  || (HOST->can_queue && HOST->host_busy >= HOST->can_queue))
 
-static unsigned char generic_sense[6] = {REQUEST_SENSE, 0, 0, 0, 255, 0};
+static unsigned char generic_sense[6] =
+{REQUEST_SENSE, 0, 0, 0, 255, 0};
 
 /*
  *  This is the number  of clock ticks we should wait before we time out
@@ -232,7 +234,7 @@
 	SCpnt->use_sg = 0;
 	SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
 	SCpnt->result = 0;
-	internal_cmnd(SCpnt);
+	scsi_dispatch_cmd(SCpnt);
 }
 
 
@@ -443,7 +445,7 @@
 							       __LINE__);
 						}
 					}
-					/* end WAS_SENSE */ 
+					/* end WAS_SENSE */
 					else {
 #ifdef DEBUG
 						printk("COMMAND COMPLETE message returned, "
@@ -628,7 +630,7 @@
 			SCpnt->use_sg = SCpnt->old_use_sg;
 			SCpnt->cmd_len = SCpnt->old_cmd_len;
 			SCpnt->result = 0;
-			internal_cmnd(SCpnt);
+			scsi_dispatch_cmd(SCpnt);
 		}
 		break;
 	default:
@@ -641,18 +643,6 @@
 #endif
 		host->host_busy--;	/* Indicate that we are free */
 
-		if (host->block && host->host_busy == 0) {
-			host_active = NULL;
-
-			/* For block devices "wake_up" is done in end_scsi_request */
-			if (!SCSI_BLK_MAJOR(MAJOR(SCpnt->request.rq_dev))) {
-				struct Scsi_Host *next;
-
-				for (next = host->block; next != host; next = next->block)
-					wake_up(&next->host_wait);
-			}
-		}
-		wake_up(&host->host_wait);
 		SCpnt->result = result | ((exit & 0xff) << 24);
 		SCpnt->use_sg = SCpnt->old_use_sg;
 		SCpnt->cmd_len = SCpnt->old_cmd_len;
@@ -925,8 +915,7 @@
 				if (host->last_reset - jiffies > 20UL * HZ)
 					host->last_reset = jiffies;
 			} else {
-				if (!host->block)
-					host->host_busy++;
+				host->host_busy++;
 				host->last_reset = jiffies;
 				host->resetting = 1;
 				SCpnt->flags |= (WAS_RESET | IS_RESETTING);
@@ -939,8 +928,7 @@
 				if (time_before(host->last_reset, jiffies) ||
 				    (time_after(host->last_reset, jiffies + 20 * HZ)))
 					host->last_reset = jiffies;
-				if (!host->block)
-					host->host_busy--;
+				host->host_busy--;
 			}
 			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	Sun Sep 12 15:26:06 1999
+++ linux.new2/drivers/scsi/scsi_queue.c	Sun Nov 14 08:55:36 1999
@@ -56,14 +56,6 @@
 
 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 $";
 
-/*
- * 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.
- */
-
-spinlock_t scsi_mlqueue_lock = SPIN_LOCK_UNLOCKED;
-spinlock_t scsi_mlqueue_remove_lock = SPIN_LOCK_UNLOCKED;
 
 /*
  * Function:    scsi_mlqueue_insert()
@@ -84,8 +76,6 @@
  */
 int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason)
 {
-	Scsi_Cmnd *cpnt;
-	unsigned long flags;
 	struct Scsi_Host *host;
 
 	SCSI_LOG_MLQUEUE(1, printk("Inserting command %p into mlqueue\n", cmd));
@@ -126,12 +116,12 @@
 		 * 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) {
 				return 0;
 			}
 		}
-		cmd->device->device_busy = TRUE;
+		cmd->device->device_blocked = TRUE;
 		cmd->device_wait = TRUE;
 	}
 
@@ -143,142 +133,9 @@
 	cmd->bh_next = NULL;
 
 	/*
-	 * As a performance enhancement, look to see whether the list is
-	 * empty.  If it is, then we can just atomicly insert the command
-	 * in the list and return without locking.
-	 */
-	if (host->pending_commands == NULL) {
-		cpnt = xchg(&host->pending_commands, cmd);
-		if (cpnt == NULL) {
-			return 0;
-		}
-		/*
-		 * Rats.  Something slipped in while we were exchanging.
-		 * Swap it back and fall through to do it the hard way.
-		 */
-		cmd = xchg(&host->pending_commands, cpnt);
-
-	}
-	/*
-	 * Next append the command to the list of pending commands.
-	 */
-	spin_lock_irqsave(&scsi_mlqueue_lock, flags);
-	for (cpnt = host->pending_commands; cpnt && cpnt->bh_next;
-	     cpnt = cpnt->bh_next) {
-		continue;
-	}
-	if (cpnt != NULL) {
-		cpnt->bh_next = cmd;
-	} else {
-		host->pending_commands = cmd;
-	}
-
-	spin_unlock_irqrestore(&scsi_mlqueue_lock, flags);
-	return 0;
-}
-
-/*
- * Function:    scsi_mlqueue_finish()
- *
- * Purpose:     Try and queue commands from the midlevel queue.
- *
- * Arguments:   host    - host that just finished a command.
- *              device  - device that just finished a command.
- *
- * Returns:     Nothing.
- *
- * Notes:       This could be called either from an interrupt context or a
- *              normal process context.
- */
-int scsi_mlqueue_finish(struct Scsi_Host *host, Scsi_Device * device)
-{
-	Scsi_Cmnd *cpnt;
-	unsigned long flags;
-	Scsi_Cmnd *next;
-	Scsi_Cmnd *prev;
-	int reason = 0;
-	int rtn;
-
-	SCSI_LOG_MLQUEUE(2, printk("scsi_mlqueue_finish starting\n"));
-	/*
-	 * First, clear the flag for the host/device.  We will then start
-	 * pushing commands through until either something else blocks, or
-	 * the queue is empty.
-	 */
-	if (host->host_blocked) {
-		reason = SCSI_MLQUEUE_HOST_BUSY;
-		host->host_blocked = FALSE;
-	}
-	if (device->device_busy) {
-		reason = SCSI_MLQUEUE_DEVICE_BUSY;
-		device->device_busy = FALSE;
-	}
-	/*
-	 * Walk the list of commands to see if there is anything we can
-	 * queue.  This probably needs to be optimized for performance at
-	 * some point.
+	 * 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.
 	 */
-	prev = NULL;
-	spin_lock_irqsave(&scsi_mlqueue_remove_lock, flags);
-	for (cpnt = host->pending_commands; cpnt; cpnt = next) {
-		next = cpnt->bh_next;
-		/*
-		 * First, see if this command is suitable for being retried now.
-		 */
-		if (reason == SCSI_MLQUEUE_HOST_BUSY) {
-			/*
-			 * The host was busy, but isn't any more.  Thus we may be
-			 * able to queue the command now, but we were waiting for
-			 * the device, then we should keep waiting.  Similarily, if
-			 * the device is now busy, we should also keep waiting.
-			 */
-			if ((cpnt->host_wait == FALSE)
-			    || (device->device_busy == TRUE)) {
-				prev = cpnt;
-				continue;
-			}
-		}
-		if (reason == SCSI_MLQUEUE_DEVICE_BUSY) {
-			/*
-			 * The device was busy, but isn't any more.  Thus we may be
-			 * able to queue the command now, but we were waiting for
-			 * the host, then we should keep waiting.  Similarily, if
-			 * the host is now busy, we should also keep waiting.
-			 */
-			if ((cpnt->device_wait == FALSE)
-			    || (host->host_blocked == TRUE)) {
-				prev = cpnt;
-				continue;
-			}
-		}
-		/*
-		 * First, remove the command from the list.
-		 */
-		if (prev == NULL) {
-			host->pending_commands = next;
-		} else {
-			prev->bh_next = next;
-		}
-		cpnt->bh_next = NULL;
-
-		rtn = scsi_retry_command(cpnt);
-
-		/*
-		 * If we got a non-zero return value, it means that the host rejected
-		 * the command.  The internal_cmnd function will have added the
-		 * command back to the end of the list, so we don't have anything
-		 * more to do here except return.
-		 */
-		if (rtn) {
-			spin_unlock_irqrestore(&scsi_mlqueue_remove_lock, flags);
-			SCSI_LOG_MLQUEUE(1, printk("Unable to remove command %p from mlqueue\n", cpnt));
-			goto finish;
-		}
-		SCSI_LOG_MLQUEUE(1, printk("Removed command %p from mlqueue\n", cpnt));
-	}
-
-	spin_unlock_irqrestore(&scsi_mlqueue_remove_lock, flags);
-finish:
-	SCSI_LOG_MLQUEUE(2, printk("scsi_mlqueue_finish returning\n"));
+	scsi_insert_special_cmd(cmd, 1);
 	return 0;
 }
diff -u -r linux.clean/drivers/scsi/scsi_syms.c linux.new2/drivers/scsi/scsi_syms.c
--- linux.clean/drivers/scsi/scsi_syms.c	Sun Oct 17 12:32:58 1999
+++ linux.new2/drivers/scsi/scsi_syms.c	Sun Nov 14 08:55:36 1999
@@ -33,8 +33,8 @@
  * modules.
  */
 
-extern void print_command (unsigned char *command);
-extern void print_sense(const char * devclass, Scsi_Cmnd * SCpnt);
+extern void print_command(unsigned char *command);
+extern void print_sense(const char *devclass, Scsi_Cmnd * SCpnt);
 
 extern const char *const scsi_device_types[];
 
@@ -60,19 +60,22 @@
 EXPORT_SYMBOL(scsi_dma_free_sectors);
 EXPORT_SYMBOL(kernel_scsi_ioctl);
 EXPORT_SYMBOL(scsi_need_isa_buffer);
-EXPORT_SYMBOL(scsi_request_queueable);
 EXPORT_SYMBOL(scsi_release_command);
 EXPORT_SYMBOL(print_Scsi_Cmnd);
 EXPORT_SYMBOL(scsi_block_when_processing_errors);
 EXPORT_SYMBOL(scsi_mark_host_reset);
 EXPORT_SYMBOL(scsi_ioctl_send_command);
-#if defined(CONFIG_SCSI_LOGGING) /* { */
+#if defined(CONFIG_SCSI_LOGGING)	/* { */
 EXPORT_SYMBOL(scsi_logging_level);
 #endif
 
 EXPORT_SYMBOL(scsi_sleep);
 
 EXPORT_SYMBOL(proc_print_scsidevice);
+
+EXPORT_SYMBOL(scsi_io_completion);
+EXPORT_SYMBOL(scsi_end_request);
+
 /*
  * These are here only while I debug the rest of the scsi stuff.
  */
@@ -81,5 +84,4 @@
 EXPORT_SYMBOL(scsi_devicelist);
 EXPORT_SYMBOL(scsi_device_types);
 
-
-#endif /* CONFIG_MODULES */
+#endif				/* CONFIG_MODULES */
diff -u -r linux.clean/drivers/scsi/sd.c linux.new2/drivers/scsi/sd.c
--- linux.clean/drivers/scsi/sd.c	Sun Oct 17 12:32:58 1999
+++ linux.new2/drivers/scsi/sd.c	Sun Nov 14 10:22:10 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,15 @@
 
 static int sd_init_onedisk(int);
 
-static void requeue_sd_request(Scsi_Cmnd * SCpnt);
 
 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);
+
+static int sd_init_command(Scsi_Cmnd *);
 
 static void sd_devname(unsigned int disknum, char *buffer)
 {
@@ -120,12 +122,171 @@
 }
 
 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,
+	init_command:sd_init_command,
 };
 
+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;
+}
+
 static int sd_open(struct inode *inode, struct file *filp)
 {
 	int target;
@@ -283,7 +444,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,
@@ -304,202 +465,37 @@
 		(SCpnt->sense_buffer[4] << 16) |
 		(SCpnt->sense_buffer[5] << 8) |
 		SCpnt->sense_buffer[6];
-		int sector_size =
-		rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].sector_size;
 		if (SCpnt->request.bh != NULL)
 			block_sectors = SCpnt->request.bh->b_size >> 9;
-		if (sector_size == 1024) {
+		switch (SCpnt->device->sector_size) {
+		case 1024:
 			error_sector <<= 1;
 			if (block_sectors < 2)
 				block_sectors = 2;
-		} else if (sector_size == 2048) {
+			break;
+		case 2048:
 			error_sector <<= 2;
 			if (block_sectors < 4)
 				block_sectors = 4;
-		} else if (sector_size == 256)
+			break;
+		case 256:
 			error_sector >>= 1;
-		error_sector -= sd[SD_PARTITION(SCpnt->request.rq_dev)].start_sect;
+			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;
 	}
 	/*
-	 * First case : we assume that the command succeeded.  One of two things
-	 * will happen here.  Either we will be finished, or there will be more
-	 * sectors that we were unable to read last time.
+	 * 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.
 	 */
-
-	if (good_sectors > 0) {
-
-		SCSI_LOG_HLCOMPLETE(1, printk("%s : %ld sectors remain.\n", nbuff,
-					      SCpnt->request.nr_sectors));
-		SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n ", SCpnt->use_sg));
-
-		if (SCpnt->use_sg) {
-			struct scatterlist *sgpnt;
-			int i;
-			sgpnt = (struct scatterlist *) SCpnt->buffer;
-			for (i = 0; i < SCpnt->use_sg; i++) {
-
-#if 0
-				SCSI_LOG_HLCOMPLETE(3, printk(":%p %p %d\n", sgpnt[i].alt_address, sgpnt[i].address,
-						       sgpnt[i].length));
-#endif
-
-				if (sgpnt[i].alt_address) {
-					if (SCpnt->request.cmd == READ)
-						memcpy(sgpnt[i].alt_address, sgpnt[i].address,
-						       sgpnt[i].length);
-					scsi_free(sgpnt[i].address, sgpnt[i].length);
-				}
-			}
-
-			/* Free list of scatter-gather pointers */
-			scsi_free(SCpnt->buffer, SCpnt->sglist_len);
-		} else {
-			if (SCpnt->buffer != SCpnt->request.buffer) {
-				SCSI_LOG_HLCOMPLETE(3, printk("nosg: %p %p %d\n",
-				    SCpnt->request.buffer, SCpnt->buffer,
-							SCpnt->bufflen));
-
-				if (SCpnt->request.cmd == READ)
-					memcpy(SCpnt->request.buffer, SCpnt->buffer,
-					       SCpnt->bufflen);
-				scsi_free(SCpnt->buffer, SCpnt->bufflen);
-			}
-		}
-		/*
-		 * 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.
-		 */
-		if (SCpnt->request.nr_sectors > this_count) {
-			SCpnt->request.errors = 0;
-
-			if (!SCpnt->request.bh) {
-				SCSI_LOG_HLCOMPLETE(2, printk("%s : handling page request, no buffer\n",
-							      nbuff));
-
-				/*
-				 * The SCpnt->request.nr_sectors field is always done in
-				 * 512 byte sectors, even if this really isn't the case.
-				 */
-				panic("sd.c: linked page request (%lx %x)",
-				      SCpnt->request.sector, this_count);
-			}
-		}
-		SCpnt = end_scsi_request(SCpnt, 1, good_sectors);
-		if (result == 0) {
-			requeue_sd_request(SCpnt);
-			return;
-		}
-	}
-	if (good_sectors == 0) {
-
-		/* Free up any indirection buffers we allocated for DMA purposes. */
-		if (SCpnt->use_sg) {
-			struct scatterlist *sgpnt;
-			int i;
-			sgpnt = (struct scatterlist *) SCpnt->buffer;
-			for (i = 0; i < SCpnt->use_sg; i++) {
-				SCSI_LOG_HLCOMPLETE(3, printk("err: %p %p %d\n",
-				    SCpnt->request.buffer, SCpnt->buffer,
-							SCpnt->bufflen));
-				if (sgpnt[i].alt_address) {
-					scsi_free(sgpnt[i].address, sgpnt[i].length);
-				}
-			}
-			scsi_free(SCpnt->buffer, SCpnt->sglist_len);	/* Free list of scatter-gather pointers */
-		} else {
-			SCSI_LOG_HLCOMPLETE(2, printk("nosgerr: %p %p %d\n",
-				    SCpnt->request.buffer, SCpnt->buffer,
-						      SCpnt->bufflen));
-			if (SCpnt->buffer != SCpnt->request.buffer)
-				scsi_free(SCpnt->buffer, SCpnt->bufflen);
-		}
-	}
-	/*
-	 * 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 rscsi_disks
-				[DEVICE_NR(SCpnt->request.rq_dev)].remap
-			{
-				result = 0;
-			}
-#endif
-		}
-		if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) {
-			if ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) {
-				if (rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->removable) {
-					/* detected disc change.  set a bit and quietly refuse
-					 * further access.
-					 */
-					rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->changed = 1;
-					SCpnt = end_scsi_request(SCpnt, 0, this_count);
-					requeue_sd_request(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.
-					 */
-					requeue_sd_request(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.
-		 */
-
-		if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) {
-			if (rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].ten) {
-				rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].ten = 0;
-				requeue_sd_request(SCpnt);
-				result = 0;
-			} else {
-				/* ???? */
-			}
-		}
-		if (SCpnt->sense_buffer[2] == MEDIUM_ERROR) {
-			printk("scsi%d: MEDIUM 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 = end_scsi_request(SCpnt, 0, block_sectors);
-			requeue_sd_request(SCpnt);
-			return;
-		}
-	}			/* driver byte != 0 */
-	if (result) {
-		printk("SCSI disk error : host %d channel %d id %d lun %d return code = %x\n",
-		       rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->host->host_no,
-		       rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->channel,
-		rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->id,
-		       rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->lun, result);
-
-		if (driver_byte(result) & DRIVER_SENSE)
-			print_sense("sd", SCpnt);
-		SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors);
-		requeue_sd_request(SCpnt);
-		return;
-	}
+	scsi_io_completion(SCpnt, good_sectors, block_sectors);
 }
 /*
  * requeue_sd_request() is the request handler function for the sd driver.
@@ -507,532 +503,6 @@
  * them to SCSI commands.
  */
 
-static void do_sd_request(void)
-{
-	Scsi_Cmnd *SCpnt = NULL;
-	Scsi_Device *SDev;
-	struct request *req = NULL;
-	int flag = 0;
-
-	while (1 == 1) {
-		if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) {
-			return;
-		}
-		INIT_SCSI_REQUEST;
-		SDev = rscsi_disks[CURRENT_DEV].device;
-
-		/*
-		 * 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.
-		 */
-		if (SDev->host->in_recovery) {
-			return;
-		}
-		/*
-		 * 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.
-		 */
-		if (SDev->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.  FIXME(eric) - do this
-			 * from the kernel error handling thred.
-			 */
-			if (SDev->removable && !in_interrupt()) {
-				spin_unlock_irq(&io_request_lock);	/* FIXME!!!! */
-				scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0);
-				/* scsi_ioctl may allow CURRENT to change, so start over. */
-				SDev->was_reset = 0;
-				spin_lock_irq(&io_request_lock);	/* FIXME!!!! */
-				continue;
-			}
-			SDev->was_reset = 0;
-		}
-		/* We have to be careful here. scsi_allocate_device will get a free pointer,
-		 * but there is no guarantee that it is queueable.  In normal usage,
-		 * we want to call this, because other types of devices may have the
-		 * host all tied up, and we want to make sure that we have at least
-		 * one request pending for this type of device. We can also come
-		 * through here while servicing an interrupt, because of the need to
-		 * start another command. If we call scsi_allocate_device more than once,
-		 * then the system can wedge if the command is not queueable. The
-		 * scsi_request_queueable function is safe because it checks to make sure
-		 * that the host is able to take another command before it returns
-		 * a pointer.
-		 */
-
-		if (flag++ == 0)
-			SCpnt = scsi_allocate_device(&CURRENT,
-				     rscsi_disks[CURRENT_DEV].device, 0);
-		else
-			SCpnt = NULL;
-
-		/*
-		 * The following restore_flags leads to latency problems.  FIXME.
-		 * Using a "sti()" gets rid of the latency problems but causes
-		 * race conditions and crashes.
-		 */
-
-		/* This is a performance enhancement. We dig down into the request
-		 * list and try to find a queueable request (i.e. device not busy,
-		 * and host able to accept another command. If we find one, then we
-		 * queue it. This can make a big difference on systems with more than
-		 * one disk drive.  We want to have the interrupts off when monkeying
-		 * with the request list, because otherwise the kernel might try to
-		 * slip in a request in between somewhere.
-		 *
-		 * FIXME(eric) - this doesn't belong at this level.  The device code in
-		 * ll_rw_blk.c should know how to dig down into the device queue to
-		 * figure out what it can deal with, and what it can't.  Consider
-		 * possibility of pulling entire queue down into scsi layer.
-		 */
-		if (!SCpnt && sd_template.nr_dev > 1) {
-			struct request *req1;
-			req1 = NULL;
-			req = CURRENT;
-			while (req) {
-				SCpnt = scsi_request_queueable(req,
-							       rscsi_disks[DEVICE_NR(req->rq_dev)].device);
-				if (SCpnt)
-					break;
-				req1 = req;
-				req = req->next;
-			}
-			if (SCpnt && req->rq_status == RQ_INACTIVE) {
-				if (req == CURRENT)
-					CURRENT = CURRENT->next;
-				else
-					req1->next = req->next;
-			}
-		}
-		if (!SCpnt)
-			return;	/* Could not find anything to do */
-
-		/* Queue command */
-		requeue_sd_request(SCpnt);
-	}			/* While */
-}
-
-static void requeue_sd_request(Scsi_Cmnd * SCpnt)
-{
-	int dev, devm, block, this_count;
-	unsigned char cmd[10];
-	char nbuff[6];
-	int bounce_size, contiguous;
-	int max_sg;
-	struct buffer_head *bh, *bhp;
-	char *buff, *bounce_buffer;
-
-repeat:
-
-	if (!SCpnt || SCpnt->request.rq_status == RQ_INACTIVE) {
-		do_sd_request();
-		return;
-	}
-	devm = SD_PARTITION(SCpnt->request.rq_dev);
-	dev = DEVICE_NR(SCpnt->request.rq_dev);
-
-	block = SCpnt->request.sector;
-	this_count = 0;
-
-	SCSI_LOG_HLQUEUE(1, printk("Doing sd request, dev = %d, block = %d\n", devm, block));
-
-	if (devm >= (sd_template.dev_max << 4) ||
-	    !rscsi_disks[dev].device ||
-	    !rscsi_disks[dev].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 = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
-		SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt));
-		goto repeat;
-	}
-	block += sd[devm].start_sect;
-
-	if (rscsi_disks[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 = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
-		goto repeat;
-	}
-	sd_devname(devm >> 4, 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 (rscsi_disks[dev].sector_size == 1024)
-		if ((block & 1) || (SCpnt->request.nr_sectors & 1)) {
-			printk("sd.c:Bad block number/count requested");
-			SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
-			goto repeat;
-		}
-	if (rscsi_disks[dev].sector_size == 2048)
-		if ((block & 3) || (SCpnt->request.nr_sectors & 3)) {
-			printk("sd.c:Bad block number/count requested");
-			SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
-			goto repeat;
-		}
-	if (rscsi_disks[dev].sector_size == 4096)
-		if ((block & 7) || (SCpnt->request.nr_sectors & 7)) {
-			printk("sd.cBad block number/count requested");
-			SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
-			goto repeat;
-		}
-	switch (SCpnt->request.cmd) {
-	case WRITE:
-		if (!rscsi_disks[dev].device->writeable) {
-			SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
-			goto repeat;
-		}
-		cmd[0] = WRITE_6;
-		break;
-	case READ:
-		cmd[0] = READ_6;
-		break;
-	default:
-		panic("Unknown sd command %d\n", SCpnt->request.cmd);
-	}
-
-	SCpnt->this_count = 0;
-
-	/* If the host adapter can deal with very large scatter-gather
-	 * requests, it is a waste of time to cluster
-	 */
-	contiguous = (!CLUSTERABLE_DEVICE(SCpnt) ? 0 : 1);
-	bounce_buffer = NULL;
-	bounce_size = (SCpnt->request.nr_sectors << 9);
-
-	/* First see if we need a bounce buffer for this request. If we do, make
-	 * sure that we can allocate a buffer. Do not waste space by allocating
-	 * a bounce buffer if we are straddling the 16Mb line
-	 */
-	if (contiguous && SCpnt->request.bh &&
-	    virt_to_phys(SCpnt->request.bh->b_data)
-	    + (SCpnt->request.nr_sectors << 9) - 1 > ISA_DMA_THRESHOLD
-	    && SCpnt->host->unchecked_isa_dma) {
-		if (virt_to_phys(SCpnt->request.bh->b_data) > ISA_DMA_THRESHOLD)
-			bounce_buffer = (char *) scsi_malloc(bounce_size);
-		if (!bounce_buffer)
-			contiguous = 0;
-	}
-	if (contiguous && SCpnt->request.bh && SCpnt->request.bh->b_reqnext)
-		for (bh = SCpnt->request.bh, bhp = bh->b_reqnext; bhp; bh = bhp,
-		     bhp = bhp->b_reqnext) {
-			if (!CONTIGUOUS_BUFFERS(bh, bhp)) {
-				if (bounce_buffer)
-					scsi_free(bounce_buffer, bounce_size);
-				contiguous = 0;
-				break;
-			}
-		}
-	if (!SCpnt->request.bh || contiguous) {
-
-		/* case of page request (i.e. raw device), or unlinked buffer */
-		this_count = SCpnt->request.nr_sectors;
-		buff = SCpnt->request.buffer;
-		SCpnt->use_sg = 0;
-
-	} else if (SCpnt->host->sg_tablesize == 0 ||
-		 (scsi_need_isa_buffer && scsi_dma_free_sectors <= 10)) {
-
-		/* Case of host adapter that cannot scatter-gather.  We also
-		 * come here if we are running low on DMA buffer memory.  We set
-		 * a threshold higher than that we would need for this request so
-		 * we leave room for other requests.  Even though we would not need
-		 * it all, we need to be conservative, because if we run low enough
-		 * we have no choice but to panic.
-		 */
-		if (SCpnt->host->sg_tablesize != 0 &&
-		    scsi_need_isa_buffer &&
-		    scsi_dma_free_sectors <= 10)
-			printk("Warning: SCSI DMA buffer space running low.  Using non scatter-gather I/O.\n");
-
-		this_count = SCpnt->request.current_nr_sectors;
-		buff = SCpnt->request.buffer;
-		SCpnt->use_sg = 0;
-
-	} else {
-
-		/* Scatter-gather capable host adapter */
-		struct scatterlist *sgpnt;
-		int count, this_count_max;
-		int counted;
-
-		bh = SCpnt->request.bh;
-		this_count = 0;
-		this_count_max = (rscsi_disks[dev].ten ? 0xffff : 0xff);
-		count = 0;
-		bhp = NULL;
-		while (bh) {
-			if ((this_count + (bh->b_size >> 9)) > this_count_max)
-				break;
-			if (!bhp || !CONTIGUOUS_BUFFERS(bhp, bh) ||
-			    !CLUSTERABLE_DEVICE(SCpnt) ||
-			    (SCpnt->host->unchecked_isa_dma &&
-			     virt_to_phys(bh->b_data - 1) == ISA_DMA_THRESHOLD)) {
-				if (count < SCpnt->host->sg_tablesize)
-					count++;
-				else
-					break;
-			}
-			this_count += (bh->b_size >> 9);
-			bhp = bh;
-			bh = bh->b_reqnext;
-		}
-#if 0
-		if (SCpnt->host->unchecked_isa_dma &&
-		    virt_to_phys(SCpnt->request.bh->b_data - 1) == ISA_DMA_THRESHOLD)
-			count--;
-#endif
-		SCpnt->use_sg = count;	/* Number of chains */
-		/* scsi_malloc can only allocate in chunks of 512 bytes */
-		count = (SCpnt->use_sg * sizeof(struct scatterlist) + 511) & ~511;
-
-		SCpnt->sglist_len = count;
-		max_sg = count / sizeof(struct scatterlist);
-		if (SCpnt->host->sg_tablesize < max_sg)
-			max_sg = SCpnt->host->sg_tablesize;
-		sgpnt = (struct scatterlist *) scsi_malloc(count);
-		if (!sgpnt) {
-			printk("Warning - running *really* short on DMA buffers\n");
-			SCpnt->use_sg = 0;	/* No memory left - bail out */
-			this_count = SCpnt->request.current_nr_sectors;
-			buff = SCpnt->request.buffer;
-		} else {
-			memset(sgpnt, 0, count);	/* Zero so it is easy to fill, but only
-							 * if memory is available
-							 */
-			buff = (char *) sgpnt;
-			counted = 0;
-			for (count = 0, bh = SCpnt->request.bh, bhp = bh->b_reqnext;
-			     count < SCpnt->use_sg && bh;
-			     count++, bh = bhp) {
-
-				bhp = bh->b_reqnext;
-
-				if (!sgpnt[count].address)
-					sgpnt[count].address = bh->b_data;
-				sgpnt[count].length += bh->b_size;
-				counted += bh->b_size >> 9;
-
-				if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length - 1 >
-				    ISA_DMA_THRESHOLD && (SCpnt->host->unchecked_isa_dma) &&
-				    !sgpnt[count].alt_address) {
-					sgpnt[count].alt_address = sgpnt[count].address;
-					/* We try to avoid exhausting the DMA pool, since it is
-					 * easier to control usage here. In other places we might
-					 * have a more pressing need, and we would be screwed if
-					 * we ran out */
-					if (scsi_dma_free_sectors < (sgpnt[count].length >> 9) + 10) {
-						sgpnt[count].address = NULL;
-					} else {
-						sgpnt[count].address =
-						    (char *) scsi_malloc(sgpnt[count].length);
-					}
-					/* If we start running low on DMA buffers, we abort the
-					 * scatter-gather operation, and free all of the memory
-					 * we have allocated.  We want to ensure that all scsi
-					 * operations are able to do at least a non-scatter/gather
-					 * operation */
-					if (sgpnt[count].address == NULL) {	/* Out of dma memory */
-#if 0
-						printk("Warning: Running low on SCSI DMA buffers");
-						/* Try switching back to a non s-g operation. */
-						while (--count >= 0) {
-							if (sgpnt[count].alt_address)
-								scsi_free(sgpnt[count].address,
-									  sgpnt[count].length);
-						}
-						this_count = SCpnt->request.current_nr_sectors;
-						buff = SCpnt->request.buffer;
-						SCpnt->use_sg = 0;
-						scsi_free(sgpnt, SCpnt->sglist_len);
-#endif
-						SCpnt->use_sg = count;
-						this_count = counted -= bh->b_size >> 9;
-						break;
-					}
-				}
-				/* Only cluster buffers if we know that we can supply DMA
-				 * buffers large enough to satisfy the request. Do not cluster
-				 * a new request if this would mean that we suddenly need to
-				 * start using DMA bounce buffers */
-				if (bhp && CONTIGUOUS_BUFFERS(bh, bhp)
-				    && CLUSTERABLE_DEVICE(SCpnt)) {
-					char *tmp;
-
-					if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length +
-					    bhp->b_size - 1 > ISA_DMA_THRESHOLD &&
-					    (SCpnt->host->unchecked_isa_dma) &&
-					    !sgpnt[count].alt_address)
-						continue;
-
-					if (!sgpnt[count].alt_address) {
-						count--;
-						continue;
-					}
-					if (scsi_dma_free_sectors > 10)
-						tmp = (char *) scsi_malloc(sgpnt[count].length
-							  + bhp->b_size);
-					else {
-						tmp = NULL;
-						max_sg = SCpnt->use_sg;
-					}
-					if (tmp) {
-						scsi_free(sgpnt[count].address, sgpnt[count].length);
-						sgpnt[count].address = tmp;
-						count--;
-						continue;
-					}
-					/* If we are allowed another sg chain, then increment
-					 * counter so we can insert it.  Otherwise we will end
-					 up truncating */
-
-					if (SCpnt->use_sg < max_sg)
-						SCpnt->use_sg++;
-				}	/* contiguous buffers */
-			}	/* for loop */
-
-			/* This is actually how many we are going to transfer */
-			this_count = counted;
-
-			if (count < SCpnt->use_sg || SCpnt->use_sg
-			    > SCpnt->host->sg_tablesize) {
-				bh = SCpnt->request.bh;
-				printk("Use sg, count %d %x %d\n",
-				       SCpnt->use_sg, count, scsi_dma_free_sectors);
-				printk("maxsg = %x, counted = %d this_count = %d\n",
-				       max_sg, counted, this_count);
-				while (bh) {
-					printk("[%p %x] ", bh->b_data, bh->b_size);
-					bh = bh->b_reqnext;
-				}
-				if (SCpnt->use_sg < 16)
-					for (count = 0; count < SCpnt->use_sg; count++)
-						printk("{%d:%p %p %d}  ", count,
-						    sgpnt[count].address,
-						sgpnt[count].alt_address,
-						    sgpnt[count].length);
-				panic("Ooops");
-			}
-			if (SCpnt->request.cmd == WRITE)
-				for (count = 0; count < SCpnt->use_sg; count++)
-					if (sgpnt[count].alt_address)
-						memcpy(sgpnt[count].address, sgpnt[count].alt_address,
-						    sgpnt[count].length);
-		}		/* Able to malloc sgpnt */
-	}			/* Host adapter capable of scatter-gather */
-
-	/* Now handle the possibility of DMA to addresses > 16Mb */
-
-	if (SCpnt->use_sg == 0) {
-		if (virt_to_phys(buff) + (this_count << 9) - 1 > ISA_DMA_THRESHOLD &&
-		    (SCpnt->host->unchecked_isa_dma)) {
-			if (bounce_buffer)
-				buff = bounce_buffer;
-			else
-				buff = (char *) scsi_malloc(this_count << 9);
-			if (buff == NULL) {	/* Try backing off a bit if we are low on mem */
-				this_count = SCpnt->request.current_nr_sectors;
-				buff = (char *) scsi_malloc(this_count << 9);
-				if (!buff)
-					panic("Ran out of DMA buffers.");
-			}
-			if (SCpnt->request.cmd == WRITE)
-				memcpy(buff, (char *) SCpnt->request.buffer, this_count << 9);
-		}
-	}
-	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));
-
-	cmd[1] = (SCpnt->lun << 5) & 0xe0;
-
-	if (rscsi_disks[dev].sector_size == 4096) {
-		if (block & 7)
-			panic("sd.c:Bad block number requested");
-		if (this_count & 7)
-			panic("sd.c:Bad block number requested");
-		block = block >> 3;
-		this_count = block >> 3;
-	}
-	if (rscsi_disks[dev].sector_size == 2048) {
-		if (block & 3)
-			panic("sd.c:Bad block number requested");
-		if (this_count & 3)
-			panic("sd.c:Bad block number requested");
-		block = block >> 2;
-		this_count = this_count >> 2;
-	}
-	if (rscsi_disks[dev].sector_size == 1024) {
-		if (block & 1)
-			panic("sd.c:Bad block number requested");
-		if (this_count & 1)
-			panic("sd.c:Bad block number requested");
-		block = block >> 1;
-		this_count = this_count >> 1;
-	}
-	if (rscsi_disks[dev].sector_size == 256) {
-		block = block << 1;
-		this_count = this_count << 1;
-	}
-	if (((this_count > 0xff) || (block > 0x1fffff)) && rscsi_disks[dev].ten) {
-		if (this_count > 0xffff)
-			this_count = 0xffff;
-
-		cmd[0] += READ_10 - READ_6;
-		cmd[2] = (unsigned char) (block >> 24) & 0xff;
-		cmd[3] = (unsigned char) (block >> 16) & 0xff;
-		cmd[4] = (unsigned char) (block >> 8) & 0xff;
-		cmd[5] = (unsigned char) block & 0xff;
-		cmd[6] = cmd[9] = 0;
-		cmd[7] = (unsigned char) (this_count >> 8) & 0xff;
-		cmd[8] = (unsigned char) this_count & 0xff;
-	} else {
-		if (this_count > 0xff)
-			this_count = 0xff;
-
-		cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
-		cmd[2] = (unsigned char) ((block >> 8) & 0xff);
-		cmd[3] = (unsigned char) block & 0xff;
-		cmd[4] = (unsigned char) this_count;
-		cmd[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 = rscsi_disks[dev].sector_size;
-	SCpnt->underflow = this_count << 9;
-	SCpnt->cmd_len = 0;
-	scsi_do_cmd(SCpnt, (void *) cmd, buff,
-		    this_count * rscsi_disks[dev].sector_size,
-		    rw_intr,
-		    (SCpnt->device->type == TYPE_DISK ?
-		     SD_TIMEOUT : SD_MOD_TIMEOUT),
-		    MAX_RETRIES);
-}
 
 static int check_scsidisk_media_change(kdev_t full_dev)
 {
@@ -1097,19 +567,17 @@
 	return retval;
 }
 
-static void sd_wait_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
-		  void *buffer, unsigned bufflen, void (*done)(Scsi_Cmnd *),
-		  int timeout, int retries)
+static void sd_wait_cmd(Scsi_Cmnd * SCpnt, const void *cmnd,
+	      void *buffer, unsigned bufflen, void (*done) (Scsi_Cmnd *),
+			int timeout, int retries)
 {
 	DECLARE_MUTEX_LOCKED(sem);
-	
+
 	SCpnt->request.sem = &sem;
 	SCpnt->request.rq_status = RQ_SCSI_BUSY;
-	scsi_do_cmd (SCpnt, (void *) cmnd,
-        	buffer, bufflen, done, timeout, retries);
-	spin_unlock_irq(&io_request_lock);
-	down (&sem);
-	spin_lock_irq(&io_request_lock);
+	scsi_do_cmd(SCpnt, (void *) cmnd,
+		    buffer, bufflen, done, timeout, retries);
+	down(&sem);
 	SCpnt->request.sem = NULL;
 }
 
@@ -1131,6 +599,7 @@
 	unsigned char *buffer;
 	unsigned long spintime_value = 0;
 	int the_result, retries, spintime;
+	int sector_size;
 	Scsi_Cmnd *SCpnt;
 
 	/*
@@ -1145,14 +614,13 @@
 	if (rscsi_disks[i].device->online == FALSE) {
 		return i;
 	}
-	spin_lock_irq(&io_request_lock);
-
 	/* 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.
 	 */
 
-	SCpnt = scsi_allocate_device(NULL, rscsi_disks[i].device, 1);
+	SCpnt = scsi_allocate_device(rscsi_disks[i].device, 1);
+
 	buffer = (unsigned char *) scsi_malloc(512);
 
 	spintime = 0;
@@ -1161,7 +629,7 @@
 	/* Spinup needs to be done for module loads too. */
 	do {
 		retries = 0;
-		
+
 		while (retries < 3) {
 			cmd[0] = TEST_UNIT_READY;
 			cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
@@ -1170,8 +638,8 @@
 			SCpnt->sense_buffer[0] = 0;
 			SCpnt->sense_buffer[2] = 0;
 
-			sd_wait_cmd (SCpnt, (void *) cmd, (void *) buffer,
-				512, sd_init_done,  SD_TIMEOUT, MAX_RETRIES);
+			sd_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
+			     512, sd_init_done, SD_TIMEOUT, MAX_RETRIES);
 
 			the_result = SCpnt->result;
 			retries++;
@@ -1183,11 +651,9 @@
 		/* Look for non-removable devices that return NOT_READY.
 		 * Issue command to spin up drive for these cases. */
 		if (the_result && !rscsi_disks[i].device->removable &&
-		    SCpnt->sense_buffer[2] == NOT_READY) 
-		{
+		    SCpnt->sense_buffer[2] == NOT_READY) {
 			unsigned long time1;
-			if (!spintime) 
-			{
+			if (!spintime) {
 				printk("%s: Spinning up disk...", nbuff);
 				cmd[0] = START_STOP;
 				cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
@@ -1199,19 +665,15 @@
 				SCpnt->sense_buffer[2] = 0;
 
 				sd_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
-					512, sd_init_done, SD_TIMEOUT, MAX_RETRIES);
+					    512, sd_init_done, SD_TIMEOUT, MAX_RETRIES);
 			}
-
 			spintime = 1;
 			spintime_value = jiffies;
 			time1 = jiffies + HZ;
-			spin_unlock_irq(&io_request_lock);
-			while(time_before(jiffies, time1)); /* Wait 1 second for next try */
+			while (time_before(jiffies, time1));	/* Wait 1 second for next try */
 			printk(".");
-			spin_lock_irq(&io_request_lock);
 		}
-	} while(the_result && spintime && time_after(spintime_value+100*HZ, jiffies));
-
+	} while (the_result && spintime && time_after(spintime_value + 100 * HZ, jiffies));
 	if (spintime) {
 		if (the_result)
 			printk("not responding...\n");
@@ -1229,7 +691,7 @@
 		SCpnt->sense_buffer[2] = 0;
 
 		sd_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
-			8, sd_init_done, SD_TIMEOUT, MAX_RETRIES);
+			    8, sd_init_done, SD_TIMEOUT, MAX_RETRIES);
 
 		the_result = SCpnt->result;
 		retries--;
@@ -1268,7 +730,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. */
@@ -1287,38 +749,29 @@
 					       (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);
-			if (rscsi_disks[i].device->removable) {
-				rscsi_disks[i].capacity = 0;
-			} else {
-				printk("scsi : deleting disk entry.\n");
-				sd_detach(rscsi_disks[i].device);
-				rscsi_disks[i].device = NULL;
-
-				/* Wake up a process waiting for device */
-				wake_up(&SCpnt->device->device_wait);
-				scsi_release_command(SCpnt);
-				SCpnt = NULL;
-				scsi_free(buffer, 512);
-				spin_unlock_irq(&io_request_lock);
-
-				return i;
-			}
+			       nbuff, sector_size);
+			/*
+			 * 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;
 		}
-		if (rscsi_disks[i].sector_size == 2048) {
+		if (sector_size == 2048) {
 			int m;
 
 			/*
@@ -1338,7 +791,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;
@@ -1353,13 +806,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 */
 	}
 
@@ -1389,7 +842,7 @@
 
 		/* same code as READCAPA !! */
 		sd_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
-				512, sd_init_done, SD_TIMEOUT, MAX_RETRIES);
+			    512, sd_init_done, SD_TIMEOUT, MAX_RETRIES);
 
 		the_result = SCpnt->result;
 
@@ -1403,15 +856,15 @@
 		}
 
 	}			/* check for write protect */
+	SCpnt->device->ten = 1;
+	SCpnt->device->remap = 1;
+	SCpnt->device->sector_size = sector_size;
 	/* 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);
-	spin_unlock_irq(&io_request_lock);
 	return i;
 }
 
@@ -1496,23 +949,14 @@
 	return 0;
 }
 
-/*
- * sd_get_queue() returns the queue which corresponds to a given device.
- */
-static struct request **sd_get_queue(kdev_t dev)
-{
-	return &blk_dev[MAJOR_NR].current_request;
-}
+
 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;
-		if (i)
-			blk_dev[SD_MAJOR(i)].queue = sd_get_queue;
+		blk_dev[SD_MAJOR(i)].queue = sd_find_queue;
 	}
 	for (gendisk = gendisk_head; gendisk != NULL; gendisk = gendisk->next)
 		if (gendisk == sd_gendisks)
@@ -1582,7 +1026,6 @@
 	if (i >= sd_template.dev_max)
 		panic("scsi_devices corrupt (sd)");
 
-	SDp->scsi_request_fn = do_sd_request;
 	rscsi_disks[i].device = SDp;
 	rscsi_disks[i].has_part_table = 0;
 	sd_template.nr_dev++;
@@ -1637,7 +1080,7 @@
 		 * to make sure that everything remains consistent.
 		 */
 		sd_blocksizes[index] = 1024;
-		if (rscsi_disks[target].sector_size == 2048)
+		if (rscsi_disks[target].device->sector_size == 2048)
 			sd_blocksizes[index] = 2048;
 		else
 			sd_blocksizes[index] = 1024;
@@ -1748,7 +1191,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	Wed Oct 20 16:36:45 1999
+++ linux.new2/drivers/scsi/sd.h	Sun Nov 14 09:25:47 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,11 @@
 
 typedef struct scsi_disk {
 	unsigned capacity;	/* size in blocks */
-	unsigned sector_size;	/* size in bytes */
 	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 */
-	unsigned ten:1;		/* support ten byte read / write */
-	unsigned remap:1;	/* support remapping  */
 	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	Sun Oct 17 15:43:53 1999
+++ linux.new2/drivers/scsi/sg.c	Sun Nov 14 09:22:55 1999
@@ -355,7 +355,6 @@
 static ssize_t sg_write(struct file * filp, const char * buf, 
                         size_t count, loff_t *ppos)
 {
-    unsigned long         flags;
     int                   mxsize, cmd_size, k;
     unsigned char         cmnd[MAX_COMMAND_SIZE];
     int                   input_size;
@@ -432,8 +431,9 @@
         return k;    /* probably out of space --> ENOMEM */
     }
 /*  SCSI_LOG_TIMEOUT(7, printk("sg_write: allocating device\n")); */
-    if (! (SCpnt = scsi_allocate_device(NULL, sdp->device, 
-                                        !(filp->f_flags & O_NONBLOCK)))) {
+    if (! (SCpnt = scsi_allocate_device(sdp->device, 
+                                        !(filp->f_flags & O_NONBLOCK)))) 
+    {
         sg_finish_rem_req(srp, NULL, 0);
         return -EAGAIN;   /* No available command blocks at the moment */
     }
@@ -448,7 +448,6 @@
     cmnd[1]= (cmnd[1] & 0x1f) | (sdp->device->lun << 5);
 
 /*  SCSI_LOG_TIMEOUT(7, printk("sg_write: do cmd\n")); */
-    spin_lock_irqsave(&io_request_lock, flags);
     SCpnt->use_sg = srp->data.use_sg;
     SCpnt->sglist_len = srp->data.sglist_len;
     SCpnt->bufflen = srp->data.bufflen;
@@ -467,7 +466,6 @@
                 (void *)SCpnt->buffer, mxsize,
                 sg_command_done, sfp->timeout, SG_DEFAULT_RETRIES);
     /* 'mxsize' overwrites SCpnt->bufflen, hence need for b_malloc_len */
-    spin_unlock_irqrestore(&io_request_lock, flags);
 /*  SCSI_LOG_TIMEOUT(6, printk("sg_write: sent scsi cmd to mid-level\n")); */
     return count;
 }
@@ -1116,7 +1114,9 @@
         scsi_add_timer(scpnt, scpnt->timeout_per_command,
                        scsi_old_times_out);
 #else
+    spin_unlock_irq(&io_request_lock);
     scsi_sleep(HZ); /* just sleep 1 second and hope ... */
+    spin_lock_irq(&io_request_lock);
 #endif
 }
 
diff -u -r linux.clean/drivers/scsi/sr.c linux.new2/drivers/scsi/sr.c
--- linux.clean/drivers/scsi/sr.c	Sun Nov  7 16:35:21 1999
+++ linux.new2/drivers/scsi/sr.c	Sun Nov 14 10:16:49 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
@@ -60,11 +60,21 @@
 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
+static int sr_init_command(Scsi_Cmnd *);
+
+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,
+	init_command:sr_init_command
 };
 
 Scsi_CD *scsi_CDs = NULL;
@@ -82,7 +92,7 @@
 
 static void sr_release(struct cdrom_device_info *cdi)
 {
-	if (scsi_CDs[MINOR(cdi->dev)].sector_size > 2048)
+	if (scsi_CDs[MINOR(cdi->dev)].device->sector_size > 2048)
 		sr_set_blocklength(MINOR(cdi->dev), 2048);
 	sync_dev(cdi->dev);
 	scsi_CDs[MINOR(cdi->dev)].device->access_count--;
@@ -108,7 +118,7 @@
 	sr_audio_ioctl,		/* audio ioctl */
 	sr_dev_ioctl,		/* device-specific ioctl */
 	CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED |
-	CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED |
+      CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED |
 	CDC_PLAY_AUDIO | CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS |
 	CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM |
 	CDC_GENERIC_PACKET,
@@ -165,7 +175,7 @@
 		 */
 		scsi_CDs[MINOR(cdi->dev)].needs_sector_size = 1;
 
-		scsi_CDs[MINOR(cdi->dev)].sector_size = 2048;
+		scsi_CDs[MINOR(cdi->dev)].device->sector_size = 2048;
 	}
 	return retval;
 }
@@ -191,6 +201,7 @@
 	   avoid unnecessary additional work such as memcpy's that could be avoided.
 	 */
 
+
 	if (driver_byte(result) != 0 &&		/* An error occurred */
 	    SCpnt->sense_buffer[0] == 0xF0 &&	/* Sense data is valid */
 	    (SCpnt->sense_buffer[2] == MEDIUM_ERROR ||
@@ -205,177 +216,177 @@
 			block_sectors = SCpnt->request.bh->b_size >> 9;
 		if (block_sectors < 4)
 			block_sectors = 4;
-		if (scsi_CDs[device_nr].sector_size == 2048)
+		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.
+		 * 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;
 	}
-	if (good_sectors > 0) {	/* Some sectors were read successfully. */
-		if (SCpnt->use_sg == 0) {
-			if (SCpnt->buffer != SCpnt->request.buffer) {
-				int offset;
-				offset = (SCpnt->request.sector % 4) << 9;
-				memcpy((char *) SCpnt->request.buffer,
-				       (char *) SCpnt->buffer + offset,
-				       good_sectors << 9);
-				/* Even though we are not using scatter-gather, we look
-				 * ahead and see if there is a linked request for the
-				 * other half of this buffer.  If there is, then satisfy
-				 * it. */
-				if ((offset == 0) && good_sectors == 2 &&
-				    SCpnt->request.nr_sectors > good_sectors &&
-				    SCpnt->request.bh &&
-				    SCpnt->request.bh->b_reqnext &&
-				    SCpnt->request.bh->b_reqnext->b_size == 1024) {
-					memcpy((char *) SCpnt->request.bh->b_reqnext->b_data,
-					   (char *) SCpnt->buffer + 1024,
-					       1024);
-					good_sectors += 2;
-				};
+	/*
+	 * 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);
+}
 
-				scsi_free(SCpnt->buffer, 2048);
-			}
-		} else {
-			struct scatterlist *sgpnt;
-			int i;
-			sgpnt = (struct scatterlist *) SCpnt->buffer;
-			for (i = 0; i < SCpnt->use_sg; i++) {
-				if (sgpnt[i].alt_address) {
-					if (sgpnt[i].alt_address != sgpnt[i].address) {
-						memcpy(sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
-					};
-					scsi_free(sgpnt[i].address, sgpnt[i].length);
-				};
-			};
-			scsi_free(SCpnt->buffer, SCpnt->sglist_len);	/* Free list of scatter-gather pointers */
-			if (SCpnt->request.sector % 4)
-				good_sectors -= 2;
-			/* See   if there is a padding record at the end that needs to be removed */
-			if (good_sectors > SCpnt->request.nr_sectors)
-				good_sectors -= 2;
-		};
 
-#ifdef DEBUG
-		printk("(%x %x %x) ", SCpnt->request.bh, SCpnt->request.nr_sectors,
-		       good_sectors);
-#endif
-		if (SCpnt->request.nr_sectors > this_count) {
-			SCpnt->request.errors = 0;
-			if (!SCpnt->request.bh)
-				panic("sr.c: linked page request (%lx %x)",
-				      SCpnt->request.sector, this_count);
-		}
-		SCpnt = end_scsi_request(SCpnt, 1, good_sectors);	/* All done */
-		if (result == 0) {
-			requeue_sr_request(SCpnt);
-			return;
-		}
-	}
-	if (good_sectors == 0) {
-		/* We only come through here if no sectors were read successfully. */
+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;
+}
 
-		/* Free up any indirection buffers we allocated for DMA purposes. */
-		if (SCpnt->use_sg) {
-			struct scatterlist *sgpnt;
-			int i;
-			sgpnt = (struct scatterlist *) SCpnt->buffer;
-			for (i = 0; i < SCpnt->use_sg; i++) {
-				if (sgpnt[i].alt_address) {
-					scsi_free(sgpnt[i].address, sgpnt[i].length);
-				}
-			}
-			scsi_free(SCpnt->buffer, SCpnt->sglist_len);	/* Free list of scatter-gather pointers */
-		} else {
-			if (SCpnt->buffer != SCpnt->request.buffer)
-				scsi_free(SCpnt->buffer, SCpnt->bufflen);
-		}
+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;
 	}
-	if (driver_byte(result) != 0) {
-		if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) {
-			if ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) {
-				/* detected disc change.  set a bit and quietly refuse
-				 * further access.    */
-
-				scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->changed = 1;
-				SCpnt = end_scsi_request(SCpnt, 0, this_count);
-				requeue_sr_request(SCpnt);
-				return;
-			}
-		}
-		if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) {
-			printk("sr%d: CD-ROM error: ",
-			       DEVICE_NR(SCpnt->request.rq_dev));
-			print_sense("sr", SCpnt);
-			printk("command was: ");
-			print_command(SCpnt->cmnd);
-			if (scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].ten) {
-				scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].ten = 0;
-				requeue_sr_request(SCpnt);
-				result = 0;
-				return;
-			} else {
-				SCpnt = end_scsi_request(SCpnt, 0, this_count);
-				requeue_sr_request(SCpnt);	/* Do next request */
-				return;
-			}
+	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 (SCpnt->sense_buffer[2] == NOT_READY) {
-			printk(KERN_INFO "sr%d: CD-ROM not ready.  Make sure you have a disc in the drive.\n",
-			       DEVICE_NR(SCpnt->request.rq_dev));
-			SCpnt = end_scsi_request(SCpnt, 0, this_count);
-			requeue_sr_request(SCpnt);	/* Do next request */
-			return;
-		}
-		if (SCpnt->sense_buffer[2] == MEDIUM_ERROR) {
-			printk("scsi%d: MEDIUM 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("sr", SCpnt);
-			SCpnt = end_scsi_request(SCpnt, 0, block_sectors);
-			requeue_sr_request(SCpnt);
-			return;
+	}
+	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;
 		}
-		if (SCpnt->sense_buffer[2] == VOLUME_OVERFLOW) {
-			printk("scsi%d: VOLUME OVERFLOW 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("sr", SCpnt);
-			SCpnt = end_scsi_request(SCpnt, 0, block_sectors);
-			requeue_sr_request(SCpnt);
-			return;
+	}
+	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);
 	}
-	/* We only get this far if we have an error we have not recognized */
-	if (result) {
-		printk("SCSI CD error : host %d id %d lun %d return code = %03x\n",
-		       scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->host->host_no,
-		   scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->id,
-		  scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->lun,
-		       result);
 
-		if (status_byte(result) == CHECK_CONDITION)
-			print_sense("sr", SCpnt);
+	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 = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors);
-		requeue_sr_request(SCpnt);
+		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;
 }
 
 static int sr_open(struct cdrom_device_info *cdi, int purpose)
@@ -416,390 +427,6 @@
  * translate them to SCSI commands.
  */
 
-static void do_sr_request(void)
-{
-	Scsi_Cmnd *SCpnt = NULL;
-	struct request *req = NULL;
-	Scsi_Device *SDev;
-	int flag = 0;
-
-	while (1 == 1) {
-		if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) {
-			return;
-		};
-
-		INIT_SCSI_REQUEST;
-
-		SDev = scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device;
-
-		/*
-		 * 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.
-		 */
-		if (SDev->host->in_recovery) {
-			return;
-		}
-		/*
-		 * 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.
-		 */
-		if (SDev->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 (SDev->removable && !in_interrupt()) {
-				spin_unlock_irq(&io_request_lock);	/* FIXME!!!! */
-				scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0);
-				spin_lock_irq(&io_request_lock);	/* FIXME!!!! */
-				/* scsi_ioctl may allow CURRENT to change, so start over. */
-				SDev->was_reset = 0;
-				continue;
-			}
-			SDev->was_reset = 0;
-		}
-		/* we do lazy blocksize switching (when reading XA sectors,
-		 * see CDROMREADMODE2 ioctl) */
-		if (scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].sector_size > 2048) {
-			if (!in_interrupt())
-				sr_set_blocklength(DEVICE_NR(CURRENT->rq_dev), 2048);
-#if 1
-			else
-				printk("sr: can't switch blocksize: in interrupt\n");
-#endif
-		}
-		if (flag++ == 0)
-			SCpnt = scsi_allocate_device(&CURRENT,
-			 scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device, 0);
-		else
-			SCpnt = NULL;
-
-		/* This is a performance enhancement.  We dig down into the request list and
-		 * try to find a queueable request (i.e. device not busy, and host able to
-		 * accept another command.  If we find one, then we queue it. This can
-		 * make a big difference on systems with more than one disk drive.  We want
-		 * to have the interrupts off when monkeying with the request list, because
-		 * otherwise the kernel might try to slip in a request in between somewhere. */
-
-		if (!SCpnt && sr_template.nr_dev > 1) {
-			struct request *req1;
-			req1 = NULL;
-			req = CURRENT;
-			while (req) {
-				SCpnt = scsi_request_queueable(req,
-				scsi_CDs[DEVICE_NR(req->rq_dev)].device);
-				if (SCpnt)
-					break;
-				req1 = req;
-				req = req->next;
-			}
-			if (SCpnt && req->rq_status == RQ_INACTIVE) {
-				if (req == CURRENT)
-					CURRENT = CURRENT->next;
-				else
-					req1->next = req->next;
-			}
-		}
-		if (!SCpnt)
-			return;	/* Could not find anything to do */
-
-		wake_up(&wait_for_request);
-
-		/* Queue command */
-		requeue_sr_request(SCpnt);
-	}			/* While */
-}
-
-void requeue_sr_request(Scsi_Cmnd * SCpnt)
-{
-	unsigned int dev, block, realcount;
-	unsigned char cmd[10], *buffer, tries;
-	int this_count, start, end_rec;
-
-	tries = 2;
-
-repeat:
-	if (!SCpnt || SCpnt->request.rq_status == RQ_INACTIVE) {
-		do_sr_request();
-		return;
-	}
-	dev = MINOR(SCpnt->request.rq_dev);
-	block = SCpnt->request.sector;
-	buffer = NULL;
-	this_count = 0;
-
-	if (dev >= sr_template.nr_dev) {
-		/* printk("CD-ROM request error: invalid device.\n");                   */
-		SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
-		tries = 2;
-		goto repeat;
-	}
-	if (!scsi_CDs[dev].use) {
-		/* printk("CD-ROM request error: device marked not in use.\n");         */
-		SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
-		tries = 2;
-		goto repeat;
-	}
-	if (!scsi_CDs[dev].device->online) {
-		SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
-		tries = 2;
-		goto repeat;
-	}
-	if (scsi_CDs[dev].device->changed) {
-		/*
-		 * quietly refuse to do anything to a changed disc
-		 * until the changed bit has been reset
-		 */
-		/* printk("CD-ROM has been changed.  Prohibiting further I/O.\n");      */
-		SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
-		tries = 2;
-		goto repeat;
-	}
-	switch (SCpnt->request.cmd) {
-	case WRITE:
-		SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
-		goto repeat;
-		break;
-	case READ:
-		cmd[0] = READ_6;
-		break;
-	default:
-		panic("Unknown sr command %d\n", SCpnt->request.cmd);
-	}
-
-	cmd[1] = (SCpnt->lun << 5) & 0xe0;
-
-	/*
-	 * Now do the grungy work of figuring out which sectors we need, and
-	 * where in memory we are going to put them.
-	 *
-	 * The variables we need are:
-	 *
-	 * this_count= number of 512 byte sectors being read
-	 * block     = starting cdrom sector to read.
-	 * realcount = # of cdrom sectors to read
-	 *
-	 * The major difference between a scsi disk and a scsi cdrom
-	 * is that we will always use scatter-gather if we can, because we can
-	 * work around the fact that the buffer cache has a block size of 1024,
-	 * and we have 2048 byte sectors.  This code should work for buffers that
-	 * are any multiple of 512 bytes long.
-	 */
-
-	SCpnt->use_sg = 0;
-
-	if (SCpnt->host->sg_tablesize > 0 &&
-	    (!scsi_need_isa_buffer ||
-	     scsi_dma_free_sectors >= 10)) {
-		struct buffer_head *bh;
-		struct scatterlist *sgpnt;
-		int count, this_count_max;
-		bh = SCpnt->request.bh;
-		this_count = 0;
-		count = 0;
-		this_count_max = (scsi_CDs[dev].ten ? 0xffff : 0xff) << 4;
-		/* Calculate how many links we can use.  First see if we need
-		 * a padding record at the start */
-		this_count = SCpnt->request.sector % 4;
-		if (this_count)
-			count++;
-		while (bh && count < SCpnt->host->sg_tablesize) {
-			if ((this_count + (bh->b_size >> 9)) > this_count_max)
-				break;
-			this_count += (bh->b_size >> 9);
-			count++;
-			bh = bh->b_reqnext;
-		};
-		/* Fix up in case of an odd record at the end */
-		end_rec = 0;
-		if (this_count % 4) {
-			if (count < SCpnt->host->sg_tablesize) {
-				count++;
-				end_rec = (4 - (this_count % 4)) << 9;
-				this_count += 4 - (this_count % 4);
-			} else {
-				count--;
-				this_count -= (this_count % 4);
-			};
-		};
-		SCpnt->use_sg = count;	/* Number of chains */
-		/* scsi_malloc can only allocate in chunks of 512 bytes */
-		count = (SCpnt->use_sg * sizeof(struct scatterlist) + 511) & ~511;
-
-		SCpnt->sglist_len = count;
-		sgpnt = (struct scatterlist *) scsi_malloc(count);
-		if (!sgpnt) {
-			printk("Warning - running *really* short on DMA buffers\n");
-			SCpnt->use_sg = 0;	/* No memory left - bail out */
-		} else {
-			buffer = (unsigned char *) sgpnt;
-			count = 0;
-			bh = SCpnt->request.bh;
-			if (SCpnt->request.sector % 4) {
-				sgpnt[count].length = (SCpnt->request.sector % 4) << 9;
-				sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length);
-				if (!sgpnt[count].address)
-					panic("SCSI DMA pool exhausted.");
-				sgpnt[count].alt_address = sgpnt[count].address;	/* Flag to delete
-											   if needed */
-				count++;
-			};
-			for (bh = SCpnt->request.bh; count < SCpnt->use_sg;
-			     count++, bh = bh->b_reqnext) {
-				if (bh) {	/* Need a placeholder at the end of the record? */
-					sgpnt[count].address = bh->b_data;
-					sgpnt[count].length = bh->b_size;
-					sgpnt[count].alt_address = NULL;
-				} else {
-					sgpnt[count].address = (char *) scsi_malloc(end_rec);
-					if (!sgpnt[count].address)
-						panic("SCSI DMA pool exhausted.");
-					sgpnt[count].length = end_rec;
-					sgpnt[count].alt_address = sgpnt[count].address;
-					if (count + 1 != SCpnt->use_sg)
-						panic("Bad sr request list");
-					break;
-				};
-				if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length - 1 >
-				    ISA_DMA_THRESHOLD && SCpnt->host->unchecked_isa_dma) {
-					sgpnt[count].alt_address = sgpnt[count].address;
-					/* We try to avoid exhausting the DMA pool, since it is easier
-					 * to control usage here.  In other places we might have a more
-					 * pressing need, and we would be screwed if we ran out */
-					if (scsi_dma_free_sectors < (sgpnt[count].length >> 9) + 5) {
-						sgpnt[count].address = NULL;
-					} else {
-						sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length);
-					};
-					/* If we start running low on DMA buffers, we abort the scatter-gather
-					 * operation, and free all of the memory we have allocated.  We want to
-					 * ensure that all scsi operations are able to do at least a non-scatter/gather
-					 * operation */
-					if (sgpnt[count].address == NULL) {	/* Out of dma memory */
-						printk("Warning: Running low on SCSI DMA buffers\n");
-						/* Try switching back to a non scatter-gather operation. */
-						while (--count >= 0) {
-							if (sgpnt[count].alt_address)
-								scsi_free(sgpnt[count].address, sgpnt[count].length);
-						};
-						SCpnt->use_sg = 0;
-						scsi_free(buffer, SCpnt->sglist_len);
-						break;
-					};	/* if address == NULL */
-				};	/* if need DMA fixup */
-			};	/* for loop to fill list */
-#ifdef DEBUG
-			printk("SR: %d %d %d %d %d *** ", SCpnt->use_sg, SCpnt->request.sector,
-			       this_count,
-			       SCpnt->request.current_nr_sectors,
-			       SCpnt->request.nr_sectors);
-			for (count = 0; count < SCpnt->use_sg; count++)
-				printk("SGlist: %d %x %x %x\n", count,
-				       sgpnt[count].address,
-				       sgpnt[count].alt_address,
-				       sgpnt[count].length);
-#endif
-		};		/* Able to allocate scatter-gather list */
-	};
-
-	if (SCpnt->use_sg == 0) {
-		/* We cannot use scatter-gather.  Do this the old fashion way */
-		if (!SCpnt->request.bh)
-			this_count = SCpnt->request.nr_sectors;
-		else
-			this_count = (SCpnt->request.bh->b_size >> 9);
-
-		start = block % 4;
-		if (start) {
-			this_count = ((this_count > 4 - start) ?
-				      (4 - start) : (this_count));
-			buffer = (unsigned char *) scsi_malloc(2048);
-		} else if (this_count < 4) {
-			buffer = (unsigned char *) scsi_malloc(2048);
-		} else {
-			this_count -= this_count % 4;
-			buffer = (unsigned char *) SCpnt->request.buffer;
-			if (virt_to_phys(buffer) + (this_count << 9) > ISA_DMA_THRESHOLD &&
-			    SCpnt->host->unchecked_isa_dma)
-				buffer = (unsigned char *) scsi_malloc(this_count << 9);
-		}
-	};
-
-	if (scsi_CDs[dev].sector_size == 2048)
-		block = block >> 2;	/* These are the sectors that the cdrom uses */
-	else
-		block = block & 0xfffffffc;
-
-	realcount = (this_count + 3) / 4;
-
-	if (scsi_CDs[dev].sector_size == 512)
-		realcount = realcount << 2;
-
-	/*
-	 * Note: The scsi standard says that READ_6 is *optional*, while
-	 * READ_10 is mandatory.   Thus there is no point in using
-	 * READ_6.
-	 */
-	if (scsi_CDs[dev].ten) {
-		if (realcount > 0xffff) {
-			realcount = 0xffff;
-			this_count = realcount * (scsi_CDs[dev].sector_size >> 9);
-		}
-		cmd[0] += READ_10 - READ_6;
-		cmd[2] = (unsigned char) (block >> 24) & 0xff;
-		cmd[3] = (unsigned char) (block >> 16) & 0xff;
-		cmd[4] = (unsigned char) (block >> 8) & 0xff;
-		cmd[5] = (unsigned char) block & 0xff;
-		cmd[6] = cmd[9] = 0;
-		cmd[7] = (unsigned char) (realcount >> 8) & 0xff;
-		cmd[8] = (unsigned char) realcount & 0xff;
-	} else {
-		if (realcount > 0xff) {
-			realcount = 0xff;
-			this_count = realcount * (scsi_CDs[dev].sector_size >> 9);
-		}
-		cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
-		cmd[2] = (unsigned char) ((block >> 8) & 0xff);
-		cmd[3] = (unsigned char) block & 0xff;
-		cmd[4] = (unsigned char) realcount;
-		cmd[5] = 0;
-	}
-
-#ifdef DEBUG
-	{
-		int i;
-		printk("ReadCD: %d %d %d %d\n", block, realcount, buffer, this_count);
-		printk("Use sg: %d\n", SCpnt->use_sg);
-		printk("Dumping command: ");
-		for (i = 0; i < 12; i++)
-			printk("%2.2x ", cmd[i]);
-		printk("\n");
-	};
-#endif
-
-	/* Some dumb host adapters can speed transfers by knowing the
-	 * minimum transfersize in advance.
-	 *
-	 * We shouldn't disconnect in the middle of a sector, but the cdrom
-	 * sector size can be larger than the size of a buffer and the
-	 * transfer may be split to the size of a buffer.  So it's safe to
-	 * assume that we can at least transfer the minimum of the buffer
-	 * size (1024) and the sector size between each connect / disconnect.
-	 */
-
-	SCpnt->transfersize = (scsi_CDs[dev].sector_size > 1024) ?
-	    1024 : scsi_CDs[dev].sector_size;
-
-	SCpnt->this_count = this_count;
-	scsi_do_cmd(SCpnt, (void *) cmd, buffer,
-		    realcount * scsi_CDs[dev].sector_size,
-		    rw_intr, SR_TIMEOUT, MAX_RETRIES);
-}
 
 static int sr_detect(Scsi_Device * SDp)
 {
@@ -833,7 +460,7 @@
 	if (i >= sr_template.dev_max)
 		panic("scsi_devices corrupt (sr)");
 
-	SDp->scsi_request_fn = do_sr_request;
+
 	scsi_CDs[i].device = SDp;
 
 	sr_template.nr_dev++;
@@ -860,12 +487,13 @@
 	unsigned char cmd[10];
 	unsigned char *buffer;
 	int the_result, retries;
+	int sector_size;
 	Scsi_Cmnd *SCpnt;
 
-	spin_lock_irq(&io_request_lock);
 	buffer = (unsigned char *) scsi_malloc(512);
-	SCpnt = scsi_allocate_device(NULL, scsi_CDs[i].device, 1);
-	spin_unlock_irq(&io_request_lock);
+
+
+	SCpnt = scsi_allocate_device(scsi_CDs[i].device, 1);
 
 	retries = 3;
 	do {
@@ -879,8 +507,8 @@
 
 		/* Do the command and wait.. */
 
-		scsi_wait_cmd (SCpnt, (void *) cmd, (void *) buffer,
-			512, sr_init_done,  SR_TIMEOUT,	 MAX_RETRIES);
+		scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
+			      512, sr_init_done, SR_TIMEOUT, MAX_RETRIES);
 
 		the_result = SCpnt->result;
 		retries--;
@@ -894,7 +522,7 @@
 
 	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 {
 #if 0
@@ -905,9 +533,9 @@
 						    (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
@@ -917,7 +545,7 @@
 		case 0:
 		case 2340:
 		case 2352:
-			scsi_CDs[i].sector_size = 2048;
+			sector_size = 2048;
 			/* fall through */
 		case 2048:
 			scsi_CDs[i].capacity *= 4;
@@ -926,11 +554,13 @@
 			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;
 		}
 
+		scsi_CDs[i].device->sector_size = sector_size;
+
 		/*
 		 * Add this so that we have the ability to correctly gauge
 		 * what the device is capable of.
@@ -959,9 +589,7 @@
 		""
 	};
 
-	spin_lock_irq(&io_request_lock);
 	buffer = (unsigned char *) scsi_malloc(512);
-	spin_unlock_irq(&io_request_lock);
 	cmd[0] = MODE_SENSE;
 	cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0;
 	cmd[2] = 0x2a;
@@ -1008,19 +636,19 @@
 	if ((buffer[n + 3] & 0x1) == 0)
 		/* can't write CD-R media */
 		scsi_CDs[i].cdi.mask |= CDC_CD_R;
-	if ((buffer[n+6] & 0x8) == 0)
+	if ((buffer[n + 6] & 0x8) == 0)
 		/* can't eject */
 		scsi_CDs[i].cdi.mask |= CDC_OPEN_TRAY;
 
-	if ((buffer[n+6] >> 5) == mechtype_individual_changer ||
-	    (buffer[n+6] >> 5) == mechtype_cartridge_changer)
-		scsi_CDs[i].cdi.capacity = 
-			cdrom_number_of_slots(&(scsi_CDs[i].cdi));
+	if ((buffer[n + 6] >> 5) == mechtype_individual_changer ||
+	    (buffer[n + 6] >> 5) == mechtype_cartridge_changer)
+		scsi_CDs[i].cdi.capacity =
+		    cdrom_number_of_slots(&(scsi_CDs[i].cdi));
 	if (scsi_CDs[i].cdi.capacity <= 1)
-                /* not a changer */
+		/* not a changer */
 		scsi_CDs[i].cdi.mask |= CDC_SELECT_DISC;
 	/*else    I don't think it can close its tray
-		scsi_CDs[i].cdi.mask |= CDC_CLOSE_TRAY; */
+	   scsi_CDs[i].cdi.mask |= CDC_CLOSE_TRAY; */
 
 
 	scsi_free(buffer, 512);
@@ -1039,24 +667,21 @@
 	int stat;
 
 	/* get the device */
-	SCpnt = scsi_allocate_device(NULL, device, 1);
+	SCpnt = scsi_allocate_device(device, 1);
 	if (SCpnt == NULL)
 		return -ENODEV;	/* this just doesn't seem right /axboe */
 
 	/* use buffer for ISA DMA */
 	buflen = (cgc->buflen + 511) & ~511;
 	if (cgc->buffer && SCpnt->host->unchecked_isa_dma &&
-    	   (virt_to_phys(cgc->buffer) + cgc->buflen - 1 > ISA_DMA_THRESHOLD)) {
-		spin_lock_irq(&io_request_lock);
+	    (virt_to_phys(cgc->buffer) + cgc->buflen - 1 > ISA_DMA_THRESHOLD)) {
 		buffer = scsi_malloc(buflen);
-		spin_unlock_irq(&io_request_lock);
 		if (buffer == NULL) {
 			printk("sr: SCSI DMA pool exhausted.");
 			return -ENOMEM;
 		}
 		memcpy(buffer, cgc->buffer, cgc->buflen);
 	}
-
 	/* set the LUN */
 	cgc->cmd[1] |= device->lun << 5;
 
@@ -1065,8 +690,8 @@
 	/* scsi_do_cmd sets the command length */
 	SCpnt->cmd_len = 0;
 
-	scsi_wait_cmd (SCpnt, (void *)cgc->cmd, (void *)buffer, cgc->buflen,
-		sr_init_done, SR_TIMEOUT, MAX_RETRIES);
+	scsi_wait_cmd(SCpnt, (void *) cgc->cmd, (void *) buffer, cgc->buflen,
+		      sr_init_done, SR_TIMEOUT, MAX_RETRIES);
 
 	stat = SCpnt->result;
 
@@ -1080,7 +705,6 @@
 		memcpy(cgc->buffer, buffer, cgc->buflen);
 		scsi_free(buffer, buflen);
 	}
-
 	return stat;
 }
 
@@ -1127,7 +751,7 @@
 	int i;
 	char name[6];
 
-	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	blk_dev[MAJOR_NR].queue = sr_find_queue;
 	blk_size[MAJOR_NR] = sr_sizes;
 
 	for (i = 0; i < sr_template.nr_dev; ++i) {
@@ -1136,7 +760,7 @@
 		if (scsi_CDs[i].capacity)
 			continue;
 		scsi_CDs[i].capacity = 0x1fffff;
-		scsi_CDs[i].sector_size = 2048;		/* A guess, just in case */
+		scsi_CDs[i].device->sector_size = 2048;		/* A guess, just in case */
 		scsi_CDs[i].needs_sector_size = 1;
 		scsi_CDs[i].device->changed = 1;	/* force recheck CD type */
 #if 0
@@ -1145,8 +769,9 @@
 		printk("Scd sectorsize = %d bytes.\n", scsi_CDs[i].sector_size);
 #endif
 		scsi_CDs[i].use = 1;
-		scsi_CDs[i].ten = 1;
-		scsi_CDs[i].remap = 1;
+
+		scsi_CDs[i].device->ten = 1;
+		scsi_CDs[i].device->remap = 1;
 		scsi_CDs[i].readcd_known = 0;
 		scsi_CDs[i].readcd_cdda = 0;
 		sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9);
@@ -1236,7 +861,7 @@
 		sr_blocksizes = NULL;
 	}
 	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	Wed Oct 20 16:40:28 1999
+++ linux.new2/drivers/scsi/sr.h	Sun Nov 14 09:29:38 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.
  */
@@ -21,15 +21,12 @@
 
 typedef struct {
 	unsigned capacity;	/* size in blocks                       */
-	unsigned sector_size;	/* size in bytes                        */
 	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 */
-	unsigned ten:1;		/* support ten byte commands            */
-	unsigned remap:1;	/* support remapping                    */
 	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 Nov  7 16:35:21 1999
+++ linux.new2/drivers/scsi/sr_ioctl.c	Sun Nov 14 10:16:15 1999
@@ -16,7 +16,7 @@
 #include "sr.h"
 
 #if 0
-# define DEBUG
+#define DEBUG
 #endif
 
 /* The sr_is_xa() seems to trigger firmware bugs with some drives :-(
@@ -32,134 +32,121 @@
 
 static void sr_ioctl_done(Scsi_Cmnd * SCpnt)
 {
-    struct request * req;
-    
-    req = &SCpnt->request;
-    req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */
-
-    if (SCpnt->buffer && req->buffer && SCpnt->buffer != req->buffer) {
-	memcpy(req->buffer, SCpnt->buffer, SCpnt->bufflen);
-	scsi_free(SCpnt->buffer, (SCpnt->bufflen + 511) & ~511);
-	SCpnt->buffer = req->buffer;
-    } 
-    
-    if (req->sem != NULL) {
-	up(req->sem);
-    }
+	struct request *req;
+
+	req = &SCpnt->request;
+	req->rq_status = RQ_SCSI_DONE;	/* Busy, but indicate request done */
+
+	if (SCpnt->buffer && req->buffer && SCpnt->buffer != req->buffer) {
+		memcpy(req->buffer, SCpnt->buffer, SCpnt->bufflen);
+		scsi_free(SCpnt->buffer, (SCpnt->bufflen + 511) & ~511);
+		SCpnt->buffer = req->buffer;
+	}
+	if (req->sem != NULL) {
+		up(req->sem);
+	}
 }
 
 /* We do our own retries because we want to know what the specific
    error code is.  Normally the UNIT_ATTENTION code will automatically
    clear after one error */
 
-int sr_do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned buflength, int quiet)
+int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflength, int quiet)
 {
-    Scsi_Cmnd * SCpnt;
-    Scsi_Device * SDev;
-    int result, err = 0, retries = 0;
-    unsigned long flags;
-    char * bounce_buffer;
-
-    spin_lock_irqsave(&io_request_lock, flags);
-    SDev  = scsi_CDs[target].device;
-    SCpnt = scsi_allocate_device(NULL, scsi_CDs[target].device, 1);
-    spin_unlock_irqrestore(&io_request_lock, flags);
-
-    /* use ISA DMA buffer if necessary */
-    SCpnt->request.buffer=buffer;
-    if (buffer && SCpnt->host->unchecked_isa_dma &&
-       (virt_to_phys(buffer) + buflength - 1 > ISA_DMA_THRESHOLD)) {
-	bounce_buffer = (char *)scsi_malloc((buflength + 511) & ~511);
-	if (bounce_buffer == NULL) {
-		printk("SCSI DMA pool exhausted.");
-		return -ENOMEM;
-	}
-	memcpy(bounce_buffer, (char *)buffer, buflength);
-	buffer = bounce_buffer;
-    }
-
-retry:
-    if( !scsi_block_when_processing_errors(SDev) )
-        return -ENODEV;
-
-    scsi_wait_cmd(SCpnt, (void *)sr_cmd, (void *)buffer, buflength,
-		  sr_ioctl_done, IOCTL_TIMEOUT, IOCTL_RETRIES);
-
-    result = SCpnt->result;
-    
-    /* Minimal error checking.  Ignore cases we know about, and report the rest. */
-    if(driver_byte(result) != 0) {
-	switch(SCpnt->sense_buffer[2] & 0xf) {
-	case UNIT_ATTENTION:
-	    scsi_CDs[target].device->changed = 1;
-	    if (!quiet)
-	    	printk(KERN_INFO "sr%d: disc change detected.\n", target);
-	    if (retries++ < 10)
-		goto retry;
-	    err = -ENOMEDIUM;
-	    break;
-	case NOT_READY: /* This happens if there is no disc in drive */
-            if (SCpnt->sense_buffer[12] == 0x04 &&
-                SCpnt->sense_buffer[13] == 0x01) {
-                /* sense: Logical unit is in process of becoming ready */
-                if (!quiet)
-                    printk(KERN_INFO "sr%d: CDROM not ready yet.\n", target);
-		if (retries++ < 10) {
-		    /* sleep 2 sec and try again */
-		    /*
-		     * 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);
-		    scsi_sleep(2*HZ);
-		    spin_unlock_irqrestore(&io_request_lock, flags);
-                    goto retry;
-		} else {
-		    /* 20 secs are enough? */
-		    err = -ENOMEDIUM;
-		    break;
+	Scsi_Cmnd *SCpnt;
+	Scsi_Device *SDev;
+	int result, err = 0, retries = 0;
+	unsigned long flags;
+	char *bounce_buffer;
+
+	SDev = scsi_CDs[target].device;
+	SCpnt = scsi_allocate_device(scsi_CDs[target].device, 1);
+
+	/* use ISA DMA buffer if necessary */
+	SCpnt->request.buffer = buffer;
+	if (buffer && SCpnt->host->unchecked_isa_dma &&
+	    (virt_to_phys(buffer) + buflength - 1 > ISA_DMA_THRESHOLD)) {
+		bounce_buffer = (char *) scsi_malloc((buflength + 511) & ~511);
+		if (bounce_buffer == NULL) {
+			printk("SCSI DMA pool exhausted.");
+			return -ENOMEM;
 		}
-            }
-	    if (!quiet)
-            	printk(KERN_INFO "sr%d: CDROM not ready.  Make sure there is a disc in the drive.\n",target);
+		memcpy(bounce_buffer, (char *) buffer, buflength);
+		buffer = bounce_buffer;
+	}
+      retry:
+	if (!scsi_block_when_processing_errors(SDev))
+		return -ENODEV;
+
+
+	scsi_wait_cmd(SCpnt, (void *) sr_cmd, (void *) buffer, buflength,
+		      sr_ioctl_done, IOCTL_TIMEOUT, IOCTL_RETRIES);
+
+	result = SCpnt->result;
+
+	/* Minimal error checking.  Ignore cases we know about, and report the rest. */
+	if (driver_byte(result) != 0) {
+		switch (SCpnt->sense_buffer[2] & 0xf) {
+		case UNIT_ATTENTION:
+			scsi_CDs[target].device->changed = 1;
+			if (!quiet)
+				printk(KERN_INFO "sr%d: disc change detected.\n", target);
+			if (retries++ < 10)
+				goto retry;
+			err = -ENOMEDIUM;
+			break;
+		case NOT_READY:	/* This happens if there is no disc in drive */
+			if (SCpnt->sense_buffer[12] == 0x04 &&
+			    SCpnt->sense_buffer[13] == 0x01) {
+				/* sense: Logical unit is in process of becoming ready */
+				if (!quiet)
+					printk(KERN_INFO "sr%d: CDROM not ready yet.\n", target);
+				if (retries++ < 10) {
+					/* sleep 2 sec and try again */
+					scsi_sleep(2 * HZ);
+					goto retry;
+				} else {
+					/* 20 secs are enough? */
+					err = -ENOMEDIUM;
+					break;
+				}
+			}
+			if (!quiet)
+				printk(KERN_INFO "sr%d: CDROM not ready.  Make sure there is a disc in the drive.\n", target);
 #ifdef DEBUG
-            print_sense("sr", SCpnt);
+			print_sense("sr", SCpnt);
 #endif
-            err = -ENOMEDIUM;
-	    break;
-	case ILLEGAL_REQUEST:
-            if (!quiet)
-		printk(KERN_ERR "sr%d: CDROM (ioctl) reports ILLEGAL "
-		       "REQUEST.\n", target);
-            if (SCpnt->sense_buffer[12] == 0x20 &&
-                SCpnt->sense_buffer[13] == 0x00) {
-                /* sense: Invalid command operation code */
-                err = -EDRIVE_CANT_DO_THIS;
-            } else {
-                err = -EINVAL;
-            }
+			err = -ENOMEDIUM;
+			break;
+		case ILLEGAL_REQUEST:
+			if (!quiet)
+				printk(KERN_ERR "sr%d: CDROM (ioctl) reports ILLEGAL "
+				       "REQUEST.\n", target);
+			if (SCpnt->sense_buffer[12] == 0x20 &&
+			    SCpnt->sense_buffer[13] == 0x00) {
+				/* sense: Invalid command operation code */
+				err = -EDRIVE_CANT_DO_THIS;
+			} else {
+				err = -EINVAL;
+			}
 #ifdef DEBUG
-	    print_command(sr_cmd);
-            print_sense("sr", SCpnt);
+			print_command(sr_cmd);
+			print_sense("sr", SCpnt);
 #endif
-	    break;
-	default:
-	    printk(KERN_ERR "sr%d: CDROM (ioctl) error, command: ", target);
-	    print_command(sr_cmd);
-	    print_sense("sr", SCpnt);
-            err = -EIO;
-	}
-    }
-   
-    spin_lock_irqsave(&io_request_lock, flags);
-    result = SCpnt->result;
-    /* Wake up a process waiting for device*/
-    wake_up(&SCpnt->device->device_wait);
-    scsi_release_command(SCpnt);
-    SCpnt = NULL;
-    spin_unlock_irqrestore(&io_request_lock, flags);
-    return err;
+			break;
+		default:
+			printk(KERN_ERR "sr%d: CDROM (ioctl) error, command: ", target);
+			print_command(sr_cmd);
+			print_sense("sr", SCpnt);
+			err = -EIO;
+		}
+	}
+	result = SCpnt->result;
+	/* Wake up a process waiting for device */
+	wake_up(&SCpnt->device->device_wait);
+	scsi_release_command(SCpnt);
+	SCpnt = NULL;
+	return err;
 }
 
 /* ---------------------------------------------------------------------- */
@@ -167,95 +154,94 @@
 
 static int test_unit_ready(int minor)
 {
-	u_char  sr_cmd[10];
+	u_char sr_cmd[10];
 
-        sr_cmd[0] = GPCMD_TEST_UNIT_READY;
-        sr_cmd[1] = ((scsi_CDs[minor].device -> lun) << 5);
-        sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
-        return sr_do_ioctl(minor, sr_cmd, NULL, 255, 1);
+	sr_cmd[0] = GPCMD_TEST_UNIT_READY;
+	sr_cmd[1] = ((scsi_CDs[minor].device->lun) << 5);
+	sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
+	return sr_do_ioctl(minor, sr_cmd, NULL, 255, 1);
 }
 
 int sr_tray_move(struct cdrom_device_info *cdi, int pos)
 {
-        u_char  sr_cmd[10];
+	u_char sr_cmd[10];
 
-        sr_cmd[0] = GPCMD_START_STOP_UNIT;
-        sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device -> lun) << 5);
-        sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
-        sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */;
-	
-        return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 255, 0);
+	sr_cmd[0] = GPCMD_START_STOP_UNIT;
+	sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5);
+	sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
+	sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ;
+
+	return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 255, 0);
 }
 
 int sr_lock_door(struct cdrom_device_info *cdi, int lock)
 {
-        return scsi_ioctl (scsi_CDs[MINOR(cdi->dev)].device,
-                           lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK,
-                           0);
+	return scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device,
+		      lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK,
+			  0);
 }
 
 int sr_drive_status(struct cdrom_device_info *cdi, int slot)
 {
-        if (CDSL_CURRENT != slot) {
-                /* we have no changer support */
-                return -EINVAL;
-        }
-
-        if (0 == test_unit_ready(MINOR(cdi->dev)))
-            return CDS_DISC_OK;
+	if (CDSL_CURRENT != slot) {
+		/* we have no changer support */
+		return -EINVAL;
+	}
+	if (0 == test_unit_ready(MINOR(cdi->dev)))
+		return CDS_DISC_OK;
 
-        return CDS_TRAY_OPEN;
+	return CDS_TRAY_OPEN;
 }
 
 int sr_disk_status(struct cdrom_device_info *cdi)
 {
-	struct cdrom_tochdr    toc_h;
-	struct cdrom_tocentry  toc_e;
-        int                    i,rc,have_datatracks = 0;
-
-        /* look for data tracks */
-        if (0 != (rc = sr_audio_ioctl(cdi, CDROMREADTOCHDR, &toc_h)))
-                return (rc == -ENOMEDIUM) ? CDS_NO_DISC : CDS_NO_INFO;
-
-        for (i = toc_h.cdth_trk0; i <= toc_h.cdth_trk1; i++) {
-                toc_e.cdte_track  = i;
-                toc_e.cdte_format = CDROM_LBA;
-                if (sr_audio_ioctl(cdi, CDROMREADTOCENTRY, &toc_e))
-                        return CDS_NO_INFO;
-                if (toc_e.cdte_ctrl & CDROM_DATA_TRACK) {
-                        have_datatracks = 1;
-                        break;
-                }
-        }
-        if (!have_datatracks)
-            return CDS_AUDIO;
-
-        if (scsi_CDs[MINOR(cdi->dev)].xa_flag)
-            return CDS_XA_2_1;
-        else
-            return CDS_DATA_1;
+	struct cdrom_tochdr toc_h;
+	struct cdrom_tocentry toc_e;
+	int i, rc, have_datatracks = 0;
+
+	/* look for data tracks */
+	if (0 != (rc = sr_audio_ioctl(cdi, CDROMREADTOCHDR, &toc_h)))
+		return (rc == -ENOMEDIUM) ? CDS_NO_DISC : CDS_NO_INFO;
+
+	for (i = toc_h.cdth_trk0; i <= toc_h.cdth_trk1; i++) {
+		toc_e.cdte_track = i;
+		toc_e.cdte_format = CDROM_LBA;
+		if (sr_audio_ioctl(cdi, CDROMREADTOCENTRY, &toc_e))
+			return CDS_NO_INFO;
+		if (toc_e.cdte_ctrl & CDROM_DATA_TRACK) {
+			have_datatracks = 1;
+			break;
+		}
+	}
+	if (!have_datatracks)
+		return CDS_AUDIO;
+
+	if (scsi_CDs[MINOR(cdi->dev)].xa_flag)
+		return CDS_XA_2_1;
+	else
+		return CDS_DATA_1;
 }
 
 int sr_get_last_session(struct cdrom_device_info *cdi,
-                        struct cdrom_multisession* ms_info)
+			struct cdrom_multisession *ms_info)
 {
-        ms_info->addr.lba=scsi_CDs[MINOR(cdi->dev)].ms_offset;
-        ms_info->xa_flag=scsi_CDs[MINOR(cdi->dev)].xa_flag ||
-            (scsi_CDs[MINOR(cdi->dev)].ms_offset > 0);
+	ms_info->addr.lba = scsi_CDs[MINOR(cdi->dev)].ms_offset;
+	ms_info->xa_flag = scsi_CDs[MINOR(cdi->dev)].xa_flag ||
+	    (scsi_CDs[MINOR(cdi->dev)].ms_offset > 0);
 
 	return 0;
 }
 
-int sr_get_mcn(struct cdrom_device_info *cdi,struct cdrom_mcn *mcn)
+int sr_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
 {
-        u_char  sr_cmd[10];
+	u_char sr_cmd[10];
 	char buffer[32];
-        int result;
-        	
+	int result;
+
 	sr_cmd[0] = GPCMD_READ_SUBCHANNEL;
 	sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5);
-	sr_cmd[2] = 0x40;    /* I do want the subchannel info */
-	sr_cmd[3] = 0x02;    /* Give me medium catalog number info */
+	sr_cmd[2] = 0x40;	/* I do want the subchannel info */
+	sr_cmd[3] = 0x02;	/* Give me medium catalog number info */
 	sr_cmd[4] = sr_cmd[5] = 0;
 	sr_cmd[6] = 0;
 	sr_cmd[7] = 0;
@@ -263,9 +249,9 @@
 	sr_cmd[9] = 0;
 
 	result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24, 0);
-	
-	memcpy (mcn->medium_catalog_number, buffer + 9, 13);
-        mcn->medium_catalog_number[13] = 0;
+
+	memcpy(mcn->medium_catalog_number, buffer + 9, 13);
+	mcn->medium_catalog_number[13] = 0;
 
 	return result;
 }
@@ -273,26 +259,26 @@
 int sr_reset(struct cdrom_device_info *cdi)
 {
 	invalidate_buffers(cdi->dev);
-	return 0;        
+	return 0;
 }
 
 int sr_select_speed(struct cdrom_device_info *cdi, int speed)
 {
-        u_char  sr_cmd[12];
+	u_char sr_cmd[12];
 
-        if (speed == 0)
-            speed = 0xffff; /* set to max */
-        else
-            speed *= 177;   /* Nx to kbyte/s */
-        
-	memset(sr_cmd,0,12);
-	sr_cmd[0] = GPCMD_SET_SPEED; /* SET CD SPEED */
+	if (speed == 0)
+		speed = 0xffff;	/* set to max */
+	else
+		speed *= 177;	/* Nx to kbyte/s */
+
+	memset(sr_cmd, 0, 12);
+	sr_cmd[0] = GPCMD_SET_SPEED;	/* SET CD SPEED */
 	sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->lun) << 5;
-	sr_cmd[2] = (speed >> 8) & 0xff; /* MSB for speed (in kbytes/sec) */
-	sr_cmd[3] =  speed       & 0xff; /* LSB */
+	sr_cmd[2] = (speed >> 8) & 0xff;	/* MSB for speed (in kbytes/sec) */
+	sr_cmd[3] = speed & 0xff;	/* LSB */
 
-        if (sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0))
-            return -EIO;
+	if (sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0))
+		return -EIO;
 	return 0;
 }
 
@@ -302,73 +288,72 @@
 /* only cdromreadtochdr and cdromreadtocentry are left - for use with the  */
 /* sr_disk_status interface for the generic cdrom driver.                  */
 
-int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
+int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
 {
-    u_char  sr_cmd[10];    
-    int result, target  = MINOR(cdi->dev);
-    unsigned char buffer[32];
-    
-    switch (cmd) 
-    {
-    case CDROMREADTOCHDR:
-    {
-	struct cdrom_tochdr* tochdr = (struct cdrom_tochdr*)arg;
-	
-	sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
-	sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5);
-	sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
-	sr_cmd[6] = 0;
-	sr_cmd[7] = 0;              /* MSB of length (12) */
-	sr_cmd[8] = 12;             /* LSB of length */
-	sr_cmd[9] = 0;
-	
-	result = sr_do_ioctl(target, sr_cmd, buffer, 12, 1);
-	
-	tochdr->cdth_trk0 = buffer[2];
-	tochdr->cdth_trk1 = buffer[3];
-	
-        break;
-    }
-	
-    case CDROMREADTOCENTRY:
-    {
-	struct cdrom_tocentry* tocentry = (struct cdrom_tocentry*)arg;
-	
-	sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
-	sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) |
-          (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0);
-	sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
-	sr_cmd[6] = tocentry->cdte_track;
-	sr_cmd[7] = 0;             /* MSB of length (12)  */
-	sr_cmd[8] = 12;            /* LSB of length */
-	sr_cmd[9] = 0;
-	
-	result = sr_do_ioctl (target, sr_cmd, buffer, 12, 0);
-	
-        tocentry->cdte_ctrl = buffer[5] & 0xf;	
-        tocentry->cdte_adr = buffer[5] >> 4;
-        tocentry->cdte_datamode = (tocentry->cdte_ctrl & 0x04) ? 1 : 0;
-	if (tocentry->cdte_format == CDROM_MSF) {
-	    tocentry->cdte_addr.msf.minute = buffer[9];
-	    tocentry->cdte_addr.msf.second = buffer[10];
-	    tocentry->cdte_addr.msf.frame = buffer[11];
-	} else
-	    tocentry->cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8)
-                                       + buffer[10]) << 8) + buffer[11];
-	
-        break;
-    }
-
-    default:
-        return -EINVAL;
-    }
+	u_char sr_cmd[10];
+	int result, target = MINOR(cdi->dev);
+	unsigned char buffer[32];
+
+	switch (cmd) {
+	case CDROMREADTOCHDR:
+		{
+			struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg;
+
+			sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
+			sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5);
+			sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
+			sr_cmd[6] = 0;
+			sr_cmd[7] = 0;	/* MSB of length (12) */
+			sr_cmd[8] = 12;		/* LSB of length */
+			sr_cmd[9] = 0;
+
+			result = sr_do_ioctl(target, sr_cmd, buffer, 12, 1);
+
+			tochdr->cdth_trk0 = buffer[2];
+			tochdr->cdth_trk1 = buffer[3];
+
+			break;
+		}
+
+	case CDROMREADTOCENTRY:
+		{
+			struct cdrom_tocentry *tocentry = (struct cdrom_tocentry *) arg;
+
+			sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
+			sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) |
+			    (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0);
+			sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
+			sr_cmd[6] = tocentry->cdte_track;
+			sr_cmd[7] = 0;	/* MSB of length (12)  */
+			sr_cmd[8] = 12;		/* LSB of length */
+			sr_cmd[9] = 0;
+
+			result = sr_do_ioctl(target, sr_cmd, buffer, 12, 0);
+
+			tocentry->cdte_ctrl = buffer[5] & 0xf;
+			tocentry->cdte_adr = buffer[5] >> 4;
+			tocentry->cdte_datamode = (tocentry->cdte_ctrl & 0x04) ? 1 : 0;
+			if (tocentry->cdte_format == CDROM_MSF) {
+				tocentry->cdte_addr.msf.minute = buffer[9];
+				tocentry->cdte_addr.msf.second = buffer[10];
+				tocentry->cdte_addr.msf.frame = buffer[11];
+			} else
+				tocentry->cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8)
+					+ buffer[10]) << 8) + buffer[11];
+
+			break;
+		}
+
+	default:
+		return -EINVAL;
+	}
 
 #if 0
-    if (result)
-        printk("DEBUG: sr_audio: result for ioctl %x: %x\n",cmd,result);
+	if (result)
+		printk("DEBUG: sr_audio: result for ioctl %x: %x\n", cmd, result);
 #endif
-    
-    return result;
+
+	return result;
 }
 
 /* -----------------------------------------------------------------------
@@ -385,73 +370,78 @@
  * blksize: 2048 | 2336 | 2340 | 2352
  */
 
-int
-sr_read_cd(int minor, unsigned char *dest, int lba, int format, int blksize)
+int sr_read_cd(int minor, unsigned char *dest, int lba, int format, int blksize)
 {
-    unsigned char  cmd[12];
+	unsigned char cmd[12];
 
 #ifdef DEBUG
-    printk("sr%d: sr_read_cd lba=%d format=%d blksize=%d\n",
-           minor,lba,format,blksize);
+	printk("sr%d: sr_read_cd lba=%d format=%d blksize=%d\n",
+	       minor, lba, format, blksize);
 #endif
 
-    memset(cmd,0,12);
-    cmd[0] = GPCMD_READ_CD; /* READ_CD */
-    cmd[1] = (scsi_CDs[minor].device->lun << 5) | ((format & 7) << 2);
-    cmd[2] = (unsigned char)(lba >> 24) & 0xff;
-    cmd[3] = (unsigned char)(lba >> 16) & 0xff;
-    cmd[4] = (unsigned char)(lba >>  8) & 0xff;
-    cmd[5] = (unsigned char) lba        & 0xff;
-    cmd[8] = 1;
-    switch (blksize) {
-    case 2336: cmd[9] = 0x58; break;
-    case 2340: cmd[9] = 0x78; break;
-    case 2352: cmd[9] = 0xf8; break;
-    default:   cmd[9] = 0x10; break;
-    }
-    return sr_do_ioctl(minor, cmd, dest, blksize, 0);
+	memset(cmd, 0, 12);
+	cmd[0] = GPCMD_READ_CD;	/* READ_CD */
+	cmd[1] = (scsi_CDs[minor].device->lun << 5) | ((format & 7) << 2);
+	cmd[2] = (unsigned char) (lba >> 24) & 0xff;
+	cmd[3] = (unsigned char) (lba >> 16) & 0xff;
+	cmd[4] = (unsigned char) (lba >> 8) & 0xff;
+	cmd[5] = (unsigned char) lba & 0xff;
+	cmd[8] = 1;
+	switch (blksize) {
+	case 2336:
+		cmd[9] = 0x58;
+		break;
+	case 2340:
+		cmd[9] = 0x78;
+		break;
+	case 2352:
+		cmd[9] = 0xf8;
+		break;
+	default:
+		cmd[9] = 0x10;
+		break;
+	}
+	return sr_do_ioctl(minor, cmd, dest, blksize, 0);
 }
 
 /*
  * read sectors with blocksizes other than 2048
  */
 
-int
-sr_read_sector(int minor, int lba, int blksize, unsigned char *dest)
+int sr_read_sector(int minor, int lba, int blksize, unsigned char *dest)
 {
-    unsigned char   cmd[12];    /* the scsi-command */
-    int             rc;
-
-    /* we try the READ CD command first... */
-    if (scsi_CDs[minor].readcd_known) {
-        rc = sr_read_cd(minor, dest, lba, 0, blksize);
-        if (-EDRIVE_CANT_DO_THIS != rc)
-            return rc;
-        scsi_CDs[minor].readcd_known = 0;
-        printk("CDROM does'nt support READ CD (0xbe) command\n");
-        /* fall & retry the other way */
-    }
-
-    /* ... if this fails, we switch the blocksize using MODE SELECT */
-    if (blksize != scsi_CDs[minor].sector_size)
-        if (0 != (rc = sr_set_blocklength(minor, blksize)))
-            return rc;
+	unsigned char cmd[12];	/* the scsi-command */
+	int rc;
 
+	/* we try the READ CD command first... */
+	if (scsi_CDs[minor].readcd_known) {
+		rc = sr_read_cd(minor, dest, lba, 0, blksize);
+		if (-EDRIVE_CANT_DO_THIS != rc)
+			return rc;
+		scsi_CDs[minor].readcd_known = 0;
+		printk("CDROM does'nt support READ CD (0xbe) command\n");
+		/* fall & retry the other way */
+	}
+	/* ... if this fails, we switch the blocksize using MODE SELECT */
+	if (blksize != scsi_CDs[minor].device->sector_size) {
+		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);
+	printk("sr%d: sr_read_sector lba=%d blksize=%d\n", minor, lba, blksize);
 #endif
-    
-    memset(cmd,0,12);
-    cmd[0] = GPCMD_READ_10;
-    cmd[1] = (scsi_CDs[minor].device->lun << 5);
-    cmd[2] = (unsigned char)(lba >> 24) & 0xff;
-    cmd[3] = (unsigned char)(lba >> 16) & 0xff;
-    cmd[4] = (unsigned char)(lba >>  8) & 0xff;
-    cmd[5] = (unsigned char) lba        & 0xff;
-    cmd[8] = 1;
-    rc = sr_do_ioctl(minor, cmd, dest, blksize, 0);
-    
-    return rc;
+
+	memset(cmd, 0, 12);
+	cmd[0] = GPCMD_READ_10;
+	cmd[1] = (scsi_CDs[minor].device->lun << 5);
+	cmd[2] = (unsigned char) (lba >> 24) & 0xff;
+	cmd[3] = (unsigned char) (lba >> 16) & 0xff;
+	cmd[4] = (unsigned char) (lba >> 8) & 0xff;
+	cmd[5] = (unsigned char) lba & 0xff;
+	cmd[8] = 1;
+	rc = sr_do_ioctl(minor, cmd, dest, blksize, 0);
+
+	return rc;
 }
 
 /*
@@ -459,55 +449,50 @@
  * ret: 1 == mode2 (XA), 0 == mode1, <0 == error 
  */
 
-int
-sr_is_xa(int minor)
+int sr_is_xa(int minor)
 {
-    unsigned char *raw_sector;
-    int is_xa;
-    unsigned long flags;
-    
-    if (!xa_test)
-        return 0;
-   
-    spin_lock_irqsave(&io_request_lock, flags);
-    raw_sector = (unsigned char *) scsi_malloc(2048+512);
-    spin_unlock_irqrestore(&io_request_lock, flags);
-    if (!raw_sector) return -ENOMEM;
-    if (0 == sr_read_sector(minor,scsi_CDs[minor].ms_offset+16,
-                            CD_FRAMESIZE_RAW1,raw_sector)) {
-        is_xa = (raw_sector[3] == 0x02) ? 1 : 0;
-    } else {
-        /* read a raw sector failed for some reason. */
-        is_xa = -1;
-    }
-    spin_lock_irqsave(&io_request_lock, flags);
-    scsi_free(raw_sector, 2048+512);
-    spin_unlock_irqrestore(&io_request_lock, flags);
+	unsigned char *raw_sector;
+	int is_xa;
+
+	if (!xa_test)
+		return 0;
+
+	raw_sector = (unsigned char *) scsi_malloc(2048 + 512);
+	if (!raw_sector)
+		return -ENOMEM;
+	if (0 == sr_read_sector(minor, scsi_CDs[minor].ms_offset + 16,
+				CD_FRAMESIZE_RAW1, raw_sector)) {
+		is_xa = (raw_sector[3] == 0x02) ? 1 : 0;
+	} else {
+		/* read a raw sector failed for some reason. */
+		is_xa = -1;
+	}
+	scsi_free(raw_sector, 2048 + 512);
 #ifdef DEBUG
-    printk("sr%d: sr_is_xa: %d\n",minor,is_xa);
+	printk("sr%d: sr_is_xa: %d\n", minor, is_xa);
 #endif
-    return is_xa;
+	return is_xa;
 }
 
 int sr_dev_ioctl(struct cdrom_device_info *cdi,
-                 unsigned int cmd, unsigned long arg)
+		 unsigned int cmd, unsigned long arg)
 {
-    int target;
-    
-    target = MINOR(cdi->dev);
-    
-    switch (cmd) {
-    case BLKROSET:
-    case BLKROGET:
-    case BLKRASET:
-    case BLKRAGET:
-    case BLKFLSBUF:
-    case BLKSSZGET:
-	return blk_ioctl(cdi->dev, cmd, arg);
-
-    default:
-	return scsi_ioctl(scsi_CDs[target].device,cmd,(void *) arg);
-    }
+	int target;
+
+	target = MINOR(cdi->dev);
+
+	switch (cmd) {
+	case BLKROSET:
+	case BLKROGET:
+	case BLKRASET:
+	case BLKRAGET:
+	case BLKFLSBUF:
+	case BLKSSZGET:
+		return blk_ioctl(cdi->dev, cmd, arg);
+
+	default:
+		return scsi_ioctl(scsi_CDs[target].device, cmd, (void *) arg);
+	}
 }
 
 /*
diff -u -r linux.clean/drivers/scsi/sr_vendor.c linux.new2/drivers/scsi/sr_vendor.c
--- linux.clean/drivers/scsi/sr_vendor.c	Sun Nov  7 16:35:21 1999
+++ linux.new2/drivers/scsi/sr_vendor.c	Sun Nov 14 10:16:36 1999
@@ -1,5 +1,5 @@
 /* -*-linux-c-*-
- *
+
  * vendor-specific code for SCSI CD-ROM's goes here.
  *
  * This is needed becauce most of the new features (multisession and
@@ -23,15 +23,15 @@
  *   - TOSHIBA: Detection and support of multisession CD's.
  *              Some XA-Sector tweaking, required for older drives.
  *
- *   - SONY:	Detection and support of multisession CD's.
+ *   - SONY:    Detection and support of multisession CD's.
  *              added by Thomas Quinot <thomas@cuivre.freenix.fr>
  *
  *   - PIONEER, HITACHI, PLEXTOR, MATSHITA, TEAC, PHILIPS: known to
  *              work with SONY (SCSI3 now)  code.
  *
- *   - HP:	Much like SONY, but a little different... (Thomas)
+ *   - HP:      Much like SONY, but a little different... (Thomas)
  *              HP-Writers only ??? Maybe other CD-Writers work with this too ?
- *		HP 6020 writers now supported.
+ *              HP 6020 writers now supported.
  */
 
 #include <linux/config.h>
@@ -47,16 +47,16 @@
 #include "sr.h"
 
 #if 0
-# define DEBUG
+#define DEBUG
 #endif
 
 /* here are some constants to sort the vendors into groups */
 
-#define VENDOR_SCSI3           1   /* default: scsi-3 mmc */
+#define VENDOR_SCSI3           1	/* default: scsi-3 mmc */
 
 #define VENDOR_NEC             2
 #define VENDOR_TOSHIBA         3
-#define VENDOR_WRITER          4   /* pre-scsi3 writers */
+#define VENDOR_WRITER          4	/* pre-scsi3 writers */
 
 #define VENDOR_ID (scsi_CDs[minor].vendor)
 
@@ -66,7 +66,7 @@
 	VENDOR_ID = VENDOR_SCSI3;
 #else
 	char *vendor = scsi_CDs[minor].device->vendor;
-	char *model  = scsi_CDs[minor].device->model;
+	char *model = scsi_CDs[minor].device->model;
 
 	/* default */
 	VENDOR_ID = VENDOR_SCSI3;
@@ -77,24 +77,24 @@
 	if (scsi_CDs[minor].device->type == TYPE_WORM) {
 		VENDOR_ID = VENDOR_WRITER;
 
-	} else if (!strncmp (vendor, "NEC", 3)) {
+	} else if (!strncmp(vendor, "NEC", 3)) {
 		VENDOR_ID = VENDOR_NEC;
-		if (!strncmp (model,"CD-ROM DRIVE:25", 15)  ||
-		    !strncmp (model,"CD-ROM DRIVE:36", 15)  ||
-		    !strncmp (model,"CD-ROM DRIVE:83", 15)  ||
-		    !strncmp (model,"CD-ROM DRIVE:84 ",16)
+		if (!strncmp(model, "CD-ROM DRIVE:25", 15) ||
+		    !strncmp(model, "CD-ROM DRIVE:36", 15) ||
+		    !strncmp(model, "CD-ROM DRIVE:83", 15) ||
+		    !strncmp(model, "CD-ROM DRIVE:84 ", 16)
 #if 0
-		        /* my NEC 3x returns the read-raw data if a read-raw
-		           is followed by a read for the same sector - aeb */
-		    || !strncmp (model,"CD-ROM DRIVE:500",16)
+		/* my NEC 3x returns the read-raw data if a read-raw
+		   is followed by a read for the same sector - aeb */
+		    || !strncmp(model, "CD-ROM DRIVE:500", 16)
 #endif
-		   )
+		    )
 			/* these can't handle multisession, may hang */
 			scsi_CDs[minor].cdi.mask |= CDC_MULTI_SESSION;
 
-	} else if (!strncmp (vendor, "TOSHIBA", 7)) {
+	} else if (!strncmp(vendor, "TOSHIBA", 7)) {
 		VENDOR_ID = VENDOR_TOSHIBA;
-		
+
 	}
 #endif
 }
@@ -105,10 +105,10 @@
 
 int sr_set_blocklength(int minor, int blocklength)
 {
-	unsigned char           *buffer;    /* the buffer for the ioctl */
-	unsigned char		cmd[12];    /* the scsi-command */
-	struct ccs_modesel_head	*modesel;
-	int			rc,density = 0;
+	unsigned char *buffer;	/* the buffer for the ioctl */
+	unsigned char cmd[12];	/* the scsi-command */
+	struct ccs_modesel_head *modesel;
+	int rc, density = 0;
 
 #ifdef CONFIG_BLK_DEV_SR_VENDOR
 	if (VENDOR_ID == VENDOR_TOSHIBA)
@@ -116,27 +116,29 @@
 #endif
 
 	buffer = (unsigned char *) scsi_malloc(512);
-	if (!buffer) return -ENOMEM;
+	if (!buffer)
+		return -ENOMEM;
 
 #ifdef DEBUG
-	printk("sr%d: MODE SELECT 0x%x/%d\n",minor,density,blocklength);
+	printk("sr%d: MODE SELECT 0x%x/%d\n", minor, density, blocklength);
 #endif
-	memset(cmd,0,12);
+	memset(cmd, 0, 12);
 	cmd[0] = MODE_SELECT;
 	cmd[1] = (scsi_CDs[minor].device->lun << 5) | (1 << 4);
 	cmd[4] = 12;
-	modesel = (struct ccs_modesel_head*)buffer;
-	memset(modesel,0,sizeof(*modesel));
+	modesel = (struct ccs_modesel_head *) buffer;
+	memset(modesel, 0, sizeof(*modesel));
 	modesel->block_desc_length = 0x08;
-	modesel->density           = density;
-	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)))
-		scsi_CDs[minor].sector_size = blocklength;
+	modesel->density = density;
+	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))) {
+		scsi_CDs[minor].device->sector_size = blocklength;
+	}
 #ifdef DEBUG
 	else
 		printk("sr%d: switching blocklength to %d bytes failed\n",
-		       minor,blocklength);
+		       minor, blocklength);
 #endif
 	scsi_free(buffer, 512);
 	return rc;
@@ -149,28 +151,27 @@
 
 int sr_cd_check(struct cdrom_device_info *cdi)
 {
-	unsigned long   sector;
-	unsigned char   *buffer;     /* the buffer for the ioctl */
-	unsigned char   cmd[12];     /* the scsi-command */
-	int             rc,no_multi,minor;
+	unsigned long sector;
+	unsigned char *buffer;	/* the buffer for the ioctl */
+	unsigned char cmd[12];	/* the scsi-command */
+	int rc, no_multi, minor;
 
 	minor = MINOR(cdi->dev);
 	if (scsi_CDs[minor].cdi.mask & CDC_MULTI_SESSION)
 		return 0;
-	
-	spin_lock_irq(&io_request_lock);
+
 	buffer = (unsigned char *) scsi_malloc(512);
-	spin_unlock_irq(&io_request_lock);
-	if(!buffer) return -ENOMEM;
-	
-	sector   = 0;         /* the multisession sector offset goes here  */
-	no_multi = 0;         /* flag: the drive can't handle multisession */
-	rc       = 0;
-    
-	switch(VENDOR_ID) {
-	
+	if (!buffer)
+		return -ENOMEM;
+
+	sector = 0;		/* the multisession sector offset goes here  */
+	no_multi = 0;		/* flag: the drive can't handle multisession */
+	rc = 0;
+
+	switch (VENDOR_ID) {
+
 	case VENDOR_SCSI3:
-		memset(cmd,0,12);
+		memset(cmd, 0, 12);
 		cmd[0] = READ_TOC;
 		cmd[1] = (scsi_CDs[minor].device->lun << 5);
 		cmd[8] = 12;
@@ -180,70 +181,70 @@
 			break;
 		if ((buffer[0] << 8) + buffer[1] < 0x0a) {
 			printk(KERN_INFO "sr%d: Hmm, seems the drive "
-			       "doesn't support multisession CD's\n",minor);
+			   "doesn't support multisession CD's\n", minor);
 			no_multi = 1;
 			break;
 		}
 		sector = buffer[11] + (buffer[10] << 8) +
-			(buffer[9] << 16) + (buffer[8] << 24);
+		    (buffer[9] << 16) + (buffer[8] << 24);
 		if (buffer[6] <= 1) {
 			/* ignore sector offsets from first track */
 			sector = 0;
 		}
 		break;
-		
+
 #ifdef CONFIG_BLK_DEV_SR_VENDOR
-	case VENDOR_NEC: {
-		unsigned long min,sec,frame;
-		memset(cmd,0,12);
-		cmd[0] = 0xde;
-		cmd[1] = (scsi_CDs[minor].device->lun << 5) | 0x03;
-		cmd[2] = 0xb0;
-		rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 1);
-		if (rc != 0)
-			break;
-		if (buffer[14] != 0 && buffer[14] != 0xb0) {
-			printk(KERN_INFO "sr%d: Hmm, seems the cdrom "
-			       "doesn't support multisession CD's\n",minor);
-			no_multi = 1;
+	case VENDOR_NEC:{
+			unsigned long min, sec, frame;
+			memset(cmd, 0, 12);
+			cmd[0] = 0xde;
+			cmd[1] = (scsi_CDs[minor].device->lun << 5) | 0x03;
+			cmd[2] = 0xb0;
+			rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 1);
+			if (rc != 0)
+				break;
+			if (buffer[14] != 0 && buffer[14] != 0xb0) {
+				printk(KERN_INFO "sr%d: Hmm, seems the cdrom "
+				       "doesn't support multisession CD's\n", minor);
+				no_multi = 1;
+				break;
+			}
+			min = BCD_TO_BIN(buffer[15]);
+			sec = BCD_TO_BIN(buffer[16]);
+			frame = BCD_TO_BIN(buffer[17]);
+			sector = min * CD_SECS * CD_FRAMES + sec * CD_FRAMES + frame;
 			break;
 		}
-		min    = BCD_TO_BIN(buffer[15]);
-		sec    = BCD_TO_BIN(buffer[16]);
-		frame  = BCD_TO_BIN(buffer[17]);
-		sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
-		break;
-	}
 
-	case VENDOR_TOSHIBA: {
-		unsigned long min,sec,frame;
+	case VENDOR_TOSHIBA:{
+			unsigned long min, sec, frame;
 
-		/* we request some disc information (is it a XA-CD ?,
-		 * where starts the last session ?) */
-		memset(cmd,0,12);
-		cmd[0] = 0xc7;
-		cmd[1] = (scsi_CDs[minor].device->lun << 5) | 3;
-		rc = sr_do_ioctl(minor, cmd, buffer, 4, 1);
-		if (rc == -EINVAL) {
-			printk(KERN_INFO "sr%d: Hmm, seems the drive "
-			       "doesn't support multisession CD's\n",minor);
-			no_multi = 1;
+			/* we request some disc information (is it a XA-CD ?,
+			 * where starts the last session ?) */
+			memset(cmd, 0, 12);
+			cmd[0] = 0xc7;
+			cmd[1] = (scsi_CDs[minor].device->lun << 5) | 3;
+			rc = sr_do_ioctl(minor, cmd, buffer, 4, 1);
+			if (rc == -EINVAL) {
+				printk(KERN_INFO "sr%d: Hmm, seems the drive "
+				       "doesn't support multisession CD's\n", minor);
+				no_multi = 1;
+				break;
+			}
+			if (rc != 0)
+				break;
+			min = BCD_TO_BIN(buffer[1]);
+			sec = BCD_TO_BIN(buffer[2]);
+			frame = BCD_TO_BIN(buffer[3]);
+			sector = min * CD_SECS * CD_FRAMES + sec * CD_FRAMES + frame;
+			if (sector)
+				sector -= CD_MSF_OFFSET;
+			sr_set_blocklength(minor, 2048);
 			break;
 		}
-		if (rc != 0)
-			break;
-		min    = BCD_TO_BIN(buffer[1]);
-		sec    = BCD_TO_BIN(buffer[2]);
-		frame  = BCD_TO_BIN(buffer[3]);
-		sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
-		if (sector)
-			sector -= CD_MSF_OFFSET;
-		sr_set_blocklength(minor,2048);
-		break;
-	}
 
 	case VENDOR_WRITER:
-		memset(cmd,0,12);
+		memset(cmd, 0, 12);
 		cmd[0] = READ_TOC;
 		cmd[1] = (scsi_CDs[minor].device->lun << 5);
 		cmd[8] = 0x04;
@@ -253,31 +254,29 @@
 			break;
 		}
 		if ((rc = buffer[2]) == 0) {
-			printk (KERN_WARNING
-				"sr%d: No finished session\n",minor);
+			printk(KERN_WARNING
+			       "sr%d: No finished session\n", minor);
 			break;
 		}
-
-		cmd[0] = READ_TOC; /* Read TOC */
+		cmd[0] = READ_TOC;	/* Read TOC */
 		cmd[1] = (scsi_CDs[minor].device->lun << 5);
-		cmd[6] = rc & 0x7f;  /* number of last session */
+		cmd[6] = rc & 0x7f;	/* number of last session */
 		cmd[8] = 0x0c;
 		cmd[9] = 0x40;
-		rc = sr_do_ioctl(minor, cmd, buffer, 12, 1);	
+		rc = sr_do_ioctl(minor, cmd, buffer, 12, 1);
 		if (rc != 0) {
 			break;
 		}
-
 		sector = buffer[11] + (buffer[10] << 8) +
-			(buffer[9] << 16) + (buffer[8] << 24);
+		    (buffer[9] << 16) + (buffer[8] << 24);
 		break;
-#endif /* CONFIG_BLK_DEV_SR_VENDOR */
+#endif				/* CONFIG_BLK_DEV_SR_VENDOR */
 
 	default:
 		/* should not happen */
 		printk(KERN_WARNING
-		       "sr%d: unknown vendor code (%i), not initialized ?\n",
-		       minor,VENDOR_ID);
+		   "sr%d: unknown vendor code (%i), not initialized ?\n",
+		       minor, VENDOR_ID);
 		sector = 0;
 		no_multi = 1;
 		break;
@@ -286,16 +285,17 @@
 	scsi_CDs[minor].xa_flag = 0;
 	if (CDS_AUDIO != sr_disk_status(cdi) && 1 == sr_is_xa(minor))
 		scsi_CDs[minor].xa_flag = 1;
-	
-	if (2048 != scsi_CDs[minor].sector_size)
-		sr_set_blocklength(minor,2048);
+
+	if (2048 != scsi_CDs[minor].device->sector_size) {
+		sr_set_blocklength(minor, 2048);
+	}
 	if (no_multi)
 		cdi->mask |= CDC_MULTI_SESSION;
 
 #ifdef DEBUG
 	if (sector)
 		printk(KERN_DEBUG "sr%d: multisession offset=%lu\n",
-		       minor,sector);
+		       minor, sector);
 #endif
 	scsi_free(buffer, 512);
 	return rc;
diff -u -r linux.clean/drivers/scsi/st.c linux.new2/drivers/scsi/st.c
--- linux.clean/drivers/scsi/st.c	Sun Nov  7 16:33:52 1999
+++ linux.new2/drivers/scsi/st.c	Sun Nov 14 09:01:03 1999
@@ -286,15 +286,13 @@
  st_do_scsi(Scsi_Cmnd * SCpnt, Scsi_Tape * STp, unsigned char *cmd, int bytes,
 	    int timeout, int retries, int do_wait)
 {
-	unsigned long flags;
 	unsigned char *bp;
 
-	spin_lock_irqsave(&io_request_lock, flags);
 	if (SCpnt == NULL)
-		if ((SCpnt = scsi_allocate_device(NULL, STp->device, 1)) == NULL) {
+		SCpnt = scsi_allocate_device(STp->device, 1);
+		if (SCpnt == NULL) {
 			printk(KERN_ERR "st%d: Can't get SCSI request.\n",
                                TAPE_NR(STp->devt));
-			spin_unlock_irqrestore(&io_request_lock, flags);
 			return NULL;
 		}
 
@@ -315,7 +313,6 @@
 
 	scsi_do_cmd(SCpnt, (void *) cmd, bp, bytes,
 		    st_sleep_done, timeout, retries);
-	spin_unlock_irqrestore(&io_request_lock, flags);
 
 	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	Tue Oct 19 19:56:18 1999
+++ linux.new2/include/linux/blk.h	Sun Nov 14 08:35:50 1999
@@ -157,9 +157,7 @@
 #elif (SCSI_DISK_MAJOR(MAJOR_NR))
 
 #define DEVICE_NAME "scsidisk"
-#define DEVICE_INTR do_sd  
 #define TIMEOUT_VALUE (2*HZ)
-#define DEVICE_REQUEST do_sd_request
 #define DEVICE_NR(device) (((MAJOR(device) & SD_MAJOR_MASK) << (8 - 4)) + (MINOR(device) >> 4))
 #define DEVICE_ON(device)
 #define DEVICE_OFF(device)
@@ -184,8 +182,6 @@
 #elif (MAJOR_NR == SCSI_CDROM_MAJOR)
 
 #define DEVICE_NAME "CD-ROM"
-#define DEVICE_INTR do_sr
-#define DEVICE_REQUEST do_sr_request
 #define DEVICE_NR(device) (MINOR(device))
 #define DEVICE_ON(device)
 #define DEVICE_OFF(device)
@@ -387,7 +383,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
@@ -421,7 +417,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	Sun Nov  7 16:35:24 1999
+++ linux.new2/include/linux/blkdev.h	Sun Nov  7 16:57:12 1999
@@ -27,6 +27,7 @@
 	unsigned long nr_sectors;
 	unsigned long nr_segments;
 	unsigned long current_nr_sectors;
+        void * special;
 	char * buffer;
 	struct semaphore * sem;
 	struct buffer_head * bh;
@@ -34,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 {
@@ -54,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	Sun Nov  7 16:35:24 1999
+++ linux.new2/include/linux/fs.h	Sun Nov  7 16:56:44 1999
@@ -62,6 +62,7 @@
 #define READ 0
 #define WRITE 1
 #define READA 2		/* read-ahead  - don't block if no resources */
+#define SPECIAL 4	/* For non-blockdevice requests in request queue */
 
 #define WRITERAW 5	/* raw write - don't play with buffer lists */
 
diff -u -r linux.clean/include/linux/ide.h linux.new2/include/linux/ide.h
--- linux.clean/include/linux/ide.h	Sun Nov  7 16:35:24 1999
+++ linux.new2/include/linux/ide.h	Sun Nov  7 17:00:09 1999
@@ -231,7 +231,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 */
@@ -728,7 +728,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,
@@ -741,33 +741,33 @@
 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
 #if MAX_HWIFS > 8
-void do_ide8_request (void);
+void do_ide8_request (request_queue_t * q);
 #endif
 #if MAX_HWIFS > 9
-void do_ide9_request (void);
+void do_ide9_request (request_queue_t * q);
 #endif
 void ide_init_subdrivers (void);
 
