svn commit: r274679 - head/sys/dev/scd
John Baldwin
jhb at FreeBSD.org
Tue Nov 18 22:02:39 UTC 2014
Author: jhb
Date: Tue Nov 18 22:02:37 2014
New Revision: 274679
URL: https://svnweb.freebsd.org/changeset/base/274679
Log:
Add locking to scd(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. SCDINIT being clear).
- Use bus_*() instead of bus_space_*().
Tested by: no one
Modified:
head/sys/dev/scd/scd.c
head/sys/dev/scd/scd_isa.c
head/sys/dev/scd/scdvar.h
Modified: head/sys/dev/scd/scd.c
==============================================================================
--- head/sys/dev/scd/scd.c Tue Nov 18 21:58:57 2014 (r274678)
+++ head/sys/dev/scd/scd.c Tue Nov 18 22:02:37 2014 (r274679)
@@ -120,7 +120,7 @@ static int get_result(struct scd_softc *
static void print_error(struct scd_softc *, int errcode);
static void scd_start(struct scd_softc *);
-static timeout_t scd_timeout;
+static void scd_timeout(void *);
static void scd_doread(struct scd_softc *, int state, struct scd_mbx *mbxin);
static int scd_eject(struct scd_softc *);
@@ -153,7 +153,7 @@ static struct cdevsw scd_cdevsw = {
.d_ioctl = scdioctl,
.d_strategy = scdstrategy,
.d_name = "scd",
- .d_flags = D_DISK | D_NEEDGIANT,
+ .d_flags = D_DISK,
};
int
@@ -163,11 +163,13 @@ scd_attach(struct scd_softc *sc)
unit = device_get_unit(sc->dev);
+ SCD_LOCK(sc);
init_drive(sc);
sc->data.flags = SCDINIT;
sc->data.audio_status = CD_AS_AUDIO_INVALID;
bioq_init(&sc->data.head);
+ SCD_UNLOCK(sc);
sc->scd_dev_t = make_dev(&scd_cdevsw, 8 * unit,
UID_ROOT, GID_OPERATOR, 0640, "scd%d", unit);
@@ -184,18 +186,18 @@ scdopen(struct cdev *dev, int flags, int
sc = (struct scd_softc *)dev->si_drv1;
- /* not initialized*/
- if (!(sc->data.flags & SCDINIT))
- return (ENXIO);
-
- /* invalidated in the meantime? mark all open part's invalid */
- if (sc->data.openflag)
+ /* mark all open part's invalid */
+ SCD_LOCK(sc);
+ if (sc->data.openflag) {
+ SCD_UNLOCK(sc);
return (ENXIO);
+ }
XDEBUG(sc, 1, "DEBUG: status = 0x%x\n", SCD_READ(sc, IREG_STATUS));
if ((rc = spin_up(sc)) != 0) {
print_error(sc, rc);
+ SCD_UNLOCK(sc);
return (EIO);
}
if (!(sc->data.flags & SCDTOC)) {
@@ -205,18 +207,21 @@ scdopen(struct cdev *dev, int flags, int
if (rc == ERR_NOT_SPINNING) {
rc = spin_up(sc);
if (rc) {
- print_error(sc, rc);\
+ print_error(sc, rc);
+ SCD_UNLOCK(sc);
return (EIO);
}
continue;
}
device_printf(sc->dev, "TOC read error 0x%x\n", rc);
+ SCD_UNLOCK(sc);
return (EIO);
}
}
sc->data.openflag = 1;
sc->data.flags |= SCDVALID;
+ SCD_UNLOCK(sc);
return (0);
}
@@ -228,17 +233,17 @@ scdclose(struct cdev *dev, int flags, in
sc = (struct scd_softc *)dev->si_drv1;
- if (!(sc->data.flags & SCDINIT) || !sc->data.openflag)
- return (ENXIO);
+ SCD_LOCK(sc);
+ KASSERT(sc->data.openflag, ("device not open"));
if (sc->data.audio_status != CD_AS_PLAY_IN_PROGRESS) {
(void)send_cmd(sc, CMD_SPIN_DOWN, 0);
sc->data.flags &= ~SCDSPINNING;
}
-
/* close channel */
sc->data.openflag = 0;
+ SCD_UNLOCK(sc);
return (0);
}
@@ -246,12 +251,12 @@ scdclose(struct cdev *dev, int flags, in
static void
scdstrategy(struct bio *bp)
{
- int s;
struct scd_softc *sc;
sc = (struct scd_softc *)bp->bio_dev->si_drv1;
/* if device invalidated (e.g. media change, door open), error */
+ SCD_LOCK(sc);
if (!(sc->data.flags & SCDVALID)) {
device_printf(sc->dev, "media changed\n");
bp->bio_error = EIO;
@@ -276,17 +281,17 @@ scdstrategy(struct bio *bp)
bp->bio_resid = 0;
/* queue it */
- s = splbio();
bioq_disksort(&sc->data.head, bp);
- splx(s);
/* now check whether we can perform processing */
scd_start(sc);
+ SCD_UNLOCK(sc);
return;
bad:
bp->bio_flags |= BIO_ERROR;
done:
+ SCD_UNLOCK(sc);
bp->bio_resid = bp->bio_bcount;
biodone(bp);
return;
@@ -296,27 +301,22 @@ static void
scd_start(struct scd_softc *sc)
{
struct bio *bp;
- int s = splbio();
- if (sc->data.flags & SCDMBXBSY) {
- splx(s);
+ SCD_ASSERT_LOCKED(sc);
+ if (sc->data.flags & SCDMBXBSY)
return;
- }
bp = bioq_takefirst(&sc->data.head);
if (bp != 0) {
/* block found to process, dequeue */
sc->data.flags |= SCDMBXBSY;
- splx(s);
} else {
/* nothing to do */
- splx(s);
return;
}
sc->data.mbx.retry = 3;
sc->data.mbx.bp = bp;
- splx(s);
scd_doread(sc, SCD_S_BEGIN, &(sc->data.mbx));
return;
@@ -326,39 +326,47 @@ static int
scdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
{
struct scd_softc *sc;
+ int error;
sc = (struct scd_softc *)dev->si_drv1;
XDEBUG(sc, 1, "ioctl: cmd=0x%lx\n", cmd);
- if (!(sc->data.flags & SCDVALID))
+ SCD_LOCK(sc);
+ if (!(sc->data.flags & SCDVALID)) {
+ SCD_UNLOCK(sc);
return (EIO);
+ }
+ error = 0;
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 scd_playtracks(sc, (struct ioc_play_track *) addr);
+ error = scd_playtracks(sc, (struct ioc_play_track *) addr);
+ break;
case CDIOCPLAYBLOCKS:
- return (EINVAL);
+ error = EINVAL;
+ break;
case CDIOCPLAYMSF:
- return scd_playmsf(sc, (struct ioc_play_msf *) addr);
+ error = scd_playmsf(sc, (struct ioc_play_msf *) addr);
+ break;
case CDIOCREADSUBCHANNEL_SYSSPACE:
return scd_subchan(sc, (struct ioc_read_subchannel *) addr, 1);
case CDIOCREADSUBCHANNEL:
return scd_subchan(sc, (struct ioc_read_subchannel *) addr, 0);
case CDIOREADTOCHEADER:
- return scd_toc_header (sc, (struct ioc_toc_header *) addr);
+ error = scd_toc_header (sc, (struct ioc_toc_header *) addr);
+ break;
case CDIOREADTOCENTRYS:
return scd_toc_entrys (sc, (struct ioc_read_toc_entry*) addr);
case CDIOREADTOCENTRY:
- return scd_toc_entry (sc, (struct ioc_read_toc_single_entry*) addr);
+ error = scd_toc_entry (sc, (struct ioc_read_toc_single_entry*) addr);
+ break;
case CDIOCSETPATCH:
case CDIOCGETVOL:
case CDIOCSETVOL:
@@ -367,34 +375,43 @@ scdioctl(struct cdev *dev, u_long cmd, c
case CDIOCSETMUTE:
case CDIOCSETLEFT:
case CDIOCSETRIGHT:
- return (EINVAL);
+ error = EINVAL;
+ break;
case CDIOCRESUME:
- return scd_resume(sc);
+ error = scd_resume(sc);
+ break;
case CDIOCPAUSE:
- return scd_pause(sc);
+ error = scd_pause(sc);
+ break;
case CDIOCSTART:
- return (EINVAL);
+ error = EINVAL;
+ break;
case CDIOCSTOP:
- return scd_stop(sc);
+ error = scd_stop(sc);
+ break;
case CDIOCEJECT:
- return scd_eject(sc);
+ error = scd_eject(sc);
+ break;
case CDIOCALLOW:
- return (0);
+ break;
case CDIOCSETDEBUG:
#ifdef SCD_DEBUG
scd_debuglevel++;
#endif
- return (0);
+ break;
case CDIOCCLRDEBUG:
#ifdef SCD_DEBUG
scd_debuglevel = 0;
#endif
- return (0);
+ break;
default:
device_printf(sc->dev, "unsupported ioctl (cmd=0x%lx)\n", cmd);
- return (ENOTTY);
+ error = ENOTTY;
+ break;
}
+ SCD_UNLOCK(sc);
+ return (error);
}
/***************************************************************
@@ -573,6 +590,7 @@ scd_subchan(struct scd_softc *sc, struct
data.what.position.absaddr.msf.minute = bcd2bin(q.abs_msf[0]);
data.what.position.absaddr.msf.second = bcd2bin(q.abs_msf[1]);
data.what.position.absaddr.msf.frame = bcd2bin(q.abs_msf[2]);
+ SCD_UNLOCK(sc);
if (nocopyout == 0) {
if (copyout(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len))!=0)
@@ -680,6 +698,7 @@ scd_timeout(void *arg)
struct scd_softc *sc;
sc = (struct scd_softc *)arg;
+ SCD_ASSERT_LOCKED(sc);
scd_doread(sc, sc->ch_state, sc->ch_mbxsave);
}
@@ -693,6 +712,7 @@ scd_doread(struct scd_softc *sc, int sta
caddr_t addr;
static char sdata[3]; /* Must be preserved between calls to this function */
+ SCD_ASSERT_LOCKED(sc);
loop:
switch (state) {
case SCD_S_BEGIN:
@@ -707,7 +727,7 @@ loop:
case SCD_S_WAITSTAT:
sc->ch_state = SCD_S_WAITSTAT;
- untimeout(scd_timeout, (caddr_t)sc, sc->ch);
+ callout_stop(&sc->timer);
if (mbx->count-- <= 0) {
device_printf(sc->dev, "timeout. drive busy.\n");
goto harderr;
@@ -716,7 +736,7 @@ loop:
trystat:
if (IS_BUSY(sc)) {
sc->ch_state = SCD_S_WAITSTAT;
- sc->ch = timeout(scd_timeout, (caddr_t)sc, hz/100); /* XXX */
+ callout_reset(&sc->timer, hz / 100, scd_timeout, sc); /* XXX */
return;
}
@@ -754,19 +774,19 @@ nextblock:
mbx->count = 100;
sc->ch_state = SCD_S_WAITFIFO;
- sc->ch = timeout(scd_timeout, (caddr_t)sc, hz/100); /* XXX */
+ callout_reset(&sc->timer, hz / 100, scd_timeout, sc); /* XXX */
return;
case SCD_S_WAITSPIN:
sc->ch_state = SCD_S_WAITSPIN;
- untimeout(scd_timeout,(caddr_t)sc, sc->ch);
+ callout_stop(&sc->timer);
if (mbx->count-- <= 0) {
device_printf(sc->dev, "timeout waiting for drive to spin up.\n");
goto harderr;
}
if (!STATUS_BIT(sc, SBIT_RESULT_READY)) {
sc->ch_state = SCD_S_WAITSPIN;
- sc->ch = timeout(scd_timeout, (caddr_t)sc, hz/100); /* XXX */
+ callout_reset(&sc->timer, hz / 100, scd_timeout, sc); /* XXX */
return;
}
SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR);
@@ -787,14 +807,14 @@ nextblock:
case SCD_S_WAITFIFO:
sc->ch_state = SCD_S_WAITFIFO;
- untimeout(scd_timeout,(caddr_t)sc, sc->ch);
+ callout_stop(&sc->timer);
if (mbx->count-- <= 0) {
device_printf(sc->dev, "timeout. write param not ready.\n");
goto harderr;
}
if (!FSTATUS_BIT(sc, FBIT_WPARAM_READY)) {
sc->ch_state = SCD_S_WAITFIFO;
- sc->ch = timeout(scd_timeout, (caddr_t)sc,hz/100); /* XXX */
+ callout_reset(&sc->timer, hz / 100, scd_timeout, sc); /* XXX */
return;
}
XDEBUG(sc, 1, "mbx->count (writeparamwait) = %d(%d)\n", mbx->count, 100);
@@ -807,12 +827,11 @@ writeparam:
SCD_WRITE(sc, OREG_COMMAND, CMD_SPIN_UP);
mbx->count = 300;
sc->ch_state = SCD_S_WAITSPIN;
- sc->ch = timeout(scd_timeout, (caddr_t)sc, hz/100); /* XXX */
+ callout_reset(&sc->timer, hz / 100, scd_timeout, sc); /* XXX */
return;
}
/* send the read command */
- critical_enter();
SCD_WRITE(sc, OREG_WPARAMS, sdata[0]);
SCD_WRITE(sc, OREG_WPARAMS, sdata[1]);
SCD_WRITE(sc, OREG_WPARAMS, sdata[2]);
@@ -820,7 +839,6 @@ writeparam:
SCD_WRITE(sc, OREG_WPARAMS, 0);
SCD_WRITE(sc, OREG_WPARAMS, 1);
SCD_WRITE(sc, OREG_COMMAND, CMD_READ);
- critical_exit();
mbx->count = RDELAY_WAITREAD;
for (i = 0; i < 50; i++) {
@@ -830,12 +848,12 @@ writeparam:
}
sc->ch_state = SCD_S_WAITREAD;
- sc->ch = timeout(scd_timeout, (caddr_t)sc, hz/100); /* XXX */
+ callout_reset(&sc->timer, hz / 100, scd_timeout, sc); /* XXX */
return;
case SCD_S_WAITREAD:
sc->ch_state = SCD_S_WAITREAD;
- untimeout(scd_timeout,(caddr_t)sc, sc->ch);
+ callout_stop(&sc->timer);
if (mbx->count-- <= 0) {
if (STATUS_BIT(sc, SBIT_RESULT_READY))
goto got_param;
@@ -847,7 +865,7 @@ writeparam:
if (!(sc->data.flags & SCDVALID))
goto changed;
sc->ch_state = SCD_S_WAITREAD;
- sc->ch = timeout(scd_timeout, (caddr_t)sc, hz/100); /* XXX */
+ callout_reset(&sc->timer, hz / 100, scd_timeout, sc); /* XXX */
return;
}
XDEBUG(sc, 2, "mbx->count (after RDY_BIT) = %d(%d)\n", mbx->count, RDELAY_WAITREAD);
@@ -868,7 +886,7 @@ got_data:
case SCD_S_WAITPARAM:
sc->ch_state = SCD_S_WAITPARAM;
- untimeout(scd_timeout,(caddr_t)sc, sc->ch);
+ callout_stop(&sc->timer);
if (mbx->count-- <= 0) {
device_printf(sc->dev, "timeout waiting for params\n");
goto readerr;
@@ -877,7 +895,7 @@ got_data:
waitfor_param:
if (!STATUS_BIT(sc, SBIT_RESULT_READY)) {
sc->ch_state = SCD_S_WAITPARAM;
- sc->ch = timeout(scd_timeout, (caddr_t)sc, hz/100); /* XXX */
+ callout_reset(&sc->timer, hz / 100, scd_timeout, sc); /* XXX */
return;
}
#ifdef SCD_DEBUG
@@ -1293,7 +1311,9 @@ waitfor_status_bits(struct scd_softc *sc
{
break;
}
+ SCD_UNLOCK(sc);
pause("waitfor", hz/10);
+ SCD_LOCK(sc);
}
}
if ((c & bits_set) == bits_set &&
@@ -1363,6 +1383,7 @@ scd_toc_entrys (struct scd_softc *sc, st
toc_entry.addr.msf.second = bcd2bin(sc->data.toc[i].start_msf[1]);
toc_entry.addr.msf.frame = bcd2bin(sc->data.toc[i].start_msf[2]);
}
+ SCD_UNLOCK(sc);
/* copy the data back */
if (copyout(&toc_entry, te->data, sizeof(struct cd_toc_entry)) != 0)
Modified: head/sys/dev/scd/scd_isa.c
==============================================================================
--- head/sys/dev/scd/scd_isa.c Tue Nov 18 21:58:57 2014 (r274678)
+++ head/sys/dev/scd/scd_isa.c Tue Nov 18 22:02:37 2014 (r274679)
@@ -125,6 +125,7 @@ scd_alloc_resources (device_t dev)
sc = device_get_softc(dev);
error = 0;
+ mtx_init(&sc->mtx, "scd", NULL, MTX_DEF);
if (sc->port_type) {
sc->port = bus_alloc_resource_any(dev, sc->port_type,
@@ -134,13 +135,8 @@ scd_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);
}
- mtx_init(&sc->mtx, device_get_nameunit(dev),
- "Interrupt lock", MTX_DEF | MTX_RECURSE);
-
bad:
return (error);
}
@@ -152,14 +148,10 @@ scd_release_resources (device_t dev)
sc = device_get_softc(dev);
- 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 (mtx_initialized(&sc->mtx) != 0)
- mtx_destroy(&sc->mtx);
+ mtx_destroy(&sc->mtx);
return;
}
Modified: head/sys/dev/scd/scdvar.h
==============================================================================
--- head/sys/dev/scd/scdvar.h Tue Nov 18 21:58:57 2014 (r274678)
+++ head/sys/dev/scd/scdvar.h Tue Nov 18 22:02:37 2014 (r274679)
@@ -40,27 +40,26 @@ struct scd_softc {
struct resource * port;
int port_rid;
int port_type;
- bus_space_tag_t port_bst;
- bus_space_handle_t port_bsh;
struct mtx mtx;
- struct callout_handle ch;
+ struct callout timer;
int ch_state;
struct scd_mbx * ch_mbxsave;
struct scd_data data;
};
-#define SCD_LOCK(_sc) splx(&(_sc)->mtx
-#define SCD_UNLOCK(_sc) splx(&(_sc)->mtx
+#define SCD_LOCK(_sc) mtx_lock(&_sc->mtx)
+#define SCD_UNLOCK(_sc) mtx_unlock(&_sc->mtx)
+#define SCD_ASSERT_LOCKED(_sc) mtx_assert(&_sc->mtx, MA_OWNED)
#define SCD_READ(_sc, _reg) \
- bus_space_read_1(_sc->port_bst, _sc->port_bsh, _reg)
+ bus_read_1(_sc->port, _reg)
#define SCD_READ_MULTI(_sc, _reg, _addr, _count) \
- bus_space_read_multi_1(_sc->port_bst, _sc->port_bsh, _reg, _addr, _count)
+ bus_read_multi_1(_sc->port, _reg, _addr, _count)
#define SCD_WRITE(_sc, _reg, _val) \
- bus_space_write_1(_sc->port_bst, _sc->port_bsh, _reg, _val)
+ bus_write_1(_sc->port, _reg, _val)
int scd_probe (struct scd_softc *);
int scd_attach (struct scd_softc *);
More information about the svn-src-all
mailing list