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