Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 19 Mar 2009 15:46:33 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-6@freebsd.org
Subject:   svn commit: r190073 - in stable/6/sys: . boot/i386/libi386 contrib/pf dev/cxgb
Message-ID:  <200903191546.n2JFkXBa067438@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Thu Mar 19 15:46:33 2009
New Revision: 190073
URL: http://svn.freebsd.org/changeset/base/190073

Log:
  MFC: Teach the BIOS CD driver to use bounce buffers when the destination
  address is > 1 MB.

Modified:
  stable/6/sys/   (props changed)
  stable/6/sys/boot/i386/libi386/bioscd.c
  stable/6/sys/boot/i386/libi386/biosdisk.c
  stable/6/sys/boot/i386/libi386/libi386.h
  stable/6/sys/contrib/pf/   (props changed)
  stable/6/sys/dev/cxgb/   (props changed)

Modified: stable/6/sys/boot/i386/libi386/bioscd.c
==============================================================================
--- stable/6/sys/boot/i386/libi386/bioscd.c	Thu Mar 19 15:45:43 2009	(r190072)
+++ stable/6/sys/boot/i386/libi386/bioscd.c	Thu Mar 19 15:46:33 2009	(r190073)
@@ -173,9 +173,9 @@ bc_add(int biosdev)
 static void
 bc_print(int verbose)
 {
-	int i;
 	char line[80];
-    
+	int i;
+
 	for (i = 0; i < nbcinfo; i++) {
 		sprintf(line, "    cd%d: Device 0x%x\n", i,
 		    bcinfo[i].bc_sp.sp_devicespec);
@@ -235,7 +235,7 @@ bc_strategy(void *devdata, int rw, daddr
 	if (dblk % (BIOSCD_SECSIZE / DEV_BSIZE) != 0)
 		return (EINVAL);
 	dblk /= (BIOSCD_SECSIZE / DEV_BSIZE);
-	DEBUG("read %d from %d to %p", blks, dblk, buf);
+	DEBUG("read %d from %lld to %p", blks, dblk, buf);
 
 	if (rsize)
 		*rsize = 0;
@@ -244,9 +244,9 @@ bc_strategy(void *devdata, int rw, daddr
 		return (EIO);
 	}
 #ifdef BD_SUPPORT_FRAGS
-	DEBUG("bc_strategy: frag read %d from %d+%d to %p", 
+	DEBUG("frag read %d from %lld+%d to %p", 
 	    fragsize, dblk, blks, buf + (blks * BIOSCD_SECSIZE));
-	if (fragsize && bc_read(unit, dblk + blks, 1, fragsize)) {
+	if (fragsize && bc_read(unit, dblk + blks, 1, fragbuf)) {
 		DEBUG("frag read error");
 		return(EIO);
 	}
@@ -257,11 +257,15 @@ bc_strategy(void *devdata, int rw, daddr
 	return (0);
 }
 
+/* Max number of sectors to bounce-buffer at a time. */
+#define	CD_BOUNCEBUF	8
+
 static int
 bc_read(int unit, daddr_t dblk, int blks, caddr_t dest)
 {
-	u_int result, retry;
-	static unsigned short packet[8];
+	u_int maxfer, resid, result, retry, x;
+	caddr_t bbuf, p, xp;
+	static struct edd_packet packet;
 	int biosdev;
 #ifdef DISK_DEBUG
 	int error;
@@ -275,47 +279,77 @@ bc_read(int unit, daddr_t dblk, int blks
 	if (blks == 0)
 		return (0);
 
+	/* Decide whether we have to bounce */
+	if (VTOP(dest) >> 20 != 0) {
+		/* 
+		 * The destination buffer is above first 1MB of
+		 * physical memory so we have to arrange a suitable
+		 * bounce buffer.
+		 */
+		x = min(CD_BOUNCEBUF, (unsigned)blks);
+		bbuf = alloca(x * BIOSCD_SECSIZE);
+		maxfer = x;
+	} else {
+		bbuf = NULL;
+		maxfer = 0;
+	}
+	
 	biosdev = bc_unit2bios(unit);
-	/*
-	 * Loop retrying the operation a couple of times.  The BIOS
-	 * may also retry.
-	 */
-	for (retry = 0; retry < 3; retry++) {
-		/* If retrying, reset the drive */
-		if (retry > 0) {
+	resid = blks;
+	p = dest;
+
+	while (resid > 0) {
+		if (bbuf)
+			xp = bbuf;
+		else
+			xp = p;
+		x = resid;
+		if (maxfer > 0)
+			x = min(x, maxfer);
+
+		/*
+		 * Loop retrying the operation a couple of times.  The BIOS
+		 * may also retry.
+		 */
+		for (retry = 0; retry < 3; retry++) {
+			/* If retrying, reset the drive */
+			if (retry > 0) {
+				v86.ctl = V86_FLAGS;
+				v86.addr = 0x13;
+				v86.eax = 0;
+				v86.edx = biosdev;
+				v86int();
+			}
+
+			packet.len = 0x10;
+			packet.count = x;
+			packet.offset = VTOPOFF(xp);
+			packet.seg = VTOPSEG(xp);
+			packet.lba = dblk;
 			v86.ctl = V86_FLAGS;
 			v86.addr = 0x13;
-			v86.eax = 0;
+			v86.eax = 0x4200;
 			v86.edx = biosdev;
+			v86.ds = VTOPSEG(&packet);
+			v86.esi = VTOPOFF(&packet);
 			v86int();
+			result = (v86.efl & PSL_C);
+			if (result == 0)
+				break;
 		}
-	    
-		packet[0] = 0x10;
-		packet[1] = blks;
-		packet[2] = VTOPOFF(dest);
-		packet[3] = VTOPSEG(dest);
-		packet[4] = dblk & 0xffff;
-		packet[5] = dblk >> 16;
-		packet[6] = 0;
-		packet[7] = 0;
-		v86.ctl = V86_FLAGS;
-		v86.addr = 0x13;
-		v86.eax = 0x4200;
-		v86.edx = biosdev;
-		v86.ds = VTOPSEG(packet);
-		v86.esi = VTOPOFF(packet);
-		v86int();
-		result = (v86.efl & PSL_C);
-		if (result == 0)
-			break;
-	}
 	
 #ifdef DISK_DEBUG
-	error = (v86.eax >> 8) & 0xff;
+		error = (v86.eax >> 8) & 0xff;
 #endif
-	DEBUG("%d sectors from %ld to %p (0x%x) %s", blks, dblk, dest,
-	    VTOP(dest), result ? "failed" : "ok");
-	DEBUG("unit %d  status 0x%x",  unit, error);
+		DEBUG("%d sectors from %lld to %p (0x%x) %s", x, dblk, p,
+		    VTOP(p), result ? "failed" : "ok");
+		DEBUG("unit %d  status 0x%x", unit, error);
+		if (bbuf != NULL)
+			bcopy(bbuf, p, x * BIOSCD_SECSIZE);
+		p += (x * BIOSCD_SECSIZE);
+		dblk += x;
+		resid -= x;
+	}
 	
 /*	hexdump(dest, (blks * BIOSCD_SECSIZE)); */
 	return(0);

Modified: stable/6/sys/boot/i386/libi386/biosdisk.c
==============================================================================
--- stable/6/sys/boot/i386/libi386/biosdisk.c	Thu Mar 19 15:45:43 2009	(r190072)
+++ stable/6/sys/boot/i386/libi386/biosdisk.c	Thu Mar 19 15:46:33 2009	(r190073)
@@ -1105,14 +1105,6 @@ bd_realstrategy(void *devdata, int rw, d
 /* Max number of sectors to bounce-buffer if the request crosses a 64k boundary */
 #define FLOPPY_BOUNCEBUF	18
 
-struct edd_packet {
-    uint16_t	len;
-    uint16_t	count;
-    uint16_t	offset;
-    uint16_t	seg;
-    uint64_t	lba;
-};
-
 static int
 bd_edd_io(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest, int write)
 {

Modified: stable/6/sys/boot/i386/libi386/libi386.h
==============================================================================
--- stable/6/sys/boot/i386/libi386/libi386.h	Thu Mar 19 15:45:43 2009	(r190072)
+++ stable/6/sys/boot/i386/libi386/libi386.h	Thu Mar 19 15:46:33 2009	(r190073)
@@ -57,6 +57,14 @@ struct i386_devdesc
     } d_kind;
 };
 
+struct edd_packet {
+    uint16_t	len;
+    uint16_t	count;
+    uint16_t	offset;
+    uint16_t	seg;
+    uint64_t	lba;
+};
+                 
 int	i386_getdev(void **vdev, const char *devspec, const char **path);
 char	*i386_fmtdev(void *vdev);
 int	i386_setcurrdev(struct env_var *ev, int flags, const void *value);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200903191546.n2JFkXBa067438>