Ejemplo n.º 1
0
Archivo: mcd.c Proyecto: MarginC/kame
static int
mcdopen(dev_t dev, int flags, int fmt, struct thread *td)
{
	struct mcd_softc *sc;
	int r,retry;

	sc = (struct mcd_softc *)dev->si_drv1;

	/* not initialized*/
	if (!(sc->data.flags & MCDINIT))
		return (ENXIO);

	/* invalidated in the meantime? mark all open part's invalid */
	if (!(sc->data.flags & MCDVALID) && sc->data.openflags)
		return (ENXIO);

	if (mcd_getstat(sc, 1) == -1)
		return (EIO);

	if (    (sc->data.status & (MCDDSKCHNG|MCDDOOROPEN))
	    || !(sc->data.status & MCDDSKIN))
		for (retry = 0; retry < DISK_SENSE_SECS * WAIT_FRAC; retry++) {
			(void) tsleep((caddr_t)sc, PSOCK | PCATCH, "mcdsn1", hz/WAIT_FRAC);
			if ((r = mcd_getstat(sc, 1)) == -1)
				return (EIO);
			if (r != -2)
				break;
		}

	if (sc->data.status & MCDDOOROPEN) {
		device_printf(sc->dev, "door is open\n");
		return (ENXIO);
	}
	if (!(sc->data.status & MCDDSKIN)) {
		device_printf(sc->dev, "no CD inside\n");
		return (ENXIO);
	}
	if (sc->data.status & MCDDSKCHNG) {
		device_printf(sc->dev, "CD not sensed\n");
		return (ENXIO);
	}

	if (mcdsize(dev) < 0) {
		device_printf(sc->dev, "failed to get disk size\n");
		return (ENXIO);
	}

	dev->si_bsize_phys = sc->data.blksize;

	sc->data.openflags = 1;
	sc->data.partflags |= MCDREADRAW;
	sc->data.flags |= MCDVALID;

	(void) mcd_lock_door(sc, MCD_LK_LOCK);
	if (!(sc->data.flags & MCDVALID))
		return (ENXIO);

	return mcd_read_toc(sc);
}
Ejemplo n.º 2
0
Archivo: mcd.c Proyecto: MarginC/kame
static int
mcd_setmode(struct mcd_softc *sc, int mode)
{
	int retry, st;

	if (sc->data.curr_mode == mode)
		return (0);
	if (sc->data.debug)
		device_printf(sc->dev, "setting mode to %d\n", mode);
	for(retry=0; retry<MCD_RETRYS; retry++)
	{
		sc->data.curr_mode = MCD_MD_UNKNOWN;
		MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDSETMODE);
		MCD_WRITE(sc, MCD_REG_COMMAND, mode);
		if ((st = mcd_getstat(sc, 0)) >= 0) {
			sc->data.curr_mode = mode;
			return (0);
		}
		if (st == -2) {
			device_printf(sc->dev, "media changed\n");
			break;
		}
	}

	return (-1);
}
Ejemplo n.º 3
0
Archivo: mcd.c Proyecto: MarginC/kame
static int
mcd_eject(struct mcd_softc *sc)
{
	int r;

	if (mcd_getstat(sc, 1) == -1)    /* detect disk change too */
		return (EIO);
	if (sc->data.status & MCDDOOROPEN)
		return (0);
	if ((r = mcd_stop(sc)) == EIO)
		return (r);
	MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDEJECTDISK);
	if (mcd_getstat(sc, 0) == -1)
		return (EIO);
	return (0);
}
Ejemplo n.º 4
0
Archivo: mcd.c Proyecto: MarginC/kame
static int
mcd_inject(struct mcd_softc *sc)
{

	if (mcd_getstat(sc, 1) == -1)    /* detect disk change too */
		return (EIO);
	if (sc->data.status & MCDDOOROPEN)
		return mcd_close_tray(sc);
	return (0);
}
Ejemplo n.º 5
0
Archivo: mcd.c Proyecto: MarginC/kame
static int
mcd_lock_door(struct mcd_softc *sc, int lock)
{

	MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDLOCKDRV);
	MCD_WRITE(sc, MCD_REG_COMMAND, lock);
	if (mcd_getstat(sc, 0) == -1)
		return (EIO);
	return (0);
}
Ejemplo n.º 6
0
Archivo: mcd.c Proyecto: MarginC/kame
static int
mcd_close_tray(struct mcd_softc *sc)
{
	int retry, r;

	if (mcd_getstat(sc, 1) == -1)
		return (EIO);
	if (sc->data.status & MCDDOOROPEN) {
		MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDCLOSETRAY);
		for (retry = 0; retry < CLOSE_TRAY_SECS * WAIT_FRAC; retry++) {
			if (MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL)
				(void) tsleep((caddr_t)sc, PSOCK | PCATCH, "mcdcls", hz/WAIT_FRAC);
			else {
				if ((r = mcd_getstat(sc, 0)) == -1)
					return (EIO);
				return (0);
			}
		}
		return (ENXIO);
	}
	return (0);
}
Ejemplo n.º 7
0
Archivo: mcd.c Proyecto: MarginC/kame
static int
mcd_send(struct mcd_softc *sc, int cmd,int nretrys)
{
	int i,k=0;

/*MCD_TRACE("mcd_send: command = 0x%02x\n",cmd,0,0,0);*/
	for (i=0; i<nretrys; i++) {
		MCD_WRITE(sc, MCD_REG_COMMAND, cmd);
		if ((k=mcd_getstat(sc, 0)) != -1)
			break;
	}
	if (k == -2) {
		device_printf(sc->dev, "media changed\n");
		return (-1);
	}
	if (i == nretrys) {
		device_printf(sc->dev, "mcd_send retry cnt exceeded\n");
		return (-1);
	}
/*MCD_TRACE("mcd_send: done\n",0,0,0,0);*/
	return (0);
}
Ejemplo n.º 8
0
Archivo: mcd.c Proyecto: MarginC/kame
static int
mcd_play(struct mcd_softc *sc, struct mcd_read2 *pb)
{
	int retry, st = -1, status;

	sc->data.lastpb = *pb;
	for(retry=0; retry<MCD_RETRYS; retry++) {

		critical_enter();
		MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDSINGLESPEEDREAD);
		MCD_WRITE(sc, MCD_REG_COMMAND, pb->start_msf[0]);
		MCD_WRITE(sc, MCD_REG_COMMAND, pb->start_msf[1]);
		MCD_WRITE(sc, MCD_REG_COMMAND, pb->start_msf[2]);
		MCD_WRITE(sc, MCD_REG_COMMAND, pb->end_msf[0]);
		MCD_WRITE(sc, MCD_REG_COMMAND, pb->end_msf[1]);
		MCD_WRITE(sc, MCD_REG_COMMAND, pb->end_msf[2]);
		critical_exit();

		status=mcd_getstat(sc, 0);
		if (status == -1)
			continue;
		else if (status != -2)
			st = 0;
		break;
	}

	if (status == -2) {
		device_printf(sc->dev, "media changed\n");
		return (ENXIO);
	}
	if (sc->data.debug)
		device_printf(sc->dev,
			"mcd_play retry=%d, status=0x%02x\n", retry, status);
	if (st < 0)
		return (ENXIO);
	sc->data.audio_status = CD_AS_PLAY_IN_PROGRESS;
	return (0);
}
Ejemplo n.º 9
0
Archivo: mcd.c Proyecto: MarginC/kame
static void
mcd_doread(struct mcd_softc *sc, int state, struct mcd_mbx *mbxin)
{
	struct mcd_mbx *mbx;
	struct bio *bp;
	int rm, i, k;
	struct mcd_read2 rbuf;
	int blknum;
	caddr_t	addr;

	mbx = (state!=MCD_S_BEGIN) ? sc->ch_mbxsave : mbxin;
	bp = mbx->bp;

loop:
	switch (state) {
	case MCD_S_BEGIN:
		mbx = sc->ch_mbxsave = mbxin;

	case MCD_S_BEGIN1:
retry_status:
		/* get status */
		MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDGETSTAT);
		mbx->count = RDELAY_WAITSTAT;
		sc->ch_state = MCD_S_WAITSTAT;
		sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */
		return;
	case MCD_S_WAITSTAT:
		sc->ch_state = MCD_S_WAITSTAT;
		untimeout(mcd_timeout,(caddr_t)sc, sc->ch);
		if (mbx->count-- >= 0) {
			if (MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL) {
				sc->ch_state = MCD_S_WAITSTAT;
				timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */
				return;
			}
			sc->data.status = MCD_READ(sc, MCD_REG_STATUS) & 0xFF;
			if (sc->data.status & MCD_ST_CMDCHECK)
				goto retry_status;
			if (mcd_setflags(sc) < 0)
				goto changed;
			MCD_TRACE("got WAITSTAT delay=%d\n",
				RDELAY_WAITSTAT-mbx->count);
			/* reject, if audio active */
			if (sc->data.status & MCDAUDIOBSY) {
				device_printf(sc->dev, "audio is active\n");
				goto readerr;
			}

retry_mode:
			/* to check for raw/cooked mode */
			if (sc->data.flags & MCDREADRAW) {
				rm = MCD_MD_RAW;
				mbx->sz = MCDRBLK;
			} else {
				rm = MCD_MD_COOKED;
				mbx->sz = sc->data.blksize;
			}

			if (rm == sc->data.curr_mode)
				goto modedone;

			mbx->count = RDELAY_WAITMODE;

			sc->data.curr_mode = MCD_MD_UNKNOWN;
			mbx->mode = rm;
			MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDSETMODE);
			MCD_WRITE(sc, MCD_REG_COMMAND, rm);

			sc->ch_state = MCD_S_WAITMODE;
			sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */
			return;
		} else {
			device_printf(sc->dev, "timeout getstatus\n");
			goto readerr;
		}

	case MCD_S_WAITMODE:
		sc->ch_state = MCD_S_WAITMODE;
		untimeout(mcd_timeout, (caddr_t)sc, sc->ch);
		if (mbx->count-- < 0) {
			device_printf(sc->dev, "timeout set mode\n");
			goto readerr;
		}
		if (MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL) {
			sc->ch_state = MCD_S_WAITMODE;
			sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100);
			return;
		}
		sc->data.status = MCD_READ(sc, MCD_REG_STATUS) & 0xFF;
		if (sc->data.status & MCD_ST_CMDCHECK) {
			sc->data.curr_mode = MCD_MD_UNKNOWN;
			goto retry_mode;
		}
		if (mcd_setflags(sc) < 0)
			goto changed;
		sc->data.curr_mode = mbx->mode;
		MCD_TRACE("got WAITMODE delay=%d\n",
			RDELAY_WAITMODE-mbx->count);
modedone:
		/* for first block */
		mbx->nblk = (bp->bio_bcount + (mbx->sz-1)) / mbx->sz;
		mbx->skip = 0;

nextblock:
		blknum 	= (bp->bio_blkno / (mbx->sz/DEV_BSIZE))
			+ mbx->skip/mbx->sz;

		MCD_TRACE("mcd_doread: read blknum=%d for bp=%p\n",
			blknum, bp);

		/* build parameter block */
		hsg2msf(blknum,rbuf.start_msf);
retry_read:
		/* send the read command */
		critical_enter();
		MCD_WRITE(sc, MCD_REG_COMMAND, sc->data.read_command);
		MCD_WRITE(sc, MCD_REG_COMMAND, rbuf.start_msf[0]);
		MCD_WRITE(sc, MCD_REG_COMMAND, rbuf.start_msf[1]);
		MCD_WRITE(sc, MCD_REG_COMMAND, rbuf.start_msf[2]);
		MCD_WRITE(sc, MCD_REG_COMMAND, 0);
		MCD_WRITE(sc, MCD_REG_COMMAND, 0);
		MCD_WRITE(sc, MCD_REG_COMMAND, 1);
		critical_exit();

		/* Spin briefly (<= 2ms) to avoid missing next block */
		for (i = 0; i < 20; i++) {
			k = MCD_READ(sc, MCD_FLAGS);
			if (!(k & MFL_DATA_NOT_AVAIL))
				goto got_it;
			DELAY(100);
		}

		mbx->count = RDELAY_WAITREAD;
		sc->ch_state = MCD_S_WAITREAD;
		sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */
		return;
	case MCD_S_WAITREAD:
		sc->ch_state = MCD_S_WAITREAD;
		untimeout(mcd_timeout, (caddr_t)sc, sc->ch);
		if (mbx->count-- > 0) {
			k = MCD_READ(sc, MCD_FLAGS);
			if (!(k & MFL_DATA_NOT_AVAIL)) { /* XXX */
				MCD_TRACE("got data delay=%d\n",
					RDELAY_WAITREAD-mbx->count);
			got_it:
				/* data is ready */
				addr	= bp->bio_data + mbx->skip;

				MCD_WRITE(sc, MCD_REG_CTL2,0x04);	/* XXX */
				for (i=0; i<mbx->sz; i++)
					*addr++ = MCD_READ(sc, MCD_REG_RDATA);
				MCD_WRITE(sc, MCD_REG_CTL2,0x0c);	/* XXX */

				k = MCD_READ(sc, MCD_FLAGS);
				/* If we still have some junk, read it too */
				if (!(k & MFL_DATA_NOT_AVAIL)) {
					MCD_WRITE(sc, MCD_REG_CTL2, 0x04);       /* XXX */
					(void)MCD_READ(sc, MCD_REG_RDATA);
					(void)MCD_READ(sc, MCD_REG_RDATA);
					MCD_WRITE(sc, MCD_REG_CTL2, 0x0c);       /* XXX */
				}

				if (--mbx->nblk > 0) {
					mbx->skip += mbx->sz;
					goto nextblock;
				}

				/* return buffer */
				bp->bio_resid = 0;
				biodone(bp);

				sc->data.flags &= ~(MCDMBXBSY|MCDREADRAW);
				mcd_start(sc);
				return;
			}
			if (!(k & MFL_STATUS_NOT_AVAIL)) {
				sc->data.status = MCD_READ(sc, MCD_REG_STATUS) & 0xFF;
				if (sc->data.status & MCD_ST_CMDCHECK)
					goto retry_read;
				if (mcd_setflags(sc) < 0)
					goto changed;
			}
			sc->ch_state = MCD_S_WAITREAD;
			sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */
			return;
		} else {
			device_printf(sc->dev, "timeout read data\n");
			goto readerr;
		}
	}

readerr:
	if (mbx->retry-- > 0) {
		device_printf(sc->dev, "retrying\n");
		state = MCD_S_BEGIN1;
		goto loop;
	}
harderr:
	/* invalidate the buffer */
	bp->bio_flags |= BIO_ERROR;
	bp->bio_resid = bp->bio_bcount;
	biodone(bp);

	sc->data.flags &= ~(MCDMBXBSY|MCDREADRAW);
	mcd_start(sc);
	return;

changed:
	device_printf(sc->dev, "media changed\n");
	goto harderr;

#ifdef NOTDEF
	device_printf(sc->dev, "unit timeout, resetting\n");
	MCD_WRITE(sc, MCD_REG_RESET, MCD_CMDRESET);
	DELAY(300000);
	(void)mcd_getstat(sc, 1);
	(void)mcd_getstat(sc, 1);
	/*sc->data.status &= ~MCDDSKCHNG; */
	sc->data.debug = 1; /* preventive set debug mode */

#endif

}
Ejemplo n.º 10
0
Archivo: mcd.c Proyecto: MarginC/kame
static int
mcdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
{
	struct mcd_softc *sc;
	int retry,r;

	sc = (struct mcd_softc *)dev->si_drv1;

	if (mcd_getstat(sc, 1) == -1) /* detect disk change too */
		return (EIO);
MCD_TRACE("ioctl called 0x%lx\n", cmd);

	switch (cmd) {
	case CDIOCSETPATCH:
	case CDIOCGETVOL:
	case CDIOCSETVOL:
	case CDIOCSETMONO:
	case CDIOCSETSTERIO:
	case CDIOCSETMUTE:
	case CDIOCSETLEFT:
	case CDIOCSETRIGHT:
		return (EINVAL);
	case CDIOCEJECT:
		return mcd_eject(sc);
	case CDIOCSETDEBUG:
		sc->data.debug = 1;
		return (0);
	case CDIOCCLRDEBUG:
		sc->data.debug = 0;
		return (0);
	case CDIOCRESET:
		return mcd_hard_reset(sc);
	case CDIOCALLOW:
		return mcd_lock_door(sc, MCD_LK_UNLOCK);
	case CDIOCPREVENT:
		return mcd_lock_door(sc, MCD_LK_LOCK);
	case CDIOCCLOSE:
		return mcd_inject(sc);
	}

	if (!(sc->data.flags & MCDVALID)) {
		if (    (sc->data.status & (MCDDSKCHNG|MCDDOOROPEN))
		    || !(sc->data.status & MCDDSKIN))
			for (retry = 0; retry < DISK_SENSE_SECS * WAIT_FRAC; retry++) {
				(void) tsleep((caddr_t)sc, PSOCK | PCATCH, "mcdsn2", hz/WAIT_FRAC);
				if ((r = mcd_getstat(sc, 1)) == -1)
					return (EIO);
				if (r != -2)
					break;
			}
		if (   (sc->data.status & (MCDDOOROPEN|MCDDSKCHNG))
		    || !(sc->data.status & MCDDSKIN)
		    || mcdsize(dev) < 0
		   )
			return (ENXIO);
		sc->data.flags |= MCDVALID;
		sc->data.partflags |= MCDREADRAW;
		(void) mcd_lock_door(sc, MCD_LK_LOCK);
		if (!(sc->data.flags & MCDVALID))
			return (ENXIO);
	}

	switch (cmd) {
	case DIOCGMEDIASIZE:
		*(off_t *)addr = (off_t)sc->data.disksize * sc->data.blksize;
		return (0);
		break;
	case DIOCGSECTORSIZE:
		*(u_int *)addr = sc->data.blksize;
		return (0);
		break;

	case CDIOCPLAYTRACKS:
		return mcd_playtracks(sc, (struct ioc_play_track *) addr);
	case CDIOCPLAYBLOCKS:
		return mcd_playblocks(sc, (struct ioc_play_blocks *) addr);
	case CDIOCPLAYMSF:
		return mcd_playmsf(sc, (struct ioc_play_msf *) addr);
	case CDIOCREADSUBCHANNEL:
		return mcd_subchan(sc, (struct ioc_read_subchannel *) addr);
	case CDIOREADTOCHEADER:
		return mcd_toc_header(sc, (struct ioc_toc_header *) addr);
	case CDIOREADTOCENTRYS:
		return mcd_toc_entrys(sc, (struct ioc_read_toc_entry *) addr);
	case CDIOCRESUME:
		return mcd_resume(sc);
	case CDIOCPAUSE:
		return mcd_pause(sc);
	case CDIOCSTART:
		if (mcd_setmode(sc, MCD_MD_COOKED) != 0)
			return (EIO);
		return (0);
	case CDIOCSTOP:
		return mcd_stop(sc);
	default:
		return (ENOTTY);
	}
	/*NOTREACHED*/
}
Ejemplo n.º 11
0
/*
 * State machine to process read requests.
 * Initialize with MCD_S_BEGIN: calculate sizes, and set mode
 * MCD_S_WAITMODE: waits for status reply from set mode, set read command
 * MCD_S_WAITREAD: wait for read ready, read data.
 */
int
mcdintr(void *arg)
{
	struct mcd_softc *sc = arg;
	struct mcd_mbx *mbx = &sc->mbx;
	struct buf *bp = mbx->bp;
	bus_space_tag_t iot = sc->sc_iot;
	bus_space_handle_t ioh = sc->sc_ioh;

	int i;
	u_char x;
	bcd_t msf[3];

	switch (mbx->state) {
	case MCD_S_IDLE:
		return 0;

	case MCD_S_BEGIN:
	tryagain:
		if (mbx->mode == sc->lastmode)
			goto firstblock;

		sc->lastmode = MCD_MD_UNKNOWN;
		bus_space_write_1(iot, ioh, MCD_COMMAND, MCD_CMDSETMODE);
		bus_space_write_1(iot, ioh, MCD_COMMAND, mbx->mode);

		mbx->count = RDELAY_WAITMODE;
		mbx->state = MCD_S_WAITMODE;

	case MCD_S_WAITMODE:
		callout_stop(&sc->sc_pintr_ch);
		for (i = 20; i; i--) {
			x = bus_space_read_1(iot, ioh, MCD_XFER);
			if ((x & MCD_XF_STATUSUNAVAIL) == 0)
				break;
			delay(50);
		}
		if (i == 0)
			goto hold;
		sc->status = bus_space_read_1(iot, ioh, MCD_STATUS);
		mcd_setflags(sc);
		if ((sc->flags & MCDF_LOADED) == 0)
			goto changed;
		MCD_TRACE("doread: got WAITMODE delay=%d\n",
		    RDELAY_WAITMODE - mbx->count);

		sc->lastmode = mbx->mode;

	firstblock:
		MCD_TRACE("doread: read blkno=%d for bp=0x%p\n", 
		    (int) mbx->blkno, bp);

		/* Build parameter block. */
		hsg2msf(mbx->blkno, msf);

		/* Send the read command. */
		bus_space_write_1(iot, ioh, MCD_COMMAND, sc->readcmd);
		bus_space_write_1(iot, ioh, MCD_COMMAND, msf[0]);
		bus_space_write_1(iot, ioh, MCD_COMMAND, msf[1]);
		bus_space_write_1(iot, ioh, MCD_COMMAND, msf[2]);
		bus_space_write_1(iot, ioh, MCD_COMMAND, 0);
		bus_space_write_1(iot, ioh, MCD_COMMAND, 0);
		bus_space_write_1(iot, ioh, MCD_COMMAND, mbx->nblk);

		mbx->count = RDELAY_WAITREAD;
		mbx->state = MCD_S_WAITREAD;

	case MCD_S_WAITREAD:
		callout_stop(&sc->sc_pintr_ch);
	nextblock:
	loop:
		for (i = 20; i; i--) {
			x = bus_space_read_1(iot, ioh, MCD_XFER);
			if ((x & MCD_XF_DATAUNAVAIL) == 0)
				goto gotblock;
			if ((x & MCD_XF_STATUSUNAVAIL) == 0)
				break;
			delay(50);
		}
		if (i == 0)
			goto hold;
		sc->status = bus_space_read_1(iot, ioh, MCD_STATUS);
		mcd_setflags(sc);
		if ((sc->flags & MCDF_LOADED) == 0)
			goto changed;
#if 0
		printf("%s: got status byte %02x during read\n",
		    device_xname(sc->sc_dev), (u_int)sc->status);
#endif
		goto loop;

	gotblock:
		MCD_TRACE("doread: got data delay=%d\n",
		    RDELAY_WAITREAD - mbx->count);

		/* Data is ready. */
		bus_space_write_1(iot, ioh, MCD_CTL2, 0x04);	/* XXX */
		bus_space_read_multi_1(iot, ioh, MCD_RDATA,
		    (char *)bp->b_data + mbx->skip, mbx->sz);
		bus_space_write_1(iot, ioh, MCD_CTL2, 0x0c);	/* XXX */
		mbx->blkno += 1;
		mbx->skip += mbx->sz;
		if (--mbx->nblk > 0)
			goto nextblock;

		mbx->state = MCD_S_IDLE;

		/* Return buffer. */
		bp->b_resid = 0;
		disk_unbusy(&sc->sc_dk, bp->b_bcount, (bp->b_flags & B_READ));
		biodone(bp);

		mcdstart(sc);
		return 1;

	hold:
		if (mbx->count-- < 0) {
			printf("%s: timeout in state %d",
			    device_xname(sc->sc_dev), mbx->state);
			goto readerr;
		}

#if 0
		printf("%s: sleep in state %d\n", device_xname(sc->sc_dev),
		    mbx->state);
#endif
		callout_reset(&sc->sc_pintr_ch, hz / 100,
		    mcd_pseudointr, sc);
		return -1;
	}

readerr:
	if (mbx->retry-- > 0) {
		printf("; retrying\n");
		goto tryagain;
	} else
		printf("; giving up\n");

changed:
	/* Invalidate the buffer. */
	bp->b_error = EIO;
	bp->b_resid = bp->b_bcount - mbx->skip;
	disk_unbusy(&sc->sc_dk, (bp->b_bcount - bp->b_resid),
	    (bp->b_flags & B_READ));
	biodone(bp);

	mcdstart(sc);
	return -1;

#ifdef notyet
	printf("%s: unit timeout; resetting\n", device_xname(sc->sc_dev));
	bus_space_write_1(iot, ioh, MCD_RESET, MCD_CMDRESET);
	delay(300000);
	(void) mcd_getstat(sc, 1);
	(void) mcd_getstat(sc, 1);
	/*sc->status &= ~MCD_ST_DSKCHNG; */
	sc->debug = 1; /* preventive set debug mode */
#endif
}