svn commit: r274676 - head/sys/dev/mcd

John Baldwin jhb at FreeBSD.org
Tue Nov 18 21:51:02 UTC 2014


Author: jhb
Date: Tue Nov 18 21:51:01 2014
New Revision: 274676
URL: https://svnweb.freebsd.org/changeset/base/274676

Log:
  Add locking to mcd(4) and mark MPSAFE.
  - Actually use existing per-softc mutex.
  - Use mutex in cdev routines and remove D_NEEDGIANT.
  - Use callout(9) instead of timeout(9).
  - Don't check for impossible conditions (e.g. MCDINIT being clear).
  - Remove critical_enter/exit when sending a PIO command.
  - Use bus_*() instead of bus_space_*().
  
  Tested by:	no one

Modified:
  head/sys/dev/mcd/mcd.c
  head/sys/dev/mcd/mcd_isa.c
  head/sys/dev/mcd/mcdvar.h

Modified: head/sys/dev/mcd/mcd.c
==============================================================================
--- head/sys/dev/mcd/mcd.c	Tue Nov 18 21:03:46 2014	(r274675)
+++ head/sys/dev/mcd/mcd.c	Tue Nov 18 21:51:01 2014	(r274676)
@@ -128,7 +128,7 @@ static void	hsg2msf(int hsg, bcd_t *msf)
 static int	msf2hsg(bcd_t *msf, int relative);
 static int	mcd_volinfo(struct mcd_softc *);
 static int	mcd_waitrdy(struct mcd_softc *,int dly);
-static timeout_t mcd_timeout;
+static void	mcd_timeout(void *arg);
 static void	mcd_doread(struct mcd_softc *, int state, struct mcd_mbx *mbxin);
 static void	mcd_soft_reset(struct mcd_softc *);
 static int	mcd_hard_reset(struct mcd_softc *);
@@ -168,7 +168,7 @@ static struct cdevsw mcd_cdevsw = {
 	.d_ioctl =	mcdioctl,
 	.d_strategy =	mcdstrategy,
 	.d_name =	"mcd",
-	.d_flags =	D_DISK | D_NEEDGIANT,
+	.d_flags =	D_DISK,
 };
 
 #define MCD_RETRYS	5
@@ -193,6 +193,7 @@ mcd_attach(struct mcd_softc *sc)
 
 	unit = device_get_unit(sc->dev);
 
+	MCD_LOCK(sc);
 	sc->data.flags |= MCDINIT;
 	mcd_soft_reset(sc);
 	bioq_init(&sc->data.head);
@@ -201,11 +202,13 @@ mcd_attach(struct mcd_softc *sc)
 	/* wire controller for interrupts and dma */
 	mcd_configure(sc);
 #endif
+	MCD_UNLOCK(sc);
 	/* name filled in probe */
 	sc->mcd_dev_t = make_dev(&mcd_cdevsw, 8 * unit,
 				 UID_ROOT, GID_OPERATOR, 0640, "mcd%d", unit);
 
 	sc->mcd_dev_t->si_drv1 = (void *)sc;
+	callout_init_mtx(&sc->timer, &sc->mtx, 0);
 
 	return (0);
 }
@@ -218,41 +221,49 @@ mcdopen(struct cdev *dev, int flags, int
 
 	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)
+	MCD_LOCK(sc);
+	if (!(sc->data.flags & MCDVALID) && sc->data.openflags) {
+		MCD_UNLOCK(sc);
 		return (ENXIO);
+	}
 
-	if (mcd_getstat(sc, 1) == -1)
+	if (mcd_getstat(sc, 1) == -1) {
+		MCD_UNLOCK(sc);
 		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)
+			(void) mtx_sleep(sc, &sc->mtx, PSOCK | PCATCH,
+			    "mcdsn1", hz/WAIT_FRAC);
+			if ((r = mcd_getstat(sc, 1)) == -1) {
+				MCD_UNLOCK(sc);
 				return (EIO);
+			}
 			if (r != -2)
 				break;
 		}
 
 	if (sc->data.status & MCDDOOROPEN) {
+		MCD_UNLOCK(sc);
 		device_printf(sc->dev, "door is open\n");
 		return (ENXIO);
 	}
 	if (!(sc->data.status & MCDDSKIN)) {
+		MCD_UNLOCK(sc);
 		device_printf(sc->dev, "no CD inside\n");
 		return (ENXIO);
 	}
 	if (sc->data.status & MCDDSKCHNG) {
+		MCD_UNLOCK(sc);
 		device_printf(sc->dev, "CD not sensed\n");
 		return (ENXIO);
 	}
 
 	if (mcd_size(dev) < 0) {
+		MCD_UNLOCK(sc);
 		device_printf(sc->dev, "failed to get disk size\n");
 		return (ENXIO);
 	}
@@ -262,10 +273,14 @@ mcdopen(struct cdev *dev, int flags, int
 	sc->data.flags |= MCDVALID;
 
 	(void) mcd_lock_door(sc, MCD_LK_LOCK);
-	if (!(sc->data.flags & MCDVALID))
+	if (!(sc->data.flags & MCDVALID)) {
+		MCD_UNLOCK(sc);
 		return (ENXIO);
+	}
 
-	return mcd_read_toc(sc);
+	r = mcd_read_toc(sc);
+	MCD_UNLOCK(sc);
+	return (r);
 }
 
 static int
@@ -275,12 +290,13 @@ mcdclose(struct cdev *dev, int flags, in
 
 	sc = (struct mcd_softc *)dev->si_drv1;
 
-	if (!(sc->data.flags & MCDINIT) || !sc->data.openflags)
-		return (ENXIO);
+	MCD_LOCK(sc);
+	KASSERT(sc->data.openflags, ("device not open"));
 
 	(void) mcd_lock_door(sc, MCD_LK_UNLOCK);
 	sc->data.openflags = 0;
 	sc->data.partflags &= ~MCDREADRAW;
+	MCD_UNLOCK(sc);
 
 	return (0);
 }
@@ -293,6 +309,7 @@ mcdstrategy(struct bio *bp)
 	sc = (struct mcd_softc *)bp->bio_dev->si_drv1;
 
 	/* if device invalidated (e.g. media change, door open), error */
+	MCD_LOCK(sc);
 	if (!(sc->data.flags & MCDVALID)) {
 		device_printf(sc->dev, "media changed\n");
 		bp->bio_error = EIO;
@@ -321,11 +338,13 @@ mcdstrategy(struct bio *bp)
 
 	/* now check whether we can perform processing */
 	mcd_start(sc);
+	MCD_UNLOCK(sc);
 	return;
 
 bad:
 	bp->bio_flags |= BIO_ERROR;
 done:
+	MCD_UNLOCK(sc);
 	bp->bio_resid = bp->bio_bcount;
 	biodone(bp);
 	return;
@@ -336,6 +355,7 @@ mcd_start(struct mcd_softc *sc)
 {
 	struct bio *bp;
 
+	MCD_ASSERT_LOCKED(sc);
 	if (sc->data.flags & MCDMBXBSY) {
 		return;
 	}
@@ -365,8 +385,11 @@ mcdioctl(struct cdev *dev, u_long cmd, c
 
 	sc = (struct mcd_softc *)dev->si_drv1;
 
-	if (mcd_getstat(sc, 1) == -1) /* detect disk change too */
+	MCD_LOCK(sc);
+	if (mcd_getstat(sc, 1) == -1) { /* detect disk change too */
+		MCD_UNLOCK(sc);
 		return (EIO);
+	}
 MCD_TRACE("ioctl called 0x%lx\n", cmd);
 
 	switch (cmd) {
@@ -378,83 +401,114 @@ MCD_TRACE("ioctl called 0x%lx\n", cmd);
 	case CDIOCSETMUTE:
 	case CDIOCSETLEFT:
 	case CDIOCSETRIGHT:
+		MCD_UNLOCK(sc);
 		return (EINVAL);
 	case CDIOCEJECT:
-		return mcd_eject(sc);
+		r = mcd_eject(sc);
+		MCD_UNLOCK(sc);
+		return (r);
 	case CDIOCSETDEBUG:
 		sc->data.debug = 1;
+		MCD_UNLOCK(sc);
 		return (0);
 	case CDIOCCLRDEBUG:
 		sc->data.debug = 0;
+		MCD_UNLOCK(sc);
 		return (0);
 	case CDIOCRESET:
-		return mcd_hard_reset(sc);
+		r = mcd_hard_reset(sc);
+		MCD_UNLOCK(sc);
+		return (r);
 	case CDIOCALLOW:
-		return mcd_lock_door(sc, MCD_LK_UNLOCK);
+		r = mcd_lock_door(sc, MCD_LK_UNLOCK);
+		MCD_UNLOCK(sc);
+		return (r);
 	case CDIOCPREVENT:
-		return mcd_lock_door(sc, MCD_LK_LOCK);
+		r = mcd_lock_door(sc, MCD_LK_LOCK);
+		MCD_UNLOCK(sc);
+		return (r);
 	case CDIOCCLOSE:
-		return mcd_inject(sc);
+		r = mcd_inject(sc);
+		MCD_UNLOCK(sc);
+		return (r);
 	}
 
 	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)
+				(void) mtx_sleep(sc, &sc->mtx, PSOCK | PCATCH,
+				    "mcdsn2", hz/WAIT_FRAC);
+				if ((r = mcd_getstat(sc, 1)) == -1) {
+					MCD_UNLOCK(sc);
 					return (EIO);
+				}
 				if (r != -2)
 					break;
 			}
 		if (   (sc->data.status & (MCDDOOROPEN|MCDDSKCHNG))
 		    || !(sc->data.status & MCDDSKIN)
 		    || mcd_size(dev) < 0
-		   )
+		   ) {
+			MCD_UNLOCK(sc);
 			return (ENXIO);
+		}
 		sc->data.flags |= MCDVALID;
 		sc->data.partflags |= MCDREADRAW;
 		(void) mcd_lock_door(sc, MCD_LK_LOCK);
-		if (!(sc->data.flags & MCDVALID))
+		if (!(sc->data.flags & MCDVALID)) {
+			MCD_UNLOCK(sc);
 			return (ENXIO);
+		}
 	}
 
 	switch (cmd) {
 	case DIOCGMEDIASIZE:
 		*(off_t *)addr = (off_t)sc->data.disksize * sc->data.blksize;
-		return (0);
+		r = 0;
+		break;
 	case DIOCGSECTORSIZE:
 		*(u_int *)addr = sc->data.blksize;
-		return (0);
-
+		r = 0;
+		break;
 	case CDIOCPLAYTRACKS:
-		return mcd_playtracks(sc, (struct ioc_play_track *) addr);
+		r = mcd_playtracks(sc, (struct ioc_play_track *) addr);
+		break;
 	case CDIOCPLAYBLOCKS:
-		return mcd_playblocks(sc, (struct ioc_play_blocks *) addr);
+		r = mcd_playblocks(sc, (struct ioc_play_blocks *) addr);
+		break;
 	case CDIOCPLAYMSF:
-		return mcd_playmsf(sc, (struct ioc_play_msf *) addr);
+		r = mcd_playmsf(sc, (struct ioc_play_msf *) addr);
+		break;
 	case CDIOCREADSUBCHANNEL_SYSSPACE:
 		return mcd_subchan(sc, (struct ioc_read_subchannel *) addr, 1);
 	case CDIOCREADSUBCHANNEL:
 		return mcd_subchan(sc, (struct ioc_read_subchannel *) addr, 0);
 	case CDIOREADTOCHEADER:
-		return mcd_toc_header(sc, (struct ioc_toc_header *) addr);
+		r = mcd_toc_header(sc, (struct ioc_toc_header *) addr);
+		break;
 	case CDIOREADTOCENTRYS:
 		return mcd_toc_entrys(sc, (struct ioc_read_toc_entry *) addr);
 	case CDIOCRESUME:
-		return mcd_resume(sc);
+		r = mcd_resume(sc);
+		break;
 	case CDIOCPAUSE:
-		return mcd_pause(sc);
+		r = mcd_pause(sc);
+		break;
 	case CDIOCSTART:
 		if (mcd_setmode(sc, MCD_MD_COOKED) != 0)
-			return (EIO);
-		return (0);
+			r = EIO;
+		else
+			r = 0;
+		break;
 	case CDIOCSTOP:
-		return mcd_stop(sc);
+		r = mcd_stop(sc);
+		break;
 	default:
-		return (ENOTTY);
+		r = ENOTTY;
 	}
-	/*NOTREACHED*/
+	MCD_UNLOCK(sc);
+	return (r);
 }
 
 static int
@@ -762,6 +816,7 @@ mcd_timeout(void *arg)
 
 	sc = (struct mcd_softc *)arg;
 
+	MCD_ASSERT_LOCKED(sc);
 	mcd_doread(sc, sc->ch_state, sc->ch_mbxsave);
 }
 
@@ -775,6 +830,7 @@ mcd_doread(struct mcd_softc *sc, int sta
 	int blknum;
 	caddr_t	addr;
 
+	MCD_ASSERT_LOCKED(sc);
 	mbx = (state!=MCD_S_BEGIN) ? sc->ch_mbxsave : mbxin;
 	bp = mbx->bp;
 
@@ -789,15 +845,16 @@ retry_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 */
+		callout_reset(&sc->timer, hz/100, mcd_timeout, sc); /* XXX */
 		return;
 	case MCD_S_WAITSTAT:
 		sc->ch_state = MCD_S_WAITSTAT;
-		untimeout(mcd_timeout,(caddr_t)sc, sc->ch);
+		callout_stop(&sc->timer);
 		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 */
+				callout_reset(&sc->timer, hz/100,
+				    mcd_timeout, sc); /* XXX */
 				return;
 			}
 			sc->data.status = MCD_READ(sc, MCD_REG_STATUS) & 0xFF;
@@ -834,7 +891,7 @@ retry_mode:
 			MCD_WRITE(sc, MCD_REG_COMMAND, rm);
 
 			sc->ch_state = MCD_S_WAITMODE;
-			sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */
+			callout_reset(&sc->timer, hz / 100, mcd_timeout, sc); /* XXX */
 			return;
 		} else {
 			device_printf(sc->dev, "timeout getstatus\n");
@@ -843,14 +900,14 @@ retry_mode:
 
 	case MCD_S_WAITMODE:
 		sc->ch_state = MCD_S_WAITMODE;
-		untimeout(mcd_timeout, (caddr_t)sc, sc->ch);
+		callout_stop(&sc->timer);
 		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);
+			callout_reset(&sc->timer, hz / 100, mcd_timeout, sc);
 			return;
 		}
 		sc->data.status = MCD_READ(sc, MCD_REG_STATUS) & 0xFF;
@@ -878,7 +935,6 @@ nextblock:
 		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]);
@@ -886,7 +942,6 @@ retry_read:
 		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++) {
@@ -898,11 +953,11 @@ retry_read:
 
 		mbx->count = RDELAY_WAITREAD;
 		sc->ch_state = MCD_S_WAITREAD;
-		sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */
+		callout_reset(&sc->timer, hz / 100, mcd_timeout, sc); /* XXX */
 		return;
 	case MCD_S_WAITREAD:
 		sc->ch_state = MCD_S_WAITREAD;
-		untimeout(mcd_timeout, (caddr_t)sc, sc->ch);
+		callout_stop(&sc->timer);
 		if (mbx->count-- > 0) {
 			k = MCD_READ(sc, MCD_FLAGS);
 			if (!(k & MFL_DATA_NOT_AVAIL)) { /* XXX */
@@ -947,7 +1002,7 @@ retry_read:
 					goto changed;
 			}
 			sc->ch_state = MCD_S_WAITREAD;
-			sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */
+			callout_reset(&sc->timer, hz / 100, mcd_timeout, sc); /* XXX */
 			return;
 		} else {
 			device_printf(sc->dev, "timeout read data\n");
@@ -1010,7 +1065,8 @@ mcd_close_tray(struct mcd_softc *sc)
 		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);
+				(void) mtx_sleep(sc, &sc->mtx, PSOCK | PCATCH,
+				    "mcdcls", hz/WAIT_FRAC);
 			else {
 				if ((r = mcd_getstat(sc, 0)) == -1)
 					return (EIO);
@@ -1303,6 +1359,7 @@ mcd_toc_entrys(struct mcd_softc *sc, str
 	}
 
 	/* copy the data back */
+	MCD_UNLOCK(sc);
 	return copyout(entries, te->data, n * sizeof(struct cd_toc_entry));
 }
 
@@ -1418,6 +1475,7 @@ mcd_subchan(struct mcd_softc *sc, struct
 		break;
 	}
 
+	MCD_UNLOCK(sc);
 	if (nocopyout == 0)
 		return copyout(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len));
 	bcopy(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len));

Modified: head/sys/dev/mcd/mcd_isa.c
==============================================================================
--- head/sys/dev/mcd/mcd_isa.c	Tue Nov 18 21:03:46 2014	(r274675)
+++ head/sys/dev/mcd/mcd_isa.c	Tue Nov 18 21:51:01 2014	(r274676)
@@ -126,6 +126,7 @@ mcd_alloc_resources (device_t dev)
 
 	sc = device_get_softc(dev);
 	error = 0;
+	mtx_init(&sc->mtx, "mcd", NULL, MTX_DEF);
 
 	if (sc->port_type) {
 		sc->port = bus_alloc_resource_any(dev, sc->port_type,
@@ -135,8 +136,6 @@ mcd_alloc_resources (device_t dev)
 			error = ENOMEM;
 			goto bad;
 		}
-		sc->port_bst = rman_get_bustag(sc->port);
-		sc->port_bsh = rman_get_bushandle(sc->port);
 	}
 
 	if (sc->irq_type) {
@@ -159,9 +158,6 @@ mcd_alloc_resources (device_t dev)
 		}
 	}
 
-	mtx_init(&sc->mtx, device_get_nameunit(dev),
-		"Interrupt lock", MTX_DEF | MTX_RECURSE);
-
 bad:
 	return (error);
 }
@@ -175,18 +171,14 @@ mcd_release_resources (device_t dev)
 
 	if (sc->irq_ih)
 		bus_teardown_intr(dev, sc->irq, sc->irq_ih);
-	if (sc->port) {
+	if (sc->port)
 		bus_release_resource(dev, sc->port_type, sc->port_rid, sc->port);
-		sc->port_bst = 0;
-		sc->port_bsh = 0;
-	}
 	if (sc->irq)
 		bus_release_resource(dev, sc->irq_type, sc->irq_rid, sc->irq);
 	if (sc->drq)
 		bus_release_resource(dev, sc->drq_type, sc->drq_rid, sc->drq);
 
-	if (mtx_initialized(&sc->mtx) != 0)
-		mtx_destroy(&sc->mtx);
+	mtx_destroy(&sc->mtx);
 
 	return;
 }

Modified: head/sys/dev/mcd/mcdvar.h
==============================================================================
--- head/sys/dev/mcd/mcdvar.h	Tue Nov 18 21:03:46 2014	(r274675)
+++ head/sys/dev/mcd/mcdvar.h	Tue Nov 18 21:51:01 2014	(r274676)
@@ -41,8 +41,6 @@ struct mcd_softc {
 	struct resource *	port;
 	int			port_rid;
 	int			port_type;
-	bus_space_tag_t		port_bst;
-	bus_space_handle_t	port_bsh;
 
 	struct resource *	irq;
 	int			irq_rid;
@@ -55,20 +53,19 @@ struct mcd_softc {
 
 	struct mtx		mtx;
 
-	struct callout_handle	ch;
+	struct callout		timer;
 	int			ch_state;
 	struct mcd_mbx *	ch_mbxsave;
 
 	struct mcd_data		data;
 };
 
-#define	MCD_LOCK(_sc)		splx(&(_sc)->mtx
-#define	MCD_UNLOCK(_sc)		splx(&(_sc)->mtx
+#define	MCD_LOCK(_sc)		mtx_lock(&_sc->mtx)
+#define	MCD_UNLOCK(_sc)		mtx_unlock(&_sc->mtx)
+#define	MCD_ASSERT_LOCKED(_sc)	mtx_assert(&_sc->mtx, MA_OWNED)
 
-#define	MCD_READ(_sc, _reg) \
-	bus_space_read_1(_sc->port_bst, _sc->port_bsh, _reg)
-#define	MCD_WRITE(_sc, _reg, _val) \
-	bus_space_write_1(_sc->port_bst, _sc->port_bsh, _reg, _val)
+#define	MCD_READ(_sc, _reg)		bus_read_1(_sc->port, _reg)
+#define	MCD_WRITE(_sc, _reg, _val)	bus_write_1(_sc->port, _reg, _val)
 
 int	mcd_probe	(struct mcd_softc *);
 int	mcd_attach	(struct mcd_softc *);


More information about the svn-src-head mailing list