[BACK]Return to biosdev.c CVS log [TXT][DIR] Up to [local] / sys / arch / i386 / stand / libsa

Annotation of sys/arch/i386/stand/libsa/biosdev.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: biosdev.c,v 1.72 2007/05/27 00:57:17 tom Exp $        */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 1996 Michael Shalayeff
        !             5:  * Copyright (c) 2003 Tobias Weingartner
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer.
        !            13:  * 2. Redistributions in binary form must reproduce the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer in the
        !            15:  *    documentation and/or other materials provided with the distribution.
        !            16:  *
        !            17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            18:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
        !            19:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            20:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            21:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            22:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            23:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            24:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            25:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            26:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            27:  * SUCH DAMAGE.
        !            28:  *
        !            29:  */
        !            30:
        !            31: #include <sys/param.h>
        !            32: #include <sys/reboot.h>
        !            33: #include <sys/disklabel.h>
        !            34: #include <machine/tss.h>
        !            35: #include <machine/biosvar.h>
        !            36: #include <lib/libsa/saerrno.h>
        !            37: #include <isofs/cd9660/iso.h>
        !            38: #include "disk.h"
        !            39: #include "debug.h"
        !            40: #include "libsa.h"
        !            41: #include "biosdev.h"
        !            42:
        !            43: static const char *biosdisk_err(u_int);
        !            44: static int biosdisk_errno(u_int);
        !            45:
        !            46: static int CHS_rw (int, int, int, int, int, int, void *);
        !            47: static int EDD_rw (int, int, u_int64_t, u_int32_t, void *);
        !            48:
        !            49: extern int debug;
        !            50: int bios_bootdev;
        !            51: int bios_cddev = -1;           /* Set by srt0 if coming from CD */
        !            52:
        !            53: #if 0
        !            54: struct biosdisk {
        !            55:        bios_diskinfo_t *bios_info;
        !            56:        dev_t   bsddev;
        !            57:        struct disklabel disklabel;
        !            58: };
        !            59: #endif
        !            60:
        !            61: struct EDD_CB {
        !            62:        u_int8_t  edd_len;      /* size of packet */
        !            63:        u_int8_t  edd_res1;     /* reserved */
        !            64:        u_int8_t  edd_nblk;     /* # of blocks to transfer */
        !            65:        u_int8_t  edd_res2;     /* reserved */
        !            66:        u_int16_t edd_off;      /* address of buffer (offset) */
        !            67:        u_int16_t edd_seg;      /* address of buffer (segment) */
        !            68:        u_int64_t edd_daddr;    /* starting block */
        !            69: };
        !            70:
        !            71: /*
        !            72:  * reset disk system
        !            73:  */
        !            74: static int
        !            75: biosdreset(int dev)
        !            76: {
        !            77:        int rv;
        !            78:
        !            79:        __asm __volatile (DOINT(0x13) "; setc %b0" : "=a" (rv)
        !            80:            : "0" (0), "d" (dev) : "%ecx", "cc");
        !            81:
        !            82:        return ((rv & 0xff)? rv >> 8 : 0);
        !            83: }
        !            84:
        !            85: /*
        !            86:  * Fill out a bios_diskinfo_t for this device.
        !            87:  * Return 0 if all ok.
        !            88:  * Return 1 if not ok.
        !            89:  */
        !            90: int
        !            91: bios_getdiskinfo(int dev, bios_diskinfo_t *pdi)
        !            92: {
        !            93:        u_int rv;
        !            94:
        !            95:        /* Just reset, don't check return code */
        !            96:        rv = biosdreset(dev);
        !            97:
        !            98: #ifdef BIOS_DEBUG
        !            99:        if (debug)
        !           100:                printf("getinfo: try #8, 0x%x, %p\n", dev, pdi);
        !           101: #endif
        !           102:        __asm __volatile (DOINT(0x13) "\n\t"
        !           103:            "setc %b0; movzbl %h1, %1\n\t"
        !           104:            "movzbl %%cl, %3; andb $0x3f, %b3\n\t"
        !           105:            "xchgb %%cl, %%ch; rolb $2, %%ch"
        !           106:            : "=a" (rv), "=d" (pdi->bios_heads),
        !           107:              "=c" (pdi->bios_cylinders),
        !           108:              "=b" (pdi->bios_sectors)
        !           109:            : "0" (0x0800), "1" (dev) : "cc");
        !           110:
        !           111: #ifdef BIOS_DEBUG
        !           112:        if (debug) {
        !           113:                printf("getinfo: got #8\n");
        !           114:                printf("disk 0x%x: %d,%d,%d\n", dev, pdi->bios_cylinders,
        !           115:                    pdi->bios_heads, pdi->bios_sectors);
        !           116:        }
        !           117: #endif
        !           118:        if (rv & 0xff)
        !           119:                return 1;
        !           120:
        !           121:        /* Fix up info */
        !           122:        pdi->bios_number = dev;
        !           123:        pdi->bios_heads++;
        !           124:        pdi->bios_cylinders &= 0x3ff;
        !           125:        pdi->bios_cylinders++;
        !           126:
        !           127:        /* Sanity check */
        !           128:        if (!pdi->bios_cylinders || !pdi->bios_heads || !pdi->bios_sectors)
        !           129:                return 1;
        !           130:
        !           131:        /* CD-ROMs sometimes return heads == 1 */
        !           132:        if (pdi->bios_heads < 2)
        !           133:                return 1;
        !           134:
        !           135:        /* NOTE:
        !           136:         * This currently hangs/reboots some machines
        !           137:         * The IBM ThinkPad 750ED for one.
        !           138:         *
        !           139:         * Funny that an IBM/MS extension would not be
        !           140:         * implemented by an IBM system...
        !           141:         *
        !           142:         * Future hangs (when reported) can be "fixed"
        !           143:         * with getSYSCONFaddr() and an exceptions list.
        !           144:         */
        !           145:        if (dev & 0x80 && (dev == 0x80 || dev == 0x81 || dev == bios_bootdev)) {
        !           146:                int bm;
        !           147:
        !           148: #ifdef BIOS_DEBUG
        !           149:                if (debug)
        !           150:                        printf("getinfo: try #41, 0x%x\n", dev);
        !           151: #endif
        !           152:                /* EDD support check */
        !           153:                __asm __volatile(DOINT(0x13) "; setc %b0"
        !           154:                         : "=a" (rv), "=c" (bm)
        !           155:                         : "0" (0x4100), "b" (0x55aa), "d" (dev) : "cc");
        !           156:                if (!(rv & 0xff) && (BIOS_regs.biosr_bx & 0xffff) == 0xaa55)
        !           157:                        pdi->bios_edd = (bm & 0xffff) | ((rv & 0xff) << 16);
        !           158:                else
        !           159:                        pdi->bios_edd = -1;
        !           160:
        !           161: #ifdef BIOS_DEBUG
        !           162:                if (debug) {
        !           163:                        printf("getinfo: got #41\n");
        !           164:                        printf("disk 0x%x: 0x%x\n", dev, bm);
        !           165:                }
        !           166: #endif
        !           167:                /*
        !           168:                 * If extended disk access functions are not supported
        !           169:                 * there is not much point on doing EDD.
        !           170:                 */
        !           171:                if (!(pdi->bios_edd & EXT_BM_EDA))
        !           172:                        pdi->bios_edd = -1;
        !           173:        } else
        !           174:                pdi->bios_edd = -1;
        !           175:
        !           176:        return 0;
        !           177: }
        !           178:
        !           179: /*
        !           180:  * Read/Write a block from given place using the BIOS.
        !           181:  */
        !           182: static __inline int
        !           183: CHS_rw(int rw, int dev, int cyl, int head, int sect, int nsect, void *buf)
        !           184: {
        !           185:        int rv;
        !           186:
        !           187:        rw = rw == F_READ ? 2 : 3;
        !           188:        BIOS_regs.biosr_es = (u_int32_t)buf >> 4;
        !           189:        __asm __volatile ("movb %b7, %h1\n\t"
        !           190:            "movb %b6, %%dh\n\t"
        !           191:            "andl $0xf, %4\n\t"
        !           192:            /* cylinder; the highest 2 bits of cyl is in %cl */
        !           193:            "xchgb %%ch, %%cl\n\t"
        !           194:            "rorb  $2, %%cl\n\t"
        !           195:            "orb %b5, %%cl\n\t"
        !           196:            "inc %%cx\n\t"
        !           197:            DOINT(0x13) "\n\t"
        !           198:            "setc %b0"
        !           199:            : "=a" (rv)
        !           200:            : "0" (nsect), "d" (dev), "c" (cyl),
        !           201:              "b" (buf), "m" (sect), "m" (head),
        !           202:              "m" (rw)
        !           203:            : "cc", "memory");
        !           204:
        !           205:        return ((rv & 0xff)? rv >> 8 : 0);
        !           206: }
        !           207:
        !           208: static __inline int
        !           209: EDD_rw(int rw, int dev, u_int64_t daddr, u_int32_t nblk, void *buf)
        !           210: {
        !           211:        int rv;
        !           212:        volatile static struct EDD_CB cb;
        !           213:
        !           214:        /* Zero out reserved stuff */
        !           215:        cb.edd_res1 = 0;
        !           216:        cb.edd_res2 = 0;
        !           217:
        !           218:        /* Fill in parameters */
        !           219:        cb.edd_len = sizeof(cb);
        !           220:        cb.edd_nblk = nblk;
        !           221:        cb.edd_seg = ((u_int32_t)buf >> 4) & 0xffff;
        !           222:        cb.edd_off = (u_int32_t)buf & 0xf;
        !           223:        cb.edd_daddr = daddr;
        !           224:
        !           225:        /* if offset/segment are zero, punt */
        !           226:        if (!cb.edd_seg && !cb.edd_off)
        !           227:                return 1;
        !           228:
        !           229:        /* Call extended read/write (with disk packet) */
        !           230:        BIOS_regs.biosr_ds = (u_int32_t)&cb >> 4;
        !           231:        __asm __volatile (DOINT(0x13) "; setc %b0" : "=a" (rv)
        !           232:            : "0" ((rw == F_READ)? 0x4200: 0x4300),
        !           233:              "d" (dev), "S" ((int) (&cb) & 0xf) : "%ecx", "cc");
        !           234:        return ((rv & 0xff)? rv >> 8 : 0);
        !           235: }
        !           236:
        !           237: /*
        !           238:  * Read given sector, handling retry/errors/etc.
        !           239:  */
        !           240: int
        !           241: biosd_io(int rw, bios_diskinfo_t *bd, daddr_t off, int nsect, void *buf)
        !           242: {
        !           243:        int dev = bd->bios_number;
        !           244:        int j, error;
        !           245:        void *bb;
        !           246:        int bbsize = nsect * DEV_BSIZE;
        !           247:
        !           248:        if (bd->flags & BDI_EL_TORITO) {        /* It's a CD device */
        !           249:                dev &= 0xff;                    /* Mask out this flag bit */
        !           250:
        !           251:                /*
        !           252:                 * sys/lib/libsa/cd9600.c converts 2,048-byte CD sectors
        !           253:                 * to DEV_BSIZE blocks before calling the device strategy
        !           254:                 * routine.  However, the El Torito spec says that the
        !           255:                 * BIOS will work in 2,048-byte sectors.  So shift back.
        !           256:                 */
        !           257:                off >>= (ISO_DEFAULT_BLOCK_SHIFT - DEV_BSHIFT);
        !           258:                nsect >>= (ISO_DEFAULT_BLOCK_SHIFT - DEV_BSHIFT);
        !           259:        }
        !           260:
        !           261:        /*
        !           262:         * Use a bounce buffer to not cross 64k DMA boundary, and to
        !           263:         * not access 1 MB or above.
        !           264:         */
        !           265:        if (((((u_int32_t)buf) & ~0xffff) !=
        !           266:            (((u_int32_t)buf + bbsize) & ~0xffff)) ||
        !           267:            (((u_int32_t)buf) >= 0x100000)) {
        !           268:                /*
        !           269:                 * XXX we believe that all the io is buffered
        !           270:                 * by fs routines, so no big reads anyway
        !           271:                 */
        !           272:                bb = alloca(bbsize);
        !           273:                if (rw != F_READ)
        !           274:                        bcopy(buf, bb, bbsize);
        !           275:        } else
        !           276:                bb = buf;
        !           277:
        !           278:        /* Try to do operation up to 5 times */
        !           279:        for (error = 1, j = 5; j-- && error; ) {
        !           280:                /* CHS or LBA access? */
        !           281:                if (bd->bios_edd != -1) {
        !           282:                        error = EDD_rw(rw, dev, off, nsect, bb);
        !           283:                } else {
        !           284:                        int cyl, head, sect;
        !           285:                        size_t i, n;
        !           286:                        char *p = bb;
        !           287:
        !           288:                        /* Handle track boundaries */
        !           289:                        for (error = i = 0; error == 0 && i < nsect;
        !           290:                            i += n, off += n, p += n * DEV_BSIZE) {
        !           291:
        !           292:                                btochs(off, cyl, head, sect, bd->bios_heads,
        !           293:                                    bd->bios_sectors);
        !           294:
        !           295:                                if ((sect + (nsect - i)) >= bd->bios_sectors)
        !           296:                                        n = bd->bios_sectors - sect;
        !           297:                                else
        !           298:                                        n = nsect - i;
        !           299:
        !           300:                                error = CHS_rw(rw, dev, cyl, head, sect, n, p);
        !           301:
        !           302:                                /* ECC corrected */
        !           303:                                if (error == 0x11)
        !           304:                                        error = 0;
        !           305:                        }
        !           306:                }
        !           307:                switch (error) {
        !           308:                case 0x00:      /* No errors */
        !           309:                case 0x11:      /* ECC corrected */
        !           310:                        error = 0;
        !           311:                        break;
        !           312:
        !           313:                default:        /* All other errors */
        !           314: #ifdef BIOS_DEBUG
        !           315:                        if (debug)
        !           316:                                printf("\nBIOS error 0x%x (%s)\n",
        !           317:                                    error, biosdisk_err(error));
        !           318: #endif
        !           319:                        biosdreset(dev);
        !           320:                        break;
        !           321:                }
        !           322:        }
        !           323:
        !           324:        if (bb != buf && rw == F_READ)
        !           325:                bcopy(bb, buf, bbsize);
        !           326:
        !           327: #ifdef BIOS_DEBUG
        !           328:        if (debug) {
        !           329:                if (error != 0)
        !           330:                        printf("=0x%x(%s)", error, biosdisk_err(error));
        !           331:                putchar('\n');
        !           332:        }
        !           333: #endif
        !           334:
        !           335:        return error;
        !           336: }
        !           337:
        !           338: /*
        !           339:  * Try to read the bsd label on the given BIOS device
        !           340:  */
        !           341: const char *
        !           342: bios_getdisklabel(bios_diskinfo_t *bd, struct disklabel *label)
        !           343: {
        !           344:        daddr_t off = LABELSECTOR;
        !           345:        char *buf;
        !           346:        struct dos_mbr mbr;
        !           347:        int error, i;
        !           348:
        !           349:        /* Sanity check */
        !           350:        if (bd->bios_heads == 0 || bd->bios_sectors == 0)
        !           351:                return "failed to read disklabel";
        !           352:
        !           353:        /* MBR is a harddisk thing */
        !           354:        if (bd->bios_number & 0x80) {
        !           355:                /* Read MBR */
        !           356:                error = biosd_io(F_READ, bd, DOSBBSECTOR, 1, &mbr);
        !           357:                if (error)
        !           358:                        return (biosdisk_err(error));
        !           359:
        !           360:                /* check mbr signature */
        !           361:                if (mbr.dmbr_sign != DOSMBR_SIGNATURE)
        !           362:                        return "bad MBR signature\n";
        !           363:
        !           364:                /* Search for OpenBSD partition */
        !           365:                for (off = 0, i = 0; off == 0 && i < NDOSPART; i++)
        !           366:                        if (mbr.dmbr_parts[i].dp_typ == DOSPTYP_OPENBSD)
        !           367:                                off = mbr.dmbr_parts[i].dp_start + LABELSECTOR;
        !           368:                if (off == 0)
        !           369:                        return "no OpenBSD partition\n";
        !           370:        } else
        !           371:                off = LABELSECTOR;
        !           372:
        !           373:        /* Load BSD disklabel */
        !           374:        buf = alloca(DEV_BSIZE);
        !           375: #ifdef BIOS_DEBUG
        !           376:        if (debug)
        !           377:                printf("loading disklabel @ %u\n", off);
        !           378: #endif
        !           379:        /* read disklabel */
        !           380:        error = biosd_io(F_READ, bd, off, 1, buf);
        !           381:
        !           382:        if (error)
        !           383:                return "failed to read disklabel";
        !           384:
        !           385:        /* Fill in disklabel */
        !           386:        return (getdisklabel(buf, label));
        !           387: }
        !           388:
        !           389: int
        !           390: biosopen(struct open_file *f, ...)
        !           391: {
        !           392:        va_list ap;
        !           393:        register char   *cp, **file;
        !           394:        dev_t maj, unit, part;
        !           395:        struct diskinfo *dip;
        !           396:        int biosdev;
        !           397:
        !           398:        va_start(ap, f);
        !           399:        cp = *(file = va_arg(ap, char **));
        !           400:        va_end(ap);
        !           401:
        !           402: #ifdef BIOS_DEBUG
        !           403:        if (debug)
        !           404:                printf("%s\n", cp);
        !           405: #endif
        !           406:
        !           407:        f->f_devdata = NULL;
        !           408:        /* search for device specification */
        !           409:        cp += 2;
        !           410:        if (cp[2] != ':') {
        !           411:                if (cp[3] != ':')
        !           412:                        return ENOENT;
        !           413:                else
        !           414:                        cp++;
        !           415:        }
        !           416:
        !           417:        for (maj = 0; maj < nbdevs && strncmp(*file, bdevs[maj], cp - *file); )
        !           418:            maj++;
        !           419:        if (maj >= nbdevs) {
        !           420:                printf("Unknown device: ");
        !           421:                for (cp = *file; *cp != ':'; cp++)
        !           422:                        putchar(*cp);
        !           423:                putchar('\n');
        !           424:                return EADAPT;
        !           425:        }
        !           426:
        !           427:        /* get unit */
        !           428:        if ('0' <= *cp && *cp <= '9')
        !           429:                unit = *cp++ - '0';
        !           430:        else {
        !           431:                printf("Bad unit number\n");
        !           432:                return EUNIT;
        !           433:        }
        !           434:        /* get partition */
        !           435:        if ('a' <= *cp && *cp <= 'p')
        !           436:                part = *cp++ - 'a';
        !           437:        else {
        !           438:                printf("Bad partition id\n");
        !           439:                return EPART;
        !           440:        }
        !           441:
        !           442:        cp++;   /* skip ':' */
        !           443:        if (*cp != 0)
        !           444:                *file = cp;
        !           445:        else
        !           446:                f->f_flags |= F_RAW;
        !           447:
        !           448:        biosdev = unit;
        !           449:        switch (maj) {
        !           450:        case 0:  /* wd */
        !           451:        case 4:  /* sd */
        !           452:        case 17: /* hd */
        !           453:                biosdev |= 0x80;
        !           454:                break;
        !           455:        case 2:  /* fd */
        !           456:                break;
        !           457:        case 6:  /* cd */
        !           458:                biosdev = bios_bootdev & 0xff;
        !           459:                break;
        !           460:        default:
        !           461:                return ENXIO;
        !           462:        }
        !           463:
        !           464:        /* Find device */
        !           465:        bootdev_dip = dip = dklookup(biosdev);
        !           466:
        !           467:        /* Fix up bootdev */
        !           468:        { dev_t bsd_dev;
        !           469:                bsd_dev = dip->bios_info.bsd_dev;
        !           470:                dip->bsddev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev),
        !           471:                    B_CONTROLLER(bsd_dev), unit, part);
        !           472:                dip->bootdev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev),
        !           473:                    B_CONTROLLER(bsd_dev), B_UNIT(bsd_dev), part);
        !           474:        }
        !           475:
        !           476: #if 0
        !           477:        dip->bios_info.bsd_dev = dip->bootdev;
        !           478:        bootdev = dip->bootdev;
        !           479: #endif
        !           480:
        !           481: #ifdef BIOS_DEBUG
        !           482:        if (debug) {
        !           483:                printf("BIOS geometry: heads=%u, s/t=%u; EDD=%d\n",
        !           484:                    dip->bios_info.bios_heads, dip->bios_info.bios_sectors,
        !           485:                    dip->bios_info.bios_edd);
        !           486:        }
        !           487: #endif
        !           488:
        !           489:        /* Try for disklabel again (might be removable media) */
        !           490:        if (dip->bios_info.flags & BDI_BADLABEL){
        !           491:                const char *st = bios_getdisklabel(&dip->bios_info,
        !           492:                    &dip->disklabel);
        !           493: #ifdef BIOS_DEBUG
        !           494:                if (debug && st)
        !           495:                        printf("%s\n", st);
        !           496: #endif
        !           497:                if (!st) {
        !           498:                        dip->bios_info.flags &= ~BDI_BADLABEL;
        !           499:                        dip->bios_info.flags |= BDI_GOODLABEL;
        !           500:                } else
        !           501:                        return ERDLAB;
        !           502:        }
        !           503:
        !           504:        f->f_devdata = dip;
        !           505:
        !           506:        return 0;
        !           507: }
        !           508:
        !           509: const u_char bidos_errs[] =
        !           510: /* ignored     "\x00" "successful completion\0" */
        !           511:                "\x01" "invalid function/parameter\0"
        !           512:                "\x02" "address mark not found\0"
        !           513:                "\x03" "write-protected\0"
        !           514:                "\x04" "sector not found\0"
        !           515:                "\x05" "reset failed\0"
        !           516:                "\x06" "disk changed\0"
        !           517:                "\x07" "drive parameter activity failed\0"
        !           518:                "\x08" "DMA overrun\0"
        !           519:                "\x09" "data boundary error\0"
        !           520:                "\x0A" "bad sector detected\0"
        !           521:                "\x0B" "bad track detected\0"
        !           522:                "\x0C" "invalid media\0"
        !           523:                "\x0E" "control data address mark detected\0"
        !           524:                "\x0F" "DMA arbitration level out of range\0"
        !           525:                "\x10" "uncorrectable CRC or ECC error on read\0"
        !           526: /* ignored     "\x11" "data ECC corrected\0" */
        !           527:                "\x20" "controller failure\0"
        !           528:                "\x31" "no media in drive\0"
        !           529:                "\x32" "incorrect drive type in CMOS\0"
        !           530:                "\x40" "seek failed\0"
        !           531:                "\x80" "operation timed out\0"
        !           532:                "\xAA" "drive not ready\0"
        !           533:                "\xB0" "volume not locked in drive\0"
        !           534:                "\xB1" "volume locked in drive\0"
        !           535:                "\xB2" "volume not removable\0"
        !           536:                "\xB3" "volume in use\0"
        !           537:                "\xB4" "lock count exceeded\0"
        !           538:                "\xB5" "valid eject request failed\0"
        !           539:                "\xBB" "undefined error\0"
        !           540:                "\xCC" "write fault\0"
        !           541:                "\xE0" "status register error\0"
        !           542:                "\xFF" "sense operation failed\0"
        !           543:                "\x00" "\0";
        !           544:
        !           545: static const char *
        !           546: biosdisk_err(u_int error)
        !           547: {
        !           548:        register const u_char *p = bidos_errs;
        !           549:
        !           550:        while (*p && *p != error)
        !           551:                while (*p++);
        !           552:
        !           553:        return ++p;
        !           554: }
        !           555:
        !           556: const struct biosdisk_errors {
        !           557:        u_char error;
        !           558:        u_char errno;
        !           559: } tab[] = {
        !           560:        { 0x01, EINVAL },
        !           561:        { 0x03, EROFS },
        !           562:        { 0x08, EINVAL },
        !           563:        { 0x09, EINVAL },
        !           564:        { 0x0A, EBSE },
        !           565:        { 0x0B, EBSE },
        !           566:        { 0x0C, ENXIO },
        !           567:        { 0x0D, EINVAL },
        !           568:        { 0x10, EECC },
        !           569:        { 0x20, EHER },
        !           570:        { 0x31, ENXIO },
        !           571:        { 0x32, ENXIO },
        !           572:        { 0x00, EIO }
        !           573: };
        !           574:
        !           575: static int
        !           576: biosdisk_errno(u_int error)
        !           577: {
        !           578:        register const struct biosdisk_errors *p;
        !           579:
        !           580:        if (error == 0)
        !           581:                return 0;
        !           582:
        !           583:        for (p = tab; p->error && p->error != error; p++);
        !           584:
        !           585:        return p->errno;
        !           586: }
        !           587:
        !           588: int
        !           589: biosstrategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf,
        !           590:     size_t *rsize)
        !           591: {
        !           592:        struct diskinfo *dip = (struct diskinfo *)devdata;
        !           593:        bios_diskinfo_t *bd = &dip->bios_info;
        !           594:        u_int8_t error = 0;
        !           595:        size_t nsect;
        !           596:
        !           597:        nsect = (size + DEV_BSIZE-1) / DEV_BSIZE;
        !           598:        if (rsize != NULL)
        !           599:                blk += dip->disklabel.
        !           600:                        d_partitions[B_PARTITION(dip->bsddev)].p_offset;
        !           601:
        !           602:        /* Read all, sub-functions handle track boundaries */
        !           603:        error = biosd_io(rw, bd, blk, nsect, buf);
        !           604:
        !           605: #ifdef BIOS_DEBUG
        !           606:        if (debug) {
        !           607:                if (error != 0)
        !           608:                        printf("=0x%x(%s)", error, biosdisk_err(error));
        !           609:                putchar('\n');
        !           610:        }
        !           611: #endif
        !           612:
        !           613:        if (rsize != NULL)
        !           614:                *rsize = nsect * DEV_BSIZE;
        !           615:
        !           616:        return (biosdisk_errno(error));
        !           617: }
        !           618:
        !           619: int
        !           620: biosclose(struct open_file *f)
        !           621: {
        !           622:        f->f_devdata = NULL;
        !           623:
        !           624:        return 0;
        !           625: }
        !           626:
        !           627: int
        !           628: biosioctl(struct open_file *f, u_long cmd, void *data)
        !           629: {
        !           630:        return 0;
        !           631: }

CVSweb