Home | History | Annotate | Line # | Download | only in qbus
rl.c revision 1.9.4.1
      1  1.9.4.1     fvdl /*	$NetBSD: rl.c,v 1.9.4.1 2001/10/10 11:56:59 fvdl Exp $	*/
      2      1.1    ragge 
      3      1.1    ragge /*
      4      1.1    ragge  * Copyright (c) 2000 Ludd, University of Lule}, Sweden. All rights reserved.
      5      1.1    ragge  *
      6      1.1    ragge  * Redistribution and use in source and binary forms, with or without
      7      1.1    ragge  * modification, are permitted provided that the following conditions
      8      1.1    ragge  * are met:
      9      1.1    ragge  * 1. Redistributions of source code must retain the above copyright
     10      1.1    ragge  *    notice, this list of conditions and the following disclaimer.
     11      1.1    ragge  * 2. Redistributions in binary form must reproduce the above copyright
     12      1.1    ragge  *    notice, this list of conditions and the following disclaimer in the
     13      1.1    ragge  *    documentation and/or other materials provided with the distribution.
     14      1.1    ragge  * 3. All advertising materials mentioning features or use of this software
     15      1.1    ragge  *    must display the following acknowledgement:
     16      1.1    ragge  *      This product includes software developed at Ludd, University of
     17      1.1    ragge  *      Lule}, Sweden and its contributors.
     18      1.1    ragge  * 4. The name of the author may not be used to endorse or promote products
     19      1.1    ragge  *    derived from this software without specific prior written permission
     20      1.1    ragge  *
     21      1.1    ragge  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22      1.1    ragge  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23      1.1    ragge  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24      1.1    ragge  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25      1.1    ragge  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26      1.1    ragge  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27      1.1    ragge  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28      1.1    ragge  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29      1.1    ragge  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30      1.1    ragge  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31      1.1    ragge  */
     32      1.1    ragge 
     33      1.1    ragge /*
     34      1.1    ragge  * RL11/RLV11/RLV12 disk controller driver and
     35      1.1    ragge  * RL01/RL02 disk device driver.
     36      1.1    ragge  *
     37      1.1    ragge  * TODO:
     38      1.1    ragge  *	Handle disk errors more gracefully
     39      1.1    ragge  *	Do overlapping seeks on multiple drives
     40      1.1    ragge  *
     41      1.1    ragge  * Implementation comments:
     42      1.1    ragge  *
     43      1.1    ragge  */
     44      1.1    ragge 
     45      1.1    ragge #include <sys/param.h>
     46      1.1    ragge #include <sys/device.h>
     47      1.1    ragge #include <sys/systm.h>
     48      1.1    ragge #include <sys/conf.h>
     49      1.1    ragge #include <sys/disk.h>
     50      1.1    ragge #include <sys/disklabel.h>
     51      1.1    ragge #include <sys/buf.h>
     52      1.1    ragge #include <sys/stat.h>
     53      1.1    ragge #include <sys/dkio.h>
     54      1.1    ragge #include <sys/fcntl.h>
     55  1.9.4.1     fvdl #include <sys/vnode.h>
     56      1.1    ragge 
     57      1.1    ragge #include <ufs/ufs/dinode.h>
     58      1.1    ragge #include <ufs/ffs/fs.h>
     59      1.1    ragge 
     60      1.1    ragge #include <machine/bus.h>
     61      1.1    ragge 
     62      1.1    ragge #include <dev/qbus/ubavar.h>
     63      1.1    ragge #include <dev/qbus/rlreg.h>
     64      1.1    ragge 
     65      1.1    ragge #include "ioconf.h"
     66      1.1    ragge #include "locators.h"
     67      1.1    ragge 
     68      1.1    ragge struct rlc_softc {
     69      1.1    ragge 	struct device sc_dev;
     70      1.4     matt 	struct evcnt sc_intrcnt;
     71      1.1    ragge 	bus_space_tag_t sc_iot;
     72      1.1    ragge 	bus_space_handle_t sc_ioh;
     73      1.1    ragge 	bus_dma_tag_t sc_dmat;
     74      1.1    ragge 	bus_dmamap_t sc_dmam;
     75      1.1    ragge 	struct buf_queue sc_q;		/* Queue of waiting bufs */
     76      1.1    ragge 	struct buf *sc_active;		/* Currently active buf */
     77      1.1    ragge 	caddr_t sc_bufaddr;		/* Current in-core address */
     78      1.1    ragge 	int sc_diskblk;			/* Current block on disk */
     79      1.1    ragge 	int sc_bytecnt;			/* How much left to transfer */
     80      1.1    ragge };
     81      1.1    ragge 
     82      1.1    ragge struct rl_softc {
     83      1.1    ragge 	struct device rc_dev;
     84      1.1    ragge 	struct disk rc_disk;
     85      1.1    ragge 	int rc_state;
     86      1.1    ragge 	int rc_head;
     87      1.1    ragge 	int rc_cyl;
     88      1.1    ragge 	int rc_hwid;
     89      1.1    ragge };
     90      1.1    ragge 
     91      1.1    ragge static	int rlcmatch(struct device *, struct cfdata *, void *);
     92      1.1    ragge static	void rlcattach(struct device *, struct device *, void *);
     93      1.1    ragge static	int rlcprint(void *, const char *);
     94      1.1    ragge static	void rlcintr(void *);
     95      1.1    ragge static	int rlmatch(struct device *, struct cfdata *, void *);
     96      1.1    ragge static	void rlattach(struct device *, struct device *, void *);
     97      1.1    ragge static	void rlcstart(struct rlc_softc *, struct buf *);
     98      1.1    ragge static	void waitcrdy(struct rlc_softc *);
     99      1.2    ragge static	void rlreset(struct device *);
    100      1.1    ragge cdev_decl(rl);
    101      1.1    ragge bdev_decl(rl);
    102      1.1    ragge 
    103      1.1    ragge struct cfattach rlc_ca = {
    104      1.1    ragge 	sizeof(struct rlc_softc), rlcmatch, rlcattach
    105      1.1    ragge };
    106      1.1    ragge 
    107      1.1    ragge struct cfattach rl_ca = {
    108      1.1    ragge 	sizeof(struct rl_softc), rlmatch, rlattach
    109      1.1    ragge };
    110      1.1    ragge 
    111      1.1    ragge struct rlc_attach_args {
    112      1.1    ragge 	u_int16_t type;
    113      1.1    ragge 	int hwid;
    114      1.1    ragge };
    115      1.1    ragge 
    116      1.1    ragge #define	MAXRLXFER (RL_BPS * RL_SPT)
    117      1.1    ragge #define	RLMAJOR	14
    118      1.1    ragge 
    119      1.1    ragge #define	RL_WREG(reg, val) \
    120      1.1    ragge 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, (reg), (val))
    121      1.1    ragge #define RL_RREG(reg) \
    122      1.1    ragge 	bus_space_read_2(sc->sc_iot, sc->sc_ioh, (reg))
    123      1.1    ragge 
    124      1.1    ragge void
    125      1.1    ragge waitcrdy(struct rlc_softc *sc)
    126      1.1    ragge {
    127      1.1    ragge 	int i;
    128      1.1    ragge 
    129      1.1    ragge 	for (i = 0; i < 1000; i++) {
    130      1.1    ragge 		DELAY(10000);
    131      1.1    ragge 		if (RL_RREG(RL_CS) & RLCS_CRDY)
    132      1.1    ragge 			return;
    133      1.1    ragge 	}
    134      1.1    ragge 	printf("%s: never got ready\n", sc->sc_dev.dv_xname); /* ?panic? */
    135      1.1    ragge }
    136      1.1    ragge 
    137      1.1    ragge int
    138      1.1    ragge rlcprint(void *aux, const char *name)
    139      1.1    ragge {
    140      1.1    ragge 	struct rlc_attach_args *ra = aux;
    141      1.1    ragge 
    142      1.1    ragge 	if (name)
    143      1.1    ragge 		printf("RL0%d at %s", ra->type & RLMP_DT ? '2' : '1', name);
    144      1.1    ragge 	printf(" drive %d", ra->hwid);
    145      1.1    ragge 	return UNCONF;
    146      1.1    ragge }
    147      1.1    ragge 
    148      1.1    ragge /*
    149      1.1    ragge  * Force the controller to interrupt.
    150      1.1    ragge  */
    151      1.1    ragge int
    152      1.1    ragge rlcmatch(struct device *parent, struct cfdata *cf, void *aux)
    153      1.1    ragge {
    154      1.1    ragge 	struct uba_attach_args *ua = aux;
    155      1.1    ragge 	struct rlc_softc ssc, *sc = &ssc;
    156      1.1    ragge 	int i;
    157      1.1    ragge 
    158      1.1    ragge 	sc->sc_iot = ua->ua_iot;
    159      1.1    ragge 	sc->sc_ioh = ua->ua_ioh;
    160      1.1    ragge 	/* Force interrupt by issuing a "Get Status" command */
    161      1.1    ragge 	RL_WREG(RL_DA, RLDA_GS);
    162      1.1    ragge 	RL_WREG(RL_CS, RLCS_GS|RLCS_IE);
    163      1.1    ragge 
    164      1.1    ragge 	for (i = 0; i < 100; i++) {
    165      1.1    ragge 		DELAY(100000);
    166      1.1    ragge 		if (RL_RREG(RL_CS) & RLCS_CRDY)
    167      1.1    ragge 			return 1;
    168      1.1    ragge 	}
    169      1.1    ragge 	return 0;
    170      1.1    ragge }
    171      1.1    ragge 
    172      1.1    ragge void
    173      1.1    ragge rlcattach(struct device *parent, struct device *self, void *aux)
    174      1.1    ragge {
    175      1.1    ragge 	struct rlc_softc *sc = (struct rlc_softc *)self;
    176      1.1    ragge 	struct uba_attach_args *ua = aux;
    177      1.1    ragge 	struct rlc_attach_args ra;
    178      1.1    ragge 	int i, error;
    179      1.1    ragge 
    180      1.1    ragge 	sc->sc_iot = ua->ua_iot;
    181      1.1    ragge 	sc->sc_ioh = ua->ua_ioh;
    182      1.1    ragge 	sc->sc_dmat = ua->ua_dmat;
    183      1.4     matt 	uba_intr_establish(ua->ua_icookie, ua->ua_cvec,
    184      1.4     matt 		rlcintr, sc, &sc->sc_intrcnt);
    185      1.5     matt 	evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, ua->ua_evcnt,
    186      1.5     matt 		sc->sc_dev.dv_xname, "intr");
    187      1.1    ragge 	printf("\n");
    188      1.1    ragge 
    189      1.1    ragge 	/*
    190      1.1    ragge 	 * The RL11 can only have one transfer going at a time,
    191      1.1    ragge 	 * and max transfer size is one track, so only one dmamap
    192      1.1    ragge 	 * is needed.
    193      1.1    ragge 	 */
    194      1.1    ragge 	error = bus_dmamap_create(sc->sc_dmat, MAXRLXFER, 1, MAXRLXFER, 0,
    195      1.1    ragge 	    BUS_DMA_ALLOCNOW, &sc->sc_dmam);
    196      1.1    ragge 	if (error) {
    197      1.1    ragge 		printf(": Failed to allocate DMA map, error %d\n", error);
    198      1.1    ragge 		return;
    199      1.1    ragge 	}
    200      1.1    ragge 	BUFQ_INIT(&sc->sc_q);
    201      1.1    ragge 	for (i = 0; i < RL_MAXDPC; i++) {
    202      1.1    ragge 		waitcrdy(sc);
    203      1.1    ragge 		RL_WREG(RL_DA, RLDA_GS|RLDA_RST);
    204      1.1    ragge 		RL_WREG(RL_CS, RLCS_GS|(i << RLCS_USHFT));
    205      1.1    ragge 		waitcrdy(sc);
    206      1.1    ragge 		ra.type = RL_RREG(RL_MP);
    207      1.1    ragge 		ra.hwid = i;
    208      1.1    ragge 		if ((RL_RREG(RL_CS) & RLCS_ERR) == 0)
    209      1.1    ragge 			config_found(&sc->sc_dev, &ra, rlcprint);
    210      1.1    ragge 	}
    211      1.1    ragge }
    212      1.1    ragge 
    213      1.1    ragge int
    214      1.1    ragge rlmatch(struct device *parent, struct cfdata *cf, void *aux)
    215      1.1    ragge {
    216      1.1    ragge 	struct rlc_attach_args *ra = aux;
    217      1.1    ragge 
    218      1.1    ragge 	if (cf->cf_loc[RLCCF_DRIVE] != RLCCF_DRIVE_DEFAULT &&
    219      1.1    ragge 	    cf->cf_loc[RLCCF_DRIVE] != ra->hwid)
    220      1.1    ragge 		return 0;
    221      1.1    ragge 	return 1;
    222      1.1    ragge }
    223      1.1    ragge 
    224      1.1    ragge void
    225      1.1    ragge rlattach(struct device *parent, struct device *self, void *aux)
    226      1.1    ragge {
    227      1.1    ragge 	struct rl_softc *rc = (struct rl_softc *)self;
    228      1.1    ragge 	struct rlc_attach_args *ra = aux;
    229      1.1    ragge 	struct disklabel *dl;
    230      1.1    ragge 
    231      1.2    ragge 	uba_reset_establish(rlreset, self);
    232      1.2    ragge 
    233      1.1    ragge 	rc->rc_hwid = ra->hwid;
    234      1.1    ragge 	rc->rc_disk.dk_name = rc->rc_dev.dv_xname;
    235      1.1    ragge 	disk_attach(&rc->rc_disk);
    236      1.1    ragge 	dl = rc->rc_disk.dk_label;
    237      1.1    ragge 	dl->d_npartitions = 3;
    238      1.1    ragge 	strcpy(dl->d_typename, "RL01");
    239      1.1    ragge 	if (ra->type & RLMP_DT)
    240      1.1    ragge 		dl->d_typename[3] = '2';
    241      1.1    ragge 	dl->d_secsize = DEV_BSIZE; /* XXX - wrong, but OK for now */
    242      1.1    ragge 	dl->d_nsectors = RL_SPT/2;
    243      1.1    ragge 	dl->d_ntracks = RL_SPD;
    244      1.1    ragge 	dl->d_ncylinders = ra->type & RLMP_DT ? RL_TPS02 : RL_TPS01;
    245      1.1    ragge 	dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
    246      1.1    ragge 	dl->d_secperunit = dl->d_ncylinders * dl->d_secpercyl;
    247      1.1    ragge 	dl->d_partitions[0].p_size = dl->d_partitions[2].p_size =
    248      1.1    ragge 	    dl->d_secperunit;
    249      1.1    ragge 	dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0;
    250      1.1    ragge 	dl->d_interleave = dl->d_headswitch = 1;
    251      1.1    ragge 	dl->d_bbsize = BBSIZE;
    252      1.1    ragge 	dl->d_sbsize = SBSIZE;
    253      1.1    ragge 	dl->d_rpm = 2400;
    254      1.1    ragge 	dl->d_type = DTYPE_DEC;
    255      1.1    ragge 	printf(": %s\n", dl->d_typename);
    256      1.1    ragge }
    257      1.1    ragge 
    258      1.1    ragge int
    259  1.9.4.1     fvdl rlopen(struct vnode *devvp, int flag, int fmt, struct proc *p)
    260      1.1    ragge {
    261      1.1    ragge 	int part, unit, mask;
    262      1.1    ragge 	struct disklabel *dl;
    263      1.1    ragge 	struct rlc_softc *sc;
    264      1.1    ragge 	struct rl_softc *rc;
    265      1.1    ragge 	char *msg;
    266  1.9.4.1     fvdl 	dev_t dev;
    267  1.9.4.1     fvdl 
    268      1.1    ragge 	/*
    269      1.1    ragge 	 * Make sure this is a reasonable open request.
    270      1.1    ragge 	 */
    271  1.9.4.1     fvdl 	dev = vdev_rdev(devvp);
    272      1.1    ragge 	unit = DISKUNIT(dev);
    273      1.1    ragge 	if (unit >= rl_cd.cd_ndevs)
    274      1.1    ragge 		return ENXIO;
    275      1.1    ragge 	rc = rl_cd.cd_devs[unit];
    276      1.1    ragge 	if (rc == 0)
    277      1.1    ragge 		return ENXIO;
    278      1.1    ragge 
    279  1.9.4.1     fvdl 	vdev_setprivdata(devvp, rc);
    280  1.9.4.1     fvdl 
    281      1.1    ragge 	sc = (struct rlc_softc *)rc->rc_dev.dv_parent;
    282      1.1    ragge 	/* XXX - check that the disk actually is useable */
    283      1.1    ragge 	/*
    284      1.1    ragge 	 * If this is the first open; read in where on the disk we are.
    285      1.1    ragge 	 */
    286      1.1    ragge 	dl = rc->rc_disk.dk_label;
    287      1.1    ragge 	if (rc->rc_state == DK_CLOSED) {
    288      1.1    ragge 		u_int16_t mp;
    289      1.1    ragge 		RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
    290      1.1    ragge 		waitcrdy(sc);
    291      1.1    ragge 		mp = RL_RREG(RL_MP);
    292      1.1    ragge 		rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
    293      1.1    ragge 		rc->rc_cyl = (mp >> 7) & 0777;
    294      1.1    ragge 		rc->rc_state = DK_OPEN;
    295      1.1    ragge 		/* Get disk label */
    296      1.1    ragge 		printf("%s: ", rc->rc_dev.dv_xname);
    297  1.9.4.1     fvdl 		if ((msg = readdisklabel(devvp, rlstrategy, dl, NULL)))
    298      1.1    ragge 			printf("%s: ", msg);
    299      1.1    ragge 		printf("size %d sectors\n", dl->d_secperunit);
    300      1.1    ragge 	}
    301      1.1    ragge 	part = DISKPART(dev);
    302      1.1    ragge 	if (part >= dl->d_npartitions)
    303      1.1    ragge 		return ENXIO;
    304      1.1    ragge 
    305      1.1    ragge 	mask = 1 << part;
    306      1.1    ragge 	switch (fmt) {
    307      1.1    ragge 	case S_IFCHR:
    308      1.1    ragge 		rc->rc_disk.dk_copenmask |= mask;
    309      1.1    ragge 		break;
    310      1.1    ragge 	case S_IFBLK:
    311      1.1    ragge 		rc->rc_disk.dk_bopenmask |= mask;
    312      1.1    ragge 		break;
    313      1.1    ragge 	}
    314      1.1    ragge 	rc->rc_disk.dk_openmask |= mask;
    315  1.9.4.1     fvdl 
    316      1.1    ragge 	return 0;
    317      1.1    ragge }
    318      1.1    ragge 
    319      1.1    ragge int
    320  1.9.4.1     fvdl rlclose(struct vnode *devvp, int flag, int fmt, struct proc *p)
    321      1.1    ragge {
    322  1.9.4.1     fvdl 	struct rl_softc *rc = vdev_privdata(devvp);
    323  1.9.4.1     fvdl 	int mask = (1 << DISKPART(vdev_rdev(devvp)));
    324      1.1    ragge 
    325      1.1    ragge 	switch (fmt) {
    326      1.1    ragge 	case S_IFCHR:
    327      1.1    ragge 		rc->rc_disk.dk_copenmask &= ~mask;
    328      1.1    ragge 		break;
    329      1.1    ragge 	case S_IFBLK:
    330      1.1    ragge 		rc->rc_disk.dk_bopenmask &= ~mask;
    331      1.1    ragge 		break;
    332      1.1    ragge 	}
    333      1.1    ragge 	rc->rc_disk.dk_openmask =
    334      1.1    ragge 	    rc->rc_disk.dk_copenmask | rc->rc_disk.dk_bopenmask;
    335      1.1    ragge 
    336      1.1    ragge 	if (rc->rc_disk.dk_openmask == 0)
    337      1.1    ragge 		rc->rc_state = DK_CLOSED; /* May change pack */
    338      1.1    ragge 	return 0;
    339      1.1    ragge }
    340      1.1    ragge 
    341      1.1    ragge void
    342      1.1    ragge rlstrategy(struct buf *bp)
    343      1.1    ragge {
    344      1.1    ragge 	struct disklabel *lp;
    345      1.1    ragge 	struct rlc_softc *sc;
    346      1.1    ragge         struct rl_softc *rc;
    347  1.9.4.1     fvdl         int s, err, part;
    348  1.9.4.1     fvdl 
    349      1.1    ragge         /*
    350      1.1    ragge          * Make sure this is a reasonable drive to use.
    351      1.1    ragge          */
    352  1.9.4.1     fvdl 	rc = vdev_privdata(bp->b_devvp);
    353  1.9.4.1     fvdl         if (rc == NULL) {
    354      1.1    ragge                 bp->b_error = ENXIO;
    355      1.1    ragge                 bp->b_flags |= B_ERROR;
    356      1.1    ragge                 goto done;
    357      1.1    ragge         }
    358      1.1    ragge 	if (rc->rc_state != DK_OPEN) /* How did we end up here at all? */
    359      1.1    ragge 		panic("rlstrategy: state impossible");
    360      1.1    ragge 
    361      1.1    ragge 	lp = rc->rc_disk.dk_label;
    362      1.1    ragge 	if ((err = bounds_check_with_label(bp, lp, 1)) <= 0)
    363      1.1    ragge 		goto done;
    364      1.1    ragge 
    365  1.9.4.1     fvdl 	part = (bp->b_flags & B_DKLABEL) ? RAW_PART :
    366  1.9.4.1     fvdl 	    DISKPART(vdev_rdev(bp->b_devvp));
    367  1.9.4.1     fvdl 
    368      1.1    ragge 	if (bp->b_bcount == 0)
    369      1.1    ragge 		goto done;
    370      1.1    ragge 
    371      1.1    ragge 	bp->b_rawblkno =
    372  1.9.4.1     fvdl 	    bp->b_blkno + lp->d_partitions[part].p_offset;
    373      1.1    ragge 	bp->b_cylinder = bp->b_rawblkno / lp->d_secpercyl;
    374      1.1    ragge 	sc = (struct rlc_softc *)rc->rc_dev.dv_parent;
    375      1.1    ragge 
    376      1.8  thorpej 	s = splbio();
    377      1.1    ragge 	disksort_cylinder(&sc->sc_q, bp);
    378      1.1    ragge 	rlcstart(sc, 0);
    379      1.1    ragge 	splx(s);
    380      1.1    ragge 	return;
    381      1.1    ragge 
    382      1.1    ragge done:	biodone(bp);
    383      1.1    ragge }
    384      1.1    ragge 
    385      1.1    ragge int
    386  1.9.4.1     fvdl rlioctl(struct vnode *devvp, u_long cmd, caddr_t addr, int flag, struct proc *p)
    387      1.1    ragge {
    388  1.9.4.1     fvdl 	struct rl_softc *rc = vdev_privdata(devvp);
    389      1.1    ragge 	struct disklabel *lp = rc->rc_disk.dk_label;
    390      1.1    ragge 	int err = 0;
    391      1.6     fvdl #ifdef __HAVE_OLD_DISKLABEL
    392      1.6     fvdl 	struct disklabel newlabel;
    393      1.6     fvdl #endif
    394      1.1    ragge 
    395      1.1    ragge 	switch (cmd) {
    396      1.1    ragge 	case DIOCGDINFO:
    397      1.1    ragge 		bcopy(lp, addr, sizeof (struct disklabel));
    398      1.1    ragge 		break;
    399      1.1    ragge 
    400      1.6     fvdl #ifdef __HAVE_OLD_DISKLABEL
    401      1.6     fvdl 	case ODIOCGDINFO:
    402      1.6     fvdl 		newlabel = *lp;
    403      1.6     fvdl 		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
    404      1.7     fvdl 			return ENOTTY;
    405      1.6     fvdl 		bcopy(&newlabel, addr, sizeof (struct olddisklabel));
    406      1.6     fvdl 		break;
    407      1.6     fvdl #endif
    408      1.6     fvdl 
    409      1.1    ragge 	case DIOCGPART:
    410      1.1    ragge 		((struct partinfo *)addr)->disklab = lp;
    411      1.1    ragge 		((struct partinfo *)addr)->part =
    412  1.9.4.1     fvdl 		    &lp->d_partitions[DISKPART(vdev_rdev(devvp))];
    413      1.1    ragge 		break;
    414      1.1    ragge 
    415      1.1    ragge 	case DIOCSDINFO:
    416      1.1    ragge 	case DIOCWDINFO:
    417      1.6     fvdl #ifdef __HAVE_OLD_DISKLABEL
    418      1.6     fvdl 	case ODIOCWDINFO:
    419      1.6     fvdl 	case ODIOCSDINFO:
    420      1.6     fvdl #endif
    421      1.6     fvdl 	{
    422      1.6     fvdl 		struct disklabel *tp;
    423      1.6     fvdl 
    424      1.6     fvdl #ifdef __HAVE_OLD_DISKLABEL
    425      1.6     fvdl 		if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
    426      1.6     fvdl 			memset(&newlabel, 0, sizeof newlabel);
    427      1.6     fvdl 			memcpy(&newlabel, addr, sizeof (struct olddisklabel));
    428      1.6     fvdl 			tp = &newlabel;
    429      1.6     fvdl 		} else
    430      1.6     fvdl #endif
    431      1.6     fvdl 		tp = (struct disklabel *)addr;
    432      1.6     fvdl 
    433      1.1    ragge 		if ((flag & FWRITE) == 0)
    434      1.1    ragge 			err = EBADF;
    435      1.1    ragge 		else
    436      1.6     fvdl 			err = ((
    437      1.6     fvdl #ifdef __HAVE_OLD_DISKLABEL
    438      1.6     fvdl 			       cmd == ODIOCSDINFO ||
    439      1.6     fvdl #endif
    440      1.6     fvdl 			       cmd == DIOCSDINFO) ?
    441      1.6     fvdl 			    setdisklabel(lp, tp, 0, 0) :
    442  1.9.4.1     fvdl 			    writedisklabel(devvp, rlstrategy, lp, 0));
    443      1.1    ragge 		break;
    444      1.6     fvdl 	}
    445      1.1    ragge 
    446      1.1    ragge 	case DIOCWLABEL:
    447      1.1    ragge 		if ((flag & FWRITE) == 0)
    448      1.1    ragge 			err = EBADF;
    449      1.1    ragge 		break;
    450      1.1    ragge 
    451      1.1    ragge 	default:
    452      1.1    ragge 		err = ENOTTY;
    453      1.1    ragge 	}
    454      1.1    ragge 	return err;
    455      1.1    ragge }
    456      1.1    ragge 
    457      1.1    ragge int
    458      1.1    ragge rlsize(dev_t dev)
    459      1.1    ragge {
    460      1.1    ragge 	struct disklabel *dl;
    461      1.1    ragge 	struct rl_softc *rc;
    462      1.1    ragge 	int size, unit = DISKUNIT(dev);
    463      1.1    ragge 
    464      1.1    ragge 	if ((unit >= rl_cd.cd_ndevs) || ((rc = rl_cd.cd_devs[unit]) == 0))
    465      1.1    ragge 		return -1;
    466      1.1    ragge 	dl = rc->rc_disk.dk_label;
    467      1.1    ragge 	size = dl->d_partitions[DISKPART(dev)].p_size *
    468      1.1    ragge 	    (dl->d_secsize / DEV_BSIZE);
    469      1.1    ragge 	return size;
    470      1.1    ragge }
    471      1.1    ragge 
    472      1.1    ragge int
    473      1.1    ragge rldump(dev_t dev, daddr_t blkno, caddr_t va, size_t size)
    474      1.1    ragge {
    475      1.1    ragge 	/* Not likely... */
    476      1.1    ragge 	return 0;
    477      1.1    ragge }
    478      1.1    ragge 
    479      1.1    ragge int
    480  1.9.4.1     fvdl rlread(struct vnode *devvp, struct uio *uio, int ioflag)
    481      1.1    ragge {
    482  1.9.4.1     fvdl 	return (physio(rlstrategy, NULL, devvp, B_READ, minphys, uio));
    483      1.1    ragge }
    484      1.1    ragge 
    485      1.1    ragge int
    486  1.9.4.1     fvdl rlwrite(struct vnode *devvp, struct uio *uio, int ioflag)
    487      1.1    ragge {
    488  1.9.4.1     fvdl 	return (physio(rlstrategy, NULL, devvp, B_WRITE, minphys, uio));
    489      1.1    ragge }
    490      1.1    ragge 
    491      1.1    ragge static char *rlerr[] = {
    492      1.1    ragge 	"no",
    493      1.1    ragge 	"operation incomplete",
    494      1.1    ragge 	"read data CRC",
    495      1.1    ragge 	"header CRC",
    496      1.1    ragge 	"data late",
    497      1.1    ragge 	"header not found",
    498      1.1    ragge 	"",
    499      1.1    ragge 	"",
    500      1.9      wiz 	"non-existent memory",
    501      1.1    ragge 	"memory parity error",
    502      1.1    ragge 	"",
    503      1.1    ragge 	"",
    504      1.1    ragge 	"",
    505      1.1    ragge 	"",
    506      1.1    ragge 	"",
    507      1.1    ragge 	"",
    508      1.1    ragge };
    509      1.1    ragge 
    510      1.1    ragge void
    511      1.1    ragge rlcintr(void *arg)
    512      1.1    ragge {
    513      1.1    ragge 	struct rlc_softc *sc = arg;
    514      1.1    ragge 	struct buf *bp;
    515      1.1    ragge 	u_int16_t cs;
    516      1.1    ragge 
    517      1.1    ragge 	bp = sc->sc_active;
    518      1.1    ragge 	if (bp == 0) {
    519      1.1    ragge 		printf("%s: strange interrupt\n", sc->sc_dev.dv_xname);
    520      1.1    ragge 		return;
    521      1.1    ragge 	}
    522      1.1    ragge 	bus_dmamap_unload(sc->sc_dmat, sc->sc_dmam);
    523      1.1    ragge 	sc->sc_active = 0;
    524      1.1    ragge 	cs = RL_RREG(RL_CS);
    525      1.1    ragge 	if (cs & RLCS_ERR) {
    526      1.1    ragge 		int error = (cs & RLCS_ERRMSK) >> 10;
    527      1.1    ragge 
    528      1.1    ragge 		printf("%s: %s\n", sc->sc_dev.dv_xname, rlerr[error]);
    529      1.1    ragge 		bp->b_flags |= B_ERROR;
    530      1.1    ragge 		bp->b_error = EIO;
    531      1.1    ragge 		bp->b_resid = bp->b_bcount;
    532      1.1    ragge 		sc->sc_bytecnt = 0;
    533      1.1    ragge 	}
    534      1.1    ragge 	if (sc->sc_bytecnt == 0) /* Finished transfer */
    535      1.1    ragge 		biodone(bp);
    536      1.1    ragge 	rlcstart(sc, sc->sc_bytecnt ? bp : 0);
    537      1.1    ragge }
    538      1.1    ragge 
    539      1.1    ragge /*
    540      1.1    ragge  * Start routine. First position the disk to the given position,
    541      1.1    ragge  * then start reading/writing. An optimization would be to be able
    542      1.1    ragge  * to handle overlapping seeks between disks.
    543      1.1    ragge  */
    544      1.1    ragge void
    545      1.1    ragge rlcstart(struct rlc_softc *sc, struct buf *ob)
    546      1.1    ragge {
    547      1.1    ragge 	struct disklabel *lp;
    548      1.1    ragge 	struct rl_softc *rc;
    549      1.1    ragge 	struct buf *bp;
    550      1.1    ragge 	int bn, cn, sn, tn, blks, err;
    551  1.9.4.1     fvdl 	dev_t dev;
    552      1.1    ragge 
    553      1.1    ragge 	if (sc->sc_active)
    554      1.1    ragge 		return;	/* Already doing something */
    555      1.1    ragge 
    556      1.1    ragge 	if (ob == 0) {
    557      1.1    ragge 		bp = BUFQ_FIRST(&sc->sc_q);
    558      1.1    ragge 		if (bp == NULL)
    559      1.1    ragge 			return;	/* Nothing to do */
    560      1.1    ragge 		BUFQ_REMOVE(&sc->sc_q, bp);
    561      1.3  thorpej 		sc->sc_bufaddr = bp->b_data;
    562      1.1    ragge 		sc->sc_diskblk = bp->b_rawblkno;
    563      1.1    ragge 		sc->sc_bytecnt = bp->b_bcount;
    564      1.1    ragge 		bp->b_resid = 0;
    565      1.1    ragge 	} else
    566      1.1    ragge 		bp = ob;
    567      1.1    ragge 	sc->sc_active = bp;
    568      1.1    ragge 
    569  1.9.4.1     fvdl 	dev = vdev_rdev(bp->b_devvp);
    570  1.9.4.1     fvdl 	rc = rl_cd.cd_devs[DISKUNIT(dev)];
    571      1.1    ragge 	bn = sc->sc_diskblk;
    572      1.1    ragge 	lp = rc->rc_disk.dk_label;
    573      1.1    ragge 	if (bn) {
    574      1.1    ragge 		cn = bn / lp->d_secpercyl;
    575      1.1    ragge 		sn = bn % lp->d_secpercyl;
    576      1.1    ragge 		tn = sn / lp->d_nsectors;
    577      1.1    ragge 		sn = sn % lp->d_nsectors;
    578      1.1    ragge 	} else
    579      1.1    ragge 		cn = sn = tn = 0;
    580      1.1    ragge 
    581      1.1    ragge 	/*
    582      1.1    ragge 	 * Check if we have to position disk first.
    583      1.1    ragge 	 */
    584      1.1    ragge 	if (rc->rc_cyl != cn || rc->rc_head != tn) {
    585      1.1    ragge 		u_int16_t da = RLDA_SEEK;
    586      1.1    ragge 		if (cn > rc->rc_cyl)
    587      1.1    ragge 			da |= ((cn - rc->rc_cyl) << RLDA_CYLSHFT) | RLDA_DIR;
    588      1.1    ragge 		else
    589      1.1    ragge 			da |= ((rc->rc_cyl - cn) << RLDA_CYLSHFT);
    590      1.1    ragge 		if (tn)
    591      1.1    ragge 			da |= RLDA_HSSEEK;
    592      1.1    ragge 		waitcrdy(sc);
    593      1.1    ragge 		RL_WREG(RL_DA, da);
    594      1.1    ragge 		RL_WREG(RL_CS, RLCS_SEEK | (rc->rc_hwid << RLCS_USHFT));
    595      1.1    ragge 		waitcrdy(sc);
    596      1.1    ragge 		rc->rc_cyl = cn;
    597      1.1    ragge 		rc->rc_head = tn;
    598      1.1    ragge 	}
    599      1.1    ragge 	RL_WREG(RL_DA, (cn << RLDA_CYLSHFT) | (tn ? RLDA_HSRW : 0) | (sn << 1));
    600      1.1    ragge 	blks = sc->sc_bytecnt/DEV_BSIZE;
    601      1.1    ragge 
    602      1.1    ragge 	if (sn + blks > RL_SPT/2)
    603      1.1    ragge 		blks = RL_SPT/2 - sn;
    604      1.1    ragge 	RL_WREG(RL_MP, -(blks*DEV_BSIZE)/2);
    605      1.1    ragge 	err = bus_dmamap_load(sc->sc_dmat, sc->sc_dmam, sc->sc_bufaddr,
    606      1.1    ragge 	    (blks*DEV_BSIZE), bp->b_proc, BUS_DMA_NOWAIT);
    607      1.1    ragge 	if (err)
    608      1.1    ragge 		panic("%s: bus_dmamap_load failed: %d",
    609      1.1    ragge 		    sc->sc_dev.dv_xname, err);
    610      1.1    ragge 	RL_WREG(RL_BA, (sc->sc_dmam->dm_segs[0].ds_addr & 0xffff));
    611      1.1    ragge 
    612      1.1    ragge 	/* Count up vars */
    613      1.1    ragge 	sc->sc_bufaddr += (blks*DEV_BSIZE);
    614      1.1    ragge 	sc->sc_diskblk += blks;
    615      1.1    ragge 	sc->sc_bytecnt -= (blks*DEV_BSIZE);
    616      1.1    ragge 
    617      1.1    ragge 	if (bp->b_flags & B_READ)
    618      1.1    ragge 		RL_WREG(RL_CS, RLCS_IE|RLCS_RD|(rc->rc_hwid << RLCS_USHFT));
    619      1.1    ragge 	else
    620      1.1    ragge 		RL_WREG(RL_CS, RLCS_IE|RLCS_WD|(rc->rc_hwid << RLCS_USHFT));
    621      1.2    ragge }
    622      1.2    ragge 
    623      1.2    ragge void
    624      1.2    ragge rlreset(struct device *dev)
    625      1.2    ragge {
    626      1.2    ragge 	struct rl_softc *rc = (struct rl_softc *)dev;
    627      1.2    ragge 	struct rlc_softc *sc = (struct rlc_softc *)rc->rc_dev.dv_parent;
    628      1.2    ragge 	u_int16_t mp;
    629      1.2    ragge 
    630      1.2    ragge 	if (rc->rc_state != DK_OPEN)
    631      1.2    ragge 		return;
    632      1.2    ragge 	RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
    633      1.2    ragge 	waitcrdy(sc);
    634      1.2    ragge 	mp = RL_RREG(RL_MP);
    635      1.2    ragge 	rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
    636      1.2    ragge 	rc->rc_cyl = (mp >> 7) & 0777;
    637      1.2    ragge 	if (sc->sc_active == 0)
    638      1.2    ragge 		return;
    639      1.2    ragge 
    640      1.2    ragge 	BUFQ_INSERT_HEAD(&sc->sc_q, sc->sc_active);
    641      1.2    ragge 	sc->sc_active = 0;
    642      1.2    ragge 	rlcstart(sc, 0);
    643      1.1    ragge }
    644