I forgot to note imp, sorry…

rgds,
toomas

> On 31 Oct 2018, at 18:42, Toomas Soome <tso...@freebsd.org> wrote:
> 
> Author: tsoome
> Date: Wed Oct 31 16:42:40 2018
> New Revision: 339959
> URL: https://svnweb.freebsd.org/changeset/base/339959
> 
> Log:
>  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.
> 
>  Differential Revision:       https://reviews.freebsd.org/D17667
> 
> Modified:
>  head/stand/i386/libi386/biosdisk.c
> 
> Modified: head/stand/i386/libi386/biosdisk.c
> ==============================================================================
> --- head/stand/i386/libi386/biosdisk.c        Wed Oct 31 16:17:45 2018        
> (r339958)
> +++ head/stand/i386/libi386/biosdisk.c        Wed Oct 31 16:42:40 2018        
> (r339959)
> @@ -43,7 +43,6 @@ __FBSDID("$FreeBSD$");
> #include <stand.h>
> #include <machine/bootinfo.h>
> #include <stdarg.h>
> -#include <stdbool.h>
> 
> #include <bootstrap.h>
> #include <btxv86.h>
> @@ -81,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 */
> @@ -188,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(&params, sizeof(params));
> +     params.len = sizeof(params);
>       v86.ctl = V86_FLAGS;
>       v86.addr = 0x13;
>       v86.eax = 0x4800;
> @@ -249,37 +273,120 @@ bd_int13probe(struct bdinfo *bd)
>       v86.ds = VTOPSEG(&params);
>       v86.esi = VTOPOFF(&params);
>       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).
> -              * 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;
> +     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);
> }
> 
> /*
> @@ -301,9 +408,11 @@ 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)
> @@ -351,6 +460,11 @@ bd_open(struct open_file *f, ...)
> 
>       if (dev->dd.d_unit < 0 || dev->dd.d_unit >= nbdinfo)
>               return (EIO);
> +
> +     if ((BD(dev).bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) {
> +             if (!bd_int13probe(&BD(dev)))
> +                     return (EIO);
> +     }
>       BD(dev).bd_open++;
>       if (BD(dev).bd_bcache == NULL)
>           BD(dev).bd_bcache = bcache_allocate();
> @@ -499,7 +613,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. */
> @@ -685,29 +799,33 @@ bd_io(struct disk_devdesc *dev, daddr_t dblk, int blks
>       if (dowrite == BD_RD && dblk >= 0x100000000)
>               bd_io_workaround(dev);
>       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)
> +             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);
> 
> -             if (result == 0)
> +             if (result == 0) {
> +                     if (BD(dev).bd_flags & BD_NO_MEDIA)
> +                             BD(dev).bd_flags &= ~BD_NO_MEDIA;
>                       break;
> +             }
> +
> +             bd_reset_disk(BD(dev).bd_unit);
> +
> +             /*
> +              * 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 (result == 0x20 || result == 0x31 || result == 0x80) {
> +                     BD(dev).bd_flags |= BD_NO_MEDIA;
> +                     break;
> +             }
>       }
> 
> -     /*
> -      * 0x20 - Controller failure. This is common error when the
> -      * media is not present.
> -      */
> -     if (result != 0 && result != 0x20) {
> +     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,
> 

_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to