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