Author: jhb
Date: Thu Mar 19 15:40:44 2009
New Revision: 190070
URL: http://svn.freebsd.org/changeset/base/190070

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

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

Modified: stable/7/sys/boot/i386/libi386/bioscd.c
==============================================================================
--- stable/7/sys/boot/i386/libi386/bioscd.c     Thu Mar 19 15:40:39 2009        
(r190069)
+++ stable/7/sys/boot/i386/libi386/bioscd.c     Thu Mar 19 15:40:44 2009        
(r190070)
@@ -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/7/sys/boot/i386/libi386/biosdisk.c
==============================================================================
--- stable/7/sys/boot/i386/libi386/biosdisk.c   Thu Mar 19 15:40:39 2009        
(r190069)
+++ stable/7/sys/boot/i386/libi386/biosdisk.c   Thu Mar 19 15:40:44 2009        
(r190070)
@@ -1109,14 +1109,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/7/sys/boot/i386/libi386/libi386.h
==============================================================================
--- stable/7/sys/boot/i386/libi386/libi386.h    Thu Mar 19 15:40:39 2009        
(r190069)
+++ stable/7/sys/boot/i386/libi386/libi386.h    Thu Mar 19 15:40:44 2009        
(r190070)
@@ -52,6 +52,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);
_______________________________________________
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