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