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