[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     ! 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