Annotation of Net2/arch/i386/isa/wd.c, revision 1.1.1.2

1.1       root        1: /*-
                      2:  * Copyright (c) 1990 The Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * This code is derived from software contributed to Berkeley by
                      6:  * William Jolitz.
                      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:  * 3. All advertising materials mentioning features or use of this software
                     17:  *    must display the following acknowledgement:
                     18:  *     This product includes software developed by the University of
                     19:  *     California, Berkeley and its contributors.
                     20:  * 4. Neither the name of the University nor the names of its contributors
                     21:  *    may be used to endorse or promote products derived from this software
                     22:  *    without specific prior written permission.
                     23:  *
                     24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     34:  * SUCH DAMAGE.
                     35:  *
                     36:  *     @(#)wd.c        7.2 (Berkeley) 5/9/91
                     37:  */
                     38: 
                     39: /* TODO:peel out buffer at low ipl,
                     40:    speed improvement, rewrite to clean code from garbage artifacts */
                     41: 
                     42: 
                     43: #include "wd.h"
                     44: #if    NWD > 0
                     45: 
                     46: #include "param.h"
                     47: #include "dkbad.h"
                     48: #include "systm.h"
                     49: #include "conf.h"
                     50: #include "file.h"
                     51: #include "stat.h"
                     52: #include "ioctl.h"
                     53: #include "disklabel.h"
                     54: #include "buf.h"
                     55: #include "uio.h"
                     56: #include "i386/isa/isa_device.h"
                     57: #include "i386/isa/icu.h"
                     58: #include "i386/isa/wdreg.h"
                     59: #include "syslog.h"
                     60: #include "vm/vm.h"
                     61: 
                     62: #define        RETRIES         5       /* number of retries before giving up */
                     63: #define        MAXTRANSFER     32      /* max size of transfer in page clusters */
                     64: 
1.1.1.2 ! root       65: #define wdctlr(dev)    ((minor(dev) & 0x20) >> 5)
        !            66: #define wdunit(dev)    ((minor(dev) & 0x18) >> 3)
        !            67: #define wdpart(dev)    ((minor(dev) & 0x7))
1.1       root       68: 
                     69: #define b_cylin        b_resid         /* cylinder number for doing IO to */
                     70:                                /* shares an entry in the buf struct */
                     71: 
                     72: /*
                     73:  * Drive states.  Used for open and format operations.
                     74:  * States < OPEN (> 0) are transient, during an open operation.
                     75:  * OPENRAW is used for unlabeled disks, and for floppies, to inhibit
                     76:  * bad-sector forwarding.
                     77:  */
                     78: #define RAWDISK                8               /* raw disk operation, no translation*/
                     79: #define ISRAWSTATE(s)  (RAWDISK&(s))   /* are we in a raw state? */
                     80: #define DISKSTATE(s)   (~RAWDISK&(s))  /* are we in a given state regardless
                     81:                                           of raw or cooked mode? */
                     82: 
                     83: #define        CLOSED          0               /* disk is closed. */
                     84:                                        /* "cooked" disk states */
                     85: #define        WANTOPEN        1               /* open requested, not started */
                     86: #define        RECAL           2               /* doing restore */
                     87: #define        RDLABEL         3               /* reading pack label */
                     88: #define        RDBADTBL        4               /* reading bad-sector table */
                     89: #define        OPEN            5               /* done with open */
                     90: 
                     91: #define        WANTOPENRAW     (WANTOPEN|RAWDISK)      /* raw WANTOPEN */
                     92: #define        RECALRAW        (RECAL|RAWDISK) /* raw open, doing restore */
                     93: #define        OPENRAW         (OPEN|RAWDISK)  /* open, but unlabeled disk or floppy */
                     94: 
                     95: 
                     96: /*
                     97:  * The structure of a disk drive.
                     98:  */
                     99: struct disk {
                    100:        struct disklabel dk_dd; /* device configuration data */
                    101:        long    dk_bc;          /* byte count left */
                    102:        short   dk_skip;        /* blocks already transferred */
                    103:        char    dk_unit;        /* physical unit number */
                    104:        char    dk_state;       /* control state */
                    105:        u_char  dk_status;      /* copy of status reg. */
                    106:        u_char  dk_error;       /* copy of error reg. */
                    107:        short   dk_open;        /* open/closed refcnt */
                    108:         u_long  dk_copenpart;   /* character units open on this drive */
                    109:         u_long  dk_bopenpart;   /* block units open on this drive */
                    110:         u_long  dk_openpart;    /* all units open on this drive */
                    111:        short   dk_wlabel;      /* label writable? */
                    112: };
                    113: 
                    114: /*
                    115:  * This label is used as a default when initializing a new or raw disk.
                    116:  * It really only lets us access the first track until we know more.
                    117:  */
                    118: struct disklabel dflt_sizes = {
                    119:        DISKMAGIC, DTYPE_ST506, 0, "default", "",
                    120:                512,            /* sector size */
                    121:                17,             /* # of sectors per track */
                    122:                8,              /* # of tracks per cylinder */
                    123:                766,            /* # of cylinders per unit */
                    124:                17*8,           /* # of sectors per cylinder */
                    125:                766*8*17,       /* # of sectors per unit */
                    126:                0,              /* # of spare sectors per track */
                    127:                0,              /* # of spare sectors per cylinder */
                    128:                0,              /* # of alt. cylinders per unit */
                    129:                3600,           /* rotational speed */
                    130:                1,              /* hardware sector interleave */
                    131:                0,              /* sector 0 skew, per track */
                    132:                0,              /* sector 0 skew, per cylinder */
                    133:                0,              /* head switch time, usec */
                    134:                0,              /* track-to-track seek, usec */
                    135:                0,              /* generic flags */
                    136:                0,0,0,0,0,
                    137:                0,0,0,0,0,
                    138:                DISKMAGIC,
                    139:                0,
                    140:                8,
                    141:                8192,
                    142:                8192,
                    143:        
                    144:        {{21600,        0, 0,0,0,0},    /* A=root filesystem */
1.1.1.2 ! root      145:        {21600, 21600, 0,0,0,0},
1.1       root      146:        {660890, 0, 0,0,0,0},   /* C=whole disk */
                    147:        {216000,        80, 0,0,0,0},
                    148:        {0,     0, 0,0,0,0},
                    149:        {0,     0, 0,0,0,0},
                    150:        {0,     0, 0,0,0,0},
                    151:        {399600,        480, 0,0,0,0}}
                    152: };
                    153: 
                    154: static struct  dkbad   dkbad[NWD];
                    155: struct disk    wddrives[NWD] = {0};    /* table of units */
                    156: struct buf     wdtab = {0};
                    157: struct buf     wdutab[NWD] = {0};      /* head of queue per drive */
                    158: struct buf     rwdbuf[NWD] = {0};      /* buffers for raw IO */
                    159: long   wdxfer[NWD] = {0};              /* count of transfers */
                    160: int    writeprotected[NWD] = { 0 };
                    161: int    wdprobe(), wdattach(), wdintr();
                    162: struct isa_driver wddriver = {
                    163:        wdprobe, wdattach, "wd",
                    164: };
                    165: 
                    166: static wdc;
                    167: /*
                    168:  * Probe routine
                    169:  */
                    170: wdprobe(dvp)
                    171:        struct isa_device *dvp;
                    172: {
                    173: wdc = dvp->id_iobase;
                    174: 
                    175: #ifdef lint
                    176:        wdintr(0);
                    177: #endif
                    178:        /* XXX sorry, needs to be better */
                    179:        outb(wdc+wd_error, 0x5a) ;      /* error register not writable */
                    180:        outb(wdc+wd_cyl_lo, 0xa5) ;     /* but all of cyllo are implemented */
                    181:        if(inb(wdc+wd_error) != 0x5a && inb(wdc+wd_cyl_lo) == 0xa5)
                    182:                return(1) ;
                    183:        return (0);
                    184: }
                    185: 
                    186: /*
                    187:  * attach each drive if possible.
                    188:  */
                    189: wdattach(dvp)
                    190:        struct isa_device *dvp;
                    191: {
                    192:        int unit = dvp->id_unit;
                    193: 
                    194:        outb(wdc+wd_ctlr,12);
                    195:        DELAY(1000);
                    196:        outb(wdc+wd_ctlr,8);
                    197: }
                    198: 
                    199: /* Read/write routine for a buffer.  Finds the proper unit, range checks
                    200:  * arguments, and schedules the transfer.  Does not wait for the transfer
                    201:  * to complete.  Multi-page transfers are supported.  All I/O requests must
                    202:  * be a multiple of a sector in length.
                    203:  */
                    204: wdstrategy(bp)
                    205:        register struct buf *bp;        /* IO operation to perform */
                    206: {
                    207:        register struct buf *dp;
                    208:        register struct disk *du;       /* Disk unit to do the IO.      */
                    209:        register struct partition *p;
                    210:        long maxsz, sz;
                    211:        int     unit = wdunit(bp->b_dev);
                    212:        int     s;
                    213: 
                    214:        if ((unit >= NWD) || (bp->b_blkno < 0)) {
                    215:                printf("wdstrat: unit = %d, blkno = %d, bcount = %d\n",
                    216:                        unit, bp->b_blkno, bp->b_bcount);
                    217:                pg("wd:error in wdstrategy");
                    218:                bp->b_flags |= B_ERROR;
                    219:                goto bad;
                    220:        }
                    221:        if (writeprotected[unit] && (bp->b_flags & B_READ) == 0) {
                    222:                printf("wd%d: write protected\n", unit);
                    223:                goto bad;
                    224:        }
                    225:        du = &wddrives[unit];
                    226:        if (DISKSTATE(du->dk_state) != OPEN)
                    227:                goto q;
                    228: #ifdef old
                    229:        /*
                    230:         * Convert DEV_BSIZE "blocks" to sectors.
                    231:         * Note: doing the conversions this way limits the partition size
                    232:         * to about 8 million sectors (1-8 Gb).
                    233:         */
                    234:        blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / du->dk_dd.d_secsize;
                    235:        if (((u_long) bp->b_blkno * DEV_BSIZE % du->dk_dd.d_secsize != 0) ||
                    236:            bp->b_bcount >= MAXTRANSFER * CLBYTES) {
                    237:                bp->b_flags |= B_ERROR;
                    238:                goto bad;
                    239:        }
                    240:        nblocks = du->dk_dd.d_partitions[part].p_size;
                    241:        cyloff = du->dk_dd.d_partitions[part].p_offset;
                    242:        if (blknum + (bp->b_bcount / du->dk_dd.d_secsize) > nblocks) {
                    243:                if (blknum == nblocks)
                    244:                        bp->b_resid = bp->b_bcount;
                    245:                else
                    246:                        bp->b_flags |= B_ERROR;
                    247:                goto bad;
                    248:        }
                    249:        bp->b_cylin = blknum / du->dk_dd.d_secpercyl + cyloff;
                    250: #else
                    251:         /*
                    252:          * Determine the size of the transfer, and make sure it is
                    253:          * within the boundaries of the partition.
                    254:          */
                    255:         p = &du->dk_dd.d_partitions[wdpart(bp->b_dev)];
                    256:         maxsz = p->p_size;
                    257:         sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
                    258:         if (bp->b_blkno + p->p_offset <= LABELSECTOR &&
                    259: #if LABELSECTOR != 0
                    260:             bp->b_blkno + p->p_offset + sz > LABELSECTOR &&
                    261: #endif
                    262:             (bp->b_flags & B_READ) == 0 && du->dk_wlabel == 0) {
                    263:                 bp->b_error = EROFS;
                    264:                 goto bad;
                    265:         }
                    266:         if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) {
                    267:                 /* if exactly at end of disk, return an EOF */
                    268:                 if (bp->b_blkno == maxsz) {
                    269:                         bp->b_resid = bp->b_bcount;
                    270:                         biodone(bp);
                    271:                         return;
                    272:                 }
                    273:                 /* or truncate if part of it fits */
                    274:                 sz = maxsz - bp->b_blkno;
                    275:                 if (sz <= 0)
                    276:                         goto bad;
                    277:                 bp->b_bcount = sz << DEV_BSHIFT;
                    278:         }
                    279:         bp->b_cylin = (bp->b_blkno + p->p_offset) / du->dk_dd.d_secpercyl;
                    280: #endif
                    281: q:
                    282:        dp = &wdutab[unit];
                    283:        s = splhigh();
                    284:        disksort(dp, bp);
                    285:        if (dp->b_active == 0)
                    286:                wdustart(du);           /* start drive if idle */
                    287:        if (wdtab.b_active == 0)
                    288:                wdstart(s);             /* start IO if controller idle */
                    289:        splx(s);
                    290:        return;
                    291: 
                    292: bad:
                    293:        bp->b_error = EINVAL;
                    294:        biodone(bp);
                    295: }
                    296: 
                    297: /* Routine to queue a read or write command to the controller.  The request is
                    298:  * linked into the active list for the controller.  If the controller is idle,
                    299:  * the transfer is started.
                    300:  */
                    301: wdustart(du)
                    302:        register struct disk *du;
                    303: {
                    304:        register struct buf *bp, *dp;
                    305: 
                    306:        dp = &wdutab[du->dk_unit];
                    307:        if (dp->b_active)
                    308:                return;
                    309:        bp = dp->b_actf;
                    310:        if (bp == NULL)
                    311:                return; 
                    312:        dp->b_forw = NULL;
                    313:        if (wdtab.b_actf  == NULL)              /* link unit into active list */
                    314:                wdtab.b_actf = dp;
                    315:        else
                    316:                wdtab.b_actl->b_forw = dp;
                    317:        wdtab.b_actl = dp;
                    318:        dp->b_active = 1;               /* mark the drive as busy */
                    319: }
                    320: 
                    321: /*
                    322:  * Controller startup routine.  This does the calculation, and starts
                    323:  * a single-sector read or write operation.  Called to start a transfer,
                    324:  * or from the interrupt routine to continue a multi-sector transfer.
                    325:  * RESTRICTIONS:
                    326:  * 1.  The transfer length must be an exact multiple of the sector size.
                    327:  */
                    328: 
                    329: static wd_sebyse;
                    330: 
                    331: wdstart()
                    332: {
                    333:        register struct disk *du;       /* disk unit for IO */
                    334:        register struct buf *bp;
                    335:        struct buf *dp;
                    336:        register struct bt_bad *bt_ptr;
                    337:        long    blknum, pagcnt, cylin, head, sector;
                    338:        long    secpertrk, secpercyl, addr, i;
                    339:        int     unit, s;
                    340: 
                    341: loop:
                    342:        dp = wdtab.b_actf;
                    343:        if (dp == NULL)
                    344:                return;
                    345:        bp = dp->b_actf;
                    346:        if (bp == NULL) {
                    347:                wdtab.b_actf = dp->b_forw;
                    348:                goto loop;
                    349:        }
                    350:        unit = wdunit(bp->b_dev);
                    351:        du = &wddrives[unit];
                    352:        if (DISKSTATE(du->dk_state) <= RDLABEL) {
                    353:                if (wdcontrol(bp)) {
                    354:                        dp->b_actf = bp->av_forw;
                    355:                        goto loop;      /* done */
                    356:                }
                    357:                return;
                    358:        }
                    359:        secpertrk = du->dk_dd.d_nsectors;
                    360:        secpercyl = du->dk_dd.d_secpercyl;
                    361:        /*
                    362:         * Convert DEV_BSIZE "blocks" to sectors.
                    363:         */
                    364:        blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / du->dk_dd.d_secsize
                    365:                + du->dk_skip;
                    366: #ifdef WDDEBUG
                    367:        if (du->dk_skip == 0) {
                    368:                dprintf(DDSK,"\nwdstart %d: %s %d@%d; map ", unit,
                    369:                        (bp->b_flags & B_READ) ? "read" : "write",
                    370:                        bp->b_bcount, blknum);
                    371:        } else {
                    372:                dprintf(DDSK," %d)%x", du->dk_skip, inb(wdc+wd_altsts));
                    373:        }
                    374: #endif
                    375: 
                    376:        addr = (int) bp->b_un.b_addr;
                    377:        if(du->dk_skip==0) du->dk_bc = bp->b_bcount;
                    378:        cylin = blknum / secpercyl;
                    379:        head = (blknum % secpercyl) / secpertrk;
                    380:        sector = blknum % secpertrk;
                    381:        if (DISKSTATE(du->dk_state) == OPEN)
                    382:                cylin += du->dk_dd.d_partitions[wdpart(bp->b_dev)].p_offset
                    383:                                / secpercyl;
                    384: 
                    385:        /* 
                    386:         * See if the current block is in the bad block list.
                    387:         * (If we have one, and not formatting.)
                    388:         */
                    389:        if (DISKSTATE(du->dk_state) == OPEN && wd_sebyse)
                    390:            for (bt_ptr = dkbad[unit].bt_bad; bt_ptr->bt_cyl != -1; bt_ptr++) {
                    391:                if (bt_ptr->bt_cyl > cylin)
                    392:                        /* Sorted list, and we passed our cylinder. quit. */
                    393:                        break;
                    394:                if (bt_ptr->bt_cyl == cylin &&
                    395:                                bt_ptr->bt_trksec == (head << 8) + sector) {
                    396:                        /*
                    397:                         * Found bad block.  Calculate new block addr.
                    398:                         * This starts at the end of the disk (skip the
                    399:                         * last track which is used for the bad block list),
                    400:                         * and works backwards to the front of the disk.
                    401:                         */
                    402: #ifdef WDDEBUG
                    403:                            dprintf(DDSK,"--- badblock code -> Old = %d; ",
                    404:                                blknum);
                    405: #endif
                    406:                        blknum = du->dk_dd.d_secperunit - du->dk_dd.d_nsectors
                    407:                                - (bt_ptr - dkbad[unit].bt_bad) - 1;
                    408:                        cylin = blknum / secpercyl;
                    409:                        head = (blknum % secpercyl) / secpertrk;
                    410:                        sector = blknum % secpertrk;
                    411: #ifdef WDDEBUG
                    412:                            dprintf(DDSK, "new = %d\n", blknum);
                    413: #endif
                    414:                        break;
                    415:                }
                    416:        }
                    417:        sector += 1;    /* sectors begin with 1, not 0 */
                    418: 
                    419:        wdtab.b_active = 1;             /* mark controller active */
                    420: 
                    421:        if(du->dk_skip==0 || wd_sebyse) {
                    422:        if(wdtab.b_errcnt && (bp->b_flags & B_READ) == 0) du->dk_bc += 512;
                    423:        while ((inb(wdc+wd_status) & WDCS_BUSY) != 0) ;
                    424:        /*while ((inb(wdc+wd_status) & WDCS_DRQ)) inb(wdc+wd_data);*/
                    425:        outb(wdc+wd_precomp, 0xff);
                    426:        /*wr(wdc+wd_precomp, du->dk_dd.dk_precompcyl / 4);*/
                    427:        /*if (bp->b_flags & B_FORMAT) {
                    428:                wr(wdc+wd_sector, du->dk_dd.dk_gap3);
                    429:                wr(wdc+wd_seccnt, du->dk_dd.dk_nsectors);
                    430:        } else {*/
                    431:        if(wd_sebyse)
                    432:                outb(wdc+wd_seccnt, 1);
                    433:        else
                    434:                outb(wdc+wd_seccnt, ((du->dk_bc +511) / 512));
                    435:        outb(wdc+wd_sector, sector);
                    436: 
                    437:        outb(wdc+wd_cyl_lo, cylin);
                    438:        outb(wdc+wd_cyl_hi, cylin >> 8);
                    439: 
                    440:        /* Set up the SDH register (select drive).     */
                    441:        outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf));
                    442:        while ((inb(wdc+wd_status) & WDCS_READY) == 0) ;
                    443: 
                    444:        /*if (bp->b_flags & B_FORMAT)
                    445:                wr(wdc+wd_command, WDCC_FORMAT);
                    446:        else*/
                    447:                outb(wdc+wd_command,
                    448:                        (bp->b_flags & B_READ)? WDCC_READ : WDCC_WRITE);
1.1.1.2 ! root      449:        /*printf("sector %d cylin %d head %d addr %x sts %x\n",
        !           450:            sector, cylin, head, addr, inb(wdc+wd_altsts));*/
1.1       root      451: }
                    452:                
                    453:        /* If this is a read operation, just go away until it's done.   */
                    454:        if (bp->b_flags & B_READ) return;
                    455: 
                    456:        /* Ready to send data?  */
                    457:        while ((inb(wdc+wd_status) & WDCS_DRQ) == 0);
                    458: 
                    459:        /* ASSUMES CONTIGUOUS MEMORY */
                    460:        outsw (wdc+wd_data, addr+du->dk_skip*512, 256);
                    461:        du->dk_bc -= 512;
                    462: }
                    463: 
                    464: /*
                    465:  * these are globally defined so they can be found
                    466:  * by the debugger easily in the case of a system crash
                    467:  */
                    468: daddr_t wd_errsector;
                    469: daddr_t wd_errbn;
                    470: unsigned char wd_errstat;
                    471: 
                    472: /* Interrupt routine for the controller.  Acknowledge the interrupt, check for
                    473:  * errors on the current operation, mark it done if necessary, and start
                    474:  * the next request.  Also check for a partially done transfer, and
                    475:  * continue with the next chunk if so.
                    476:  */
                    477: wdintr(unit)
                    478: {
                    479:        register struct disk *du;
                    480:        register struct buf *bp, *dp;
                    481:        int status;
                    482:        char partch ;
                    483:        static wd_haderror;
                    484: 
                    485:        /* Shouldn't need this, but it may be a slow controller.        */
                    486:        while ((status = inb(wdc+wd_status)) & WDCS_BUSY) ;
                    487:        if (!wdtab.b_active) {
                    488:                printf("wd: extra interrupt\n");
                    489:                return;
                    490:        }
                    491: 
                    492: #ifdef WDDEBUG
                    493:        dprintf(DDSK,"I ");
                    494: #endif
                    495:        dp = wdtab.b_actf;
                    496:        bp = dp->b_actf;
                    497:        du = &wddrives[wdunit(bp->b_dev)];
                    498:        partch = wdpart(bp->b_dev) + 'a';
                    499:        if (DISKSTATE(du->dk_state) <= RDLABEL) {
                    500:                if (wdcontrol(bp))
                    501:                        goto done;
                    502:                return;
                    503:        }
                    504:        if (status & (WDCS_ERR | WDCS_ECCCOR)) {
                    505:                wd_errstat = inb(wdc+wd_error);         /* save error status */
                    506: #ifdef WDDEBUG
                    507:                printf("status %x error %x\n", status, wd_errstat);
                    508: #endif
                    509:                if(wd_sebyse == 0) {
                    510:                        wd_haderror = 1;
                    511:                        goto outt;
                    512:                }
                    513:                /*if (bp->b_flags & B_FORMAT) {
                    514:                        du->dk_status = status;
                    515:                        du->dk_error = wdp->wd_error;
                    516:                        bp->b_flags |= B_ERROR;
                    517:                        goto done;
                    518:                }*/
                    519:                
                    520:                wd_errsector = (bp->b_cylin * du->dk_dd.d_secpercyl) +
                    521:                        (((unsigned long) bp->b_blkno * DEV_BSIZE /
                    522:                            du->dk_dd.d_secsize) % du->dk_dd.d_secpercyl) +
                    523:                        du->dk_skip;
                    524:                wd_errbn = bp->b_blkno
                    525:                        + du->dk_skip * du->dk_dd.d_secsize / DEV_BSIZE ;
                    526:                if (status & WDCS_ERR) {
                    527:                        if (++wdtab.b_errcnt < RETRIES) {
                    528:                                wdtab.b_active = 0;
                    529:                        } else {
                    530:                                printf("wd%d%c: ", du->dk_unit, partch);
                    531:                                printf(
                    532:                                "hard %s error, sn %d bn %d status %b error %b\n",
                    533:                                        (bp->b_flags & B_READ)? "read":"write",
                    534:                                        wd_errsector, wd_errbn, status, WDCS_BITS,
                    535:                                        wd_errstat, WDERR_BITS);
                    536:                                bp->b_flags |= B_ERROR; /* flag the error */
                    537:                        }
                    538:                } else
                    539:                        log(LOG_WARNING,"wd%d%c: soft ecc sn %d bn %d\n",
                    540:                                du->dk_unit, partch, wd_errsector,
                    541:                                wd_errbn);
                    542:        }
                    543: outt:
                    544: 
                    545:        /*
                    546:         * If this was a successful read operation, fetch the data.
                    547:         */
                    548:        if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) && wdtab.b_active) {
                    549:                int chk, dummy;
                    550: 
                    551:                chk = min(256,du->dk_bc/2);
                    552:                /* Ready to receive data?       */
                    553:                while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ;
                    554: 
                    555: /*dprintf(DDSK,"addr %x\n", (int)bp->b_un.b_addr + du->dk_skip * 512);*/
                    556:                insw(wdc+wd_data,(int)bp->b_un.b_addr + du->dk_skip * 512 ,chk);
                    557:                du->dk_bc -= 2*chk;
                    558:                while (chk++ < 256) insw (wdc+wd_data,&dummy,1);
                    559:        }
                    560: 
                    561:        wdxfer[du->dk_unit]++;
                    562:        if (wdtab.b_active) {
                    563:                if ((bp->b_flags & B_ERROR) == 0) {
                    564:                        du->dk_skip++;          /* Add to successful sectors. */
                    565:                        if (wdtab.b_errcnt) {
                    566:                                log(LOG_WARNING, "wd%d%c: ",
                    567:                                                du->dk_unit, partch);
                    568:                                log(LOG_WARNING,
                    569:                        "soft %s error, sn %d bn %d error %b retries %d\n",
                    570:                                    (bp->b_flags & B_READ) ? "read" : "write",
                    571:                                    wd_errsector, wd_errbn, wd_errstat,
                    572:                                    WDERR_BITS, wdtab.b_errcnt);
                    573:                        }
                    574:                        wdtab.b_errcnt = 0;
                    575: 
                    576:                        /* see if more to transfer */
                    577:                        /*if (du->dk_skip < (bp->b_bcount + 511) / 512) {*/
                    578:                        if (du->dk_bc > 0 && wd_haderror == 0) {
                    579:                                wdstart();
                    580:                                return;         /* next chunk is started */
                    581:                        } else if (wd_haderror && wd_sebyse == 0) {
                    582:                                du->dk_skip = 0;
                    583:                                wd_haderror = 0;
                    584:                                wd_sebyse = 1;
                    585:                                wdstart();
                    586:                                return;         /* redo xfer sector by sector */
                    587:                        }
                    588:                }
                    589: 
                    590: done:
                    591:                wd_sebyse = 0;
                    592:                /* done with this transfer, with or without error */
                    593:                wdtab.b_actf = dp->b_forw;
                    594:                wdtab.b_errcnt = 0;
                    595:                du->dk_skip = 0;
                    596:                dp->b_active = 0;
                    597:                dp->b_actf = bp->av_forw;
                    598:                dp->b_errcnt = 0;
                    599:                bp->b_resid = 0;
                    600:                biodone(bp);
                    601:        }
                    602:        wdtab.b_active = 0;
                    603:        if (dp->b_actf)
                    604:                wdustart(du);           /* requeue disk if more io to do */
                    605:        if (wdtab.b_actf)
                    606:                wdstart();              /* start IO on next drive */
                    607: }
                    608: 
                    609: /*
                    610:  * Initialize a drive.
                    611:  */
                    612: wdopen(dev, flags, fmt)
                    613:         dev_t dev;
                    614:         int flags, fmt;
                    615: {
                    616:        register unsigned int unit;
                    617:        register struct buf *bp;
                    618:        register struct disk *du;
                    619:         int part = wdpart(dev), mask = 1 << part;
                    620:         struct partition *pp;
                    621:        struct dkbad *db;
                    622:        int i, error = 0;
                    623: 
                    624:        unit = wdunit(dev);
                    625:        if (unit >= NWD) return (ENXIO) ;
                    626:        du = &wddrives[unit];
                    627: #ifdef notdef
                    628:        if (du->dk_open){
                    629:                du->dk_open++ ;
                    630:                return(0);      /* already is open, don't mess with it */
                    631:        }
                    632: #endif
                    633:        du->dk_unit = unit;
                    634:        wdutab[unit].b_actf = NULL;
                    635:        /*if (flags & O_NDELAY)
                    636:                du->dk_state = WANTOPENRAW;
                    637:        else*/
                    638:                du->dk_state = WANTOPEN;
                    639:        /*
                    640:         * Use the default sizes until we've read the label,
                    641:         * or longer if there isn't one there.
                    642:         */
                    643:        du->dk_dd = dflt_sizes;
                    644: 
                    645:        /*
                    646:         * Recal, read of disk label will be done in wdcontrol
                    647:         * during first read operation.
                    648:         */
                    649:        bp = geteblk(512);
                    650:        bp->b_dev = dev & 0xff00;
                    651:        bp->b_bcount = 0;
                    652:        bp->b_blkno = LABELSECTOR;
                    653:        bp->b_flags = B_READ;
                    654:        wdstrategy(bp);
                    655:        biowait(bp);
                    656:        if (bp->b_flags & B_ERROR) {
                    657:                error = ENXIO;
                    658:                du->dk_state = CLOSED;
                    659:                goto done;
                    660:        }
                    661:        if (du->dk_state == OPENRAW) {
                    662:                du->dk_state = OPENRAW;
                    663:                goto done;
                    664:        }
                    665:        /*
                    666:         * Read bad sector table into memory.
                    667:         */
                    668:        i = 0;
                    669:        do {
                    670:                bp->b_flags = B_BUSY | B_READ;
                    671:                bp->b_blkno = du->dk_dd.d_secperunit - du->dk_dd.d_nsectors
                    672:                        + i;
                    673:                if (du->dk_dd.d_secsize > DEV_BSIZE)
                    674:                        bp->b_blkno *= du->dk_dd.d_secsize / DEV_BSIZE;
                    675:                else
                    676:                        bp->b_blkno /= DEV_BSIZE / du->dk_dd.d_secsize;
                    677:                bp->b_bcount = du->dk_dd.d_secsize;
                    678:                bp->b_cylin = du->dk_dd.d_ncylinders - 1;
                    679:                wdstrategy(bp);
                    680:                biowait(bp);
                    681:        } while ((bp->b_flags & B_ERROR) && (i += 2) < 10 &&
                    682:                i < du->dk_dd.d_nsectors);
                    683:        db = (struct dkbad *)(bp->b_un.b_addr);
                    684: #define DKBAD_MAGIC 0x4321
                    685:        if ((bp->b_flags & B_ERROR) == 0 && db->bt_mbz == 0 &&
                    686:            db->bt_flag == DKBAD_MAGIC) {
                    687:                dkbad[unit] = *db;
                    688:                du->dk_state = OPEN;
                    689:        } else {
                    690:                printf("wd%d: %s bad-sector file\n", unit,
                    691:                    (bp->b_flags & B_ERROR) ? "can't read" : "format error in");
1.1.1.2 ! root      692:                /*error = ENXIO ;
        !           693:                du->dk_state = OPENRAW;*/
        !           694:                du->dk_state = OPEN;
1.1       root      695:        }
                    696: done:
                    697:        bp->b_flags = B_INVAL | B_AGE;
                    698:        brelse(bp);
                    699:        if (error == 0)
                    700:                du->dk_open = 1;
                    701: 
                    702:         /*
                    703:          * Warn if a partion is opened
                    704:          * that overlaps another partition which is open
                    705:          * unless one is the "raw" partition (whole disk).
                    706:          */
1.1.1.2 ! root      707: #define RAWPART         2               /* 'c' partition */     /* XXX */
1.1       root      708:         if ((du->dk_openpart & mask) == 0 && part != RAWPART) {
                    709:                int     start, end;
                    710: 
                    711:                 pp = &du->dk_dd.d_partitions[part];
                    712:                 start = pp->p_offset;
                    713:                 end = pp->p_offset + pp->p_size;
                    714:                 for (pp = du->dk_dd.d_partitions;
                    715:                      pp < &du->dk_dd.d_partitions[du->dk_dd.d_npartitions];
                    716:                        pp++) {
                    717:                         if (pp->p_offset + pp->p_size <= start ||
                    718:                             pp->p_offset >= end)
                    719:                                 continue;
                    720:                         if (pp - du->dk_dd.d_partitions == RAWPART)
                    721:                                 continue;
                    722:                         if (du->dk_openpart & (1 << (pp -
                    723:                                        du->dk_dd.d_partitions)))
                    724:                                 log(LOG_WARNING,
                    725:                                     "wd%d%c: overlaps open partition (%c)\n",
                    726:                                     unit, part + 'a',
                    727:                                     pp - du->dk_dd.d_partitions + 'a');
                    728:                 }
                    729:         }
                    730:         if (part >= du->dk_dd.d_npartitions)
                    731:                 return (ENXIO);
                    732:         du->dk_openpart |= mask;
                    733:         switch (fmt) {
                    734:         case S_IFCHR:
                    735:                 du->dk_copenpart |= mask;
                    736:                 break;
                    737:         case S_IFBLK:
                    738:                 du->dk_bopenpart |= mask;
                    739:                 break;
                    740:         }
                    741:        return (error);
                    742: }
                    743: 
                    744: /*
                    745:  * Implement operations other than read/write.
                    746:  * Called from wdstart or wdintr during opens and formats.
                    747:  * Uses finite-state-machine to track progress of operation in progress.
                    748:  * Returns 0 if operation still in progress, 1 if completed.
                    749:  */
                    750: wdcontrol(bp)
                    751:        register struct buf *bp;
                    752: {
                    753:        register struct disk *du;
                    754:        register unit;
                    755:        unsigned char  stat;
                    756:        int s, cnt;
                    757:        extern int bootdev, cyloffset;
                    758: 
                    759:        du = &wddrives[wdunit(bp->b_dev)];
                    760:        unit = du->dk_unit;
                    761:        switch (DISKSTATE(du->dk_state)) {
                    762: 
                    763:        tryagainrecal:
                    764:        case WANTOPEN:                  /* set SDH, step rate, do restore */
                    765: #ifdef WDDEBUG
                    766:                dprintf(DDSK,"wd%d: recal ", unit);
                    767: #endif
                    768:                s = splbio();           /* not called from intr level ... */
                    769:                outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
                    770:                wdtab.b_active = 1;
                    771:                outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
                    772:                du->dk_state++;
                    773:                splx(s);
                    774:                return(0);
                    775: 
                    776:        case RECAL:
                    777:                if ((stat = inb(wdc+wd_status)) & WDCS_ERR) {
                    778:                        printf("wd%d: recal", du->dk_unit);
                    779:                        if (unit == 0) {
                    780:                                printf(": status %b error %b\n",
                    781:                                        stat, WDCS_BITS,
                    782:                                        inb(wdc+wd_error), WDERR_BITS);
                    783:                                if (++wdtab.b_errcnt < RETRIES)
                    784:                                        goto tryagainrecal;
                    785:                        }
                    786:                        goto badopen;
                    787:                }
                    788: 
                    789:                /* some compaq controllers require this ... */
                    790:                wdsetctlr(bp->b_dev, du);
                    791: 
                    792:                wdtab.b_errcnt = 0;
                    793:                if (ISRAWSTATE(du->dk_state)) {
                    794:                        du->dk_state = OPENRAW;
                    795:                        return(1);
                    796:                }
                    797: retry:
                    798: #ifdef WDDEBUG
                    799:                dprintf(DDSK,"rdlabel ");
                    800: #endif
1.1.1.2 ! root      801: /*if( cyloffset < 0 || cyloffset > 8192) */cyloffset=0;
1.1       root      802:                /*
                    803:                 * Read in sector LABELSECTOR to get the pack label
                    804:                 * and geometry.
                    805:                 */
                    806:                outb(wdc+wd_precomp, 0xff);/* sometimes this is head bit 3 */
                    807:                outb(wdc+wd_seccnt, 1);
                    808:                outb(wdc+wd_sector, LABELSECTOR+1);
1.1.1.2 ! root      809: /*printf("sec %d ", LABELSECTOR);*/
1.1       root      810:                /*if (bp->b_dev == bootdev) {
                    811:                        (wdc+wd_cyl_lo = cyloffset & 0xff;
                    812:                        (wdc+wd_cyl_hi = cyloffset >> 8;
                    813:                } else {
                    814:                        (wdc+wd_cyl_lo = 0;
                    815:                        (wdc+wd_cyl_hi = 0;
                    816:                }*/
                    817:                outb(wdc+wd_cyl_lo, (cyloffset & 0xff));
                    818:                outb(wdc+wd_cyl_hi, (cyloffset >> 8));
                    819:                outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
                    820:                outb(wdc+wd_command, WDCC_READ);
                    821:                du->dk_state = RDLABEL;
                    822:                return(0);
                    823: 
                    824:        case RDLABEL:
                    825:                if ((stat = inb(wdc+wd_status)) & WDCS_ERR) {
                    826:                        if (++wdtab.b_errcnt < RETRIES)
                    827:                                goto retry;
                    828:                        printf("wd%d: read label", unit);
                    829:                        goto badopen;
                    830:                }
                    831: 
                    832:                insw(wdc+wd_data, bp->b_un.b_addr, 256);
                    833: 
                    834:                if (((struct disklabel *)
                    835:                    (bp->b_un.b_addr + LABELOFFSET))->d_magic == DISKMAGIC) {
                    836:                       du->dk_dd =
                    837:                         * (struct disklabel *) (bp->b_un.b_addr + LABELOFFSET);
                    838:                } else {
1.1.1.2 ! root      839:                        printf("wd%d: bad disk label (%x)\n", du->dk_unit,
        !           840:     ((struct disklabel *)(bp->b_un.b_addr + LABELOFFSET))->d_magic
        !           841: );
1.1       root      842:                        du->dk_state = OPENRAW;
                    843:                }
                    844: 
                    845:                s = splbio();           /* not called from intr level ... */
                    846:                while ((stat = inb(wdc+wd_status)) & WDCS_BUSY);
                    847: 
                    848:                wdsetctlr(bp->b_dev, du);
                    849: 
                    850:                outb(wdc+wd_seccnt, 0);
                    851:                splx(s);
                    852: 
                    853:                if (du->dk_state == RDLABEL)
                    854:                        du->dk_state = RDBADTBL;
                    855:                /*
                    856:                 * The rest of the initialization can be done
                    857:                 * by normal means.
                    858:                 */
                    859:                return(1);
                    860: 
                    861:        default:
                    862:                panic("wdcontrol");
                    863:        }
                    864:        /* NOTREACHED */
                    865: 
                    866: badopen:
                    867:        printf(": status %b error %b\n",
                    868:                stat, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS);
                    869:        du->dk_state = OPENRAW;
                    870:        return(1);
                    871: }
                    872: 
                    873: wdsetctlr(dev, du) dev_t dev; struct disk *du; {
                    874:        int stat;
                    875: 
1.1.1.2 ! root      876:        outb(wdc+wd_cyl_lo, du->dk_dd.d_ncylinders+1);
        !           877:        outb(wdc+wd_cyl_hi, (du->dk_dd.d_ncylinders+1)>>8);
1.1       root      878:        outb(wdc+wd_sdh, WDSD_IBM | (wdunit(dev) << 4) + du->dk_dd.d_ntracks-1);
                    879:        outb(wdc+wd_seccnt, du->dk_dd.d_nsectors);
                    880:        outb(wdc+wd_command, 0x91);
                    881: 
                    882:        while ((stat = inb(wdc+wd_status)) & WDCS_BUSY) ;
                    883:        stat = inb(wdc+wd_error);
                    884:        return(stat);
                    885: }
                    886: 
                    887: /* ARGSUSED */
                    888: wdclose(dev, flags, fmt)
                    889:         dev_t dev;
                    890:         int flags, fmt;
                    891: {
                    892:        register struct disk *du;
                    893: 
                    894:        du = &wddrives[wdunit(dev)];
                    895:        du->dk_open-- ;
                    896:        /*if (du->dk_open == 0) du->dk_state = CLOSED ; does not work */
1.1.1.2 ! root      897:        return(0);
1.1       root      898: }
                    899: 
                    900: wdioctl(dev,cmd,addr,flag)
                    901:        dev_t dev;
                    902:        caddr_t addr;
                    903: {
                    904:        int unit = wdunit(dev);
                    905:        register struct disk *du;
                    906:        int error = 0;
                    907:        struct uio auio;
                    908:        struct iovec aiov;
                    909:        /*int wdformat();*/
                    910: 
                    911:        du = &wddrives[unit];
                    912: 
                    913:        switch (cmd) {
                    914: 
                    915:        case DIOCGDINFO:
                    916:                *(struct disklabel *)addr = du->dk_dd;
                    917:                break;
                    918: 
                    919:         case DIOCGPART:
                    920:                 ((struct partinfo *)addr)->disklab = &du->dk_dd;
                    921:                 ((struct partinfo *)addr)->part =
                    922:                     &du->dk_dd.d_partitions[wdpart(dev)];
                    923:                 break;
                    924: 
                    925:         case DIOCSDINFO:
                    926:                 if ((flag & FWRITE) == 0)
                    927:                         error = EBADF;
                    928:                 else
                    929:                         error = setdisklabel(&du->dk_dd,
                    930:                                        (struct disklabel *)addr,
                    931:                          0 /*(dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart*/);
                    932:                 /*if (error == 0 && dk->dk_state == OPENRAW &&
                    933:                     vdreset_drive(vddinfo[unit]))
                    934:                         dk->dk_state = OPEN;*/
                    935:                wdsetctlr(dev, du);
                    936:                 break;
                    937: 
                    938:         case DIOCWLABEL:
                    939:                 if ((flag & FWRITE) == 0)
                    940:                         error = EBADF;
                    941:                 else
                    942:                         du->dk_wlabel = *(int *)addr;
                    943:                 break;
                    944: 
                    945:         case DIOCWDINFO:
                    946:                 if ((flag & FWRITE) == 0)
                    947:                         error = EBADF;
                    948:                 else if ((error = setdisklabel(&du->dk_dd, (struct disklabel *)addr,
                    949:                   0/*(dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart*/)) == 0) {
                    950:                         int wlab;
                    951: 
                    952:                         /*if (error == 0 && dk->dk_state == OPENRAW &&
                    953:                             vdreset_drive(vddinfo[unit]))
                    954:                                 dk->dk_state = OPEN; */
                    955:                        wdsetctlr(dev, du);
                    956: 
                    957:                         /* simulate opening partition 0 so write succeeds */
                    958:                         /* dk->dk_openpart |= (1 << 0);            /* XXX */
                    959:                         wlab = du->dk_wlabel;
                    960:                         du->dk_wlabel = 1;
                    961:                         error = writedisklabel(dev, wdstrategy, &du->dk_dd,wdpart(dev));
                    962:                         /*dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart;*/
                    963:                         du->dk_wlabel = wlab;
                    964:                 }
                    965:                 break;
                    966: 
                    967: #ifdef notyet
                    968:        case DIOCGDINFOP:
                    969:                *(struct disklabel **)addr = &(du->dk_dd);
                    970:                break;
                    971: 
                    972:        case DIOCWFORMAT:
                    973:                if ((flag & FWRITE) == 0)
                    974:                        error = EBADF;
                    975:                else {
                    976:                        register struct format_op *fop;
                    977: 
                    978:                        fop = (struct format_op *)addr;
                    979:                        aiov.iov_base = fop->df_buf;
                    980:                        aiov.iov_len = fop->df_count;
                    981:                        auio.uio_iov = &aiov;
                    982:                        auio.uio_iovcnt = 1;
                    983:                        auio.uio_resid = fop->df_count;
                    984:                        auio.uio_segflg = 0;
                    985:                        auio.uio_offset =
                    986:                                fop->df_startblk * du->dk_dd.d_secsize;
                    987:                        error = physio(wdformat, &rwdbuf[unit], dev, B_WRITE,
                    988:                                minphys, &auio);
                    989:                        fop->df_count -= auio.uio_resid;
                    990:                        fop->df_reg[0] = du->dk_status;
                    991:                        fop->df_reg[1] = du->dk_error;
                    992:                }
                    993:                break;
                    994: #endif
                    995: 
                    996:        default:
                    997:                error = ENOTTY;
                    998:                break;
                    999:        }
                   1000:        return (error);
                   1001: }
                   1002: 
                   1003: /*wdformat(bp)
                   1004:        struct buf *bp;
                   1005: {
                   1006: 
                   1007:        bp->b_flags |= B_FORMAT;
                   1008:        return (wdstrategy(bp));
                   1009: }*/
                   1010: 
                   1011: wdsize(dev)
                   1012:        dev_t dev;
                   1013: {
                   1014:        register unit = wdunit(dev);
                   1015:        register part = wdpart(dev);
                   1016:        register struct disk *du;
                   1017:        register val ;
                   1018: 
                   1019:        if (unit >= NWD) return(-1);
                   1020:        if (wddrives[unit].dk_state == 0) {
                   1021:                val = wdopen (dev, 0);
                   1022:                if (val < 0)
                   1023:                        return (-1);
                   1024:        }
                   1025:        du = &wddrives[unit];
                   1026:        return((int)((u_long)du->dk_dd.d_partitions[part].p_size *
                   1027:                du->dk_dd.d_secsize / 512));
                   1028: }
                   1029: 
                   1030: extern        char *vmmap;            /* poor name! */
                   1031: 
                   1032: wddump(dev)                    /* dump core after a system crash */
                   1033:        dev_t dev;
                   1034: {
                   1035:        register struct disk *du;       /* disk unit to do the IO */
                   1036:        register struct bt_bad *bt_ptr;
                   1037:        long    num;                    /* number of sectors to write */
                   1038:        int     unit, part;
                   1039:        long    cyloff, blknum, blkcnt;
                   1040:        long    cylin, head, sector, stat;
                   1041:        long    secpertrk, secpercyl, nblocks, i;
                   1042:        char *addr;
                   1043:        extern  int Maxmem;
                   1044:        static  wddoingadump = 0 ;
                   1045:        extern CMAP1;
                   1046:        extern char CADDR1[];
                   1047: 
                   1048:        
                   1049: #ifdef ARGO
                   1050: outb(0x461,0); /* disable failsafe timer */
                   1051: #endif
                   1052:        addr = (char *) 0;              /* starting address */
                   1053:        /* size of memory to dump */
                   1054:        num = Maxmem;
                   1055:        unit = wdunit(dev);             /* eventually support floppies? */
                   1056:        part = wdpart(dev);             /* file system */
                   1057:        /* check for acceptable drive number */
                   1058:        if (unit >= NWD) return(ENXIO);
                   1059: 
                   1060:        du = &wddrives[unit];
                   1061:        /* was it ever initialized ? */
                   1062:        if (du->dk_state < OPEN) return (ENXIO) ;
                   1063: 
                   1064:        /* Convert to disk sectors */
                   1065:        num = (u_long) num * NBPG / du->dk_dd.d_secsize;
                   1066: 
                   1067:        /* check if controller active */
                   1068:        /*if (wdtab.b_active) return(EFAULT); */
                   1069:        if (wddoingadump) return(EFAULT);
                   1070: 
                   1071:        secpertrk = du->dk_dd.d_nsectors;
                   1072:        secpercyl = du->dk_dd.d_secpercyl;
                   1073:        nblocks = du->dk_dd.d_partitions[part].p_size;
                   1074:        cyloff = du->dk_dd.d_partitions[part].p_offset / secpercyl;
                   1075: 
                   1076: /*pg("xunit %x, nblocks %d, dumplo %d num %d\n", part,nblocks,dumplo,num);*/
                   1077:        /* check transfer bounds against partition size */
                   1078:        if ((dumplo < 0) || ((dumplo + num) > nblocks))
                   1079:                return(EINVAL);
                   1080: 
                   1081:        /*wdtab.b_active = 1;           /* mark controller active for if we
                   1082:                                           panic during the dump */
                   1083:        wddoingadump = 1  ;  i = 100000 ;
                   1084:        while ((inb(wdc+wd_status) & WDCS_BUSY) && (i-- > 0)) ;
                   1085:        outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
                   1086:        outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
                   1087:        while (inb(wdc+wd_status) & WDCS_BUSY) ;
                   1088: 
                   1089:        /* some compaq controllers require this ... */
                   1090:        wdsetctlr(dev, du);
                   1091:        
                   1092:        blknum = dumplo;
                   1093:        while (num > 0) {
                   1094: #ifdef notdef
                   1095:                if (blkcnt > MAXTRANSFER) blkcnt = MAXTRANSFER;
                   1096:                if ((blknum + blkcnt - 1) / secpercyl != blknum / secpercyl)
                   1097:                        blkcnt = secpercyl - (blknum % secpercyl);
                   1098:                            /* keep transfer within current cylinder */
                   1099: #endif
                   1100:                pmap_enter(pmap_kernel(), vmmap, addr, VM_PROT_READ, TRUE);
                   1101: 
                   1102:                /* compute disk address */
                   1103:                cylin = blknum / secpercyl;
                   1104:                head = (blknum % secpercyl) / secpertrk;
                   1105:                sector = blknum % secpertrk;
                   1106:                cylin += cyloff;
                   1107: 
                   1108: #ifdef notyet
                   1109:                /* 
                   1110:                 * See if the current block is in the bad block list.
                   1111:                 * (If we have one.)
                   1112:                 */
                   1113:                        for (bt_ptr = dkbad[unit].bt_bad;
                   1114:                                bt_ptr->bt_cyl != -1; bt_ptr++) {
                   1115:                        if (bt_ptr->bt_cyl > cylin)
                   1116:                                /* Sorted list, and we passed our cylinder.
                   1117:                                        quit. */
                   1118:                                break;
                   1119:                        if (bt_ptr->bt_cyl == cylin &&
                   1120:                                bt_ptr->bt_trksec == (head << 8) + sector) {
                   1121:                        /*
                   1122:                         * Found bad block.  Calculate new block addr.
                   1123:                         * This starts at the end of the disk (skip the
                   1124:                         * last track which is used for the bad block list),
                   1125:                         * and works backwards to the front of the disk.
                   1126:                         */
                   1127:                                blknum = (du->dk_dd.d_secperunit)
                   1128:                                        - du->dk_dd.d_nsectors
                   1129:                                        - (bt_ptr - dkbad[unit].bt_bad) - 1;
                   1130:                                cylin = blknum / secpercyl;
                   1131:                                head = (blknum % secpercyl) / secpertrk;
                   1132:                                sector = blknum % secpertrk;
                   1133:                                break;
                   1134:                        }
                   1135: 
                   1136: #endif
                   1137:                sector++;               /* origin 1 */
                   1138: 
                   1139:                /* select drive.     */
                   1140:                outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf));
                   1141:                while ((inb(wdc+wd_status) & WDCS_READY) == 0) ;
                   1142: 
                   1143:                /* transfer some blocks */
                   1144:                outb(wdc+wd_sector, sector);
                   1145:                outb(wdc+wd_seccnt,1);
                   1146:                outb(wdc+wd_cyl_lo, cylin);
                   1147:                outb(wdc+wd_cyl_hi, cylin >> 8);
                   1148: #ifdef notdef
                   1149:                /* lets just talk about this first...*/
                   1150:                pg ("sdh 0%o sector %d cyl %d addr 0x%x",
                   1151:                        inb(wdc+wd_sdh), inb(wdc+wd_sector),
                   1152:                        inb(wdc+wd_cyl_hi)*256+inb(wdc+wd_cyl_lo), addr) ;
                   1153: #endif
                   1154: #ifdef ODYSSEUS
                   1155: if(cylin < 46 || cylin > 91)pg("oops");
                   1156: #endif
                   1157: #ifdef PRIAM
                   1158: if(cylin < 40 || cylin > 79)pg("oops");
                   1159: #endif
                   1160:                outb(wdc+wd_command, WDCC_WRITE);
                   1161:                
                   1162:                /* Ready to send data?  */
                   1163:                while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ;
                   1164:                if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
                   1165: 
                   1166:                outsw (wdc+wd_data, CADDR1+((int)addr&(NBPG-1)), 256);
                   1167:                (int) addr += 512;
                   1168: 
                   1169:                if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
                   1170:                /* Check data request (should be done).         */
                   1171:                if (inb(wdc+wd_status) & WDCS_DRQ) return(EIO) ;
                   1172: 
                   1173:                /* wait for completion */
                   1174:                for ( i = 1000000 ; inb(wdc+wd_status) & WDCS_BUSY ; i--) {
                   1175:                                if (i < 0) return (EIO) ;
                   1176:                }
                   1177:                /* error check the xfer */
                   1178:                if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
                   1179:                /* update block count */
                   1180:                num--;
                   1181:                blknum++ ;
                   1182: if (num % 100 == 0) printf(".") ;
                   1183:        }
                   1184:        return(0);
                   1185: }
                   1186: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.