summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornyan <nyan@FreeBSD.org>2007-10-25 12:57:46 +0000
committernyan <nyan@FreeBSD.org>2007-10-25 12:57:46 +0000
commitd957274e54a31df7ba4e5f7da31a4220d9415a1b (patch)
treeee34a4fb91a8229b63e55eede2d3bf3cd6aaaf61
parent06cf08f7c6c5e4449fd89a0ffa82bd66599e58db (diff)
downloadFreeBSD-src-d957274e54a31df7ba4e5f7da31a4220d9415a1b.zip
FreeBSD-src-d957274e54a31df7ba4e5f7da31a4220d9415a1b.tar.gz
MFi386: part of revision 1.51
Rework the read/write support in the bios disk driver some to cut down on duplicated code. - All of the bounce buffer and retry logic duplicated in bd_read() and bd_write() are merged into a single bd_io() routine that takes an extra direction argument. bd_read() and bd_write() are now simple wrappers around bd_io().
-rw-r--r--sys/boot/pc98/libpc98/biosdisk.c244
1 files changed, 83 insertions, 161 deletions
diff --git a/sys/boot/pc98/libpc98/biosdisk.c b/sys/boot/pc98/libpc98/biosdisk.c
index 8afcee9..25cb9a7 100644
--- a/sys/boot/pc98/libpc98/biosdisk.c
+++ b/sys/boot/pc98/libpc98/biosdisk.c
@@ -731,16 +731,52 @@ bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, siz
#define FLOPPY_BOUNCEBUF 18
static int
-bd_read(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest)
+bd_chs_io(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest, int write)
{
- u_int x, bpc, cyl, hd, sec, result, resid, retry, maxfer;
+ u_int x, bpc, cyl, hd, sec;
+
+ bpc = (od->od_sec * od->od_hds); /* blocks per cylinder */
+ x = dblk;
+ cyl = x / bpc; /* block # / blocks per cylinder */
+ x %= bpc; /* block offset into cylinder */
+ hd = x / od->od_sec; /* offset / blocks per track */
+ sec = x % od->od_sec; /* offset into track */
+
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x1b;
+ if (write)
+ v86.eax = 0x0500 | od->od_unit;
+ else
+ v86.eax = 0x0600 | od->od_unit;
+ if (od->od_flags & BD_FLOPPY) {
+ v86.eax |= 0xd000;
+ v86.ecx = 0x0200 | (cyl & 0xff);
+ v86.edx = (hd << 8) | (sec + 1);
+ } else if (od->od_flags & BD_OPTICAL) {
+ v86.eax &= 0xFF7F;
+ v86.ecx = dblk & 0xFFFF;
+ v86.edx = dblk >> 16;
+ } else {
+ v86.ecx = cyl;
+ v86.edx = (hd << 8) | sec;
+ }
+ v86.ebx = blks * BIOSDISK_SECSIZE;
+ v86.es = VTOPSEG(dest);
+ v86.ebp = VTOPOFF(dest);
+ v86int();
+ return (v86.efl & 0x1);
+}
+
+static int
+bd_io(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest, int write)
+{
+ u_int x, sec, result, resid, retry, maxfer;
caddr_t p, xp, bbuf, breg;
- /* Just in case some idiot actually tries to read -1 blocks... */
+ /* Just in case some idiot actually tries to read/write -1 blocks... */
if (blks < 0)
return (-1);
- bpc = (od->od_sec * od->od_hds); /* blocks per cylinder */
resid = blks;
p = dest;
@@ -749,33 +785,33 @@ bd_read(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest)
((VTOP(dest) >> 16) != (VTOP(dest + blks * BIOSDISK_SECSIZE) >> 16))) {
/*
- * There is a 64k physical boundary somewhere in the destination buffer, or the
- * destination buffer is above first 1MB of physical memory so we have
- * to arrange a suitable bounce buffer. Allocate a buffer twice as large as we
- * need to. Use the bottom half unless there is a break there, in which case we
- * use the top half.
+ * There is a 64k physical boundary somewhere in the
+ * destination buffer, or the destination buffer is above
+ * first 1MB of physical memory so we have to arrange a
+ * suitable bounce buffer. Allocate a buffer twice as large
+ * as we need to. Use the bottom half unless there is a break
+ * there, in which case we use the top half.
*/
x = min(od->od_sec, (unsigned)blks);
bbuf = alloca(x * 2 * BIOSDISK_SECSIZE);
- if (((u_int32_t)VTOP(bbuf) & 0xffff0000) == ((u_int32_t)VTOP(bbuf + x * BIOSDISK_SECSIZE) & 0xffff0000)) {
+ if (((u_int32_t)VTOP(bbuf) & 0xffff0000) ==
+ ((u_int32_t)VTOP(bbuf + x * BIOSDISK_SECSIZE) & 0xffff0000)) {
breg = bbuf;
} else {
breg = bbuf + x * BIOSDISK_SECSIZE;
}
- maxfer = x; /* limit transfers to bounce region size */
+ maxfer = x; /* limit transfers to bounce region size */
} else {
breg = bbuf = NULL;
maxfer = 0;
}
while (resid > 0) {
- x = dblk;
- cyl = x / bpc; /* block # / blocks per cylinder */
- x %= bpc; /* block offset into cylinder */
- hd = x / od->od_sec; /* offset / blocks per track */
- sec = x % od->od_sec; /* offset into track */
-
- /* play it safe and don't cross track boundaries (XXX this is probably unnecessary) */
+ /*
+ * Play it safe and don't cross track boundaries.
+ * (XXX this is probably unnecessary)
+ */
+ sec = dblk % od->od_sec; /* offset into track */
x = min(od->od_sec - sec, resid);
if (maxfer > 0)
x = min(x, maxfer); /* fit bounce buffer */
@@ -783,11 +819,17 @@ bd_read(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest)
/* where do we transfer to? */
xp = bbuf == NULL ? p : breg;
- /* correct sector number for 1-based BIOS numbering */
- if ((od->od_unit & 0xf0) == 0x30 || (od->od_unit & 0xf0) == 0x90)
- sec++;
+ /*
+ * Put your Data In, Put your Data out,
+ * Put your Data In, and shake it all about
+ */
+ if (write && bbuf != NULL)
+ bcopy(p, breg, x * BIOSDISK_SECSIZE);
- /* Loop retrying the operation a couple of times. The BIOS may also retry. */
+ /*
+ * 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) {
@@ -796,166 +838,46 @@ bd_read(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest)
v86.eax = 0x0300 | od->od_unit;
v86int();
}
-
- v86.ctl = V86_FLAGS;
- v86.addr = 0x1b;
- if (od->od_flags & BD_FLOPPY) {
- v86.eax = 0xd600 | od->od_unit;
- v86.ecx = 0x0200 | (cyl & 0xff);
- }
- else {
- v86.eax = 0x0600 | od->od_unit;
- v86.ecx = cyl;
- }
- if (od->od_flags & BD_OPTICAL) {
- v86.eax &= 0xFF7F;
- v86.ecx = dblk & 0xFFFF;
- v86.edx = dblk >> 16;
- } else {
- v86.edx = (hd << 8) | sec;
- }
- v86.ebx = x * BIOSDISK_SECSIZE;
- v86.es = VTOPSEG(xp);
- v86.ebp = VTOPOFF(xp);
- v86int();
- result = (v86.efl & 0x1);
+
+ result = bd_chs_io(od, dblk, x, xp, write);
if (result == 0)
break;
}
-
- DEBUG("%d sectors from %d/%d/%d to %p (0x%x) %s", x, cyl, hd, od->od_flags & BD_FLOPPY ? sec - 1 : sec, p, VTOP(p), result ? "failed" : "ok");
- /* BUG here, cannot use v86 in printf because putchar uses it too */
- DEBUG("ax = 0x%04x cx = 0x%04x dx = 0x%04x status 0x%x",
- od->od_flags & BD_FLOPPY ? 0xd600 | od->od_unit : 0x0600 | od->od_unit,
- od->od_flags & BD_FLOPPY ? 0x0200 | cyl : cyl, (hd << 8) | sec,
- (v86.eax >> 8) & 0xff);
+
+ if (write)
+ DEBUG("%d sectors from %lld to %p (0x%x) %s", x, dblk, p, VTOP(p),
+ result ? "failed" : "ok");
+ else
+ DEBUG("%d sectors from %p (0x%x) to %lld %s", x, p, VTOP(p), dblk,
+ result ? "failed" : "ok");
if (result) {
return(-1);
}
- if (bbuf != NULL)
+ if (!write && bbuf != NULL)
bcopy(breg, p, x * BIOSDISK_SECSIZE);
p += (x * BIOSDISK_SECSIZE);
dblk += x;
resid -= x;
}
-
+
/* hexdump(dest, (blks * BIOSDISK_SECSIZE)); */
return(0);
}
-
static int
-bd_write(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest)
+bd_read(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest)
{
- u_int x, bpc, cyl, hd, sec, result, resid, retry, maxfer;
- caddr_t p, xp, bbuf, breg;
-
- /* Just in case some idiot actually tries to read -1 blocks... */
- if (blks < 0)
- return (-1);
-
- bpc = (od->od_sec * od->od_hds); /* blocks per cylinder */
- resid = blks;
- p = dest;
-
- /* Decide whether we have to bounce */
- if (VTOP(dest) >> 20 != 0 ||
- ((VTOP(dest) >> 16) != (VTOP(dest + blks * BIOSDISK_SECSIZE) >> 16))) {
- /*
- * There is a 64k physical boundary somewhere in the destination buffer, or the
- * destination buffer is above first 1MB of physical memory so we have
- * to arrange a suitable bounce buffer. Allocate a buffer twice as large as we
- * need to. Use the bottom half unless there is a break there, in which case we
- * use the top half.
- */
- x = min(od->od_sec, (unsigned)blks);
- bbuf = alloca(x * 2 * BIOSDISK_SECSIZE);
- if (((u_int32_t)VTOP(bbuf) & 0xffff0000) == ((u_int32_t)VTOP(bbuf + x * BIOSDISK_SECSIZE) & 0xffff0000)) {
- breg = bbuf;
- } else {
- breg = bbuf + x * BIOSDISK_SECSIZE;
- }
- maxfer = x; /* limit transfers to bounce region size */
- } else {
- breg = bbuf = NULL;
- maxfer = 0;
- }
-
- while (resid > 0) {
- x = dblk;
- cyl = x / bpc; /* block # / blocks per cylinder */
- x %= bpc; /* block offset into cylinder */
- hd = x / od->od_sec; /* offset / blocks per track */
- sec = x % od->od_sec; /* offset into track */
-
- /* play it safe and don't cross track boundaries (XXX this is probably unnecessary) */
- x = min(od->od_sec - sec, resid);
- if (maxfer > 0)
- x = min(x, maxfer); /* fit bounce buffer */
-
- /* where do we transfer to? */
- xp = bbuf == NULL ? p : breg;
-
- /* correct sector number for 1-based BIOS numbering */
- if ((od->od_unit & 0xf0) == 0x30 || (od->od_unit & 0xf0) == 0x90)
- sec++;
-
- /* Put your Data In, Put your Data out,
- Put your Data In, and shake it all about
- */
- if (bbuf != NULL)
- bcopy(p, breg, x * BIOSDISK_SECSIZE);
- p += (x * BIOSDISK_SECSIZE);
- dblk += x;
- resid -= x;
+ return (bd_io(od, dblk, blks, dest, 0));
+}
- /* 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 | od->od_unit;
- v86int();
- }
-
- v86.ctl = V86_FLAGS;
- v86.addr = 0x1b;
- if (od->od_flags & BD_FLOPPY) {
- v86.eax = 0xd500 | od->od_unit;
- v86.ecx = 0x0200 | (cyl & 0xff);
- } else {
- v86.eax = 0x0500 | od->od_unit;
- v86.ecx = cyl;
- }
- v86.edx = (hd << 8) | sec;
- v86.ebx = x * BIOSDISK_SECSIZE;
- v86.es = VTOPSEG(xp);
- v86.ebp = VTOPOFF(xp);
- v86int();
- result = (v86.efl & 0x1);
- if (result == 0)
- break;
- }
-
- DEBUG("%d sectors from %d/%d/%d to %p (0x%x) %s", x, cyl, hd,
- od->od_flags & BD_FLOPPY ? sec - 1 : sec, p, VTOP(p),
- result ? "failed" : "ok");
- /* BUG here, cannot use v86 in printf because putchar uses it too */
- DEBUG("ax = 0x%04x cx = 0x%04x dx = 0x%04x status 0x%x",
- od->od_flags & BD_FLOPPY ? 0xd600 | od->od_unit : 0x0600 | od->od_unit,
- od->od_flags & BD_FLOPPY ? 0x0200 | cyl : cyl, (hd << 8) | sec,
- (v86.eax >> 8) & 0xff);
+static int
+bd_write(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest)
+{
- if (result) {
- return(-1);
- }
- }
-
-/* hexdump(dest, (blks * BIOSDISK_SECSIZE)); */
- return(0);
+ return (bd_io(od, dblk, blks, dest, 1));
}
+
static int
bd_getgeom(struct open_disk *od)
{
OpenPOWER on IntegriCloud