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