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);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to