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