Home | History | Annotate | Line # | Download | only in qbus
rl.c revision 1.37
      1 /*	$NetBSD: rl.c,v 1.37 2007/10/19 12:01:09 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.37 2007/10/19 12:01:09 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 <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(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 	disk_init(&rc->rc_disk, rc->rc_dev.dv_xname, &rldkdriver);
    257 	disk_attach(&rc->rc_disk);
    258 	dl = rc->rc_disk.dk_label;
    259 	dl->d_npartitions = 3;
    260 	strcpy(dl->d_typename, "RL01");
    261 	if (ra->type & RLMP_DT)
    262 		dl->d_typename[3] = '2';
    263 	dl->d_secsize = DEV_BSIZE; /* XXX - wrong, but OK for now */
    264 	dl->d_nsectors = RL_SPT/2;
    265 	dl->d_ntracks = RL_SPD;
    266 	dl->d_ncylinders = ra->type & RLMP_DT ? RL_TPS02 : RL_TPS01;
    267 	dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
    268 	dl->d_secperunit = dl->d_ncylinders * dl->d_secpercyl;
    269 	dl->d_partitions[0].p_size = dl->d_partitions[2].p_size =
    270 	    dl->d_secperunit;
    271 	dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0;
    272 	dl->d_interleave = dl->d_headswitch = 1;
    273 	dl->d_bbsize = BBSIZE;
    274 	dl->d_sbsize = SBLOCKSIZE;
    275 	dl->d_rpm = 2400;
    276 	dl->d_type = DTYPE_DEC;
    277 	printf(": %s, %s\n", dl->d_typename,
    278 	    rlstate((struct rlc_softc *)parent, ra->hwid));
    279 
    280 	/*
    281 	 * XXX We should try to discovery wedges here, but
    282 	 * XXX that would mean loading up the pack and being
    283 	 * XXX able to do I/O.  Should use config_defer() here.
    284 	 */
    285 }
    286 
    287 int
    288 rlopen(dev_t dev, int flag, int fmt, struct lwp *l)
    289 {
    290 	int error, part, unit, mask;
    291 	struct disklabel *dl;
    292 	struct rlc_softc *sc;
    293 	struct rl_softc *rc;
    294 	const char *msg;
    295 
    296 	/*
    297 	 * Make sure this is a reasonable open request.
    298 	 */
    299 	unit = DISKUNIT(dev);
    300 	if (unit >= rl_cd.cd_ndevs)
    301 		return ENXIO;
    302 	rc = rl_cd.cd_devs[unit];
    303 	if (rc == 0)
    304 		return ENXIO;
    305 
    306 	part = DISKPART(dev);
    307 
    308 	mutex_enter(&rc->rc_disk.dk_openlock);
    309 
    310 	/*
    311 	 * If there are wedges, and this is not RAW_PART, then we
    312 	 * need to fail.
    313 	 */
    314 	if (rc->rc_disk.dk_nwedges != 0 && part != RAW_PART) {
    315 		error = EBUSY;
    316 		goto bad1;
    317 	}
    318 
    319 	sc = (struct rlc_softc *)device_parent(&rc->rc_dev);
    320 	/* Check that the disk actually is useable */
    321 	msg = rlstate(sc, rc->rc_hwid);
    322 	if (msg == NULL || msg == rlstates[RLMP_UNLOAD] ||
    323 	    msg == rlstates[RLMP_SPUNDOWN]) {
    324 		error = ENXIO;
    325 		goto bad1;
    326 	}
    327 	/*
    328 	 * If this is the first open; read in where on the disk we are.
    329 	 */
    330 	dl = rc->rc_disk.dk_label;
    331 	if (rc->rc_state == DK_CLOSED) {
    332 		u_int16_t mp;
    333 		int maj;
    334 		RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
    335 		waitcrdy(sc);
    336 		mp = RL_RREG(RL_MP);
    337 		rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
    338 		rc->rc_cyl = (mp >> 7) & 0777;
    339 		rc->rc_state = DK_OPEN;
    340 		/* Get disk label */
    341 		printf("%s: ", rc->rc_dev.dv_xname);
    342 		maj = cdevsw_lookup_major(&rl_cdevsw);
    343 		if ((msg = readdisklabel(MAKEDISKDEV(maj,
    344 		    device_unit(&rc->rc_dev), RAW_PART), rlstrategy, dl, NULL)))
    345 			printf("%s: ", msg);
    346 		printf("size %d sectors\n", dl->d_secperunit);
    347 	}
    348 	if (part >= dl->d_npartitions) {
    349 		error = ENXIO;
    350 		goto bad1;
    351 	}
    352 
    353 	mask = 1 << part;
    354 	switch (fmt) {
    355 	case S_IFCHR:
    356 		rc->rc_disk.dk_copenmask |= mask;
    357 		break;
    358 	case S_IFBLK:
    359 		rc->rc_disk.dk_bopenmask |= mask;
    360 		break;
    361 	}
    362 	rc->rc_disk.dk_openmask |= mask;
    363 	error = 0;
    364  bad1:
    365 	mutex_exit(&rc->rc_disk.dk_openlock);
    366 	return (error);
    367 }
    368 
    369 int
    370 rlclose(dev_t dev, int flag, int fmt, struct lwp *l)
    371 {
    372 	int unit = DISKUNIT(dev);
    373 	struct rl_softc *rc = rl_cd.cd_devs[unit];
    374 	int mask = (1 << DISKPART(dev));
    375 
    376 	mutex_enter(&rc->rc_disk.dk_openlock);
    377 
    378 	switch (fmt) {
    379 	case S_IFCHR:
    380 		rc->rc_disk.dk_copenmask &= ~mask;
    381 		break;
    382 	case S_IFBLK:
    383 		rc->rc_disk.dk_bopenmask &= ~mask;
    384 		break;
    385 	}
    386 	rc->rc_disk.dk_openmask =
    387 	    rc->rc_disk.dk_copenmask | rc->rc_disk.dk_bopenmask;
    388 
    389 	if (rc->rc_disk.dk_openmask == 0)
    390 		rc->rc_state = DK_CLOSED; /* May change pack */
    391 	mutex_exit(&rc->rc_disk.dk_openlock);
    392 	return 0;
    393 }
    394 
    395 void
    396 rlstrategy(struct buf *bp)
    397 {
    398 	struct disklabel *lp;
    399 	struct rlc_softc *sc;
    400 	struct rl_softc *rc;
    401 	int unit, s, err;
    402 	/*
    403 	 * Make sure this is a reasonable drive to use.
    404 	 */
    405 	unit = DISKUNIT(bp->b_dev);
    406 	if (unit > rl_cd.cd_ndevs || (rc = rl_cd.cd_devs[unit]) == NULL) {
    407 		bp->b_error = ENXIO;
    408 		goto done;
    409 	}
    410 	if (rc->rc_state != DK_OPEN) /* How did we end up here at all? */
    411 		panic("rlstrategy: state impossible");
    412 
    413 	lp = rc->rc_disk.dk_label;
    414 	if ((err = bounds_check_with_label(&rc->rc_disk, bp, 1)) <= 0)
    415 		goto done;
    416 
    417 	if (bp->b_bcount == 0)
    418 		goto done;
    419 
    420 	bp->b_rawblkno =
    421 	    bp->b_blkno + lp->d_partitions[DISKPART(bp->b_dev)].p_offset;
    422 	bp->b_cylinder = bp->b_rawblkno / lp->d_secpercyl;
    423 	sc = (struct rlc_softc *)device_parent(&rc->rc_dev);
    424 
    425 	s = splbio();
    426 	BUFQ_PUT(sc->sc_q, bp);
    427 	rlcstart(sc, 0);
    428 	splx(s);
    429 	return;
    430 
    431 done:	biodone(bp);
    432 }
    433 
    434 int
    435 rlioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
    436 {
    437 	struct rl_softc *rc = rl_cd.cd_devs[DISKUNIT(dev)];
    438 	struct disklabel *lp = rc->rc_disk.dk_label;
    439 	int err = 0;
    440 #ifdef __HAVE_OLD_DISKLABEL
    441 	struct disklabel newlabel;
    442 #endif
    443 
    444 	switch (cmd) {
    445 	case DIOCGDINFO:
    446 		bcopy(lp, addr, sizeof (struct disklabel));
    447 		break;
    448 
    449 #ifdef __HAVE_OLD_DISKLABEL
    450 	case ODIOCGDINFO:
    451 		newlabel = *lp;
    452 		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
    453 			return ENOTTY;
    454 		bcopy(&newlabel, addr, sizeof (struct olddisklabel));
    455 		break;
    456 #endif
    457 
    458 	case DIOCGPART:
    459 		((struct partinfo *)addr)->disklab = lp;
    460 		((struct partinfo *)addr)->part =
    461 		    &lp->d_partitions[DISKPART(dev)];
    462 		break;
    463 
    464 	case DIOCSDINFO:
    465 	case DIOCWDINFO:
    466 #ifdef __HAVE_OLD_DISKLABEL
    467 	case ODIOCWDINFO:
    468 	case ODIOCSDINFO:
    469 #endif
    470 	{
    471 		struct disklabel *tp;
    472 
    473 #ifdef __HAVE_OLD_DISKLABEL
    474 		if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
    475 			memset(&newlabel, 0, sizeof newlabel);
    476 			memcpy(&newlabel, addr, sizeof (struct olddisklabel));
    477 			tp = &newlabel;
    478 		} else
    479 #endif
    480 		tp = (struct disklabel *)addr;
    481 
    482 		if ((flag & FWRITE) == 0)
    483 			err = EBADF;
    484 		else {
    485 			mutex_enter(&rc->rc_disk.dk_openlock);
    486 			err = ((
    487 #ifdef __HAVE_OLD_DISKLABEL
    488 			       cmd == ODIOCSDINFO ||
    489 #endif
    490 			       cmd == DIOCSDINFO) ?
    491 			    setdisklabel(lp, tp, 0, 0) :
    492 			    writedisklabel(dev, rlstrategy, lp, 0));
    493 			mutex_exit(&rc->rc_disk.dk_openlock);
    494 		}
    495 		break;
    496 	}
    497 
    498 	case DIOCWLABEL:
    499 		if ((flag & FWRITE) == 0)
    500 			err = EBADF;
    501 		break;
    502 
    503 	case DIOCAWEDGE:
    504 	    {
    505 		struct dkwedge_info *dkw = (void *) addr;
    506 
    507 		if ((flag & FWRITE) == 0)
    508 			return (EBADF);
    509 
    510 		/* If the ioctl happens here, the parent is us. */
    511 		strcpy(dkw->dkw_parent, rc->rc_dev.dv_xname);
    512 		return (dkwedge_add(dkw));
    513 	    }
    514 
    515 	case DIOCDWEDGE:
    516 	    {
    517 		struct dkwedge_info *dkw = (void *) addr;
    518 
    519 		if ((flag & FWRITE) == 0)
    520 			return (EBADF);
    521 
    522 		/* If the ioctl happens here, the parent is us. */
    523 		strcpy(dkw->dkw_parent, rc->rc_dev.dv_xname);
    524 		return (dkwedge_del(dkw));
    525 	    }
    526 
    527 	case DIOCLWEDGES:
    528 	    {
    529 		struct dkwedge_list *dkwl = (void *) addr;
    530 
    531 		return (dkwedge_list(&rc->rc_disk, dkwl, l));
    532 	    }
    533 
    534 	default:
    535 		err = ENOTTY;
    536 	}
    537 	return err;
    538 }
    539 
    540 int
    541 rlsize(dev_t dev)
    542 {
    543 	struct disklabel *dl;
    544 	struct rl_softc *rc;
    545 	int size, unit = DISKUNIT(dev);
    546 
    547 	if ((unit >= rl_cd.cd_ndevs) || ((rc = rl_cd.cd_devs[unit]) == 0))
    548 		return -1;
    549 	dl = rc->rc_disk.dk_label;
    550 	size = dl->d_partitions[DISKPART(dev)].p_size *
    551 	    (dl->d_secsize / DEV_BSIZE);
    552 	return size;
    553 }
    554 
    555 int
    556 rldump(dev_t dev, daddr_t blkno, void *va, size_t size)
    557 {
    558 	/* Not likely... */
    559 	return 0;
    560 }
    561 
    562 int
    563 rlread(dev_t dev, struct uio *uio, int ioflag)
    564 {
    565 	return (physio(rlstrategy, NULL, dev, B_READ, minphys, uio));
    566 }
    567 
    568 int
    569 rlwrite(dev_t dev, struct uio *uio, int ioflag)
    570 {
    571 	return (physio(rlstrategy, NULL, dev, B_WRITE, minphys, uio));
    572 }
    573 
    574 static const char *rlerr[] = {
    575 	"no",
    576 	"operation incomplete",
    577 	"read data CRC",
    578 	"header CRC",
    579 	"data late",
    580 	"header not found",
    581 	"",
    582 	"",
    583 	"non-existent memory",
    584 	"memory parity error",
    585 	"",
    586 	"",
    587 	"",
    588 	"",
    589 	"",
    590 	"",
    591 };
    592 
    593 void
    594 rlcintr(void *arg)
    595 {
    596 	struct rlc_softc *sc = arg;
    597 	struct buf *bp;
    598 	u_int16_t cs;
    599 
    600 	bp = sc->sc_active;
    601 	if (bp == 0) {
    602 		printf("%s: strange interrupt\n", sc->sc_dev.dv_xname);
    603 		return;
    604 	}
    605 	bus_dmamap_unload(sc->sc_dmat, sc->sc_dmam);
    606 	sc->sc_active = 0;
    607 	cs = RL_RREG(RL_CS);
    608 	if (cs & RLCS_ERR) {
    609 		int error = (cs & RLCS_ERRMSK) >> 10;
    610 
    611 		printf("%s: %s\n", sc->sc_dev.dv_xname, rlerr[error]);
    612 		bp->b_error = EIO;
    613 		bp->b_resid = bp->b_bcount;
    614 		sc->sc_bytecnt = 0;
    615 	}
    616 	if (sc->sc_bytecnt == 0) /* Finished transfer */
    617 		biodone(bp);
    618 	rlcstart(sc, sc->sc_bytecnt ? bp : 0);
    619 }
    620 
    621 /*
    622  * Start routine. First position the disk to the given position,
    623  * then start reading/writing. An optimization would be to be able
    624  * to handle overlapping seeks between disks.
    625  */
    626 void
    627 rlcstart(struct rlc_softc *sc, struct buf *ob)
    628 {
    629 	struct disklabel *lp;
    630 	struct rl_softc *rc;
    631 	struct buf *bp;
    632 	int bn, cn, sn, tn, blks, err;
    633 
    634 	if (sc->sc_active)
    635 		return;	/* Already doing something */
    636 
    637 	if (ob == 0) {
    638 		bp = BUFQ_GET(sc->sc_q);
    639 		if (bp == NULL)
    640 			return;	/* Nothing to do */
    641 		sc->sc_bufaddr = bp->b_data;
    642 		sc->sc_diskblk = bp->b_rawblkno;
    643 		sc->sc_bytecnt = bp->b_bcount;
    644 		bp->b_resid = 0;
    645 	} else
    646 		bp = ob;
    647 	sc->sc_active = bp;
    648 
    649 	rc = rl_cd.cd_devs[DISKUNIT(bp->b_dev)];
    650 	bn = sc->sc_diskblk;
    651 	lp = rc->rc_disk.dk_label;
    652 	if (bn) {
    653 		cn = bn / lp->d_secpercyl;
    654 		sn = bn % lp->d_secpercyl;
    655 		tn = sn / lp->d_nsectors;
    656 		sn = sn % lp->d_nsectors;
    657 	} else
    658 		cn = sn = tn = 0;
    659 
    660 	/*
    661 	 * Check if we have to position disk first.
    662 	 */
    663 	if (rc->rc_cyl != cn || rc->rc_head != tn) {
    664 		u_int16_t da = RLDA_SEEK;
    665 		if (cn > rc->rc_cyl)
    666 			da |= ((cn - rc->rc_cyl) << RLDA_CYLSHFT) | RLDA_DIR;
    667 		else
    668 			da |= ((rc->rc_cyl - cn) << RLDA_CYLSHFT);
    669 		if (tn)
    670 			da |= RLDA_HSSEEK;
    671 		waitcrdy(sc);
    672 		RL_WREG(RL_DA, da);
    673 		RL_WREG(RL_CS, RLCS_SEEK | (rc->rc_hwid << RLCS_USHFT));
    674 		waitcrdy(sc);
    675 		rc->rc_cyl = cn;
    676 		rc->rc_head = tn;
    677 	}
    678 	RL_WREG(RL_DA, (cn << RLDA_CYLSHFT) | (tn ? RLDA_HSRW : 0) | (sn << 1));
    679 	blks = sc->sc_bytecnt/DEV_BSIZE;
    680 
    681 	if (sn + blks > RL_SPT/2)
    682 		blks = RL_SPT/2 - sn;
    683 	RL_WREG(RL_MP, -(blks*DEV_BSIZE)/2);
    684 	err = bus_dmamap_load(sc->sc_dmat, sc->sc_dmam, sc->sc_bufaddr,
    685 	    (blks*DEV_BSIZE), (bp->b_flags & B_PHYS ? bp->b_proc : 0),
    686 	    BUS_DMA_NOWAIT);
    687 	if (err)
    688 		panic("%s: bus_dmamap_load failed: %d",
    689 		    sc->sc_dev.dv_xname, err);
    690 	RL_WREG(RL_BA, (sc->sc_dmam->dm_segs[0].ds_addr & 0xffff));
    691 
    692 	/* Count up vars */
    693 	sc->sc_bufaddr = (char *)sc->sc_bufaddr + (blks*DEV_BSIZE);
    694 	sc->sc_diskblk += blks;
    695 	sc->sc_bytecnt -= (blks*DEV_BSIZE);
    696 
    697 	if (bp->b_flags & B_READ)
    698 		RL_WREG(RL_CS, RLCS_IE|RLCS_RD|(rc->rc_hwid << RLCS_USHFT));
    699 	else
    700 		RL_WREG(RL_CS, RLCS_IE|RLCS_WD|(rc->rc_hwid << RLCS_USHFT));
    701 }
    702 
    703 /*
    704  * Called once per controller when an ubareset occurs.
    705  * Retracts all disks and restarts active transfers.
    706  */
    707 void
    708 rlcreset(struct device *dev)
    709 {
    710 	struct rlc_softc *sc = (struct rlc_softc *)dev;
    711 	struct rl_softc *rc;
    712 	int i;
    713 	u_int16_t mp;
    714 
    715 	for (i = 0; i < rl_cd.cd_ndevs; i++) {
    716 		if ((rc = rl_cd.cd_devs[i]) == NULL)
    717 			continue;
    718 		if (rc->rc_state != DK_OPEN)
    719 			continue;
    720 
    721 		printf(" %s", rc->rc_dev.dv_xname);
    722 		RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
    723 		waitcrdy(sc);
    724 		mp = RL_RREG(RL_MP);
    725 		rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
    726 		rc->rc_cyl = (mp >> 7) & 0777;
    727 	}
    728 	if (sc->sc_active == 0)
    729 		return;
    730 
    731 	BUFQ_PUT(sc->sc_q, sc->sc_active);
    732 	sc->sc_active = 0;
    733 	rlcstart(sc, 0);
    734 }
    735