Home | History | Annotate | Line # | Download | only in qbus
rl.c revision 1.12
      1 /*	$NetBSD: rl.c,v 1.12 2002/07/22 21:48:38 hannken 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.12 2002/07/22 21:48:38 hannken 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 cdev_decl(rl);
     81 bdev_decl(rl);
     82 
     83 struct cfattach rlc_ca = {
     84 	sizeof(struct rlc_softc), rlcmatch, rlcattach
     85 };
     86 
     87 struct cfattach rl_ca = {
     88 	sizeof(struct rl_softc), rlmatch, rlattach
     89 };
     90 
     91 #define	MAXRLXFER (RL_BPS * RL_SPT)
     92 #define	RLMAJOR	14
     93 
     94 #define	RL_WREG(reg, val) \
     95 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, (reg), (val))
     96 #define RL_RREG(reg) \
     97 	bus_space_read_2(sc->sc_iot, sc->sc_ioh, (reg))
     98 
     99 static char *rlstates[] = {
    100 	"drive not loaded",
    101 	"drive spinning up",
    102 	"drive brushes out",
    103 	"drive loading heads",
    104 	"drive seeking",
    105 	"drive ready",
    106 	"drive unloading heads",
    107 	"drive spun down",
    108 };
    109 
    110 static char *
    111 rlstate(struct rlc_softc *sc, int unit)
    112 {
    113 	int i = 0;
    114 
    115 	do {
    116 		RL_WREG(RL_DA, RLDA_GS);
    117 		RL_WREG(RL_CS, RLCS_GS|(unit << RLCS_USHFT));
    118 		waitcrdy(sc);
    119 	} while (((RL_RREG(RL_CS) & RLCS_ERR) != 0) && i++ < 10);
    120 	if (i == 10)
    121 		return NULL;
    122 	i = RL_RREG(RL_MP) & RLMP_STATUS;
    123 	return rlstates[i];
    124 }
    125 
    126 void
    127 waitcrdy(struct rlc_softc *sc)
    128 {
    129 	int i;
    130 
    131 	for (i = 0; i < 1000; i++) {
    132 		DELAY(10000);
    133 		if (RL_RREG(RL_CS) & RLCS_CRDY)
    134 			return;
    135 	}
    136 	printf("%s: never got ready\n", sc->sc_dev.dv_xname); /* ?panic? */
    137 }
    138 
    139 int
    140 rlcprint(void *aux, const char *name)
    141 {
    142 	struct rlc_attach_args *ra = aux;
    143 
    144 	if (name)
    145 		printf("RL0%d at %s", ra->type & RLMP_DT ? '2' : '1', name);
    146 	printf(" drive %d", ra->hwid);
    147 	return UNCONF;
    148 }
    149 
    150 /*
    151  * Force the controller to interrupt.
    152  */
    153 int
    154 rlcmatch(struct device *parent, struct cfdata *cf, void *aux)
    155 {
    156 	struct uba_attach_args *ua = aux;
    157 	struct rlc_softc ssc, *sc = &ssc;
    158 	int i;
    159 
    160 	sc->sc_iot = ua->ua_iot;
    161 	sc->sc_ioh = ua->ua_ioh;
    162 	/* Force interrupt by issuing a "Get Status" command */
    163 	RL_WREG(RL_DA, RLDA_GS);
    164 	RL_WREG(RL_CS, RLCS_GS|RLCS_IE);
    165 
    166 	for (i = 0; i < 100; i++) {
    167 		DELAY(100000);
    168 		if (RL_RREG(RL_CS) & RLCS_CRDY)
    169 			return 1;
    170 	}
    171 	return 0;
    172 }
    173 
    174 void
    175 rlcattach(struct device *parent, struct device *self, void *aux)
    176 {
    177 	struct rlc_softc *sc = (struct rlc_softc *)self;
    178 	struct uba_attach_args *ua = aux;
    179 	struct rlc_attach_args ra;
    180 	int i, error;
    181 
    182 	sc->sc_iot = ua->ua_iot;
    183 	sc->sc_ioh = ua->ua_ioh;
    184 	sc->sc_dmat = ua->ua_dmat;
    185 	uba_intr_establish(ua->ua_icookie, ua->ua_cvec,
    186 		rlcintr, sc, &sc->sc_intrcnt);
    187 	evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, ua->ua_evcnt,
    188 		sc->sc_dev.dv_xname, "intr");
    189 	uba_reset_establish(rlcreset, self);
    190 
    191 	printf("\n");
    192 
    193 	/*
    194 	 * The RL11 can only have one transfer going at a time,
    195 	 * and max transfer size is one track, so only one dmamap
    196 	 * is needed.
    197 	 */
    198 	error = bus_dmamap_create(sc->sc_dmat, MAXRLXFER, 1, MAXRLXFER, 0,
    199 	    BUS_DMA_ALLOCNOW, &sc->sc_dmam);
    200 	if (error) {
    201 		printf(": Failed to allocate DMA map, error %d\n", error);
    202 		return;
    203 	}
    204 	bufq_alloc(&sc->sc_q, BUFQ_DISKSORT|BUFQ_SORT_CYLINDER);
    205 	for (i = 0; i < RL_MAXDPC; i++) {
    206 		waitcrdy(sc);
    207 		RL_WREG(RL_DA, RLDA_GS|RLDA_RST);
    208 		RL_WREG(RL_CS, RLCS_GS|(i << RLCS_USHFT));
    209 		waitcrdy(sc);
    210 		ra.type = RL_RREG(RL_MP);
    211 		ra.hwid = i;
    212 		if ((RL_RREG(RL_CS) & RLCS_ERR) == 0)
    213 			config_found(&sc->sc_dev, &ra, rlcprint);
    214 	}
    215 }
    216 
    217 int
    218 rlmatch(struct device *parent, struct cfdata *cf, void *aux)
    219 {
    220 	struct rlc_attach_args *ra = aux;
    221 
    222 	if (cf->cf_loc[RLCCF_DRIVE] != RLCCF_DRIVE_DEFAULT &&
    223 	    cf->cf_loc[RLCCF_DRIVE] != ra->hwid)
    224 		return 0;
    225 	return 1;
    226 }
    227 
    228 void
    229 rlattach(struct device *parent, struct device *self, void *aux)
    230 {
    231 	struct rl_softc *rc = (struct rl_softc *)self;
    232 	struct rlc_attach_args *ra = aux;
    233 	struct disklabel *dl;
    234 
    235 	rc->rc_hwid = ra->hwid;
    236 	rc->rc_disk.dk_name = rc->rc_dev.dv_xname;
    237 	disk_attach(&rc->rc_disk);
    238 	dl = rc->rc_disk.dk_label;
    239 	dl->d_npartitions = 3;
    240 	strcpy(dl->d_typename, "RL01");
    241 	if (ra->type & RLMP_DT)
    242 		dl->d_typename[3] = '2';
    243 	dl->d_secsize = DEV_BSIZE; /* XXX - wrong, but OK for now */
    244 	dl->d_nsectors = RL_SPT/2;
    245 	dl->d_ntracks = RL_SPD;
    246 	dl->d_ncylinders = ra->type & RLMP_DT ? RL_TPS02 : RL_TPS01;
    247 	dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
    248 	dl->d_secperunit = dl->d_ncylinders * dl->d_secpercyl;
    249 	dl->d_partitions[0].p_size = dl->d_partitions[2].p_size =
    250 	    dl->d_secperunit;
    251 	dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0;
    252 	dl->d_interleave = dl->d_headswitch = 1;
    253 	dl->d_bbsize = BBSIZE;
    254 	dl->d_sbsize = SBSIZE;
    255 	dl->d_rpm = 2400;
    256 	dl->d_type = DTYPE_DEC;
    257 	printf(": %s, %s\n", dl->d_typename,
    258 	    rlstate((struct rlc_softc *)parent, ra->hwid));
    259 }
    260 
    261 int
    262 rlopen(dev_t dev, int flag, int fmt, struct proc *p)
    263 {
    264 	int part, unit, mask;
    265 	struct disklabel *dl;
    266 	struct rlc_softc *sc;
    267 	struct rl_softc *rc;
    268 	char *msg;
    269 
    270 	/*
    271 	 * Make sure this is a reasonable open request.
    272 	 */
    273 	unit = DISKUNIT(dev);
    274 	if (unit >= rl_cd.cd_ndevs)
    275 		return ENXIO;
    276 	rc = rl_cd.cd_devs[unit];
    277 	if (rc == 0)
    278 		return ENXIO;
    279 
    280 	sc = (struct rlc_softc *)rc->rc_dev.dv_parent;
    281 	/* Check that the disk actually is useable */
    282 	msg = rlstate(sc, rc->rc_hwid);
    283 	if (msg == NULL || msg == rlstates[RLMP_UNLOAD] ||
    284 	    msg == rlstates[RLMP_SPUNDOWN])
    285 		return ENXIO;
    286 	/*
    287 	 * If this is the first open; read in where on the disk we are.
    288 	 */
    289 	dl = rc->rc_disk.dk_label;
    290 	if (rc->rc_state == DK_CLOSED) {
    291 		u_int16_t mp;
    292 		RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
    293 		waitcrdy(sc);
    294 		mp = RL_RREG(RL_MP);
    295 		rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
    296 		rc->rc_cyl = (mp >> 7) & 0777;
    297 		rc->rc_state = DK_OPEN;
    298 		/* Get disk label */
    299 		printf("%s: ", rc->rc_dev.dv_xname);
    300 		if ((msg = readdisklabel(MAKEDISKDEV(RLMAJOR,
    301 		    rc->rc_dev.dv_unit, RAW_PART), rlstrategy, dl, NULL)))
    302 			printf("%s: ", msg);
    303 		printf("size %d sectors\n", dl->d_secperunit);
    304 	}
    305 	part = DISKPART(dev);
    306 	if (part >= dl->d_npartitions)
    307 		return ENXIO;
    308 
    309 	mask = 1 << part;
    310 	switch (fmt) {
    311 	case S_IFCHR:
    312 		rc->rc_disk.dk_copenmask |= mask;
    313 		break;
    314 	case S_IFBLK:
    315 		rc->rc_disk.dk_bopenmask |= mask;
    316 		break;
    317 	}
    318 	rc->rc_disk.dk_openmask |= mask;
    319 	return 0;
    320 }
    321 
    322 int
    323 rlclose(dev_t dev, int flag, int fmt, struct proc *p)
    324 {
    325 	int unit = DISKUNIT(dev);
    326 	struct rl_softc *rc = rl_cd.cd_devs[unit];
    327 	int mask = (1 << DISKPART(dev));
    328 
    329 	switch (fmt) {
    330 	case S_IFCHR:
    331 		rc->rc_disk.dk_copenmask &= ~mask;
    332 		break;
    333 	case S_IFBLK:
    334 		rc->rc_disk.dk_bopenmask &= ~mask;
    335 		break;
    336 	}
    337 	rc->rc_disk.dk_openmask =
    338 	    rc->rc_disk.dk_copenmask | rc->rc_disk.dk_bopenmask;
    339 
    340 	if (rc->rc_disk.dk_openmask == 0)
    341 		rc->rc_state = DK_CLOSED; /* May change pack */
    342 	return 0;
    343 }
    344 
    345 void
    346 rlstrategy(struct buf *bp)
    347 {
    348 	struct disklabel *lp;
    349 	struct rlc_softc *sc;
    350         struct rl_softc *rc;
    351         int unit, s, err;
    352         /*
    353          * Make sure this is a reasonable drive to use.
    354          */
    355         unit = DISKUNIT(bp->b_dev);
    356         if (unit > rl_cd.cd_ndevs || (rc = rl_cd.cd_devs[unit]) == NULL) {
    357                 bp->b_error = ENXIO;
    358                 bp->b_flags |= B_ERROR;
    359                 goto done;
    360         }
    361 	if (rc->rc_state != DK_OPEN) /* How did we end up here at all? */
    362 		panic("rlstrategy: state impossible");
    363 
    364 	lp = rc->rc_disk.dk_label;
    365 	if ((err = bounds_check_with_label(bp, lp, 1)) <= 0)
    366 		goto done;
    367 
    368 	if (bp->b_bcount == 0)
    369 		goto done;
    370 
    371 	bp->b_rawblkno =
    372 	    bp->b_blkno + lp->d_partitions[DISKPART(bp->b_dev)].p_offset;
    373 	bp->b_cylinder = bp->b_rawblkno / lp->d_secpercyl;
    374 	sc = (struct rlc_softc *)rc->rc_dev.dv_parent;
    375 
    376 	s = splbio();
    377 	BUFQ_PUT(&sc->sc_q, bp);
    378 	rlcstart(sc, 0);
    379 	splx(s);
    380 	return;
    381 
    382 done:	biodone(bp);
    383 }
    384 
    385 int
    386 rlioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
    387 {
    388 	struct rl_softc *rc = rl_cd.cd_devs[DISKUNIT(dev)];
    389 	struct disklabel *lp = rc->rc_disk.dk_label;
    390 	int err = 0;
    391 #ifdef __HAVE_OLD_DISKLABEL
    392 	struct disklabel newlabel;
    393 #endif
    394 
    395 	switch (cmd) {
    396 	case DIOCGDINFO:
    397 		bcopy(lp, addr, sizeof (struct disklabel));
    398 		break;
    399 
    400 #ifdef __HAVE_OLD_DISKLABEL
    401 	case ODIOCGDINFO:
    402 		newlabel = *lp;
    403 		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
    404 			return ENOTTY;
    405 		bcopy(&newlabel, addr, sizeof (struct olddisklabel));
    406 		break;
    407 #endif
    408 
    409 	case DIOCGPART:
    410 		((struct partinfo *)addr)->disklab = lp;
    411 		((struct partinfo *)addr)->part =
    412 		    &lp->d_partitions[DISKPART(dev)];
    413 		break;
    414 
    415 	case DIOCSDINFO:
    416 	case DIOCWDINFO:
    417 #ifdef __HAVE_OLD_DISKLABEL
    418 	case ODIOCWDINFO:
    419 	case ODIOCSDINFO:
    420 #endif
    421 	{
    422 		struct disklabel *tp;
    423 
    424 #ifdef __HAVE_OLD_DISKLABEL
    425 		if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
    426 			memset(&newlabel, 0, sizeof newlabel);
    427 			memcpy(&newlabel, addr, sizeof (struct olddisklabel));
    428 			tp = &newlabel;
    429 		} else
    430 #endif
    431 		tp = (struct disklabel *)addr;
    432 
    433 		if ((flag & FWRITE) == 0)
    434 			err = EBADF;
    435 		else
    436 			err = ((
    437 #ifdef __HAVE_OLD_DISKLABEL
    438 			       cmd == ODIOCSDINFO ||
    439 #endif
    440 			       cmd == DIOCSDINFO) ?
    441 			    setdisklabel(lp, tp, 0, 0) :
    442 			    writedisklabel(dev, rlstrategy, lp, 0));
    443 		break;
    444 	}
    445 
    446 	case DIOCWLABEL:
    447 		if ((flag & FWRITE) == 0)
    448 			err = EBADF;
    449 		break;
    450 
    451 	default:
    452 		err = ENOTTY;
    453 	}
    454 	return err;
    455 }
    456 
    457 int
    458 rlsize(dev_t dev)
    459 {
    460 	struct disklabel *dl;
    461 	struct rl_softc *rc;
    462 	int size, unit = DISKUNIT(dev);
    463 
    464 	if ((unit >= rl_cd.cd_ndevs) || ((rc = rl_cd.cd_devs[unit]) == 0))
    465 		return -1;
    466 	dl = rc->rc_disk.dk_label;
    467 	size = dl->d_partitions[DISKPART(dev)].p_size *
    468 	    (dl->d_secsize / DEV_BSIZE);
    469 	return size;
    470 }
    471 
    472 int
    473 rldump(dev_t dev, daddr_t blkno, caddr_t va, size_t size)
    474 {
    475 	/* Not likely... */
    476 	return 0;
    477 }
    478 
    479 int
    480 rlread(dev_t dev, struct uio *uio, int ioflag)
    481 {
    482 	return (physio(rlstrategy, NULL, dev, B_READ, minphys, uio));
    483 }
    484 
    485 int
    486 rlwrite(dev_t dev, struct uio *uio, int ioflag)
    487 {
    488 	return (physio(rlstrategy, NULL, dev, B_WRITE, minphys, uio));
    489 }
    490 
    491 static char *rlerr[] = {
    492 	"no",
    493 	"operation incomplete",
    494 	"read data CRC",
    495 	"header CRC",
    496 	"data late",
    497 	"header not found",
    498 	"",
    499 	"",
    500 	"non-existent memory",
    501 	"memory parity error",
    502 	"",
    503 	"",
    504 	"",
    505 	"",
    506 	"",
    507 	"",
    508 };
    509 
    510 void
    511 rlcintr(void *arg)
    512 {
    513 	struct rlc_softc *sc = arg;
    514 	struct buf *bp;
    515 	u_int16_t cs;
    516 
    517 	bp = sc->sc_active;
    518 	if (bp == 0) {
    519 		printf("%s: strange interrupt\n", sc->sc_dev.dv_xname);
    520 		return;
    521 	}
    522 	bus_dmamap_unload(sc->sc_dmat, sc->sc_dmam);
    523 	sc->sc_active = 0;
    524 	cs = RL_RREG(RL_CS);
    525 	if (cs & RLCS_ERR) {
    526 		int error = (cs & RLCS_ERRMSK) >> 10;
    527 
    528 		printf("%s: %s\n", sc->sc_dev.dv_xname, rlerr[error]);
    529 		bp->b_flags |= B_ERROR;
    530 		bp->b_error = EIO;
    531 		bp->b_resid = bp->b_bcount;
    532 		sc->sc_bytecnt = 0;
    533 	}
    534 	if (sc->sc_bytecnt == 0) /* Finished transfer */
    535 		biodone(bp);
    536 	rlcstart(sc, sc->sc_bytecnt ? bp : 0);
    537 }
    538 
    539 /*
    540  * Start routine. First position the disk to the given position,
    541  * then start reading/writing. An optimization would be to be able
    542  * to handle overlapping seeks between disks.
    543  */
    544 void
    545 rlcstart(struct rlc_softc *sc, struct buf *ob)
    546 {
    547 	struct disklabel *lp;
    548 	struct rl_softc *rc;
    549 	struct buf *bp;
    550 	int bn, cn, sn, tn, blks, err;
    551 
    552 	if (sc->sc_active)
    553 		return;	/* Already doing something */
    554 
    555 	if (ob == 0) {
    556 		bp = BUFQ_GET(&sc->sc_q);
    557 		if (bp == NULL)
    558 			return;	/* Nothing to do */
    559 		sc->sc_bufaddr = bp->b_data;
    560 		sc->sc_diskblk = bp->b_rawblkno;
    561 		sc->sc_bytecnt = bp->b_bcount;
    562 		bp->b_resid = 0;
    563 	} else
    564 		bp = ob;
    565 	sc->sc_active = bp;
    566 
    567 	rc = rl_cd.cd_devs[DISKUNIT(bp->b_dev)];
    568 	bn = sc->sc_diskblk;
    569 	lp = rc->rc_disk.dk_label;
    570 	if (bn) {
    571 		cn = bn / lp->d_secpercyl;
    572 		sn = bn % lp->d_secpercyl;
    573 		tn = sn / lp->d_nsectors;
    574 		sn = sn % lp->d_nsectors;
    575 	} else
    576 		cn = sn = tn = 0;
    577 
    578 	/*
    579 	 * Check if we have to position disk first.
    580 	 */
    581 	if (rc->rc_cyl != cn || rc->rc_head != tn) {
    582 		u_int16_t da = RLDA_SEEK;
    583 		if (cn > rc->rc_cyl)
    584 			da |= ((cn - rc->rc_cyl) << RLDA_CYLSHFT) | RLDA_DIR;
    585 		else
    586 			da |= ((rc->rc_cyl - cn) << RLDA_CYLSHFT);
    587 		if (tn)
    588 			da |= RLDA_HSSEEK;
    589 		waitcrdy(sc);
    590 		RL_WREG(RL_DA, da);
    591 		RL_WREG(RL_CS, RLCS_SEEK | (rc->rc_hwid << RLCS_USHFT));
    592 		waitcrdy(sc);
    593 		rc->rc_cyl = cn;
    594 		rc->rc_head = tn;
    595 	}
    596 	RL_WREG(RL_DA, (cn << RLDA_CYLSHFT) | (tn ? RLDA_HSRW : 0) | (sn << 1));
    597 	blks = sc->sc_bytecnt/DEV_BSIZE;
    598 
    599 	if (sn + blks > RL_SPT/2)
    600 		blks = RL_SPT/2 - sn;
    601 	RL_WREG(RL_MP, -(blks*DEV_BSIZE)/2);
    602 	err = bus_dmamap_load(sc->sc_dmat, sc->sc_dmam, sc->sc_bufaddr,
    603 	    (blks*DEV_BSIZE), (bp->b_flags & B_PHYS ? bp->b_proc : 0),
    604 	    BUS_DMA_NOWAIT);
    605 	if (err)
    606 		panic("%s: bus_dmamap_load failed: %d",
    607 		    sc->sc_dev.dv_xname, err);
    608 	RL_WREG(RL_BA, (sc->sc_dmam->dm_segs[0].ds_addr & 0xffff));
    609 
    610 	/* Count up vars */
    611 	sc->sc_bufaddr += (blks*DEV_BSIZE);
    612 	sc->sc_diskblk += blks;
    613 	sc->sc_bytecnt -= (blks*DEV_BSIZE);
    614 
    615 	if (bp->b_flags & B_READ)
    616 		RL_WREG(RL_CS, RLCS_IE|RLCS_RD|(rc->rc_hwid << RLCS_USHFT));
    617 	else
    618 		RL_WREG(RL_CS, RLCS_IE|RLCS_WD|(rc->rc_hwid << RLCS_USHFT));
    619 }
    620 
    621 /*
    622  * Called once per controller when an ubareset occurs.
    623  * Retracts all disks and restarts active transfers.
    624  */
    625 void
    626 rlcreset(struct device *dev)
    627 {
    628 	struct rlc_softc *sc = (struct rlc_softc *)dev;
    629 	struct rl_softc *rc;
    630 	int i;
    631 	u_int16_t mp;
    632 
    633 	for (i = 0; i < rl_cd.cd_ndevs; i++) {
    634 		if ((rc = rl_cd.cd_devs[i]) == NULL)
    635 			continue;
    636 		if (rc->rc_state != DK_OPEN)
    637 			continue;
    638 
    639 		printf(" %s", rc->rc_dev.dv_xname);
    640 		RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
    641 		waitcrdy(sc);
    642 		mp = RL_RREG(RL_MP);
    643 		rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
    644 		rc->rc_cyl = (mp >> 7) & 0777;
    645 	}
    646 	if (sc->sc_active == 0)
    647 		return;
    648 
    649 	BUFQ_PUT(&sc->sc_q, sc->sc_active);
    650 	sc->sc_active = 0;
    651 	rlcstart(sc, 0);
    652 }
    653