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

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

unix.superglobalmegacorp.com

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