xref: /netbsd-src/sys/dev/qbus/rl.c (revision 80d9064ac03cbb6a4174695f0d5b237c8766d3d0)
1 /*	$NetBSD: rl.c,v 1.45 2014/07/25 08:10:38 dholland 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.45 2014/07/25 08:10:38 dholland 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 = DTYPE_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 err = 0;
447 #ifdef __HAVE_OLD_DISKLABEL
448 	struct disklabel newlabel;
449 #endif
450 
451 	switch (cmd) {
452 	case DIOCGDINFO:
453 		memcpy(addr, lp, sizeof (struct disklabel));
454 		break;
455 
456 #ifdef __HAVE_OLD_DISKLABEL
457 	case ODIOCGDINFO:
458 		newlabel = *lp;
459 		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
460 			return ENOTTY;
461 		memcpy(addr, &newlabel, sizeof (struct olddisklabel));
462 		break;
463 #endif
464 
465 	case DIOCGPART:
466 		((struct partinfo *)addr)->disklab = lp;
467 		((struct partinfo *)addr)->part =
468 		    &lp->d_partitions[DISKPART(dev)];
469 		break;
470 
471 	case DIOCSDINFO:
472 	case DIOCWDINFO:
473 #ifdef __HAVE_OLD_DISKLABEL
474 	case ODIOCWDINFO:
475 	case ODIOCSDINFO:
476 #endif
477 	{
478 		struct disklabel *tp;
479 
480 #ifdef __HAVE_OLD_DISKLABEL
481 		if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
482 			memset(&newlabel, 0, sizeof newlabel);
483 			memcpy(&newlabel, addr, sizeof (struct olddisklabel));
484 			tp = &newlabel;
485 		} else
486 #endif
487 		tp = (struct disklabel *)addr;
488 
489 		if ((flag & FWRITE) == 0)
490 			err = EBADF;
491 		else {
492 			mutex_enter(&rc->rc_disk.dk_openlock);
493 			err = ((
494 #ifdef __HAVE_OLD_DISKLABEL
495 			       cmd == ODIOCSDINFO ||
496 #endif
497 			       cmd == DIOCSDINFO) ?
498 			    setdisklabel(lp, tp, 0, 0) :
499 			    writedisklabel(dev, rlstrategy, lp, 0));
500 			mutex_exit(&rc->rc_disk.dk_openlock);
501 		}
502 		break;
503 	}
504 
505 	case DIOCWLABEL:
506 		if ((flag & FWRITE) == 0)
507 			err = EBADF;
508 		break;
509 
510 	case DIOCAWEDGE: {
511 		struct dkwedge_info *dkw = (void *) addr;
512 
513 		if ((flag & FWRITE) == 0)
514 			return (EBADF);
515 
516 		/* If the ioctl happens here, the parent is us. */
517 		strcpy(dkw->dkw_parent, device_xname(rc->rc_dev));
518 		return dkwedge_add(dkw);
519 	}
520 
521 	case DIOCDWEDGE: {
522 		struct dkwedge_info *dkw = (void *) addr;
523 
524 		if ((flag & FWRITE) == 0)
525 			return (EBADF);
526 
527 		/* If the ioctl happens here, the parent is us. */
528 		strcpy(dkw->dkw_parent, device_xname(rc->rc_dev));
529 		return dkwedge_del(dkw);
530 	}
531 
532 	case DIOCLWEDGES: {
533 		struct dkwedge_list *dkwl = (void *) addr;
534 
535 		return dkwedge_list(&rc->rc_disk, dkwl, l);
536 	}
537 
538 	default:
539 		err = ENOTTY;
540 		break;
541 	}
542 	return err;
543 }
544 
545 int
546 rlpsize(dev_t dev)
547 {
548 	struct rl_softc * const rc = device_lookup_private(&rl_cd, DISKUNIT(dev));
549 	struct disklabel *dl;
550 	int size;
551 
552 	if (rc == NULL)
553 		return -1;
554 	dl = rc->rc_disk.dk_label;
555 	size = dl->d_partitions[DISKPART(dev)].p_size *
556 	    (dl->d_secsize / DEV_BSIZE);
557 	return size;
558 }
559 
560 int
561 rldump(dev_t dev, daddr_t blkno, void *va, size_t size)
562 {
563 	/* Not likely... */
564 	return 0;
565 }
566 
567 int
568 rlread(dev_t dev, struct uio *uio, int ioflag)
569 {
570 	return (physio(rlstrategy, NULL, dev, B_READ, minphys, uio));
571 }
572 
573 int
574 rlwrite(dev_t dev, struct uio *uio, int ioflag)
575 {
576 	return (physio(rlstrategy, NULL, dev, B_WRITE, minphys, uio));
577 }
578 
579 static const char * const rlerr[] = {
580 	"no",
581 	"operation incomplete",
582 	"read data CRC",
583 	"header CRC",
584 	"data late",
585 	"header not found",
586 	"",
587 	"",
588 	"non-existent memory",
589 	"memory parity error",
590 	"",
591 	"",
592 	"",
593 	"",
594 	"",
595 	"",
596 };
597 
598 void
599 rlcintr(void *arg)
600 {
601 	struct rlc_softc *sc = arg;
602 	struct buf *bp;
603 	u_int16_t cs;
604 
605 	bp = sc->sc_active;
606 	if (bp == 0) {
607 		aprint_error_dev(sc->sc_dev, "strange interrupt\n");
608 		return;
609 	}
610 	bus_dmamap_unload(sc->sc_dmat, sc->sc_dmam);
611 	sc->sc_active = 0;
612 	cs = RL_RREG(RL_CS);
613 	if (cs & RLCS_ERR) {
614 		int error = (cs & RLCS_ERRMSK) >> 10;
615 
616 		aprint_error_dev(sc->sc_dev, "%s\n", rlerr[error]);
617 		bp->b_error = EIO;
618 		bp->b_resid = bp->b_bcount;
619 		sc->sc_bytecnt = 0;
620 	}
621 	if (sc->sc_bytecnt == 0) /* Finished transfer */
622 		biodone(bp);
623 	rlcstart(sc, sc->sc_bytecnt ? bp : 0);
624 }
625 
626 /*
627  * Start routine. First position the disk to the given position,
628  * then start reading/writing. An optimization would be to be able
629  * to handle overlapping seeks between disks.
630  */
631 void
632 rlcstart(struct rlc_softc *sc, struct buf *ob)
633 {
634 	struct disklabel *lp;
635 	struct rl_softc *rc;
636 	struct buf *bp;
637 	int bn, cn, sn, tn, blks, err;
638 
639 	if (sc->sc_active)
640 		return;	/* Already doing something */
641 
642 	if (ob == 0) {
643 		bp = bufq_get(sc->sc_q);
644 		if (bp == NULL)
645 			return;	/* Nothing to do */
646 		sc->sc_bufaddr = bp->b_data;
647 		sc->sc_diskblk = bp->b_rawblkno;
648 		sc->sc_bytecnt = bp->b_bcount;
649 		bp->b_resid = 0;
650 	} else
651 		bp = ob;
652 	sc->sc_active = bp;
653 
654 	rc = device_lookup_private(&rl_cd, DISKUNIT(bp->b_dev));
655 	bn = sc->sc_diskblk;
656 	lp = rc->rc_disk.dk_label;
657 	if (bn) {
658 		cn = bn / lp->d_secpercyl;
659 		sn = bn % lp->d_secpercyl;
660 		tn = sn / lp->d_nsectors;
661 		sn = sn % lp->d_nsectors;
662 	} else
663 		cn = sn = tn = 0;
664 
665 	/*
666 	 * Check if we have to position disk first.
667 	 */
668 	if (rc->rc_cyl != cn || rc->rc_head != tn) {
669 		u_int16_t da = RLDA_SEEK;
670 		if (cn > rc->rc_cyl)
671 			da |= ((cn - rc->rc_cyl) << RLDA_CYLSHFT) | RLDA_DIR;
672 		else
673 			da |= ((rc->rc_cyl - cn) << RLDA_CYLSHFT);
674 		if (tn)
675 			da |= RLDA_HSSEEK;
676 		waitcrdy(sc);
677 		RL_WREG(RL_DA, da);
678 		RL_WREG(RL_CS, RLCS_SEEK | (rc->rc_hwid << RLCS_USHFT));
679 		waitcrdy(sc);
680 		rc->rc_cyl = cn;
681 		rc->rc_head = tn;
682 	}
683 	RL_WREG(RL_DA, (cn << RLDA_CYLSHFT) | (tn ? RLDA_HSRW : 0) | (sn << 1));
684 	blks = sc->sc_bytecnt/DEV_BSIZE;
685 
686 	if (sn + blks > RL_SPT/2)
687 		blks = RL_SPT/2 - sn;
688 	RL_WREG(RL_MP, -(blks*DEV_BSIZE)/2);
689 	err = bus_dmamap_load(sc->sc_dmat, sc->sc_dmam, sc->sc_bufaddr,
690 	    (blks*DEV_BSIZE), (bp->b_flags & B_PHYS ? bp->b_proc : 0),
691 	    BUS_DMA_NOWAIT);
692 	if (err)
693 		panic("%s: bus_dmamap_load failed: %d",
694 		    device_xname(sc->sc_dev), err);
695 	RL_WREG(RL_BA, (sc->sc_dmam->dm_segs[0].ds_addr & 0xffff));
696 
697 	/* Count up vars */
698 	sc->sc_bufaddr = (char *)sc->sc_bufaddr + (blks*DEV_BSIZE);
699 	sc->sc_diskblk += blks;
700 	sc->sc_bytecnt -= (blks*DEV_BSIZE);
701 
702 	if (bp->b_flags & B_READ)
703 		RL_WREG(RL_CS, RLCS_IE|RLCS_RD|(rc->rc_hwid << RLCS_USHFT));
704 	else
705 		RL_WREG(RL_CS, RLCS_IE|RLCS_WD|(rc->rc_hwid << RLCS_USHFT));
706 }
707 
708 /*
709  * Called once per controller when an ubareset occurs.
710  * Retracts all disks and restarts active transfers.
711  */
712 void
713 rlcreset(device_t dev)
714 {
715 	struct rlc_softc *sc = device_private(dev);
716 	struct rl_softc *rc;
717 	int i;
718 	u_int16_t mp;
719 
720 	for (i = 0; i < rl_cd.cd_ndevs; i++) {
721 		if ((rc = device_lookup_private(&rl_cd, i)) == NULL)
722 			continue;
723 		if (rc->rc_state != DK_OPEN)
724 			continue;
725 		if (rc->rc_rlc != sc)
726 			continue;
727 
728 		RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
729 		waitcrdy(sc);
730 		mp = RL_RREG(RL_MP);
731 		rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
732 		rc->rc_cyl = (mp >> 7) & 0777;
733 	}
734 	if (sc->sc_active == 0)
735 		return;
736 
737 	bufq_put(sc->sc_q, sc->sc_active);
738 	sc->sc_active = 0;
739 	rlcstart(sc, 0);
740 }
741