Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 23 Oct 2018 08:41:14 -0700
From:      Cy Schubert <Cy.Schubert@cschubert.com>
To:        Toomas Soome <tsoome@FreeBSD.org>,  "src-committers@freebsd.org" <src-committers@freebsd.org>,  "svn-src-all@freebsd.org" <svn-src-all@freebsd.org>,  "svn-src-head@freebsd.org" <svn-src-head@freebsd.org>
Subject:   RE: svn commit: r339658 - head/stand/i386/libi386
Message-ID:  <20181023154112.067AD431@spqr.komquats.com>

next in thread | raw e-mail | index | archive | help
Thank you Toomas.

---
Sent using a tiny phone keyboard.
Apologies for any typos and autocorrect.
Also, this old phone only supports top post. Apologies.

Cy Schubert
<Cy.Schubert@cschubert.com> or <cy@freebsd.org>
The need of the many outweighs the greed of the few.
---

-----Original Message-----
From: Toomas Soome
Sent: 23/10/2018 07:44
To: src-committers@freebsd.org; svn-src-all@freebsd.org; svn-src-head@freeb=
sd.org
Subject: svn commit: r339658 - head/stand/i386/libi386

Author: tsoome
Date: Tue Oct 23 14:44:32 2018
New Revision: 339658
URL: https://svnweb.freebsd.org/changeset/base/339658

Log:
  loader: biosdisk interface should be able to cope with 4k sectors
 =20
  The 4kn support in current bios specific biosdisk.c is broken, as the cod=
e
  is only implementing the support for the 512B sector size.
 =20
  This work is building the support for custom size sectors, we still do as=
sume
  the requested data to be multiple of 512B blocks and we only do address t=
he
  biosdisk.c interface here.
 =20
  For reference, see also:
  https://www.illumos.org/issues/8303
  https://www.illumos.org/rb/r/547
 =20
  As the GELI is moved above biosdisk "layer", the GELI should just work
 =20
  Reviewed by:	imp
  Differential Revision:	https://reviews.freebsd.org/D11174

Modified:
  head/stand/i386/libi386/biosdisk.c

Modified: head/stand/i386/libi386/biosdisk.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- head/stand/i386/libi386/biosdisk.c	Tue Oct 23 14:38:08 2018	(r339657)
+++ head/stand/i386/libi386/biosdisk.c	Tue Oct 23 14:44:32 2018	(r339658)
@@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
 #include <stand.h>
 #include <machine/bootinfo.h>
 #include <stdarg.h>
+#include <stdbool.h>
=20
 #include <bootstrap.h>
 #include <btxv86.h>
@@ -255,10 +256,11 @@ bd_int13probe(struct bdinfo *bd)
 		 * Sector size must be a multiple of 512 bytes.
 		 * An alternate test would be to check power of 2,
 		 * powerof2(params.sector_size).
+		 * 4K is largest read buffer we can use at this time.
 		 */
-		if (params.sector_size % BIOSDISK_SECSIZE)
-			bd->bd_sectorsize =3D BIOSDISK_SECSIZE;
-		else
+		if (params.sector_size >=3D 512 &&
+		    params.sector_size <=3D 4096 &&
+		    (params.sector_size % BIOSDISK_SECSIZE) =3D=3D 0)
 			bd->bd_sectorsize =3D params.sector_size;
=20
 		total =3D bd->bd_sectorsize * params.sectors;
@@ -448,16 +450,29 @@ bd_realstrategy(void *devdata, int rw, daddr_t dblk, =
s
     char *buf, size_t *rsize)
 {
 	struct disk_devdesc *dev =3D (struct disk_devdesc *)devdata;
-	uint64_t		disk_blocks;
-	int			blks, rc;
+	uint64_t disk_blocks, offset;
+	size_t blks, blkoff, bsize, rest;
+	caddr_t bbuf;
+	int rc;
=20
-	if (size % BD(dev).bd_sectorsize) {
-		panic("bd_strategy: %d bytes I/O not multiple of block size",
-		    size);
+	/*
+	 * First make sure the IO size is a multiple of 512 bytes. While we do
+	 * process partial reads below, the strategy mechanism is built
+	 * assuming IO is a multiple of 512B blocks. If the request is not
+	 * a multiple of 512B blocks, it has to be some sort of bug.
+	 */
+	if (size =3D=3D 0 || (size % BIOSDISK_SECSIZE) !=3D 0) {
+		printf("bd_strategy: %d bytes I/O not multiple of %d\n",
+		    size, BIOSDISK_SECSIZE);
+		return (EIO);
 	}
=20
 	DEBUG("open_disk %p", dev);
=20
+	offset =3D dblk * BIOSDISK_SECSIZE;
+	dblk =3D offset / BD(dev).bd_sectorsize;
+	blkoff =3D offset % BD(dev).bd_sectorsize;
+
 	/*
 	 * Check the value of the size argument. We do have quite small
 	 * heap (64MB), but we do not know good upper limit, so we check against
@@ -465,11 +480,14 @@ bd_realstrategy(void *devdata, int rw, daddr_t dblk, =
s
 	 * while translating block count to bytes.
 	 */
 	if (size > INT_MAX) {
-		DEBUG("too large read: %zu bytes", size);
+		DEBUG("too large I/O: %zu bytes", size);
 		return (EIO);
 	}
=20
 	blks =3D size / BD(dev).bd_sectorsize;
+	if (blks =3D=3D 0 || (size % BD(dev).bd_sectorsize) !=3D 0)
+		blks++;
+
 	if (dblk > dblk + blks)
 		return (EIO);
=20
@@ -498,36 +516,75 @@ bd_realstrategy(void *devdata, int rw, daddr_t dblk, =
s
 	if (dblk + blks >=3D dev->d_offset + disk_blocks) {
 		blks =3D dev->d_offset + disk_blocks - dblk;
 		size =3D blks * BD(dev).bd_sectorsize;
-		DEBUG("short read %d", blks);
+		DEBUG("short I/O %d", blks);
 	}
=20
-	switch (rw & F_MASK) {
-	case F_READ:
-		DEBUG("read %d from %lld to %p", blks, dblk, buf);
+	if (V86_IO_BUFFER_SIZE / BD(dev).bd_sectorsize =3D=3D 0)
+		panic("BUG: Real mode buffer is too small\n");
=20
-		if (blks && (rc =3D bd_io(dev, dblk, blks, buf, BD_RD))) {
-			/* Filter out floppy controller errors */
-			if (BD(dev).bd_flags !=3D BD_FLOPPY || rc !=3D 0x20) {
-				printf("read %d from %lld to %p, error: 0x%x\n",
-				    blks, dblk, buf, rc);
+	bbuf =3D PTOV(V86_IO_BUFFER);
+	rest =3D size;
+
+	while (blks > 0) {
+		int x =3D min(blks, V86_IO_BUFFER_SIZE / BD(dev).bd_sectorsize);
+
+		switch (rw & F_MASK) {
+		case F_READ:
+			DEBUG("read %d from %lld to %p", x, dblk, buf);
+			bsize =3D BD(dev).bd_sectorsize * x - blkoff;
+			if (rest < bsize)
+				bsize =3D rest;
+
+			if ((rc =3D bd_io(dev, dblk, x, bbuf, BD_RD)) !=3D 0)
+				return (EIO);
+
+			bcopy(bbuf + blkoff, buf, bsize);
+			break;
+		case F_WRITE :
+			DEBUG("write %d from %lld to %p", x, dblk, buf);
+			if (blkoff !=3D 0) {
+				/*
+				 * We got offset to sector, read 1 sector to
+				 * bbuf.
+				 */
+				x =3D 1;
+				bsize =3D BD(dev).bd_sectorsize - blkoff;
+				bsize =3D min(bsize, rest);
+				rc =3D bd_io(dev, dblk, x, bbuf, BD_RD);
+			} else if (rest < BD(dev).bd_sectorsize) {
+				/*
+				 * The remaining block is not full
+				 * sector. Read 1 sector to bbuf.
+				 */
+				x =3D 1;
+				bsize =3D rest;
+				rc =3D bd_io(dev, dblk, x, bbuf, BD_RD);
+			} else {
+				/* We can write full sector(s). */
+				bsize =3D BD(dev).bd_sectorsize * x;
 			}
-			return (EIO);
-		}
-		break;
-	case F_WRITE :
-		DEBUG("write %d from %lld to %p", blks, dblk, buf);
+			/*
+			 * Put your Data In, Put your Data out,
+			 * Put your Data In, and shake it all about
+			 */
+			bcopy(buf, bbuf + blkoff, bsize);
+			if ((rc =3D bd_io(dev, dblk, x, bbuf, BD_WR)) !=3D 0)
+				return (EIO);
=20
-		if (blks && bd_io(dev, dblk, blks, buf, BD_WR)) {
-			DEBUG("write error");
-			return (EIO);
+			break;
+		default:
+			/* DO NOTHING */
+			return (EROFS);
 		}
-		break;
-	default:
-		/* DO NOTHING */
-		return (EROFS);
+
+		blkoff =3D 0;
+		buf +=3D bsize;
+		rest -=3D bsize;
+		blks -=3D x;
+		dblk +=3D x;
 	}
=20
-	if (rsize)
+	if (rsize !=3D NULL)
 		*rsize =3D size;
 	return (0);
 }
@@ -604,21 +661,16 @@ bd_io_workaround(struct disk_devdesc *dev)
 	bd_edd_io(dev, 0xffffffff, 1, (caddr_t)buf, BD_RD);
 }
=20
-
 static int
 bd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest,
     int dowrite)
 {
-	u_int	x, sec, result, resid, retry, maxfer;
-	caddr_t	p, xp, bbuf;
-   =20
+	int result, retry;
+
 	/* Just in case some idiot actually tries to read/write -1 blocks... */
 	if (blks < 0)
 		return (-1);
=20
-	resid =3D blks;
-	p =3D dest;
-
 	/*
 	 * Workaround for a problem with some HP ProLiant BIOS failing to work
 	 * out the boot disk after installation. hrs and kuriyama discovered
@@ -627,91 +679,49 @@ bd_io(struct disk_devdesc *dev, daddr_t dblk, int blk=
s
 	 * the bios. The problem is alleviated by doing an extra read before
 	 * the buggy read. It is not immediately known whether other models
 	 * are similarly affected.
+	 * Loop retrying the operation a couple of times.  The BIOS
+	 * may also retry.
 	 */
 	if (dowrite =3D=3D BD_RD && dblk >=3D 0x100000000)
 		bd_io_workaround(dev);
+	for (retry =3D 0; retry < 3; retry++) {
+		/* if retrying, reset the drive */
+		if (retry > 0) {
+			v86.ctl =3D V86_FLAGS;
+			v86.addr =3D 0x13;
+			v86.eax =3D 0;
+			v86.edx =3D BD(dev).bd_unit;
+			v86int();
+		}
=20
-	/* Decide whether we have to bounce */
-	if (VTOP(dest) >> 20 !=3D 0 || (BD(dev).bd_unit < 0x80 &&
-	    (VTOP(dest) >> 16) !=3D
-	    (VTOP(dest + blks * BD(dev).bd_sectorsize) >> 16))) {
+		if (BD(dev).bd_flags & BD_MODEEDD1)
+			result =3D bd_edd_io(dev, dblk, blks, dest, dowrite);
+		else
+			result =3D bd_chs_io(dev, dblk, blks, dest, dowrite);
=20
-		/*=20
-		 * 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 =3D V86_IO_BUFFER_SIZE / BD(dev).bd_sectorsize;
-		x =3D min(x, (unsigned)blks);
-		bbuf =3D PTOV(V86_IO_BUFFER);
-		maxfer =3D x;	/* limit transfers to bounce region size */
-	} else {
-		bbuf =3D NULL;
-		maxfer =3D 0;
+		if (result =3D=3D 0)
+			break;
 	}
-   =20
-	while (resid > 0) {
-		/*
-		 * Play it safe and don't cross track boundaries.
-		 * (XXX this is probably unnecessary)
-		 */
-		sec =3D dblk % BD(dev).bd_sec;	/* offset into track */
-		x =3D min(BD(dev).bd_sec - sec, resid);
-		if (maxfer > 0)
-			x =3D min(x, maxfer);		/* fit bounce buffer */
=20
-		/* where do we transfer to? */
-		xp =3D bbuf =3D=3D NULL ? p : bbuf;
-
-		/*
-		 * Put your Data In, Put your Data out,
-		 * Put your Data In, and shake it all about=20
-		 */
-		if (dowrite =3D=3D BD_WR && bbuf !=3D NULL)
-			bcopy(p, bbuf, x * BD(dev).bd_sectorsize);
-
-		/*
-		 * Loop retrying the operation a couple of times.  The BIOS
-		 * may also retry.
-		 */
-		for (retry =3D 0; retry < 3; retry++) {
-			/* if retrying, reset the drive */
-			if (retry > 0) {
-				v86.ctl =3D V86_FLAGS;
-				v86.addr =3D 0x13;
-				v86.eax =3D 0;
-				v86.edx =3D BD(dev).bd_unit;
-				v86int();
-			}
-
-			if (BD(dev).bd_flags & BD_MODEEDD1)
-				result =3D bd_edd_io(dev, dblk, x, xp, dowrite);
-			else
-				result =3D bd_chs_io(dev, dblk, x, xp, dowrite);
-			if (result =3D=3D 0)
-				break;
+	/*
+	 * 0x20 - Controller failure. This is common error when the
+	 * media is not present.
+	 */
+	if (result !=3D 0 && result !=3D 0x20) {
+		if (dowrite =3D=3D BD_WR) {
+			printf("%s%d: Write %d sector(s) from %p (0x%x) "
+			    "to %lld: 0x%x\n", dev->dd.d_dev->dv_name,
+			    dev->dd.d_unit, blks, dest, VTOP(dest), dblk,
+			    result);
+		} else {
+			printf("%s%d: Read %d sector(s) from %lld to %p "
+			    "(0x%x): 0x%x\n", dev->dd.d_dev->dv_name,
+			    dev->dd.d_unit, blks, dblk, dest, VTOP(dest),
+			    result);
 		}
-
-		if (dowrite =3D=3D BD_WR)
-			DEBUG("Write %d sector(s) from %p (0x%x) to %lld %s", x,
-			    p, VTOP(p), dblk, result ? "failed" : "ok");
-		else
-			DEBUG("Read %d sector(s) from %lld to %p (0x%x) %s", x,
-			    dblk, p, VTOP(p), result ? "failed" : "ok");
-		if (result) {
-			return (result);
-		}
-		if (dowrite =3D=3D BD_RD && bbuf !=3D NULL)
-			bcopy(bbuf, p, x * BD(dev).bd_sectorsize);
-		p +=3D (x * BD(dev).bd_sectorsize);
-		dblk +=3D x;
-		resid -=3D x;
 	}
=20
-	return (0);
+	return (result);
 }
=20
 /*




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20181023154112.067AD431>