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