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