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>