1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-20 11:11:24 +00:00

MFi386: r189749

Teach the BIOS CD driver to use bounce buffers when the destination
  address is > 1 MB.
This commit is contained in:
Yoshihiro Takahashi 2009-03-20 12:26:42 +00:00
parent 15fb32c07d
commit d0680af004
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=190146

View File

@ -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);
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) {
v86.ctl = V86_FLAGS;
v86.addr = 0x1b;
v86.eax = 0x0300 | biosdev;
v86int();
}
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;
/* 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);
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 = 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);