From owner-svn-src-stable-11@freebsd.org Sun Apr 21 03:30:49 2019 Return-Path: Delivered-To: svn-src-stable-11@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id E9D6F157FD10; Sun, 21 Apr 2019 03:30:48 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 9BBA7885B9; Sun, 21 Apr 2019 03:30:48 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 75FB01F9D2; Sun, 21 Apr 2019 03:30:48 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x3L3Umqh015697; Sun, 21 Apr 2019 03:30:48 GMT (envelope-from kevans@FreeBSD.org) Received: (from kevans@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x3L3UlHt015693; Sun, 21 Apr 2019 03:30:47 GMT (envelope-from kevans@FreeBSD.org) Message-Id: <201904210330.x3L3UlHt015693@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kevans set sender to kevans@FreeBSD.org using -f From: Kyle Evans Date: Sun, 21 Apr 2019 03:30:47 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r346475 - in stable/11/stand: common i386/libi386 i386/loader X-SVN-Group: stable-11 X-SVN-Commit-Author: kevans X-SVN-Commit-Paths: in stable/11/stand: common i386/libi386 i386/loader X-SVN-Commit-Revision: 346475 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: 9BBA7885B9 X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.95 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.999,0]; NEURAL_HAM_SHORT(-0.95)[-0.954,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US]; NEURAL_HAM_LONG(-1.00)[-1.000,0] X-BeenThere: svn-src-stable-11@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: SVN commit messages for only the 11-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 21 Apr 2019 03:30:49 -0000 Author: kevans Date: Sun Apr 21 03:30:47 2019 New Revision: 346475 URL: https://svnweb.freebsd.org/changeset/base/346475 Log: MFC r339658, r339959, r340047, r340049, r340215 r339658: loader: biosdisk interface should be able to cope with 4k sectors The 4kn support in current bios specific biosdisk.c is broken, as the code is only implementing the support for the 512B sector size. This work is building the support for custom size sectors, we still do assume the requested data to be multiple of 512B blocks and we only do address the biosdisk.c interface here. For reference, see also: https://www.illumos.org/issues/8303 https://www.illumos.org/rb/r/547 As the GELI is moved above biosdisk "layer", the GELI should just work r339959: loader: issue edd probe before legacy ah=08 and detect no media while probing for drives, use int13 extended info before standard one and provide workaround for case we are not getting needed information in case of floppy drive. In case of INT13 errors, there are (at least) 3 error codes appearing in case of missin media - 20h, 31h and 80h. Flag the no media and do not print an error. r340047: loader: do not probe floppy devices for zfs The subject is telling it all. r340049: loader: biosdisk should check if the media is present The bd_print/bd_open/bd_strategy need to make sure the device does have media, before getting into performing IO operations. Some systems can hung if the device without a media is accessed. r340215: loader: always set media size from partition. The disk access is validated by using partition table definitions, therefore we have no need for if statements, just set the disk size. Of course the partition table itself may be incorrect/inconsistent, but if so, we are in trouble anyhow. Modified: stable/11/stand/common/disk.c stable/11/stand/common/part.c stable/11/stand/i386/libi386/biosdisk.c stable/11/stand/i386/loader/main.c Directory Properties: stable/11/ (props changed) Modified: stable/11/stand/common/disk.c ============================================================================== --- stable/11/stand/common/disk.c Sun Apr 21 03:27:12 2019 (r346474) +++ stable/11/stand/common/disk.c Sun Apr 21 03:30:47 2019 (r346475) @@ -265,9 +265,7 @@ disk_open(struct disk_devdesc *dev, uint64_t mediasize rc = ENXIO; goto out; } - if (mediasize > od->mediasize) { - od->mediasize = mediasize; - } + od->mediasize = mediasize; if (ptable_gettype(od->table) == PTABLE_BSD && partition >= 0) { Modified: stable/11/stand/common/part.c ============================================================================== --- stable/11/stand/common/part.c Sun Apr 21 03:27:12 2019 (r346474) +++ stable/11/stand/common/part.c Sun Apr 21 03:30:47 2019 (r346475) @@ -323,8 +323,7 @@ ptable_gptread(struct ptable *table, void *dev, diskre * Note, this is still not a foolproof way to get disk's size. For * example, an image file can be truncated when copied to smaller media. */ - if (hdr.hdr_lba_alt + 1 > table->sectors) - table->sectors = hdr.hdr_lba_alt + 1; + table->sectors = hdr.hdr_lba_alt + 1; for (i = 0; i < size / hdr.hdr_entsz; i++) { ent = (struct gpt_ent *)(tbl + i * hdr.hdr_entsz); Modified: stable/11/stand/i386/libi386/biosdisk.c ============================================================================== --- stable/11/stand/i386/libi386/biosdisk.c Sun Apr 21 03:27:12 2019 (r346474) +++ stable/11/stand/i386/libi386/biosdisk.c Sun Apr 21 03:30:47 2019 (r346475) @@ -80,8 +80,10 @@ static struct bdinfo #define BD_MODEINT13 0x0000 #define BD_MODEEDD1 0x0001 #define BD_MODEEDD3 0x0002 +#define BD_MODEEDD (BD_MODEEDD1 | BD_MODEEDD3) #define BD_MODEMASK 0x0003 #define BD_FLOPPY 0x0004 +#define BD_NO_MEDIA 0x0008 int bd_type; /* BIOS 'drive type' (floppy only) */ uint16_t bd_sectorsize; /* Sector size */ uint64_t bd_sectors; /* Disk size */ @@ -187,60 +189,83 @@ bd_init(void) } /* - * Try to detect a device supported by the legacy int13 BIOS + * Return EDD version or 0 if EDD is not supported on this drive. */ static int -bd_int13probe(struct bdinfo *bd) +bd_check_extensions(int unit) { - struct edd_params params; - int ret = 1; /* assume success */ + /* Determine if we can use EDD with this device. */ + v86.ctl = V86_FLAGS; + v86.addr = 0x13; + v86.eax = 0x4100; + v86.edx = unit; + v86.ebx = 0x55aa; + v86int(); + if (V86_CY(v86.efl) || /* carry set */ + (v86.ebx & 0xffff) != 0xaa55) /* signature */ + return (0); + + /* extended disk access functions (AH=42h-44h,47h,48h) supported */ + if ((v86.ecx & EDD_INTERFACE_FIXED_DISK) == 0) + return (0); + + return ((v86.eax >> 8) & 0xff); +} + +static void +bd_reset_disk(int unit) +{ + /* reset disk */ v86.ctl = V86_FLAGS; v86.addr = 0x13; + v86.eax = 0; + v86.edx = unit; + v86int(); +} + +/* + * Read CHS info. Return 0 on success, error otherwise. + */ +static int +bd_get_diskinfo_std(struct bdinfo *bd) +{ + bzero(&v86, sizeof(v86)); + v86.ctl = V86_FLAGS; + v86.addr = 0x13; v86.eax = 0x800; v86.edx = bd->bd_unit; v86int(); - /* Don't error out if we get bad sector number, try EDD as well */ - if (V86_CY(v86.efl) || /* carry set */ - (v86.edx & 0xff) <= (unsigned)(bd->bd_unit & 0x7f)) /* unit # bad */ - return (0); /* skip device */ + if (V86_CY(v86.efl) && ((v86.eax & 0xff00) != 0)) + return ((v86.eax & 0xff00) >> 8); - if ((v86.ecx & 0x3f) == 0) /* absurd sector number */ - ret = 0; /* set error */ + /* return custom error on absurd sector number */ + if ((v86.ecx & 0x3f) == 0) + return (0x60); - /* Convert max cyl # -> # of cylinders */ bd->bd_cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1; /* Convert max head # -> # of heads */ bd->bd_hds = ((v86.edx & 0xff00) >> 8) + 1; bd->bd_sec = v86.ecx & 0x3f; - bd->bd_type = v86.ebx & 0xff; - bd->bd_flags |= BD_MODEINT13; + bd->bd_type = v86.ebx; + bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec; - /* Calculate sectors count from the geometry */ - bd->bd_sectors = bd->bd_cyl * bd->bd_hds * bd->bd_sec; - bd->bd_sectorsize = BIOSDISK_SECSIZE; - DEBUG("unit 0x%x geometry %d/%d/%d", bd->bd_unit, bd->bd_cyl, - bd->bd_hds, bd->bd_sec); + return (0); +} - /* Determine if we can use EDD with this device. */ - v86.ctl = V86_FLAGS; - v86.addr = 0x13; - v86.eax = 0x4100; - v86.edx = bd->bd_unit; - v86.ebx = 0x55aa; - v86int(); - if (V86_CY(v86.efl) || /* carry set */ - (v86.ebx & 0xffff) != 0xaa55 || /* signature */ - (v86.ecx & EDD_INTERFACE_FIXED_DISK) == 0) - return (ret); /* return code from int13 AH=08 */ +/* + * Read EDD info. Return 0 on success, error otherwise. + */ +static int +bd_get_diskinfo_ext(struct bdinfo *bd) +{ + struct edd_params params; + uint64_t total; - /* EDD supported */ - bd->bd_flags |= BD_MODEEDD1; - if ((v86.eax & 0xff00) >= 0x3000) - bd->bd_flags |= BD_MODEEDD3; /* Get disk params */ - params.len = sizeof(struct edd_params); + bzero(¶ms, sizeof(params)); + params.len = sizeof(params); v86.ctl = V86_FLAGS; v86.addr = 0x13; v86.eax = 0x4800; @@ -248,36 +273,120 @@ bd_int13probe(struct bdinfo *bd) v86.ds = VTOPSEG(¶ms); v86.esi = VTOPOFF(¶ms); v86int(); - if (!V86_CY(v86.efl)) { - uint64_t total; - /* - * Sector size must be a multiple of 512 bytes. - * An alternate test would be to check power of 2, - * powerof2(params.sector_size). - */ - if (params.sector_size % BIOSDISK_SECSIZE) - bd->bd_sectorsize = BIOSDISK_SECSIZE; - else - bd->bd_sectorsize = params.sector_size; + if (V86_CY(v86.efl) && ((v86.eax & 0xff00) != 0)) + return ((v86.eax & 0xff00) >> 8); - total = bd->bd_sectorsize * params.sectors; - if (params.sectors != 0) { - /* Only update if we did not overflow. */ - if (total > params.sectors) - bd->bd_sectors = params.sectors; - } + /* + * 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 >= 512 && + params.sector_size <= 4096 && + (params.sector_size % BIOSDISK_SECSIZE) == 0) + bd->bd_sectorsize = params.sector_size; + bd->bd_cyl = params.cylinders; + bd->bd_hds = params.heads; + bd->bd_sec = params.sectors_per_track; + + if (params.sectors != 0) { + total = params.sectors; + } else { total = (uint64_t)params.cylinders * params.heads * params.sectors_per_track; - if (total > 0 && bd->bd_sectors > total) - bd->bd_sectors = total; + } + bd->bd_sectors = total; - ret = 1; + return (0); +} + +/* + * Try to detect a device supported by the legacy int13 BIOS + */ +static int +bd_int13probe(struct bdinfo *bd) +{ + int edd; + int ret; + + bd->bd_flags &= ~BD_NO_MEDIA; + + edd = bd_check_extensions(bd->bd_unit); + if (edd == 0) + bd->bd_flags |= BD_MODEINT13; + else if (edd < 0x30) + bd->bd_flags |= BD_MODEEDD1; + else + bd->bd_flags |= BD_MODEEDD3; + + /* Default sector size */ + bd->bd_sectorsize = BIOSDISK_SECSIZE; + + /* + * Test if the floppy device is present, so we can avoid receiving + * bogus information from bd_get_diskinfo_std(). + */ + if (bd->bd_unit < 0x80) { + /* reset disk */ + bd_reset_disk(bd->bd_unit); + + /* Get disk type */ + v86.ctl = V86_FLAGS; + v86.addr = 0x13; + v86.eax = 0x1500; + v86.edx = bd->bd_unit; + v86int(); + if (V86_CY(v86.efl) || (v86.eax & 0x300) == 0) + return (0); } - DEBUG("unit 0x%x flags %x, sectors %llu, sectorsize %u", - bd->bd_unit, bd->bd_flags, bd->bd_sectors, bd->bd_sectorsize); - return (ret); + + ret = 1; + if (edd != 0) + ret = bd_get_diskinfo_ext(bd); + if (ret != 0 || bd->bd_sectors == 0) + ret = bd_get_diskinfo_std(bd); + + if (ret != 0 && bd->bd_unit < 0x80) { + /* Set defaults for 1.44 floppy */ + bd->bd_cyl = 80; + bd->bd_hds = 2; + bd->bd_sec = 18; + bd->bd_type = 4; + bd->bd_sectors = 2880; + /* Since we are there, there most likely is no media */ + bd->bd_flags |= BD_NO_MEDIA; + ret = 0; + } + + if (ret != 0) { + if (bd->bd_sectors != 0 && edd != 0) { + bd->bd_sec = 63; + bd->bd_hds = 255; + bd->bd_cyl = + (bd->bd_sectors + bd->bd_sec * bd->bd_hds - 1) / + bd->bd_sec * bd->bd_hds; + } else { + printf("Can not get information about %s unit %#x\n", + biosdisk.dv_name, bd->bd_unit); + return (0); + } + } + + if (bd->bd_sec == 0) + bd->bd_sec = 63; + if (bd->bd_hds == 0) + bd->bd_hds = 255; + + if (bd->bd_sectors == 0) + bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec; + + DEBUG("unit 0x%x geometry %d/%d/%d", bd->bd_unit, bd->bd_cyl, + bd->bd_hds, bd->bd_sec); + + return (1); } /* @@ -299,14 +408,19 @@ bd_print(int verbose) for (i = 0; i < nbdinfo; i++) { snprintf(line, sizeof(line), - " disk%d: BIOS drive %c (%ju X %u):\n", i, + " disk%d: BIOS drive %c (%s%ju X %u):\n", i, (bdinfo[i].bd_unit < 0x80) ? ('A' + bdinfo[i].bd_unit): ('C' + bdinfo[i].bd_unit - 0x80), + (bdinfo[i].bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA ? + "no media, " : "", (uintmax_t)bdinfo[i].bd_sectors, bdinfo[i].bd_sectorsize); if ((ret = pager_output(line)) != 0) break; + if ((bdinfo[i].bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) + continue; + dev.dd.d_dev = &biosdisk; dev.dd.d_unit = i; dev.d_slice = -1; @@ -325,6 +439,33 @@ bd_print(int verbose) } /* + * Read disk size from partition. + * This is needed to work around buggy BIOS systems returning + * wrong (truncated) disk media size. + * During bd_probe() we tested if the multiplication of bd_sectors + * would overflow so it should be safe to perform here. + */ +static uint64_t +bd_disk_get_sectors(struct disk_devdesc *dev) +{ + struct disk_devdesc disk; + uint64_t size; + + disk.dd.d_dev = dev->dd.d_dev; + disk.dd.d_unit = dev->dd.d_unit; + disk.d_slice = -1; + disk.d_partition = -1; + disk.d_offset = 0; + + size = BD(dev).bd_sectors * BD(dev).bd_sectorsize; + if (disk_open(&disk, size, BD(dev).bd_sectorsize) == 0) { + (void) disk_ioctl(&disk, DIOCGMEDIASIZE, &size); + disk_close(&disk); + } + return (size / BD(dev).bd_sectorsize); +} + +/* * Attempt to open the disk described by (dev) for use by (f). * * Note that the philosophy here is "give them exactly what @@ -338,9 +479,7 @@ static int bd_open(struct open_file *f, ...) { struct disk_devdesc *dev; - struct disk_devdesc disk; va_list ap; - uint64_t size; int rc; va_start(ap, f); @@ -349,34 +488,20 @@ bd_open(struct open_file *f, ...) if (dev->dd.d_unit < 0 || dev->dd.d_unit >= nbdinfo) return (EIO); - BD(dev).bd_open++; + + if ((BD(dev).bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) { + if (!bd_int13probe(&BD(dev))) + return (EIO); + if ((BD(dev).bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) + return (EIO); + } if (BD(dev).bd_bcache == NULL) BD(dev).bd_bcache = bcache_allocate(); - /* - * Read disk size from partition. - * This is needed to work around buggy BIOS systems returning - * wrong (truncated) disk media size. - * During bd_probe() we tested if the mulitplication of bd_sectors - * would overflow so it should be safe to perform here. - */ - disk.dd.d_dev = dev->dd.d_dev; - disk.dd.d_unit = dev->dd.d_unit; - disk.d_slice = -1; - disk.d_partition = -1; - disk.d_offset = 0; + if (BD(dev).bd_open == 0) + BD(dev).bd_sectors = bd_disk_get_sectors(dev); + BD(dev).bd_open++; - if (disk_open(&disk, BD(dev).bd_sectors * BD(dev).bd_sectorsize, - BD(dev).bd_sectorsize) == 0) { - - if (disk_ioctl(&disk, DIOCGMEDIASIZE, &size) == 0) { - size /= BD(dev).bd_sectorsize; - if (size > BD(dev).bd_sectors) - BD(dev).bd_sectors = size; - } - disk_close(&disk); - } - rc = disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize, BD(dev).bd_sectorsize); if (rc != 0) { @@ -448,16 +573,32 @@ bd_realstrategy(void *devdata, int rw, daddr_t dblk, s char *buf, size_t *rsize) { struct disk_devdesc *dev = (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; - if (size % BD(dev).bd_sectorsize) { - panic("bd_strategy: %d bytes I/O not multiple of block size", - size); + if ((BD(dev).bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) + return (EIO); + + /* + * 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 == 0 || (size % BIOSDISK_SECSIZE) != 0) { + printf("bd_strategy: %d bytes I/O not multiple of %d\n", + size, BIOSDISK_SECSIZE); + return (EIO); } DEBUG("open_disk %p", dev); + offset = dblk * BIOSDISK_SECSIZE; + dblk = offset / BD(dev).bd_sectorsize; + blkoff = 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 +606,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); } blks = size / BD(dev).bd_sectorsize; + if (blks == 0 || (size % BD(dev).bd_sectorsize) != 0) + blks++; + if (dblk > dblk + blks) return (EIO); @@ -481,7 +625,7 @@ bd_realstrategy(void *devdata, int rw, daddr_t dblk, s * partition. */ if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) { - /* DIOCGMEDIASIZE returns bytes. */ + /* DIOCGMEDIASIZE does return bytes. */ disk_blocks /= BD(dev).bd_sectorsize; } else { /* We should not get here. Just try to survive. */ @@ -498,36 +642,75 @@ bd_realstrategy(void *devdata, int rw, daddr_t dblk, s if (dblk + blks >= dev->d_offset + disk_blocks) { blks = dev->d_offset + disk_blocks - dblk; size = blks * BD(dev).bd_sectorsize; - DEBUG("short read %d", blks); + DEBUG("short I/O %d", blks); } - 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 == 0) + panic("BUG: Real mode buffer is too small\n"); - if (blks && (rc = bd_io(dev, dblk, blks, buf, BD_RD))) { - /* Filter out floppy controller errors */ - if (BD(dev).bd_flags != BD_FLOPPY || rc != 0x20) { - printf("read %d from %lld to %p, error: 0x%x\n", - blks, dblk, buf, rc); + bbuf = PTOV(V86_IO_BUFFER); + rest = size; + + while (blks > 0) { + int x = 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 = BD(dev).bd_sectorsize * x - blkoff; + if (rest < bsize) + bsize = rest; + + if ((rc = bd_io(dev, dblk, x, bbuf, BD_RD)) != 0) + return (EIO); + + bcopy(bbuf + blkoff, buf, bsize); + break; + case F_WRITE : + DEBUG("write %d from %lld to %p", x, dblk, buf); + if (blkoff != 0) { + /* + * We got offset to sector, read 1 sector to + * bbuf. + */ + x = 1; + bsize = BD(dev).bd_sectorsize - blkoff; + bsize = min(bsize, rest); + rc = 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 = 1; + bsize = rest; + rc = bd_io(dev, dblk, x, bbuf, BD_RD); + } else { + /* We can write full sector(s). */ + bsize = 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 = bd_io(dev, dblk, x, bbuf, BD_WR)) != 0) + return (EIO); - 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 = 0; + buf += bsize; + rest -= bsize; + blks -= x; + dblk += x; } - if (rsize) + if (rsize != NULL) *rsize = size; return (0); } @@ -604,21 +787,16 @@ bd_io_workaround(struct disk_devdesc *dev) bd_edd_io(dev, 0xffffffff, 1, (caddr_t)buf, BD_RD); } - 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; - + int result, retry; + /* Just in case some idiot actually tries to read/write -1 blocks... */ if (blks < 0) return (-1); - resid = blks; - p = 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 +805,53 @@ bd_io(struct disk_devdesc *dev, daddr_t dblk, int blks * 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 == BD_RD && dblk >= 0x100000000) bd_io_workaround(dev); + for (retry = 0; retry < 3; retry++) { + if (BD(dev).bd_flags & BD_MODEEDD) + result = bd_edd_io(dev, dblk, blks, dest, dowrite); + else + result = bd_chs_io(dev, dblk, blks, dest, dowrite); - /* Decide whether we have to bounce */ - if (VTOP(dest) >> 20 != 0 || (BD(dev).bd_unit < 0x80 && - (VTOP(dest) >> 16) != - (VTOP(dest + blks * BD(dev).bd_sectorsize) >> 16))) { + if (result == 0) { + if (BD(dev).bd_flags & BD_NO_MEDIA) + BD(dev).bd_flags &= ~BD_NO_MEDIA; + break; + } - /* - * 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 = V86_IO_BUFFER_SIZE / BD(dev).bd_sectorsize; - x = min(x, (unsigned)blks); - bbuf = PTOV(V86_IO_BUFFER); - maxfer = x; /* limit transfers to bounce region size */ - } else { - bbuf = NULL; - maxfer = 0; - } - - while (resid > 0) { - /* - * Play it safe and don't cross track boundaries. - * (XXX this is probably unnecessary) - */ - sec = dblk % BD(dev).bd_sec; /* offset into track */ - x = min(BD(dev).bd_sec - sec, resid); - if (maxfer > 0) - x = min(x, maxfer); /* fit bounce buffer */ + bd_reset_disk(BD(dev).bd_unit); - /* where do we transfer to? */ - xp = bbuf == NULL ? p : bbuf; - /* - * Put your Data In, Put your Data out, - * Put your Data In, and shake it all about + * Error codes: + * 20h controller failure + * 31h no media in drive (IBM/MS INT 13 extensions) + * 80h no media in drive, VMWare (Fusion) + * There is no reason to repeat the IO with errors above. */ - if (dowrite == BD_WR && bbuf != NULL) - bcopy(p, bbuf, x * BD(dev).bd_sectorsize); - - /* - * 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 = BD(dev).bd_unit; - v86int(); - } - - if (BD(dev).bd_flags & BD_MODEEDD1) - result = bd_edd_io(dev, dblk, x, xp, dowrite); - else - result = bd_chs_io(dev, dblk, x, xp, dowrite); - if (result == 0) - break; + if (result == 0x20 || result == 0x31 || result == 0x80) { + BD(dev).bd_flags |= BD_NO_MEDIA; + break; } + } - if (dowrite == 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 (result != 0 && (BD(dev).bd_flags & BD_NO_MEDIA) == 0) { + if (dowrite == 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 == BD_RD && bbuf != NULL) - bcopy(bbuf, p, x * BD(dev).bd_sectorsize); - p += (x * BD(dev).bd_sectorsize); - dblk += x; - resid -= x; } - return (0); + return (result); } /* Modified: stable/11/stand/i386/loader/main.c ============================================================================== --- stable/11/stand/i386/loader/main.c Sun Apr 21 03:27:12 2019 (r346474) +++ stable/11/stand/i386/loader/main.c Sun Apr 21 03:30:47 2019 (r346475) @@ -408,6 +408,8 @@ i386_zfs_probe(void) for (unit = 0; unit < MAXBDDEV; unit++) { if (bd_unit2bios(unit) == -1) break; + if (bd_unit2bios(unit) < 0x80) + continue; sprintf(devname, "disk%d:", unit); zfs_probe_dev(devname, NULL); }