svn commit: r247331 - stable/9/sys/dev/twe
John Baldwin
jhb at FreeBSD.org
Tue Feb 26 18:19:52 UTC 2013
Author: jhb
Date: Tue Feb 26 18:19:51 2013
New Revision: 247331
URL: http://svnweb.freebsd.org/changeset/base/247331
Log:
MFC 239244,240137,240209:
Add locking to the twe(4) driver and make it MPSAFE.
Modified:
stable/9/sys/dev/twe/twe.c
stable/9/sys/dev/twe/twe_compat.h
stable/9/sys/dev/twe/twe_freebsd.c
stable/9/sys/dev/twe/twevar.h
Directory Properties:
stable/9/sys/ (props changed)
stable/9/sys/dev/ (props changed)
Modified: stable/9/sys/dev/twe/twe.c
==============================================================================
--- stable/9/sys/dev/twe/twe.c Tue Feb 26 18:18:39 2013 (r247330)
+++ stable/9/sys/dev/twe/twe.c Tue Feb 26 18:19:51 2013 (r247331)
@@ -68,7 +68,7 @@ static int twe_del_unit(struct twe_softc
/*
* Command I/O to controller.
*/
-static void twe_done(struct twe_softc *sc);
+static void twe_done(struct twe_softc *sc, int startio);
static void twe_complete(struct twe_softc *sc);
static int twe_wait_status(struct twe_softc *sc, u_int32_t status, int timeout);
static int twe_drain_response_queue(struct twe_softc *sc);
@@ -151,8 +151,11 @@ twe_setup(struct twe_softc *sc)
/*
* Put command onto the freelist.
*/
+ TWE_IO_LOCK(sc);
twe_release_request(tr);
+ TWE_IO_UNLOCK(sc);
}
+ TWE_IO_LOCK(sc);
/*
* Check status register for errors, clear them.
@@ -164,6 +167,7 @@ twe_setup(struct twe_softc *sc)
* Wait for the controller to come ready.
*/
if (twe_wait_status(sc, TWE_STATUS_MICROCONTROLLER_READY, 60)) {
+ TWE_IO_UNLOCK(sc);
twe_printf(sc, "microcontroller not ready\n");
return(ENXIO);
}
@@ -185,6 +189,7 @@ twe_setup(struct twe_softc *sc)
if (!twe_soft_reset(sc))
break; /* reset process complete */
}
+ TWE_IO_UNLOCK(sc);
/* did we give up? */
if (i >= TWE_MAX_RESET_TRIES) {
twe_printf(sc, "can't initialise controller, giving up\n");
@@ -203,14 +208,17 @@ twe_add_unit(struct twe_softc *sc, int u
TWE_Param *drives = NULL, *param = NULL;
TWE_Array_Descriptor *ud;
+ TWE_CONFIG_ASSERT_LOCKED(sc);
if (unit < 0 || unit > TWE_MAX_UNITS)
return (EINVAL);
/*
* The controller is in a safe state, so try to find drives attached to it.
*/
+ TWE_IO_LOCK(sc);
if ((drives = twe_get_param(sc, TWE_PARAM_UNITSUMMARY, TWE_PARAM_UNITSUMMARY_Status,
TWE_MAX_UNITS, NULL)) == NULL) {
+ TWE_IO_UNLOCK(sc);
twe_printf(sc, "can't detect attached units\n");
return (EIO);
}
@@ -218,6 +226,7 @@ twe_add_unit(struct twe_softc *sc, int u
dr = &sc->twe_drive[unit];
/* check that the drive is online */
if (!(drives->data[unit] & TWE_PARAM_UNITSTATUS_Online)) {
+ TWE_IO_UNLOCK(sc);
error = ENXIO;
goto out;
}
@@ -225,21 +234,25 @@ twe_add_unit(struct twe_softc *sc, int u
table = TWE_PARAM_UNITINFO + unit;
if (twe_get_param_4(sc, table, TWE_PARAM_UNITINFO_Capacity, &dr->td_size)) {
+ TWE_IO_UNLOCK(sc);
twe_printf(sc, "error fetching capacity for unit %d\n", unit);
error = EIO;
goto out;
}
if (twe_get_param_1(sc, table, TWE_PARAM_UNITINFO_Status, &dr->td_state)) {
+ TWE_IO_UNLOCK(sc);
twe_printf(sc, "error fetching state for unit %d\n", unit);
error = EIO;
goto out;
}
if (twe_get_param_2(sc, table, TWE_PARAM_UNITINFO_DescriptorSize, &dsize)) {
+ TWE_IO_UNLOCK(sc);
twe_printf(sc, "error fetching descriptor size for unit %d\n", unit);
error = EIO;
goto out;
}
if ((param = twe_get_param(sc, table, TWE_PARAM_UNITINFO_Descriptor, dsize - 3, NULL)) == NULL) {
+ TWE_IO_UNLOCK(sc);
twe_printf(sc, "error fetching descriptor for unit %d\n", unit);
error = EIO;
goto out;
@@ -258,6 +271,7 @@ twe_add_unit(struct twe_softc *sc, int u
}
dr->td_cylinders = dr->td_size / (dr->td_heads * dr->td_sectors);
dr->td_twe_unit = unit;
+ TWE_IO_UNLOCK(sc);
error = twe_attach_drive(sc, dr);
@@ -274,6 +288,7 @@ twe_del_unit(struct twe_softc *sc, int u
{
int error;
+ TWE_CONFIG_ASSERT_LOCKED(sc);
if (unit < 0 || unit >= TWE_MAX_UNITS)
return (ENXIO);
@@ -295,12 +310,15 @@ twe_init(struct twe_softc *sc)
/*
* Scan for drives
*/
+ TWE_CONFIG_LOCK(sc);
for (i = 0; i < TWE_MAX_UNITS; i++)
twe_add_unit(sc, i);
+ TWE_CONFIG_UNLOCK(sc);
/*
* Initialise connection with controller.
*/
+ TWE_IO_LOCK(sc);
twe_init_connection(sc, TWE_INIT_MESSAGE_CREDITS);
#ifdef TWE_SHUTDOWN_NOTIFICATION
@@ -319,6 +337,7 @@ twe_init(struct twe_softc *sc)
* Finally enable interrupts.
*/
twe_enable_interrupts(sc);
+ TWE_IO_UNLOCK(sc);
}
/********************************************************************************
@@ -330,6 +349,7 @@ twe_deinit(struct twe_softc *sc)
/*
* Mark the controller as shutting down, and disable any further interrupts.
*/
+ TWE_IO_ASSERT_LOCKED(sc);
sc->twe_state |= TWE_STATE_SHUTDOWN;
twe_disable_interrupts(sc);
@@ -368,7 +388,7 @@ twe_intr(struct twe_softc *sc)
if (status_reg & TWE_STATUS_COMMAND_INTERRUPT)
twe_command_intr(sc);
if (status_reg & TWE_STATUS_RESPONSE_INTERRUPT)
- twe_done(sc);
+ twe_done(sc, 1);
};
/********************************************************************************
@@ -380,11 +400,12 @@ twe_startio(struct twe_softc *sc)
{
struct twe_request *tr;
TWE_Command *cmd;
- twe_bio *bp;
+ struct bio *bp;
int error;
debug_called(4);
+ TWE_IO_ASSERT_LOCKED(sc);
if (sc->twe_state & (TWE_STATE_CTLR_BUSY | TWE_STATE_FRZN))
return;
@@ -410,10 +431,10 @@ twe_startio(struct twe_softc *sc)
/* connect the bio to the command */
tr->tr_complete = twe_completeio;
tr->tr_private = bp;
- tr->tr_data = TWE_BIO_DATA(bp);
- tr->tr_length = TWE_BIO_LENGTH(bp);
+ tr->tr_data = bp->bio_data;
+ tr->tr_length = bp->bio_bcount;
cmd = TWE_FIND_COMMAND(tr);
- if (TWE_BIO_IS_READ(bp)) {
+ if (bp->bio_cmd == BIO_READ) {
tr->tr_flags |= TWE_CMD_DATAIN;
cmd->io.opcode = TWE_OP_READ;
} else {
@@ -423,9 +444,9 @@ twe_startio(struct twe_softc *sc)
/* build a suitable I/O command (assumes 512-byte rounded transfers) */
cmd->io.size = 3;
- cmd->io.unit = TWE_BIO_UNIT(bp);
+ cmd->io.unit = *(int *)(bp->bio_driver1);
cmd->io.block_count = (tr->tr_length + TWE_BLOCK_SIZE - 1) / TWE_BLOCK_SIZE;
- cmd->io.lba = TWE_BIO_LBA(bp);
+ cmd->io.lba = bp->bio_pblkno;
}
/* did we find something to do? */
@@ -440,8 +461,9 @@ twe_startio(struct twe_softc *sc)
break;
tr->tr_status = TWE_CMD_ERROR;
if (tr->tr_private != NULL) {
- bp = (twe_bio *)(tr->tr_private);
- TWE_BIO_SET_ERROR(bp, error);
+ bp = (struct bio *)(tr->tr_private);
+ bp->bio_error = error;
+ bp->bio_flags |= BIO_ERROR;
tr->tr_private = NULL;
twed_intr(bp);
twe_release_request(tr);
@@ -500,15 +522,32 @@ twe_ioctl(struct twe_softc *sc, u_long i
u_int16_t *aen_code = (u_int16_t *)addr;
struct twe_request *tr;
u_int8_t srid;
- int s, error;
+ int error;
+ size_t tr_length;
error = 0;
switch(ioctlcmd) {
/* handle a command from userspace */
case TWEIO_COMMAND:
+ /*
+ * if there's a data buffer, allocate and copy it in.
+ * Must be in multipled of 512 bytes.
+ */
+ tr_length = roundup2(tu->tu_size, 512);
+ if (tr_length > 0) {
+ data = malloc(tr_length, M_DEVBUF, M_WAITOK);
+ error = copyin(tu->tu_data, data, tu->tu_size);
+ if (error) {
+ free(data, M_DEVBUF);
+ break;
+ }
+ } else
+ data = NULL;
+
/* get a request */
+ TWE_IO_LOCK(sc);
while (twe_get_request(sc, &tr))
- tsleep(sc, PPAUSE, "twioctl", hz);
+ mtx_sleep(sc, &sc->twe_io_lock, PPAUSE, "twioctl", hz);
/*
* Save the command's request ID, copy the user-supplied command in,
@@ -519,23 +558,15 @@ twe_ioctl(struct twe_softc *sc, u_long i
bcopy(&tu->tu_command, cmd, sizeof(TWE_Command));
cmd->generic.request_id = srid;
- /*
- * if there's a data buffer, allocate and copy it in.
- * Must be in multipled of 512 bytes.
- */
- tr->tr_length = (tu->tu_size + 511) & ~511;
+ tr->tr_length = tr_length;
+ tr->tr_data = data;
if (tr->tr_length > 0) {
- if ((tr->tr_data = malloc(tr->tr_length, M_DEVBUF, M_WAITOK)) == NULL) {
- error = ENOMEM;
- goto cmd_done;
- }
- if ((error = copyin(tu->tu_data, tr->tr_data, tu->tu_size)) != 0)
- goto cmd_done;
tr->tr_flags |= TWE_CMD_DATAIN | TWE_CMD_DATAOUT;
}
/* run the command */
error = twe_wait_request(tr);
+ TWE_IO_UNLOCK(sc);
if (error)
goto cmd_done;
@@ -550,8 +581,9 @@ twe_ioctl(struct twe_softc *sc, u_long i
/* free resources */
if (tr->tr_data != NULL)
free(tr->tr_data, M_DEVBUF);
- if (tr != NULL)
- twe_release_request(tr);
+ TWE_IO_LOCK(sc);
+ twe_release_request(tr);
+ TWE_IO_UNLOCK(sc);
break;
@@ -564,7 +596,9 @@ twe_ioctl(struct twe_softc *sc, u_long i
case TWEQ_READY:
case TWEQ_BUSY:
case TWEQ_COMPLETE:
+ TWE_IO_LOCK(sc);
bcopy(&sc->twe_qstat[ts->ts_item], &ts->ts_qstat, sizeof(struct twe_qstat));
+ TWE_IO_UNLOCK(sc);
break;
#endif
default:
@@ -575,22 +609,28 @@ twe_ioctl(struct twe_softc *sc, u_long i
/* poll for an AEN */
case TWEIO_AEN_POLL:
+ TWE_IO_LOCK(sc);
*aen_code = twe_dequeue_aen(sc);
+ TWE_IO_UNLOCK(sc);
break;
/* wait for another AEN to show up */
case TWEIO_AEN_WAIT:
- s = splbio();
+ TWE_IO_LOCK(sc);
while ((*aen_code = twe_dequeue_aen(sc)) == TWE_AEN_QUEUE_EMPTY) {
- error = tsleep(&sc->twe_aen_queue, PRIBIO | PCATCH, "tweaen", 0);
+ error = mtx_sleep(&sc->twe_aen_queue, &sc->twe_io_lock, PRIBIO | PCATCH,
+ "tweaen", 0);
if (error == EINTR)
break;
}
- splx(s);
+ TWE_IO_UNLOCK(sc);
break;
case TWEIO_GET_PARAM:
- if ((param = twe_get_param(sc, tp->tp_table_id, tp->tp_param_id, tp->tp_size, NULL)) == NULL) {
+ TWE_IO_LOCK(sc);
+ param = twe_get_param(sc, tp->tp_table_id, tp->tp_param_id, tp->tp_size, NULL);
+ TWE_IO_UNLOCK(sc);
+ if (param == NULL) {
twe_printf(sc, "TWEIO_GET_PARAM failed for 0x%x/0x%x/%d\n",
tp->tp_table_id, tp->tp_param_id, tp->tp_size);
error = EINVAL;
@@ -607,26 +647,32 @@ twe_ioctl(struct twe_softc *sc, u_long i
break;
case TWEIO_SET_PARAM:
- if ((data = malloc(tp->tp_size, M_DEVBUF, M_WAITOK)) == NULL) {
- error = ENOMEM;
- } else {
- error = copyin(tp->tp_data, data, tp->tp_size);
- if (error == 0)
- error = twe_set_param(sc, tp->tp_table_id, tp->tp_param_id, tp->tp_size, data);
- free(data, M_DEVBUF);
+ data = malloc(tp->tp_size, M_DEVBUF, M_WAITOK);
+ error = copyin(tp->tp_data, data, tp->tp_size);
+ if (error == 0) {
+ TWE_IO_LOCK(sc);
+ error = twe_set_param(sc, tp->tp_table_id, tp->tp_param_id, tp->tp_size, data);
+ TWE_IO_UNLOCK(sc);
}
+ free(data, M_DEVBUF);
break;
case TWEIO_RESET:
+ TWE_IO_LOCK(sc);
twe_reset(sc);
+ TWE_IO_UNLOCK(sc);
break;
case TWEIO_ADD_UNIT:
+ TWE_CONFIG_LOCK(sc);
error = twe_add_unit(sc, td->td_unit);
+ TWE_CONFIG_UNLOCK(sc);
break;
case TWEIO_DEL_UNIT:
+ TWE_CONFIG_LOCK(sc);
error = twe_del_unit(sc, td->td_unit);
+ TWE_CONFIG_UNLOCK(sc);
break;
/* XXX implement ATA PASSTHROUGH */
@@ -724,6 +770,7 @@ twe_get_param(struct twe_softc *sc, int
debug_called(4);
+ TWE_IO_ASSERT_LOCKED(sc);
tr = NULL;
param = NULL;
@@ -817,6 +864,7 @@ twe_set_param(struct twe_softc *sc, int
debug_called(4);
+ TWE_IO_ASSERT_LOCKED(sc);
tr = NULL;
param = NULL;
error = ENOMEM;
@@ -874,6 +922,8 @@ twe_init_connection(struct twe_softc *sc
debug_called(4);
+ TWE_IO_ASSERT_LOCKED(sc);
+
/* get a command */
if (twe_get_request(sc, &tr))
return(0);
@@ -903,18 +953,16 @@ twe_init_connection(struct twe_softc *sc
static int
twe_wait_request(struct twe_request *tr)
{
- int s;
debug_called(4);
+ TWE_IO_ASSERT_LOCKED(tr->tr_sc);
tr->tr_flags |= TWE_CMD_SLEEPER;
tr->tr_status = TWE_CMD_BUSY;
twe_enqueue_ready(tr);
twe_startio(tr->tr_sc);
- s = splbio();
while (tr->tr_status == TWE_CMD_BUSY)
- tsleep(tr, PRIBIO, "twewait", 0);
- splx(s);
+ mtx_sleep(tr, &tr->tr_sc->twe_io_lock, PRIBIO, "twewait", 0);
return(tr->tr_status != TWE_CMD_COMPLETE);
}
@@ -949,7 +997,7 @@ twe_immediate_request(struct twe_request
/* Wait up to 5 seconds for the command to complete */
while ((count++ < 5000) && (tr->tr_status == TWE_CMD_BUSY)){
DELAY(1000);
- twe_done(sc);
+ twe_done(sc, 1);
}
if (usetmp && (tr->tr_data != NULL))
bcopy(sc->twe_immediate, tr->tr_data, tr->tr_length);
@@ -965,15 +1013,17 @@ twe_completeio(struct twe_request *tr)
{
TWE_Command *cmd = TWE_FIND_COMMAND(tr);
struct twe_softc *sc = tr->tr_sc;
- twe_bio *bp = (twe_bio *)tr->tr_private;
+ struct bio *bp = tr->tr_private;
debug_called(4);
if (tr->tr_status == TWE_CMD_COMPLETE) {
if (cmd->generic.status)
- if (twe_report_request(tr))
- TWE_BIO_SET_ERROR(bp, EIO);
+ if (twe_report_request(tr)) {
+ bp->bio_error = EIO;
+ bp->bio_flags |= BIO_ERROR;
+ }
} else {
twe_panic(sc, "twe_completeio on incomplete command");
@@ -991,12 +1041,12 @@ static void
twe_reset(struct twe_softc *sc)
{
struct twe_request *tr;
- int i, s;
+ int i;
/*
* Sleep for a short period to allow AENs to be signalled.
*/
- tsleep(sc, PRIBIO, "twereset", hz);
+ mtx_sleep(sc, &sc->twe_io_lock, PRIBIO, "twereset", hz);
/*
* Disable interrupts from the controller, and mask any accidental entry
@@ -1004,7 +1054,6 @@ twe_reset(struct twe_softc *sc)
*/
twe_printf(sc, "controller reset in progress...\n");
twe_disable_interrupts(sc);
- s = splbio();
/*
* Try to soft-reset the controller.
@@ -1036,11 +1085,9 @@ twe_reset(struct twe_softc *sc)
* Kick the controller to start things going again, then re-enable interrupts.
*/
twe_startio(sc);
- twe_enable_interrupts(sc);
twe_printf(sc, "controller reset done, %d commands restarted\n", i);
out:
- splx(s);
twe_enable_interrupts(sc);
}
@@ -1060,11 +1107,14 @@ twe_start(struct twe_request *tr)
{
struct twe_softc *sc = tr->tr_sc;
TWE_Command *cmd;
- int i, s, done;
+ int i;
u_int32_t status_reg;
debug_called(4);
+ if (!dumping)
+ TWE_IO_ASSERT_LOCKED(sc);
+
/* mark the command as currently being processed */
tr->tr_status = TWE_CMD_BUSY;
cmd = TWE_FIND_COMMAND(tr);
@@ -1075,8 +1125,7 @@ twe_start(struct twe_request *tr)
* XXX it might be more efficient to return EBUSY immediately
* and let the command be rescheduled.
*/
- for (i = 100000, done = 0; (i > 0) && !done; i--) {
- s = splbio();
+ for (i = 100000; (i > 0); i--) {
/* check to see if we can post a command */
status_reg = TWE_STATUS(sc);
@@ -1086,7 +1135,7 @@ twe_start(struct twe_request *tr)
twe_enqueue_busy(tr);
TWE_COMMAND_QUEUE(sc, TWE_FIND_COMMANDPHYS(tr));
- done = 1;
+
/* move command to work queue */
#ifdef TWE_DEBUG
if (tr->tr_complete != NULL) {
@@ -1097,14 +1146,11 @@ twe_start(struct twe_request *tr)
debug(3, "queued request %d for polling caller", cmd->generic.request_id);
}
#endif
- }
- splx(s); /* drop spl to allow completion interrupts */
+ return(0);
+ } else if (!(status_reg & TWE_STATUS_RESPONSE_QUEUE_EMPTY) && i > 1)
+ twe_done(sc, 0);
}
- /* command is enqueued */
- if (done)
- return(0);
-
/*
* We couldn't get the controller to take the command; try submitting it again later.
* This should only happen if something is wrong with the controller, or if we have
@@ -1120,19 +1166,18 @@ twe_start(struct twe_request *tr)
* Can be called at any interrupt level, with or without interrupts enabled.
*/
static void
-twe_done(struct twe_softc *sc)
+twe_done(struct twe_softc *sc, int startio)
{
TWE_Response_Queue rq;
TWE_Command *cmd;
struct twe_request *tr;
- int s, found;
+ int found;
u_int32_t status_reg;
debug_called(5);
/* loop collecting completed commands */
found = 0;
- s = splbio();
for (;;) {
status_reg = TWE_STATUS(sc);
twe_check_bits(sc, status_reg); /* XXX should this fail? */
@@ -1155,10 +1200,9 @@ twe_done(struct twe_softc *sc)
break; /* no response ready */
}
}
- splx(s);
/* if we've completed any commands, try posting some more */
- if (found)
+ if (found && startio)
twe_startio(sc);
/* handle completion and timeouts */
@@ -1259,6 +1303,7 @@ twe_soft_reset(struct twe_softc *sc)
debug_called(2);
+ TWE_IO_ASSERT_LOCKED(sc);
TWE_SOFT_RESET(sc);
if (twe_wait_status(sc, TWE_STATUS_ATTENTION_INTERRUPT, 30)) {
@@ -1396,6 +1441,7 @@ twe_drain_aen_queue(struct twe_softc *sc
{
u_int16_t aen;
+ TWE_IO_ASSERT_LOCKED(sc);
for (;;) {
if (twe_get_param_2(sc, TWE_PARAM_AEN, TWE_PARAM_AEN_UnitCode, &aen))
return(1);
@@ -1417,14 +1463,14 @@ static void
twe_enqueue_aen(struct twe_softc *sc, u_int16_t aen)
{
char *msg;
- int s, next, nextnext;
+ int next, nextnext;
debug_called(4);
+ TWE_IO_ASSERT_LOCKED(sc);
if ((msg = twe_format_aen(sc, aen)) != NULL)
twe_printf(sc, "AEN: <%s>\n", msg);
- s = splbio();
/* enqueue the AEN */
next = ((sc->twe_aen_head + 1) % TWE_Q_LENGTH);
nextnext = ((sc->twe_aen_head + 2) % TWE_Q_LENGTH);
@@ -1447,7 +1493,6 @@ twe_enqueue_aen(struct twe_softc *sc, u_
sc->twe_wait_aen = -1;
wakeup(&sc->twe_wait_aen);
}
- splx(s);
}
/********************************************************************************
@@ -1462,6 +1507,7 @@ twe_dequeue_aen(struct twe_softc *sc)
debug_called(4);
+ TWE_IO_ASSERT_LOCKED(sc);
if (sc->twe_aen_tail == sc->twe_aen_head) {
result = TWE_AEN_QUEUE_EMPTY;
} else {
@@ -1479,15 +1525,13 @@ twe_dequeue_aen(struct twe_softc *sc)
static int
twe_find_aen(struct twe_softc *sc, u_int16_t aen)
{
- int i, s, missing;
+ int i, missing;
missing = 1;
- s = splbio();
for (i = sc->twe_aen_tail; (i != sc->twe_aen_head) && missing; i = (i + 1) % TWE_Q_LENGTH) {
if (sc->twe_aen_queue[i] == aen)
missing = 0;
}
- splx(s);
return(missing);
}
@@ -1504,22 +1548,20 @@ static int
twe_wait_aen(struct twe_softc *sc, int aen, int timeout)
{
time_t expiry;
- int found, s;
+ int found;
debug_called(4);
expiry = time_second + timeout;
found = 0;
- s = splbio();
sc->twe_wait_aen = aen;
do {
twe_fetch_aen(sc);
- tsleep(&sc->twe_wait_aen, PZERO, "twewaen", hz);
+ mtx_sleep(&sc->twe_wait_aen, &sc->twe_io_lock, PZERO, "twewaen", hz);
if (sc->twe_wait_aen == -1)
found = 1;
} while ((time_second <= expiry) && !found);
- splx(s);
return(!found);
}
#endif
@@ -1541,6 +1583,9 @@ twe_get_request(struct twe_softc *sc, st
TWE_Command *cmd;
debug_called(4);
+ if (!dumping)
+ TWE_IO_ASSERT_LOCKED(sc);
+
/* try to reuse an old buffer */
*tr = twe_dequeue_free(sc);
@@ -1567,6 +1612,8 @@ twe_release_request(struct twe_request *
{
debug_called(4);
+ if (!dumping)
+ TWE_IO_ASSERT_LOCKED(tr->tr_sc);
if (tr->tr_private != NULL)
twe_panic(tr->tr_sc, "tr_private != NULL");
twe_enqueue_free(tr);
@@ -1591,6 +1638,8 @@ twe_describe_controller(struct twe_softc
debug_called(2);
+ TWE_IO_LOCK(sc);
+
/* get the port count */
twe_get_param_1(sc, TWE_PARAM_CONTROLLER, TWE_PARAM_CONTROLLER_PortCount, &ports);
@@ -1641,6 +1690,7 @@ twe_describe_controller(struct twe_softc
if (p[0])
free(p[0], M_DEVBUF);
}
+ TWE_IO_UNLOCK(sc);
}
/********************************************************************************
@@ -1722,7 +1772,6 @@ twe_check_bits(struct twe_softc *sc, u_i
static char *
twe_format_aen(struct twe_softc *sc, u_int16_t aen)
{
- static char buf[80];
device_t child;
char *code, *msg;
@@ -1739,25 +1788,28 @@ twe_format_aen(struct twe_softc *sc, u_i
case 'c':
if ((child = sc->twe_drive[TWE_AEN_UNIT(aen)].td_disk) != NULL) {
- sprintf(buf, "twed%d: %s", device_get_unit(child), msg);
+ snprintf(sc->twe_aen_buf, sizeof(sc->twe_aen_buf), "twed%d: %s",
+ device_get_unit(child), msg);
} else {
- sprintf(buf, "twe%d: %s for unknown unit %d", device_get_unit(sc->twe_dev),
- msg, TWE_AEN_UNIT(aen));
+ snprintf(sc->twe_aen_buf, sizeof(sc->twe_aen_buf),
+ "twe%d: %s for unknown unit %d", device_get_unit(sc->twe_dev),
+ msg, TWE_AEN_UNIT(aen));
}
- return(buf);
+ return(sc->twe_aen_buf);
case 'p':
- sprintf(buf, "twe%d: port %d: %s", device_get_unit(sc->twe_dev), TWE_AEN_UNIT(aen),
- msg);
- return(buf);
+ snprintf(sc->twe_aen_buf, sizeof(sc->twe_aen_buf),
+ "twe%d: port %d: %s", device_get_unit(sc->twe_dev),
+ TWE_AEN_UNIT(aen), msg);
+ return(sc->twe_aen_buf);
case 'x':
default:
break;
}
- sprintf(buf, "unknown AEN 0x%x", aen);
- return(buf);
+ snprintf(sc->twe_aen_buf, sizeof(sc->twe_aen_buf), "unknown AEN 0x%x", aen);
+ return(sc->twe_aen_buf);
}
/********************************************************************************
Modified: stable/9/sys/dev/twe/twe_compat.h
==============================================================================
--- stable/9/sys/dev/twe/twe_compat.h Tue Feb 26 18:18:39 2013 (r247330)
+++ stable/9/sys/dev/twe/twe_compat.h Tue Feb 26 18:19:51 2013 (r247331)
@@ -43,9 +43,13 @@
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
+#include <sys/lock.h>
#include <sys/module.h>
+#include <sys/mutex.h>
#include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <sys/bio.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/disk.h>
@@ -58,6 +62,8 @@
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
+#include <geom/geom_disk.h>
+
#define TWE_DRIVER_NAME twe
#define TWED_DRIVER_NAME twed
#define TWE_MALLOC_CLASS M_TWE
@@ -65,10 +71,10 @@
/*
* Wrappers for bus-space actions
*/
-#define TWE_CONTROL(sc, val) bus_space_write_4((sc)->twe_btag, (sc)->twe_bhandle, 0x0, (u_int32_t)val)
-#define TWE_STATUS(sc) (u_int32_t)bus_space_read_4((sc)->twe_btag, (sc)->twe_bhandle, 0x4)
-#define TWE_COMMAND_QUEUE(sc, val) bus_space_write_4((sc)->twe_btag, (sc)->twe_bhandle, 0x8, (u_int32_t)val)
-#define TWE_RESPONSE_QUEUE(sc) (TWE_Response_Queue)bus_space_read_4((sc)->twe_btag, (sc)->twe_bhandle, 0xc)
+#define TWE_CONTROL(sc, val) bus_write_4((sc)->twe_io, 0x0, (u_int32_t)val)
+#define TWE_STATUS(sc) (u_int32_t)bus_read_4((sc)->twe_io, 0x4)
+#define TWE_COMMAND_QUEUE(sc, val) bus_write_4((sc)->twe_io, 0x8, (u_int32_t)val)
+#define TWE_RESPONSE_QUEUE(sc) (TWE_Response_Queue)bus_read_4((sc)->twe_io, 0xc)
/*
* FreeBSD-specific softc elements
@@ -79,8 +85,6 @@
device_t twe_dev; /* bus device */ \
struct cdev *twe_dev_t; /* control device */ \
struct resource *twe_io; /* register interface window */ \
- bus_space_handle_t twe_bhandle; /* bus space handle */ \
- bus_space_tag_t twe_btag; /* bus space tag */ \
bus_dma_tag_t twe_parent_dmat; /* parent DMA tag */ \
bus_dma_tag_t twe_buffer_dmat; /* data buffer DMA tag */ \
bus_dma_tag_t twe_cmd_dmat; /* command buffer DMA tag */ \
@@ -91,8 +95,8 @@
void *twe_cmd; /* command structures */ \
void *twe_immediate; /* immediate commands */ \
bus_dmamap_t twe_immediate_map; \
- struct sysctl_ctx_list sysctl_ctx; \
- struct sysctl_oid *sysctl_tree;
+ struct mtx twe_io_lock; \
+ struct sx twe_config_lock;
/*
* FreeBSD-specific request elements
@@ -107,52 +111,12 @@
#define twe_printf(sc, fmt, args...) device_printf(sc->twe_dev, fmt , ##args)
#define twed_printf(twed, fmt, args...) device_printf(twed->twed_dev, fmt , ##args)
-#if __FreeBSD_version < 500003
-# include <machine/clock.h>
-# define INTR_ENTROPY 0
-# define FREEBSD_4
-
-# include <sys/buf.h> /* old buf style */
-typedef struct buf twe_bio;
-typedef struct buf_queue_head twe_bioq;
-# define TWE_BIO_QINIT(bq) bufq_init(&bq);
-# define TWE_BIO_QINSERT(bq, bp) bufq_insert_tail(&bq, bp)
-# define TWE_BIO_QFIRST(bq) bufq_first(&bq)
-# define TWE_BIO_QREMOVE(bq, bp) bufq_remove(&bq, bp)
-# define TWE_BIO_IS_READ(bp) ((bp)->b_flags & B_READ)
-# define TWE_BIO_DATA(bp) (bp)->b_data
-# define TWE_BIO_LENGTH(bp) (bp)->b_bcount
-# define TWE_BIO_LBA(bp) (bp)->b_pblkno
-# define TWE_BIO_SOFTC(bp) (bp)->b_dev->si_drv1
-# define TWE_BIO_UNIT(bp) *(int *)((bp)->b_dev->si_drv2)
-# define TWE_BIO_SET_ERROR(bp, err) do { (bp)->b_error = err; (bp)->b_flags |= B_ERROR;} while(0)
-# define TWE_BIO_HAS_ERROR(bp) ((bp)->b_flags & B_ERROR)
-# define TWE_BIO_RESID(bp) (bp)->b_resid
-# define TWE_BIO_DONE(bp) biodone(bp)
-# define TWE_BIO_STATS_START(bp) devstat_start_transaction(&((struct twed_softc *)TWE_BIO_SOFTC(bp))->twed_stats)
-# define TWE_BIO_STATS_END(bp) devstat_end_transaction_buf(&((struct twed_softc *)TWE_BIO_SOFTC(bp))->twed_stats, bp)
-#else
-# include <sys/bio.h>
-# include <geom/geom_disk.h>
-typedef struct bio twe_bio;
-typedef struct bio_queue_head twe_bioq;
-# define TWE_BIO_QINIT(bq) bioq_init(&bq);
-# define TWE_BIO_QINSERT(bq, bp) bioq_insert_tail(&bq, bp)
-# define TWE_BIO_QFIRST(bq) bioq_first(&bq)
-# define TWE_BIO_QREMOVE(bq, bp) bioq_remove(&bq, bp)
-# define TWE_BIO_IS_READ(bp) ((bp)->bio_cmd == BIO_READ)
-# define TWE_BIO_DATA(bp) (bp)->bio_data
-# define TWE_BIO_LENGTH(bp) (bp)->bio_bcount
-# define TWE_BIO_LBA(bp) (bp)->bio_pblkno
-# define TWE_BIO_SOFTC(bp) (bp)->bio_disk->d_drv1
-# define TWE_BIO_UNIT(bp) *(int *)(bp->bio_driver1)
-# define TWE_BIO_SET_ERROR(bp, err) do { (bp)->bio_error = err; (bp)->bio_flags |= BIO_ERROR;} while(0)
-# define TWE_BIO_HAS_ERROR(bp) ((bp)->bio_flags & BIO_ERROR)
-# define TWE_BIO_RESID(bp) (bp)->bio_resid
-# define TWE_BIO_DONE(bp) biodone(bp)
-# define TWE_BIO_STATS_START(bp)
-# define TWE_BIO_STATS_END(bp)
-#endif
+#define TWE_IO_LOCK(sc) mtx_lock(&(sc)->twe_io_lock)
+#define TWE_IO_UNLOCK(sc) mtx_unlock(&(sc)->twe_io_lock)
+#define TWE_IO_ASSERT_LOCKED(sc) mtx_assert(&(sc)->twe_io_lock, MA_OWNED)
+#define TWE_CONFIG_LOCK(sc) sx_xlock(&(sc)->twe_config_lock)
+#define TWE_CONFIG_UNLOCK(sc) sx_xunlock(&(sc)->twe_config_lock)
+#define TWE_CONFIG_ASSERT_LOCKED(sc) sx_assert(&(sc)->twe_config_lock, SA_XLOCKED)
#endif /* FreeBSD */
Modified: stable/9/sys/dev/twe/twe_freebsd.c
==============================================================================
--- stable/9/sys/dev/twe/twe_freebsd.c Tue Feb 26 18:18:39 2013 (r247330)
+++ stable/9/sys/dev/twe/twe_freebsd.c Tue Feb 26 18:19:51 2013 (r247331)
@@ -69,7 +69,6 @@ static d_ioctl_t twe_ioctl_wrapper;
static struct cdevsw twe_cdevsw = {
.d_version = D_VERSION,
- .d_flags = D_NEEDGIANT,
.d_open = twe_open,
.d_close = twe_close,
.d_ioctl = twe_ioctl_wrapper,
@@ -84,7 +83,13 @@ twe_open(struct cdev *dev, int flags, in
{
struct twe_softc *sc = (struct twe_softc *)dev->si_drv1;
+ TWE_IO_LOCK(sc);
+ if (sc->twe_state & TWE_STATE_DETACHING) {
+ TWE_IO_UNLOCK(sc);
+ return (ENXIO);
+ }
sc->twe_state |= TWE_STATE_OPEN;
+ TWE_IO_UNLOCK(sc);
return(0);
}
@@ -96,7 +101,9 @@ twe_close(struct cdev *dev, int flags, i
{
struct twe_softc *sc = (struct twe_softc *)dev->si_drv1;
+ TWE_IO_LOCK(sc);
sc->twe_state &= ~TWE_STATE_OPEN;
+ TWE_IO_UNLOCK(sc);
return (0);
}
@@ -172,8 +179,8 @@ static int
twe_attach(device_t dev)
{
struct twe_softc *sc;
+ struct sysctl_oid *sysctl_tree;
int rid, error;
- u_int32_t command;
debug_called(4);
@@ -182,32 +189,30 @@ twe_attach(device_t dev)
*/
sc = device_get_softc(dev);
sc->twe_dev = dev;
+ mtx_init(&sc->twe_io_lock, "twe I/O", NULL, MTX_DEF);
+ sx_init(&sc->twe_config_lock, "twe config");
- sysctl_ctx_init(&sc->sysctl_ctx);
- sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
+ /*
+ * XXX: This sysctl tree must stay at hw.tweX rather than using
+ * the device_get_sysctl_tree() created by new-bus because
+ * existing 3rd party binary tools such as tw_cli and 3dm2 use the
+ * existence of this sysctl node to discover controllers.
+ */
+ sysctl_tree = SYSCTL_ADD_NODE(device_get_sysctl_ctx(dev),
SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
device_get_nameunit(dev), CTLFLAG_RD, 0, "");
- if (sc->sysctl_tree == NULL) {
+ if (sysctl_tree == NULL) {
twe_printf(sc, "cannot add sysctl tree node\n");
return (ENXIO);
}
- SYSCTL_ADD_STRING(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
+ SYSCTL_ADD_STRING(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(sysctl_tree),
OID_AUTO, "driver_version", CTLFLAG_RD, TWE_DRIVER_VERSION_STRING, 0,
"TWE driver version");
/*
- * Make sure we are going to be able to talk to this board.
- */
- command = pci_read_config(dev, PCIR_COMMAND, 2);
- if ((command & PCIM_CMD_PORTEN) == 0) {
- twe_printf(sc, "register window not available\n");
- return(ENXIO);
- }
- /*
* Force the busmaster enable bit on, in case the BIOS forgot.
*/
- command |= PCIM_CMD_BUSMASTEREN;
- pci_write_config(dev, PCIR_COMMAND, command, 2);
+ pci_enable_busmaster(dev);
/*
* Allocate the PCI register window.
@@ -219,8 +224,6 @@ twe_attach(device_t dev)
twe_free(sc);
return(ENXIO);
}
- sc->twe_btag = rman_get_bustag(sc->twe_io);
- sc->twe_bhandle = rman_get_bushandle(sc->twe_io);
/*
* Allocate the parent bus DMA tag appropriate for PCI.
@@ -251,7 +254,7 @@ twe_attach(device_t dev)
twe_free(sc);
return(ENXIO);
}
- if (bus_setup_intr(sc->twe_dev, sc->twe_irq, INTR_TYPE_BIO | INTR_ENTROPY,
+ if (bus_setup_intr(sc->twe_dev, sc->twe_irq, INTR_TYPE_BIO | INTR_ENTROPY | INTR_MPSAFE,
NULL, twe_pci_intr, sc, &sc->twe_intr)) {
twe_printf(sc, "can't set up interrupt\n");
twe_free(sc);
@@ -302,7 +305,7 @@ twe_attach(device_t dev)
BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
BUS_DMA_ALLOCNOW, /* flags */
busdma_lock_mutex, /* lockfunc */
- &Giant, /* lockarg */
+ &sc->twe_io_lock, /* lockarg */
&sc->twe_buffer_dmat)) {
twe_printf(sc, "can't allocate data buffer DMA tag\n");
twe_free(sc);
@@ -424,7 +427,8 @@ twe_free(struct twe_softc *sc)
if (sc->twe_dev_t != (struct cdev *)NULL)
destroy_dev(sc->twe_dev_t);
- sysctl_ctx_free(&sc->sysctl_ctx);
+ sx_destroy(&sc->twe_config_lock);
+ mtx_destroy(&sc->twe_io_lock);
}
/********************************************************************************
@@ -434,27 +438,30 @@ static int
twe_detach(device_t dev)
{
struct twe_softc *sc = device_get_softc(dev);
- int s, error;
debug_called(4);
- error = EBUSY;
- s = splbio();
- if (sc->twe_state & TWE_STATE_OPEN)
- goto out;
+ TWE_IO_LOCK(sc);
+ if (sc->twe_state & TWE_STATE_OPEN) {
+ TWE_IO_UNLOCK(sc);
+ return (EBUSY);
+ }
+ sc->twe_state |= TWE_STATE_DETACHING;
+ TWE_IO_UNLOCK(sc);
/*
* Shut the controller down.
*/
- if (twe_shutdown(dev))
- goto out;
+ if (twe_shutdown(dev)) {
+ TWE_IO_LOCK(sc);
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-stable-9
mailing list