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