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