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