Home | History | Annotate | Line # | Download | only in qbus
rl.c revision 1.29
      1  1.29   thorpej /*	$NetBSD: rl.c,v 1.29 2006/03/28 17:38:34 thorpej 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.24    simonb  *      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.24    simonb  *
     43   1.1     ragge  */
     44  1.10     lukem 
     45  1.10     lukem #include <sys/cdefs.h>
     46  1.29   thorpej __KERNEL_RCSID(0, "$NetBSD: rl.c,v 1.29 2006/03/28 17:38:34 thorpej Exp $");
     47   1.1     ragge 
     48   1.1     ragge #include <sys/param.h>
     49   1.1     ragge #include <sys/device.h>
     50   1.1     ragge #include <sys/systm.h>
     51   1.1     ragge #include <sys/conf.h>
     52   1.1     ragge #include <sys/disk.h>
     53   1.1     ragge #include <sys/disklabel.h>
     54   1.1     ragge #include <sys/buf.h>
     55  1.23      yamt #include <sys/bufq.h>
     56   1.1     ragge #include <sys/stat.h>
     57   1.1     ragge #include <sys/dkio.h>
     58   1.1     ragge #include <sys/fcntl.h>
     59  1.17  jdolecek #include <sys/event.h>
     60   1.1     ragge 
     61   1.1     ragge #include <ufs/ufs/dinode.h>
     62   1.1     ragge #include <ufs/ffs/fs.h>
     63   1.1     ragge 
     64   1.1     ragge #include <machine/bus.h>
     65   1.1     ragge 
     66   1.1     ragge #include <dev/qbus/ubavar.h>
     67   1.1     ragge #include <dev/qbus/rlreg.h>
     68  1.11     ragge #include <dev/qbus/rlvar.h>
     69   1.1     ragge 
     70   1.1     ragge #include "ioconf.h"
     71   1.1     ragge #include "locators.h"
     72   1.1     ragge 
     73   1.1     ragge static	int rlcmatch(struct device *, struct cfdata *, void *);
     74   1.1     ragge static	void rlcattach(struct device *, struct device *, void *);
     75   1.1     ragge static	int rlcprint(void *, const char *);
     76   1.1     ragge static	void rlcintr(void *);
     77   1.1     ragge static	int rlmatch(struct device *, struct cfdata *, void *);
     78   1.1     ragge static	void rlattach(struct device *, struct device *, void *);
     79   1.1     ragge static	void rlcstart(struct rlc_softc *, struct buf *);
     80   1.1     ragge static	void waitcrdy(struct rlc_softc *);
     81  1.11     ragge static	void rlcreset(struct device *);
     82   1.1     ragge 
     83  1.15   thorpej CFATTACH_DECL(rlc, sizeof(struct rlc_softc),
     84  1.16   thorpej     rlcmatch, rlcattach, NULL, NULL);
     85  1.15   thorpej 
     86  1.15   thorpej CFATTACH_DECL(rl, sizeof(struct rl_softc),
     87  1.16   thorpej     rlmatch, rlattach, NULL, NULL);
     88   1.1     ragge 
     89  1.13   gehenna dev_type_open(rlopen);
     90  1.13   gehenna dev_type_close(rlclose);
     91  1.13   gehenna dev_type_read(rlread);
     92  1.13   gehenna dev_type_write(rlwrite);
     93  1.13   gehenna dev_type_ioctl(rlioctl);
     94  1.13   gehenna dev_type_strategy(rlstrategy);
     95  1.13   gehenna dev_type_dump(rldump);
     96  1.13   gehenna dev_type_size(rlsize);
     97  1.13   gehenna 
     98  1.13   gehenna const struct bdevsw rl_bdevsw = {
     99  1.13   gehenna 	rlopen, rlclose, rlstrategy, rlioctl, rldump, rlsize, D_DISK
    100  1.13   gehenna };
    101  1.13   gehenna 
    102  1.13   gehenna const struct cdevsw rl_cdevsw = {
    103  1.13   gehenna 	rlopen, rlclose, rlread, rlwrite, rlioctl,
    104  1.17  jdolecek 	nostop, notty, nopoll, nommap, nokqfilter, D_DISK
    105  1.13   gehenna };
    106  1.13   gehenna 
    107   1.1     ragge #define	MAXRLXFER (RL_BPS * RL_SPT)
    108   1.1     ragge 
    109   1.1     ragge #define	RL_WREG(reg, val) \
    110   1.1     ragge 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, (reg), (val))
    111   1.1     ragge #define RL_RREG(reg) \
    112   1.1     ragge 	bus_space_read_2(sc->sc_iot, sc->sc_ioh, (reg))
    113   1.1     ragge 
    114  1.25     ragge static const char *rlstates[] = {
    115  1.11     ragge 	"drive not loaded",
    116  1.11     ragge 	"drive spinning up",
    117  1.11     ragge 	"drive brushes out",
    118  1.11     ragge 	"drive loading heads",
    119  1.11     ragge 	"drive seeking",
    120  1.11     ragge 	"drive ready",
    121  1.11     ragge 	"drive unloading heads",
    122  1.11     ragge 	"drive spun down",
    123  1.11     ragge };
    124  1.11     ragge 
    125  1.22   thorpej static struct dkdriver rldkdriver = {
    126  1.22   thorpej 	rlstrategy, minphys
    127  1.22   thorpej };
    128  1.22   thorpej 
    129  1.25     ragge static const char *
    130  1.11     ragge rlstate(struct rlc_softc *sc, int unit)
    131  1.11     ragge {
    132  1.11     ragge 	int i = 0;
    133  1.11     ragge 
    134  1.11     ragge 	do {
    135  1.11     ragge 		RL_WREG(RL_DA, RLDA_GS);
    136  1.11     ragge 		RL_WREG(RL_CS, RLCS_GS|(unit << RLCS_USHFT));
    137  1.11     ragge 		waitcrdy(sc);
    138  1.11     ragge 	} while (((RL_RREG(RL_CS) & RLCS_ERR) != 0) && i++ < 10);
    139  1.11     ragge 	if (i == 10)
    140  1.11     ragge 		return NULL;
    141  1.11     ragge 	i = RL_RREG(RL_MP) & RLMP_STATUS;
    142  1.11     ragge 	return rlstates[i];
    143  1.11     ragge }
    144  1.11     ragge 
    145   1.1     ragge void
    146   1.1     ragge waitcrdy(struct rlc_softc *sc)
    147   1.1     ragge {
    148   1.1     ragge 	int i;
    149   1.1     ragge 
    150   1.1     ragge 	for (i = 0; i < 1000; i++) {
    151   1.1     ragge 		DELAY(10000);
    152   1.1     ragge 		if (RL_RREG(RL_CS) & RLCS_CRDY)
    153   1.1     ragge 			return;
    154   1.1     ragge 	}
    155   1.1     ragge 	printf("%s: never got ready\n", sc->sc_dev.dv_xname); /* ?panic? */
    156   1.1     ragge }
    157   1.1     ragge 
    158   1.1     ragge int
    159   1.1     ragge rlcprint(void *aux, const char *name)
    160   1.1     ragge {
    161   1.1     ragge 	struct rlc_attach_args *ra = aux;
    162   1.1     ragge 
    163   1.1     ragge 	if (name)
    164  1.18   thorpej 		aprint_normal("RL0%d at %s",
    165  1.18   thorpej 		    ra->type & RLMP_DT ? '2' : '1', name);
    166  1.18   thorpej 	aprint_normal(" drive %d", ra->hwid);
    167   1.1     ragge 	return UNCONF;
    168   1.1     ragge }
    169   1.1     ragge 
    170   1.1     ragge /*
    171   1.1     ragge  * Force the controller to interrupt.
    172   1.1     ragge  */
    173   1.1     ragge int
    174   1.1     ragge rlcmatch(struct device *parent, struct cfdata *cf, void *aux)
    175   1.1     ragge {
    176   1.1     ragge 	struct uba_attach_args *ua = aux;
    177   1.1     ragge 	struct rlc_softc ssc, *sc = &ssc;
    178   1.1     ragge 	int i;
    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 	/* Force interrupt by issuing a "Get Status" command */
    183   1.1     ragge 	RL_WREG(RL_DA, RLDA_GS);
    184   1.1     ragge 	RL_WREG(RL_CS, RLCS_GS|RLCS_IE);
    185   1.1     ragge 
    186   1.1     ragge 	for (i = 0; i < 100; i++) {
    187   1.1     ragge 		DELAY(100000);
    188   1.1     ragge 		if (RL_RREG(RL_CS) & RLCS_CRDY)
    189   1.1     ragge 			return 1;
    190   1.1     ragge 	}
    191   1.1     ragge 	return 0;
    192   1.1     ragge }
    193   1.1     ragge 
    194   1.1     ragge void
    195   1.1     ragge rlcattach(struct device *parent, struct device *self, void *aux)
    196   1.1     ragge {
    197   1.1     ragge 	struct rlc_softc *sc = (struct rlc_softc *)self;
    198   1.1     ragge 	struct uba_attach_args *ua = aux;
    199   1.1     ragge 	struct rlc_attach_args ra;
    200   1.1     ragge 	int i, error;
    201   1.1     ragge 
    202   1.1     ragge 	sc->sc_iot = ua->ua_iot;
    203   1.1     ragge 	sc->sc_ioh = ua->ua_ioh;
    204   1.1     ragge 	sc->sc_dmat = ua->ua_dmat;
    205   1.4      matt 	uba_intr_establish(ua->ua_icookie, ua->ua_cvec,
    206   1.4      matt 		rlcintr, sc, &sc->sc_intrcnt);
    207   1.5      matt 	evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, ua->ua_evcnt,
    208   1.5      matt 		sc->sc_dev.dv_xname, "intr");
    209  1.11     ragge 	uba_reset_establish(rlcreset, self);
    210  1.11     ragge 
    211   1.1     ragge 	printf("\n");
    212   1.1     ragge 
    213   1.1     ragge 	/*
    214  1.24    simonb 	 * The RL11 can only have one transfer going at a time,
    215   1.1     ragge 	 * and max transfer size is one track, so only one dmamap
    216   1.1     ragge 	 * is needed.
    217   1.1     ragge 	 */
    218   1.1     ragge 	error = bus_dmamap_create(sc->sc_dmat, MAXRLXFER, 1, MAXRLXFER, 0,
    219   1.1     ragge 	    BUS_DMA_ALLOCNOW, &sc->sc_dmam);
    220   1.1     ragge 	if (error) {
    221   1.1     ragge 		printf(": Failed to allocate DMA map, error %d\n", error);
    222   1.1     ragge 		return;
    223   1.1     ragge 	}
    224  1.26      yamt 	bufq_alloc(&sc->sc_q, "disksort", BUFQ_SORT_CYLINDER);
    225   1.1     ragge 	for (i = 0; i < RL_MAXDPC; i++) {
    226   1.1     ragge 		waitcrdy(sc);
    227   1.1     ragge 		RL_WREG(RL_DA, RLDA_GS|RLDA_RST);
    228   1.1     ragge 		RL_WREG(RL_CS, RLCS_GS|(i << RLCS_USHFT));
    229   1.1     ragge 		waitcrdy(sc);
    230   1.1     ragge 		ra.type = RL_RREG(RL_MP);
    231   1.1     ragge 		ra.hwid = i;
    232   1.1     ragge 		if ((RL_RREG(RL_CS) & RLCS_ERR) == 0)
    233   1.1     ragge 			config_found(&sc->sc_dev, &ra, rlcprint);
    234   1.1     ragge 	}
    235   1.1     ragge }
    236   1.1     ragge 
    237   1.1     ragge int
    238   1.1     ragge rlmatch(struct device *parent, struct cfdata *cf, void *aux)
    239   1.1     ragge {
    240   1.1     ragge 	struct rlc_attach_args *ra = aux;
    241   1.1     ragge 
    242   1.1     ragge 	if (cf->cf_loc[RLCCF_DRIVE] != RLCCF_DRIVE_DEFAULT &&
    243   1.1     ragge 	    cf->cf_loc[RLCCF_DRIVE] != ra->hwid)
    244   1.1     ragge 		return 0;
    245   1.1     ragge 	return 1;
    246   1.1     ragge }
    247   1.1     ragge 
    248   1.1     ragge void
    249   1.1     ragge rlattach(struct device *parent, struct device *self, void *aux)
    250   1.1     ragge {
    251   1.1     ragge 	struct rl_softc *rc = (struct rl_softc *)self;
    252   1.1     ragge 	struct rlc_attach_args *ra = aux;
    253   1.1     ragge 	struct disklabel *dl;
    254   1.1     ragge 
    255   1.1     ragge 	rc->rc_hwid = ra->hwid;
    256   1.1     ragge 	rc->rc_disk.dk_name = rc->rc_dev.dv_xname;
    257  1.22   thorpej 	rc->rc_disk.dk_driver = &rldkdriver;
    258   1.1     ragge 	disk_attach(&rc->rc_disk);
    259   1.1     ragge 	dl = rc->rc_disk.dk_label;
    260   1.1     ragge 	dl->d_npartitions = 3;
    261   1.1     ragge 	strcpy(dl->d_typename, "RL01");
    262   1.1     ragge 	if (ra->type & RLMP_DT)
    263   1.1     ragge 		dl->d_typename[3] = '2';
    264   1.1     ragge 	dl->d_secsize = DEV_BSIZE; /* XXX - wrong, but OK for now */
    265   1.1     ragge 	dl->d_nsectors = RL_SPT/2;
    266   1.1     ragge 	dl->d_ntracks = RL_SPD;
    267   1.1     ragge 	dl->d_ncylinders = ra->type & RLMP_DT ? RL_TPS02 : RL_TPS01;
    268   1.1     ragge 	dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
    269   1.1     ragge 	dl->d_secperunit = dl->d_ncylinders * dl->d_secpercyl;
    270   1.1     ragge 	dl->d_partitions[0].p_size = dl->d_partitions[2].p_size =
    271   1.1     ragge 	    dl->d_secperunit;
    272   1.1     ragge 	dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0;
    273   1.1     ragge 	dl->d_interleave = dl->d_headswitch = 1;
    274   1.1     ragge 	dl->d_bbsize = BBSIZE;
    275  1.19        he 	dl->d_sbsize = SBLOCKSIZE;
    276   1.1     ragge 	dl->d_rpm = 2400;
    277   1.1     ragge 	dl->d_type = DTYPE_DEC;
    278  1.11     ragge 	printf(": %s, %s\n", dl->d_typename,
    279  1.11     ragge 	    rlstate((struct rlc_softc *)parent, ra->hwid));
    280  1.22   thorpej 
    281  1.22   thorpej 	/*
    282  1.22   thorpej 	 * XXX We should try to discovery wedges here, but
    283  1.22   thorpej 	 * XXX that would mean loading up the pack and being
    284  1.22   thorpej 	 * XXX able to do I/O.  Should use config_defer() here.
    285  1.22   thorpej 	 */
    286   1.1     ragge }
    287   1.1     ragge 
    288   1.1     ragge int
    289  1.27  christos rlopen(dev_t dev, int flag, int fmt, struct lwp *l)
    290   1.1     ragge {
    291  1.22   thorpej 	int error, part, unit, mask;
    292   1.1     ragge 	struct disklabel *dl;
    293   1.1     ragge 	struct rlc_softc *sc;
    294   1.1     ragge 	struct rl_softc *rc;
    295  1.20       dsl 	const char *msg;
    296  1.11     ragge 
    297   1.1     ragge 	/*
    298   1.1     ragge 	 * Make sure this is a reasonable open request.
    299   1.1     ragge 	 */
    300   1.1     ragge 	unit = DISKUNIT(dev);
    301   1.1     ragge 	if (unit >= rl_cd.cd_ndevs)
    302   1.1     ragge 		return ENXIO;
    303   1.1     ragge 	rc = rl_cd.cd_devs[unit];
    304   1.1     ragge 	if (rc == 0)
    305   1.1     ragge 		return ENXIO;
    306   1.1     ragge 
    307  1.22   thorpej 	part = DISKPART(dev);
    308  1.22   thorpej 
    309  1.22   thorpej 	if ((error = lockmgr(&rc->rc_disk.dk_openlock, LK_EXCLUSIVE,
    310  1.22   thorpej 			     NULL)) != 0)
    311  1.22   thorpej 		return (error);
    312  1.22   thorpej 
    313  1.22   thorpej 	/*
    314  1.22   thorpej 	 * If there are wedges, and this is not RAW_PART, then we
    315  1.22   thorpej 	 * need to fail.
    316  1.22   thorpej 	 */
    317  1.22   thorpej 	if (rc->rc_disk.dk_nwedges != 0 && part != RAW_PART) {
    318  1.22   thorpej 		error = EBUSY;
    319  1.22   thorpej 		goto bad1;
    320  1.22   thorpej 	}
    321  1.22   thorpej 
    322  1.28   thorpej 	sc = (struct rlc_softc *)device_parent(&rc->rc_dev);
    323  1.11     ragge 	/* Check that the disk actually is useable */
    324  1.11     ragge 	msg = rlstate(sc, rc->rc_hwid);
    325  1.11     ragge 	if (msg == NULL || msg == rlstates[RLMP_UNLOAD] ||
    326  1.22   thorpej 	    msg == rlstates[RLMP_SPUNDOWN]) {
    327  1.22   thorpej 		error = ENXIO;
    328  1.22   thorpej 		goto bad1;
    329  1.22   thorpej 	}
    330   1.1     ragge 	/*
    331   1.1     ragge 	 * If this is the first open; read in where on the disk we are.
    332   1.1     ragge 	 */
    333   1.1     ragge 	dl = rc->rc_disk.dk_label;
    334   1.1     ragge 	if (rc->rc_state == DK_CLOSED) {
    335   1.1     ragge 		u_int16_t mp;
    336  1.13   gehenna 		int maj;
    337   1.1     ragge 		RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
    338   1.1     ragge 		waitcrdy(sc);
    339   1.1     ragge 		mp = RL_RREG(RL_MP);
    340   1.1     ragge 		rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
    341   1.1     ragge 		rc->rc_cyl = (mp >> 7) & 0777;
    342   1.1     ragge 		rc->rc_state = DK_OPEN;
    343   1.1     ragge 		/* Get disk label */
    344   1.1     ragge 		printf("%s: ", rc->rc_dev.dv_xname);
    345  1.13   gehenna 		maj = cdevsw_lookup_major(&rl_cdevsw);
    346  1.13   gehenna 		if ((msg = readdisklabel(MAKEDISKDEV(maj,
    347  1.29   thorpej 		    device_unit(&rc->rc_dev), RAW_PART), rlstrategy, dl, NULL)))
    348   1.1     ragge 			printf("%s: ", msg);
    349   1.1     ragge 		printf("size %d sectors\n", dl->d_secperunit);
    350   1.1     ragge 	}
    351  1.22   thorpej 	if (part >= dl->d_npartitions) {
    352  1.22   thorpej 		error = ENXIO;
    353  1.22   thorpej 		goto bad1;
    354  1.22   thorpej 	}
    355   1.1     ragge 
    356   1.1     ragge 	mask = 1 << part;
    357   1.1     ragge 	switch (fmt) {
    358   1.1     ragge 	case S_IFCHR:
    359   1.1     ragge 		rc->rc_disk.dk_copenmask |= mask;
    360   1.1     ragge 		break;
    361   1.1     ragge 	case S_IFBLK:
    362   1.1     ragge 		rc->rc_disk.dk_bopenmask |= mask;
    363   1.1     ragge 		break;
    364   1.1     ragge 	}
    365   1.1     ragge 	rc->rc_disk.dk_openmask |= mask;
    366  1.22   thorpej 	(void) lockmgr(&rc->rc_disk.dk_openlock, LK_RELEASE, NULL);
    367   1.1     ragge 	return 0;
    368  1.22   thorpej 
    369  1.22   thorpej  bad1:
    370  1.22   thorpej 	(void) lockmgr(&rc->rc_disk.dk_openlock, LK_RELEASE, NULL);
    371  1.22   thorpej 	return (error);
    372   1.1     ragge }
    373   1.1     ragge 
    374   1.1     ragge int
    375  1.27  christos rlclose(dev_t dev, int flag, int fmt, struct lwp *l)
    376   1.1     ragge {
    377  1.22   thorpej 	int error, unit = DISKUNIT(dev);
    378   1.1     ragge 	struct rl_softc *rc = rl_cd.cd_devs[unit];
    379   1.1     ragge 	int mask = (1 << DISKPART(dev));
    380   1.1     ragge 
    381  1.22   thorpej 	if ((error = lockmgr(&rc->rc_disk.dk_openlock, LK_EXCLUSIVE,
    382  1.22   thorpej 			     NULL)) != 0)
    383  1.22   thorpej 		return (error);
    384  1.22   thorpej 
    385   1.1     ragge 	switch (fmt) {
    386   1.1     ragge 	case S_IFCHR:
    387   1.1     ragge 		rc->rc_disk.dk_copenmask &= ~mask;
    388   1.1     ragge 		break;
    389   1.1     ragge 	case S_IFBLK:
    390   1.1     ragge 		rc->rc_disk.dk_bopenmask &= ~mask;
    391   1.1     ragge 		break;
    392   1.1     ragge 	}
    393   1.1     ragge 	rc->rc_disk.dk_openmask =
    394   1.1     ragge 	    rc->rc_disk.dk_copenmask | rc->rc_disk.dk_bopenmask;
    395   1.1     ragge 
    396   1.1     ragge 	if (rc->rc_disk.dk_openmask == 0)
    397   1.1     ragge 		rc->rc_state = DK_CLOSED; /* May change pack */
    398  1.22   thorpej 	(void) lockmgr(&rc->rc_disk.dk_openlock, LK_RELEASE, NULL);
    399   1.1     ragge 	return 0;
    400   1.1     ragge }
    401   1.1     ragge 
    402   1.1     ragge void
    403   1.1     ragge rlstrategy(struct buf *bp)
    404   1.1     ragge {
    405   1.1     ragge 	struct disklabel *lp;
    406   1.1     ragge 	struct rlc_softc *sc;
    407  1.24    simonb 	struct rl_softc *rc;
    408  1.24    simonb 	int unit, s, err;
    409  1.24    simonb 	/*
    410  1.24    simonb 	 * Make sure this is a reasonable drive to use.
    411  1.24    simonb 	 */
    412  1.24    simonb 	unit = DISKUNIT(bp->b_dev);
    413  1.24    simonb 	if (unit > rl_cd.cd_ndevs || (rc = rl_cd.cd_devs[unit]) == NULL) {
    414  1.24    simonb 		bp->b_error = ENXIO;
    415  1.24    simonb 		bp->b_flags |= B_ERROR;
    416  1.24    simonb 		goto done;
    417  1.24    simonb 	}
    418   1.1     ragge 	if (rc->rc_state != DK_OPEN) /* How did we end up here at all? */
    419   1.1     ragge 		panic("rlstrategy: state impossible");
    420   1.1     ragge 
    421   1.1     ragge 	lp = rc->rc_disk.dk_label;
    422  1.21   thorpej 	if ((err = bounds_check_with_label(&rc->rc_disk, bp, 1)) <= 0)
    423   1.1     ragge 		goto done;
    424   1.1     ragge 
    425   1.1     ragge 	if (bp->b_bcount == 0)
    426   1.1     ragge 		goto done;
    427   1.1     ragge 
    428   1.1     ragge 	bp->b_rawblkno =
    429   1.1     ragge 	    bp->b_blkno + lp->d_partitions[DISKPART(bp->b_dev)].p_offset;
    430   1.1     ragge 	bp->b_cylinder = bp->b_rawblkno / lp->d_secpercyl;
    431  1.28   thorpej 	sc = (struct rlc_softc *)device_parent(&rc->rc_dev);
    432   1.1     ragge 
    433   1.8   thorpej 	s = splbio();
    434  1.26      yamt 	BUFQ_PUT(sc->sc_q, bp);
    435   1.1     ragge 	rlcstart(sc, 0);
    436   1.1     ragge 	splx(s);
    437   1.1     ragge 	return;
    438   1.1     ragge 
    439   1.1     ragge done:	biodone(bp);
    440   1.1     ragge }
    441   1.1     ragge 
    442   1.1     ragge int
    443  1.27  christos rlioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct lwp *l)
    444   1.1     ragge {
    445   1.1     ragge 	struct rl_softc *rc = rl_cd.cd_devs[DISKUNIT(dev)];
    446   1.1     ragge 	struct disklabel *lp = rc->rc_disk.dk_label;
    447   1.1     ragge 	int err = 0;
    448   1.6      fvdl #ifdef __HAVE_OLD_DISKLABEL
    449   1.6      fvdl 	struct disklabel newlabel;
    450   1.6      fvdl #endif
    451   1.1     ragge 
    452   1.1     ragge 	switch (cmd) {
    453   1.1     ragge 	case DIOCGDINFO:
    454   1.1     ragge 		bcopy(lp, addr, sizeof (struct disklabel));
    455   1.1     ragge 		break;
    456   1.1     ragge 
    457   1.6      fvdl #ifdef __HAVE_OLD_DISKLABEL
    458   1.6      fvdl 	case ODIOCGDINFO:
    459   1.6      fvdl 		newlabel = *lp;
    460   1.6      fvdl 		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
    461   1.7      fvdl 			return ENOTTY;
    462   1.6      fvdl 		bcopy(&newlabel, addr, sizeof (struct olddisklabel));
    463   1.6      fvdl 		break;
    464   1.6      fvdl #endif
    465   1.6      fvdl 
    466   1.1     ragge 	case DIOCGPART:
    467   1.1     ragge 		((struct partinfo *)addr)->disklab = lp;
    468   1.1     ragge 		((struct partinfo *)addr)->part =
    469   1.1     ragge 		    &lp->d_partitions[DISKPART(dev)];
    470   1.1     ragge 		break;
    471   1.1     ragge 
    472   1.1     ragge 	case DIOCSDINFO:
    473   1.1     ragge 	case DIOCWDINFO:
    474   1.6      fvdl #ifdef __HAVE_OLD_DISKLABEL
    475   1.6      fvdl 	case ODIOCWDINFO:
    476   1.6      fvdl 	case ODIOCSDINFO:
    477   1.6      fvdl #endif
    478   1.6      fvdl 	{
    479   1.6      fvdl 		struct disklabel *tp;
    480   1.6      fvdl 
    481   1.6      fvdl #ifdef __HAVE_OLD_DISKLABEL
    482   1.6      fvdl 		if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
    483   1.6      fvdl 			memset(&newlabel, 0, sizeof newlabel);
    484   1.6      fvdl 			memcpy(&newlabel, addr, sizeof (struct olddisklabel));
    485   1.6      fvdl 			tp = &newlabel;
    486   1.6      fvdl 		} else
    487   1.6      fvdl #endif
    488   1.6      fvdl 		tp = (struct disklabel *)addr;
    489   1.6      fvdl 
    490   1.1     ragge 		if ((flag & FWRITE) == 0)
    491   1.1     ragge 			err = EBADF;
    492  1.22   thorpej 		else {
    493  1.22   thorpej 			if ((err = lockmgr(&rc->rc_disk.dk_openlock,
    494  1.22   thorpej 					   LK_EXCLUSIVE, NULL)) != 0)
    495  1.22   thorpej 				break;
    496   1.6      fvdl 			err = ((
    497   1.6      fvdl #ifdef __HAVE_OLD_DISKLABEL
    498   1.6      fvdl 			       cmd == ODIOCSDINFO ||
    499   1.6      fvdl #endif
    500   1.6      fvdl 			       cmd == DIOCSDINFO) ?
    501   1.6      fvdl 			    setdisklabel(lp, tp, 0, 0) :
    502   1.1     ragge 			    writedisklabel(dev, rlstrategy, lp, 0));
    503  1.22   thorpej 			(void) lockmgr(&rc->rc_disk.dk_openlock,
    504  1.22   thorpej 				       LK_RELEASE, NULL);
    505  1.22   thorpej 		}
    506   1.1     ragge 		break;
    507   1.6      fvdl 	}
    508   1.1     ragge 
    509   1.1     ragge 	case DIOCWLABEL:
    510   1.1     ragge 		if ((flag & FWRITE) == 0)
    511   1.1     ragge 			err = EBADF;
    512   1.1     ragge 		break;
    513   1.1     ragge 
    514  1.22   thorpej 	case DIOCAWEDGE:
    515  1.22   thorpej 	    {
    516  1.24    simonb 		struct dkwedge_info *dkw = (void *) addr;
    517  1.22   thorpej 
    518  1.22   thorpej 		if ((flag & FWRITE) == 0)
    519  1.22   thorpej 			return (EBADF);
    520  1.22   thorpej 
    521  1.22   thorpej 		/* If the ioctl happens here, the parent is us. */
    522  1.22   thorpej 		strcpy(dkw->dkw_parent, rc->rc_dev.dv_xname);
    523  1.22   thorpej 		return (dkwedge_add(dkw));
    524  1.22   thorpej 	    }
    525  1.24    simonb 
    526  1.22   thorpej 	case DIOCDWEDGE:
    527  1.22   thorpej 	    {
    528  1.24    simonb 		struct dkwedge_info *dkw = (void *) addr;
    529  1.22   thorpej 
    530  1.22   thorpej 		if ((flag & FWRITE) == 0)
    531  1.22   thorpej 			return (EBADF);
    532  1.22   thorpej 
    533  1.22   thorpej 		/* If the ioctl happens here, the parent is us. */
    534  1.22   thorpej 		strcpy(dkw->dkw_parent, rc->rc_dev.dv_xname);
    535  1.22   thorpej 		return (dkwedge_del(dkw));
    536  1.22   thorpej 	    }
    537  1.24    simonb 
    538  1.22   thorpej 	case DIOCLWEDGES:
    539  1.22   thorpej 	    {
    540  1.24    simonb 		struct dkwedge_list *dkwl = (void *) addr;
    541  1.22   thorpej 
    542  1.27  christos 		return (dkwedge_list(&rc->rc_disk, dkwl, l));
    543  1.22   thorpej 	    }
    544  1.22   thorpej 
    545   1.1     ragge 	default:
    546   1.1     ragge 		err = ENOTTY;
    547   1.1     ragge 	}
    548   1.1     ragge 	return err;
    549   1.1     ragge }
    550   1.1     ragge 
    551   1.1     ragge int
    552   1.1     ragge rlsize(dev_t dev)
    553   1.1     ragge {
    554   1.1     ragge 	struct disklabel *dl;
    555   1.1     ragge 	struct rl_softc *rc;
    556   1.1     ragge 	int size, unit = DISKUNIT(dev);
    557   1.1     ragge 
    558   1.1     ragge 	if ((unit >= rl_cd.cd_ndevs) || ((rc = rl_cd.cd_devs[unit]) == 0))
    559   1.1     ragge 		return -1;
    560   1.1     ragge 	dl = rc->rc_disk.dk_label;
    561   1.1     ragge 	size = dl->d_partitions[DISKPART(dev)].p_size *
    562   1.1     ragge 	    (dl->d_secsize / DEV_BSIZE);
    563   1.1     ragge 	return size;
    564   1.1     ragge }
    565   1.1     ragge 
    566   1.1     ragge int
    567   1.1     ragge rldump(dev_t dev, daddr_t blkno, caddr_t va, size_t size)
    568   1.1     ragge {
    569   1.1     ragge 	/* Not likely... */
    570   1.1     ragge 	return 0;
    571   1.1     ragge }
    572   1.1     ragge 
    573   1.1     ragge int
    574   1.1     ragge rlread(dev_t dev, struct uio *uio, int ioflag)
    575   1.1     ragge {
    576   1.1     ragge 	return (physio(rlstrategy, NULL, dev, B_READ, minphys, uio));
    577   1.1     ragge }
    578   1.1     ragge 
    579   1.1     ragge int
    580   1.1     ragge rlwrite(dev_t dev, struct uio *uio, int ioflag)
    581   1.1     ragge {
    582   1.1     ragge 	return (physio(rlstrategy, NULL, dev, B_WRITE, minphys, uio));
    583   1.1     ragge }
    584   1.1     ragge 
    585  1.25     ragge static const char *rlerr[] = {
    586   1.1     ragge 	"no",
    587   1.1     ragge 	"operation incomplete",
    588   1.1     ragge 	"read data CRC",
    589   1.1     ragge 	"header CRC",
    590   1.1     ragge 	"data late",
    591   1.1     ragge 	"header not found",
    592   1.1     ragge 	"",
    593   1.1     ragge 	"",
    594   1.9       wiz 	"non-existent memory",
    595   1.1     ragge 	"memory parity error",
    596   1.1     ragge 	"",
    597   1.1     ragge 	"",
    598   1.1     ragge 	"",
    599   1.1     ragge 	"",
    600   1.1     ragge 	"",
    601   1.1     ragge 	"",
    602   1.1     ragge };
    603   1.1     ragge 
    604   1.1     ragge void
    605   1.1     ragge rlcintr(void *arg)
    606   1.1     ragge {
    607   1.1     ragge 	struct rlc_softc *sc = arg;
    608   1.1     ragge 	struct buf *bp;
    609   1.1     ragge 	u_int16_t cs;
    610   1.1     ragge 
    611   1.1     ragge 	bp = sc->sc_active;
    612   1.1     ragge 	if (bp == 0) {
    613   1.1     ragge 		printf("%s: strange interrupt\n", sc->sc_dev.dv_xname);
    614   1.1     ragge 		return;
    615   1.1     ragge 	}
    616   1.1     ragge 	bus_dmamap_unload(sc->sc_dmat, sc->sc_dmam);
    617   1.1     ragge 	sc->sc_active = 0;
    618   1.1     ragge 	cs = RL_RREG(RL_CS);
    619   1.1     ragge 	if (cs & RLCS_ERR) {
    620   1.1     ragge 		int error = (cs & RLCS_ERRMSK) >> 10;
    621   1.1     ragge 
    622   1.1     ragge 		printf("%s: %s\n", sc->sc_dev.dv_xname, rlerr[error]);
    623   1.1     ragge 		bp->b_flags |= B_ERROR;
    624   1.1     ragge 		bp->b_error = EIO;
    625   1.1     ragge 		bp->b_resid = bp->b_bcount;
    626   1.1     ragge 		sc->sc_bytecnt = 0;
    627   1.1     ragge 	}
    628   1.1     ragge 	if (sc->sc_bytecnt == 0) /* Finished transfer */
    629   1.1     ragge 		biodone(bp);
    630   1.1     ragge 	rlcstart(sc, sc->sc_bytecnt ? bp : 0);
    631   1.1     ragge }
    632   1.1     ragge 
    633   1.1     ragge /*
    634  1.24    simonb  * Start routine. First position the disk to the given position,
    635   1.1     ragge  * then start reading/writing. An optimization would be to be able
    636   1.1     ragge  * to handle overlapping seeks between disks.
    637   1.1     ragge  */
    638   1.1     ragge void
    639   1.1     ragge rlcstart(struct rlc_softc *sc, struct buf *ob)
    640   1.1     ragge {
    641   1.1     ragge 	struct disklabel *lp;
    642   1.1     ragge 	struct rl_softc *rc;
    643   1.1     ragge 	struct buf *bp;
    644   1.1     ragge 	int bn, cn, sn, tn, blks, err;
    645   1.1     ragge 
    646   1.1     ragge 	if (sc->sc_active)
    647   1.1     ragge 		return;	/* Already doing something */
    648   1.1     ragge 
    649   1.1     ragge 	if (ob == 0) {
    650  1.26      yamt 		bp = BUFQ_GET(sc->sc_q);
    651   1.1     ragge 		if (bp == NULL)
    652   1.1     ragge 			return;	/* Nothing to do */
    653   1.3   thorpej 		sc->sc_bufaddr = bp->b_data;
    654   1.1     ragge 		sc->sc_diskblk = bp->b_rawblkno;
    655   1.1     ragge 		sc->sc_bytecnt = bp->b_bcount;
    656   1.1     ragge 		bp->b_resid = 0;
    657   1.1     ragge 	} else
    658   1.1     ragge 		bp = ob;
    659   1.1     ragge 	sc->sc_active = bp;
    660   1.1     ragge 
    661   1.1     ragge 	rc = rl_cd.cd_devs[DISKUNIT(bp->b_dev)];
    662   1.1     ragge 	bn = sc->sc_diskblk;
    663   1.1     ragge 	lp = rc->rc_disk.dk_label;
    664   1.1     ragge 	if (bn) {
    665   1.1     ragge 		cn = bn / lp->d_secpercyl;
    666   1.1     ragge 		sn = bn % lp->d_secpercyl;
    667   1.1     ragge 		tn = sn / lp->d_nsectors;
    668   1.1     ragge 		sn = sn % lp->d_nsectors;
    669   1.1     ragge 	} else
    670   1.1     ragge 		cn = sn = tn = 0;
    671   1.1     ragge 
    672   1.1     ragge 	/*
    673   1.1     ragge 	 * Check if we have to position disk first.
    674   1.1     ragge 	 */
    675   1.1     ragge 	if (rc->rc_cyl != cn || rc->rc_head != tn) {
    676   1.1     ragge 		u_int16_t da = RLDA_SEEK;
    677   1.1     ragge 		if (cn > rc->rc_cyl)
    678   1.1     ragge 			da |= ((cn - rc->rc_cyl) << RLDA_CYLSHFT) | RLDA_DIR;
    679   1.1     ragge 		else
    680   1.1     ragge 			da |= ((rc->rc_cyl - cn) << RLDA_CYLSHFT);
    681   1.1     ragge 		if (tn)
    682   1.1     ragge 			da |= RLDA_HSSEEK;
    683   1.1     ragge 		waitcrdy(sc);
    684   1.1     ragge 		RL_WREG(RL_DA, da);
    685   1.1     ragge 		RL_WREG(RL_CS, RLCS_SEEK | (rc->rc_hwid << RLCS_USHFT));
    686   1.1     ragge 		waitcrdy(sc);
    687   1.1     ragge 		rc->rc_cyl = cn;
    688   1.1     ragge 		rc->rc_head = tn;
    689   1.1     ragge 	}
    690   1.1     ragge 	RL_WREG(RL_DA, (cn << RLDA_CYLSHFT) | (tn ? RLDA_HSRW : 0) | (sn << 1));
    691   1.1     ragge 	blks = sc->sc_bytecnt/DEV_BSIZE;
    692   1.1     ragge 
    693   1.1     ragge 	if (sn + blks > RL_SPT/2)
    694   1.1     ragge 		blks = RL_SPT/2 - sn;
    695   1.1     ragge 	RL_WREG(RL_MP, -(blks*DEV_BSIZE)/2);
    696   1.1     ragge 	err = bus_dmamap_load(sc->sc_dmat, sc->sc_dmam, sc->sc_bufaddr,
    697  1.11     ragge 	    (blks*DEV_BSIZE), (bp->b_flags & B_PHYS ? bp->b_proc : 0),
    698  1.11     ragge 	    BUS_DMA_NOWAIT);
    699   1.1     ragge 	if (err)
    700   1.1     ragge 		panic("%s: bus_dmamap_load failed: %d",
    701   1.1     ragge 		    sc->sc_dev.dv_xname, err);
    702   1.1     ragge 	RL_WREG(RL_BA, (sc->sc_dmam->dm_segs[0].ds_addr & 0xffff));
    703   1.1     ragge 
    704   1.1     ragge 	/* Count up vars */
    705   1.1     ragge 	sc->sc_bufaddr += (blks*DEV_BSIZE);
    706   1.1     ragge 	sc->sc_diskblk += blks;
    707   1.1     ragge 	sc->sc_bytecnt -= (blks*DEV_BSIZE);
    708   1.1     ragge 
    709   1.1     ragge 	if (bp->b_flags & B_READ)
    710   1.1     ragge 		RL_WREG(RL_CS, RLCS_IE|RLCS_RD|(rc->rc_hwid << RLCS_USHFT));
    711   1.1     ragge 	else
    712   1.1     ragge 		RL_WREG(RL_CS, RLCS_IE|RLCS_WD|(rc->rc_hwid << RLCS_USHFT));
    713   1.2     ragge }
    714   1.2     ragge 
    715  1.11     ragge /*
    716  1.11     ragge  * Called once per controller when an ubareset occurs.
    717  1.11     ragge  * Retracts all disks and restarts active transfers.
    718  1.11     ragge  */
    719   1.2     ragge void
    720  1.11     ragge rlcreset(struct device *dev)
    721   1.2     ragge {
    722  1.11     ragge 	struct rlc_softc *sc = (struct rlc_softc *)dev;
    723  1.11     ragge 	struct rl_softc *rc;
    724  1.11     ragge 	int i;
    725   1.2     ragge 	u_int16_t mp;
    726   1.2     ragge 
    727  1.11     ragge 	for (i = 0; i < rl_cd.cd_ndevs; i++) {
    728  1.11     ragge 		if ((rc = rl_cd.cd_devs[i]) == NULL)
    729  1.11     ragge 			continue;
    730  1.11     ragge 		if (rc->rc_state != DK_OPEN)
    731  1.11     ragge 			continue;
    732  1.11     ragge 
    733  1.11     ragge 		printf(" %s", rc->rc_dev.dv_xname);
    734  1.11     ragge 		RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
    735  1.11     ragge 		waitcrdy(sc);
    736  1.11     ragge 		mp = RL_RREG(RL_MP);
    737  1.11     ragge 		rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
    738  1.11     ragge 		rc->rc_cyl = (mp >> 7) & 0777;
    739  1.11     ragge 	}
    740   1.2     ragge 	if (sc->sc_active == 0)
    741   1.2     ragge 		return;
    742   1.2     ragge 
    743  1.26      yamt 	BUFQ_PUT(sc->sc_q, sc->sc_active);
    744   1.2     ragge 	sc->sc_active = 0;
    745   1.2     ragge 	rlcstart(sc, 0);
    746   1.1     ragge }
    747