---
 drivers/scsi/aha152x.c |  297 ++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 259 insertions(+), 38 deletions(-)

--- linux-2617-rc1g7.orig/drivers/scsi/aha152x.c
+++ linux-2617-rc1g7/drivers/scsi/aha152x.c
@@ -241,12 +241,16 @@
 #include <asm/io.h>
 #include <linux/blkdev.h>
 #include <asm/system.h>
+#include <linux/compiler.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/wait.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
+#include <linux/preempt.h>
 #include <linux/proc_fs.h>
+#include <linux/hardirq.h>
+#include <linux/highmem.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -260,6 +264,7 @@
 #include <scsi/scsi_dbg.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport_spi.h>
+#define AHA152X_DEBUG
 #include "aha152x.h"
 
 
@@ -277,7 +282,8 @@
 #endif
 
 #if defined(AHA152X_DEBUG)
-#define DEBUG_DEFAULT debug_eh
+///#define DEBUG_DEFAULT debug_eh
+#define DEBUG_DEFAULT (debug_queue | debug_datai | debug_datao)
 
 #define DPRINTK(when,msgs...) \
 	do { if(HOSTDATA(shpnt)->debug & (when)) printk(msgs); } while(0)
@@ -287,18 +293,18 @@
 		if(spin_is_locked(&QLOCK)) { \
 			DPRINTK(debug_intr, DEBUG_LEAD "(%s:%d) already locked at %s:%d\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
 		} \
-		DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+		/*DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__);*/ \
 		spin_lock_irqsave(&QLOCK,flags); \
-		DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) locked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+		/*DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) locked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__);*/ \
 		QLOCKER=__FUNCTION__; \
 		QLOCKERL=__LINE__; \
 	} while(0)
 
 #define DO_UNLOCK(flags)	\
 	do { \
-		DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) unlocking (locked at %s:%d)\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
+		/*DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) unlocking (locked at %s:%d)\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL);*/ \
 		spin_unlock_irqrestore(&QLOCK,flags); \
-		DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) unlocked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+		/*DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) unlocked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__);*/ \
 		QLOCKER="(not locked)"; \
 		QLOCKERL=0; \
 	} while(0)
@@ -353,6 +359,10 @@ MODULE_AUTHOR("Jürgen Fischer");
 MODULE_DESCRIPTION(AHA152X_REVID);
 MODULE_LICENSE("GPL");
 
+int isa_dma;
+module_param(isa_dma, bool, 0644);
+MODULE_PARM_DESC(isa_dma, "Use only (ISA) low memory for DMA");
+
 #if !defined(PCMCIA)
 #if defined(MODULE)
 static int io[] = {0, 0};
@@ -541,6 +551,17 @@ struct aha152x_hostdata {
 #ifdef __ISAPNP__
 	struct pnp_dev *pnpdev;
 #endif
+
+	/* use these during datao_init/run/end() to keep from overwriting
+	 * the valid data in case a "resend" must be done */
+	char *out_ptr;
+		/* temp. buffer pointer during data-out phase */
+	int out_this_residual;
+		/* temp. buffer length during data-out phase */
+	struct scatterlist *out_buffer;
+		/* temp. next buffer during data-out phase */
+	int out_buffers_residual;
+		/* temp. left buffers in list during data-out phase */
 };
 
 
@@ -604,7 +625,8 @@ struct aha152x_scdata {
 #define SCNEXT(SCpnt)		SCDATA(SCpnt)->next
 #define SCSEM(SCpnt)		SCDATA(SCpnt)->sem
 
-#define SG_ADDRESS(buffer)	((char *) (page_address((buffer)->page)+(buffer)->offset))
+///#define SG_ADDRESS(buffer)	((char *) (page_address((buffer)->page)+(buffer)->offset))
+#define SG_ADDRESS(buffer)	(char *)(buffer)
 
 /* state handling */
 static void seldi_run(struct Scsi_Host *shpnt);
@@ -780,11 +802,16 @@ struct Scsi_Host *aha152x_probe_one(stru
 {
 	struct Scsi_Host *shpnt;
 
+	aha152x_driver_template.unchecked_isa_dma = isa_dma;
+	printk(KERN_INFO "%s: using isa_dma = %d\n", __FUNCTION__, isa_dma);
 	shpnt = scsi_host_alloc(&aha152x_driver_template, sizeof(struct aha152x_hostdata));
 	if (!shpnt) {
 		printk(KERN_ERR "aha152x: scsi_host_alloc failed\n");
 		return NULL;
 	}
+	if (shpnt->unchecked_isa_dma != isa_dma)
+		printk(KERN_DEBUG "%s: shpnt isa_dma flag (%d) is bad, should be %d\n",
+			__FUNCTION__, shpnt->unchecked_isa_dma, isa_dma);
 
 	/* need to have host registered before triggering any interrupt */
 	aha152x_host[registered_count] = shpnt;
@@ -947,24 +974,24 @@ static int setup_expected_interrupts(str
 		CURRENT_SC->SCp.phase |= 1 << 16;
 	
 		if(CURRENT_SC->SCp.phase & selecting) {
-			DPRINTK(debug_intr, DEBUG_LEAD "expecting: (seldo) (seltimo) (seldi)\n", CMDINFO(CURRENT_SC));
+			///DPRINTK(debug_intr, DEBUG_LEAD "expecting: (seldo) (seltimo) (seldi)\n", CMDINFO(CURRENT_SC));
 			SETPORT(SSTAT1, SELTO);
 			SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
 			SETPORT(SIMODE1, ENSELTIMO);
 		} else {
-			DPRINTK(debug_intr, DEBUG_LEAD "expecting: (phase change) (busfree) %s\n", CMDINFO(CURRENT_SC), CURRENT_SC->SCp.phase & spiordy ? "(spiordy)" : "");
+			///DPRINTK(debug_intr, DEBUG_LEAD "expecting: (phase change) (busfree) %s\n", CMDINFO(CURRENT_SC), CURRENT_SC->SCp.phase & spiordy ? "(spiordy)" : "");
 			SETPORT(SIMODE0, (CURRENT_SC->SCp.phase & spiordy) ? ENSPIORDY : 0);
 			SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); 
 		}
 	} else if(STATE==seldi) {
-		DPRINTK(debug_intr, DEBUG_LEAD "expecting: (phase change) (identify)\n", CMDINFO(CURRENT_SC));
+		///DPRINTK(debug_intr, DEBUG_LEAD "expecting: (phase change) (identify)\n", CMDINFO(CURRENT_SC));
 		SETPORT(SIMODE0, 0);
 		SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); 
 	} else {
-		DPRINTK(debug_intr, DEBUG_LEAD "expecting: %s %s\n",
-			CMDINFO(CURRENT_SC),
-			DISCONNECTED_SC ? "(reselection)" : "",
-			ISSUE_SC ? "(busfree)" : "");
+		///DPRINTK(debug_intr, DEBUG_LEAD "expecting: %s %s\n",
+			///CMDINFO(CURRENT_SC),
+			///DISCONNECTED_SC ? "(reselection)" : "",
+			///ISSUE_SC ? "(busfree)" : "");
 		SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
 		SETPORT(SIMODE1, ENSCSIRST | ( (ISSUE_SC||DONE_SC) ? ENBUSFREE : 0));
 	}
@@ -975,6 +1002,23 @@ static int setup_expected_interrupts(str
 	return TESTHI(DMASTAT, INTSTAT);
 }
 
+#if defined(AHA152X_DEBUG)
+void dump_sg(struct scsi_cmnd *scp)
+{
+	int ix;
+	struct scatterlist *sg = scp->request_buffer;
+
+	printk(KERN_DEBUG
+		"sg_list ptr: 0x%p, total buff_len: 0x%x, segs: %d\n",
+		scp->request_buffer, scp->request_bufflen, scp->use_sg);
+	for (ix = 0; ix < scp->use_sg; ix++, sg++)
+		printk(KERN_DEBUG "[%d]: page: 0x%p(%c), offset: 0x%x, dma_adr: 0x%llx, len: 0x%x\n",
+			ix, sg->page,
+			PageHighMem(sg->page) ? 'H' : 'L',
+			sg->offset,
+			(unsigned long long)sg->dma_address, sg->length);
+}
+#endif
 
 /* 
  *  Queue a command and setup interrupts for a free bus.
@@ -985,7 +1029,7 @@ static int aha152x_internal_queue(Scsi_C
 	unsigned long flags;
 
 #if defined(AHA152X_DEBUG)
-	if (HOSTDATA(shpnt)->debug & debug_queue) {
+	if (/*HOSTDATA(shpnt)->debug &*/ debug_queue) {
 		printk(INFO_LEAD "queue: %p; cmd_len=%d pieces=%d size=%u cmnd=",
 		       CMDINFO(SCpnt), SCpnt, SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen);
 		__scsi_print_command(SCpnt->cmnd);
@@ -1027,6 +1071,11 @@ static int aha152x_internal_queue(Scsi_C
 		SCpnt->SCp.ptr              = SG_ADDRESS(SCpnt->SCp.buffer);
 		SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
 		SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
+#if defined(AHA152X_DEBUG)
+		printk("%s: got SG_ADDRESS = 0x%p\n",
+			__FUNCTION__, SCpnt->SCp.ptr);
+		dump_sg(SCpnt);
+#endif
 	} else {
 		SCpnt->SCp.ptr              = (char *) SCpnt->request_buffer;
 		SCpnt->SCp.this_residual    = SCpnt->request_bufflen;
@@ -2183,15 +2232,24 @@ static void datai_init(struct Scsi_Host 
 	SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE);
 
 	DATA_LEN=0;
-	DPRINTK(debug_datai,
-		DEBUG_LEAD "datai_init: request_bufflen=%d resid=%d\n",
-		CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid);
+	///DPRINTK(debug_datai,
+		///DEBUG_LEAD "datai_init: request_bufflen=%d resid=%d\n",
+		///CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid);
+#if defined(AHA152X_DEBUG)
+	if (/*HOSTDATA(shpnt)->debug &*/ debug_datai)
+		printk(KERN_DEBUG "%s: %p; " LEAD ", cmd_len=%d pieces=%d size=%u\n",
+			__FUNCTION__, CURRENT_SC, CMDINFO(CURRENT_SC),
+			CURRENT_SC->cmd_len, CURRENT_SC->use_sg,
+			CURRENT_SC->request_bufflen);
+#endif
 }
 
 static void datai_run(struct Scsi_Host *shpnt)
 {
 	unsigned long the_time;
 	int fifodata, data_count;
+	void *virt = NULL, *virt_save = NULL;
+	unsigned long flags = 0;
 
 	/*
 	 * loop while the phase persists or the fifos are not empty
@@ -2229,6 +2287,32 @@ static void datai_run(struct Scsi_Host *
 		}
 
 		if(CURRENT_SC->SCp.this_residual>0) {
+			if (CURRENT_SC->use_sg) {
+				void  *base;
+				size_t offset, offset_in, sg_len;
+
+				sg_len = CURRENT_SC->SCp.this_residual;
+				offset = CURRENT_SC->request_bufflen -
+					CURRENT_SC->SCp.this_residual;
+				offset_in = offset;
+				local_irq_save(flags);
+				base = scsi_kmap_atomic_sg(
+					CURRENT_SC->request_buffer,
+					CURRENT_SC->use_sg,
+					&offset, &sg_len);
+				if (!base) {
+					local_irq_restore(flags);
+					goto chkfifo;
+				}
+				virt = base + offset;
+				virt_save = base;
+				CURRENT_SC->SCp.ptr = virt;
+				///printk(KERN_DEBUG "%s: kmap: sg offset_in: 0x%x, offset out: 0x%x, len: 0x%x, base: 0x%p, virt: 0x%p\n",
+					///__FUNCTION__, offset_in, offset,
+					///sg_len, base, virt);
+			} else
+				virt = CURRENT_SC->SCp.ptr;
+
 			while(fifodata>0 && CURRENT_SC->SCp.this_residual>0) {
                         	data_count = fifodata>CURRENT_SC->SCp.this_residual ?
 						CURRENT_SC->SCp.this_residual :
@@ -2238,27 +2322,46 @@ static void datai_run(struct Scsi_Host *
                         	if(data_count & 1) {
 					DPRINTK(debug_datai, DEBUG_LEAD "8bit\n", CMDINFO(CURRENT_SC));
                                 	SETPORT(DMACNTRL0, ENDMA|_8BIT);
-                                	*CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT);
+                                	*(char *)virt = GETPORT(DATAPORT);
+					virt++;
                                 	CURRENT_SC->SCp.this_residual--;
                                 	DATA_LEN++;
                                 	SETPORT(DMACNTRL0, ENDMA);
                         	}
 	
                         	if(data_count > 1) {
-					DPRINTK(debug_datai, DEBUG_LEAD "16bit(%d)\n", CMDINFO(CURRENT_SC), data_count);
+					///DPRINTK(debug_datai, DEBUG_LEAD "16bit(%d)\n", CMDINFO(CURRENT_SC), data_count);
                                 	data_count >>= 1;
-                                	insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
-                                	CURRENT_SC->SCp.ptr           += 2 * data_count;
+                                	insw(DATAPORT, virt, data_count);
+                                	virt                          += 2 * data_count;
                                 	CURRENT_SC->SCp.this_residual -= 2 * data_count;
                                 	DATA_LEN                      += 2 * data_count;
                         	}
-	
+				CURRENT_SC->SCp.ptr = virt;
+				if (CURRENT_SC->use_sg) {
+					flush_kernel_dcache_page(kmap_atomic_to_page(virt_save));
+					scsi_kunmap_atomic_sg(virt_save);
+					local_irq_restore(flags);
+#if 0 /// defined(AHA152X_DEBUG)
+					printk(KERN_DEBUG "%s: kunmap: 0x%p\n",
+						__FUNCTION__, virt_save);
+#endif
+					virt_save = NULL;
+				}
+
                         	if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) {
                                		/* advance to next buffer */
                                		CURRENT_SC->SCp.buffers_residual--;
                                		CURRENT_SC->SCp.buffer++;
-                               		CURRENT_SC->SCp.ptr           = SG_ADDRESS(CURRENT_SC->SCp.buffer);
+					if (!CURRENT_SC->use_sg)
+                               			CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer);
                                		CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
+#if defined(AHA152X_DEBUG)
+					printk("%s: next buffer SG_ADDRESS = 0x%p, buf_resid=0x%x, this_resid=0x%x\n",
+						__FUNCTION__, CURRENT_SC->SCp.ptr,
+						CURRENT_SC->SCp.buffers_residual,
+						CURRENT_SC->SCp.this_residual);
+#endif
 				} 
                 	}
 		} else if(fifodata>0) { 
@@ -2274,7 +2377,18 @@ static void datai_run(struct Scsi_Host *
                         SETPORT(DMACNTRL0, ENDMA|_8BIT);
 		}
 	}
+	if (virt_save) {
+		flush_kernel_dcache_page(kmap_atomic_to_page(virt_save));
+		scsi_kunmap_atomic_sg(virt_save);
+		local_irq_restore(flags);
+#if 0 /// defined(AHA152X_DEBUG)
+		printk(KERN_DEBUG "%s: kunmap/extra: 0x%p\n",
+			__FUNCTION__, virt_save);
+#endif
+		virt_save = NULL;
+	}
 
+chkfifo:
 	if(TESTLO(DMASTAT, INTSTAT) ||
 	   TESTLO(DMASTAT, DFIFOEMP) ||
 	   TESTLO(SSTAT2, SEMPTY) ||
@@ -2325,15 +2439,28 @@ static void datao_init(struct Scsi_Host 
 
 	DATA_LEN = CURRENT_SC->resid;
 
-	DPRINTK(debug_datao,
-		DEBUG_LEAD "datao_init: request_bufflen=%d; resid=%d\n",
-		CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid);
+	///DPRINTK(debug_datao,
+		///DEBUG_LEAD "datao_init: request_bufflen=%d; resid=%d\n",
+		///CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid);
+#if defined(AHA152X_DEBUG)
+	if (/*HOSTDATA(shpnt)->debug &*/ debug_datao)
+		printk(KERN_DEBUG "%s: %p; " LEAD ", cmd_len=%d pieces=%d size=%u\n",
+			__FUNCTION__, CURRENT_SC, CMDINFO(CURRENT_SC),
+			CURRENT_SC->cmd_len, CURRENT_SC->use_sg,
+			CURRENT_SC->request_bufflen);
+#endif
 }
 
+static char *last_virt, *last_ptr;
+static int last_this_resid, last_buf_resid;
+static struct scatterlist *last_buffer, *last_req_buf;
+
 static void datao_run(struct Scsi_Host *shpnt)
 {
 	unsigned long the_time;
 	int data_count;
+	void *virt = NULL, *virt_save = NULL;
+	unsigned long flags = 0;
 
 	/* until phase changes or all data sent */
 	while(TESTLO(DMASTAT, INTSTAT) && CURRENT_SC->SCp.this_residual>0) {
@@ -2347,9 +2474,43 @@ static void datao_run(struct Scsi_Host *
 			break;
 		}
 
+		if (CURRENT_SC->use_sg) {
+			void  *base;
+			size_t offset, offset_in, sg_len;
+
+			sg_len = CURRENT_SC->SCp.this_residual;
+			offset = CURRENT_SC->request_bufflen -
+				CURRENT_SC->SCp.this_residual;
+			offset_in = offset;
+			local_irq_save(flags);
+			base = scsi_kmap_atomic_sg(
+				CURRENT_SC->request_buffer,
+				CURRENT_SC->use_sg, &offset, &sg_len);
+			if (!base) {
+				local_irq_restore(flags);
+				printk("%s: kmap_atomic ret. NULL\n",
+					__FUNCTION__);
+				break;
+			}
+			virt = base + offset;
+			CURRENT_SC->SCp.ptr = virt;
+			virt_save = base;
+			last_virt = virt;
+			last_ptr = CURRENT_SC->SCp.ptr;
+			last_this_resid = CURRENT_SC->SCp.this_residual;
+			last_buf_resid = CURRENT_SC->SCp.buffers_residual;
+			last_buffer = CURRENT_SC->SCp.buffer;
+			last_req_buf = CURRENT_SC->request_buffer;
+			///printk(KERN_DEBUG "%s: kmap: sg offset_in: 0x%x, offset out: 0x%x, len: 0x%x, base: 0x%p, virt: 0x%p\n",
+				///__FUNCTION__, offset_in, offset,
+				///sg_len, base, virt);
+		} else
+			virt = CURRENT_SC->SCp.ptr;
+
 		if(data_count & 1) {
 			SETPORT(DMACNTRL0,WRITE_READ|ENDMA|_8BIT);
-			SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++);
+			SETPORT(DATAPORT, *(char *)virt);
+			virt++;
 			CURRENT_SC->SCp.this_residual--;
 			CURRENT_SC->resid--;
 			SETPORT(DMACNTRL0,WRITE_READ|ENDMA);
@@ -2357,18 +2518,42 @@ static void datao_run(struct Scsi_Host *
 
 		if(data_count > 1) {
 			data_count >>= 1;
-			outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
-			CURRENT_SC->SCp.ptr           += 2 * data_count;
+			outsw(DATAPORT, virt, data_count);
+			virt                          += 2 * data_count;
 			CURRENT_SC->SCp.this_residual -= 2 * data_count;
 			CURRENT_SC->resid             -= 2 * data_count;
 	  	}
+		CURRENT_SC->SCp.ptr = virt;
+
+		if (CURRENT_SC->use_sg) {
+			scsi_kunmap_atomic_sg(virt_save);
+			local_irq_restore(flags);
+#if 0 /// defined(AHA152X_DEBUG)
+			printk(KERN_DEBUG "%s: kunmap: 0x%p\n",
+				__FUNCTION__, virt_save);
+#endif
+			virt_save = NULL;
+		}
 
 		if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) {
 			/* advance to next buffer */
 			CURRENT_SC->SCp.buffers_residual--;
 			CURRENT_SC->SCp.buffer++;
-			CURRENT_SC->SCp.ptr           = SG_ADDRESS(CURRENT_SC->SCp.buffer);
+			if (!CURRENT_SC->use_sg)
+				CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer);
 			CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
+#if defined(AHA152X_DEBUG)
+			printk("%s: next buffer SG_ADDRESS(!) = 0x%p, buf_resid=0x%x, this_resid=0x%x\n",
+				__FUNCTION__, CURRENT_SC->SCp.ptr,
+				CURRENT_SC->SCp.buffers_residual,
+				CURRENT_SC->SCp.this_residual);
+#endif
+		} else {
+#if defined(AHA152X_DEBUG)
+			printk("%s: not advance to next buffer: this_resid: 0x%x, buffers_resid: 0x%x\n",
+				__FUNCTION__, CURRENT_SC->SCp.this_residual,
+				CURRENT_SC->SCp.buffers_residual);
+#endif
 		}
 
 		the_time=jiffies + 100*HZ;
@@ -2381,8 +2566,32 @@ static void datao_run(struct Scsi_Host *
 			break;
 		}
 	}
+	if (virt_save) {
+		scsi_kunmap_atomic_sg(virt_save);
+		local_irq_restore(flags);
+#if 0 /// defined(AHA152X_DEBUG)
+		printk(KERN_DEBUG "%s: kunmap/extra: 0x%p\n",
+			__FUNCTION__, virt_save);
+#endif
+		virt_save = NULL;
+	}
+#if defined(AHA152X_DEBUG)
+	printk(KERN_DEBUG "%s: exit while loop: DMASTAT: 0x%x, this_resid: 0x%x\n",
+		__FUNCTION__, GETPORT(DMASTAT),
+		CURRENT_SC->SCp.this_residual);
+#endif
 }
 
+#ifdef DOC_ONLY
+
+1.  don't use SG_ADDRESS at all (nor page_address)
+2.  use a temp SCp.ptr during datao_run so that datao_end can do the
+	"resend" logic easily:  determine what needs to be saved & then
+	restored in "resend";
+3.  don't use SCp.ptr as an input value in use_sg mode
+
+#endif // DOC_ONLY
+
 static void datao_end(struct Scsi_Host *shpnt)
 {
 	if(TESTLO(DMASTAT, DFIFOEMP)) {
@@ -2394,17 +2603,27 @@ static void datao_end(struct Scsi_Host *
 			DATA_LEN-CURRENT_SC->resid,
 			GETSTCNT());
 
+		DPRINTK(debug_datao, "%s: update curr->resid from 0x%x to 0x%x\n",
+			__FUNCTION__, CURRENT_SC->resid,
+			CURRENT_SC->resid + data_count);
 		CURRENT_SC->resid += data_count;
 
 		if(CURRENT_SC->use_sg) {
-			data_count -= CURRENT_SC->SCp.ptr - SG_ADDRESS(CURRENT_SC->SCp.buffer);
-			while(data_count>0) {
-				CURRENT_SC->SCp.buffer--;
-				CURRENT_SC->SCp.buffers_residual++;
-				data_count -= CURRENT_SC->SCp.buffer->length;
-			}
-			CURRENT_SC->SCp.ptr           = SG_ADDRESS(CURRENT_SC->SCp.buffer) - data_count;
-			CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length + data_count;
+			///data_count -= CURRENT_SC->SCp.ptr - SG_ADDRESS(CURRENT_SC->SCp.buffer);
+			CURRENT_SC->SCp.ptr = last_ptr;
+			CURRENT_SC->SCp.this_residual = last_this_resid;
+			CURRENT_SC->SCp.buffers_residual = last_buf_resid;
+			CURRENT_SC->SCp.buffer = last_buffer;
+			CURRENT_SC->request_buffer = last_req_buf;
+#if defined(AHA152X_DEBUG)
+			printk(KERN_DEBUG "%s: restored to: ptr = 0x%p, last_buffer(sg) = 0x%p, last_req_buf = 0x%p, this_resid = 0x%x, buf_resid = 0x%x\n",
+				__FUNCTION__, last_ptr, last_buffer,
+				last_req_buf, last_this_resid, last_buf_resid);
+#endif
+			///CURRENT_SC->SCp.buffer--;
+			///CURRENT_SC->SCp.buffers_residual++;
+			///CURRENT_SC->SCp.ptr           = SG_ADDRESS(CURRENT_SC->SCp.buffer) - data_count;
+			///CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length + data_count;
 		} else {
 			CURRENT_SC->SCp.ptr           -= data_count;
 			CURRENT_SC->SCp.this_residual += data_count;
@@ -3735,6 +3954,8 @@ static int __init aha152x_init(void)
 	    		setup[setup_count].ext_trans   = exttrans[0];
 #if defined(AHA152X_DEBUG)
 			setup[setup_count].debug       = debug[0];
+			printk(KERN_DEBUG "%s: set debug to 0x%x\n",
+				__FUNCTION__, debug[0]);
 #endif
 		}
 
