patch-2.4.20 linux-2.4.20/drivers/scsi/scsi_merge.c

Next file: linux-2.4.20/drivers/scsi/scsi_scan.c
Previous file: linux-2.4.20/drivers/scsi/scsi_lib.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.19/drivers/scsi/scsi_merge.c linux-2.4.20/drivers/scsi/scsi_merge.c
@@ -6,6 +6,7 @@
  *                        Based upon conversations with large numbers
  *                        of people at Linux Expo.
  *	Support for dynamic DMA mapping: Jakub Jelinek (jakub@redhat.com).
+ *	Support for highmem I/O: Jens Axboe <axboe@suse.de>
  */
 
 /*
@@ -48,7 +49,6 @@
 #include <linux/delay.h>
 #include <linux/smp_lock.h>
 
-
 #define __KERNEL_SYSCALLS__
 
 #include <linux/unistd.h>
@@ -64,6 +64,12 @@
 #include <scsi/scsi_ioctl.h>
 
 /*
+ * scsi_malloc() can only dish out items of PAGE_SIZE or less, so we cannot
+ * build a request that requires an sg table allocation of more than that.
+ */
+static const int scsi_max_sg = PAGE_SIZE / sizeof(struct scatterlist);
+
+/*
  * This means that bounce buffers cannot be allocated in chunks > PAGE_SIZE.
  * Ultimately we should get away from using a dedicated DMA bounce buffer
  * pool, and we should instead try and use kmalloc() instead.  If we can
@@ -95,7 +101,7 @@
 		printk("Segment 0x%p, blocks %d, addr 0x%lx\n",
 		       bh,
 		       bh->b_size >> 9,
-		       virt_to_phys(bh->b_data - 1));
+		       bh_phys(bh) - 1);
 	}
 	panic("Ththththaats all folks.  Too dangerous to continue.\n");
 }
@@ -216,11 +222,10 @@
 			 * DMA capable host, make sure that a segment doesn't span
 			 * the DMA threshold boundary.  
 			 */
-			if (dma_host &&
-			    virt_to_phys(bhnext->b_data) - 1 == ISA_DMA_THRESHOLD) {
+			if (dma_host && bh_phys(bhnext) - 1 == ISA_DMA_THRESHOLD) {
 				ret++;
 				reqsize = bhnext->b_size;
-			} else if (CONTIGUOUS_BUFFERS(bh, bhnext)) {
+			} else if (blk_seg_merge_ok(bh, bhnext)) {
 				/*
 				 * This one is OK.  Let it go.
 				 */ 
@@ -234,8 +239,7 @@
 				 * kind of screwed and we need to start
 				 * another segment.
 				 */
-				if( dma_host
-				    && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD
+				if( dma_host && bh_phys(bh) - 1 >= ISA_DMA_THRESHOLD
 				    && reqsize + bhnext->b_size > PAGE_SIZE )
 				{
 					ret++;
@@ -297,7 +301,7 @@
 }
 
 #define MERGEABLE_BUFFERS(X,Y) \
-(((((long)(X)->b_data+(X)->b_size)|((long)(Y)->b_data)) & \
+(((((long)bh_phys((X))+(X)->b_size)|((long)bh_phys((Y)))) & \
   (DMA_CHUNK_SIZE - 1)) == 0)
 
 #ifdef DMA_CHUNK_SIZE
@@ -399,11 +403,11 @@
 {
 	unsigned int count;
 	unsigned int segment_size = 0;
-	Scsi_Device *SDpnt;
-	struct Scsi_Host *SHpnt;
+	Scsi_Device *SDpnt = q->queuedata;
+	struct Scsi_Host *SHpnt = SDpnt->host;
 
-	SDpnt = (Scsi_Device *) q->queuedata;
-	SHpnt = SDpnt->host;
+	if (max_segments > scsi_max_sg)
+		max_segments = scsi_max_sg;
 
 #ifdef DMA_CHUNK_SIZE
 	if (max_segments > 64)
@@ -413,6 +417,9 @@
 	if ((req->nr_sectors + (bh->b_size >> 9)) > SHpnt->max_sectors)
 		return 0;
 
+	if (!BH_PHYS_4G(req->bhtail, bh))
+		return 0;
+
 	if (use_clustering) {
 		/* 
 		 * See if we can do this without creating another
@@ -420,14 +427,11 @@
 		 * 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) {
+		if (dma_host && bh_phys(req->bhtail) - 1 == ISA_DMA_THRESHOLD)
 			goto new_end_segment;
-		}
-		if (CONTIGUOUS_BUFFERS(req->bhtail, bh)) {
+		if (BH_CONTIG(req->bhtail, bh)) {
 #ifdef DMA_SEGMENT_SIZE_LIMITED
-			if( dma_host
-			    && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD ) {
+			if (dma_host && bh_phys(bh) - 1 >= ISA_DMA_THRESHOLD) {
 				segment_size = 0;
 				count = __count_segments(req, use_clustering, dma_host, &segment_size);
 				if( segment_size + bh->b_size > PAGE_SIZE ) {
@@ -458,11 +462,11 @@
 {
 	unsigned int count;
 	unsigned int segment_size = 0;
-	Scsi_Device *SDpnt;
-	struct Scsi_Host *SHpnt;
+	Scsi_Device *SDpnt = q->queuedata;
+	struct Scsi_Host *SHpnt = SDpnt->host;
 
-	SDpnt = (Scsi_Device *) q->queuedata;
-	SHpnt = SDpnt->host;
+	if (max_segments > scsi_max_sg)
+		max_segments = scsi_max_sg;
 
 #ifdef DMA_CHUNK_SIZE
 	if (max_segments > 64)
@@ -472,6 +476,9 @@
 	if ((req->nr_sectors + (bh->b_size >> 9)) > SHpnt->max_sectors)
 		return 0;
 
+	if (!BH_PHYS_4G(bh, req->bh))
+		return 0;
+
 	if (use_clustering) {
 		/* 
 		 * See if we can do this without creating another
@@ -479,14 +486,12 @@
 		 * 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) {
+		if (dma_host && bh_phys(bh) - 1 == ISA_DMA_THRESHOLD) {
 			goto new_start_segment;
 		}
-		if (CONTIGUOUS_BUFFERS(bh, req->bh)) {
+		if (BH_CONTIG(bh, req->bh)) {
 #ifdef DMA_SEGMENT_SIZE_LIMITED
-			if( dma_host
-			    && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD ) {
+			if (dma_host && bh_phys(bh) - 1 >= ISA_DMA_THRESHOLD) {
 				segment_size = bh->b_size;
 				count = __count_segments(req, use_clustering, dma_host, &segment_size);
 				if( count != req->nr_segments ) {
@@ -593,8 +598,8 @@
 					     int use_clustering,
 					     int dma_host)
 {
-	Scsi_Device *SDpnt;
-	struct Scsi_Host *SHpnt;
+	Scsi_Device *SDpnt = q->queuedata;
+	struct Scsi_Host *SHpnt = SDpnt->host;
 
 	/*
 	 * First check if the either of the requests are re-queued
@@ -603,8 +608,8 @@
 	if (req->special || next->special)
 		return 0;
 
-	SDpnt = (Scsi_Device *) q->queuedata;
-	SHpnt = SDpnt->host;
+	if (max_segments > scsi_max_sg)
+		max_segments = scsi_max_sg;
 
 #ifdef DMA_CHUNK_SIZE
 	if (max_segments > 64)
@@ -634,6 +639,9 @@
 	if ((req->nr_sectors + next->nr_sectors) > SHpnt->max_sectors)
 		return 0;
 
+	if (!BH_PHYS_4G(req->bhtail, next->bh))
+		return 0;
+
 	/*
 	 * The main question is whether the two segments at the boundaries
 	 * would be considered one or two.
@@ -645,18 +653,15 @@
 		 * 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) {
+		if (dma_host && bh_phys(req->bhtail) - 1 == ISA_DMA_THRESHOLD)
 			goto dont_combine;
-		}
 #ifdef DMA_SEGMENT_SIZE_LIMITED
 		/*
 		 * We currently can only allocate scatter-gather bounce
 		 * buffers in chunks of PAGE_SIZE or less.
 		 */
-		if (dma_host
-		    && CONTIGUOUS_BUFFERS(req->bhtail, next->bh)
-		    && virt_to_phys(req->bhtail->b_data) - 1 >= ISA_DMA_THRESHOLD )
+		if (dma_host && BH_CONTIG(req->bhtail, next->bh)
+		    && bh_phys(req->bhtail) - 1 >= ISA_DMA_THRESHOLD)
 		{
 			int segment_size = 0;
 			int count = 0;
@@ -668,7 +673,7 @@
 			}
 		}
 #endif
-		if (CONTIGUOUS_BUFFERS(req->bhtail, next->bh)) {
+		if (BH_CONTIG(req->bhtail, next->bh)) {
 			/*
 			 * This one is OK.  Let it go.
 			 */
@@ -796,37 +801,13 @@
 	char		   * buff;
 	int		     count;
 	int		     i;
-	struct request     * req;
+	struct request     * req = &SCpnt->request;
 	int		     sectors;
 	struct scatterlist * sgpnt;
 	int		     this_count;
 	void		   ** bbpnt;
 
 	/*
-	 * 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) {
@@ -841,21 +822,27 @@
 	 * buffer.
 	 */
 	if (dma_host && scsi_dma_free_sectors <= 10) {
-		this_count = SCpnt->request.current_nr_sectors;
+		this_count = req->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;
+	 * we really want to use sg even for a single segment request,
+	 * however some people just cannot be bothered to write decent
+	 * driver code so we can't risk to break somebody making the
+	 * assumption that sg requests will always contain at least 2
+	 * segments. if the driver is 32-bit dma safe, then use sg for
+	 * 1 entry anyways. if not, don't rely on the driver handling this
+	 * case.
+ 	 */
+	if (count == 1 && !SCpnt->host->highmem_io) {
+		this_count = req->nr_sectors;
 		goto single_segment;
 	}
-	SCpnt->use_sg = count;
 
-	/* 
-	 * Allocate the actual scatter-gather table itself.
+	/*
+	 * for sane drivers, use sg even for 1 entry request
 	 */
+	SCpnt->use_sg = count;
 	SCpnt->sglist_len = (SCpnt->use_sg * sizeof(struct scatterlist));
 
 	/* If we could potentially require ISA bounce buffers, allocate
@@ -875,15 +862,25 @@
 	 * Now fill the scatter-gather table.
 	 */
 	if (!sgpnt) {
+#if 0
 		/*
 		 * 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;
+		this_count = req->current_nr_sectors;
 		goto single_segment;
+#else
+		/*
+		 * it's probably better to simply always back off a little,
+		 * and let some memory be returned to dma pool instead of
+		 * always falling back to (slow) single segments
+		 */
+		return 0;
+#endif
 	}
-	/* 
+
+	/*
 	 * Next, walk the list, and fill in the addresses and sizes of
 	 * each segment.
 	 */
@@ -900,13 +897,11 @@
 
 	SCpnt->bounce_buffers = bbpnt;
 
-	for (count = 0, bh = SCpnt->request.bh;
-	     bh; bh = bh->b_reqnext) {
+	for (count = 0, bh = req->bh; bh; bh = bh->b_reqnext) {
 		if (use_clustering && bhprev != NULL) {
-			if (dma_host &&
-			    virt_to_phys(bhprev->b_data) - 1 == ISA_DMA_THRESHOLD) {
+			if (dma_host && bh_phys(bhprev) - 1 == ISA_DMA_THRESHOLD) {
 				/* Nothing - fall through */
-			} else if (CONTIGUOUS_BUFFERS(bhprev, bh)) {
+			} else if (blk_seg_merge_ok(bhprev, bh)) {
 				/*
 				 * This one is OK.  Let it go.  Note that we
 				 * do not have the ability to allocate
@@ -915,7 +910,7 @@
 				 */
 				if( dma_host ) {
 #ifdef DMA_SEGMENT_SIZE_LIMITED
-					if( virt_to_phys(bh->b_data) - 1 < ISA_DMA_THRESHOLD
+					if (bh_phys(bh) - 1 < ISA_DMA_THRESHOLD
 					    || sgpnt[count - 1].length + bh->b_size <= PAGE_SIZE ) {
 						sgpnt[count - 1].length += bh->b_size;
 						bhprev = bh;
@@ -934,13 +929,25 @@
 				}
 			}
 		}
-		count++;
-		sgpnt[count - 1].address = bh->b_data;
-		sgpnt[count - 1].page = NULL;
-		sgpnt[count - 1].length += bh->b_size;
-		if (!dma_host) {
-			SCpnt->request_bufflen += bh->b_size;
+
+		if (SCpnt->host->highmem_io) {
+			sgpnt[count].page = bh->b_page;
+			sgpnt[count].offset = bh_offset(bh);
+			sgpnt[count].address = NULL;
+		} else {
+			if (PageHighMem(bh->b_page))
+				BUG();
+
+			sgpnt[count].page = NULL;
+			sgpnt[count].address = bh->b_data;
 		}
+		
+		sgpnt[count].length = bh->b_size;
+
+		if (!dma_host)
+			SCpnt->request_bufflen += bh->b_size;
+
+		count++;
 		bhprev = bh;
 	}
 
@@ -963,6 +970,10 @@
 	for (i = 0; i < count; i++) {
 		sectors = (sgpnt[i].length >> 9);
 		SCpnt->request_bufflen += sgpnt[i].length;
+		/*
+		 * only done for dma_host, in which case .page is not
+		 * set since it's guarenteed to be a low memory page
+		 */
 		if (virt_to_phys(sgpnt[i].address) + sgpnt[i].length - 1 >
 		    ISA_DMA_THRESHOLD) {
 			if( scsi_dma_free_sectors - sectors <= 10  ) {
@@ -998,7 +1009,7 @@
 				}
 				break;
 			}
-			if (SCpnt->request.cmd == WRITE) {
+			if (req->cmd == WRITE) {
 				memcpy(sgpnt[i].address, bbpnt[i],
 				       sgpnt[i].length);
 			}
@@ -1043,8 +1054,7 @@
 	 * single-block requests if we had hundreds of free sectors.
 	 */
 	if( scsi_dma_free_sectors > 30 ) {
-		for (this_count = 0, bh = SCpnt->request.bh;
-		     bh; bh = bh->b_reqnext) {
+		for (this_count = 0, bh = req->bh; bh; bh = bh->b_reqnext) {
 			if( scsi_dma_free_sectors - this_count < 30 
 			    || this_count == sectors )
 			{
@@ -1057,21 +1067,32 @@
 		/*
 		 * Yow!   Take the absolute minimum here.
 		 */
-		this_count = SCpnt->request.current_nr_sectors;
+		this_count = req->current_nr_sectors;
 	}
 
 	/*
 	 * Now drop through into the single-segment case.
 	 */
 	
-      single_segment:
+single_segment:
+	/*
+	 * for highmem cases, we have to revert to bouncing for single
+	 * segments. rather just give up now and let the device starvation
+	 * path reinitiate this i/o later
+	 */
+	if (SCpnt->host->highmem_io)
+		return 0;
+
 	/*
 	 * 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;
+	bh = req->bh;
+	buff = req->buffer = bh->b_data;
+
+	if (PageHighMem(bh->b_page))
+		BUG();
 
 	if (dma_host) {
 		/*
@@ -1079,21 +1100,21 @@
 		 * 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) {
+		if (bh_phys(bh) + (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;
+				this_count = req->current_nr_sectors;
 				buff = (char *) scsi_malloc(this_count << 9);
 				if (!buff) {
 					dma_exhausted(SCpnt, 0);
 				}
 			}
-			if (SCpnt->request.cmd == WRITE)
-				memcpy(buff, (char *) SCpnt->request.buffer, this_count << 9);
+			if (req->cmd == WRITE)
+				memcpy(buff, (char *) req->buffer, this_count << 9);
 		}
 	}
+
 	SCpnt->request_bufflen = this_count << 9;
 	SCpnt->request_buffer = buff;
 	SCpnt->use_sg = 0;
@@ -1132,21 +1153,11 @@
  */
 void initialize_merge_fn(Scsi_Device * SDpnt)
 {
-	request_queue_t *q;
-	struct Scsi_Host *SHpnt;
-	SHpnt = SDpnt->host;
-
-	q = &SDpnt->request_queue;
+	struct Scsi_Host *SHpnt = SDpnt->host;
+	request_queue_t *q = &SDpnt->request_queue;
+	dma64_addr_t bounce_limit;
 
 	/*
-	 * If the host has already selected a merge manager, then don't
-	 * pick a new one.
-	 */
-#if 0
-	if (q->back_merge_fn && q->front_merge_fn)
-		return;
-#endif
-	/*
 	 * 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.
@@ -1178,4 +1189,20 @@
 		q->merge_requests_fn = scsi_merge_requests_fn_dc;
 		SDpnt->scsi_init_io_fn = scsi_init_io_vdc;
 	}
+
+	/*
+	 * now enable highmem I/O, if appropriate
+	 */
+	bounce_limit = BLK_BOUNCE_HIGH;
+	if (SHpnt->highmem_io && (SDpnt->type == TYPE_DISK)) {
+		if (!PCI_DMA_BUS_IS_PHYS)
+			/* Platforms with virtual-DMA translation
+ 			 * hardware have no practical limit.
+			 */
+			bounce_limit = BLK_BOUNCE_ANY;
+		else
+			bounce_limit = SHpnt->pci_dev->dma_mask;
+	}
+
+	blk_queue_bounce_limit(q, bounce_limit);
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)