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