Subject: port-i386/1477: Add bounce buffers to ISA DMA
To: None <gnats-bugs@gnats.netbsd.org>
From: Juergen Hannken-Illjes <hannken@eis.cs.tu-bs.de>
List: netbsd-bugs
Date: 09/19/1995 11:51:02
>Number:         1477
>Category:       port-i386
>Synopsis:       Add bounce buffers to ISA DMA
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    gnats-admin (GNATS administrator)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Tue Sep 19 06:05:02 1995
>Last-Modified:
>Originator:     Juergen Hannken-Illjes
>Organization:
	TU Braunschweig - EIS - Germany
>Release:        NetBSD-current as of Sep, 16. tarballs
>Environment:
System: NetBSD home 1.0A NetBSD 1.0A (CUSTOM) #73: Mon Sep 18 09:41:18 MET DST 1995 hannken@home:/usr/users/hannken/sys/arch/i386/compile/CUSTOM i386
>Description:
	NetBSD/I386 is missing bounce buffers for busmaster DMA.
	The hostmaster DMA code is not as good as it should be
	because DMA is only possible up to PAGESIZE bytes.
>How-To-Repeat:
>Fix:
Patch relative to Sep, 16. NetBSD-current sources.

fd.c and aha1542.c have been updated to use the new DMA mapper. I cannot
test other drivers because I don't own the corresponding devices. The tail
of isadmavar.h contains some #defines to let drivers use the old interface.
If a driver doesn't call isadma_done() a warning is sent to syslog.

--- sys/dev/isa/isadma.c.orig	Tue Apr 18 12:16:35 1995
+++ sys/dev/isa/isadma.c	Sun Sep 17 17:10:22 1995
@@ -15,30 +15,33 @@
 #include <dev/isa/isareg.h>
 #include <dev/isa/isadmavar.h>
 #include <dev/isa/isadmareg.h>
 
-/* region of physical memory known to be contiguous */
-vm_offset_t isaphysmem;
-static caddr_t dma_bounce[8];		/* XXX */
-static char bounced[8];		/* XXX */
-#define MAXDMASZ 512		/* XXX */
+struct dma_info {
+	int flags;
+	caddr_t addr;
+	vm_size_t nbytes;
+	struct isadma_seg phys[1];
+};
+
+static struct dma_info dma_info[8];
 
 /* high byte of address is stored in this port for i-th dma channel */
 static int dmapageport[8] =
 	{ 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
 
 /*
- * isa_dmacascade(): program 8237 DMA controller channel to accept
+ * isadma_cascade(): program 8237 DMA controller channel to accept
  * external dma control by a board.
  */
 void
-isa_dmacascade(chan)
+isadma_cascade(chan)
 	int chan;
 {
 
 #ifdef DIAGNOSTIC
 	if (chan < 0 || chan > 7)
-		panic("isa_dmacascade: impossible request"); 
+		panic("isadma_cascade: impossible request"); 
 #endif
 
 	/* set dma channel mode, and set dma channel mode */
 	if ((chan & 4) == 0) {
@@ -50,63 +53,67 @@
 	}
 }
 
 /*
- * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment
+ * isadma_start(): program 8237 DMA controller channel, avoid page alignment
  * problems by using a bounce buffer.
  */
 void
-isa_dmastart(flags, addr, nbytes, chan)
-	int flags;
+isadma_start(addr, nbytes, chan, flags)
 	caddr_t addr;
 	vm_size_t nbytes;
 	int chan;
+	int flags;
 {
-	vm_offset_t phys;
+	struct dma_info *di;
 	int waport;
-	caddr_t newaddr;
+	int mflags;
+	vm_size_t size;
 
 #ifdef DIAGNOSTIC
 	if (chan < 0 || chan > 7 ||
+	    ((flags & ISADMA_START_READ) == 0) == ((flags & ISADMA_START_WRITE) == 0) ||
 	    ((chan & 4) ? (nbytes >= (1<<17) || nbytes & 1 || (u_int)addr & 1) :
 	    (nbytes >= (1<<16))))
-		panic("isa_dmastart: impossible request"); 
+		panic("isadma_start: impossible request"); 
 #endif
 
-	if (isa_dmarangecheck(addr, nbytes, chan)) {
-		if (dma_bounce[chan] == 0)
-			dma_bounce[chan] =
-			    /*(caddr_t)malloc(MAXDMASZ, M_TEMP, M_WAITOK);*/
-			    (caddr_t) isaphysmem + NBPG*chan;
-		bounced[chan] = 1;
-		newaddr = dma_bounce[chan];
-		*(int *) newaddr = 0;	/* XXX */
-		/* copy bounce buffer on write */
-		if ((flags & B_READ) == 0)
-			bcopy(addr, newaddr, nbytes);
-		addr = newaddr;
+	di = dma_info+chan;
+	if (di->flags != 0) {
+		log(LOG_ERR,"isadma_start: old request active on %d\n",chan);
+		isadma_abort(chan);
 	}
 
-	/* translate to physical */
-	phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr);
+	di->flags = flags;
+	di->addr = addr;
+	di->nbytes = nbytes;
+
+	mflags = ISADMA_MAP_WAITOK | ISADMA_MAP_BOUNCE | ISADMA_MAP_CONTIG;
+	mflags |= (chan & 4) ? ISADMA_MAP_16BIT : ISADMA_MAP_8BIT;
+
+	if (isadma_map(addr, nbytes, di->phys, mflags) != 1)
+		panic("isadma_start: cannot map");
+
+	if ((flags & ISADMA_START_READ) == 0)
+		isadma_copytobuf(addr, nbytes, 1, di->phys);
 
 	if ((chan & 4) == 0) {
 		/*
 		 * Program one of DMA channels 0..3.  These are
 		 * byte mode channels.
 		 */
 		/* set dma channel mode, and reset address ff */
-		if (flags & B_READ)
+		if (flags & ISADMA_START_READ)
 			outb(DMA1_MODE, chan | DMA37MD_SINGLE | DMA37MD_WRITE);
 		else
 			outb(DMA1_MODE, chan | DMA37MD_SINGLE | DMA37MD_READ);
 		outb(DMA1_FFC, 0);
 
 		/* send start address */
 		waport =  DMA1_CHN(chan);
-		outb(waport, phys);
-		outb(waport, phys>>8);
-		outb(dmapageport[chan], phys>>16);
+		outb(waport, di->phys[0].addr);
+		outb(waport, di->phys[0].addr>>8);
+		outb(dmapageport[chan], di->phys[0].addr>>16);
 
 		/* send count */
 		outb(waport + 1, --nbytes);
 		outb(waport + 1, nbytes>>8);
@@ -118,19 +125,19 @@
 		 * Program one of DMA channels 4..7.  These are
 		 * word mode channels.
 		 */
 		/* set dma channel mode, and reset address ff */
-		if (flags & B_READ)
+		if (flags & ISADMA_START_READ)
 			outb(DMA2_MODE, (chan & 3) | DMA37MD_SINGLE | DMA37MD_WRITE);
 		else
 			outb(DMA2_MODE, (chan & 3) | DMA37MD_SINGLE | DMA37MD_READ);
 		outb(DMA2_FFC, 0);
 
 		/* send start address */
 		waport = DMA2_CHN(chan & 3);
-		outb(waport, phys>>1);
-		outb(waport, phys>>9);
-		outb(dmapageport[chan], phys>>16);
+		outb(waport, di->phys[0].addr>>1);
+		outb(waport, di->phys[0].addr>>9);
+		outb(dmapageport[chan], di->phys[0].addr>>16);
 
 		/* send count */
 		nbytes >>= 1;
 		outb(waport + 2, --nbytes);
@@ -141,40 +148,52 @@
 	}
 }
 
 void
-isa_dmaabort(chan)
+isadma_abort(chan)
 	int chan;
 {
+	struct dma_info *di;
 
 #ifdef DIAGNOSTIC
 	if (chan < 0 || chan > 7)
-		panic("isa_dmaabort: impossible request");
+		panic("isadma_abort: impossible request");
 #endif
 
-	bounced[chan] = 0;
+	di = dma_info+chan;
+	if (di->flags == 0) {
+		log(LOG_ERR,"isadma_abort: no request active on %d\n",chan);
+		return;
+	}
 
 	/* mask channel */
 	if ((chan & 4) == 0)
 		outb(DMA1_SMSK, DMA37SM_SET | chan);
 	else
 		outb(DMA2_SMSK, DMA37SM_SET | (chan & 3));
+
+	isadma_unmap(di->addr, di->nbytes, 1, di->phys);
+	di->flags = 0;
 }
 
 void
-isa_dmadone(flags, addr, nbytes, chan)
-	int flags;
-	caddr_t addr;
-	vm_size_t nbytes;
+isadma_done(chan)
 	int chan;
 {
+	struct dma_info *di;
 	u_char tc;
 
 #ifdef DIAGNOSTIC
 	if (chan < 0 || chan > 7)
-		panic("isa_dmadone: impossible request");
+		panic("isadma_done: impossible request");
 #endif
 
+	di = dma_info+chan;
+	if (di->flags == 0) {
+		log(LOG_ERR,"isadma_done: no request active on %d\n",chan);
+		return;
+	}
+
 	/* check that the terminal count was reached */
 	if ((chan & 4) == 0)
 		tc = inb(DMA1_SR) & (1 << chan);
 	else
@@ -188,86 +207,10 @@
 		outb(DMA1_SMSK, DMA37SM_SET | chan);
 	else
 		outb(DMA2_SMSK, DMA37SM_SET | (chan & 3));
 
-	/* copy bounce buffer on read */
-	if (bounced[chan]) {
-		bcopy(dma_bounce[chan], addr, nbytes);
-		bounced[chan] = 0;
-	}
-}
+	if (di->flags & ISADMA_START_READ)
+		isadma_copyfrombuf(di->addr, di->nbytes, 1, di->phys);
 
-/*
- * Check for problems with the address range of a DMA transfer
- * (non-contiguous physical pages, outside of bus address space,
- * crossing DMA page boundaries).
- * Return true if special handling needed.
- */
-int
-isa_dmarangecheck(va, length, chan)
-	vm_offset_t va;
-	u_long length;
-	int chan;
-{
-	vm_offset_t phys, priorpage = 0, endva;
-	u_int dma_pgmsk = (chan & 4) ?  ~(128*1024-1) : ~(64*1024-1);
-
-	endva = round_page(va + length);
-	for (; va < endva ; va += NBPG) {
-		phys = trunc_page(pmap_extract(pmap_kernel(), va));
-		if (phys == 0)
-			panic("isa_dmacheck: no physical page present");
-		if (phys >= (1<<24)) 
-			return 1;
-		if (priorpage) {
-			if (priorpage + NBPG != phys)
-				return 1;
-			/* check if crossing a DMA page boundary */
-			if ((priorpage ^ phys) & dma_pgmsk)
-				return 1;
-		}
-		priorpage = phys;
-	}
-	return 0;
-}
-
-/* head of queue waiting for physmem to become available */
-struct buf isa_physmemq;
-
-/* blocked waiting for resource to become free for exclusive use */
-static isaphysmemflag;
-/* if waited for and call requested when free (B_CALL) */
-static void (*isaphysmemunblock)(); /* needs to be a list */
-
-/*
- * Allocate contiguous physical memory for transfer, returning
- * a *virtual* address to region. May block waiting for resource.
- * (assumed to be called at splbio())
- */
-caddr_t
-isa_allocphysmem(caddr_t va, unsigned length, void (*func)()) {
-	
-	isaphysmemunblock = func;
-	while (isaphysmemflag & B_BUSY) {
-		isaphysmemflag |= B_WANTED;
-		sleep((caddr_t)&isaphysmemflag, PRIBIO);
-	}
-	isaphysmemflag |= B_BUSY;
-
-	return((caddr_t)isaphysmem);
-}
-
-/*
- * Free contiguous physical memory used for transfer.
- * (assumed to be called at splbio())
- */
-void
-isa_freephysmem(caddr_t va, unsigned length) {
-
-	isaphysmemflag &= ~B_BUSY;
-	if (isaphysmemflag & B_WANTED) {
-		isaphysmemflag &= B_WANTED;
-		wakeup((caddr_t)&isaphysmemflag);
-		if (isaphysmemunblock)
-			(*isaphysmemunblock)();
-	}
+	isadma_unmap(di->addr, di->nbytes, 1, di->phys);
+	di->flags = 0;
 }
--- sys/dev/isa/wd.c.orig	Tue Aug 15 18:16:43 1995
+++ sys/dev/isa/wd.c	Sun Sep 17 13:37:00 1995
@@ -54,8 +54,9 @@
 #include <machine/cpu.h>
 #include <machine/pio.h>
 
 #include <dev/isa/isavar.h>
+#include <dev/isa/isadmavar.h>
 #include <dev/isa/wdreg.h>
 
 #define	WAITTIME	(4 * hz)	/* time to wait for a completion */
 #define	RECOVERYTIME	(hz / 2)	/* time to recover from an error */
--- sys/dev/isa/isadmavar.h.orig	Fri Apr 14 12:54:45 1995
+++ sys/dev/isa/isadmavar.h	Mon Sep 18 09:36:19 1995
@@ -1,6 +1,32 @@
 /*	$NetBSD: isadmavar.h,v 1.2 1994/10/27 04:17:09 cgd Exp $	*/
 
-void isa_dmacascade __P((int));
-void isa_dmastart __P((int, caddr_t, vm_size_t, int));
-void isa_dmaabort __P((int));
-void isa_dmadone __P((int, caddr_t, vm_size_t, int));
+#define ISADMA_START_READ	0x0001	/* read from device */
+#define ISADMA_START_WRITE	0x0002	/* write to device */
+
+#define	ISADMA_MAP_WAITOK	0x0001	/* OK for isadma_map to sleep */
+#define	ISADMA_MAP_BOUNCE	0x0002	/* use bounce buffer if necessary */
+#define	ISADMA_MAP_CONTIG	0x0004	/* must be physically contiguous */
+#define	ISADMA_MAP_8BIT		0x0008	/* must not cross 64k boundary */
+#define	ISADMA_MAP_16BIT	0x0010	/* must not cross 128k boundary */
+
+struct isadma_seg {		/* a physical contiguous segment */
+	vm_offset_t addr;	/* address of this segment */
+	vm_size_t length;	/* length of this segment (bytes) */
+};
+
+int isadma_map __P((caddr_t, vm_size_t, struct isadma_seg *, int));
+void isadma_unmap __P((caddr_t, vm_size_t, int, struct isadma_seg *));
+void isadma_copytobuf __P((caddr_t, vm_size_t, int, struct isadma_seg *));
+void isadma_copyfrombuf __P((caddr_t, vm_size_t, int, struct isadma_seg *));
+
+void isadma_cascade __P((int));
+void isadma_start __P((caddr_t, vm_size_t, int, int));
+void isadma_abort __P((int));
+void isadma_done __P((int));
+
+/************ these are needed until all drivers have been cleaned up */
+#define isa_dmacascade(c) isadma_cascade((c))
+#define isa_dmastart(f,a,s,c) \
+    isadma_start((a),(s),(c),(f)&B_READ?ISADMA_START_READ:ISADMA_START_WRITE)
+#define isa_dmaabort(c) isadma_abort((c))
+#define isa_dmadone(a,s,c,f) isadma_abort((c))
--- sys/dev/isa/aha1542.c.orig	Sun Sep 17 13:35:33 1995
+++ sys/dev/isa/aha1542.c	Mon Sep 18 10:16:59 1995
@@ -1,6 +1,5 @@
 /*	$NetBSD: aha1542.c,v 1.50 1995/09/14 20:43:09 pk Exp $	*/
-
 /*
  * Copyright (c) 1994 Charles Hannum.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -49,8 +48,9 @@
  */
 
 #include <sys/types.h>
 #include <sys/param.h>
+#include <sys/syslog.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/errno.h>
 #include <sys/ioctl.h>
@@ -62,8 +62,9 @@
 
 #include <machine/pio.h>
 
 #include <dev/isa/isavar.h>
+#include <dev/isa/isadmavar.h>
 #include <scsi/scsi_all.h>
 #include <scsi/scsiconf.h>
 
 #ifdef DDB
@@ -71,8 +72,10 @@
 #else /* !DDB */
 #define Debugger() panic("should call debugger here (aha1542.c)")
 #endif /* !DDB */
 
+#define TUNE_1542	/* if bus speed check breaks the machine, undefine it */
+
 /************************** board definitions *******************************/
 
 /*
  * I/O Port Interface
@@ -185,9 +188,9 @@
 #define AHA_MBI_ERROR	0x4	/* Completed with error */
 
 /* FOR OLD VERSIONS OF THE !%$@ this may have to be 16 (yuk) */
 #define	AHA_NSEG	17	/* Number of scatter gather segments <= 16 */
-				/* allow 64 K i/o (min) */
+				/* allow 60 K i/o (min) */
 
 struct aha_ccb {
 	u_char opcode;
 	u_char lun:3;
@@ -208,18 +211,21 @@
 	struct aha_scat_gath {
 		u_char seg_len[3];
 		u_char seg_addr[3];
 	} scat_gath[AHA_NSEG];
+#define CCB_PHYS_SIZE ((int)&((struct aha_ccb *)0)->chain)
 	/*----------------------------------------------------------------*/
 	TAILQ_ENTRY(aha_ccb) chain;
 	struct aha_ccb *nexthash;
-	long hashkey;
 	struct scsi_xfer *xs;		/* the scsi_xfer for this cmd */
 	int flags;
 #define CCB_FREE	0
 #define CCB_ACTIVE	1
 #define CCB_ABORTED	2
 	struct aha_mbx_out *mbx;	/* pointer to mail box */
+	struct isadma_seg ccb_phys[1];	/* phys segment of this ccb */
+	struct isadma_seg data_phys[AHA_NSEG];	/* phys segments of data */
+	int data_nseg;
 };
 
 /*
  * opcode fields
@@ -303,10 +309,8 @@
 #define CHAN7	0x80
 
 /*********************************** end of board definitions***************/
 
-#define KVTOPHYS(x)	vtophys(x)
-
 #ifdef	AHADEBUG
 int	aha_debug = 1;
 #endif /*AHADEBUG */
 
@@ -567,9 +571,9 @@
 	struct isa_attach_args *ia = aux;
 	struct aha_softc *aha = (void *)self;
 
 	if (ia->ia_drq != DRQUNK)
-		isa_dmacascade(ia->ia_drq);
+		isadma_cascade(ia->ia_drq);
 
 	aha_init(aha);
 	TAILQ_INIT(&aha->free_ccb);
 
@@ -728,8 +732,11 @@
 	int s;
 
 	s = splbio();
 
+	if (ccb->ccb_phys[0].addr)
+		isadma_unmap((caddr_t)ccb, CCB_PHYS_SIZE, 1, ccb->ccb_phys);
+
 	ccb->flags = CCB_FREE;
 	TAILQ_INSERT_HEAD(&aha->free_ccb, ccb, chain);
 
 	/*
@@ -749,14 +756,18 @@
 aha_get_ccb(aha, flags)
 	struct aha_softc *aha;
 	int flags;
 {
-	int s;
+	int hashnum,mflags,s;
 	struct aha_ccb *ccb;
-	int hashnum;
 
 	s = splbio();
 
+	if (flags & SCSI_NOSLEEP)
+		mflags = ISADMA_MAP_BOUNCE;
+	else
+		mflags = ISADMA_MAP_BOUNCE | ISADMA_MAP_WAITOK;
+
 	/*
 	 * If we can and have to, sleep waiting for one
 	 * to come free
 	 */
@@ -770,16 +781,8 @@
 			if (ccb = (struct aha_ccb *) malloc(sizeof(struct aha_ccb),
 			    M_TEMP, M_NOWAIT)) {
 				bzero(ccb, sizeof(struct aha_ccb));
 				aha->numccbs++;
-				/*
-				 * put in the phystokv hash table
-				 * Never gets taken out.
-				 */
-				ccb->hashkey = KVTOPHYS(ccb);
-				hashnum = CCB_HASH(ccb->hashkey);
-				ccb->nexthash = aha->ccbhash[hashnum];
-				aha->ccbhash[hashnum] = ccb;
 			} else {
 				printf("%s: can't malloc ccb\n",
 				    aha->sc_dev.dv_xname);
 			}
@@ -789,29 +792,46 @@
 			break;
 		tsleep(&aha->free_ccb, PRIBIO, "ahaccb", 0);
 	}
 
+	if (isadma_map((caddr_t)ccb, CCB_PHYS_SIZE, ccb->ccb_phys,
+		       mflags | ISADMA_MAP_CONTIG) == 1) {
+		hashnum = CCB_HASH(ccb->ccb_phys[0].addr);
+		ccb->nexthash = aha->ccbhash[hashnum];
+		aha->ccbhash[hashnum] = ccb;
+	} else {
+		ccb->ccb_phys[0].addr = 0;
+		aha_free_ccb(aha,ccb,flags);
+		ccb = 0;
+	}
+
 	splx(s);
+
 	return ccb;
 }
 
 /*
- * given a physical address, find the ccb that it corresponds to.
+ * given a physical address, find the ccb that it corresponds to and remove
+ * it from the hash list.
  */
 struct aha_ccb *
 aha_ccb_phys_kv(aha, ccb_phys)
 	struct aha_softc *aha;
 	u_long ccb_phys;
 {
 	int hashnum = CCB_HASH(ccb_phys);
-	struct aha_ccb *ccb = aha->ccbhash[hashnum];
+	struct aha_ccb *res, **ccb = &aha->ccbhash[hashnum];
 
-	while (ccb) {
-		if (ccb->hashkey == ccb_phys)
+	while (*ccb) {
+		if ((*ccb)->ccb_phys[0].addr == ccb_phys)
 			break;
-		ccb = ccb->nexthash;
+		(*ccb) = (*ccb)->nexthash;
 	}
-	return ccb;
+
+	if (res = *ccb)
+		*ccb = (*ccb)->nexthash;
+
+	return res;
 }
 
 /*
  * Get a mbo and send the ccb.
@@ -853,9 +873,9 @@
 		tsleep(wmbx, PRIBIO, "ahasnd", 0);/*XXX can't do this */
 	}
 
 	/* Link ccb to mbo. */
-	lto3b(KVTOPHYS(ccb), wmbo->ccb_addr);
+	lto3b(ccb->ccb_phys[0].addr, wmbo->ccb_addr);
 	ccb->mbx = wmbo;
 	wmbo->cmd = cmd;
 
 	/* Sent it! */
@@ -920,8 +940,22 @@
 		} else
 			xs->resid = 0;
 	}
 	xs->flags |= ITSDONE;
+/* XXX fixme: */
+#ifndef KSTACK_IS_VALID_ON_INTERRUPT
+	if (xs->bp == NULL && (xs->flags & SCSI_POLL) == 0) {
+		wakeup(ccb);
+		return;
+	}
+#endif
+	if (ccb->data_nseg) {
+		if (xs->flags & SCSI_DATA_IN)
+			isadma_copyfrombuf(xs->data,xs->datalen,ccb->data_nseg,
+					   ccb->data_phys);
+		isadma_unmap(xs->data,xs->datalen,ccb->data_nseg,
+			     ccb->data_phys);
+	}
 	aha_free_ccb(aha, ccb, xs->flags);
 	scsi_done(xs);
 }
 
@@ -931,9 +965,8 @@
 int
 aha_find(aha)
 	struct aha_softc *aha;
 {
-	u_char ad[3];
 	volatile int i, sts;
 	struct aha_config conf;
 	struct aha_inquire inquire;
 	struct aha_extbios extbios;
@@ -1069,18 +1102,8 @@
 	 */
 	aha_cmd(aha, 1, 0, 0, 0, AHA_BUS_ON_TIME_SET, 7);
 	aha_cmd(aha, 1, 0, 0, 0, AHA_BUS_OFF_TIME_SET, 4);
 
-#ifdef TUNE_1542
-#error XXX Must deal with configuring the DRQ channel if we do this.
-	/*
-	 * Initialize memory transfer speed
-	 * Not compiled in by default because it breaks some machines
-	 */
-	if (!aha_set_bus_speed(aha))
-		return EIO;
-#endif /* TUNE_1542 */
-
 	return 0;
 }
 
 /*
@@ -1090,14 +1113,27 @@
 aha_init(aha)
 	struct aha_softc *aha;
 {
 	u_char ad[3];
+	struct isadma_seg mbx_phys[1];
 	int i;
 
+#ifdef TUNE_1542
 	/*
-	 * Initialize mail box
+	 * Initialize memory transfer speed
+	 * Not compiled in by default because it breaks some machines
 	 */
-	lto3b(KVTOPHYS(&aha->aha_mbx), ad);
+	if (!aha_set_bus_speed(aha))
+		panic("aha_init: cannot set bus speed");
+#endif /* TUNE_1542 */
+
+	/*
+	 * Initialize mail box. This mapping will never be undone.
+	 */
+	if (isadma_map((caddr_t)(&aha->aha_mbx), sizeof(struct aha_mbx),
+		       mbx_phys,ISADMA_MAP_CONTIG) != 1)
+		panic("aha_init: cannot map mail box");
+	lto3b(mbx_phys[0].addr, ad);
 
 	aha_cmd(aha, 4, 0, 0, 0, AHA_MBX_INIT, AHA_MBX_SIZE,
 	    ad[0], ad[1], ad[2]);
 
@@ -1117,10 +1153,10 @@
 ahaminphys(bp)
 	struct buf *bp;
 {
 
-	if (bp->b_bcount > ((AHA_NSEG - 1) << PGSHIFT))
-		bp->b_bcount = ((AHA_NSEG - 1) << PGSHIFT);
+	if (bp->b_bcount > ((AHA_NSEG - 2) << PGSHIFT))
+		bp->b_bcount = ((AHA_NSEG - 2) << PGSHIFT);
 	minphys(bp);
 }
 
 /*
@@ -1134,12 +1170,9 @@
 	struct scsi_link *sc_link = xs->sc_link;
 	struct aha_softc *aha = sc_link->adapter_softc;
 	struct aha_ccb *ccb;
 	struct aha_scat_gath *sg;
-	int seg;		/* scatter gather seg being worked on */
-	int thiskv;
-	u_long thisphys, nextphys;
-	int bytes_this_seg, bytes_this_page, datalen, flags;
+	int seg, datalen, flags, mflags;
 	struct iovec *iovp;
 	struct aha_mbx_out *mbo;
 	int s;
 
@@ -1149,8 +1182,12 @@
 	 * is from a buf (possibly from interrupt time)
 	 * then we can't allow it to sleep
 	 */
 	flags = xs->flags;
+	if (flags & SCSI_NOSLEEP)
+		mflags = ISADMA_MAP_BOUNCE;
+	else
+		mflags = ISADMA_MAP_BOUNCE | ISADMA_MAP_WAITOK;
 	if ((flags & (ITSDONE|INUSE)) != INUSE) {
 		printf("%s: done or not in use?\n", aha->sc_dev.dv_xname);
 		xs->flags &= ~ITSDONE;
 		xs->flags |= INUSE;
@@ -1158,8 +1195,9 @@
 	if ((ccb = aha_get_ccb(aha, flags)) == NULL) {
 		xs->error = XS_DRIVER_STUFFUP;
 		return TRY_AGAIN_LATER;
 	}
+
 	ccb->flags = CCB_ACTIVE;
 	ccb->xs = xs;
 
 	/*
@@ -1179,11 +1217,13 @@
 	ccb->scsi_cmd_length = xs->cmdlen;
 	ccb->req_sense_length = sizeof(ccb->scsi_sense);
 	ccb->host_stat = 0x00;
 	ccb->target_stat = 0x00;
+	ccb->data_nseg = 0;
 
 	if (xs->datalen && (flags & SCSI_RESET) == 0) {
-		lto3b(KVTOPHYS(ccb->scat_gath), ccb->data_addr);
+		sg = ((struct aha_ccb *)(ccb->ccb_phys[0].addr))->scat_gath;
+		lto3b((vm_offset_t)sg, ccb->data_addr);
 		sg = ccb->scat_gath;
 		seg = 0;
 #ifdef	TFS
 		if (flags & SCSI_DATA_UIO) {
@@ -1207,75 +1247,25 @@
 			/*
 			 * Set up the scatter gather block
 			 */
 
-			SC_DEBUG(sc_link, SDEV_DB4,
-				("%d @0x%x:- ", xs->datalen, xs->data));
-			datalen = xs->datalen;
-			thiskv = (int) xs->data;
-			thisphys = KVTOPHYS(thiskv);
-
-			while (datalen && seg < AHA_NSEG) {
-				bytes_this_seg = 0;
-
-				/* put in the base address */
-				lto3b(thisphys, sg->seg_addr);
-
-				SC_DEBUGN(sc_link, SDEV_DB4, ("0x%x", thisphys));
-
-				/* do it at least once */
-				nextphys = thisphys;
-				while (datalen && thisphys == nextphys) {
-					/*
-					 * This page is contiguous (physically)
-					 * with the the last, just extend the
-					 * length
-					 */
-					/* check it fits on the ISA bus */
-					if (thisphys > 0xFFFFFF) {
-						printf("%s: DMA beyond"
-							" end of ISA\n",
-							aha->sc_dev.dv_xname);
-						xs->error = XS_DRIVER_STUFFUP;
-						aha_free_ccb(aha, ccb, flags);
-						return COMPLETE;
-					}
-					/** how far to the end of the page ***/
-					nextphys = (thisphys & ~PGOFSET) + NBPG;
-					bytes_this_page = nextphys - thisphys;
-					/**** or the data ****/
-					bytes_this_page = min(bytes_this_page,
-							      datalen);
-					bytes_this_seg += bytes_this_page;
-					datalen -= bytes_this_page;
-
-					/* get more ready for the next page */
-					thiskv = (thiskv & ~PGOFSET) + NBPG;
-					if (datalen)
-						thisphys = KVTOPHYS(thiskv);
-				}
-				/*
-				 * next page isn't contiguous, finish the seg
-				 */
-				SC_DEBUGN(sc_link, SDEV_DB4,
-				    ("(0x%x)", bytes_this_seg));
-				lto3b(bytes_this_seg, sg->seg_len);
-				sg++;
-				seg++;
+			ccb->data_nseg = isadma_map(xs->data,xs->datalen,
+						    ccb->data_phys, mflags);
+			for (seg = 0; seg < ccb->data_nseg; seg++) {
+				lto3b(ccb->data_phys[seg].addr,sg[seg].seg_addr);
+				lto3b(ccb->data_phys[seg].length,sg[seg].seg_len);
 			}
 		}
-		lto3b(seg * sizeof(struct aha_scat_gath), ccb->data_length);
-		SC_DEBUGN(sc_link, SDEV_DB4, ("\n"));
-		if (datalen) {
-			/*
-			 * there's still data, must have run out of segs!
-			 */
-			printf("%s: aha_scsi_cmd, more than %d dma segs\n",
-			    aha->sc_dev.dv_xname, AHA_NSEG);
+		lto3b(ccb->data_nseg * sizeof(struct aha_scat_gath), ccb->data_length);
+		if (ccb->data_nseg == 0) {
+			printf("%s: aha_scsi_cmd, cannot map\n",
+			    aha->sc_dev.dv_xname);
 			xs->error = XS_DRIVER_STUFFUP;
 			aha_free_ccb(aha, ccb, flags);
 			return COMPLETE;
-		}
+		} else if (flags & SCSI_DATA_OUT)
+			isadma_copytobuf(xs->data,xs->datalen,ccb->data_nseg,
+					 ccb->data_phys);
 	} else {		/* No data xfer, use non S/G values */
 		lto3b(0, ccb->data_addr);
 		lto3b(0, ccb->data_length);
 	}
@@ -1289,19 +1279,45 @@
 		bcopy(xs->cmd, &ccb->scsi_cmd, ccb->scsi_cmd_length);
 
 	s = splbio();
 
+	isadma_copytobuf((caddr_t)ccb, CCB_PHYS_SIZE, 1, ccb->ccb_phys);
+
 	if (aha_send_mbo(aha, AHA_MBO_START, ccb) == NULL) {
 		splx(s);
 		xs->error = XS_DRIVER_STUFFUP;
+		if (ccb->data_nseg)
+			isadma_unmap(xs->data,xs->datalen,ccb->data_nseg,
+				     ccb->data_phys);
 		aha_free_ccb(aha, ccb, flags);
 		return TRY_AGAIN_LATER;
 	}
 
 	/*
 	 * Usually return SUCCESSFULLY QUEUED
 	 */
 	SC_DEBUG(sc_link, SDEV_DB3, ("cmd_sent\n"));
+/* XXX fixme: */
+#ifndef KSTACK_IS_VALID_ON_INTERRUPT
+	if (xs->bp == NULL && (flags & SCSI_POLL) == 0) {
+		if (tsleep(ccb,PRIBIO,"ahawait",(xs->timeout * hz) / 1000)) {
+			aha_timeout(ccb);
+			tsleep(ccb,PRIBIO,"ahawait1",2000);
+		}
+		splx(s);
+		if (ccb->data_nseg) {
+			if (flags & SCSI_DATA_IN)
+				isadma_copyfrombuf(xs->data,xs->datalen,
+						   ccb->data_nseg,
+				 		   ccb->data_phys);
+			isadma_unmap(xs->data,xs->datalen,ccb->data_nseg,
+				     ccb->data_phys);
+		}
+		aha_free_ccb(aha, ccb, xs->flags);
+		scsi_done(xs);
+		return COMPLETE;
+	}
+#endif
 	if ((flags & SCSI_POLL) == 0) {
 		timeout(aha_timeout, ccb, (xs->timeout * hz) / 1000);
 		splx(s);
 		return SUCCESSFULLY_QUEUED;
@@ -1382,21 +1398,20 @@
 			break;
 		lastworking = speed;
 	}
 	if (lastworking == -1) {
-		printf("no working bus speed\n");
+		printf(" no working bus speed");
 		return 0;
 	}
-	printf("%d nsec ", aha_bus_speeds[lastworking].nsecs);
+	printf(", %d nsec ", aha_bus_speeds[lastworking].nsecs);
 	if (lastworking == 7)	/* is slowest already */
-		printf("marginal\n");
+		printf("marginal");
 	else {
 		lastworking++;
-		printf("ok, using %d nsec\n",
-		    aha_bus_speeds[lastworking].nsecs);
+		printf("ok, using %d nsec", aha_bus_speeds[lastworking].nsecs);
 	}
 	if (!aha_bus_speed_check(aha, lastworking)) {
-		printf("test retry failed.. aborting.\n");
+		printf("test retry failed.. aborting.");
 		return 0;
 	}
 	return 1;
 }
@@ -1415,11 +1430,25 @@
 	struct aha_softc *aha;
 	int speed;
 {
 	int numspeeds = sizeof(aha_bus_speeds) / sizeof(struct bus_speed);
-	int loopcount;
+	int result, loopcount;
+	struct isadma_seg test_phys[1], scratch_phys[1];
 	u_char ad[3];
 
+	result = 1;
+
+	if (isadma_map(aha_scratch_buf,sizeof(aha_scratch_buf),scratch_phys,
+		       ISADMA_MAP_CONTIG) != 1)
+		return 0;
+	if (isadma_map(aha_test_string,sizeof(aha_test_string),test_phys,
+		       ISADMA_MAP_CONTIG) != 1) {
+		isadma_unmap(aha_scratch_buf,sizeof(aha_scratch_buf),1,
+			     scratch_phys);
+		return 0;
+	}
+	isadma_copytobuf(aha_test_string,sizeof(aha_test_string),1,test_phys);
+
 	/*
 	 * Set the dma-speed
 	 */
 	aha_cmd(aha, 1, 0, 0, 0, AHA_SPEED_SET, aha_bus_speeds[speed].arg);
@@ -1428,32 +1457,41 @@
 	 * put the test data into the buffer and calculate
 	 * it's address. Read it onto the board
 	 */
 	for (loopcount = 100; loopcount; loopcount--) {
-		lto3b(KVTOPHYS(aha_test_string), ad);
+		lto3b(test_phys[0].addr, ad);
 		aha_cmd(aha, 3, 0, 0, 0, AHA_WRITE_FIFO, ad[0], ad[1], ad[2]);
 
 		/*
 		 * Clear the buffer then copy the contents back from the
 		 * board.
 		 */
 		bzero(aha_scratch_buf, 54);
+		isadma_copytobuf(aha_scratch_buf, sizeof(aha_scratch_buf),
+				 1, scratch_phys);
 
-		lto3b(KVTOPHYS(aha_scratch_buf), ad);
+		lto3b(scratch_phys[0].addr, ad);
 		aha_cmd(aha, 3, 0, 0, 0, AHA_READ_FIFO, ad[0], ad[1], ad[2]);
+		isadma_copyfrombuf(aha_scratch_buf, sizeof(aha_scratch_buf),
+				   1, scratch_phys);
 
 		/*
 		 * Compare the original data and the final data and return the
 		 * correct value depending upon the result.  We only check the
 		 * first 54 bytes, because that's all the board copies during
 		 * WRITE_FIFO and READ_FIFO.
 		 */
-		if (memcmp(aha_test_string, aha_scratch_buf, 54))
-			return 0; /* failed test */
+		if (memcmp(aha_test_string, aha_scratch_buf, 54)) {
+			result = 0; /* failed test */
+			break;
+		}
 	}
 
+	isadma_unmap(aha_scratch_buf,sizeof(aha_scratch_buf),1,scratch_phys);
+	isadma_unmap(aha_test_string,sizeof(aha_test_string),1,test_phys);
+
 	/* copy succeeded; assume speed ok */
-	return 1;
+	return result;
 }
 #endif /* TUNE_1542 */
 
 void
--- sys/dev/isa/ultra14f.c.orig	Sun Sep 17 13:35:40 1995
+++ sys/dev/isa/ultra14f.c	Mon Sep 18 10:45:14 1995
@@ -65,8 +65,9 @@
 
 #include <machine/pio.h>
 
 #include <dev/isa/isavar.h>
+#include <dev/isa/isadmavar.h>
 
 #include <scsi/scsi_all.h>
 #include <scsi/scsiconf.h>
 
--- sys/dev/isa/wd7000.c.orig	Sat Aug 19 18:41:04 1995
+++ sys/dev/isa/wd7000.c	Mon Sep 18 10:46:03 1995
@@ -39,8 +39,9 @@
 
 #include <machine/cpu.h>
 #include <machine/pio.h>
 
+#include <dev/isa/isadmavar.h>
 #include <i386/isa/isa_device.h>	/* XXX BROKEN */
 
 extern int delaycount;  /* from clock setup code */
 
--- sys/arch/i386/i386/pmap.c.orig	Tue Aug 15 18:14:12 1995
+++ sys/arch/i386/i386/pmap.c	Sun Sep 17 13:37:03 1995
@@ -275,11 +275,20 @@
 	/*
 	 * reserve special hunk of memory for use by bus dma as a bounce
 	 * buffer (contiguous virtual *and* physical memory).  XXX
 	 */
-#if NISA > 0
-	isaphysmem = pmap_steal_memory(DMA_BOUNCE * NBPG);
-#endif
+	if (NISA > 0) {
+		if (ctob(physmem) >= 0x1000000) {
+			isaphysmem = pmap_steal_memory(DMA_BOUNCE * NBPG);
+			isaphysmempgs = DMA_BOUNCE;
+		} else {
+			isaphysmem = pmap_steal_memory(DMA_BOUNCE_LOW * NBPG);
+			isaphysmempgs = DMA_BOUNCE_LOW;
+		}
+	} else {
+		isaphysmem = NULL;
+		isaphysmempgs = 0;
+	}
 
 	pmap_update();
 }
 
--- sys/arch/i386/isa/isa_machdep.h.orig	Fri May  5 12:03:18 1995
+++ sys/arch/i386/isa/isa_machdep.h	Mon Sep 18 09:17:06 1995
@@ -96,19 +96,25 @@
  * ISA DMA bounce buffers.
  * XXX should be made partially machine- and bus-mapping-independent.
  *
  * DMA_BOUNCE is the number of pages of low-addressed physical memory
- * to acquire for ISA bounce buffers.
+ * to acquire for ISA bounce buffers. If physical memory below 16 MB
+ * then DMA_BOUNCE_LOW will be used.
  *
- * isaphysmem is the location of those bounce buffers.  (They are currently
- * assumed to be contiguous.
+ * isaphysmem is the address of this physical contiguous low memory.
+ * isaphysmempgs is the number of pages allocated.
  */
 
 #ifndef DMA_BOUNCE
-#define	DMA_BOUNCE      8		/* one buffer per channel */
+#define	DMA_BOUNCE      48		/* number of pages if memory > 16M */
+#endif
+
+#ifndef DMA_BOUNCE_LOW
+#define	DMA_BOUNCE_LOW  16		/* number of pages if memory <= 16M */
 #endif
 
 extern vm_offset_t isaphysmem;
+extern int isaphysmempgs;
 
 
 /*
  * Variables and macros to deal with the ISA I/O hole.
--- sys/arch/i386/isa/isa_machdep.c.orig	Tue Aug 15 18:14:17 1995
+++ sys/arch/i386/isa/isa_machdep.c	Mon Sep 18 09:34:16 1995
@@ -43,13 +43,16 @@
 #include <sys/syslog.h>
 #include <sys/device.h>
 #include <sys/malloc.h>
 
+#include <vm/vm.h>
+
 #include <machine/pio.h>
 #include <machine/cpufunc.h>
 
 #include <dev/isa/isareg.h>
 #include <dev/isa/isavar.h>
+#include <dev/isa/isadmavar.h>
 #include <i386/isa/isa_machdep.h>
 #include <i386/isa/icu.h>
 
 #define	IDTVEC(name)	__CONCAT(X,name)
@@ -369,5 +372,308 @@
 	intr_calculatemasks();
 
 	if (intrhand[irq] == NULL)
 		intrtype[irq] = ISA_IST_NONE;
+}
+
+/*
+ * ISA DMA and bounce buffer management
+ */
+
+#define MAX_CHUNK 256		/* number of low memory segments */
+
+static unsigned long bitmap[MAX_CHUNK / 32 + 1];
+
+#define set(i) (bitmap[(i) >> 5] |= (1 << (i)))
+#define clr(i) (bitmap[(i) >> 5] &= ~(1 << (i)))
+#define bit(i) ((bitmap[(i) >> 5] & (1 << (i))) != 0)
+
+static int bit_ptr = -1;	/* last segment visited */
+static int chunk_size = 0;	/* size (bytes) of one low mem segment */
+static int chunk_num = 0;	/* actual number of low mem segments */
+
+vm_offset_t isaphysmem;		/* base address of low mem arena */
+int isaphysmempgs;		/* number of pages of low mem arena */
+
+/*
+ * check if addr is from our low mem arena
+ */
+
+static int
+bounce_isbounced(addr)
+	vm_offset_t addr;
+{
+	return(addr >= vtophys(isaphysmem) &&
+	       addr < vtophys(isaphysmem)+isaphysmempgs*NBPG);
+}
+
+/*
+ * return the virtual address of addr. addr must be from low mem arena
+ */
+
+static caddr_t
+bounce_to_virt(addr)
+	vm_offset_t addr;
+{
+	return((caddr_t)(isaphysmem+(addr-vtophys(isaphysmem))));
+}
+
+/*
+ * alloc a low mem segment of size nbytes. Alignment constraint is:
+ *   (addr & pmask) == ((addr+size-1) & pmask)
+ * if waitok, call may wait for memory to become available.
+ * returns 0 on failure
+ */
+
+static vm_offset_t
+bounce_alloc(nbytes, pmask, waitok)
+	vm_size_t nbytes;
+	vm_offset_t pmask;
+	int waitok;
+{
+	int i,l;
+	vm_offset_t a,b,c,r;
+	vm_size_t n;
+	int nunits, opri;
+
+	opri = splbio();
+
+	if (bit_ptr < 0) {	/* initialize low mem arena */
+		if ((chunk_size = isaphysmempgs*NBPG/MAX_CHUNK) & 1)
+			chunk_size--;
+		chunk_num =  (isaphysmempgs*NBPG) / chunk_size;
+		for(i = 0; i < chunk_num; i++)
+			set(i);
+		bit_ptr = 0;
+	}
+
+	nunits = (nbytes+chunk_size-1)/chunk_size;
+
+	/*
+	 * set a=start, b=start with address constraints, c=end
+	 * check if this request may ever succeed.
+	 */
+
+	a = isaphysmem;
+	b = (isaphysmem + ~pmask) & pmask;
+	c = isaphysmem + chunk_num*chunk_size;
+	n = nunits*chunk_size;
+	if (a + n >= c || pmask != 0 && a + n >= b && b + n >= c) {
+		splx(opri);
+		return(0);
+	}
+
+	for (;;) {
+		i = bit_ptr;
+		l = -1;
+		do{
+			if (bit(i) && l >= 0 && (i - l + 1) >= nunits){
+				r = vtophys(isaphysmem+(i-nunits+1)*chunk_size);
+				if (((r ^ (r+nbytes-1)) & pmask) == 0) {
+					for (l = i - nunits + 1; l <= i; l++)
+						clr(l);
+					bit_ptr = i;
+					splx(opri);
+					return(r);
+				}
+			} else if (bit(i) && l < 0)
+				l = i;
+			else if (!bit(i))
+				l = -1;
+			if (++i == chunk_num) {
+				i = 0;
+				l = -1;
+			}
+		} while(i != bit_ptr);
+
+		if (waitok)
+			tsleep((caddr_t) &bit_ptr, PRIBIO, "physmem", 0);
+		else {
+			splx(opri);
+			return(0);
+		}
+	}
+}
+
+/* 
+ * return a segent of the low mem arena to the free pool
+ */
+
+static void
+bounce_free(addr, nbytes)
+	vm_offset_t addr;
+	vm_size_t nbytes;
+{
+	int i,j, opri;
+	vm_offset_t vaddr;
+
+	opri = splbio();
+
+	vaddr = (vm_offset_t)bounce_to_virt(addr);
+	if (vaddr < isaphysmem || vaddr >= isaphysmem+chunk_num*chunk_size ||
+	    ((i = (int)(vaddr-isaphysmem)) % chunk_size) != 0)
+		panic("bounce_free: bad address");
+
+	i /= chunk_size;
+	j = i + (nbytes+chunk_size-1)/chunk_size;
+
+	while (i < j) {
+		if (bit(i))
+			panic("bounce_free: already free");
+		set(i);
+		i++;
+	}
+
+	wakeup((caddr_t)&bit_ptr);
+	splx(opri);
+}
+
+/*
+ * setup (addr,nbytes) for an ISA dma transfer.
+ * flags&ISADMA_MAP_WAITOK	may wait
+ * flags&ISADMA_MAP_BOUNCE	may use a bounce buffer if necessary
+ * flags&ISADMA_MAP_CONTIG	result must be physically contiguous
+ * flags&ISADMA_MAP_8BIT	must not cross 64k boundary
+ * flags&ISADMA_MAP_16BIT	must not cross 128k boundary
+ *
+ * returns the number of used phys entries, 0 on failure.
+ * if flags&ISADMA_MAP_CONTIG result is 1 on sucess!
+ */
+
+int
+isadma_map(addr, nbytes, phys, flags)
+	caddr_t addr;
+	vm_size_t nbytes;
+	struct isadma_seg *phys;
+	int flags;
+{
+	vm_offset_t pmask, thiskv, thisphys, nextphys;
+	vm_size_t datalen;
+	int seg, waitok, i;
+
+	if (flags & ISADMA_MAP_8BIT)
+		pmask = ~((64*1024)-1);
+	else if (flags & ISADMA_MAP_16BIT)
+		pmask = ~((128*1024)-1);
+	else
+		pmask = 0;
+
+	waitok = (flags & ISADMA_MAP_WAITOK) != 0;
+
+	thiskv = (vm_offset_t)addr;
+	datalen = nbytes;
+	thisphys = vtophys(thiskv);
+	seg = 0;
+
+	while (datalen > 0 && (seg == 0 || (flags & ISADMA_MAP_CONTIG) == 0)) {
+		if (thisphys == 0)
+			panic("isadma_map: no physical page present");
+
+		phys[seg].length = 0;
+		phys[seg].addr = thisphys;
+
+		nextphys = thisphys;
+		while (datalen > 0 && thisphys == nextphys) {
+			nextphys = trunc_page(thisphys) + NBPG;
+			phys[seg].length += min(nextphys-thisphys, datalen);
+			datalen -= min(nextphys-thisphys, datalen);
+			thiskv = trunc_page(thiskv) + NBPG;
+			if (datalen)
+				thisphys = vtophys(thiskv);
+		}
+
+		if (phys[seg].addr+phys[seg].length > 0xffffff) {
+			if (flags & ISADMA_MAP_CONTIG) {
+				phys[seg].length = nbytes;
+				datalen = 0;
+			}
+			if ((flags & ISADMA_MAP_BOUNCE) == 0)
+				phys[seg].addr = 0;
+			else
+				phys[seg].addr =
+				    bounce_alloc(phys[seg].length, pmask,
+						 waitok);
+			if (phys[seg].addr == 0) {
+				for (i = 0; i < seg; i++)
+					if (bounce_isbounced(phys[i].addr))
+						bounce_free(phys[i].addr,
+							    phys[i].length);
+				return 0;
+			}
+		}
+
+		seg++;
+	}
+
+	/* check all constraints */
+	if (datalen ||
+	    ((phys[0].addr ^ (phys[0].addr+phys[0].length-1)) & pmask) != 0 ||
+	    ((phys[0].addr & 1) && (flags & ISADMA_MAP_16BIT))) {
+		if ((flags & ISADMA_MAP_BOUNCE) == 0)
+			return 0;
+		if ((phys[0].addr = bounce_alloc(nbytes,pmask,waitok)) == 0)
+			return 0;
+		phys[0].length = nbytes;
+	}
+
+	return seg;
+}
+
+/*
+ * undo a ISA dma mapping. Simply return the bounced segments to the pool.
+ */
+
+void
+isadma_unmap(addr, nbytes, nphys, phys)
+	caddr_t addr;
+	vm_size_t nbytes;
+	int nphys;
+	struct isadma_seg *phys;
+{
+	int i;
+
+	for (i = 0; i < nphys; i++)
+		if (bounce_isbounced(phys[i].addr))
+			bounce_free(phys[i].addr,phys[i].length);
+}
+
+/*
+ * copy bounce buffer to buffer where needed
+ */
+
+void
+isadma_copyfrombuf(addr, nbytes, nphys, phys)
+	caddr_t addr;
+	vm_size_t nbytes;
+	int nphys;
+	struct isadma_seg *phys;
+{
+	int i;
+
+	for (i = 0; i < nphys; i++) {
+		if (bounce_isbounced(phys[i].addr)) {
+			bcopy(bounce_to_virt(phys[i].addr),addr,phys[i].length);
+		}
+		addr += phys[i].length;
+	}
+}
+
+/*
+ * copy buffer to bounce buffer where needed
+ */
+
+void
+isadma_copytobuf(addr, nbytes, nphys, phys)
+	caddr_t addr;
+	vm_size_t nbytes;
+	int nphys;
+	struct isadma_seg *phys;
+{
+	int i;
+
+	for (i = 0; i < nphys; i++) {
+		if (bounce_isbounced(phys[i].addr)) {
+			bcopy(addr,bounce_to_virt(phys[i].addr),phys[i].length);
+		}
+		addr += phys[i].length;
+	}
 }
--- sys/arch/i386/isa/fd.c.orig	Sat Aug 26 18:34:34 1995
+++ sys/arch/i386/isa/fd.c	Sun Sep 17 16:55:39 1995
@@ -914,10 +914,10 @@
 #ifdef NEWCONFIG
 		at_dma(read, bp->b_data + fd->sc_skip, fd->sc_nbytes,
 		    fdc->sc_drq);
 #else
-		isa_dmastart(read, bp->b_data + fd->sc_skip, fd->sc_nbytes,
-		    fdc->sc_drq);
+		isadma_start(bp->b_data + fd->sc_skip, fd->sc_nbytes,
+		    fdc->sc_drq, read ? ISADMA_START_READ : ISADMA_START_WRITE);
 #endif
 		outb(iobase + fdctl, type->rate);
 #ifdef FD_DEBUG
 		printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n",
@@ -965,9 +965,9 @@
 	case IOTIMEDOUT:
 #ifdef NEWCONFIG
 		at_dma_abort(fdc->sc_drq);
 #else
-		isa_dmaabort(fdc->sc_drq);
+		isadma_abort(fdc->sc_drq);
 #endif
 	case SEEKTIMEDOUT:
 	case RECALTIMEDOUT:
 	case RESETTIMEDOUT:
@@ -979,9 +979,9 @@
 		if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) {
 #ifdef NEWCONFIG
 			at_dma_abort(fdc->sc_drq);
 #else
-			isa_dmaabort(fdc->sc_drq);
+			isadma_abort(fdc->sc_drq);
 #endif
 #ifdef FD_DEBUG
 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
 			    "read failed" : "write failed");
@@ -993,11 +993,9 @@
 		}
 #ifdef NEWCONFIG
 		at_dma_terminate(fdc->sc_drq);
 #else
-		read = bp->b_flags & B_READ;
-		isa_dmadone(read, bp->b_data + fd->sc_skip, fd->sc_nbytes,
-		    fdc->sc_drq);
+		isadma_done(fdc->sc_drq);
 #endif
 		if (fdc->sc_errors) {
 			diskerr(bp, "fd", "soft error", LOG_PRINTF,
 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
--- sys/arch/i386/isa/fdreg.h.orig	Tue Aug 15 18:14:16 1995
+++ sys/arch/i386/isa/fdreg.h	Sun Sep 17 16:56:29 1995
@@ -62,5 +62,5 @@
 #define	FDI_DCHG	0x80	/* diskette has been changed */
 
 #define	FDC_BSIZE	512
 #define	FDC_NPORT	8
-#define	FDC_MAXIOSIZE	NBPG	/* XXX should be MAXBSIZE */
+#define	FDC_MAXIOSIZE	MAXBSIZE

-- 
Juergen Hannken-Illjes - hannken@eis.cs.tu-bs.de - TU Braunschweig (W Germany)
>Audit-Trail:
>Unformatted: