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