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