svn commit: r190146 - head/sys/boot/pc98/libpc98

Takahashi Yoshihiro nyan at FreeBSD.org
Fri Mar 20 05:26:44 PDT 2009


Author: nyan
Date: Fri Mar 20 12:26:42 2009
New Revision: 190146
URL: http://svn.freebsd.org/changeset/base/190146

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

Modified:
  head/sys/boot/pc98/libpc98/bioscd.c

Modified: head/sys/boot/pc98/libpc98/bioscd.c
==============================================================================
--- head/sys/boot/pc98/libpc98/bioscd.c	Fri Mar 20 11:08:57 2009	(r190145)
+++ head/sys/boot/pc98/libpc98/bioscd.c	Fri Mar 20 12:26:42 2009	(r190146)
@@ -170,9 +170,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);
@@ -232,7 +232,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;
@@ -241,9 +241,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);
 	}
@@ -254,11 +254,14 @@ 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;
 	int biosdev;
 #ifdef DISK_DEBUG
 	int error;
@@ -272,40 +275,73 @@ 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 = 0x1b;
+				v86.eax = 0x0300 | biosdev;
+				v86int();
+			}
+
 			v86.ctl = V86_FLAGS;
 			v86.addr = 0x1b;
-			v86.eax = 0x0300 | biosdev;
+			v86.eax = 0x0600 | (biosdev & 0x7f);
+			v86.ebx = blks * BIOSCD_SECSIZE;
+			v86.ecx = dblk & 0xffff;
+			v86.edx = (dblk >> 16) & 0xffff;
+			v86.ebp = VTOPOFF(dest);
+			v86.es = VTOPSEG(dest);
 			v86int();
+			result = (v86.efl & PSL_C);
+			if (result == 0)
+				break;
 		}
-
-		v86.ctl = V86_FLAGS;
-		v86.addr = 0x1b;
-		v86.eax = 0x0600 | (biosdev & 0x7f);
-		v86.ebx = blks * BIOSCD_SECSIZE;
-		v86.ecx = dblk & 0xffff;
-		v86.edx = (dblk >> 16) & 0xffff;
-		v86.ebp = VTOPOFF(dest);
-		v86.es = VTOPSEG(dest);
-		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);


More information about the svn-src-head mailing list