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

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

unix.superglobalmegacorp.com

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