summaryrefslogtreecommitdiffstats
path: root/sys/boot
diff options
context:
space:
mode:
authornyan <nyan@FreeBSD.org>2009-03-20 12:26:42 +0000
committernyan <nyan@FreeBSD.org>2009-03-20 12:26:42 +0000
commitcea83e1bafee25e4af4431b58e156f2a3394fce0 (patch)
tree2d022e97cd18c155c87d572b7efb2bfba6802d79 /sys/boot
parentc8b4c76eed87a28addbdc90f84635dd414796b51 (diff)
downloadFreeBSD-src-cea83e1bafee25e4af4431b58e156f2a3394fce0.zip
FreeBSD-src-cea83e1bafee25e4af4431b58e156f2a3394fce0.tar.gz
MFi386: r189749
Teach the BIOS CD driver to use bounce buffers when the destination address is > 1 MB.
Diffstat (limited to 'sys/boot')
-rw-r--r--sys/boot/pc98/libpc98/bioscd.c102
1 files changed, 69 insertions, 33 deletions
diff --git a/sys/boot/pc98/libpc98/bioscd.c b/sys/boot/pc98/libpc98/bioscd.c
index 40d455b..e0258ad 100644
--- a/sys/boot/pc98/libpc98/bioscd.c
+++ b/sys/boot/pc98/libpc98/bioscd.c
@@ -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_t dblk, size_t size, char *buf,
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_t dblk, size_t size, char *buf,
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_t dblk, size_t size, char *buf,
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, caddr_t dest)
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);
OpenPOWER on IntegriCloud