summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/boot/i386/libi386/bioscd.c112
-rw-r--r--sys/boot/i386/libi386/biosdisk.c8
-rw-r--r--sys/boot/i386/libi386/libi386.h8
3 files changed, 81 insertions, 47 deletions
diff --git a/sys/boot/i386/libi386/bioscd.c b/sys/boot/i386/libi386/bioscd.c
index 93de958..a6dba0c 100644
--- a/sys/boot/i386/libi386/bioscd.c
+++ b/sys/boot/i386/libi386/bioscd.c
@@ -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_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;
@@ -244,9 +244,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);
}
@@ -257,11 +257,15 @@ 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;
+ 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, 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 = 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);
diff --git a/sys/boot/i386/libi386/biosdisk.c b/sys/boot/i386/libi386/biosdisk.c
index 9d31325..a54418f 100644
--- a/sys/boot/i386/libi386/biosdisk.c
+++ b/sys/boot/i386/libi386/biosdisk.c
@@ -1125,14 +1125,6 @@ bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, siz
/* 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)
{
diff --git a/sys/boot/i386/libi386/libi386.h b/sys/boot/i386/libi386/libi386.h
index ccae099..4ac5cb5 100644
--- a/sys/boot/i386/libi386/libi386.h
+++ b/sys/boot/i386/libi386/libi386.h
@@ -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);
OpenPOWER on IntegriCloud