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

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:  *
1.1.1.3   root       36:  *     from:@(#)wd.c   7.2 (Berkeley) 5/9/91
1.1       root       37:  */
                     38: 
1.1.1.4 ! root       39: /* Note: This code heavily modified by [email protected]; use at own risk! */
        !            40: /* The following defines represent only a very small part of the mods, most */
        !            41: /* of them are not marked in any way.  -tih                                 */
        !            42: 
        !            43: #undef WDOPENLOCK      /* Prevent reentrancy in wdopen() for testing */
        !            44: #define        TIHMODS         /* wdopen() workaround, some splx() calls */
        !            45: #define        TIHBAD144       /* new bad144 bad sector handling */
        !            46: #define        QUIETWORKS      /* define this when wdopen() can actually set DKFL_QUIET */
        !            47: #define INSTRUMENT     /* Add instrumentation stuff by Brad Parker */
1.1       root       48: 
1.1.1.4 ! root       49: /* TODO: peel out buffer at low ipl, speed improvement */
        !            50: /* TODO: find and fix the timing bugs apparent on some controllers */
1.1       root       51: 
                     52: #include "wd.h"
1.1.1.4 ! root       53: #if    NWDC > 0
1.1       root       54: 
                     55: #include "param.h"
                     56: #include "dkbad.h"
                     57: #include "systm.h"
                     58: #include "conf.h"
                     59: #include "file.h"
                     60: #include "stat.h"
                     61: #include "ioctl.h"
                     62: #include "disklabel.h"
                     63: #include "buf.h"
                     64: #include "uio.h"
1.1.1.3   root       65: #include "malloc.h"
                     66: #include "machine/cpu.h"
1.1.1.4 ! root       67: #ifdef INSTRUMENT
        !            68: #include "sys/dkstat.h"
        !            69: #endif
        !            70: #include "i386/isa/isa.h"
1.1       root       71: #include "i386/isa/isa_device.h"
                     72: #include "i386/isa/icu.h"
                     73: #include "i386/isa/wdreg.h"
                     74: #include "syslog.h"
                     75: #include "vm/vm.h"
                     76: 
                     77: #define        RETRIES         5       /* number of retries before giving up */
                     78: 
1.1.1.3   root       79: #define wdnoreloc(dev) (minor(dev) & 0x80)     /* ignore partition table */
                     80: #define wddospart(dev) (minor(dev) & 0x40)     /* use dos partitions */
                     81: #define wdunit(dev)    ((minor(dev) & 0x38) >> 3)
                     82: #define wdpart(dev)    (minor(dev) & 0x7)
                     83: #define makewddev(maj, unit, part)     (makedev(maj,((unit<<3)+part)))
                     84: #define WDRAW  3               /* 'd' partition isn't a partition! */
1.1       root       85: 
                     86: #define b_cylin        b_resid         /* cylinder number for doing IO to */
                     87:                                /* shares an entry in the buf struct */
                     88: 
                     89: /*
1.1.1.3   root       90:  * Drive states.  Used to initialize drive.
1.1       root       91:  */
                     92: 
                     93: #define        CLOSED          0               /* disk is closed. */
                     94: #define        WANTOPEN        1               /* open requested, not started */
                     95: #define        RECAL           2               /* doing restore */
1.1.1.3   root       96: #define        OPEN            3               /* done with open */
1.1       root       97: 
                     98: /*
                     99:  * The structure of a disk drive.
                    100:  */
                    101: struct disk {
                    102:        long    dk_bc;          /* byte count left */
1.1.1.4 ! root      103:        long    dk_bct;         /* total byte count left */
1.1       root      104:        short   dk_skip;        /* blocks already transferred */
1.1.1.4 ! root      105:        short   dk_skipm;       /* blocks already transferred for multi */
        !           106:        char    dk_ctrlr;       /* physical controller number */
1.1       root      107:        char    dk_unit;        /* physical unit number */
1.1.1.4 ! root      108:        char    dk_lunit;       /* logical unit number */
1.1       root      109:        char    dk_state;       /* control state */
                    110:        u_char  dk_status;      /* copy of status reg. */
                    111:        u_char  dk_error;       /* copy of error reg. */
1.1.1.3   root      112:        short   dk_port;        /* i/o port base */
                    113:        
1.1.1.4 ! root      114:        u_long  dk_copenpart;   /* character units open on this drive */
        !           115:        u_long  dk_bopenpart;   /* block units open on this drive */
        !           116:        u_long  dk_openpart;    /* all units open on this drive */
1.1       root      117:        short   dk_wlabel;      /* label writable? */
1.1.1.3   root      118:        short   dk_flags;       /* drive characteistics found */
                    119: #define        DKFL_DOSPART    0x00001  /* has DOS partition table */
                    120: #define        DKFL_QUIET      0x00002  /* report errors back, but don't complain */
                    121: #define        DKFL_SINGLE     0x00004  /* sector at a time mode */
                    122: #define        DKFL_ERROR      0x00008  /* processing a disk error */
                    123: #define        DKFL_BSDLABEL   0x00010  /* has a BSD disk label */
                    124: #define        DKFL_BADSECT    0x00020  /* has a bad144 badsector table */
                    125: #define        DKFL_WRITEPROT  0x00040  /* manual unit write protect */
                    126:        struct wdparams dk_params; /* ESDI/IDE drive/controller parameters */
                    127:        struct disklabel dk_dd; /* device configuration data */
                    128:        struct  dos_partition
                    129:                dk_dospartitions[NDOSPART];     /* DOS view of disk */
                    130:        struct  dkbad   dk_bad; /* bad sector table */
1.1.1.4 ! root      131: #ifdef TIHBAD144
        !           132:        long    dk_badsect[127];        /* 126 plus trailing -1 marker */
        !           133: #endif
1.1       root      134: };
                    135: 
1.1.1.4 ! root      136: #ifdef TIHBAD144
        !           137: void bad144intern(struct disk *);
        !           138: #endif
        !           139: void wddisksort();
        !           140: 
1.1.1.3   root      141: struct disk    *wddrives[NWD];         /* table of units */
1.1.1.4 ! root      142: struct buf     wdtab[NWDC];            /* various per-controller info */
1.1.1.3   root      143: struct buf     wdutab[NWD];            /* head of queue per drive */
                    144: struct buf     rwdbuf[NWD];            /* buffers for raw IO */
                    145: long   wdxfer[NWD];                    /* count of transfers */
1.1.1.4 ! root      146: 
        !           147: #ifdef WDOPENLOCK
        !           148: int wdopenbusy = 0;
1.1.1.3   root      149: #endif
1.1       root      150: 
1.1.1.4 ! root      151: int wdprobe(), wdattach();
        !           152: 
        !           153: struct isa_driver wdcdriver = {
        !           154:        wdprobe, wdattach, "wdc",
1.1       root      155: };
1.1.1.3   root      156: 
                    157: void wdustart(struct disk *);
1.1.1.4 ! root      158: void wdstart(int);
1.1.1.3   root      159: int wdcommand(struct disk *, int);
                    160: int wdcontrol(struct buf *);
                    161: int wdsetctlr(dev_t, struct disk *);
                    162: int wdgetctlr(int, struct disk *);
                    163: 
1.1       root      164: /*
1.1.1.3   root      165:  * Probe for controller.
1.1       root      166:  */
1.1.1.3   root      167: int
                    168: wdprobe(struct isa_device *dvp)
1.1       root      169: {
1.1.1.3   root      170:        struct disk *du;
                    171:        int wdc;
1.1       root      172: 
1.1.1.4 ! root      173: #ifdef WDOPENLOCK
        !           174:        wdopenbusy = 0;
        !           175: #endif
        !           176: 
        !           177:        if (dvp->id_unit >= NWDC)
1.1.1.3   root      178:                return(0);
                    179: 
1.1.1.4 ! root      180:        du = (struct disk *) malloc (sizeof(struct disk), M_TEMP, M_NOWAIT);
        !           181:        bzero(du, sizeof(struct disk));
        !           182: 
        !           183:        du->dk_ctrlr = dvp->id_unit;
        !           184:        du->dk_unit = 0;
        !           185:        du->dk_lunit = 0;
1.1.1.3   root      186: 
                    187:        wdc = du->dk_port = dvp->id_iobase;
1.1.1.4 ! root      188: 
1.1.1.3   root      189:        /* check if we have registers that work */
1.1.1.4 ! root      190:        outb(wdc+wd_error, 0x5a);       /* error register not writable */
        !           191:        outb(wdc+wd_cyl_lo, 0xa5);      /* but all of cyllo are implemented */
1.1.1.3   root      192:        if(inb(wdc+wd_error) == 0x5a || inb(wdc+wd_cyl_lo) != 0xa5)
                    193:                goto nodevice;
                    194: 
                    195:        /* reset the device */
                    196:        outb(wdc+wd_ctlr, (WDCTL_RST|WDCTL_IDS));
                    197:        DELAY(1000);
                    198:        outb(wdc+wd_ctlr, WDCTL_IDS);
                    199:        DELAY(1000);
                    200: 
                    201:        /* execute a controller only command */
                    202:        if (wdcommand(du, WDCC_DIAGNOSE) < 0)
                    203:                goto nodevice;
                    204: 
                    205:        (void) inb(wdc+wd_error);       /* XXX! */
                    206:        outb(wdc+wd_ctlr, WDCTL_4BIT);
1.1.1.4 ! root      207:        DELAY(1000);
        !           208:     
        !           209:        bzero(&wdtab[du->dk_ctrlr], sizeof(struct buf));
        !           210: 
        !           211:        free(du, M_TEMP);
        !           212:        return (8);
1.1.1.3   root      213: 
                    214: nodevice:
                    215:        free(du, M_TEMP);
1.1       root      216:        return (0);
                    217: }
                    218: 
                    219: /*
1.1.1.3   root      220:  * Attach each drive if possible.
1.1       root      221:  */
1.1.1.3   root      222: int
                    223: wdattach(struct isa_device *dvp)
1.1       root      224: {
1.1.1.4 ! root      225:        int unit, lunit;
        !           226:        extern struct isa_device isa_biotab_wdc[];
        !           227:        struct isa_device *wdup;
        !           228:        struct disk *du;
        !           229:        int first = 0;
1.1       root      230: 
1.1.1.4 ! root      231:        if (dvp->id_unit >= NWDC)
        !           232:                return(0);
        !           233:     
        !           234:        for (wdup = isa_biotab_wdc; wdup->id_driver != 0; wdup++) {
        !           235:                if (wdup->id_iobase != dvp->id_iobase)
        !           236:                        continue;
        !           237:                lunit = wdup->id_unit;
        !           238:                if (lunit >= NWD)
        !           239:                        continue;
        !           240:                unit = wdup->id_physid;
        !           241:        
        !           242:                du = wddrives[lunit] = (struct disk *)
        !           243:                        malloc(sizeof(struct disk), M_TEMP, M_NOWAIT);
        !           244:                bzero(du, sizeof(struct disk));
        !           245:                bzero(&wdutab[lunit], sizeof(struct buf));
        !           246:                bzero(&rwdbuf[lunit], sizeof(struct buf));
        !           247:                wdxfer[lunit] = 0;
        !           248: 
        !           249:                du->dk_ctrlr = dvp->id_unit;
        !           250:                du->dk_unit = unit;
        !           251:                du->dk_lunit = lunit;
        !           252:                du->dk_port = dvp->id_iobase;
        !           253: 
        !           254:                if(wdgetctlr(unit, du) == 0)  {
        !           255:                        int i, blank;
        !           256:                        if(first==0) {
        !           257:                                first = 1;
        !           258:                                printf("wdc%d: <", dvp->id_unit);
        !           259: 
        !           260:                                for (i=blank=0; i<sizeof(du->dk_params.wdp_model); i++) {
        !           261:                                        char c = du->dk_params.wdp_model[i];
        !           262:                                        if (blank && c == ' ')
        !           263:                                                continue;
        !           264:                                        if (blank && c != ' ') {
        !           265:                                                printf(" %c", c);
        !           266:                                                blank = 0;
        !           267:                                                continue;
        !           268:                                        } 
        !           269:                                        if (c == ' ')
        !           270:                                                blank = 1;
        !           271:                                        else
        !           272:                                                printf("%c", c);
        !           273:                                }
        !           274:                                printf(">\n");
        !           275:                        }
        !           276:                        printf("wd%d at wdc%d slave %d\n", lunit, dvp->id_unit, unit);
        !           277:                } else {
        !           278:                        /*printf("wd%d at wdc%d slave %d -- error\n",
        !           279:                                lunit, dvp->id_unit, unit);*/
        !           280:                        wddrives[lunit] = 0;
        !           281:                        free(du, M_TEMP);
1.1.1.3   root      282:                }
                    283:        }
                    284:        return(1);
1.1       root      285: }
                    286: 
                    287: /* Read/write routine for a buffer.  Finds the proper unit, range checks
                    288:  * arguments, and schedules the transfer.  Does not wait for the transfer
                    289:  * to complete.  Multi-page transfers are supported.  All I/O requests must
                    290:  * be a multiple of a sector in length.
                    291:  */
1.1.1.3   root      292: int
                    293: wdstrategy(register struct buf *bp)
1.1       root      294: {
                    295:        register struct buf *dp;
1.1.1.3   root      296:        struct disk *du;        /* Disk unit to do the IO.      */
1.1.1.4 ! root      297:        int     lunit = wdunit(bp->b_dev);
1.1       root      298:        int     s;
1.1.1.4 ! root      299:     
1.1.1.3   root      300:        /* valid unit, controller, and request?  */
1.1.1.4 ! root      301:        if (lunit >= NWD || bp->b_blkno < 0 ||
        !           302:            howmany(bp->b_bcount, DEV_BSIZE) >= (1<<NBBY) ||
        !           303:            (du = wddrives[lunit]) == 0) {
1.1.1.3   root      304:                bp->b_error = EINVAL;
1.1       root      305:                bp->b_flags |= B_ERROR;
1.1.1.3   root      306:                goto done;
1.1       root      307:        }
1.1.1.4 ! root      308:     
1.1.1.3   root      309:        /* "soft" write protect check */
                    310:        if ((du->dk_flags & DKFL_WRITEPROT) && (bp->b_flags & B_READ) == 0) {
                    311:                bp->b_error = EROFS;
1.1       root      312:                bp->b_flags |= B_ERROR;
1.1.1.3   root      313:                goto done;
1.1       root      314:        }
1.1.1.4 ! root      315:     
1.1.1.3   root      316:        /* have partitions and want to use them? */
                    317:        if ((du->dk_flags & DKFL_BSDLABEL) != 0 && wdpart(bp->b_dev) != WDRAW) {
                    318:                /*
                    319:                 * do bounds checking, adjust transfer. if error, process.
                    320:                 * if end of partition, just return
                    321:                 */
                    322:                if (bounds_check_with_label(bp, &du->dk_dd, du->dk_wlabel) <= 0)
                    323:                        goto done;
                    324:                /* otherwise, process transfer request */
1.1       root      325:        }
1.1.1.4 ! root      326:     
1.1.1.3   root      327:        /* queue transfer on drive, activate drive and controller if idle */
1.1.1.4 ! root      328:        dp = &wdutab[lunit];
1.1.1.3   root      329:        s = splbio();
1.1.1.4 ! root      330:        wddisksort(dp, bp);
1.1       root      331:        if (dp->b_active == 0)
1.1.1.3   root      332:                wdustart(du);           /* start drive */
1.1.1.4 ! root      333:        if (wdtab[du->dk_ctrlr].b_active == 0)
        !           334:                wdstart(du->dk_ctrlr);          /* start controller */
1.1       root      335:        splx(s);
1.1.1.4 ! root      336:        return 0;
        !           337:     
1.1.1.3   root      338: done:
                    339:        /* toss transfer, we're done early */
1.1       root      340:        biodone(bp);
1.1.1.4 ! root      341:        return 0;
1.1       root      342: }
                    343: 
1.1.1.3   root      344: /*
                    345:  * Routine to queue a command to the controller.  The unit's
                    346:  * request is linked into the active list for the controller.
                    347:  * If the controller is idle, the transfer is started.
1.1       root      348:  */
1.1.1.3   root      349: static void
                    350: wdustart(register struct disk *du)
1.1       root      351: {
1.1.1.4 ! root      352:        register struct buf *bp, *dp = &wdutab[du->dk_lunit];
        !           353:        int ctrlr = du->dk_ctrlr;
        !           354:     
1.1.1.3   root      355:        /* unit already active? */
1.1       root      356:        if (dp->b_active)
                    357:                return;
1.1.1.4 ! root      358:     
1.1.1.3   root      359:        /* anything to start? */
1.1       root      360:        bp = dp->b_actf;
                    361:        if (bp == NULL)
                    362:                return; 
1.1.1.4 ! root      363:     
1.1.1.3   root      364:        /* link onto controller queue */
1.1       root      365:        dp->b_forw = NULL;
1.1.1.4 ! root      366:        if (wdtab[ctrlr].b_actf  == NULL)
        !           367:                wdtab[ctrlr].b_actf = dp;
1.1       root      368:        else
1.1.1.4 ! root      369:                wdtab[ctrlr].b_actl->b_forw = dp;
        !           370:        wdtab[ctrlr].b_actl = dp;
        !           371:     
1.1.1.3   root      372:        /* mark the drive unit as busy */
                    373:        dp->b_active = 1;
1.1       root      374: }
                    375: 
                    376: /*
                    377:  * Controller startup routine.  This does the calculation, and starts
                    378:  * a single-sector read or write operation.  Called to start a transfer,
                    379:  * or from the interrupt routine to continue a multi-sector transfer.
                    380:  * RESTRICTIONS:
                    381:  * 1.  The transfer length must be an exact multiple of the sector size.
                    382:  */
1.1.1.3   root      383: static void
1.1.1.4 ! root      384: wdstart(int ctrlr)
1.1       root      385: {
                    386:        register struct disk *du;       /* disk unit for IO */
                    387:        register struct buf *bp;
1.1.1.3   root      388:        struct disklabel *lp;
1.1       root      389:        struct buf *dp;
1.1.1.4 ! root      390:        long    blknum, cylin, head, sector;
        !           391:        long    secpertrk, secpercyl, addr;
        !           392:        int     lunit, wdc;
        !           393:        int xfrblknum;
        !           394:        unsigned char status;
        !           395:     
1.1       root      396: loop:
1.1.1.3   root      397:        /* is there a drive for the controller to do a transfer with? */
1.1.1.4 ! root      398:        dp = wdtab[ctrlr].b_actf;
1.1       root      399:        if (dp == NULL)
                    400:                return;
1.1.1.4 ! root      401:     
1.1.1.3   root      402:        /* is there a transfer to this drive ? if so, link it on
                    403:           the controller's queue */
1.1       root      404:        bp = dp->b_actf;
                    405:        if (bp == NULL) {
1.1.1.4 ! root      406:                wdtab[ctrlr].b_actf = dp->b_forw;
1.1       root      407:                goto loop;
                    408:        }
1.1.1.4 ! root      409:     
1.1.1.3   root      410:        /* obtain controller and drive information */
1.1.1.4 ! root      411:        lunit = wdunit(bp->b_dev);
        !           412:        du = wddrives[lunit];
        !           413:     
1.1.1.3   root      414:        /* if not really a transfer, do control operations specially */
                    415:        if (du->dk_state < OPEN) {
                    416:                (void) wdcontrol(bp);
1.1       root      417:                return;
                    418:        }
1.1.1.4 ! root      419:     
1.1.1.3   root      420:        /* calculate transfer details */
                    421:        blknum = bp->b_blkno + du->dk_skip;
1.1       root      422: #ifdef WDDEBUG
1.1.1.3   root      423:        if (du->dk_skip == 0)
1.1.1.4 ! root      424:                printf("\nwdstart %d: %s %d@%d; map ", lunit,
1.1       root      425:                        (bp->b_flags & B_READ) ? "read" : "write",
                    426:                        bp->b_bcount, blknum);
1.1.1.3   root      427:        else
1.1.1.4 ! root      428:                printf(" %d)%x", du->dk_skip, inb(du->dk_port+wd_altsts));
1.1       root      429: #endif
                    430:        addr = (int) bp->b_un.b_addr;
1.1.1.4 ! root      431:        if (du->dk_skip == 0) {
1.1.1.3   root      432:                du->dk_bc = bp->b_bcount;
1.1.1.4 ! root      433:        }
        !           434:        if (du->dk_skipm == 0) {
        !           435:                struct buf *oldbp, *nextbp;
        !           436:                oldbp = bp;
        !           437:                nextbp = bp->av_forw;
        !           438:                du->dk_bct = du->dk_bc;
        !           439:                oldbp->b_flags |= B_XXX;
        !           440:                while( nextbp
        !           441:                    && (oldbp->b_flags & DKFL_SINGLE) == 0
        !           442:                    && oldbp->b_dev == nextbp->b_dev
        !           443:                    && nextbp->b_blkno == (oldbp->b_blkno + (oldbp->b_bcount/DEV_BSIZE))
        !           444:                    && (oldbp->b_flags & B_READ) == (nextbp->b_flags & B_READ)) {
        !           445:                        if( (du->dk_bct+nextbp->b_bcount)/DEV_BSIZE >= 240) {
        !           446:                                break;
        !           447:                        }
        !           448:                        du->dk_bct += nextbp->b_bcount; 
        !           449:                        oldbp->b_flags |= B_XXX;
        !           450:                        oldbp = nextbp;
        !           451:                        nextbp = nextbp->av_forw;
        !           452:                }
        !           453:        }
        !           454:     
1.1.1.3   root      455:        lp = &du->dk_dd;
                    456:        secpertrk = lp->d_nsectors;
                    457:        secpercyl = lp->d_secpercyl;
1.1.1.4 ! root      458:        if ((du->dk_flags & DKFL_BSDLABEL) != 0 && wdpart(bp->b_dev) != WDRAW)
        !           459:                blknum += lp->d_partitions[wdpart(bp->b_dev)].p_offset;
1.1       root      460:        cylin = blknum / secpercyl;
                    461:        head = (blknum % secpercyl) / secpertrk;
                    462:        sector = blknum % secpertrk;
1.1.1.4 ! root      463:     
        !           464: #ifdef TIHBAD144
        !           465:        /* Check for bad sectors if we have them, and not formatting */
        !           466:        /* Only do this in single-sector mode, or when starting a */
        !           467:        /* multiple-sector transfer. */
        !           468: #ifdef B_FORMAT
        !           469:        if ((du->dk_flags & DKFL_BADSECT) && !(bp->b_flags & B_FORMAT) &&
        !           470:                ((du->dk_skipm == 0) || (du->dk_flags & DKFL_SINGLE))) {
        !           471: #else
        !           472:        if ((du->dk_flags & DKFL_BADSECT) &&
        !           473:                ((du->dk_skipm == 0) || (du->dk_flags & DKFL_SINGLE))) {
1.1       root      474: #endif
1.1.1.4 ! root      475: 
        !           476:                long blkchk, blkend, blknew;
        !           477:                int i;
        !           478: 
        !           479:                blkend = blknum + howmany(du->dk_bct, DEV_BSIZE) - 1;
        !           480:                for (i = 0; (blkchk = du->dk_badsect[i]) != -1; i++) {
        !           481:                        if (blkchk > blkend) {
        !           482:                                break;  /* transfer is completely OK; done */
        !           483:                        } else if (blkchk == blknum) {
        !           484:                                blknew = lp->d_secperunit - lp->d_nsectors - i - 1;
        !           485:                                cylin = blknew / secpercyl;
        !           486:                                head = (blknew % secpercyl) / secpertrk;
        !           487:                                sector = blknew % secpertrk;
        !           488:                                du->dk_flags |= DKFL_SINGLE;
        !           489:                                /* found and replaced first blk of transfer; done */
        !           490:                                break;
        !           491:                        } else if (blkchk > blknum) {
        !           492:                                du->dk_flags |= DKFL_SINGLE;
        !           493:                                break;  /* bad block inside transfer; done */
        !           494:                        }
1.1       root      495:                }
                    496:        }
1.1.1.4 ! root      497: #endif
        !           498:        if( du->dk_flags & DKFL_SINGLE) {
        !           499:                du->dk_bct = du->dk_bc;
        !           500:                du->dk_skipm = du->dk_skip;
        !           501:        }
        !           502: 
        !           503: #ifdef WDDEBUG
        !           504:        pg("c%d h%d s%d ", cylin, head, sector);
        !           505: #endif
1.1       root      506: 
1.1.1.4 ! root      507:        sector += 1;    /* sectors begin with 1, not 0 */
        !           508:     
        !           509:        wdtab[ctrlr].b_active = 1;              /* mark controller active */
1.1.1.3   root      510:        wdc = du->dk_port;
1.1.1.4 ! root      511:     
        !           512: #ifdef INSTRUMENT
        !           513:        /* instrumentation */
        !           514:        if (du->dk_unit >= 0 && du->dk_skip == 0) {
        !           515:                dk_busy |= 1 << du->dk_lunit;
        !           516:                dk_wds[du->dk_lunit] += bp->b_bcount >> 6;
        !           517:        }
        !           518:        if (du->dk_unit >= 0 && du->dk_skipm == 0) {
        !           519:                ++dk_seek[du->dk_lunit];
        !           520:                ++dk_xfer[du->dk_lunit];
        !           521:        }
        !           522: #endif
1.1       root      523: 
1.1.1.3   root      524:        /* if starting a multisector transfer, or doing single transfers */
1.1.1.4 ! root      525:        if (du->dk_skipm == 0 || (du->dk_flags & DKFL_SINGLE)) {
        !           526:                if (wdtab[ctrlr].b_errcnt && (bp->b_flags & B_READ) == 0) {
1.1.1.3   root      527:                        du->dk_bc += DEV_BSIZE;
1.1.1.4 ! root      528:                        du->dk_bct += DEV_BSIZE;
        !           529:                }
1.1.1.3   root      530: 
                    531:                /* controller idle? */
                    532:                while (inb(wdc+wd_status) & WDCS_BUSY)
                    533:                        ;
1.1.1.4 ! root      534:        
1.1.1.3   root      535:                /* stuff the task file */
                    536:                outb(wdc+wd_precomp, lp->d_precompcyl / 4);
                    537: #ifdef B_FORMAT
                    538:                if (bp->b_flags & B_FORMAT) {
                    539:                        outb(wdc+wd_sector, lp->d_gap3);
                    540:                        outb(wdc+wd_seccnt, lp->d_nsectors);
                    541:                } else {
1.1.1.4 ! root      542:                        if (du->dk_flags & DKFL_SINGLE)
        !           543:                                outb(wdc+wd_seccnt, 1);
        !           544:                        else
        !           545:                                outb(wdc+wd_seccnt, howmany(du->dk_bct, DEV_BSIZE));
        !           546:                        outb(wdc+wd_sector, sector);
        !           547:                }
        !           548: #else
1.1.1.3   root      549:                if (du->dk_flags & DKFL_SINGLE)
                    550:                        outb(wdc+wd_seccnt, 1);
                    551:                else
1.1.1.4 ! root      552:                        outb(wdc+wd_seccnt, howmany(du->dk_bct, DEV_BSIZE));
1.1.1.3   root      553:                outb(wdc+wd_sector, sector);
                    554: #endif
                    555:                outb(wdc+wd_cyl_lo, cylin);
                    556:                outb(wdc+wd_cyl_hi, cylin >> 8);
1.1.1.4 ! root      557:        
1.1.1.3   root      558:                /* set up the SDH register (select drive) */
1.1.1.4 ! root      559:                outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit<<4) | (head & 0xf));
        !           560:        
1.1.1.3   root      561:                /* wait for drive to become ready */
                    562:                while ((inb(wdc+wd_status) & WDCS_READY) == 0)
                    563:                        ;
1.1.1.4 ! root      564:        
1.1.1.3   root      565:                /* initiate command! */
                    566: #ifdef B_FORMAT
                    567:                if (bp->b_flags & B_FORMAT)
                    568:                        outb(wdc+wd_command, WDCC_FORMAT);
                    569:                else
1.1.1.4 ! root      570:                        outb(wdc+wd_command,
        !           571:                                (bp->b_flags & B_READ)? WDCC_READ : WDCC_WRITE);
        !           572: #else
        !           573:                outb(wdc+wd_command, (bp->b_flags & B_READ)? WDCC_READ : WDCC_WRITE);
1.1.1.3   root      574: #endif
                    575: #ifdef WDDEBUG
                    576:                printf("sector %d cylin %d head %d addr %x sts %x\n",
1.1.1.4 ! root      577:                        sector, cylin, head, addr, inb(wdc+wd_altsts));
1.1.1.3   root      578: #endif
                    579:        }
1.1.1.4 ! root      580:     
1.1.1.3   root      581:        /* if this is a read operation, just go away until it's done.   */
1.1.1.4 ! root      582:        if (bp->b_flags & B_READ)
        !           583:                return;
        !           584:     
1.1.1.3   root      585:        /* ready to send data?  */
1.1.1.4 ! root      586:        while ((inb(wdc+wd_altsts) & WDCS_DRQ) == 0)
1.1.1.3   root      587:                ;
1.1.1.4 ! root      588:     
1.1.1.3   root      589:        /* then send it! */
1.1.1.4 ! root      590: outagain:
1.1.1.3   root      591:        outsw (wdc+wd_data, addr+du->dk_skip * DEV_BSIZE,
                    592:                DEV_BSIZE/sizeof(short));
                    593:        du->dk_bc -= DEV_BSIZE;
1.1.1.4 ! root      594:        du->dk_bct -= DEV_BSIZE;
1.1       root      595: }
                    596: 
                    597: /* Interrupt routine for the controller.  Acknowledge the interrupt, check for
                    598:  * errors on the current operation, mark it done if necessary, and start
                    599:  * the next request.  Also check for a partially done transfer, and
                    600:  * continue with the next chunk if so.
                    601:  */
1.1.1.3   root      602: void
                    603: wdintr(struct intrframe wdif)
1.1       root      604: {
                    605:        register struct disk *du;
                    606:        register struct buf *bp, *dp;
1.1.1.4 ! root      607:        int status, wdc, ctrlr;
        !           608:     
        !           609:        ctrlr = wdif.if_vec;
1.1       root      610: 
1.1.1.4 ! root      611:        if (!wdtab[ctrlr].b_active) {
        !           612:                printf("wdc%d: extra interrupt\n", ctrlr);
1.1       root      613:                return;
                    614:        }
1.1.1.4 ! root      615:     
        !           616:        dp = wdtab[ctrlr].b_actf;
1.1       root      617:        bp = dp->b_actf;
1.1.1.3   root      618:        du = wddrives[wdunit(bp->b_dev)];
                    619:        wdc = du->dk_port;
1.1.1.4 ! root      620:     
1.1.1.3   root      621: #ifdef WDDEBUG
1.1.1.4 ! root      622:        printf("I%d ", ctrlr);
1.1.1.3   root      623: #endif
1.1.1.4 ! root      624:     
        !           625:        while ((status = inb(wdc+wd_status)) & WDCS_BUSY)
        !           626:                ;
        !           627:     
1.1.1.3   root      628:        /* is it not a transfer, but a control operation? */
                    629:        if (du->dk_state < OPEN) {
1.1       root      630:                if (wdcontrol(bp))
1.1.1.4 ! root      631:                        wdstart(ctrlr);
1.1       root      632:                return;
                    633:        }
1.1.1.4 ! root      634:     
1.1.1.3   root      635:        /* have we an error? */
1.1       root      636:        if (status & (WDCS_ERR | WDCS_ECCCOR)) {
1.1.1.3   root      637:                du->dk_status = status;
                    638:                du->dk_error = inb(wdc + wd_error);
1.1       root      639: #ifdef WDDEBUG
1.1.1.3   root      640:                printf("status %x error %x\n", status, du->dk_error);
1.1       root      641: #endif
1.1.1.3   root      642:                if((du->dk_flags & DKFL_SINGLE) == 0) {
                    643:                        du->dk_flags |=  DKFL_ERROR;
1.1       root      644:                        goto outt;
                    645:                }
1.1.1.3   root      646: #ifdef B_FORMAT
                    647:                if (bp->b_flags & B_FORMAT) {
1.1       root      648:                        bp->b_flags |= B_ERROR;
                    649:                        goto done;
1.1.1.3   root      650:                }
                    651: #endif
1.1.1.4 ! root      652:        
1.1.1.3   root      653:                /* error or error correction? */
1.1       root      654:                if (status & WDCS_ERR) {
1.1.1.4 ! root      655:                        if (++wdtab[ctrlr].b_errcnt < RETRIES) {
        !           656:                                wdtab[ctrlr].b_active = 0;
1.1       root      657:                        } else {
1.1.1.4 ! root      658:                                if((du->dk_flags & DKFL_QUIET) == 0) {
1.1.1.3   root      659:                                        diskerr(bp, "wd", "hard error",
                    660:                                                LOG_PRINTF, du->dk_skip,
                    661:                                                &du->dk_dd);
                    662: #ifdef WDDEBUG
                    663:                                        printf( "status %b error %b\n",
                    664:                                                status, WDCS_BITS,
                    665:                                                inb(wdc+wd_error), WDERR_BITS);
                    666: #endif
                    667:                                }
1.1       root      668:                                bp->b_flags |= B_ERROR; /* flag the error */
                    669:                        }
1.1.1.4 ! root      670:                } else if((du->dk_flags & DKFL_QUIET) == 0) {
        !           671:                        diskerr(bp, "wd", "soft ecc", 0,
        !           672:                                du->dk_skip, &du->dk_dd);
1.1.1.3   root      673:                }
1.1       root      674:        }
                    675: outt:
1.1.1.4 ! root      676:     
1.1       root      677:        /*
                    678:         * If this was a successful read operation, fetch the data.
                    679:         */
1.1.1.4 ! root      680:        if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) && wdtab[ctrlr].b_active) {
1.1       root      681:                int chk, dummy;
1.1.1.4 ! root      682:        
1.1.1.3   root      683:                chk = min(DEV_BSIZE / sizeof(short), du->dk_bc / sizeof(short));
1.1.1.4 ! root      684:        
1.1.1.3   root      685:                /* ready to receive data? */
                    686:                while ((inb(wdc+wd_status) & WDCS_DRQ) == 0)
                    687:                        ;
1.1.1.4 ! root      688:        
1.1.1.3   root      689:                /* suck in data */
                    690:                insw (wdc+wd_data,
                    691:                        (int)bp->b_un.b_addr + du->dk_skip * DEV_BSIZE, chk);
                    692:                du->dk_bc -= chk * sizeof(short);
1.1.1.4 ! root      693:                du->dk_bct -= chk * sizeof(short);
        !           694:        
1.1.1.3   root      695:                /* for obselete fractional sector reads */
1.1.1.4 ! root      696:                while (chk++ < (DEV_BSIZE / sizeof(short)))
        !           697:                        insw(wdc+wd_data, &dummy, 1);
1.1       root      698:        }
1.1.1.4 ! root      699:     
        !           700:        wdxfer[du->dk_lunit]++;
        !           701:        if (wdtab[ctrlr].b_active) {
        !           702: #ifdef INSTRUMENT
        !           703:                if (du->dk_unit >= 0)
        !           704:                        dk_busy &=~ (1 << du->dk_unit);
        !           705: #endif
1.1       root      706:                if ((bp->b_flags & B_ERROR) == 0) {
1.1.1.4 ! root      707:                        du->dk_skip++;          /* Add to succ. sect */
        !           708:                        du->dk_skipm++;         /* Add to succ. sect for multitransfer */
        !           709:                        if (wdtab[ctrlr].b_errcnt && (du->dk_flags & DKFL_QUIET) == 0)
1.1.1.3   root      710:                                diskerr(bp, "wd", "soft error", 0,
                    711:                                        du->dk_skip, &du->dk_dd);
1.1.1.4 ! root      712:                        wdtab[ctrlr].b_errcnt = 0;
        !           713:            
1.1       root      714:                        /* see if more to transfer */
1.1.1.3   root      715:                        if (du->dk_bc > 0 && (du->dk_flags & DKFL_ERROR) == 0) {
1.1.1.4 ! root      716:                                if( (du->dk_flags & DKFL_SINGLE)
        !           717:                                    || (du->dk_flags & B_READ) == 0)
        !           718:                                        wdstart(ctrlr);
        !           719:                                        return;         /* next chunk is started */
        !           720:                        } else if ((du->dk_flags & (DKFL_SINGLE|DKFL_ERROR)) == DKFL_ERROR) {
1.1       root      721:                                du->dk_skip = 0;
1.1.1.4 ! root      722:                                du->dk_skipm = 0;
1.1.1.3   root      723:                                du->dk_flags &= ~DKFL_ERROR;
                    724:                                du->dk_flags |=  DKFL_SINGLE;
1.1.1.4 ! root      725:                                wdstart(ctrlr);
1.1       root      726:                                return;         /* redo xfer sector by sector */
                    727:                        }
                    728:                }
                    729: 
                    730: done:
                    731:                /* done with this transfer, with or without error */
1.1.1.3   root      732:                du->dk_flags &= ~DKFL_SINGLE;
1.1.1.4 ! root      733:                wdtab[ctrlr].b_errcnt = 0;
1.1       root      734:                du->dk_skip = 0;
1.1.1.4 ! root      735:                if( du->dk_bct == 0) {
        !           736:                        wdtab[ctrlr].b_actf = dp->b_forw;
        !           737:                        du->dk_skipm = 0;
        !           738:                        dp->b_active = 0;
        !           739:                }
1.1       root      740:                dp->b_actf = bp->av_forw;
                    741:                dp->b_errcnt = 0;
                    742:                bp->b_resid = 0;
1.1.1.4 ! root      743:                bp->b_flags &= ~B_XXX;
1.1       root      744:                biodone(bp);
                    745:        }
1.1.1.4 ! root      746:     
1.1.1.3   root      747:        /* anything more on drive queue? */
1.1.1.4 ! root      748:        if (dp->b_actf && du->dk_bct == 0)
1.1.1.3   root      749:                wdustart(du);
1.1.1.4 ! root      750: 
1.1.1.3   root      751:        /* anything more for controller to do? */
1.1.1.4 ! root      752:        if (wdtab[ctrlr].b_actf)
        !           753:                wdstart(ctrlr);
        !           754: 
        !           755:        if (!wdtab[ctrlr].b_actf)
        !           756:                wdtab[ctrlr].b_active = 0;
1.1       root      757: }
                    758: 
                    759: /*
                    760:  * Initialize a drive.
                    761:  */
1.1.1.3   root      762: int
                    763: wdopen(dev_t dev, int flags, int fmt, struct proc *p)
1.1       root      764: {
1.1.1.4 ! root      765:        register unsigned int lunit;
1.1       root      766:        register struct disk *du;
1.1.1.4 ! root      767:        int part = wdpart(dev), mask = 1 << part;
        !           768:        struct partition *pp;
        !           769:        int error = 0;
1.1.1.3   root      770:        char *msg;
1.1.1.4 ! root      771:     
        !           772:        lunit = wdunit(dev);
        !           773:        if (lunit >= NWD)
        !           774:                return (ENXIO);
        !           775:     
        !           776:        du = wddrives[lunit];
        !           777: 
        !           778:        if (du == 0)
        !           779:                return (ENXIO);
        !           780:     
        !           781: #ifdef WDOPENLOCK
        !           782:        printf("[Enter wd%d%c]\n", lunit, part+'a');
        !           783:        if (wdopenbusy) {
        !           784:                printf("[Sleep wd%d%c]\n", lunit, part+'a');
        !           785:                while (wdopenbusy)
        !           786:                        ;
        !           787:        }
        !           788:        printf("[Lock  wd%d%c]\n", lunit, part+'a');
        !           789:        wdopenbusy = 1;
        !           790: #endif
1.1       root      791: 
1.1.1.4 ! root      792: #ifdef QUIETWORKS
        !           793:        if (part == WDRAW)
        !           794:                du->dk_flags |= DKFL_QUIET;
        !           795:        else
        !           796:                du->dk_flags &= ~DKFL_QUIET;
        !           797: #else
        !           798:        du->dk_flags &= ~DKFL_QUIET;
        !           799: #endif
        !           800:        
1.1.1.3   root      801:        if ((du->dk_flags & DKFL_BSDLABEL) == 0) {
                    802:                du->dk_flags |= DKFL_WRITEPROT;
1.1.1.4 ! root      803: #ifdef WDOPENLOCK
        !           804:                printf("[Init  wd%d%c]\n", lunit, part+'a');
        !           805: #endif
        !           806:                wdutab[lunit].b_actf = NULL;
1.1.1.3   root      807: 
                    808:                /*
                    809:                 * Use the default sizes until we've read the label,
                    810:                 * or longer if there isn't one there.
                    811:                 */
                    812:                bzero(&du->dk_dd, sizeof(du->dk_dd));
                    813: #undef d_type /* fix goddamn segments.h! XXX */
                    814:                du->dk_dd.d_type = DTYPE_ST506;
                    815:                du->dk_dd.d_ncylinders = 1024;
                    816:                du->dk_dd.d_secsize = DEV_BSIZE;
                    817:                du->dk_dd.d_ntracks = 8;
                    818:                du->dk_dd.d_nsectors = 17;
                    819:                du->dk_dd.d_secpercyl = 17*8;
1.1.1.4 ! root      820:                du->dk_dd.d_secperunit = 17*8*1024;
1.1.1.3   root      821:                du->dk_state = WANTOPEN;
                    822: 
1.1.1.4 ! root      823:                /* read label using "raw" partition */
        !           824: #if defined(TIHMODS) && defined(garbage)
        !           825:                /* wdsetctlr(dev, du); */       /* Maybe do this TIH */
        !           826:                msg = readdisklabel(makewddev(major(dev), wdunit(dev), WDRAW),
        !           827:                        wdstrategy, &du->dk_dd, du->dk_dospartitions,
        !           828:                        0, 0);
        !           829:                wdsetctlr(dev, du);
        !           830:                msg = readdisklabel(makewddev(major(dev), wdunit(dev), WDRAW),
        !           831:                        wdstrategy, &du->dk_dd, du->dk_dospartitions,
        !           832:                        &du->dk_bad, 0);
        !           833:                if (msg) {
        !           834: #ifdef QUIETWORKS
        !           835:                        if((du->dk_flags & DKFL_QUIET) == 0) {
        !           836:                                log(LOG_WARNING, "wd%d: cannot find label (%s)\n",
        !           837:                                        lunit, msg);
        !           838:                                error = EINVAL;         /* XXX needs translation */
        !           839:                        }
        !           840: #else
        !           841:                        log(LOG_WARNING, "wd%d: cannot find label (%s)\n", lunit, msg);
        !           842:                        if(part != WDRAW) {
        !           843:                                error = EINVAL;         /* XXX needs translation */
        !           844:                        }
        !           845: #endif
        !           846:                        goto done;
        !           847:                } else {
        !           848:                        wdsetctlr(dev, du);
        !           849:                        du->dk_flags |= DKFL_BSDLABEL;
        !           850:                du->dk_flags &= ~DKFL_WRITEPROT;
        !           851:                if (du->dk_dd.d_flags & D_BADSECT)
        !           852:                        du->dk_flags |= DKFL_BADSECT;
        !           853:                }
        !           854: #else
1.1.1.3   root      855:                if (msg = readdisklabel(makewddev(major(dev), wdunit(dev), WDRAW),
1.1.1.4 ! root      856:                    wdstrategy, &du->dk_dd, du->dk_dospartitions,
        !           857:                    &du->dk_bad, 0)) {
        !           858:                        if((du->dk_flags & DKFL_QUIET) == 0) {
1.1.1.3   root      859:                                log(LOG_WARNING, "wd%d: cannot find label (%s)\n",
1.1.1.4 ! root      860:                                        lunit, msg);
1.1.1.3   root      861:                                error = EINVAL;         /* XXX needs translation */
                    862:                        }
                    863:                        goto done;
                    864:                } else {
                    865:                        wdsetctlr(dev, du);
                    866:                        du->dk_flags |= DKFL_BSDLABEL;
                    867:                        du->dk_flags &= ~DKFL_WRITEPROT;
                    868:                        if (du->dk_dd.d_flags & D_BADSECT)
                    869:                                du->dk_flags |= DKFL_BADSECT;
                    870:                }
1.1.1.4 ! root      871: #endif
1.1.1.3   root      872: 
1.1       root      873: done:
1.1.1.4 ! root      874:                if (error) {
        !           875: #ifdef WDOPENLOCK
        !           876:                        printf("[Error wd%d%c]\n", lunit, part+'a');
        !           877:                        wdopenbusy = 0;
        !           878: #endif
1.1.1.3   root      879:                        return(error);
1.1.1.4 ! root      880:                }
1.1.1.3   root      881:        }
1.1       root      882: 
1.1.1.4 ! root      883: #ifdef TIHBAD144
        !           884:        if (du->dk_flags & DKFL_BADSECT)
        !           885:                bad144intern(du);
        !           886: #endif
1.1.1.3   root      887: 
1.1.1.4 ! root      888:        /*
        !           889:         * Warn if a partion is opened
        !           890:         * that overlaps another partition which is open
        !           891:         * unless one is the "raw" partition (whole disk).
        !           892:         */
        !           893:        if ((du->dk_openpart & mask) == 0 /*&& part != RAWPART*/ && part != WDRAW) {
        !           894:                int     start, end;
        !           895:        
        !           896:                pp = &du->dk_dd.d_partitions[part];
        !           897:                start = pp->p_offset;
        !           898:                end = pp->p_offset + pp->p_size;
        !           899:                for (pp = du->dk_dd.d_partitions;
        !           900:                    pp < &du->dk_dd.d_partitions[du->dk_dd.d_npartitions]; pp++) {
        !           901:                        if (pp->p_offset + pp->p_size <= start || pp->p_offset >= end)
        !           902:                                continue;
        !           903:                        /*if (pp - du->dk_dd.d_partitions == RAWPART)
        !           904:                                continue; */
        !           905:                        if (pp - du->dk_dd.d_partitions == WDRAW)
        !           906:                                continue;
        !           907:                        if (du->dk_openpart & (1 << (pp - du->dk_dd.d_partitions)))
        !           908:                                log(LOG_WARNING,
        !           909:                                        "wd%d%c: overlaps open partition (%c)\n",
        !           910:                                        lunit, part + 'a',
        !           911:                                        pp - du->dk_dd.d_partitions + 'a');
        !           912:                }
        !           913:        }
        !           914: 
        !           915:        if (part >= du->dk_dd.d_npartitions && part != WDRAW) {
        !           916: #ifdef WDOPENLOCK
        !           917:                printf("[ENXIO wd%d%c]\n", lunit, part+'a');
        !           918:                wdopenbusy = 0;
        !           919: #endif
        !           920:                return (ENXIO);
        !           921:        }
        !           922:     
1.1.1.3   root      923:        /* insure only one open at a time */
1.1.1.4 ! root      924:        du->dk_openpart |= mask;
        !           925:        switch (fmt) {
        !           926:        case S_IFCHR:
        !           927:                du->dk_copenpart |= mask;
        !           928:                break;
        !           929:        case S_IFBLK:
        !           930:                du->dk_bopenpart |= mask;
        !           931:                break;
        !           932:        }
        !           933: #ifdef WDOPENLOCK
        !           934:        printf("[Done  wd%d%c]\n", lunit, part+'a');
        !           935:        wdopenbusy = 0;
        !           936: #endif
1.1.1.3   root      937:        return (0);
1.1       root      938: }
                    939: 
                    940: /*
                    941:  * Implement operations other than read/write.
                    942:  * Called from wdstart or wdintr during opens and formats.
                    943:  * Uses finite-state-machine to track progress of operation in progress.
                    944:  * Returns 0 if operation still in progress, 1 if completed.
                    945:  */
1.1.1.3   root      946: static int
                    947: wdcontrol(register struct buf *bp)
1.1       root      948: {
                    949:        register struct disk *du;
1.1.1.4 ! root      950:        register unit, lunit;
1.1       root      951:        unsigned char  stat;
1.1.1.4 ! root      952:        int s, ctrlr;
        !           953:        int wdc;
        !           954:     
1.1.1.3   root      955:        du = wddrives[wdunit(bp->b_dev)];
1.1.1.4 ! root      956:        ctrlr = du->dk_ctrlr;
1.1       root      957:        unit = du->dk_unit;
1.1.1.4 ! root      958:        lunit = du->dk_lunit;
1.1.1.3   root      959:        wdc = du->dk_port;
1.1.1.4 ! root      960:     
1.1.1.3   root      961:        switch (du->dk_state) {
1.1.1.4 ! root      962: tryagainrecal:
1.1       root      963:        case WANTOPEN:                  /* set SDH, step rate, do restore */
                    964: #ifdef WDDEBUG
1.1.1.4 ! root      965:                printf("wd%d: recal ", lunit);
1.1       root      966: #endif
                    967:                s = splbio();           /* not called from intr level ... */
1.1.1.3   root      968:                wdgetctlr(unit, du);
1.1.1.4 ! root      969: #ifdef TIPCAT
        !           970:                while ((inb(wdc+wd_status) & WDCS_READY) == 0)
        !           971:                        ;
        !           972: #endif
1.1       root      973:                outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
1.1.1.4 ! root      974:                wdtab[ctrlr].b_active = 1;
1.1       root      975:                outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
1.1.1.4 ! root      976: #ifdef TIPCAT
        !           977:                while ((inb(wdc+wd_status) & WDCS_READY) == 0)
        !           978:                        ;
        !           979: #endif
        !           980:                du->dk_state = RECAL;
1.1       root      981:                splx(s);
                    982:                return(0);
                    983:        case RECAL:
                    984:                if ((stat = inb(wdc+wd_status)) & WDCS_ERR) {
1.1.1.3   root      985:                        if ((du->dk_flags & DKFL_QUIET) == 0) {
1.1.1.4 ! root      986:                                printf("wd%d: recal", du->dk_lunit);
1.1       root      987:                                printf(": status %b error %b\n",
1.1.1.4 ! root      988:                                       stat, WDCS_BITS, inb(wdc+wd_error),
        !           989:                                       WDERR_BITS);
1.1       root      990:                        }
1.1.1.4 ! root      991:                        if (++wdtab[ctrlr].b_errcnt < RETRIES)
1.1.1.3   root      992:                                goto tryagainrecal;
                    993:                        bp->b_error = ENXIO;    /* XXX needs translation */
1.1       root      994:                        goto badopen;
                    995:                }
                    996: 
1.1.1.3   root      997:                /* some controllers require this ... */
1.1       root      998:                wdsetctlr(bp->b_dev, du);
1.1.1.4 ! root      999:        
        !          1000:                wdtab[ctrlr].b_errcnt = 0;
1.1.1.3   root     1001:                du->dk_state = OPEN;
1.1       root     1002:                /*
                   1003:                 * The rest of the initialization can be done
                   1004:                 * by normal means.
                   1005:                 */
                   1006:                return(1);
                   1007:        default:
                   1008:                panic("wdcontrol");
                   1009:        }
                   1010:        /* NOTREACHED */
                   1011: 
                   1012: badopen:
1.1.1.3   root     1013:        if ((du->dk_flags & DKFL_QUIET) == 0) 
                   1014:                printf(": status %b error %b\n",
                   1015:                        stat, WDCS_BITS, inb(wdc + wd_error), WDERR_BITS);
                   1016:        bp->b_flags |= B_ERROR;
1.1       root     1017:        return(1);
                   1018: }
                   1019: 
1.1.1.3   root     1020: /*
                   1021:  * send a command and wait uninterruptibly until controller is finished.
                   1022:  * return -1 if controller busy for too long, otherwise
                   1023:  * return status. intended for brief controller commands at critical points.
                   1024:  * assumes interrupts are blocked.
                   1025:  */
                   1026: static int
1.1.1.4 ! root     1027: wdcommand(struct disk *du, int cmd)
        !          1028: {
        !          1029:        int timeout = 5000000, stat, wdc;
        !          1030:     
        !          1031:        DELAY(2000);
1.1.1.3   root     1032:        /* controller ready for command? */
                   1033:        wdc = du->dk_port;
                   1034:        while (((stat = inb(wdc + wd_status)) & WDCS_BUSY) && timeout > 0)
                   1035:                timeout--;
                   1036:        if (timeout <= 0)
                   1037:                return(-1);
1.1.1.4 ! root     1038:     
1.1.1.3   root     1039:        /* send command, await results */
                   1040:        outb(wdc+wd_command, cmd);
                   1041:        while (((stat = inb(wdc+wd_status)) & WDCS_BUSY) && timeout > 0)
                   1042:                timeout--;
                   1043:        if (timeout <= 0)
                   1044:                return(-1);
                   1045:        if (cmd != WDCC_READP)
                   1046:                return (stat);
1.1.1.4 ! root     1047:     
1.1.1.3   root     1048:        /* is controller ready to return data? */
                   1049:        while (((stat = inb(wdc+wd_status)) & (WDCS_ERR|WDCS_DRQ)) == 0 &&
1.1.1.4 ! root     1050:            timeout > 0)
1.1.1.3   root     1051:                timeout--;
                   1052:        if (timeout <= 0)
                   1053:                return(-1);
                   1054:        return (stat);
                   1055: }
                   1056: 
                   1057: /*
                   1058:  * issue IDC to drive to tell it just what geometry it is to be.
                   1059:  */
                   1060: static int
1.1.1.4 ! root     1061: wdsetctlr(dev_t dev, struct disk *du)
        !          1062: {
1.1.1.3   root     1063:        int stat, x, wdc;
1.1.1.4 ! root     1064:     
        !          1065: /*
        !          1066:        printf("wd(%d,%d) C%dH%dS%d\n", du->dk_ctrlr, du->dk_unit,
        !          1067:                du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks, du->dk_dd.d_nsectors);
        !          1068: */
        !          1069:     
        !          1070:        DELAY(2000);
1.1.1.3   root     1071:        x = splbio();
                   1072:        wdc = du->dk_port;
1.1.1.4 ! root     1073:        outb(wdc+wd_cyl_lo, du->dk_dd.d_ncylinders);            /* TIH: was ...ders+1 */
        !          1074:        outb(wdc+wd_cyl_hi, (du->dk_dd.d_ncylinders)>>8);       /* TIH: was ...ders+1 */
        !          1075:        outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4) + du->dk_dd.d_ntracks-1);
1.1       root     1076:        outb(wdc+wd_seccnt, du->dk_dd.d_nsectors);
1.1.1.3   root     1077:        stat = wdcommand(du, WDCC_IDC);
1.1.1.4 ! root     1078:     
        !          1079: #ifndef TIHMODS
1.1.1.3   root     1080:        if (stat < 0)
                   1081:                return(stat);
1.1.1.4 ! root     1082: #endif
1.1.1.3   root     1083:        if (stat & WDCS_ERR)
                   1084:                printf("wdsetctlr: status %b error %b\n",
                   1085:                        stat, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS);
                   1086:        splx(x);
1.1       root     1087:        return(stat);
                   1088: }
                   1089: 
1.1.1.3   root     1090: /*
                   1091:  * issue READP to drive to ask it what it is.
                   1092:  */
                   1093: static int
1.1.1.4 ! root     1094: wdgetctlr(int u, struct disk *du)
        !          1095: {
1.1.1.3   root     1096:        int stat, x, i, wdc;
                   1097:        char tb[DEV_BSIZE];
                   1098:        struct wdparams *wp;
1.1.1.4 ! root     1099:        long timeout = 5000000;
        !          1100:     
1.1.1.3   root     1101:        x = splbio();           /* not called from intr level ... */
                   1102:        wdc = du->dk_port;
1.1.1.4 ! root     1103: #ifdef TIPCAT
        !          1104:        while ((inb(wdc+wd_status) & WDCS_READY) == 0 && timeout > 0)
        !          1105:                timeout--;
        !          1106:        if (timeout <= 0) {
        !          1107:                splx(x);
        !          1108:                return (-1);
        !          1109:        }
        !          1110: #endif
1.1.1.3   root     1111:        outb(wdc+wd_sdh, WDSD_IBM | (u << 4));
                   1112:        stat = wdcommand(du, WDCC_READP);
1.1.1.4 ! root     1113: #ifdef TIPCAT
        !          1114:        while ((inb(wdc+wd_status) & WDCS_READY) == 0 && timeout > 0)
        !          1115:                timeout--;
        !          1116:        if (timeout <= 0) {
        !          1117:                splx(x);
        !          1118:                return (-1);
        !          1119:        }
        !          1120: #endif
        !          1121:     
        !          1122: #ifndef TIHMODS
1.1.1.3   root     1123:        if (stat < 0)
                   1124:                return(stat);
1.1.1.4 ! root     1125: #else
        !          1126:        if (stat < 0) {
        !          1127:                splx(x);
        !          1128:                return(stat);
        !          1129:        }
        !          1130: #endif
1.1.1.3   root     1131:        if (stat & WDCS_ERR) {
                   1132:                splx(x);
                   1133:                return(inb(wdc+wd_error));
                   1134:        }
1.1.1.4 ! root     1135:     
1.1.1.3   root     1136:        /* obtain parameters */
                   1137:        wp = &du->dk_params;
                   1138:        insw(wdc+wd_data, tb, sizeof(tb)/sizeof(short));
                   1139:        bcopy(tb, wp, sizeof(struct wdparams));
1.1.1.4 ! root     1140:     
1.1.1.3   root     1141:        /* shuffle string byte order */
1.1.1.4 ! root     1142:        for (i=0; i < sizeof(wp->wdp_model); i+=2) {
1.1.1.3   root     1143:                u_short *p;
                   1144:                p = (u_short *) (wp->wdp_model + i);
                   1145:                *p = ntohs(*p);
                   1146:        }
1.1.1.4 ! root     1147: /*
        !          1148:        printf("gc %x cyl %d trk %d sec %d type %d sz %d model %s\n", wp->wdp_config,
        !          1149:                wp->wdp_fixedcyl+wp->wdp_removcyl, wp->wdp_heads, wp->wdp_sectors,
        !          1150:                wp->wdp_cntype, wp->wdp_cnsbsz, wp->wdp_model);
        !          1151: */
        !          1152:     
1.1.1.3   root     1153:        /* update disklabel given drive information */
                   1154:        du->dk_dd.d_ncylinders = wp->wdp_fixedcyl + wp->wdp_removcyl /*+- 1*/;
                   1155:        du->dk_dd.d_ntracks = wp->wdp_heads;
                   1156:        du->dk_dd.d_nsectors = wp->wdp_sectors;
                   1157:        du->dk_dd.d_secpercyl = du->dk_dd.d_ntracks * du->dk_dd.d_nsectors;
1.1.1.4 ! root     1158:        du->dk_dd.d_partitions[1].p_size = du->dk_dd.d_secpercyl * wp->wdp_sectors;
1.1.1.3   root     1159:        du->dk_dd.d_partitions[1].p_offset = 0;
1.1.1.4 ! root     1160: 
1.1.1.3   root     1161:        /* dubious ... */
                   1162:        bcopy("ESDI/IDE", du->dk_dd.d_typename, 9);
                   1163:        bcopy(wp->wdp_model+20, du->dk_dd.d_packname, 14-1);
                   1164:        /* better ... */
                   1165:        du->dk_dd.d_type = DTYPE_ESDI;
                   1166:        du->dk_dd.d_subtype |= DSTYPE_GEOMETRY;
1.1.1.4 ! root     1167:     
1.1.1.3   root     1168:        /* XXX sometimes possibly needed */
                   1169:        (void) inb(wdc+wd_status);
1.1.1.4 ! root     1170: #ifdef TIHMODS
        !          1171:        splx(x);
        !          1172: #endif
1.1.1.3   root     1173:        return (0);
                   1174: }
                   1175: 
                   1176: 
1.1       root     1177: /* ARGSUSED */
1.1.1.3   root     1178: int
                   1179: wdclose(dev_t dev, int flags, int fmt)
1.1       root     1180: {
                   1181:        register struct disk *du;
1.1.1.4 ! root     1182:        int part = wdpart(dev), mask = 1 << part;
        !          1183:     
1.1.1.3   root     1184:        du = wddrives[wdunit(dev)];
1.1.1.4 ! root     1185:     
1.1.1.3   root     1186:        /* insure only one open at a time */
1.1.1.4 ! root     1187:        du->dk_openpart &= ~mask;
        !          1188:        switch (fmt) {
        !          1189:        case S_IFCHR:
        !          1190:                du->dk_copenpart &= ~mask;
        !          1191:                break;
        !          1192:        case S_IFBLK:
        !          1193:                du->dk_bopenpart &= ~mask;
        !          1194:                break;
        !          1195:        }
1.1.1.2   root     1196:        return(0);
1.1       root     1197: }
                   1198: 
1.1.1.3   root     1199: int
                   1200: wdioctl(dev_t dev, int cmd, caddr_t addr, int flag)
1.1       root     1201: {
1.1.1.4 ! root     1202:        int lunit = wdunit(dev);
1.1       root     1203:        register struct disk *du;
                   1204:        int error = 0;
                   1205:        struct uio auio;
                   1206:        struct iovec aiov;
1.1.1.4 ! root     1207:     
        !          1208:        du = wddrives[lunit];
        !          1209:     
1.1       root     1210:        switch (cmd) {
1.1.1.3   root     1211:        case DIOCSBAD:
1.1.1.4 ! root     1212:                if ((flag & FWRITE) == 0)
        !          1213:                        error = EBADF;
        !          1214:                else {
1.1.1.3   root     1215:                        du->dk_bad = *(struct dkbad *)addr;
1.1.1.4 ! root     1216: #ifdef TIHBAD144
        !          1217:                        bad144intern(du);
        !          1218: #endif
        !          1219:                }
1.1.1.3   root     1220:                break;
                   1221: 
1.1       root     1222:        case DIOCGDINFO:
                   1223:                *(struct disklabel *)addr = du->dk_dd;
                   1224:                break;
1.1.1.4 ! root     1225:        
        !          1226:        case DIOCGPART:
        !          1227:                ((struct partinfo *)addr)->disklab = &du->dk_dd;
        !          1228:                ((struct partinfo *)addr)->part =
        !          1229:                        &du->dk_dd.d_partitions[wdpart(dev)];
        !          1230:                break;
        !          1231:        
        !          1232:        case DIOCSDINFO:
        !          1233:                if ((flag & FWRITE) == 0)
        !          1234:                        error = EBADF;
        !          1235:                else
        !          1236:                        error = setdisklabel(&du->dk_dd, (struct disklabel *)addr,
        !          1237:                                 /*(du->dk_flags&DKFL_BSDLABEL) ? du->dk_openpart : */0,
        !          1238:                                 du->dk_dospartitions);
        !          1239:                if (error == 0) {
1.1.1.3   root     1240:                        du->dk_flags |= DKFL_BSDLABEL;
                   1241:                        wdsetctlr(dev, du);
                   1242:                }
1.1.1.4 ! root     1243:                break;
        !          1244:        
        !          1245:     case DIOCWLABEL:
1.1.1.3   root     1246:                du->dk_flags &= ~DKFL_WRITEPROT;
1.1.1.4 ! root     1247:                if ((flag & FWRITE) == 0)
        !          1248:                        error = EBADF;
        !          1249:                else
        !          1250:                        du->dk_wlabel = *(int *)addr;
        !          1251:                break;
        !          1252:        
        !          1253:     case DIOCWDINFO:
1.1.1.3   root     1254:                du->dk_flags &= ~DKFL_WRITEPROT;
1.1.1.4 ! root     1255:                if ((flag & FWRITE) == 0)
        !          1256:                        error = EBADF;
        !          1257:                else if ((error = setdisklabel(&du->dk_dd, (struct disklabel *)addr,
        !          1258:                    /*(du->dk_flags & DKFL_BSDLABEL) ? du->dk_openpart :*/ 0,
        !          1259:                    du->dk_dospartitions)) == 0) {
        !          1260:                        int wlab;
        !          1261:            
1.1.1.3   root     1262:                        du->dk_flags |= DKFL_BSDLABEL;
1.1       root     1263:                        wdsetctlr(dev, du);
1.1.1.4 ! root     1264:            
        !          1265:                        /* simulate opening partition 0 so write succeeds */
        !          1266:                        du->dk_openpart |= (1 << 0);            /* XXX */
        !          1267:                        wlab = du->dk_wlabel;
        !          1268:                        du->dk_wlabel = 1;
        !          1269:                        error = writedisklabel(dev, wdstrategy,
1.1.1.3   root     1270:                                &du->dk_dd, du->dk_dospartitions);
1.1.1.4 ! root     1271:                        du->dk_openpart = du->dk_copenpart | du->dk_bopenpart;
        !          1272:                        du->dk_wlabel = wlab;
        !          1273:                }
        !          1274:                break;
        !          1275:        
1.1       root     1276: #ifdef notyet
                   1277:        case DIOCGDINFOP:
                   1278:                *(struct disklabel **)addr = &(du->dk_dd);
                   1279:                break;
1.1.1.4 ! root     1280:        
1.1       root     1281:        case DIOCWFORMAT:
                   1282:                if ((flag & FWRITE) == 0)
                   1283:                        error = EBADF;
                   1284:                else {
                   1285:                        register struct format_op *fop;
1.1.1.4 ! root     1286:            
1.1       root     1287:                        fop = (struct format_op *)addr;
                   1288:                        aiov.iov_base = fop->df_buf;
                   1289:                        aiov.iov_len = fop->df_count;
                   1290:                        auio.uio_iov = &aiov;
                   1291:                        auio.uio_iovcnt = 1;
                   1292:                        auio.uio_resid = fop->df_count;
                   1293:                        auio.uio_segflg = 0;
1.1.1.4 ! root     1294:                        auio.uio_offset = fop->df_startblk * du->dk_dd.d_secsize;
        !          1295:                        error = physio(wdformat, &rwdbuf[lunit], dev, B_WRITE,
1.1       root     1296:                                minphys, &auio);
                   1297:                        fop->df_count -= auio.uio_resid;
                   1298:                        fop->df_reg[0] = du->dk_status;
                   1299:                        fop->df_reg[1] = du->dk_error;
                   1300:                }
                   1301:                break;
                   1302: #endif
1.1.1.4 ! root     1303:        
1.1       root     1304:        default:
                   1305:                error = ENOTTY;
                   1306:                break;
                   1307:        }
                   1308:        return (error);
                   1309: }
                   1310: 
1.1.1.3   root     1311: #ifdef B_FORMAT
                   1312: int
                   1313: wdformat(struct buf *bp)
1.1       root     1314: {
                   1315:        bp->b_flags |= B_FORMAT;
                   1316:        return (wdstrategy(bp));
1.1.1.3   root     1317: }
                   1318: #endif
1.1       root     1319: 
1.1.1.3   root     1320: int
                   1321: wdsize(dev_t dev)
1.1       root     1322: {
1.1.1.4 ! root     1323:        int lunit = wdunit(dev), part = wdpart(dev);
1.1.1.3   root     1324:        struct disk *du;
1.1.1.4 ! root     1325:     
        !          1326:        if (lunit >= NWD)
1.1.1.3   root     1327:                return(-1);
1.1.1.4 ! root     1328:     
        !          1329:        if ((du = wddrives[lunit]) == 0)
1.1.1.3   root     1330:                return (-1);
1.1.1.4 ! root     1331:     
        !          1332:        if (du->dk_state < OPEN || (du->dk_flags & DKFL_BSDLABEL) == 0) {
        !          1333:                int val;
        !          1334:                val = wdopen(makewddev(major(dev), lunit, WDRAW), FREAD, S_IFBLK, 0);
        !          1335:                if (val != 0)
        !          1336:                        return (-1);
        !          1337:        }
        !          1338:     
        !          1339:        if ((du->dk_flags & (DKFL_WRITEPROT|DKFL_BSDLABEL)) != DKFL_BSDLABEL)
        !          1340:                return (-1);
        !          1341:        else
        !          1342:                return((int)du->dk_dd.d_partitions[part].p_size);
1.1       root     1343: }
                   1344: 
                   1345: extern        char *vmmap;            /* poor name! */
                   1346: 
1.1.1.4 ! root     1347: /* dump core after a system crash */
1.1.1.3   root     1348: int
1.1.1.4 ! root     1349: wddump(dev_t dev)
1.1       root     1350: {
                   1351:        register struct disk *du;       /* disk unit to do the IO */
                   1352:        long    num;                    /* number of sectors to write */
1.1.1.4 ! root     1353:        int     ctrlr, lunit, part, wdc;
        !          1354:        long    blkoff, blknum;
1.1       root     1355:        long    cylin, head, sector, stat;
                   1356:        long    secpertrk, secpercyl, nblocks, i;
                   1357:        char *addr;
                   1358:        extern  int Maxmem;
1.1.1.4 ! root     1359:        static  wddoingadump = 0;
1.1.1.3   root     1360:        extern caddr_t CADDR1;
1.1.1.4 ! root     1361:     
1.1       root     1362:        addr = (char *) 0;              /* starting address */
1.1.1.4 ! root     1363:     
1.1.1.3   root     1364:        /* toss any characters present prior to dump */
                   1365:        while (sgetc(1))
                   1366:                ;
1.1.1.4 ! root     1367:     
1.1       root     1368:        /* size of memory to dump */
                   1369:        num = Maxmem;
1.1.1.4 ! root     1370:        lunit = wdunit(dev);    /* eventually support floppies? */
1.1       root     1371:        part = wdpart(dev);             /* file system */
                   1372:        /* check for acceptable drive number */
1.1.1.4 ! root     1373:        if (lunit >= NWD)
        !          1374:                return(ENXIO);
        !          1375:     
        !          1376:        du = wddrives[lunit];
        !          1377:        if (du == 0)
        !          1378:                return(ENXIO);
1.1       root     1379:        /* was it ever initialized ? */
1.1.1.4 ! root     1380:        if (du->dk_state < OPEN)
        !          1381:                return (ENXIO);
        !          1382:        if (du->dk_flags & DKFL_WRITEPROT)
        !          1383:                return(ENXIO);
1.1.1.3   root     1384:        wdc = du->dk_port;
1.1.1.4 ! root     1385:        ctrlr = du->dk_ctrlr;
        !          1386:     
1.1       root     1387:        /* Convert to disk sectors */
                   1388:        num = (u_long) num * NBPG / du->dk_dd.d_secsize;
1.1.1.4 ! root     1389:     
1.1       root     1390:        /* check if controller active */
1.1.1.4 ! root     1391:        /*if (wdtab[ctrlr].b_active)
        !          1392:                return(EFAULT); */
        !          1393:        if (wddoingadump)
        !          1394:                return(EFAULT);
        !          1395:     
1.1       root     1396:        secpertrk = du->dk_dd.d_nsectors;
                   1397:        secpercyl = du->dk_dd.d_secpercyl;
                   1398:        nblocks = du->dk_dd.d_partitions[part].p_size;
1.1.1.3   root     1399:        blkoff = du->dk_dd.d_partitions[part].p_offset;
1.1.1.4 ! root     1400:     
        !          1401:        /*pg("xunit %x, nblocks %d, dumplo %d num %d\n", part,nblocks,dumplo,num);*/
1.1       root     1402:        /* check transfer bounds against partition size */
                   1403:        if ((dumplo < 0) || ((dumplo + num) > nblocks))
                   1404:                return(EINVAL);
1.1.1.4 ! root     1405:     
        !          1406:        /* mark controller active for if we panic during the dump */
        !          1407:        /* wdtab[ctrlr].b_active = 1; */
        !          1408:        wddoingadump = 1;
        !          1409:        i = 200000000;
        !          1410:        while ((inb(wdc+wd_status) & WDCS_BUSY) && (i-- > 0))
        !          1411:                ;
        !          1412:        outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4));
1.1       root     1413:        outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
1.1.1.4 ! root     1414:        while (inb(wdc+wd_status) & WDCS_BUSY)
        !          1415:                ;
        !          1416:     
1.1       root     1417:        /* some compaq controllers require this ... */
                   1418:        wdsetctlr(dev, du);
1.1.1.4 ! root     1419:     
1.1.1.3   root     1420:        blknum = dumplo + blkoff;
1.1       root     1421:        while (num > 0) {
1.1.1.3   root     1422:                pmap_enter(kernel_pmap, CADDR1, trunc_page(addr), VM_PROT_READ, TRUE);
1.1.1.4 ! root     1423:        
1.1       root     1424:                /* compute disk address */
                   1425:                cylin = blknum / secpercyl;
                   1426:                head = (blknum % secpercyl) / secpertrk;
                   1427:                sector = blknum % secpertrk;
1.1.1.4 ! root     1428:        
        !          1429: #ifdef TIHBAD144
        !          1430:                if (du->dk_flags & DKFL_BADSECT) {
        !          1431:                        long newblk;
        !          1432:                        int i;
        !          1433: 
        !          1434:                        for (i = 0; du->dk_badsect[i] != -1; i++) {
        !          1435:                                if (blknum < du->dk_badsect[i]) {
        !          1436:                                        break;  /* sorted list, passed our block by */
        !          1437:                                } else if (blknum == du->dk_badsect[i]) {
        !          1438:                                        newblk = du->dk_dd.d_secperunit -
        !          1439:                                                du->dk_dd.d_nsectors - i - 1;
        !          1440:                                        cylin = newblk / secpercyl;
        !          1441:                                        head = (newblk % secpercyl) / secpertrk;
        !          1442:                                        sector = newblk % secpertrk;
        !          1443:                                        /* found and repl; done scanning bad144 table */
        !          1444:                                        break;
        !          1445:                                }
1.1       root     1446:                        }
1.1.1.4 ! root     1447:                }
1.1       root     1448: #endif
                   1449:                sector++;               /* origin 1 */
1.1.1.4 ! root     1450:            
1.1       root     1451:                /* select drive.     */
1.1.1.4 ! root     1452:                outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit<<4) | (head & 0xf));
        !          1453:                while ((inb(wdc+wd_status) & WDCS_READY) == 0)
        !          1454:                        ;
        !          1455:        
1.1       root     1456:                /* transfer some blocks */
                   1457:                outb(wdc+wd_sector, sector);
                   1458:                outb(wdc+wd_seccnt,1);
                   1459:                outb(wdc+wd_cyl_lo, cylin);
                   1460:                outb(wdc+wd_cyl_hi, cylin >> 8);
                   1461: #ifdef notdef
                   1462:                /* lets just talk about this first...*/
                   1463:                pg ("sdh 0%o sector %d cyl %d addr 0x%x",
                   1464:                        inb(wdc+wd_sdh), inb(wdc+wd_sector),
1.1.1.4 ! root     1465:                        inb(wdc+wd_cyl_hi)*256+inb(wdc+wd_cyl_lo), addr);
1.1       root     1466: #endif
                   1467:                outb(wdc+wd_command, WDCC_WRITE);
1.1.1.4 ! root     1468:        
1.1       root     1469:                /* Ready to send data?  */
1.1.1.4 ! root     1470:                while ((inb(wdc+wd_status) & WDCS_DRQ) == 0)
        !          1471:                        ;
        !          1472:                if (inb(wdc+wd_status) & WDCS_ERR)
        !          1473:                        return(EIO);
        !          1474:        
1.1       root     1475:                outsw (wdc+wd_data, CADDR1+((int)addr&(NBPG-1)), 256);
1.1.1.4 ! root     1476:        
        !          1477:                if (inb(wdc+wd_status) & WDCS_ERR)
        !          1478:                        return(EIO);
1.1       root     1479:                /* Check data request (should be done).         */
1.1.1.4 ! root     1480:                if (inb(wdc+wd_status) & WDCS_DRQ)
        !          1481:                        return(EIO);
        !          1482:        
1.1       root     1483:                /* wait for completion */
1.1.1.4 ! root     1484:                for (i=200000000; inb(wdc+wd_status) & WDCS_BUSY ; i--) {
        !          1485:                        if (i < 0)
        !          1486:                                return (EIO);
1.1       root     1487:                }
1.1.1.4 ! root     1488: 
1.1       root     1489:                /* error check the xfer */
1.1.1.4 ! root     1490:                if (inb(wdc+wd_status) & WDCS_ERR)
        !          1491:                        return(EIO);
        !          1492:        
        !          1493:                if ((unsigned)addr % (1024*1024) == 0)
        !          1494:                        printf("%d ", num/2048);
1.1.1.3   root     1495: 
1.1       root     1496:                /* update block count */
                   1497:                num--;
1.1.1.4 ! root     1498:                blknum++;
1.1.1.3   root     1499:                (int) addr += 512;
1.1.1.4 ! root     1500:        
1.1.1.3   root     1501:                /* operator aborting dump? */
                   1502:                if (sgetc(1))
                   1503:                        return(EINTR);
1.1       root     1504:        }
                   1505:        return(0);
                   1506: }
                   1507: #endif
1.1.1.4 ! root     1508: 
        !          1509: #ifdef TIHBAD144
        !          1510: /*
        !          1511:  * Internalize the bad sector table.
        !          1512:  */
        !          1513: void
        !          1514: bad144intern(struct disk *du)
        !          1515: {
        !          1516:        int i;
        !          1517:        if (du->dk_flags & DKFL_BADSECT) {
        !          1518:                for (i = 0; i < 127; i++) {
        !          1519:                        du->dk_badsect[i] = -1;
        !          1520:                }
        !          1521: 
        !          1522:                for (i = 0; i < 126; i++) {
        !          1523:                        if (du->dk_bad.bt_bad[i].bt_cyl == 0xffff) {
        !          1524:                                break;
        !          1525:                        } else {
        !          1526:                                du->dk_badsect[i] =
        !          1527:                                    du->dk_bad.bt_bad[i].bt_cyl * du->dk_dd.d_secpercyl +
        !          1528:                                   (du->dk_bad.bt_bad[i].bt_trksec >> 8) * du->dk_dd.d_nsectors +
        !          1529:                                   (du->dk_bad.bt_bad[i].bt_trksec & 0x00ff);
        !          1530:                        }
        !          1531:                }
        !          1532:        }
        !          1533: }
        !          1534: #endif
        !          1535: 
        !          1536: wdprint() {}
        !          1537: 
        !          1538: 
        !          1539: /* this routine was adopted from the kernel sources */
        !          1540: /* more efficient because b_cylin is not really as useful at this level */
        !          1541: /* so I eliminate the processing, I believe that sorting the sectors */
        !          1542: /* is adequate */
        !          1543: void
        !          1544: wddisksort(struct buf *dp, struct buf *bp)
        !          1545: {
        !          1546:        register struct buf *ap;
        !          1547: 
        !          1548:        /*
        !          1549:         * If nothing on the activity queue, then
        !          1550:         * we become the only thing.
        !          1551:         */
        !          1552:        ap = dp->b_actf;
        !          1553:        if(ap == NULL) {
        !          1554:                dp->b_actf = bp;
        !          1555:                dp->b_actl = bp;
        !          1556:                bp->av_forw = NULL;
        !          1557:                return;
        !          1558:        }
        !          1559:        while( ap->b_flags & B_XXX) {
        !          1560:                if( ap->av_forw == 0 || (ap->av_forw->b_flags & B_XXX) == 0)
        !          1561:                        break;
        !          1562:                ap = ap->av_forw;
        !          1563:        }
        !          1564:        /*
        !          1565:         * If we lie after the first (currently active)
        !          1566:         * request, then we must locate the second request list
        !          1567:         * and add ourselves to it.
        !          1568:         */
        !          1569:        if (bp->b_blkno < ap->b_blkno) {
        !          1570:                while (ap->av_forw) {
        !          1571:                        /*
        !          1572:                         * Check for an ``inversion'' in the
        !          1573:                         * normally ascending cylinder numbers,
        !          1574:                         * indicating the start of the second request list.
        !          1575:                         */
        !          1576:                        if (ap->av_forw->b_blkno < ap->b_blkno) {
        !          1577:                                /*
        !          1578:                                 * Search the second request list
        !          1579:                                 * for the first request at a larger
        !          1580:                                 * cylinder number.  We go before that;
        !          1581:                                 * if there is no such request, we go at end.
        !          1582:                                 */
        !          1583:                                do {
        !          1584:                                        if (bp->b_blkno < ap->av_forw->b_blkno)
        !          1585:                                                goto insert;
        !          1586:                                        ap = ap->av_forw;
        !          1587:                                } while (ap->av_forw);
        !          1588:                                goto insert;            /* after last */
        !          1589:                        }
        !          1590:                        ap = ap->av_forw;
        !          1591:                }
        !          1592:                /*
        !          1593:                 * No inversions... we will go after the last, and
        !          1594:                 * be the first request in the second request list.
        !          1595:                 */
        !          1596:                goto insert;
        !          1597:        }
        !          1598:        /*
        !          1599:         * Request is at/after the current request...
        !          1600:         * sort in the first request list.
        !          1601:         */
        !          1602:        while (ap->av_forw) {
        !          1603:                /*
        !          1604:                 * We want to go after the current request
        !          1605:                 * if there is an inversion after it (i.e. it is
        !          1606:                 * the end of the first request list), or if
        !          1607:                 * the next request is a larger cylinder than our request.
        !          1608:                 */
        !          1609:                if (ap->av_forw->b_blkno < ap->b_blkno ||
        !          1610:                    bp->b_blkno < ap->av_forw->b_blkno )
        !          1611:                        goto insert;
        !          1612:                ap = ap->av_forw;
        !          1613:        }
        !          1614:        /*
        !          1615:         * Neither a second list nor a larger
        !          1616:         * request... we go at the end of the first list,
        !          1617:         * which is the same as the end of the whole schebang.
        !          1618:         */
        !          1619: insert:
        !          1620:        bp->av_forw = ap->av_forw;
        !          1621:        ap->av_forw = bp;
        !          1622:        if (ap == dp->b_actl)
        !          1623:                dp->b_actl = bp;
        !          1624: }
        !          1625: 

unix.superglobalmegacorp.com

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