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