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-all
mailing list