[BACK]Return to hdc9224.c CVS log [TXT][DIR] Up to [local] / sys / arch / vax / vsa

Annotation of sys/arch/vax/vsa/hdc9224.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: hdc9224.c,v 1.21 2007/06/20 20:13:41 miod Exp $       */
                      2: /*     $NetBSD: hdc9224.c,v 1.16 2001/07/26 15:05:09 wiz Exp $ */
                      3: /*
                      4:  * Copyright (c) 1996 Ludd, University of Lule}, Sweden.
                      5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to Ludd by Bertram Barth.
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  * 3. All advertising materials mentioning features or use of this software
                     18:  *    must display the following acknowledgement:
                     19:  *     This product includes software developed at Ludd, University of
                     20:  *     Lule}, Sweden and its contributors.
                     21:  * 4. The name of the author may not be used to endorse or promote products
                     22:  *    derived from this software without specific prior written permission
                     23:  *
                     24:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     25:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     26:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     27:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     28:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     29:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     30:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     31:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     32:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     33:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     34:  */
                     35:
                     36: /*
                     37:  * with much help from (in alphabetical order):
                     38:  *     Jeremy
                     39:  *     Roger Ivie
                     40:  *     Rick Macklem
                     41:  *     Mike Young
                     42:  *
                     43:  * Rewritten by Ragge 25 Jun 2000. New features:
                     44:  *     - Uses interrupts instead of polling to signal ready.
                     45:  *     - Can cooperate with the SCSI routines WRT. the DMA area.
                     46:  *
                     47:  * TODO:
                     48:  *     - Floppy support missing.
                     49:  *     - Bad block forwarding missing.
                     50:  *     - Statistics collection.
                     51:  */
                     52: #undef HDDEBUG
                     53:
                     54: #include <sys/param.h>
                     55: #include <sys/systm.h>
                     56: #include <sys/kernel.h>
                     57: #include <sys/conf.h>
                     58: #include <sys/file.h>
                     59: #include <sys/stat.h>
                     60: #include <sys/ioctl.h>
                     61: #include <sys/buf.h>
                     62: #include <sys/proc.h>
                     63: #include <sys/user.h>
                     64: #include <sys/device.h>
                     65: #include <sys/disklabel.h>
                     66: #include <sys/disk.h>
                     67: #include <sys/syslog.h>
                     68: #include <sys/reboot.h>
                     69:
                     70: #include <uvm/uvm_extern.h>
                     71:
                     72: #include <ufs/ufs/dinode.h> /* For BBSIZE */
                     73: #include <ufs/ffs/fs.h>
                     74:
                     75: #include <machine/pte.h>
                     76: #include <machine/sid.h>
                     77: #include <machine/cpu.h>
                     78: #include <machine/uvax.h>
                     79: #include <machine/ka410.h>
                     80: #include <machine/vsbus.h>
                     81: #include <machine/rpb.h>
                     82: #include <machine/scb.h>
                     83:
                     84: #include <arch/vax/mscp/mscp.h> /* For DEC disk encoding */
                     85:
                     86: #include <vax/vsa/hdc9224.h>
                     87:
                     88: /*
                     89:  * on-disk geometry block
                     90:  */
                     91: struct hdgeom {
                     92:        char mbz[10];           /* 10 bytes of zero */
                     93:        long xbn_count;         /* number of XBNs */
                     94:        long dbn_count;         /* number of DBNs */
                     95:        long lbn_count;         /* number of LBNs (Logical-Block-Numbers) */
                     96:        long rbn_count;         /* number of RBNs (Replacement-Block-Numbers) */
                     97:        short nspt;             /* number of sectors per track */
                     98:        short ntracks;          /* number of tracks */
                     99:        short ncylinders;       /* number of cylinders */
                    100:        short precomp;          /* first cylinder for write precompensation */
                    101:        short reduced;          /* first cylinder for reduced write current */
                    102:        short seek_rate;        /* seek rate or zero for buffered seeks */
                    103:        short crc_eec;          /* 0 if CRC, 1 if ECC is being used */
                    104:        short rct;              /* "replacement control table" (RCT) */
                    105:        short rct_ncopies;      /* number of copies of the RCT */
                    106:        long    media_id;       /* media identifier */
                    107:        short interleave;       /* sector-to-sector interleave */
                    108:        short headskew;         /* head-to-head skew */
                    109:        short cylskew;          /* cylinder-to-cylinder skew */
                    110:        short gap0_size;        /* size of GAP 0 in the MFM format */
                    111:        short gap1_size;        /* size of GAP 1 in the MFM format */
                    112:        short gap2_size;        /* size of GAP 2 in the MFM format */
                    113:        short gap3_size;        /* size of GAP 3 in the MFM format */
                    114:        short sync_value;       /* sync value used when formatting */
                    115:        char    reserved[32];   /* reserved for use by the RQDX formatter */
                    116:        short serial_number;    /* serial number */
                    117: #if 0  /* we don't need these 412 useless bytes ... */
                    118:        char    fill[412-2];    /* Filler bytes to the end of the block */
                    119:        short checksum; /* checksum over the XBN */
                    120: #endif
                    121: } __packed;
                    122:
                    123: /*
                    124:  * Software status
                    125:  */
                    126: struct hdsoftc {
                    127:        struct device sc_dev;           /* must be here! (pseudo-OOP:) */
                    128:        struct disk sc_disk;            /* disklabel etc. */
                    129:        struct hdgeom sc_xbn;           /* on-disk geometry information */
                    130:        int sc_drive;                   /* physical unit number */
                    131: };
                    132:
                    133: struct hdcsoftc {
                    134:        struct device sc_dev;           /* must be here (pseudo-OOP:) */
                    135:        struct evcount sc_intrcnt;
                    136:        struct vsbus_dma sc_vd;
                    137:        vaddr_t sc_regs;                /* register addresses */
                    138:        struct buf sc_buf_queue;
                    139:        struct buf *sc_active;
                    140:        struct hdc9224_UDCreg sc_creg;  /* (command) registers to be written */
                    141:        struct hdc9224_UDCreg sc_sreg;  /* (status) registers being read */
                    142:        caddr_t sc_dmabase;             /* */
                    143:        int     sc_dmasize;
                    144:        caddr_t sc_bufaddr;             /* Current in-core address */
                    145:        daddr64_t sc_diskblk;           /* Current block on disk */
                    146:        int sc_bytecnt;                 /* How much left to transfer */
                    147:        int sc_xfer;                    /* Current transfer size */
                    148:        int sc_retries;
                    149:        volatile u_char sc_status;      /* last status from interrupt */
                    150:        char sc_intbit;
                    151: };
                    152:
                    153: struct hdc_attach_args {
                    154:        int ha_drive;
                    155: };
                    156:
                    157: /*
                    158:  * prototypes for (almost) all the internal routines
                    159:  */
                    160: int hdcmatch(struct device *, void *, void *);
                    161: void hdcattach(struct device *, struct device *, void *);
                    162: int hdcprint(void *, const char *);
                    163: int hdmatch(struct device *, void *, void *);
                    164: void hdattach(struct device *, struct device *, void *);
                    165: void hdcintr(void *);
                    166: int hdc_command(struct hdcsoftc *, int);
                    167: void hd_readgeom(struct hdcsoftc *, struct hdsoftc *);
                    168: #ifdef HDDEBUG
                    169: void hdc_printgeom( struct hdgeom *);
                    170: #endif
                    171: void hdc_writeregs(struct hdcsoftc *);
                    172: void hdcstart(struct hdcsoftc *, struct buf *);
                    173: int hdc_hdselect(struct hdcsoftc *, int);
                    174: void hdmakelabel(struct disklabel *, struct hdgeom *);
                    175: void hdc_writeregs(struct hdcsoftc *);
                    176: void hdc_readregs(struct hdcsoftc *);
                    177: void hdc_qstart(void *);
                    178:
                    179: bdev_decl(hd);
                    180: cdev_decl(hd);
                    181:
                    182: const struct   cfattach hdc_ca = {
                    183:        sizeof(struct hdcsoftc), hdcmatch, hdcattach
                    184: };
                    185:
                    186: struct cfdriver hdc_cd = {
                    187:        NULL, "hdc", DV_DULL
                    188: };
                    189:
                    190: const struct   cfattach hd_ca = {
                    191:        sizeof(struct hdsoftc), hdmatch, hdattach
                    192: };
                    193:
                    194: struct cfdriver hd_cd = {
                    195:        NULL, "hd", DV_DISK
                    196: };
                    197:
                    198: /* At least 0.7 uS between register accesses */
                    199: static int hd_dmasize, inq = 0;        /* XXX should be in softc... but only 1 ctrl */
                    200: static int u;
                    201: #define        WAIT    asm("movl _u,_u;movl _u,_u;movl _u,_u; movl _u,_u")
                    202:
                    203: #define        HDC_WREG(x)     *(volatile char *)(sc->sc_regs) = (x)
                    204: #define        HDC_RREG        *(volatile char *)(sc->sc_regs)
                    205: #define        HDC_WCMD(x)     *(volatile char *)(sc->sc_regs + 4) = (x)
                    206: #define        HDC_RSTAT       *(volatile char *)(sc->sc_regs + 4)
                    207:
                    208: /*
                    209:  * new-config's hdcmatch() is similar to old-config's hdcprobe(),
                    210:  * thus we probe for the existence of the controller and reset it.
                    211:  * NB: we can't initialize the controller yet, since space for hdcsoftc
                    212:  *     is not yet allocated. Thus we do this in hdcattach()...
                    213:  */
                    214: int
                    215: hdcmatch(struct device *parent, void *vcf, void *aux)
                    216: {
                    217:        static int matched = 0;
                    218:        struct vsbus_attach_args *va = aux;
                    219:        volatile char *hdc_csr = (char *)va->va_addr;
                    220:        int i;
                    221:
                    222:        if (vax_boardtype == VAX_BTYP_49 || vax_boardtype == VAX_BTYP_46 ||
                    223:            vax_boardtype == VAX_BTYP_48 || vax_boardtype == VAX_BTYP_1303)
                    224:                return (0);
                    225:
                    226:        /* Can only match once due to DMA setup. This should not be an issue. */
                    227:        if (matched != 0)
                    228:                return (0);
                    229:
                    230:        hdc_csr[4] = DKC_CMD_RESET; /* reset chip */
                    231:        for (i = 0; i < 1000; i++) {
                    232:                DELAY(1000);
                    233:                if (hdc_csr[4] & DKC_ST_DONE)
                    234:                        break;
                    235:        }
                    236:        if (i == 100)
                    237:                return 0; /* No response to reset */
                    238:
                    239:        hdc_csr[4] = DKC_CMD_SETREGPTR|UDC_TERM;
                    240:        WAIT;
                    241:        hdc_csr[0] = UDC_TC_CRCPRE|UDC_TC_INTDONE;
                    242:        WAIT;
                    243:        hdc_csr[4] = DKC_CMD_DRDESELECT; /* Should be harmless */
                    244:        DELAY(1000);
                    245:        return (matched = 1);
                    246: }
                    247:
                    248: int
                    249: hdcprint(void *aux, const char *pnp)
                    250: {
                    251:        struct hdc_attach_args *ha = aux;
                    252:
                    253:        if (pnp != NULL)
                    254:                printf("%s at %s drive %d",
                    255:                    ha->ha_drive == 2 ? "ry" : "hd", pnp, ha->ha_drive);
                    256:
                    257:        return (UNCONF);
                    258: }
                    259:
                    260: /*
                    261:  * hdc_attach() probes for all possible devices
                    262:  */
                    263: void
                    264: hdcattach(struct device *parent, struct device *self, void *aux)
                    265: {
                    266:        struct vsbus_attach_args *va = aux;
                    267:        struct hdcsoftc *sc = (void *)self;
                    268:        struct hdc_attach_args ha;
                    269:        int status, i;
                    270:
                    271:        u = 0; /* !!! - GCC */
                    272:
                    273:        printf("\n");
                    274:
                    275:        /*
                    276:         * Get interrupt vector, enable instrumentation.
                    277:         */
                    278:        scb_vecalloc(va->va_cvec, hdcintr, sc, SCB_ISTACK, &sc->sc_intrcnt);
                    279:        evcount_attach(&sc->sc_intrcnt, self->dv_xname, (void *)va->va_cvec,
                    280:            &evcount_intr);
                    281:
                    282:        sc->sc_regs = vax_map_physmem(va->va_paddr, 1);
                    283:        sc->sc_dmabase = (caddr_t)va->va_dmaaddr;
                    284:        sc->sc_dmasize = va->va_dmasize;
                    285:        sc->sc_intbit = va->va_maskno;
                    286:        hd_dmasize = min(MAXPHYS, sc->sc_dmasize); /* Used in hd_minphys */
                    287:
                    288:        sc->sc_vd.vd_go = hdc_qstart;
                    289:        sc->sc_vd.vd_arg = sc;
                    290:
                    291:        /*
                    292:         * Reset controller.
                    293:         */
                    294:        HDC_WCMD(DKC_CMD_RESET);
                    295:        DELAY(1000);
                    296:        status = HDC_RSTAT;
                    297:        if (status != (DKC_ST_DONE|DKC_TC_SUCCESS)) {
                    298:                printf("%s: RESET failed,  status 0x%x\n",
                    299:                    sc->sc_dev.dv_xname, status);
                    300:                return;
                    301:        }
                    302:
                    303:        /*
                    304:         * now probe for all possible hard drives
                    305:         */
                    306:        for (i = 0; i < 4; i++) {
                    307:                if (i == 2) /* Floppy, needs special handling */
                    308:                        continue;
                    309:                HDC_WCMD(DKC_CMD_DRSELECT | i);
                    310:                DELAY(1000);
                    311:                status = HDC_RSTAT;
                    312:                ha.ha_drive = i;
                    313:                if ((status & DKC_ST_TERMCOD) == DKC_TC_SUCCESS)
                    314:                        config_found(self, (void *)&ha, hdcprint);
                    315:        }
                    316: }
                    317:
                    318: /*
                    319:  * hdmatch() probes for the existence of a HD-type disk/floppy
                    320:  */
                    321: int
                    322: hdmatch(parent, vcf, aux)
                    323:        struct device *parent;
                    324:        void *vcf;
                    325:        void *aux;
                    326: {
                    327:        struct hdc_attach_args *ha = aux;
                    328:        struct cfdata *cf = vcf;
                    329:
                    330:        if (cf->cf_loc[0] != -1 &&
                    331:            cf->cf_loc[0] != ha->ha_drive)
                    332:                return 0;
                    333:
                    334:        if (ha->ha_drive == 2) /* Always floppy, not supported */
                    335:                return 0;
                    336:
                    337:        return 1;
                    338: }
                    339:
                    340: #define        HDMAJOR 19
                    341:
                    342: void
                    343: hdattach(struct device *parent, struct device *self, void *aux)
                    344: {
                    345:        struct hdcsoftc *sc = (void*)parent;
                    346:        struct hdsoftc *hd = (void*)self;
                    347:        struct hdc_attach_args *ha = aux;
                    348:        struct disklabel *dl;
                    349:        char *msg;
                    350:
                    351:        hd->sc_drive = ha->ha_drive;
                    352:        /*
                    353:         * Initialize and attach the disk structure.
                    354:         */
                    355:        hd->sc_disk.dk_name = hd->sc_dev.dv_xname;
                    356:        disk_attach(&hd->sc_disk);
                    357:
                    358:        /*
                    359:         * if it's not a floppy then evaluate the on-disk geometry.
                    360:         * if necessary correct the label...
                    361:         */
                    362:        hd_readgeom(sc, hd);
                    363:        disk_printtype(hd->sc_drive, hd->sc_xbn.media_id);
                    364:        dl = hd->sc_disk.dk_label;
                    365:        hdmakelabel(dl, &hd->sc_xbn);
                    366:        msg = readdisklabel(MAKEDISKDEV(HDMAJOR, hd->sc_dev.dv_unit, RAW_PART),
                    367:            hdstrategy, dl, 0);
                    368:        printf("%s: %luMB, %lu sectors\n",
                    369:            hd->sc_dev.dv_xname, DL_GETDSIZE(dl) / (1048576 / DEV_BSIZE),
                    370:            DL_GETDSIZE(dl));
                    371:        if (msg) {
                    372:                /*printf("%s: %s\n", hd->sc_dev.dv_xname, msg);*/
                    373:        }
                    374: #ifdef HDDEBUG
                    375:        hdc_printgeom(&hd->sc_xbn);
                    376: #endif
                    377: }
                    378:
                    379: void
                    380: hdcintr(void *arg)
                    381: {
                    382:        struct hdcsoftc *sc = arg;
                    383:        struct buf *bp;
                    384:
                    385:        sc->sc_status = HDC_RSTAT;
                    386:        if (sc->sc_active == 0)
                    387:                return; /* Complain? */
                    388:
                    389:        if ((sc->sc_status & (DKC_ST_INTPEND | DKC_ST_DONE)) !=
                    390:            (DKC_ST_INTPEND | DKC_ST_DONE))
                    391:                return; /* Why spurious ints sometimes??? */
                    392:
                    393:        bp = sc->sc_active;
                    394:        sc->sc_active = 0;
                    395:        if ((sc->sc_status & DKC_ST_TERMCOD) != DKC_TC_SUCCESS) {
                    396:                int i;
                    397:                u_char *g = (u_char *)&sc->sc_sreg;
                    398:
                    399:                if (sc->sc_retries++ < 3) { /* Allow 3 retries */
                    400:                        hdcstart(sc, bp);
                    401:                        return;
                    402:                }
                    403:                printf("%s: failed, status 0x%x\n",
                    404:                    sc->sc_dev.dv_xname, sc->sc_status);
                    405:                hdc_readregs(sc);
                    406:                for (i = 0; i < 10; i++)
                    407:                        printf("%i: %x\n", i, g[i]);
                    408:                bp->b_flags |= B_ERROR;
                    409:                bp->b_error = ENXIO;
                    410:                bp->b_resid = bp->b_bcount;
                    411:                biodone(bp);
                    412:                vsbus_dma_intr();
                    413:                return;
                    414:        }
                    415:
                    416:        if (bp->b_flags & B_READ) {
                    417:                vsbus_copytoproc(bp->b_proc, sc->sc_dmabase, sc->sc_bufaddr,
                    418:                    sc->sc_xfer);
                    419:        }
                    420:        sc->sc_diskblk += (sc->sc_xfer/DEV_BSIZE);
                    421:        sc->sc_bytecnt -= sc->sc_xfer;
                    422:        sc->sc_bufaddr += sc->sc_xfer;
                    423:
                    424:        if (sc->sc_bytecnt == 0) { /* Finished transfer */
                    425:                biodone(bp);
                    426:                vsbus_dma_intr();
                    427:        } else
                    428:                hdcstart(sc, bp);
                    429: }
                    430:
                    431: /*
                    432:  *
                    433:  */
                    434: void
                    435: hdstrategy(struct buf *bp)
                    436: {
                    437:        struct hdsoftc *hd;
                    438:        struct hdcsoftc *sc;
                    439:        struct disklabel *lp;
                    440:        int unit, s;
                    441:
                    442:        unit = DISKUNIT(bp->b_dev);
                    443:        if (unit > hd_cd.cd_ndevs || (hd = hd_cd.cd_devs[unit]) == NULL) {
                    444:                bp->b_error = ENXIO;
                    445:                bp->b_flags |= B_ERROR;
                    446:                goto done;
                    447:        }
                    448:        sc = (void *)hd->sc_dev.dv_parent;
                    449:
                    450:        lp = hd->sc_disk.dk_label;
                    451:        if ((bounds_check_with_label(bp, hd->sc_disk.dk_label, 1)) <= 0)
                    452:                goto done;
                    453:
                    454:        if (bp->b_bcount == 0)
                    455:                goto done;
                    456:
                    457:        s = splbio();
                    458:        disksort(&sc->sc_buf_queue, bp);
                    459:        if (inq == 0) {
                    460:                inq = 1;
                    461:                vsbus_dma_start(&sc->sc_vd);
                    462:        }
                    463:        splx(s);
                    464:        return;
                    465:
                    466: done:
                    467:        s = splbio();
                    468:        biodone(bp);
                    469:        splx(s);
                    470: }
                    471:
                    472: void
                    473: hdc_qstart(void *arg)
                    474: {
                    475:        struct hdcsoftc *sc = arg;
                    476:        struct buf *dp;
                    477:
                    478:        inq = 0;
                    479:
                    480:        hdcstart(sc, NULL);
                    481:        dp = &sc->sc_buf_queue;
                    482:        if (dp->b_actf != NULL) {
                    483:                vsbus_dma_start(&sc->sc_vd); /* More to go */
                    484:                inq = 1;
                    485:        }
                    486: }
                    487:
                    488: void
                    489: hdcstart(struct hdcsoftc *sc, struct buf *ob)
                    490: {
                    491:        struct hdc9224_UDCreg *p = &sc->sc_creg;
                    492:        struct disklabel *lp;
                    493:        struct hdsoftc *hd;
                    494:        struct buf *dp, *bp;
                    495:        int cn, sn, tn, blks;
                    496:        volatile char ch;
                    497:        daddr64_t bn;
                    498:
                    499:        splassert(IPL_BIO);
                    500:
                    501:        if (sc->sc_active)
                    502:                return; /* Already doing something */
                    503:
                    504:        if (ob == NULL) {
                    505:                dp = &sc->sc_buf_queue;
                    506:                if ((bp = dp->b_actf) == NULL)
                    507:                        return; /* Nothing to do */
                    508:
                    509:                dp->b_actf = bp->b_actf;
                    510:                sc->sc_bufaddr = bp->b_data;
                    511:                sc->sc_bytecnt = bp->b_bcount;
                    512:                sc->sc_retries = 0;
                    513:                bp->b_resid = 0;
                    514:        } else
                    515:                bp = ob;
                    516:
                    517:        hd = hd_cd.cd_devs[DISKUNIT(bp->b_dev)];
                    518:        lp = hd->sc_disk.dk_label;
                    519:        hdc_hdselect(sc, hd->sc_drive);
                    520:        sc->sc_active = bp;
                    521:
                    522:        if (ob == NULL) {
                    523:                sc->sc_diskblk = bp->b_blkno +
                    524:                    DL_GETPOFFSET(&lp->d_partitions[DISKPART(bp->b_dev)]);
                    525:        }
                    526:        bn = sc->sc_diskblk;
                    527:
                    528:         if (bn != 0) {
                    529:                 cn = bn / lp->d_secpercyl;
                    530:                 sn = bn % lp->d_secpercyl;
                    531:                 tn = sn / lp->d_nsectors;
                    532:                 sn = sn % lp->d_nsectors;
                    533:         } else
                    534:                 cn = sn = tn = 0;
                    535:
                    536:        cn++; /* first cylinder is reserved */
                    537:
                    538:        bzero(p, sizeof(struct hdc9224_UDCreg));
                    539:
                    540:        /*
                    541:         * Tricky thing: the controller itself only increases the sector
                    542:         * number, not the track or cylinder number. Therefore the driver
                    543:         * is not allowed to have transfers that crosses track boundaries.
                    544:         */
                    545:        blks = sc->sc_bytecnt / DEV_BSIZE;
                    546:        if ((sn + blks) > lp->d_nsectors)
                    547:                blks = lp->d_nsectors - sn;
                    548:
                    549:        p->udc_dsect = sn;
                    550:        p->udc_dcyl = cn & 0xff;
                    551:        p->udc_dhead = ((cn >> 4) & 0x70) | tn;
                    552:        p->udc_scnt = blks;
                    553:
                    554:        p->udc_rtcnt = UDC_RC_RTRYCNT;
                    555:        p->udc_mode = UDC_MD_HDD;
                    556:        p->udc_term = UDC_TC_CRCPRE|UDC_TC_INTDONE|UDC_TC_TDELDAT|UDC_TC_TWRFLT;
                    557:        hdc_writeregs(sc);
                    558:
                    559:        /* Count up vars */
                    560:        sc->sc_xfer = blks * DEV_BSIZE;
                    561:
                    562:        ch = HDC_RSTAT; /* Avoid pending interrupts */
                    563:        WAIT;
                    564:        vsbus_clrintr(sc->sc_intbit); /* Clear pending int's */
                    565:
                    566:        if (bp->b_flags & B_READ) {
                    567:                HDC_WCMD(DKC_CMD_READ_HDD);
                    568:        } else {
                    569:                vsbus_copyfromproc(bp->b_proc, sc->sc_bufaddr, sc->sc_dmabase,
                    570:                    sc->sc_xfer);
                    571:                HDC_WCMD(DKC_CMD_WRITE_HDD);
                    572:        }
                    573: }
                    574:
                    575: void
                    576: hd_readgeom(struct hdcsoftc *sc, struct hdsoftc *hd)
                    577: {
                    578:        struct hdc9224_UDCreg *p = &sc->sc_creg;
                    579:
                    580:        hdc_hdselect(sc, hd->sc_drive);         /* select drive right now */
                    581:
                    582:        bzero(p, sizeof(struct hdc9224_UDCreg));
                    583:
                    584:        p->udc_scnt  = 1;
                    585:        p->udc_rtcnt = UDC_RC_RTRYCNT;
                    586:        p->udc_mode  = UDC_MD_HDD;
                    587:        p->udc_term  = UDC_TC_CRCPRE|UDC_TC_INTDONE|UDC_TC_TDELDAT|UDC_TC_TWPROT;
                    588:        hdc_writeregs(sc);
                    589:        sc->sc_status = 0;
                    590:        HDC_WCMD(DKC_CMD_READ_HDD|2);
                    591:        while ((sc->sc_status & DKC_ST_INTPEND) == 0)
                    592:                ;
                    593:        bcopy(sc->sc_dmabase, &hd->sc_xbn, sizeof(struct hdgeom));
                    594: }
                    595:
                    596: #ifdef HDDEBUG
                    597: /*
                    598:  * display the contents of the on-disk geometry structure
                    599:  */
                    600: void
                    601: hdc_printgeom(p)
                    602:        struct hdgeom *p;
                    603: {
                    604:        printf("**DiskData**     XBNs: %ld, DBNs: %ld, LBNs: %ld, RBNs: %ld\n",
                    605:            p->xbn_count, p->dbn_count, p->lbn_count, p->rbn_count);
                    606:        printf("sec/track: %d, tracks: %d, cyl: %d, precomp/reduced: %d/%d\n",
                    607:            p->nspt, p->ntracks, p->ncylinders, p->precomp, p->reduced);
                    608:        printf("seek-rate: %d, crc/eec: %s, RCT: %d, RCT-copies: %d\n",
                    609:            p->seek_rate, p->crc_eec?"EEC":"CRC", p->rct, p->rct_ncopies);
                    610:        printf("media-ID: %lx, interleave: %d, headskew: %d, cylskew: %d\n",
                    611:            p->media_id, p->interleave, p->headskew, p->cylskew);
                    612:        printf("gap0: %d, gap1: %d, gap2: %d, gap3: %d, sync-value: %d\n",
                    613:            p->gap0_size, p->gap1_size, p->gap2_size, p->gap3_size,
                    614:            p->sync_value);
                    615: }
                    616: #endif
                    617:
                    618: /*
                    619:  * Return the size of a partition, if known, or -1 if not.
                    620:  */
                    621: daddr64_t
                    622: hdsize(dev_t dev)
                    623: {
                    624:        struct hdsoftc *hd;
                    625:        int unit = DISKUNIT(dev);
                    626:        int size;
                    627:
                    628:        if (unit >= hd_cd.cd_ndevs || hd_cd.cd_devs[unit] == 0)
                    629:                return -1;
                    630:        hd = hd_cd.cd_devs[unit];
                    631:        size = DL_GETPSIZE(&hd->sc_disk.dk_label->d_partitions[DISKPART(dev)]) *
                    632:            (hd->sc_disk.dk_label->d_secsize / DEV_BSIZE);
                    633:
                    634:        return (size);
                    635: }
                    636:
                    637: /*
                    638:  *
                    639:  */
                    640: int
                    641: hdopen(dev_t dev, int flag, int fmt, struct proc *p)
                    642: {
                    643:        struct hdsoftc *hd;
                    644:        int unit, part;
                    645:
                    646:        unit = DISKUNIT(dev);
                    647:        if (unit >= hd_cd.cd_ndevs)
                    648:                return ENXIO;
                    649:        hd = hd_cd.cd_devs[unit];
                    650:        if (hd == 0)
                    651:                return ENXIO;
                    652:
                    653:        part = DISKPART(dev);
                    654:        if (part >= hd->sc_disk.dk_label->d_npartitions)
                    655:                return ENXIO;
                    656:
                    657:        switch (fmt) {
                    658:        case S_IFCHR:
                    659:                hd->sc_disk.dk_copenmask |= (1 << part);
                    660:                break;
                    661:        case S_IFBLK:
                    662:                hd->sc_disk.dk_bopenmask |= (1 << part);
                    663:                break;
                    664:        }
                    665:        hd->sc_disk.dk_openmask =
                    666:            hd->sc_disk.dk_copenmask | hd->sc_disk.dk_bopenmask;
                    667:
                    668:        return 0;
                    669: }
                    670:
                    671: /*
                    672:  *
                    673:  */
                    674: int
                    675: hdclose(dev_t dev, int flag, int fmt, struct proc *p)
                    676: {
                    677:        struct hdsoftc *hd;
                    678:        int part;
                    679:
                    680:        hd = hd_cd.cd_devs[DISKUNIT(dev)];
                    681:        part = DISKPART(dev);
                    682:
                    683:        switch (fmt) {
                    684:        case S_IFCHR:
                    685:                hd->sc_disk.dk_copenmask &= ~(1 << part);
                    686:                break;
                    687:        case S_IFBLK:
                    688:                hd->sc_disk.dk_bopenmask &= ~(1 << part);
                    689:                break;
                    690:        }
                    691:        hd->sc_disk.dk_openmask =
                    692:            hd->sc_disk.dk_copenmask | hd->sc_disk.dk_bopenmask;
                    693:
                    694:        return (0);
                    695: }
                    696:
                    697: /*
                    698:  *
                    699:  */
                    700: int
                    701: hdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
                    702: {
                    703:        struct hdsoftc *hd = hd_cd.cd_devs[DISKUNIT(dev)];
                    704:        struct disklabel *lp = hd->sc_disk.dk_label;
                    705:        int err = 0;
                    706:
                    707:        switch (cmd) {
                    708:        case DIOCGDINFO:
                    709:                bcopy(lp, addr, sizeof (struct disklabel));
                    710:                break;
                    711:
                    712:        case DIOCGPART:
                    713:                ((struct partinfo *)addr)->disklab = lp;
                    714:                ((struct partinfo *)addr)->part =
                    715:                  &lp->d_partitions[DISKPART(dev)];
                    716:                break;
                    717:
                    718:        case DIOCWDINFO:
                    719:        case DIOCSDINFO:
                    720:                if ((flag & FWRITE) == 0)
                    721:                        return EBADF;
                    722:                else
                    723:                        err = (cmd == DIOCSDINFO ?
                    724:                            setdisklabel(lp, (struct disklabel *)addr, 0) :
                    725:                            writedisklabel(dev, hdstrategy, lp));
                    726:                break;
                    727:
                    728:        case DIOCWLABEL:
                    729:                if ((flag & FWRITE) == 0)
                    730:                        err = EBADF;
                    731:                break;
                    732:
                    733:        default:
                    734:                err = ENOTTY;
                    735:                break;
                    736:        }
                    737:        return err;
                    738: }
                    739:
                    740: /*
                    741:  *
                    742:  */
                    743: int
                    744: hdread(dev_t dev, struct uio *uio, int flag)
                    745: {
                    746:        return (physio(hdstrategy, NULL, dev, B_READ, minphys, uio));
                    747: }
                    748:
                    749: /*
                    750:  *
                    751:  */
                    752: int
                    753: hdwrite(dev_t dev, struct uio *uio, int flag)
                    754: {
                    755:        return (physio(hdstrategy, NULL, dev, B_WRITE, minphys, uio));
                    756: }
                    757:
                    758: /*
                    759:  *
                    760:  */
                    761: int
                    762: hddump(dev_t dev, daddr64_t daddr, caddr_t addr, size_t size)
                    763: {
                    764:        return 0;
                    765: }
                    766:
                    767: /*
                    768:  * we have to wait 0.7 usec between two accesses to any of the
                    769:  * dkc-registers, on a VS2000 with 1 MIPS, this is roughly one
                    770:  * instruction. Thus the loop-overhead will be enough...
                    771:  */
                    772: void
                    773: hdc_readregs(struct hdcsoftc *sc)
                    774: {
                    775:        int i;
                    776:        char *p;
                    777:
                    778:        HDC_WCMD(DKC_CMD_SETREGPTR);
                    779:        WAIT;
                    780:        p = (void *)&sc->sc_sreg;
                    781:        for (i = 0; i < 10; i++) {
                    782:                *p++ = HDC_RREG;        /* dkc_reg auto-increments */
                    783:                WAIT;
                    784:        }
                    785: }
                    786:
                    787: void
                    788: hdc_writeregs(struct hdcsoftc *sc)
                    789: {
                    790:        int i;
                    791:        char *p;
                    792:
                    793:        HDC_WCMD(DKC_CMD_SETREGPTR);
                    794:        p = (void *)&sc->sc_creg;
                    795:        for (i = 0; i < 10; i++) {
                    796:                HDC_WREG(*p++); /* dkc_reg auto-increments */
                    797:                WAIT;
                    798:        }
                    799: }
                    800:
                    801: /*
                    802:  * hdc_command() issues a command and polls the intreq-register
                    803:  * to find when command has completed
                    804:  */
                    805: int
                    806: hdc_command(struct hdcsoftc *sc, int cmd)
                    807: {
                    808:        hdc_writeregs(sc);              /* write the prepared registers */
                    809:        HDC_WCMD(cmd);
                    810:        WAIT;
                    811:        return (0);
                    812: }
                    813:
                    814: int
                    815: hdc_hdselect(struct hdcsoftc *sc, int unit)
                    816: {
                    817:        struct hdc9224_UDCreg *p = &sc->sc_creg;
                    818:        int error;
                    819:
                    820:        /*
                    821:         * bring "creg" in some known-to-work state and
                    822:         * select the drive with the DRIVE SELECT command.
                    823:         */
                    824:        bzero(p, sizeof(struct hdc9224_UDCreg));
                    825:
                    826:        p->udc_rtcnt = UDC_RC_HDD_READ;
                    827:        p->udc_mode  = UDC_MD_HDD;
                    828:        p->udc_term  = UDC_TC_HDD;
                    829:
                    830:        error = hdc_command(sc, DKC_CMD_DRSEL_HDD | unit);
                    831:
                    832:        return (error);
                    833: }
                    834:
                    835: void
                    836: hdmakelabel(struct disklabel *dl, struct hdgeom *g)
                    837: {
                    838:        int n, p = 0;
                    839:
                    840:        dl->d_bbsize = BBSIZE;
                    841:        dl->d_sbsize = SBSIZE;
                    842:        dl->d_typename[p++] = MSCP_MID_CHAR(2, g->media_id);
                    843:        dl->d_typename[p++] = MSCP_MID_CHAR(1, g->media_id);
                    844:        if (MSCP_MID_ECH(0, g->media_id))
                    845:                dl->d_typename[p++] = MSCP_MID_CHAR(0, g->media_id);
                    846:        n = MSCP_MID_NUM(g->media_id);
                    847:        if (n > 99) {
                    848:                dl->d_typename[p++] = '1';
                    849:                n -= 100;
                    850:        }
                    851:        if (n > 9) {
                    852:                dl->d_typename[p++] = (n / 10) + '0';
                    853:                n %= 10;
                    854:        }
                    855:        dl->d_typename[p++] = n + '0';
                    856:        dl->d_typename[p] = 0;
                    857:        dl->d_type = DTYPE_MSCP; /* XXX - what to use here??? */
                    858:        dl->d_rpm = 3600;
                    859:        dl->d_secsize = DEV_BSIZE;
                    860:
                    861:        DL_SETDSIZE(dl, g->lbn_count);
                    862:        dl->d_nsectors = g->nspt;
                    863:        dl->d_ntracks = g->ntracks;
                    864:        dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
                    865:        dl->d_ncylinders = DL_GETDSIZE(dl) / dl->d_secpercyl;
                    866:
                    867:        dl->d_npartitions = MAXPARTITIONS;
                    868:        DL_SETPSIZE(&dl->d_partitions[0], DL_GETDSIZE(dl));
                    869:        DL_SETPSIZE(&dl->d_partitions[2], DL_GETDSIZE(dl));
                    870:
                    871:        DL_SETPOFFSET(&dl->d_partitions[0], 0);
                    872:        DL_SETPOFFSET(&dl->d_partitions[2], 0);
                    873:        dl->d_interleave = dl->d_headswitch = 1;
                    874:        dl->d_version = 1;
                    875:        dl->d_magic = dl->d_magic2 = DISKMAGIC;
                    876:        dl->d_checksum = dkcksum(dl);
                    877: }

CVSweb