xref: /netbsd-src/sys/dev/qbus/rl.c (revision 220b5c059a84c51ea44107ea8951a57ffaecdc8c)
1 /*	$NetBSD: rl.c,v 1.10 2001/11/13 07:11:25 lukem 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.10 2001/11/13 07:11:25 lukem 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/stat.h>
56 #include <sys/dkio.h>
57 #include <sys/fcntl.h>
58 
59 #include <ufs/ufs/dinode.h>
60 #include <ufs/ffs/fs.h>
61 
62 #include <machine/bus.h>
63 
64 #include <dev/qbus/ubavar.h>
65 #include <dev/qbus/rlreg.h>
66 
67 #include "ioconf.h"
68 #include "locators.h"
69 
70 struct rlc_softc {
71 	struct device sc_dev;
72 	struct evcnt sc_intrcnt;
73 	bus_space_tag_t sc_iot;
74 	bus_space_handle_t sc_ioh;
75 	bus_dma_tag_t sc_dmat;
76 	bus_dmamap_t sc_dmam;
77 	struct buf_queue sc_q;		/* Queue of waiting bufs */
78 	struct buf *sc_active;		/* Currently active buf */
79 	caddr_t sc_bufaddr;		/* Current in-core address */
80 	int sc_diskblk;			/* Current block on disk */
81 	int sc_bytecnt;			/* How much left to transfer */
82 };
83 
84 struct rl_softc {
85 	struct device rc_dev;
86 	struct disk rc_disk;
87 	int rc_state;
88 	int rc_head;
89 	int rc_cyl;
90 	int rc_hwid;
91 };
92 
93 static	int rlcmatch(struct device *, struct cfdata *, void *);
94 static	void rlcattach(struct device *, struct device *, void *);
95 static	int rlcprint(void *, const char *);
96 static	void rlcintr(void *);
97 static	int rlmatch(struct device *, struct cfdata *, void *);
98 static	void rlattach(struct device *, struct device *, void *);
99 static	void rlcstart(struct rlc_softc *, struct buf *);
100 static	void waitcrdy(struct rlc_softc *);
101 static	void rlreset(struct device *);
102 cdev_decl(rl);
103 bdev_decl(rl);
104 
105 struct cfattach rlc_ca = {
106 	sizeof(struct rlc_softc), rlcmatch, rlcattach
107 };
108 
109 struct cfattach rl_ca = {
110 	sizeof(struct rl_softc), rlmatch, rlattach
111 };
112 
113 struct rlc_attach_args {
114 	u_int16_t type;
115 	int hwid;
116 };
117 
118 #define	MAXRLXFER (RL_BPS * RL_SPT)
119 #define	RLMAJOR	14
120 
121 #define	RL_WREG(reg, val) \
122 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, (reg), (val))
123 #define RL_RREG(reg) \
124 	bus_space_read_2(sc->sc_iot, sc->sc_ioh, (reg))
125 
126 void
127 waitcrdy(struct rlc_softc *sc)
128 {
129 	int i;
130 
131 	for (i = 0; i < 1000; i++) {
132 		DELAY(10000);
133 		if (RL_RREG(RL_CS) & RLCS_CRDY)
134 			return;
135 	}
136 	printf("%s: never got ready\n", sc->sc_dev.dv_xname); /* ?panic? */
137 }
138 
139 int
140 rlcprint(void *aux, const char *name)
141 {
142 	struct rlc_attach_args *ra = aux;
143 
144 	if (name)
145 		printf("RL0%d at %s", ra->type & RLMP_DT ? '2' : '1', name);
146 	printf(" drive %d", ra->hwid);
147 	return UNCONF;
148 }
149 
150 /*
151  * Force the controller to interrupt.
152  */
153 int
154 rlcmatch(struct device *parent, struct cfdata *cf, void *aux)
155 {
156 	struct uba_attach_args *ua = aux;
157 	struct rlc_softc ssc, *sc = &ssc;
158 	int i;
159 
160 	sc->sc_iot = ua->ua_iot;
161 	sc->sc_ioh = ua->ua_ioh;
162 	/* Force interrupt by issuing a "Get Status" command */
163 	RL_WREG(RL_DA, RLDA_GS);
164 	RL_WREG(RL_CS, RLCS_GS|RLCS_IE);
165 
166 	for (i = 0; i < 100; i++) {
167 		DELAY(100000);
168 		if (RL_RREG(RL_CS) & RLCS_CRDY)
169 			return 1;
170 	}
171 	return 0;
172 }
173 
174 void
175 rlcattach(struct device *parent, struct device *self, void *aux)
176 {
177 	struct rlc_softc *sc = (struct rlc_softc *)self;
178 	struct uba_attach_args *ua = aux;
179 	struct rlc_attach_args ra;
180 	int i, error;
181 
182 	sc->sc_iot = ua->ua_iot;
183 	sc->sc_ioh = ua->ua_ioh;
184 	sc->sc_dmat = ua->ua_dmat;
185 	uba_intr_establish(ua->ua_icookie, ua->ua_cvec,
186 		rlcintr, sc, &sc->sc_intrcnt);
187 	evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, ua->ua_evcnt,
188 		sc->sc_dev.dv_xname, "intr");
189 	printf("\n");
190 
191 	/*
192 	 * The RL11 can only have one transfer going at a time,
193 	 * and max transfer size is one track, so only one dmamap
194 	 * is needed.
195 	 */
196 	error = bus_dmamap_create(sc->sc_dmat, MAXRLXFER, 1, MAXRLXFER, 0,
197 	    BUS_DMA_ALLOCNOW, &sc->sc_dmam);
198 	if (error) {
199 		printf(": Failed to allocate DMA map, error %d\n", error);
200 		return;
201 	}
202 	BUFQ_INIT(&sc->sc_q);
203 	for (i = 0; i < RL_MAXDPC; i++) {
204 		waitcrdy(sc);
205 		RL_WREG(RL_DA, RLDA_GS|RLDA_RST);
206 		RL_WREG(RL_CS, RLCS_GS|(i << RLCS_USHFT));
207 		waitcrdy(sc);
208 		ra.type = RL_RREG(RL_MP);
209 		ra.hwid = i;
210 		if ((RL_RREG(RL_CS) & RLCS_ERR) == 0)
211 			config_found(&sc->sc_dev, &ra, rlcprint);
212 	}
213 }
214 
215 int
216 rlmatch(struct device *parent, struct cfdata *cf, void *aux)
217 {
218 	struct rlc_attach_args *ra = aux;
219 
220 	if (cf->cf_loc[RLCCF_DRIVE] != RLCCF_DRIVE_DEFAULT &&
221 	    cf->cf_loc[RLCCF_DRIVE] != ra->hwid)
222 		return 0;
223 	return 1;
224 }
225 
226 void
227 rlattach(struct device *parent, struct device *self, void *aux)
228 {
229 	struct rl_softc *rc = (struct rl_softc *)self;
230 	struct rlc_attach_args *ra = aux;
231 	struct disklabel *dl;
232 
233 	uba_reset_establish(rlreset, self);
234 
235 	rc->rc_hwid = ra->hwid;
236 	rc->rc_disk.dk_name = rc->rc_dev.dv_xname;
237 	disk_attach(&rc->rc_disk);
238 	dl = rc->rc_disk.dk_label;
239 	dl->d_npartitions = 3;
240 	strcpy(dl->d_typename, "RL01");
241 	if (ra->type & RLMP_DT)
242 		dl->d_typename[3] = '2';
243 	dl->d_secsize = DEV_BSIZE; /* XXX - wrong, but OK for now */
244 	dl->d_nsectors = RL_SPT/2;
245 	dl->d_ntracks = RL_SPD;
246 	dl->d_ncylinders = ra->type & RLMP_DT ? RL_TPS02 : RL_TPS01;
247 	dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
248 	dl->d_secperunit = dl->d_ncylinders * dl->d_secpercyl;
249 	dl->d_partitions[0].p_size = dl->d_partitions[2].p_size =
250 	    dl->d_secperunit;
251 	dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0;
252 	dl->d_interleave = dl->d_headswitch = 1;
253 	dl->d_bbsize = BBSIZE;
254 	dl->d_sbsize = SBSIZE;
255 	dl->d_rpm = 2400;
256 	dl->d_type = DTYPE_DEC;
257 	printf(": %s\n", dl->d_typename);
258 }
259 
260 int
261 rlopen(dev_t dev, int flag, int fmt, struct proc *p)
262 {
263 	int part, unit, mask;
264 	struct disklabel *dl;
265 	struct rlc_softc *sc;
266 	struct rl_softc *rc;
267 	char *msg;
268 	/*
269 	 * Make sure this is a reasonable open request.
270 	 */
271 	unit = DISKUNIT(dev);
272 	if (unit >= rl_cd.cd_ndevs)
273 		return ENXIO;
274 	rc = rl_cd.cd_devs[unit];
275 	if (rc == 0)
276 		return ENXIO;
277 
278 	sc = (struct rlc_softc *)rc->rc_dev.dv_parent;
279 	/* XXX - check that the disk actually is useable */
280 	/*
281 	 * If this is the first open; read in where on the disk we are.
282 	 */
283 	dl = rc->rc_disk.dk_label;
284 	if (rc->rc_state == DK_CLOSED) {
285 		u_int16_t mp;
286 		RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
287 		waitcrdy(sc);
288 		mp = RL_RREG(RL_MP);
289 		rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
290 		rc->rc_cyl = (mp >> 7) & 0777;
291 		rc->rc_state = DK_OPEN;
292 		/* Get disk label */
293 		printf("%s: ", rc->rc_dev.dv_xname);
294 		if ((msg = readdisklabel(MAKEDISKDEV(RLMAJOR,
295 		    rc->rc_dev.dv_unit, RAW_PART), rlstrategy, dl, NULL)))
296 			printf("%s: ", msg);
297 		printf("size %d sectors\n", dl->d_secperunit);
298 	}
299 	part = DISKPART(dev);
300 	if (part >= dl->d_npartitions)
301 		return ENXIO;
302 
303 	mask = 1 << part;
304 	switch (fmt) {
305 	case S_IFCHR:
306 		rc->rc_disk.dk_copenmask |= mask;
307 		break;
308 	case S_IFBLK:
309 		rc->rc_disk.dk_bopenmask |= mask;
310 		break;
311 	}
312 	rc->rc_disk.dk_openmask |= mask;
313 	return 0;
314 }
315 
316 int
317 rlclose(dev_t dev, int flag, int fmt, struct proc *p)
318 {
319 	int unit = DISKUNIT(dev);
320 	struct rl_softc *rc = rl_cd.cd_devs[unit];
321 	int mask = (1 << DISKPART(dev));
322 
323 	switch (fmt) {
324 	case S_IFCHR:
325 		rc->rc_disk.dk_copenmask &= ~mask;
326 		break;
327 	case S_IFBLK:
328 		rc->rc_disk.dk_bopenmask &= ~mask;
329 		break;
330 	}
331 	rc->rc_disk.dk_openmask =
332 	    rc->rc_disk.dk_copenmask | rc->rc_disk.dk_bopenmask;
333 
334 	if (rc->rc_disk.dk_openmask == 0)
335 		rc->rc_state = DK_CLOSED; /* May change pack */
336 	return 0;
337 }
338 
339 void
340 rlstrategy(struct buf *bp)
341 {
342 	struct disklabel *lp;
343 	struct rlc_softc *sc;
344         struct rl_softc *rc;
345         int unit, s, err;
346         /*
347          * Make sure this is a reasonable drive to use.
348          */
349         unit = DISKUNIT(bp->b_dev);
350         if (unit > rl_cd.cd_ndevs || (rc = rl_cd.cd_devs[unit]) == NULL) {
351                 bp->b_error = ENXIO;
352                 bp->b_flags |= B_ERROR;
353                 goto done;
354         }
355 	if (rc->rc_state != DK_OPEN) /* How did we end up here at all? */
356 		panic("rlstrategy: state impossible");
357 
358 	lp = rc->rc_disk.dk_label;
359 	if ((err = bounds_check_with_label(bp, lp, 1)) <= 0)
360 		goto done;
361 
362 	if (bp->b_bcount == 0)
363 		goto done;
364 
365 	bp->b_rawblkno =
366 	    bp->b_blkno + lp->d_partitions[DISKPART(bp->b_dev)].p_offset;
367 	bp->b_cylinder = bp->b_rawblkno / lp->d_secpercyl;
368 	sc = (struct rlc_softc *)rc->rc_dev.dv_parent;
369 
370 	s = splbio();
371 	disksort_cylinder(&sc->sc_q, bp);
372 	rlcstart(sc, 0);
373 	splx(s);
374 	return;
375 
376 done:	biodone(bp);
377 }
378 
379 int
380 rlioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
381 {
382 	struct rl_softc *rc = rl_cd.cd_devs[DISKUNIT(dev)];
383 	struct disklabel *lp = rc->rc_disk.dk_label;
384 	int err = 0;
385 #ifdef __HAVE_OLD_DISKLABEL
386 	struct disklabel newlabel;
387 #endif
388 
389 	switch (cmd) {
390 	case DIOCGDINFO:
391 		bcopy(lp, addr, sizeof (struct disklabel));
392 		break;
393 
394 #ifdef __HAVE_OLD_DISKLABEL
395 	case ODIOCGDINFO:
396 		newlabel = *lp;
397 		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
398 			return ENOTTY;
399 		bcopy(&newlabel, addr, sizeof (struct olddisklabel));
400 		break;
401 #endif
402 
403 	case DIOCGPART:
404 		((struct partinfo *)addr)->disklab = lp;
405 		((struct partinfo *)addr)->part =
406 		    &lp->d_partitions[DISKPART(dev)];
407 		break;
408 
409 	case DIOCSDINFO:
410 	case DIOCWDINFO:
411 #ifdef __HAVE_OLD_DISKLABEL
412 	case ODIOCWDINFO:
413 	case ODIOCSDINFO:
414 #endif
415 	{
416 		struct disklabel *tp;
417 
418 #ifdef __HAVE_OLD_DISKLABEL
419 		if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
420 			memset(&newlabel, 0, sizeof newlabel);
421 			memcpy(&newlabel, addr, sizeof (struct olddisklabel));
422 			tp = &newlabel;
423 		} else
424 #endif
425 		tp = (struct disklabel *)addr;
426 
427 		if ((flag & FWRITE) == 0)
428 			err = EBADF;
429 		else
430 			err = ((
431 #ifdef __HAVE_OLD_DISKLABEL
432 			       cmd == ODIOCSDINFO ||
433 #endif
434 			       cmd == DIOCSDINFO) ?
435 			    setdisklabel(lp, tp, 0, 0) :
436 			    writedisklabel(dev, rlstrategy, lp, 0));
437 		break;
438 	}
439 
440 	case DIOCWLABEL:
441 		if ((flag & FWRITE) == 0)
442 			err = EBADF;
443 		break;
444 
445 	default:
446 		err = ENOTTY;
447 	}
448 	return err;
449 }
450 
451 int
452 rlsize(dev_t dev)
453 {
454 	struct disklabel *dl;
455 	struct rl_softc *rc;
456 	int size, unit = DISKUNIT(dev);
457 
458 	if ((unit >= rl_cd.cd_ndevs) || ((rc = rl_cd.cd_devs[unit]) == 0))
459 		return -1;
460 	dl = rc->rc_disk.dk_label;
461 	size = dl->d_partitions[DISKPART(dev)].p_size *
462 	    (dl->d_secsize / DEV_BSIZE);
463 	return size;
464 }
465 
466 int
467 rldump(dev_t dev, daddr_t blkno, caddr_t va, size_t size)
468 {
469 	/* Not likely... */
470 	return 0;
471 }
472 
473 int
474 rlread(dev_t dev, struct uio *uio, int ioflag)
475 {
476 	return (physio(rlstrategy, NULL, dev, B_READ, minphys, uio));
477 }
478 
479 int
480 rlwrite(dev_t dev, struct uio *uio, int ioflag)
481 {
482 	return (physio(rlstrategy, NULL, dev, B_WRITE, minphys, uio));
483 }
484 
485 static char *rlerr[] = {
486 	"no",
487 	"operation incomplete",
488 	"read data CRC",
489 	"header CRC",
490 	"data late",
491 	"header not found",
492 	"",
493 	"",
494 	"non-existent memory",
495 	"memory parity error",
496 	"",
497 	"",
498 	"",
499 	"",
500 	"",
501 	"",
502 };
503 
504 void
505 rlcintr(void *arg)
506 {
507 	struct rlc_softc *sc = arg;
508 	struct buf *bp;
509 	u_int16_t cs;
510 
511 	bp = sc->sc_active;
512 	if (bp == 0) {
513 		printf("%s: strange interrupt\n", sc->sc_dev.dv_xname);
514 		return;
515 	}
516 	bus_dmamap_unload(sc->sc_dmat, sc->sc_dmam);
517 	sc->sc_active = 0;
518 	cs = RL_RREG(RL_CS);
519 	if (cs & RLCS_ERR) {
520 		int error = (cs & RLCS_ERRMSK) >> 10;
521 
522 		printf("%s: %s\n", sc->sc_dev.dv_xname, rlerr[error]);
523 		bp->b_flags |= B_ERROR;
524 		bp->b_error = EIO;
525 		bp->b_resid = bp->b_bcount;
526 		sc->sc_bytecnt = 0;
527 	}
528 	if (sc->sc_bytecnt == 0) /* Finished transfer */
529 		biodone(bp);
530 	rlcstart(sc, sc->sc_bytecnt ? bp : 0);
531 }
532 
533 /*
534  * Start routine. First position the disk to the given position,
535  * then start reading/writing. An optimization would be to be able
536  * to handle overlapping seeks between disks.
537  */
538 void
539 rlcstart(struct rlc_softc *sc, struct buf *ob)
540 {
541 	struct disklabel *lp;
542 	struct rl_softc *rc;
543 	struct buf *bp;
544 	int bn, cn, sn, tn, blks, err;
545 
546 	if (sc->sc_active)
547 		return;	/* Already doing something */
548 
549 	if (ob == 0) {
550 		bp = BUFQ_FIRST(&sc->sc_q);
551 		if (bp == NULL)
552 			return;	/* Nothing to do */
553 		BUFQ_REMOVE(&sc->sc_q, bp);
554 		sc->sc_bufaddr = bp->b_data;
555 		sc->sc_diskblk = bp->b_rawblkno;
556 		sc->sc_bytecnt = bp->b_bcount;
557 		bp->b_resid = 0;
558 	} else
559 		bp = ob;
560 	sc->sc_active = bp;
561 
562 	rc = rl_cd.cd_devs[DISKUNIT(bp->b_dev)];
563 	bn = sc->sc_diskblk;
564 	lp = rc->rc_disk.dk_label;
565 	if (bn) {
566 		cn = bn / lp->d_secpercyl;
567 		sn = bn % lp->d_secpercyl;
568 		tn = sn / lp->d_nsectors;
569 		sn = sn % lp->d_nsectors;
570 	} else
571 		cn = sn = tn = 0;
572 
573 	/*
574 	 * Check if we have to position disk first.
575 	 */
576 	if (rc->rc_cyl != cn || rc->rc_head != tn) {
577 		u_int16_t da = RLDA_SEEK;
578 		if (cn > rc->rc_cyl)
579 			da |= ((cn - rc->rc_cyl) << RLDA_CYLSHFT) | RLDA_DIR;
580 		else
581 			da |= ((rc->rc_cyl - cn) << RLDA_CYLSHFT);
582 		if (tn)
583 			da |= RLDA_HSSEEK;
584 		waitcrdy(sc);
585 		RL_WREG(RL_DA, da);
586 		RL_WREG(RL_CS, RLCS_SEEK | (rc->rc_hwid << RLCS_USHFT));
587 		waitcrdy(sc);
588 		rc->rc_cyl = cn;
589 		rc->rc_head = tn;
590 	}
591 	RL_WREG(RL_DA, (cn << RLDA_CYLSHFT) | (tn ? RLDA_HSRW : 0) | (sn << 1));
592 	blks = sc->sc_bytecnt/DEV_BSIZE;
593 
594 	if (sn + blks > RL_SPT/2)
595 		blks = RL_SPT/2 - sn;
596 	RL_WREG(RL_MP, -(blks*DEV_BSIZE)/2);
597 	err = bus_dmamap_load(sc->sc_dmat, sc->sc_dmam, sc->sc_bufaddr,
598 	    (blks*DEV_BSIZE), bp->b_proc, BUS_DMA_NOWAIT);
599 	if (err)
600 		panic("%s: bus_dmamap_load failed: %d",
601 		    sc->sc_dev.dv_xname, err);
602 	RL_WREG(RL_BA, (sc->sc_dmam->dm_segs[0].ds_addr & 0xffff));
603 
604 	/* Count up vars */
605 	sc->sc_bufaddr += (blks*DEV_BSIZE);
606 	sc->sc_diskblk += blks;
607 	sc->sc_bytecnt -= (blks*DEV_BSIZE);
608 
609 	if (bp->b_flags & B_READ)
610 		RL_WREG(RL_CS, RLCS_IE|RLCS_RD|(rc->rc_hwid << RLCS_USHFT));
611 	else
612 		RL_WREG(RL_CS, RLCS_IE|RLCS_WD|(rc->rc_hwid << RLCS_USHFT));
613 }
614 
615 void
616 rlreset(struct device *dev)
617 {
618 	struct rl_softc *rc = (struct rl_softc *)dev;
619 	struct rlc_softc *sc = (struct rlc_softc *)rc->rc_dev.dv_parent;
620 	u_int16_t mp;
621 
622 	if (rc->rc_state != DK_OPEN)
623 		return;
624 	RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
625 	waitcrdy(sc);
626 	mp = RL_RREG(RL_MP);
627 	rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
628 	rc->rc_cyl = (mp >> 7) & 0777;
629 	if (sc->sc_active == 0)
630 		return;
631 
632 	BUFQ_INSERT_HEAD(&sc->sc_q, sc->sc_active);
633 	sc->sc_active = 0;
634 	rlcstart(sc, 0);
635 }
636