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

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: 
        !            65: #define wdctlr(dev)    ((minor(dev) & 0x80) >> 7)
        !            66: #define wdunit(dev)    ((minor(dev) & 0x60) >> 5)
        !            67: #define wdpart(dev)    ((minor(dev) & 0x1f))
        !            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 */
        !           145:        {21600, 40, 0,0,0,0},
        !           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);
        !           449: #ifdef WDDEBUG
        !           450:        dprintf(DDSK,"sector %d cylin %d head %d addr %x sts %x\n",
        !           451:            sector, cylin, head, addr, inb(wdc+wd_altsts));
        !           452: #endif
        !           453: }
        !           454:                
        !           455:        /* If this is a read operation, just go away until it's done.   */
        !           456:        if (bp->b_flags & B_READ) return;
        !           457: 
        !           458:        /* Ready to send data?  */
        !           459:        while ((inb(wdc+wd_status) & WDCS_DRQ) == 0);
        !           460: 
        !           461:        /* ASSUMES CONTIGUOUS MEMORY */
        !           462:        outsw (wdc+wd_data, addr+du->dk_skip*512, 256);
        !           463:        du->dk_bc -= 512;
        !           464: }
        !           465: 
        !           466: /*
        !           467:  * these are globally defined so they can be found
        !           468:  * by the debugger easily in the case of a system crash
        !           469:  */
        !           470: daddr_t wd_errsector;
        !           471: daddr_t wd_errbn;
        !           472: unsigned char wd_errstat;
        !           473: 
        !           474: /* Interrupt routine for the controller.  Acknowledge the interrupt, check for
        !           475:  * errors on the current operation, mark it done if necessary, and start
        !           476:  * the next request.  Also check for a partially done transfer, and
        !           477:  * continue with the next chunk if so.
        !           478:  */
        !           479: wdintr(unit)
        !           480: {
        !           481:        register struct disk *du;
        !           482:        register struct buf *bp, *dp;
        !           483:        int status;
        !           484:        char partch ;
        !           485:        static wd_haderror;
        !           486: 
        !           487:        /* Shouldn't need this, but it may be a slow controller.        */
        !           488:        while ((status = inb(wdc+wd_status)) & WDCS_BUSY) ;
        !           489:        if (!wdtab.b_active) {
        !           490:                printf("wd: extra interrupt\n");
        !           491:                return;
        !           492:        }
        !           493: 
        !           494: #ifdef WDDEBUG
        !           495:        dprintf(DDSK,"I ");
        !           496: #endif
        !           497:        dp = wdtab.b_actf;
        !           498:        bp = dp->b_actf;
        !           499:        du = &wddrives[wdunit(bp->b_dev)];
        !           500:        partch = wdpart(bp->b_dev) + 'a';
        !           501:        if (DISKSTATE(du->dk_state) <= RDLABEL) {
        !           502:                if (wdcontrol(bp))
        !           503:                        goto done;
        !           504:                return;
        !           505:        }
        !           506:        if (status & (WDCS_ERR | WDCS_ECCCOR)) {
        !           507:                wd_errstat = inb(wdc+wd_error);         /* save error status */
        !           508: #ifdef WDDEBUG
        !           509:                printf("status %x error %x\n", status, wd_errstat);
        !           510: #endif
        !           511:                if(wd_sebyse == 0) {
        !           512:                        wd_haderror = 1;
        !           513:                        goto outt;
        !           514:                }
        !           515:                /*if (bp->b_flags & B_FORMAT) {
        !           516:                        du->dk_status = status;
        !           517:                        du->dk_error = wdp->wd_error;
        !           518:                        bp->b_flags |= B_ERROR;
        !           519:                        goto done;
        !           520:                }*/
        !           521:                
        !           522:                wd_errsector = (bp->b_cylin * du->dk_dd.d_secpercyl) +
        !           523:                        (((unsigned long) bp->b_blkno * DEV_BSIZE /
        !           524:                            du->dk_dd.d_secsize) % du->dk_dd.d_secpercyl) +
        !           525:                        du->dk_skip;
        !           526:                wd_errbn = bp->b_blkno
        !           527:                        + du->dk_skip * du->dk_dd.d_secsize / DEV_BSIZE ;
        !           528:                if (status & WDCS_ERR) {
        !           529:                        if (++wdtab.b_errcnt < RETRIES) {
        !           530:                                wdtab.b_active = 0;
        !           531:                        } else {
        !           532:                                printf("wd%d%c: ", du->dk_unit, partch);
        !           533:                                printf(
        !           534:                                "hard %s error, sn %d bn %d status %b error %b\n",
        !           535:                                        (bp->b_flags & B_READ)? "read":"write",
        !           536:                                        wd_errsector, wd_errbn, status, WDCS_BITS,
        !           537:                                        wd_errstat, WDERR_BITS);
        !           538:                                bp->b_flags |= B_ERROR; /* flag the error */
        !           539:                        }
        !           540:                } else
        !           541:                        log(LOG_WARNING,"wd%d%c: soft ecc sn %d bn %d\n",
        !           542:                                du->dk_unit, partch, wd_errsector,
        !           543:                                wd_errbn);
        !           544:        }
        !           545: outt:
        !           546: 
        !           547:        /*
        !           548:         * If this was a successful read operation, fetch the data.
        !           549:         */
        !           550:        if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) && wdtab.b_active) {
        !           551:                int chk, dummy;
        !           552: 
        !           553:                chk = min(256,du->dk_bc/2);
        !           554:                /* Ready to receive data?       */
        !           555:                while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ;
        !           556: 
        !           557: /*dprintf(DDSK,"addr %x\n", (int)bp->b_un.b_addr + du->dk_skip * 512);*/
        !           558:                insw(wdc+wd_data,(int)bp->b_un.b_addr + du->dk_skip * 512 ,chk);
        !           559:                du->dk_bc -= 2*chk;
        !           560:                while (chk++ < 256) insw (wdc+wd_data,&dummy,1);
        !           561:        }
        !           562: 
        !           563:        wdxfer[du->dk_unit]++;
        !           564:        if (wdtab.b_active) {
        !           565:                if ((bp->b_flags & B_ERROR) == 0) {
        !           566:                        du->dk_skip++;          /* Add to successful sectors. */
        !           567:                        if (wdtab.b_errcnt) {
        !           568:                                log(LOG_WARNING, "wd%d%c: ",
        !           569:                                                du->dk_unit, partch);
        !           570:                                log(LOG_WARNING,
        !           571:                        "soft %s error, sn %d bn %d error %b retries %d\n",
        !           572:                                    (bp->b_flags & B_READ) ? "read" : "write",
        !           573:                                    wd_errsector, wd_errbn, wd_errstat,
        !           574:                                    WDERR_BITS, wdtab.b_errcnt);
        !           575:                        }
        !           576:                        wdtab.b_errcnt = 0;
        !           577: 
        !           578:                        /* see if more to transfer */
        !           579:                        /*if (du->dk_skip < (bp->b_bcount + 511) / 512) {*/
        !           580:                        if (du->dk_bc > 0 && wd_haderror == 0) {
        !           581:                                wdstart();
        !           582:                                return;         /* next chunk is started */
        !           583:                        } else if (wd_haderror && wd_sebyse == 0) {
        !           584:                                du->dk_skip = 0;
        !           585:                                wd_haderror = 0;
        !           586:                                wd_sebyse = 1;
        !           587:                                wdstart();
        !           588:                                return;         /* redo xfer sector by sector */
        !           589:                        }
        !           590:                }
        !           591: 
        !           592: done:
        !           593:                wd_sebyse = 0;
        !           594:                /* done with this transfer, with or without error */
        !           595:                wdtab.b_actf = dp->b_forw;
        !           596:                wdtab.b_errcnt = 0;
        !           597:                du->dk_skip = 0;
        !           598:                dp->b_active = 0;
        !           599:                dp->b_actf = bp->av_forw;
        !           600:                dp->b_errcnt = 0;
        !           601:                bp->b_resid = 0;
        !           602:                biodone(bp);
        !           603:        }
        !           604:        wdtab.b_active = 0;
        !           605:        if (dp->b_actf)
        !           606:                wdustart(du);           /* requeue disk if more io to do */
        !           607:        if (wdtab.b_actf)
        !           608:                wdstart();              /* start IO on next drive */
        !           609: }
        !           610: 
        !           611: /*
        !           612:  * Initialize a drive.
        !           613:  */
        !           614: wdopen(dev, flags, fmt)
        !           615:         dev_t dev;
        !           616:         int flags, fmt;
        !           617: {
        !           618:        register unsigned int unit;
        !           619:        register struct buf *bp;
        !           620:        register struct disk *du;
        !           621:         int part = wdpart(dev), mask = 1 << part;
        !           622:         struct partition *pp;
        !           623:        struct dkbad *db;
        !           624:        int i, error = 0;
        !           625: 
        !           626:        unit = wdunit(dev);
        !           627:        if (unit >= NWD) return (ENXIO) ;
        !           628:        du = &wddrives[unit];
        !           629: #ifdef notdef
        !           630:        if (du->dk_open){
        !           631:                du->dk_open++ ;
        !           632:                return(0);      /* already is open, don't mess with it */
        !           633:        }
        !           634: #endif
        !           635:        du->dk_unit = unit;
        !           636:        wdutab[unit].b_actf = NULL;
        !           637:        /*if (flags & O_NDELAY)
        !           638:                du->dk_state = WANTOPENRAW;
        !           639:        else*/
        !           640:                du->dk_state = WANTOPEN;
        !           641:        /*
        !           642:         * Use the default sizes until we've read the label,
        !           643:         * or longer if there isn't one there.
        !           644:         */
        !           645:        du->dk_dd = dflt_sizes;
        !           646: 
        !           647:        /*
        !           648:         * Recal, read of disk label will be done in wdcontrol
        !           649:         * during first read operation.
        !           650:         */
        !           651:        bp = geteblk(512);
        !           652:        bp->b_dev = dev & 0xff00;
        !           653:        bp->b_bcount = 0;
        !           654:        bp->b_blkno = LABELSECTOR;
        !           655:        bp->b_flags = B_READ;
        !           656:        wdstrategy(bp);
        !           657:        biowait(bp);
        !           658:        if (bp->b_flags & B_ERROR) {
        !           659:                error = ENXIO;
        !           660:                du->dk_state = CLOSED;
        !           661:                goto done;
        !           662:        }
        !           663:        if (du->dk_state == OPENRAW) {
        !           664:                du->dk_state = OPENRAW;
        !           665:                goto done;
        !           666:        }
        !           667:        /*
        !           668:         * Read bad sector table into memory.
        !           669:         */
        !           670:        i = 0;
        !           671:        do {
        !           672:                bp->b_flags = B_BUSY | B_READ;
        !           673:                bp->b_blkno = du->dk_dd.d_secperunit - du->dk_dd.d_nsectors
        !           674:                        + i;
        !           675:                if (du->dk_dd.d_secsize > DEV_BSIZE)
        !           676:                        bp->b_blkno *= du->dk_dd.d_secsize / DEV_BSIZE;
        !           677:                else
        !           678:                        bp->b_blkno /= DEV_BSIZE / du->dk_dd.d_secsize;
        !           679:                bp->b_bcount = du->dk_dd.d_secsize;
        !           680:                bp->b_cylin = du->dk_dd.d_ncylinders - 1;
        !           681:                wdstrategy(bp);
        !           682:                biowait(bp);
        !           683:        } while ((bp->b_flags & B_ERROR) && (i += 2) < 10 &&
        !           684:                i < du->dk_dd.d_nsectors);
        !           685:        db = (struct dkbad *)(bp->b_un.b_addr);
        !           686: #define DKBAD_MAGIC 0x4321
        !           687:        if ((bp->b_flags & B_ERROR) == 0 && db->bt_mbz == 0 &&
        !           688:            db->bt_flag == DKBAD_MAGIC) {
        !           689:                dkbad[unit] = *db;
        !           690:                du->dk_state = OPEN;
        !           691:        } else {
        !           692:                printf("wd%d: %s bad-sector file\n", unit,
        !           693:                    (bp->b_flags & B_ERROR) ? "can't read" : "format error in");
        !           694:                error = ENXIO ;
        !           695:                du->dk_state = OPENRAW;
        !           696:        }
        !           697: done:
        !           698:        bp->b_flags = B_INVAL | B_AGE;
        !           699:        brelse(bp);
        !           700:        if (error == 0)
        !           701:                du->dk_open = 1;
        !           702: 
        !           703:         /*
        !           704:          * Warn if a partion is opened
        !           705:          * that overlaps another partition which is open
        !           706:          * unless one is the "raw" partition (whole disk).
        !           707:          */
        !           708: #define RAWPART         8               /* 'x' partition */     /* XXX */
        !           709:         if ((du->dk_openpart & mask) == 0 && part != RAWPART) {
        !           710:                int     start, end;
        !           711: 
        !           712:                 pp = &du->dk_dd.d_partitions[part];
        !           713:                 start = pp->p_offset;
        !           714:                 end = pp->p_offset + pp->p_size;
        !           715:                 for (pp = du->dk_dd.d_partitions;
        !           716:                      pp < &du->dk_dd.d_partitions[du->dk_dd.d_npartitions];
        !           717:                        pp++) {
        !           718:                         if (pp->p_offset + pp->p_size <= start ||
        !           719:                             pp->p_offset >= end)
        !           720:                                 continue;
        !           721:                         if (pp - du->dk_dd.d_partitions == RAWPART)
        !           722:                                 continue;
        !           723:                         if (du->dk_openpart & (1 << (pp -
        !           724:                                        du->dk_dd.d_partitions)))
        !           725:                                 log(LOG_WARNING,
        !           726:                                     "wd%d%c: overlaps open partition (%c)\n",
        !           727:                                     unit, part + 'a',
        !           728:                                     pp - du->dk_dd.d_partitions + 'a');
        !           729:                 }
        !           730:         }
        !           731:         if (part >= du->dk_dd.d_npartitions)
        !           732:                 return (ENXIO);
        !           733:         du->dk_openpart |= mask;
        !           734:         switch (fmt) {
        !           735:         case S_IFCHR:
        !           736:                 du->dk_copenpart |= mask;
        !           737:                 break;
        !           738:         case S_IFBLK:
        !           739:                 du->dk_bopenpart |= mask;
        !           740:                 break;
        !           741:         }
        !           742:        return (error);
        !           743: }
        !           744: 
        !           745: /*
        !           746:  * Implement operations other than read/write.
        !           747:  * Called from wdstart or wdintr during opens and formats.
        !           748:  * Uses finite-state-machine to track progress of operation in progress.
        !           749:  * Returns 0 if operation still in progress, 1 if completed.
        !           750:  */
        !           751: wdcontrol(bp)
        !           752:        register struct buf *bp;
        !           753: {
        !           754:        register struct disk *du;
        !           755:        register unit;
        !           756:        unsigned char  stat;
        !           757:        int s, cnt;
        !           758:        extern int bootdev, cyloffset;
        !           759: 
        !           760:        du = &wddrives[wdunit(bp->b_dev)];
        !           761:        unit = du->dk_unit;
        !           762:        switch (DISKSTATE(du->dk_state)) {
        !           763: 
        !           764:        tryagainrecal:
        !           765:        case WANTOPEN:                  /* set SDH, step rate, do restore */
        !           766: #ifdef WDDEBUG
        !           767:                dprintf(DDSK,"wd%d: recal ", unit);
        !           768: #endif
        !           769:                s = splbio();           /* not called from intr level ... */
        !           770:                outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
        !           771:                wdtab.b_active = 1;
        !           772:                outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
        !           773:                du->dk_state++;
        !           774:                splx(s);
        !           775:                return(0);
        !           776: 
        !           777:        case RECAL:
        !           778:                if ((stat = inb(wdc+wd_status)) & WDCS_ERR) {
        !           779:                        printf("wd%d: recal", du->dk_unit);
        !           780:                        if (unit == 0) {
        !           781:                                printf(": status %b error %b\n",
        !           782:                                        stat, WDCS_BITS,
        !           783:                                        inb(wdc+wd_error), WDERR_BITS);
        !           784:                                if (++wdtab.b_errcnt < RETRIES)
        !           785:                                        goto tryagainrecal;
        !           786:                        }
        !           787:                        goto badopen;
        !           788:                }
        !           789: 
        !           790:                /* some compaq controllers require this ... */
        !           791:                wdsetctlr(bp->b_dev, du);
        !           792: 
        !           793:                wdtab.b_errcnt = 0;
        !           794:                if (ISRAWSTATE(du->dk_state)) {
        !           795:                        du->dk_state = OPENRAW;
        !           796:                        return(1);
        !           797:                }
        !           798: retry:
        !           799: #ifdef WDDEBUG
        !           800:                dprintf(DDSK,"rdlabel ");
        !           801: #endif
        !           802: if( cyloffset < 0 || cyloffset > 8192) cyloffset=0;
        !           803:                /*
        !           804:                 * Read in sector LABELSECTOR to get the pack label
        !           805:                 * and geometry.
        !           806:                 */
        !           807:                outb(wdc+wd_precomp, 0xff);/* sometimes this is head bit 3 */
        !           808:                outb(wdc+wd_seccnt, 1);
        !           809:                outb(wdc+wd_sector, LABELSECTOR+1);
        !           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 {
        !           839:                        printf("wd%d: bad disk label\n", du->dk_unit);
        !           840:                        du->dk_state = OPENRAW;
        !           841:                }
        !           842: 
        !           843:                s = splbio();           /* not called from intr level ... */
        !           844:                while ((stat = inb(wdc+wd_status)) & WDCS_BUSY);
        !           845: 
        !           846:                wdsetctlr(bp->b_dev, du);
        !           847: 
        !           848:                outb(wdc+wd_seccnt, 0);
        !           849:                splx(s);
        !           850: 
        !           851:                if (du->dk_state == RDLABEL)
        !           852:                        du->dk_state = RDBADTBL;
        !           853:                /*
        !           854:                 * The rest of the initialization can be done
        !           855:                 * by normal means.
        !           856:                 */
        !           857:                return(1);
        !           858: 
        !           859:        default:
        !           860:                panic("wdcontrol");
        !           861:        }
        !           862:        /* NOTREACHED */
        !           863: 
        !           864: badopen:
        !           865:        printf(": status %b error %b\n",
        !           866:                stat, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS);
        !           867:        du->dk_state = OPENRAW;
        !           868:        return(1);
        !           869: }
        !           870: 
        !           871: wdsetctlr(dev, du) dev_t dev; struct disk *du; {
        !           872:        int stat;
        !           873: 
        !           874:        outb(wdc+wd_cyl_lo, du->dk_dd.d_ncylinders);
        !           875:        outb(wdc+wd_cyl_hi, (du->dk_dd.d_ncylinders)>>8);
        !           876:        outb(wdc+wd_sdh, WDSD_IBM | (wdunit(dev) << 4) + du->dk_dd.d_ntracks-1);
        !           877:        outb(wdc+wd_seccnt, du->dk_dd.d_nsectors);
        !           878:        outb(wdc+wd_command, 0x91);
        !           879: 
        !           880:        while ((stat = inb(wdc+wd_status)) & WDCS_BUSY) ;
        !           881:        stat = inb(wdc+wd_error);
        !           882:        return(stat);
        !           883: }
        !           884: 
        !           885: /* ARGSUSED */
        !           886: wdclose(dev, flags, fmt)
        !           887:         dev_t dev;
        !           888:         int flags, fmt;
        !           889: {
        !           890:        register struct disk *du;
        !           891: 
        !           892:        du = &wddrives[wdunit(dev)];
        !           893:        du->dk_open-- ;
        !           894:        /*if (du->dk_open == 0) du->dk_state = CLOSED ; does not work */
        !           895: }
        !           896: 
        !           897: wdioctl(dev,cmd,addr,flag)
        !           898:        dev_t dev;
        !           899:        caddr_t addr;
        !           900: {
        !           901:        int unit = wdunit(dev);
        !           902:        register struct disk *du;
        !           903:        int error = 0;
        !           904:        struct uio auio;
        !           905:        struct iovec aiov;
        !           906:        /*int wdformat();*/
        !           907: 
        !           908:        du = &wddrives[unit];
        !           909: 
        !           910:        switch (cmd) {
        !           911: 
        !           912:        case DIOCGDINFO:
        !           913:                *(struct disklabel *)addr = du->dk_dd;
        !           914:                break;
        !           915: 
        !           916:         case DIOCGPART:
        !           917:                 ((struct partinfo *)addr)->disklab = &du->dk_dd;
        !           918:                 ((struct partinfo *)addr)->part =
        !           919:                     &du->dk_dd.d_partitions[wdpart(dev)];
        !           920:                 break;
        !           921: 
        !           922:         case DIOCSDINFO:
        !           923:                 if ((flag & FWRITE) == 0)
        !           924:                         error = EBADF;
        !           925:                 else
        !           926:                         error = setdisklabel(&du->dk_dd,
        !           927:                                        (struct disklabel *)addr,
        !           928:                          0 /*(dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart*/);
        !           929:                 /*if (error == 0 && dk->dk_state == OPENRAW &&
        !           930:                     vdreset_drive(vddinfo[unit]))
        !           931:                         dk->dk_state = OPEN;*/
        !           932:                wdsetctlr(dev, du);
        !           933:                 break;
        !           934: 
        !           935:         case DIOCWLABEL:
        !           936:                 if ((flag & FWRITE) == 0)
        !           937:                         error = EBADF;
        !           938:                 else
        !           939:                         du->dk_wlabel = *(int *)addr;
        !           940:                 break;
        !           941: 
        !           942:         case DIOCWDINFO:
        !           943:                 if ((flag & FWRITE) == 0)
        !           944:                         error = EBADF;
        !           945:                 else if ((error = setdisklabel(&du->dk_dd, (struct disklabel *)addr,
        !           946:                   0/*(dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart*/)) == 0) {
        !           947:                         int wlab;
        !           948: 
        !           949:                         /*if (error == 0 && dk->dk_state == OPENRAW &&
        !           950:                             vdreset_drive(vddinfo[unit]))
        !           951:                                 dk->dk_state = OPEN; */
        !           952:                        wdsetctlr(dev, du);
        !           953: 
        !           954:                         /* simulate opening partition 0 so write succeeds */
        !           955:                         /* dk->dk_openpart |= (1 << 0);            /* XXX */
        !           956:                         wlab = du->dk_wlabel;
        !           957:                         du->dk_wlabel = 1;
        !           958:                         error = writedisklabel(dev, wdstrategy, &du->dk_dd,wdpart(dev));
        !           959:                         /*dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart;*/
        !           960:                         du->dk_wlabel = wlab;
        !           961:                 }
        !           962:                 break;
        !           963: 
        !           964: #ifdef notyet
        !           965:        case DIOCGDINFOP:
        !           966:                *(struct disklabel **)addr = &(du->dk_dd);
        !           967:                break;
        !           968: 
        !           969:        case DIOCWFORMAT:
        !           970:                if ((flag & FWRITE) == 0)
        !           971:                        error = EBADF;
        !           972:                else {
        !           973:                        register struct format_op *fop;
        !           974: 
        !           975:                        fop = (struct format_op *)addr;
        !           976:                        aiov.iov_base = fop->df_buf;
        !           977:                        aiov.iov_len = fop->df_count;
        !           978:                        auio.uio_iov = &aiov;
        !           979:                        auio.uio_iovcnt = 1;
        !           980:                        auio.uio_resid = fop->df_count;
        !           981:                        auio.uio_segflg = 0;
        !           982:                        auio.uio_offset =
        !           983:                                fop->df_startblk * du->dk_dd.d_secsize;
        !           984:                        error = physio(wdformat, &rwdbuf[unit], dev, B_WRITE,
        !           985:                                minphys, &auio);
        !           986:                        fop->df_count -= auio.uio_resid;
        !           987:                        fop->df_reg[0] = du->dk_status;
        !           988:                        fop->df_reg[1] = du->dk_error;
        !           989:                }
        !           990:                break;
        !           991: #endif
        !           992: 
        !           993:        default:
        !           994:                error = ENOTTY;
        !           995:                break;
        !           996:        }
        !           997:        return (error);
        !           998: }
        !           999: 
        !          1000: /*wdformat(bp)
        !          1001:        struct buf *bp;
        !          1002: {
        !          1003: 
        !          1004:        bp->b_flags |= B_FORMAT;
        !          1005:        return (wdstrategy(bp));
        !          1006: }*/
        !          1007: 
        !          1008: /*
        !          1009:  * Routines to do raw IO for a unit.
        !          1010:  */
        !          1011: wdread(dev, uio)                       /* character read routine */
        !          1012:        dev_t dev;
        !          1013:        struct uio *uio;
        !          1014: {
        !          1015:        int unit = wdunit(dev) ;
        !          1016: 
        !          1017:        if (unit >= NWD) return(ENXIO);
        !          1018:        return(physio(wdstrategy, &rwdbuf[unit], dev, B_READ, minphys, uio));
        !          1019: }
        !          1020: 
        !          1021: 
        !          1022: wdwrite(dev, uio)                      /* character write routine */
        !          1023:        dev_t dev;
        !          1024:        struct uio *uio;
        !          1025: {
        !          1026:        int unit = wdunit(dev) ;
        !          1027: 
        !          1028:        if (unit >= NWD) return(ENXIO);
        !          1029:        return(physio(wdstrategy, &rwdbuf[unit], dev, B_WRITE, minphys, uio));
        !          1030: }
        !          1031: 
        !          1032: wdsize(dev)
        !          1033:        dev_t dev;
        !          1034: {
        !          1035:        register unit = wdunit(dev);
        !          1036:        register part = wdpart(dev);
        !          1037:        register struct disk *du;
        !          1038:        register val ;
        !          1039: 
        !          1040:        if (unit >= NWD) return(-1);
        !          1041:        if (wddrives[unit].dk_state == 0) {
        !          1042:                val = wdopen (dev, 0);
        !          1043:                if (val < 0)
        !          1044:                        return (-1);
        !          1045:        }
        !          1046:        du = &wddrives[unit];
        !          1047:        return((int)((u_long)du->dk_dd.d_partitions[part].p_size *
        !          1048:                du->dk_dd.d_secsize / 512));
        !          1049: }
        !          1050: 
        !          1051: extern        char *vmmap;            /* poor name! */
        !          1052: 
        !          1053: wddump(dev)                    /* dump core after a system crash */
        !          1054:        dev_t dev;
        !          1055: {
        !          1056:        register struct disk *du;       /* disk unit to do the IO */
        !          1057:        register struct bt_bad *bt_ptr;
        !          1058:        long    num;                    /* number of sectors to write */
        !          1059:        int     unit, part;
        !          1060:        long    cyloff, blknum, blkcnt;
        !          1061:        long    cylin, head, sector, stat;
        !          1062:        long    secpertrk, secpercyl, nblocks, i;
        !          1063:        char *addr;
        !          1064:        extern  int Maxmem;
        !          1065:        static  wddoingadump = 0 ;
        !          1066:        extern CMAP1;
        !          1067:        extern char CADDR1[];
        !          1068: 
        !          1069:        
        !          1070: #ifdef ARGO
        !          1071: outb(0x461,0); /* disable failsafe timer */
        !          1072: #endif
        !          1073:        addr = (char *) 0;              /* starting address */
        !          1074:        /* size of memory to dump */
        !          1075:        num = Maxmem;
        !          1076:        unit = wdunit(dev);             /* eventually support floppies? */
        !          1077:        part = wdpart(dev);             /* file system */
        !          1078:        /* check for acceptable drive number */
        !          1079:        if (unit >= NWD) return(ENXIO);
        !          1080: 
        !          1081:        du = &wddrives[unit];
        !          1082:        /* was it ever initialized ? */
        !          1083:        if (du->dk_state < OPEN) return (ENXIO) ;
        !          1084: 
        !          1085:        /* Convert to disk sectors */
        !          1086:        num = (u_long) num * NBPG / du->dk_dd.d_secsize;
        !          1087: 
        !          1088:        /* check if controller active */
        !          1089:        /*if (wdtab.b_active) return(EFAULT); */
        !          1090:        if (wddoingadump) return(EFAULT);
        !          1091: 
        !          1092:        secpertrk = du->dk_dd.d_nsectors;
        !          1093:        secpercyl = du->dk_dd.d_secpercyl;
        !          1094:        nblocks = du->dk_dd.d_partitions[part].p_size;
        !          1095:        cyloff = du->dk_dd.d_partitions[part].p_offset / secpercyl;
        !          1096: 
        !          1097: /*pg("xunit %x, nblocks %d, dumplo %d num %d\n", part,nblocks,dumplo,num);*/
        !          1098:        /* check transfer bounds against partition size */
        !          1099:        if ((dumplo < 0) || ((dumplo + num) > nblocks))
        !          1100:                return(EINVAL);
        !          1101: 
        !          1102:        /*wdtab.b_active = 1;           /* mark controller active for if we
        !          1103:                                           panic during the dump */
        !          1104:        wddoingadump = 1  ;  i = 100000 ;
        !          1105:        while ((inb(wdc+wd_status) & WDCS_BUSY) && (i-- > 0)) ;
        !          1106:        outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
        !          1107:        outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
        !          1108:        while (inb(wdc+wd_status) & WDCS_BUSY) ;
        !          1109: 
        !          1110:        /* some compaq controllers require this ... */
        !          1111:        wdsetctlr(dev, du);
        !          1112:        
        !          1113:        blknum = dumplo;
        !          1114:        while (num > 0) {
        !          1115: #ifdef notdef
        !          1116:                if (blkcnt > MAXTRANSFER) blkcnt = MAXTRANSFER;
        !          1117:                if ((blknum + blkcnt - 1) / secpercyl != blknum / secpercyl)
        !          1118:                        blkcnt = secpercyl - (blknum % secpercyl);
        !          1119:                            /* keep transfer within current cylinder */
        !          1120: #endif
        !          1121:                pmap_enter(pmap_kernel(), vmmap, addr, VM_PROT_READ, TRUE);
        !          1122: 
        !          1123:                /* compute disk address */
        !          1124:                cylin = blknum / secpercyl;
        !          1125:                head = (blknum % secpercyl) / secpertrk;
        !          1126:                sector = blknum % secpertrk;
        !          1127:                cylin += cyloff;
        !          1128: 
        !          1129: #ifdef notyet
        !          1130:                /* 
        !          1131:                 * See if the current block is in the bad block list.
        !          1132:                 * (If we have one.)
        !          1133:                 */
        !          1134:                        for (bt_ptr = dkbad[unit].bt_bad;
        !          1135:                                bt_ptr->bt_cyl != -1; bt_ptr++) {
        !          1136:                        if (bt_ptr->bt_cyl > cylin)
        !          1137:                                /* Sorted list, and we passed our cylinder.
        !          1138:                                        quit. */
        !          1139:                                break;
        !          1140:                        if (bt_ptr->bt_cyl == cylin &&
        !          1141:                                bt_ptr->bt_trksec == (head << 8) + sector) {
        !          1142:                        /*
        !          1143:                         * Found bad block.  Calculate new block addr.
        !          1144:                         * This starts at the end of the disk (skip the
        !          1145:                         * last track which is used for the bad block list),
        !          1146:                         * and works backwards to the front of the disk.
        !          1147:                         */
        !          1148:                                blknum = (du->dk_dd.d_secperunit)
        !          1149:                                        - du->dk_dd.d_nsectors
        !          1150:                                        - (bt_ptr - dkbad[unit].bt_bad) - 1;
        !          1151:                                cylin = blknum / secpercyl;
        !          1152:                                head = (blknum % secpercyl) / secpertrk;
        !          1153:                                sector = blknum % secpertrk;
        !          1154:                                break;
        !          1155:                        }
        !          1156: 
        !          1157: #endif
        !          1158:                sector++;               /* origin 1 */
        !          1159: 
        !          1160:                /* select drive.     */
        !          1161:                outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf));
        !          1162:                while ((inb(wdc+wd_status) & WDCS_READY) == 0) ;
        !          1163: 
        !          1164:                /* transfer some blocks */
        !          1165:                outb(wdc+wd_sector, sector);
        !          1166:                outb(wdc+wd_seccnt,1);
        !          1167:                outb(wdc+wd_cyl_lo, cylin);
        !          1168:                outb(wdc+wd_cyl_hi, cylin >> 8);
        !          1169: #ifdef notdef
        !          1170:                /* lets just talk about this first...*/
        !          1171:                pg ("sdh 0%o sector %d cyl %d addr 0x%x",
        !          1172:                        inb(wdc+wd_sdh), inb(wdc+wd_sector),
        !          1173:                        inb(wdc+wd_cyl_hi)*256+inb(wdc+wd_cyl_lo), addr) ;
        !          1174: #endif
        !          1175: #ifdef ODYSSEUS
        !          1176: if(cylin < 46 || cylin > 91)pg("oops");
        !          1177: #endif
        !          1178: #ifdef PRIAM
        !          1179: if(cylin < 40 || cylin > 79)pg("oops");
        !          1180: #endif
        !          1181:                outb(wdc+wd_command, WDCC_WRITE);
        !          1182:                
        !          1183:                /* Ready to send data?  */
        !          1184:                while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ;
        !          1185:                if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
        !          1186: 
        !          1187:                outsw (wdc+wd_data, CADDR1+((int)addr&(NBPG-1)), 256);
        !          1188:                (int) addr += 512;
        !          1189: 
        !          1190:                if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
        !          1191:                /* Check data request (should be done).         */
        !          1192:                if (inb(wdc+wd_status) & WDCS_DRQ) return(EIO) ;
        !          1193: 
        !          1194:                /* wait for completion */
        !          1195:                for ( i = 1000000 ; inb(wdc+wd_status) & WDCS_BUSY ; i--) {
        !          1196:                                if (i < 0) return (EIO) ;
        !          1197:                }
        !          1198:                /* error check the xfer */
        !          1199:                if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
        !          1200:                /* update block count */
        !          1201:                num--;
        !          1202:                blknum++ ;
        !          1203: if (num % 100 == 0) printf(".") ;
        !          1204:        }
        !          1205:        return(0);
        !          1206: }
        !          1207: #endif

unix.superglobalmegacorp.com

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